1 #include <math.h>
2 #include <signal.h>
3
4 #include <stdlib.h> /* for getenv.. (would be nice to remove this) */
5 #include <stdio.h> /* For printf - again, nice to remove this */
6 #include "gfx-x.h" /* essential - ish. */
7 #include "string.h" /* for ffs (find first set) */
8
9 #ifdef DEBUG
10 static void xdbg_Dump_Ximage_Struct(XImage *);
11 static void xdbg_Print_Visual_Info(XVisualInfo *v);
12 #endif /* DEBUG */
13
14 #ifdef DEBUG
15 #define LEFT_EDGE24 0x00ff00
16 #define RIGHT_EDGE24 0x00ff00
17 #define BOTTOM_EDGE24 0x0000ff
18 #else
19 /* Colors to use for left and right edges of image :
20 handy to set these to something like red and green
21 for debugging : have to know r/g/b masks though */
22 #define BOTTOM_EDGE24 0x00ff00
23 #define LEFT_EDGE24 0x00ff00
24 #define RIGHT_EDGE24 0x00ff00
25 #endif
26
27 static void generic_render(Gfx *);
28 extern void render32(Gfx *);
29
render32_alt(Gfx * g)30 void render32_alt(Gfx *g) {
31 #define IMGDATATYPE unsigned int
32 unsigned long *cmap = g->simple_map; // not in a register
33 IMGDATATYPE *edi = (IMGDATATYPE *)g->xim->data; // think.. EDI = errr destination image.
34 unsigned char *ibuff = g->cbuffer; // think.. ESI = errr source image
35 int y = g->xim->height - 2; // THIS ISN'T IN A REGISTER.. WE'VE RUN OUT OF THEM! =(
36 int width = g->xres;
37 int ebx = width-2;
38
39 ibuff--; // because these really are +1 at start and end of line this
40 edi--; // just lets it do a +2 at the start of each horizontal loop
41
42 do {
43 ibuff += 2;
44 ebx = width;
45 edi += 2;
46 ebx -= 2;
47 do { // this loop uses: eax, ibuff, line, cmap, width
48 register int eax;
49 eax = *(ibuff - 1 - width);
50 eax += *(ibuff + 1 - width);
51 eax += *(ibuff - 1);
52 eax += *(ibuff + 1);
53 eax >>= 2;
54 *edi++ = cmap[eax];
55 *ibuff++=eax;
56 } while (--ebx);
57 } while (--y);
58
59 edi++; ibuff++; ebx=width;
60
61 do {
62 *edi++ = 0;
63 } while (--ebx) ;
64 }
65
66
doloop(unsigned char * esi,int height,int width,IMGDATATYPE * edi,unsigned long * cmap)67 void doloop(unsigned char *esi, int height, int width, IMGDATATYPE * edi, unsigned long *cmap) {
68 while (--height) {
69 register int width2 = width - 2;
70 while (width2--) {
71 register int eax = *(esi);
72 eax += *(esi+width-1);
73 eax += *(esi+width);
74 eax += *(esi+width+1);
75 eax -= eax&1;
76 eax >>= 2;
77 *esi++ = eax;
78 *edi++ = cmap[eax]; // FIXME !
79 }
80 esi+=2;
81 edi+=2;
82 }
83 while (width--) *esi++ >>= 1;
84 }
85
render32_norm(Gfx * g)86 void render32_norm(Gfx *g) {
87 register unsigned long *cmap = g->simple_map; // not in a register
88 register IMGDATATYPE *edi = (IMGDATATYPE *)g->xim->data +1; // think.. EDI = errr destination image.
89 register unsigned char *esi = g->cbuffer + 1; // think.. ESI = errr source image
90 register int width = g->xres;
91 register int height = g->yres;
92 doloop(esi, height, width, edi, cmap);
93 }
94
95
generic_render(Gfx * g)96 static void generic_render(Gfx *g) {
97 /* This is 'quite' slow really!! */
98 int x,y;
99 unsigned char *buff = g->cbuffer;
100 int acc =0;
101 #ifdef DEBUG
102 printf("Using default unaccelerated (poor performance) render routine\n");
103 #endif
104 for( y = 0; y < (g->yres -1 ) ; y++) {
105 for( x = 1; x < (g->xres - 1); x++) {
106 /* This is a poor fire effect really */
107 /* for a start it's munging itself up */
108 /* i.e. writing over bits of this frame that */
109 /* it will use again before it's finished this frame */
110 /* This could probably be fixed quite easily. */
111 acc= (buff[-1]+buff[0]+buff[1]+buff[g->xres])>>2;
112 *buff++ = acc;
113 XPutPixel(g->xim, x, y, g->simple_map[acc]);
114 }
115 buff+=2; /* skip first and last pixels on a line. */
116 /* why.. they are zero. */
117 }
118
119 for (x=1; x< g->xres;x++) {
120 *buff++ >>= 1;
121 }
122 }
123
render_blurred_buffer(Gfx * g)124 void render_blurred_buffer(Gfx *g) {
125 switch (g->xim->bits_per_pixel) {
126 case 32: if (g->renderer==1) render32_alt(g); else render32_norm(g); break;
127 default: generic_render(g); break;
128 }
129 }
130
setup_back_buff(Gfx * g)131 int setup_back_buff(Gfx *g) {
132 g->cbuffer=(unsigned char *)malloc(g->xres * g->yres * sizeof(unsigned char));
133 memset((void *)g->cbuffer,0,g->xres*g->yres); /* unecessary */
134 return (g->cbuffer!=0);
135 }
136
137 #ifdef DEBUG
check_buff(Gfx * g)138 void check_buff(Gfx *g) {
139 int left , right , y;
140 /* This checks that neither the left or right extents in a buffer */
141 /* have been set to anything other than zero! */
142 for (y=0; y<g->yres; y++) {
143 left = *(g->cbuffer + (y * g->xres));
144 right = *(g->cbuffer + (y * g->xres) + g->xres -1);
145 if ( left !=0 )
146 printf("Buffer %3d,%3d = %3d\n", 0, y, left);
147
148 if ( right !=0 )
149 printf("Buffer %3d,%3d = %3d\n", g->xres -1 ,y, right);
150 }
151 fprintf(stderr, "Did a full check of buffer extents\n");
152 }
153 #endif
154
gfx_display_image(Gfx * g)155 void gfx_display_image(Gfx *g) {
156 #ifdef USE_XSHM_EXT
157 XShmPutImage(g->dpy,g->win,g->gc,g->xim,0,0,g->xoff,g->yoff,g->xres,g->yres, False);
158 #else
159 XPutImage(g->dpy,g->win,g->gc,g->xim,0,0,g->xoff,g->yoff,g->xres,g->yres);
160 #endif
161
162 XSync(g->dpy,False);
163 }
164
gfx_create_cmap(Gfx * gf)165 void gfx_create_cmap(Gfx *gf) {
166 int R_max, R_shft, G_max, G_shft, B_max, B_shft, ent;
167 double aimr, aimg, aimb, nr, ng, nb;
168
169 R_max = gf->xim->red_mask >> (R_shft = ffs(gf->xim->red_mask) - 1);
170 G_max = gf->xim->green_mask >> (G_shft = ffs(gf->xim->green_mask) - 1);
171 B_max = gf->xim->blue_mask >> (B_shft = ffs(gf->xim->blue_mask) - 1);
172
173 aimr = ((gf->base_colour & 0xFF0000) >> 16)/255.0;
174 aimg = ((gf->base_colour & 0x00FF00) >> 8)/255.0;
175 aimb = (gf->base_colour & 0x0000FF)/255.0;
176
177 nr = 10 * (1-aimr) + 1;
178 ng = 10 * (1-aimg) + 1;
179 nb = 10 * (1-aimb) + 1;
180
181 for (ent=0; ent<256; ent++) {
182 int r,g,b;
183 double entp=ent/255.0;
184 r = (int)(R_max * pow(entp,nr));
185 g = (int)(G_max * pow(entp,ng));
186 b = (int)(B_max * pow(entp,nb));
187 gf->simple_map[ent] = ( (r<<R_shft) |
188 (g<<G_shft) |
189 (b<<B_shft) );
190 }
191 }
192
193 // in header file we now have - rather than the function
194 //#define GFX_ADD_PIXEL(G,X,Y,P) G->cbuffer[X+Y*G->xres]=P
195
WaitForNotify(Display * d,XEvent * e,XPointer arg)196 static Bool WaitForNotify(Display *d, XEvent *e, XPointer arg) {
197 return ( (e->type == MapNotify) && (e->xmap.window == (Window)arg) );
198 }
199
gfx_cleanup(Gfx * g)200 void gfx_cleanup(Gfx *g) {
201 #ifdef USE_XSHM_EXT
202 XShmDetach (g->dpy, &(g->shminfo));
203 XDestroyImage (g->xim);
204 shmdt (g->shminfo.shmaddr);
205 shmctl (g->shminfo.shmid, IPC_RMID, 0);
206 #else
207 printf("Not cleaning up anything... ! Yikes!\n");
208 XDestroyImage(g->xim);
209 #endif
210
211 if ( g->win != RootWindow(g->dpy, g->xvs.screen) )
212 XFreeGC(g->dpy, g->gc);
213
214 /* Only free the GC if it wasn't the default GC on the root window */
215
216 XCloseDisplay(g->dpy);
217 /* put back final fps details */
218 }
219
gfx_setup_ximage(Gfx * g)220 int gfx_setup_ximage(Gfx *g) {
221 #ifdef USE_XSHM_EXT
222 g->xim=
223 XShmCreateImage(g->dpy, g->xvs.visual, g->xvs.depth, ZPixmap,
224 (char *)NULL , &(g->shminfo), g->xres, g->yres);
225
226 if (!g->xim) {
227 fprintf(stderr, "Unable to create a shared memory image %dx%d in size, check kern.ipc.shmmax\n", g->xres, g->yres);
228 return 0;
229 /* FIXME SHOULD CLEAN UP AND FALL BACK TO NORMAL IMAGES */
230 }
231
232 g->shminfo.shmid=shmget(IPC_PRIVATE,g->xim->bytes_per_line * g->xim->height, IPC_CREAT|0777);
233
234 if (g->shminfo.shmid == -1) {
235 fprintf(stderr, "Could not create a shared memory segment\n");
236 /* FIXME SHOULD CLEAN UP AND FALL BACK TO NORMAL IMAGES */
237 return 0;
238 }
239
240 fprintf(stderr, "Created Shared memory segment ID: %d\n", g->shminfo.shmid);
241
242 g->shminfo.shmaddr = g->xim->data = shmat (g->shminfo.shmid, 0, 0);
243 /* FIXME: THIS COULD RETURN -1 fail code- SHOULD FALL BACK TO NORMAL IMAGES */
244 fprintf(stderr, "Have attached shm segment at %p\n", g->shminfo.shmaddr);
245
246 g->shminfo.readOnly = False;
247 if (!XShmAttach (g->dpy, &(g->shminfo))) {
248 fprintf(stderr,"XServer failed to attache to shared memory segment\n");
249 /* FIXME SHOULD CLEAN UP AND FALL BACK TO NORMAL IMAGES */
250 return 0;
251 }
252 #else
253 g->xim = XCreateImage (g->dpy, g->xvs.visual, g->xvs.depth, ZPixmap,
254 0, (char *) NULL, g->xres, g->yres, 32, 0);
255 g->xim->data = (char *) calloc(g->xim->height, g->xim->bytes_per_line);
256 #endif
257 return (g->xim && g->xim->data && setup_back_buff(g));
258 }
259
constrain_res(int * x,int minx,int maxx,int dfltx,int * y,int miny,int maxy,int dflty)260 int constrain_res(int *x, int minx, int maxx, int dfltx, int *y, int miny, int maxy, int dflty) {
261 int constrained=0;
262 if ( (*x < minx ) || (*x > maxx)) {
263 #ifdef DEBUG
264 fprintf(stderr, "Horizontal res (%d), out of bounds %d -> %d, resetting to %d\n",
265 *x, minx, maxx, dfltx);
266 #endif
267 *x=dfltx;
268 constrained=1;
269 }
270
271 if ( (*y < miny ) || ( *y > maxy)) {
272 #ifdef DEBUG
273 fprintf(stderr, "Horizontal res (%d), out of bounds %d -> %d, resetting to %d\n",
274 *y, miny, maxy, dflty);
275 #endif
276 *y= dflty;
277 constrained=1;
278 }
279 return constrained;
280 }
281
gfx_SetupGfx(Gfx * g)282 int gfx_SetupGfx(Gfx *g) {
283 char *displayname;
284 XEvent xev;
285
286 displayname = getenv("DISPLAY");
287
288 if (!(g->dpy = XOpenDisplay(displayname))) {
289 fprintf(stderr,"Unable to open display %s\n",displayname);
290 return 0;
291 }
292
293 if ( !(XMatchVisualInfo(g->dpy, DefaultScreen(g->dpy), 32, TrueColor, &(g->xvs)) ||
294 XMatchVisualInfo(g->dpy, DefaultScreen(g->dpy), 24, TrueColor, &(g->xvs)) ||
295 XMatchVisualInfo(g->dpy, DefaultScreen(g->dpy), 16, TrueColor, &(g->xvs)) ||
296 XMatchVisualInfo(g->dpy, DefaultScreen(g->dpy), 8, TrueColor, &(g->xvs)) )) {
297 fprintf(stderr,"Unable to get a suitable visual\n");
298 fprintf(stderr,"A 32,24,16 or 8 bit TrueColor display is required.\n");
299 return 0;
300 }
301
302 #ifdef DEBUG
303 xdbg_Print_Visual_Info(&(g->xvs));
304 #endif
305
306 g->win= RootWindow(g->dpy, g->xvs.screen);
307
308 if (!g->rootwin) {
309 XSetWindowAttributes swa;
310 swa.event_mask = StructureNotifyMask | KeyPressMask | ButtonPressMask | PointerMotionMask;
311 swa.backing_store = False;
312 swa.background_pixel = swa.border_pixel = BlackPixel(g->dpy, g->xvs.screen ) ;
313 swa.save_under = False;
314 /* Added a colormap so that it still works in 8bpp modes.
315 for some reason without it it was always getting a BadMatch.. hmm! */
316 swa.colormap = XCreateColormap( g->dpy , g->win , g->xvs.visual, AllocNone );
317
318 constrain_res(&(g->xres), 16, 4096, g->default_xres, &(g->yres), 16, 4096, g->default_yres);
319
320 g->win = XCreateWindow(g->dpy, g->win, 0, 0, g->xres, g->yres,
321 0, g->xvs.depth, InputOutput, g->xvs.visual,
322 CWBackPixel | CWEventMask | CWBorderPixel |
323 CWColormap | CWBackingStore | CWSaveUnder, &swa);
324
325 if (!g->win) {fprintf(stderr,"Unable to create window\n"); return 0; }
326 if (!XMapWindow(g->dpy, g->win)) {fprintf(stderr,"Unable to map windows\n"); return 0; }
327
328 XSync(g->dpy,0); /* okay, we probably shouldn't do that */
329 XStoreName(g->dpy, g->win, "glurbules" );
330 XIfEvent(g->dpy, &xev, WaitForNotify, (XPointer)(g->win));
331
332 /* Hello Houston, this is Xlib calling, we have got somewhere at last */
333 g->gc = XCreateGC(g->dpy,g->win, 0, 0);
334 g->xoff = 0;
335 g->yoff =0;
336 }
337 else {
338 g->gc = DefaultGC(g->dpy,DefaultScreen(g->dpy));
339 Screen *screen = ScreenOfDisplay(g->dpy, DefaultScreen(g->dpy));
340 int h,w;
341 h=HeightOfScreen(screen);
342 w=WidthOfScreen(screen);
343 constrain_res(&(g->xres), 16, 4096, w, &(g->yres), 16, 4096,(((h>>8)-1)<<8) );
344 if ((g->xres == 0) && (g->yres == 0)) {
345 /* neither are set, just set them to default values */
346 g->xres=g->default_xres;
347 g->yres=g->default_yres;
348 }
349 g->yoff = (HeightOfScreen(screen) - g->yres)/2;
350 g->xoff = (WidthOfScreen(screen) - g->xres)/2;
351 #ifdef DEBUG
352 printf("Xoff set to %d\n", g->xoff);
353 printf("Yoff set to %d\n", g->yoff);
354 #endif
355 }
356
357 if (!gfx_setup_ximage(g)) {
358 return 0;
359 }
360
361 gfx_create_cmap(g);
362 /* This doesn't work in certain bitdepths */
363 /* memset((void *)g->xim->data,0,g->xres*g->yres*4); erase the image */
364 #ifdef DEBUG
365 xdbg_Dump_Ximage_Struct(g->xim);
366 #endif
367 return 1;
368 }
369
gfx_getkey(Gfx * g)370 int gfx_getkey(Gfx *g) {
371 XEvent xev;
372 char c;
373 // Just return keypresses.
374 if (XCheckWindowEvent(g->dpy, g->win, KeyPressMask, &xev)) {
375 XLookupString((XKeyEvent *)&xev, &c, 1, NULL , NULL);
376 return c;
377 }
378 return 0;
379 }
380
381 /* The rest of the file is unexciting debug routines.
382 or dumping structures out etc. */
383
384 #ifdef DEBUG
xdbg_Print_Visual_Info(XVisualInfo * v)385 static void xdbg_Print_Visual_Info(XVisualInfo *v) {
386 printf("Visual Information:\n");
387 printf("Depth : %d\n", v->depth);
388 printf("bits per rgb : %d\n", v->bits_per_rgb);
389 printf("VisualID : %ld\n", v->visualid);
390 printf("Screen : %d\n", v->screen);
391 printf("Class : ");
392
393 switch(v->class) {
394 case (TrueColor) : printf ("TrueColor\n"); break;
395 case (DirectColor) : printf ("DirectColor\n"); break;
396 case (PseudoColor) : printf ("PsuedoColor\n"); break;
397 case (GrayScale) : printf ("GrayScale\n"); break;
398 default : printf(" %d (unknown type)\n", v->class);
399 }
400
401 printf("Red mask : %03lx\n", v->red_mask);
402 printf("Green mask : %lx\n", v->green_mask);
403 printf("Blue mask : %lx\n", v->blue_mask);
404 printf("Colormap Size: %d\n", v->colormap_size);
405 }
406
xdbg_Dump_Ximage_Struct(XImage * xim)407 static void xdbg_Dump_Ximage_Struct(XImage *xim) {
408 printf("---DUMP OF XImage Structure %p\n", xim);
409 printf("width = %d\n",xim->width);
410 printf("height = %d\n",xim->height);
411 printf("xoffset = %d\n",xim->xoffset);
412 printf("format = %d\n",xim->format);
413 printf("data = %p\n",xim->data);
414 printf("byte_order = %d\n",xim->byte_order);
415 printf("bitmap_unit = %d\n",xim->bitmap_unit);
416 printf("bitmap_bit_order = %d\n",xim->bitmap_bit_order);
417 printf("bitmap_pad = %d\n",xim->bitmap_pad);
418 printf("depth = %d\n",xim->depth);
419 printf("bytes_per_line = %d\n",xim->bytes_per_line);
420 printf("bits_per_pixel = %d\n",xim->bits_per_pixel);
421 printf("red_mask = %06lx\n",xim->red_mask);
422 printf("green_mask = %06lx\n",xim->green_mask);
423 printf("blue_mask = %06lx\n",xim->blue_mask);
424 printf("obdata = %p\n",xim->obdata);
425 printf("f.create_image = %p\n",xim->f.create_image);
426 printf("f.destroy_image = %p\n",xim->f.destroy_image);
427 printf("f.get_pixel = %p\n",xim->f.get_pixel);
428 printf("f.put_pixel = %p\n",xim->f.put_pixel);
429 printf("f.sub_image = %p\n",xim->f.sub_image);
430 printf("f.add_pixel = %p\n",xim->f.add_pixel);
431
432 /* Useful to have for debugging : */
433 printf ("Size of unsigned long %d\n", sizeof(unsigned long));
434 printf ("Size of long %d\n", sizeof(long));
435 printf ("Size of int %d\n", sizeof(int));
436 printf ("Size of unsigned int %d\n", sizeof(unsigned int));
437 /* on an Intel machine these are all 4 bytes long (32bit cpu) */
438 /* but given a different architecture they may be different ? */
439 }
440 #endif /* DEBUG */
441
442
443
444