Move .cvsignore to .gitignore.
[free-sw/xcb/demo] / tests / flames.c
1 /*****************************************************************************/
2 /*                                  XCB Flame                                */
3 /*****************************************************************************/
4 /* Originally By:                                                            */
5 /*     The Rasterman (Carsten Haitzler)                                      */
6 /*      Copyright (C) 1996                                                   */
7 /*****************************************************************************/
8 /* XcB port:                                                                 */
9 /*     d'Oursse (Vincent TORRI), 2006                                        */
10 /*****************************************************************************/
11 /* This code is Freeware. You may copy it, modify it or do with it as you    */
12 /* please, but you may not claim copyright on any code wholly or partly      */
13 /* based on this code. I accept no responisbility for any consequences of    */
14 /* using this code, be they proper or otherwise.                             */
15 /*****************************************************************************/
16 /* Okay, now all the legal mumbo-jumbo is out of the way, I will just say    */
17 /* this: enjoy this program, do with it as you please and watch out for more */
18 /* code releases from The Rasterman running under X... the only way to code. */
19 /*****************************************************************************/
20
21 /* standard library */
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <time.h>
25 #include <assert.h>
26 #include <string.h>
27
28 #include <X11/X.h>
29 #include <X11/XCB/xcb.h>
30 #include <X11/XCB/shm.h>
31 #include <X11/XCB/xcb_aux.h>
32 #include <X11/XCB/xcb_image.h>
33 #include <X11/XCB/xcb_icccm.h>
34
35 /* some defines for the flame */
36 #define HSPREAD 26
37 #define VSPREAD 78
38 #define VARIANCE 5
39 #define VARTREND 2
40 #define RESIDUAL 68
41
42 /* default width and height of the window */
43 #define BG_W 256
44 #define BG_H 256
45
46 #define IMAX 300
47
48 typedef struct
49 {
50   struct
51   {
52     XCBConnection *c;
53     XCBDRAWABLE    draw;
54     XCBDRAWABLE    pixmap;
55     XCBCOLORMAP    cmap;
56     CARD8          depth;
57     XCBGCONTEXT    gc;
58   }xcb;
59   
60   /* the palette */
61   unsigned int  pal[IMAX];
62   unsigned int *im;
63   int           ims;
64   
65   /* the flame arrays */
66   int           ws;
67   unsigned int *flame;
68   unsigned int *flame2;
69   
70 }flame;
71
72 static void title_set (flame *f, const char *title);
73 static int  ilog2 (unsigned int n);
74 static void flame_set_palette (flame *f);
75 static void flame_set_flame_zero (flame *f);
76 static void flame_set_random_flame_base (flame *f);
77 static void flame_modify_flame_base (flame *f);
78 static void flame_process_flame (flame *f);
79 static void flame_draw_flame (flame *f);
80
81 flame *
82 flame_init ()
83 {
84   flame       *f;
85   XCBSCREEN   *screen;
86   XCBGCONTEXT  gc = { 0 };
87   int          screen_nbr;
88   CARD32       mask;
89   CARD32       values[2];
90   int          size;
91   int          flame_width;
92   int          flame_height;
93   XCBRECTANGLE rect_coord = { 0, 0, BG_W, BG_H};
94
95   f = (flame *)malloc (sizeof (flame));
96   if (!f)
97     return NULL;
98
99   f->xcb.c = XCBConnect (NULL, &screen_nbr);
100   if (!f->xcb.c)
101     {
102       free (f);
103       return NULL;
104     }
105   screen = XCBAuxGetScreen (f->xcb.c, screen_nbr);
106
107   f->xcb.draw.window = screen->root;
108   f->xcb.gc = XCBGCONTEXTNew (f->xcb.c);
109   mask = GCForeground | GCGraphicsExposures;
110   values[0] = screen->black_pixel;
111   values[1] = 0; /* no graphics exposures */
112   XCBCreateGC (f->xcb.c, f->xcb.gc, f->xcb.draw, mask, values);
113
114   gc = XCBGCONTEXTNew (f->xcb.c);
115   mask = GCForeground | GCGraphicsExposures;
116   values[0] = screen->white_pixel;
117   values[1] = 0; /* no graphics exposures */
118   XCBCreateGC (f->xcb.c, gc, f->xcb.draw, mask, values);
119
120   f->xcb.depth = XCBAuxGetDepth (f->xcb.c, screen);
121   mask = XCBCWBackPixel | XCBCWEventMask;
122   values[0] = screen->white_pixel;
123   values[1] = ExposureMask | ButtonPressMask;
124   f->xcb.draw.window = XCBWINDOWNew (f->xcb.c);
125   XCBCreateWindow (f->xcb.c, f->xcb.depth,
126                    f->xcb.draw.window,
127                    screen->root,
128                    0, 0, BG_W, BG_H,
129                    0,
130                    InputOutput,
131                    screen->root_visual,
132                    mask, values);
133   title_set (f, "XCB Flames");
134   
135   f->xcb.pixmap.pixmap = XCBPIXMAPNew (f->xcb.c);
136   XCBCreatePixmap (f->xcb.c, f->xcb.depth,
137                    f->xcb.pixmap.pixmap, f->xcb.draw,
138                    BG_W, BG_H);
139   XCBPolyFillRectangle(f->xcb.c, f->xcb.pixmap, gc, 1, &rect_coord);
140
141   XCBMapWindow (f->xcb.c, f->xcb.draw.window);
142   XCBSync (f->xcb.c, 0);
143
144   f->xcb.cmap = XCBCOLORMAPNew (f->xcb.c);
145   XCBCreateColormap (f->xcb.c,
146                      AllocNone,
147                      f->xcb.cmap,
148                      f->xcb.draw.window,
149                      screen->root_visual);
150
151   /* Allocation of the flame arrays */
152   flame_width  = BG_W >> 1;
153   flame_height = BG_H >> 1;
154   f->ws = ilog2 (flame_width);
155   size = (1 << f->ws) * flame_height * sizeof (unsigned int);
156   f->flame = (unsigned int *)malloc (size);
157   if (! f->flame)
158     {
159       XCBDisconnect (f->xcb.c);
160       free (f);
161       return NULL;
162     }
163   f->flame2 = (unsigned int *)malloc (size);
164   if (! f->flame2)
165     {
166       free (f->flame);
167       XCBDisconnect (f->xcb.c);
168       free (f);
169       return NULL;
170     }
171
172   /* allocation of the image */
173   f->ims = ilog2 (BG_W);
174
175   /* initialization of the palette */
176   flame_set_palette (f);
177
178   return f;
179 }
180
181 void
182 flame_shutdown (flame *f)
183 {
184   if (!f)
185     return;
186
187   free (f->flame2);
188   free (f->flame);
189   XCBDisconnect (f->xcb.c);
190   free (f);
191 }
192
193 int
194 main ()
195 {
196   flame *f;
197   XCBGenericEvent *e;
198   XCBGCONTEXT gc = { 0 };
199
200   f = flame_init ();
201   if (!f)
202     {
203       printf ("Can't initialize global data\nExiting...\n");
204       return -1;
205     }
206
207   flame_set_flame_zero (f);
208   flame_set_random_flame_base (f);
209
210   while (1)
211     {
212       if ((e = XCBPollForEvent (f->xcb.c, NULL)))
213         {
214           switch (e->response_type)
215             {
216             case XCBExpose:
217               XCBCopyArea(f->xcb.c, f->xcb.pixmap, f->xcb.draw, gc,
218                           0, 0, 0, 0, BG_W, BG_H);
219               XCBSync (f->xcb.c, 0);
220               break;
221             case XCBButtonPress:
222               printf ("Exiting...\n");
223               free (e);
224               goto sortie;
225             }
226           free (e);
227         }
228       flame_draw_flame (f);
229       XCBSync (f->xcb.c, 0);
230     }
231
232  sortie:
233   flame_shutdown (f);
234
235   return 0;
236 }
237
238 static void title_set (flame *f, const char *title)
239 {
240   XCBInternAtomRep *rep;
241   XCBATOM           encoding;
242   char             *atom_name;
243
244   /* encoding */
245   atom_name = "UTF8_STRING";
246   rep = XCBInternAtomReply (f->xcb.c,
247                             XCBInternAtom (f->xcb.c,
248                                            0,
249                                            strlen (atom_name),
250                                            atom_name),
251                             NULL);
252   encoding = rep->atom;
253   free (rep);
254
255   /* ICCCM */
256 /*   SetWMName (f->xcb.c, f->xcb.draw.window, encoding, strlen (title), title); */
257
258   /* NETWM */
259   atom_name = "_NET_WM_NAME";
260   rep = XCBInternAtomReply (f->xcb.c,
261                             XCBInternAtom (f->xcb.c,
262                                            0,
263                                            strlen (atom_name),
264                                            atom_name),
265                             NULL);
266   XCBChangeProperty(f->xcb.c, PropModeReplace,
267                     f->xcb.draw.window,
268                     rep->atom, encoding, 8, strlen (title), title);
269   free (rep);
270 }
271
272 static void
273 flame_draw_flame (flame *f)
274 {
275   XCBImage     *image;
276   unsigned int *ptr;
277   int           x;
278   int           y;
279   int           xx;
280   int           yy;
281   int           cl;
282   int           cl1;
283   int           cl2;
284   int           cl3;
285   int           cl4;
286
287   /* modify the base of the flame */
288   flame_modify_flame_base (f);
289   /* process the flame array, propagating the flames up the array */
290   flame_process_flame (f);
291
292   image = XCBImageGet (f->xcb.c, f->xcb.draw,
293                        0, 0, BG_W, BG_H,
294                        ((unsigned long)~0L), ZPixmap);
295   f->im = (unsigned int *)image->data;
296
297   for (y = 0 ; y < ((BG_H >> 1) - 1) ; y++)
298     {
299       for (x = 0 ; x < ((BG_W >> 1) - 1) ; x++)
300         {
301           xx = x << 1;
302           yy = y << 1;
303
304           ptr = f->flame2 + (y << f->ws) + x;
305           cl1 = cl = (int)*ptr;
306           ptr = f->flame2 + (y << f->ws) + x + 1;
307           cl2 = (int)*ptr;
308           ptr = f->flame2 + ((y + 1) << f->ws) + x + 1;
309           cl3 = (int)*ptr;
310           ptr = f->flame2 + ((y + 1) << f->ws) + x;
311           cl4 = (int)*ptr;
312
313           
314           XCBImagePutPixel (image,
315                             xx, yy,
316                             f->pal[cl]);
317           XCBImagePutPixel (image,
318                             xx + 1, yy,
319                             f->pal[((cl1+cl2) >> 1)]);
320           XCBImagePutPixel (image,
321                             xx, yy + 1,
322                             f->pal[((cl1 + cl3) >> 1)]);
323           XCBImagePutPixel (image,
324                             xx + 1, yy + 1,
325                             f->pal[((cl1 + cl4) >> 1)]);
326         }
327     }
328   XCBImagePut (f->xcb.c, f->xcb.draw, f->xcb.gc, image,
329                0, 0, 0, 0, BG_W, BG_H);
330   XCBImageDestroy (image);
331 }
332
333 /* set the flame palette */
334 static void
335 flame_set_palette (flame *f)
336 {
337   XCBAllocColorCookie cookies[IMAX];
338   XCBAllocColorRep *rep;
339   int               i;
340   int               r;
341   int               g;
342   int               b;
343
344   for (i = 0 ; i < IMAX ; i++)
345     {
346       r = i * 3;
347       g = (i - 80) * 3;
348       b = (i - 160) * 3;
349
350       if (r < 0)   r = 0;
351       if (r > 255) r = 255;
352       if (g < 0)   g = 0;
353       if (g > 255) g = 255;
354       if (b < 0)   b = 0;
355       if (b > 255) b = 255;
356
357       cookies[i] = XCBAllocColor (f->xcb.c, f->xcb.cmap,
358                                   r << 8, g << 8, b << 8);
359     }
360
361   for (i = 0 ; i < IMAX ; i++)
362     {
363       rep = XCBAllocColorReply (f->xcb.c, cookies[i], NULL);
364       f->pal[i] = rep->pixel;
365       free (rep);
366     }
367 }
368
369 /* set the flame array to zero */
370 static void
371 flame_set_flame_zero (flame *f)
372 {
373   int           x;
374   int           y;
375   unsigned int *ptr;
376
377   for (y = 0 ; y < (BG_H >> 1) ; y++)
378     {
379       for (x = 0 ; x < (BG_W >> 1) ; x++)
380         {
381           ptr = f->flame + (y << f->ws) + x;
382           *ptr = 0;
383         }
384     }
385 }
386
387 static void
388 flame_set_random_flame_base (flame *f)
389 {
390   int           x;
391   int           y;
392   unsigned int *ptr;
393   
394   /* initialize a random number seed from the time, so we get random */
395   /* numbers each time */
396   srand (time(NULL));
397   y = (BG_H >> 1) - 1;
398   for (x = 0 ; x < (BG_W >> 1) ; x++)
399     {
400       ptr = f->flame + (y << f->ws) + x;
401       *ptr = rand ()%IMAX;
402     }
403 }
404
405 /* modify the base of the flame with random values */
406 static void
407 flame_modify_flame_base (flame *f)
408 {
409   int           x;
410   int           y;
411   unsigned int *ptr;
412   int           val;
413   
414   y = (BG_H >> 1) - 1;
415   for (x = 0 ; x < (BG_W >> 1) ; x++)
416     {
417       ptr = f->flame + (y << f->ws) + x;
418       *ptr += ((rand ()%VARIANCE) - VARTREND);
419       val = *ptr;
420       if (val > IMAX) *ptr = 0;
421       if (val < 0)    *ptr = 0;
422     }
423 }
424
425 /* process entire flame array */
426 static void
427 flame_process_flame (flame *f)
428 {
429   int           x;
430   int           y;
431   unsigned int *ptr;
432   unsigned int *p;
433   unsigned int  val;
434   unsigned int  tmp;
435   
436   for (y = ((BG_H >> 1) - 1) ; y >= 2 ; y--)
437     {
438       for (x = 1 ; x < ((BG_W >> 1) - 1) ; x++)
439         {
440           ptr = f->flame + (y << f->ws) + x;
441           val = (unsigned int)*ptr;
442           if (val > IMAX)
443             *ptr = (unsigned int)IMAX;
444           val = (unsigned int)*ptr;
445           if (val > 0)
446             {
447               tmp = (val * VSPREAD) >> 8;
448               p   = ptr - (2 << f->ws);
449               *p  = *p + (tmp >> 1);
450               p   = ptr - (1 << f->ws);
451               *p  = *p + tmp;
452               tmp = (val * HSPREAD) >> 8;
453               p   = ptr - (1 << f->ws) - 1;
454               *p  = *p + tmp;
455               p   = ptr - (1 << f->ws) + 1;
456               *p  = *p + tmp;
457               p   = ptr - 1;
458               *p  = *p + (tmp >>1 );
459               p   = ptr + 1;
460               *p  = *p + (tmp >> 1);
461               p   = f->flame2 + (y << f->ws) + x;
462               *p  = val;
463               if (y < ((BG_H >> 1) - 1))
464                 *ptr = (val * RESIDUAL) >> 8;
465             }
466         }
467     }
468 }
469
470 static int
471 ilog2 (unsigned int n)
472 {
473   int p = -1;
474
475   assert(n > 0);
476   while (n > 0) {
477     p++;
478     n >>= 1;
479   }
480
481   return p;
482 }