Browse Source

add demo volume code

cuu 1 year ago
parent
commit
b826552d3d

+ 26 - 0
demo/volume/CMakeLists.txt

@@ -0,0 +1,26 @@
+#/*
+# * ALGO     : PROJ. : Volume
+# * RESEARCH : File  : CMakeLists.txt
+# *          : Date  : 20100531.0725UTC
+# *          : Email : mail@algoresearch.net
+# */
+
+cmake_minimum_required(VERSION 2.8)
+
+#	 set(CMAKE_C_COMPILER clang)
+#	 set(CMAKE_CXX_COMPILER clang)
+
+project(template)
+
+	aux_source_directory(src SRC_LIST)
+		#set(SRC_LIST src/main.c src/test.c)
+
+	include_directories(include)
+
+	add_compile_options(-Wall -O2)
+	add_executable(main ${SRC_LIST})
+	target_link_libraries(main X11 m pthread)
+
+	set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
+
+#EOF

+ 37 - 0
demo/volume/README

@@ -0,0 +1,37 @@
+/*
+ * ALGO     : PROJ. : Volume(Demo)
+ * RESEARCH : File  : README
+ *          : Date  : 20100531.0725UTC
+ *          : Email : mail@algoresearch.net
+ */
+
+# Project structure:
+	.
+	├── README
+	├── CMakeLists.txt
+	├── bin/
+	├── build/
+	├── include/
+	│   ├── main.h
+	│   ├── observer.h
+	│   ├── space.h
+	│   ├── transform.h
+	│   └── x.h
+	└── src/
+	    ├── main.c
+	    ├── observer.c
+	    ├── space.c
+	    ├── transform.c
+	    └── x.c
+
+# How to compile:
+  At the project root directory, execute following commands:
+	cd bulid
+	cmake ..
+	make
+
+# How to run:
+  If compiled correctly, the executable file(s) will be generated in
+  the "./bin/" of the project root directory.
+
+EOF.

+ 23 - 0
demo/volume/include/main.h

@@ -0,0 +1,23 @@
+/*
+ * ALGO     : PROJ. : Volume
+ * RESEARCH : File  : main.h
+ *          : Date  : 20100531.0725UTC
+ *          : Email : mail@algoresearch.net
+ */
+
+#include <pthread.h>
+
+typedef struct{
+    pthread_t pid_observer, pid_display, pid_event_loop;
+
+    int *space_i, *space_o;
+    unsigned int space_w, space_h, space_d, size_plane, size_space;
+    int dw, dh;
+
+    int a_sync, motion, mx, my;
+    float ax, ay, c_ax, c_ay;
+
+    int main, mapping, display;
+    unsigned int iter;
+}SYS_TABLE;
+

+ 12 - 0
demo/volume/include/observer.h

@@ -0,0 +1,12 @@
+/*
+ * ALGO     : PROJ. : Volume
+ * RESEARCH : File  : observer.h
+ *          : Date  : 20100531.0725UTC
+ *          : Email : mail@algoresearch.net
+ */
+
+#include "x.h"
+#include "transform.h"
+#include "space.h"
+
+void create_observer(SYS_TABLE *sys);

+ 13 - 0
demo/volume/include/space.h

@@ -0,0 +1,13 @@
+/*
+ * ALGO     : PROJ. : Volume
+ * RESEARCH : File  : space.h
+ *          : Date  : 20100531.0725UTC
+ *          : Email : mail@algoresearch.net
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+void create_space(SYS_TABLE *sys, int w, int h, int d);
+void iterative_space (SYS_TABLE *sys);
+int cell_get(SYS_TABLE *sys, int x, int y, int z);

+ 15 - 0
demo/volume/include/transform.h

@@ -0,0 +1,15 @@
+/*
+ * ALGO     : PROJ. : Volume
+ * RESEARCH : File  : transform.h
+ *          : Date  : 20100531.0725UTC
+ *          : Email : mail@algoresearch.net
+ */
+
+#include <math.h>
+
+typedef struct{
+    float x, y, z;
+    int v;
+}VERTEX;
+
+void rotate_xy(VERTEX*, VERTEX*, float, float, VERTEX*);

+ 45 - 0
demo/volume/include/x.h

@@ -0,0 +1,45 @@
+/*
+ * ALGO     : PROJ. : Volume
+ * RESEARCH : File  : x.h
+ *          : Date  : 20100531.0725UTC
+ *          : Email : mail@algoresearch.net
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xutil.h> 
+
+extern Display *dpy;
+extern GC gc;
+extern Pixmap pixmap;
+extern Atom delWin;
+extern XEvent e;
+extern unsigned long gray[], colors[], spectrum[];
+
+typedef struct{
+	unsigned short int *image_16;
+	long *image_32;
+	XImage *screen;
+	int w, h, cx, cy;
+	unsigned long size;
+}IMG;
+
+int create_x(int, int, char*);
+int create_image(IMG *, int, int);
+
+void set_graymap();
+void set_colormap();
+void set_spectrum();
+
+void clear_image(IMG *img);
+void burn_image(IMG *img);
+void draw_buffer(int, int, int, int);
+
+void put_pixel(IMG *img, int, int, unsigned long);
+void put_apixel(IMG *img, int, int, unsigned long, float alpha);
+void draw_line (IMG *img, int x0, int y0, int x1, int y1, unsigned long c);
+
+void clear_buffer(int, int, int, int);
+void draw_image(IMG *img, int x, int y, int w, int h);
+

+ 24 - 0
demo/volume/src/main.c

@@ -0,0 +1,24 @@
+/*
+ * ALGO     : PROJ. : Volume
+ * RESEARCH : File  : main.c
+ *          : Date  : 20100531.0725UTC
+ *          : Email : mail@algoresearch.net
+ */
+
+#include <stdlib.h>
+
+#include "main.h"
+#include "space.h"
+#include "observer.h"
+
+int main()
+{
+	SYS_TABLE sys;
+
+	create_space (&sys, 320, 320, 320);
+	create_observer (&sys);
+	iterative_space (&sys);
+
+	return 0;
+}
+

+ 292 - 0
demo/volume/src/observer.c

@@ -0,0 +1,292 @@
+/*
+ * ALGO     : PROJ. : Volume
+ * RESEARCH : File  : observer.c
+ *          : Date  : 20100531.0725UTC
+ *          : Email : mail@algoresearch.net
+ */
+
+#include "main.h"
+#include "observer.h"
+
+IMG img;
+VERTEX coord[8], center;
+
+void create_window(SYS_TABLE *sys)
+{
+	XInitThreads();
+	create_x (sys->dw, sys->dh, "Volume VIZ");
+	create_image (&img, img.w, img.h);
+
+	set_colormap();
+	set_graymap();
+	set_spectrum();
+
+	clear_buffer(0, 0, sys->dw, sys->dh);
+}
+
+void set_env(SYS_TABLE *sys)
+{
+	sys->dw = 640;
+	sys->dh = 480;
+	sys->main = 1;
+
+	sys->ax = 1.2;
+	sys->ay = -2.7;
+	sys->c_ax = sys->ax;
+	sys->c_ay = sys->ay;
+
+	sys->a_sync = 0;
+	sys->motion = 1;
+	
+	img.w = sys->dw;
+	img.h = sys->dh;
+
+	img.cx = img.w / 2;
+	img.cy = img.h / 2;
+
+	center.x = sys->space_w / 2;
+	center.y = sys->space_h / 2;
+	center.z = sys->space_d / 2;
+
+	coord[0].x = 0;
+	coord[0].y = 0;
+	coord[0].z = 0;
+	coord[1].x = sys->space_w;
+	coord[1].y = 0;
+	coord[1].z = 0;
+	coord[2].x = 0;
+	coord[2].y = sys->space_h;
+	coord[2].z = 0;
+	coord[3].x = sys->space_w;
+	coord[3].y = sys->space_h;
+	coord[3].z = 0;
+	coord[4].x = sys->space_w;
+	coord[4].y = 0;
+	coord[4].z = sys->space_d; 
+	coord[5].x = 0;
+	coord[5].y = sys->space_h;
+	coord[5].z = sys->space_d;
+	coord[6].x = 0;
+	coord[6].y = 0;
+	coord[6].z = sys->space_d;
+	coord[7].x = sys->space_w;
+	coord[7].y = sys->space_h;
+	coord[7].z = sys->space_d;
+}
+
+int event_loop(SYS_TABLE *sys)
+{
+	while(XPending(dpy) || sys->main)
+	{
+		XNextEvent(dpy, &e);
+		switch(e.type)
+		{
+			case Expose:
+				if (!sys->display) draw_buffer (0, 0, sys->dw, sys->dh);
+			break;
+
+			case ClientMessage:
+				if (e.xclient.data.l[0] == delWin) sys->main = 0;
+			break;
+
+			case KeyPress:
+				if(XLookupKeysym(&e.xkey, 0) == XK_Escape) sys->main = 0;
+				if(XLookupKeysym(&e.xkey, 0) == XK_q) sys->main = 0;
+				if(XLookupKeysym(&e.xkey, 0) == XK_0)
+				{
+					sys->c_ax = 0; sys->c_ay = 0;
+					sys->a_sync = 1;
+					sys->display = 1;
+					sys->mapping = 1;
+				}
+				if(XLookupKeysym(&e.xkey, 0) == XK_Left)
+				{
+					sys->c_ay += .05;
+					sys->a_sync = 1;
+					sys->display = 1;
+					sys->mapping = 1;
+				}
+				if(XLookupKeysym(&e.xkey, 0) == XK_Right)
+				{
+					sys->c_ay -= .05;
+					sys->a_sync = 1;
+					sys->display = 1;
+					sys->mapping = 1;
+				}
+				if(XLookupKeysym(&e.xkey, 0) == XK_Up)
+				{
+					sys->c_ax -= .05;
+					sys->a_sync = 1;
+					sys->display = 1;
+					sys->mapping = 1;
+				}
+				if(XLookupKeysym(&e.xkey, 0) == XK_Down)
+				{
+					sys->c_ax += .05;
+					sys->a_sync = 1;
+					sys->display = 1;
+					sys->mapping = 1;
+				}
+			break;
+
+			case MotionNotify:
+				sys->display = 1;
+				sys->a_sync = 0;
+				if (sys->motion)
+				{
+					sys->mx = e.xmotion.x;
+					sys->my = e.xmotion.y;
+					sys->motion = 0;
+				}
+				sys->c_ay += (sys->mx - e.xmotion.x)*.01;
+				sys->c_ax += (sys->my - e.xmotion.y)*.01;
+				sys->mx = e.xmotion.x;
+				sys->my = e.xmotion.y;
+			break;
+
+			case ButtonRelease:
+				sys->a_sync = 1;
+				sys->motion = 1;
+				sys->mapping = 1;
+			break;
+
+			default:
+			break;
+		}
+		usleep(1200);
+	}
+	pthread_exit(NULL);
+	return 0;
+}
+
+void draw_status(SYS_TABLE *sys)
+{
+	char string[64];
+
+	XSetForeground(dpy, gc, gray[200]);
+
+	sprintf(string, "Space size: %d*%d*%d",
+		sys->space_w, sys->space_h, sys->space_d);
+	XDrawString (dpy, pixmap, gc, 5, 15, string, strlen(string));
+
+	sprintf(string, "Iterations: %d", sys->iter);
+	XDrawString (dpy, pixmap, gc, 5, 30, string, strlen(string));
+}
+
+void draw_coord(SYS_TABLE *sys)
+{
+	int i;
+	VERTEX out[8];
+
+	XSetForeground(dpy, gc, colors[255]);
+
+	for (i=0; i<8; i++)
+	{
+		rotate_xy (&coord[i], &out[i], sys->c_ax, sys->c_ay, &center);
+
+		out[i].x += img.cx;
+		out[i].y += img.cy;
+
+		XDrawLine
+			(dpy, pixmap, gc, out[i].x-3, out[i].y-3, out[i].x+3, out[i].y+3);
+		XDrawLine
+			(dpy, pixmap, gc, out[i].x+3, out[i].y-3, out[i].x-3, out[i].y+3);
+	}
+
+		XDrawLine (dpy, pixmap, gc, out[0].x, out[0].y, out[1].x, out[1].y);
+		XDrawLine (dpy, pixmap, gc, out[0].x, out[0].y, out[2].x, out[2].y);
+		XDrawLine (dpy, pixmap, gc, out[0].x, out[0].y, out[6].x, out[6].y);
+}
+
+void display(SYS_TABLE *sys)
+{
+	while(sys->main)
+	{
+		if (sys->display)
+		{
+			draw_image (&img, 0, 0, sys->dw, sys->dh);
+
+			draw_status (sys);
+			draw_coord (sys);
+
+			draw_buffer (0, 0, sys->dw, sys->dh);
+			sys->display = 0;
+		}
+		usleep(1000);
+	}
+	pthread_exit(NULL);
+}
+
+void mapping(SYS_TABLE *sys)
+{
+	int x, y, z;
+	VERTEX in, out;
+	float alpha;
+
+	clear_image (&img);
+
+	if (sys->a_sync)
+	{
+		sys->ax = sys->c_ax;
+		sys->ay = sys->c_ay;
+		sys->a_sync = 0;
+	}
+
+	for(z=0; z<sys->space_d; z++)
+	{
+		for(y=0; y<sys->space_h; y++)
+		{
+			for(x=0; x<sys->space_w; x++)
+			{
+				in.x = x;
+				in.y = y;
+				in.z = z;
+
+				rotate_xy (&in, &out, sys->ax, sys->ay, &center);
+
+				//put_pixel (&img, out.x + img.cx, out.y + img.cy,
+				//	colors[cell_get(sys, x, y, z)]);
+
+				alpha = cell_get(sys, x, y, z) / 4080.0;
+				put_apixel (&img, out.x + img.cx, out.y + img.cy,
+					colors[cell_get(sys, x, y, z)], alpha);
+			}
+		}
+		if (!(z%4)) sys->display = 1;
+		if (!sys->main) return;
+
+		usleep(120);
+
+		//if (!(z%2)) burn_image (&img);
+	}
+	sys->display = 1;
+}
+
+void observer(SYS_TABLE *sys)
+{
+	while(sys->main)
+	{
+		if (sys->mapping)
+		{
+			mapping (sys);
+			sys->mapping = 0;
+		}
+		usleep(1000);
+	}
+	pthread_exit(NULL);
+}
+
+void create_observer(SYS_TABLE *sys)
+{
+	set_env (sys);
+	create_window (sys);
+
+	if(pthread_create(&(sys->pid_observer),   NULL, (void *)observer,   sys)|
+		pthread_create(&(sys->pid_display),    NULL, (void *)display,    sys)|
+		pthread_create(&(sys->pid_event_loop), NULL, (void *)event_loop, sys))
+	{
+		perror("pthread_create()");
+		exit(1);
+	}
+}
+

+ 112 - 0
demo/volume/src/space.c

@@ -0,0 +1,112 @@
+/*
+ * ALGO     : PROJ. : Volume
+ * RESEARCH : File  : space.c
+ *          : Date  : 20100531.0725UTC
+ *          : Email : mail@algoresearch.net
+ */
+
+#include "main.h"
+#include "space.h"
+
+int adds(SYS_TABLE *sys, int x, int y, int z)
+{
+	if (x < 0) x += sys->space_w;
+	if (y < 0) y += sys->space_h;
+	if (z < 0) z += sys->space_d;
+	if (x >= sys->space_w) x -= sys->space_w;
+	if (y >= sys->space_h) y -= sys->space_h;
+	if (z >= sys->space_d) z -= sys->space_d;
+
+	return sys->size_plane * z + sys->space_h * y + x;
+}
+
+void cell_overlap(SYS_TABLE *sys, int v, int x, int y, int z)
+{
+
+}
+
+void cell_set(SYS_TABLE *sys, int v, int x, int y, int z)
+{
+	sys->space_i[adds(sys,x,y,z)] = v;
+}
+
+int cell_get(SYS_TABLE *sys, int x, int y, int z)
+{
+	return sys->space_i[adds(sys, x, y, z)];
+}
+
+void init_space(SYS_TABLE *sys)
+{
+	int x, y, z;
+
+	for(z=0; z<sys->space_d; z++)
+		for(y=0; y<sys->space_h; y++)
+			for(x=0; x<sys->space_w; x++)
+			{
+				sys->space_i[adds(sys,x,y,z)] = 2;
+				sys->space_o[adds(sys,x,y,z)] = sys->space_i[adds(sys,x,y,z)];
+			}
+}
+
+void create_space(SYS_TABLE *sys, int w, int h, int d)
+{
+	sys->space_w = w;
+	sys->space_h = h;
+	sys->space_d = d;
+	sys->size_plane = w * h;
+	sys->size_space = w * h * d;
+
+	sys->space_i = malloc(sys->size_space * sizeof(int));
+	sys->space_o = malloc(sys->size_space * sizeof(int));
+
+	init_space (sys);
+}
+
+void julia_set(SYS_TABLE *sys)
+{
+	int c, x, y, z;
+
+	float d, dx, dy, x0, y0, z0, q = 0.1, radius, zr, zi;
+
+	d = 2 / 320.0;
+
+	for (z=0; z<320; z++)
+	{
+		z0 = z * d - 1.5;
+		for (y = 0; y < 320; y++)
+		{
+			y0 = y * d - 1;
+			for(x = 0; x < 320; x++)
+			{
+				x0 = x * d - 1;
+
+				dx = x0; dy = y0, c = 0;
+				do
+				{
+					zr = dx * dx - dy * dy + z0;
+					zi = 2.0 * dx * dy + q;
+					dx = zr; dy = zi;
+
+					radius = zr * zr + zi * zi;
+					c++;
+				}while(radius < 64 && c < 64);
+
+				sys->space_i[adds(sys, x, y, z)] = c * 4 -1;
+			}
+		}
+	}
+}
+
+void iterative_space (SYS_TABLE *sys)
+{
+	sys->iter = 0;
+
+	julia_set(sys);
+	sys->mapping = 1;
+
+	while(sys->main)
+	{
+		usleep(1200);
+	}
+}
+

+ 21 - 0
demo/volume/src/transform.c

@@ -0,0 +1,21 @@
+/*
+ * ALGO     : PROJ. : Volume
+ * RESEARCH : File  : transform.c
+ *          : Date  : 20100531.0725UTC
+ *          : Email : mail@algoresearch.net
+ */
+
+#include "transform.h"
+
+void rotate_xy(VERTEX *in, VERTEX *out, float ax, float ay, VERTEX *offset)
+{
+	float x = in->x - offset->x,
+		  y = in->y - offset->y,
+		  z = in->z - offset->z,
+		  Cax = cos(ax),
+		  Sax = sin(ax);
+
+	out->y = y * Cax - z * Sax;
+	out->z = y * Sax + z * Cax;
+	out->x = out->z * sin(ay) + x * cos(ay);
+}

+ 306 - 0
demo/volume/src/x.c

@@ -0,0 +1,306 @@
+/*
+ * ALGO     : PROJ. : Volume
+ * RESEARCH : File  : x.c
+ *          : Date  : 20100531.0725UTC
+ *          : Email : mail@algoresearch.net
+ */
+
+#include "x.h"
+
+Display *dpy;
+GC gc, gc_out;
+Colormap xcolors;
+Atom delWin;
+XEvent e;
+
+int d_depth;
+Window d;
+Pixmap pixmap;
+XSetWindowAttributes window_attributes;
+XColor color;
+unsigned long gray[0x100], colors[0x100], spectrum[0x400];
+
+int create_x(int scr_w, int scr_h, char title[64])
+{
+	int s_number;
+	if (!(dpy=XOpenDisplay(NULL)))
+	{
+		perror("XOpenDisplay");
+		return -1;
+	}
+
+	s_number = DefaultScreen (dpy);
+	d_depth = DefaultDepth (dpy, s_number);
+	window_attributes.border_pixel = BlackPixel (dpy, s_number);
+	window_attributes.background_pixel = BlackPixel (dpy, s_number);
+	window_attributes.override_redirect = 0;
+
+	d = XCreateWindow
+	(
+		dpy, 
+		DefaultRootWindow (dpy), 
+		0, 0,
+		scr_w, scr_h, 
+		0, 
+		d_depth, 
+		InputOutput, 
+		CopyFromParent, 
+		CWBackPixel | CWBorderPixel,
+		&window_attributes
+	);
+
+	xcolors = DefaultColormap(dpy, s_number);
+	XSetWindowColormap(dpy, d, xcolors);
+
+	gc = XCreateGC (dpy, d, 0, NULL);
+	gc_out = XCreateGC (dpy, d, 0, NULL);
+
+	XSetStandardProperties(dpy, d, title, title, None, 0, 0, None);
+
+	XSelectInput
+	(
+		dpy, d,
+		ExposureMask | 
+		KeyPressMask | 
+		ButtonPressMask | ButtonReleaseMask | 
+		Button1MotionMask |Button2MotionMask |
+		StructureNotifyMask
+	);
+
+	delWin = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
+	XSetWMProtocols(dpy, d, &delWin, 1);
+
+	XMapWindow (dpy, d);
+	while(!(e.type == MapNotify)) XNextEvent(dpy, &e);
+
+	pixmap = XCreatePixmap(dpy, d, scr_w, scr_h, d_depth);
+ 
+	XSetFillStyle (dpy, gc_out, FillTiled);
+	XSetTile (dpy, gc_out, pixmap);
+
+	return 0;
+}
+
+void set_graymap()
+{
+	int i;
+	for(i=0;i<0x100;i++)
+	{
+		color.red = 0x100 * i;
+		color.green = 0x100 * i;
+		color.blue = 0x100 * i;
+			XAllocColor(dpy, xcolors, &color);
+		gray[i] = color.pixel;
+	}
+}
+
+void set_colormap()
+{
+	int i;
+	for(i=0;i<0x100;i++)
+	{
+		color.red = 0x100 * i;
+		color.green = 0x100 * abs(128-i);
+		color.blue = 0x100 * (0xff-i);
+			XAllocColor(dpy, xcolors, &color);
+		colors[i] = color.pixel;
+	}
+}
+
+void create_image_16(IMG *img, int w, int h)
+{
+	img->image_16 = (unsigned short int *) malloc (w * h * 2);
+	img->screen = XCreateImage (dpy, CopyFromParent, d_depth, ZPixmap, 0,
+		(char*)img->image_16, w, h, 16, w * 2);
+	memset(img->image_16, 0x00, w * h * 2);
+}
+
+void create_image_32(IMG *img, int w, int h)
+{
+	img->image_32 = (long *) malloc (w * h * 4);
+	img->screen = XCreateImage (dpy, CopyFromParent, d_depth, ZPixmap, 0,
+		(char*)img->image_32, w, h, 32, w * 4);
+	memset(img->image_32, 0x00, w * h * 4);
+}
+
+int create_image(IMG *img, int w, int h)
+{
+	img->w = w; img->h = h;
+
+	if (d_depth == 8 || d_depth == 16)
+	{
+		create_image_16 (img, w, h);
+		img->size = w * h * 2;
+	}
+	else if(d_depth == 24 || d_depth == 32)
+	{
+		create_image_32 (img, w, h);
+		img->size = w * h * 4;
+	}
+	else
+	{
+		fprintf (stderr, "This is not a supported depth. %d\n",d_depth);
+		return -1;
+	}
+	return 0;
+}
+
+void clear_image(IMG *img)
+{
+	if (d_depth == 8 || d_depth == 16)
+		memset(img->image_16, 0x00, img->size);
+
+	else if(d_depth == 24 || d_depth == 32)
+		memset(img->image_32, 0x00, img->size);
+}
+
+void burn_image(IMG *img)
+{
+	int i, n = img->w * img->h;
+	unsigned long c;
+	unsigned int r, g, b;
+
+	for (i=0; i<n; i++)
+	{
+		c = img->image_32[i];
+
+		r = c >> 16;
+		g = (c & 0x00ff00) >> 8;
+		b = c & 0x0000ff;
+
+		if (r > 0) r--;
+		if (g > 0) g--;
+		if (b > 0) b--;
+
+		img->image_32[i] = (r << 16) | (g << 8) | b;
+	}
+}
+
+void clear_buffer(int x, int y, int w, int h)
+{
+	XSetForeground(dpy, gc, 0);
+	XFillRectangle(dpy, pixmap, gc, x, y, w, h);
+}
+
+void draw_buffer(int x, int y, int w, int h)
+{
+	XFillRectangle (dpy, d, gc_out, x, y, w, h);
+	XFlush(dpy);
+}
+
+void draw_image(IMG *img, int x, int y, int w, int h)
+{
+	XPutImage(dpy, pixmap, gc, img->screen, 0, 0, x, y, w, h);
+}
+
+void put_pixel(IMG *img, int x, int y, unsigned long c)
+{
+	if (x<0 || y<0) return;
+	if (x>=img->w || y>=img->h) return;
+	XPutPixel(img->screen, x, y, c);
+}
+
+void put_apixel(IMG *img, int x, int y, unsigned long fg, float alpha)
+{
+	unsigned int fR, fG, fB, bR, bG, bB;
+	unsigned long bg, c;
+	float v = 1 - alpha;
+
+	if (x<0 || y<0) return;
+	if (x>=img->w || y>=img->h) return;
+
+	bg = XGetPixel(img->screen, x, y);
+
+	bR = bg >> 16;
+	bG = (bg & 0x00ff00) >> 8;
+	bB = bg & 0x0000ff;
+
+	fR = fg >> 16;
+	fG = (fg & 0x00ff00) >> 8;
+	fB = fg & 0x0000ff;
+
+	c = ((unsigned int)(fR * alpha + bR * v) << 16) |
+		 ((unsigned int)(fG * alpha + bG * v) <<  8) |
+		  (unsigned int)(fB * alpha + bB * v);
+
+	XPutPixel(img->screen, x, y, c);
+}
+
+void draw_line (IMG *img, int x0, int y0, int x1, int y1, unsigned long c)
+{
+	int dy = y1 - y0;
+	int dx = x1 - x0;
+	int stepx, stepy;
+	int fraction;
+
+	if (dy < 0) { dy = -dy;  stepy = -1; } else stepy = 1;
+	if (dx < 0) { dx = -dx;  stepx = -1; } else stepx = 1;
+
+	dy <<= 1;
+	dx <<= 1;
+
+	put_pixel(img, x0, y0, c);
+
+	if (dx > dy)
+	{
+		fraction = dy - (dx >> 1);
+		while (x0 != x1)
+		{
+			if (fraction >= 0)
+			{
+				y0 += stepy;
+				fraction -= dx;
+			}
+
+			x0 += stepx;
+			fraction += dy;
+			put_pixel(img, x0, y0, c);
+		}
+	}
+	else
+	{
+		fraction = dx - (dy >> 1);
+		while (y0 != y1)
+		{
+			if (fraction >= 0)
+			{
+				x0 += stepx;
+				fraction -= dy;
+			}
+			y0 += stepy;
+			fraction += dx;
+			put_pixel(img, x0, y0, c);
+		}
+	}
+}
+
+void set_spectrum()
+{
+	int i;
+	for(i=0; i<0x100; i++)
+	{
+		color.red   = 0xff00;
+		color.green = 0x100 * i;
+		color.blue  = 0;
+			XAllocColor (dpy, xcolors, &color);
+		spectrum[i] = color.pixel;
+
+		color.red   = 0x100 * (0xff-i);
+		color.green = 0xff00;
+		color.blue  = 0;
+			XAllocColor (dpy, xcolors, &color);
+		spectrum[i+0x100] = color.pixel;
+
+		color.red   = 0;
+		color.green = 0xff00;
+		color.blue  = 0x100 * i;
+			XAllocColor (dpy, xcolors, &color);
+		spectrum[i+0x200] = color.pixel;
+
+		color.red   = 0;
+		color.green = 0x100 * (0xff-i);
+		color.blue  = 0xff00;
+			XAllocColor (dpy, xcolors, &color);
+		spectrum[i+0x300] = color.pixel;
+	}
+}