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