Replace deprecated Automake INCLUDES variable with AM_CPPFLAGS
[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 <stdbool.h>
25 #include <time.h>
26 #include <assert.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include <xcb/xcb.h>
31 #include <xcb/shm.h>
32 #include <xcb/xcb_aux.h>
33 #include <xcb/xcb_image.h>
34 #include <xcb/xcb_atom.h>
35
36 /* Needed for xcb_set_wm_protocols() */
37 #include <xcb/xcb_icccm.h>
38
39 #define XCB_ALL_PLANES ~0
40 #include <xcb/xcb_icccm.h>
41
42 /* some defines for the flame */
43 #define HSPREAD 26
44 #define VSPREAD 78
45 #define VARIANCE 5
46 #define VARTREND 2
47 #define RESIDUAL 68
48
49 /* default width and height of the window */
50 #define BG_W 256
51 #define BG_H 256
52
53 #define IMAX 300
54
55 typedef struct
56 {
57   struct
58   {
59     xcb_connection_t *c;
60     xcb_drawable_t    draw;
61     xcb_drawable_t    pixmap;
62     xcb_colormap_t    cmap;
63     uint8_t          depth;
64     xcb_gcontext_t    gc;
65   }xcb;
66   
67   /* the palette */
68   unsigned int  pal[IMAX];
69   unsigned int *im;
70   int           ims;
71   
72   /* the flame arrays */
73   int           ws;
74   unsigned int *flame;
75   unsigned int *flame2;
76   
77 }flame;
78
79 static xcb_atom_t get_atom (xcb_connection_t *connection, const char *atomName);
80 static void title_set (flame *f, const char *title);
81 static int  ilog2 (unsigned int n);
82 static void flame_set_palette (flame *f);
83 static void flame_set_flame_zero (flame *f);
84 static void flame_set_random_flame_base (flame *f);
85 static void flame_modify_flame_base (flame *f);
86 static void flame_process_flame (flame *f);
87 static void flame_draw_flame (flame *f);
88
89 flame *
90 flame_init ()
91 {
92   flame       *f;
93   xcb_screen_t   *screen;
94   xcb_gcontext_t  gc = { 0 };
95   int          screen_nbr;
96   uint32_t       mask;
97   uint32_t       values[2];
98   int          size;
99   int          flame_width;
100   int          flame_height;
101   xcb_rectangle_t rect_coord = { 0, 0, BG_W, BG_H};
102
103   f = (flame *)malloc (sizeof (flame));
104   if (!f)
105     return NULL;
106
107   f->xcb.c = xcb_connect (NULL, &screen_nbr);
108   if (!f->xcb.c)
109     {
110       free (f);
111       return NULL;
112     }
113   screen = xcb_aux_get_screen (f->xcb.c, screen_nbr);
114
115   f->xcb.draw = screen->root;
116   f->xcb.gc = xcb_generate_id (f->xcb.c);
117   mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
118   values[0] = screen->black_pixel;
119   values[1] = 0; /* no graphics exposures */
120   xcb_create_gc (f->xcb.c, f->xcb.gc, f->xcb.draw, mask, values);
121
122   gc = xcb_generate_id (f->xcb.c);
123   mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
124   values[0] = screen->white_pixel;
125   values[1] = 0; /* no graphics exposures */
126   xcb_create_gc (f->xcb.c, gc, f->xcb.draw, mask, values);
127
128   f->xcb.depth = xcb_aux_get_depth (f->xcb.c, screen);
129   mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
130   values[0] = screen->white_pixel;
131   values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS;
132   f->xcb.draw = xcb_generate_id (f->xcb.c);
133   xcb_create_window (f->xcb.c, f->xcb.depth,
134                    f->xcb.draw,
135                    screen->root,
136                    0, 0, BG_W, BG_H,
137                    0,
138                    XCB_WINDOW_CLASS_INPUT_OUTPUT,
139                    screen->root_visual,
140                    mask, values);
141   title_set (f, "XCB Flames");
142   
143   f->xcb.pixmap = xcb_generate_id (f->xcb.c);
144   xcb_create_pixmap (f->xcb.c, f->xcb.depth,
145                    f->xcb.pixmap, f->xcb.draw,
146                    BG_W, BG_H);
147   xcb_poly_fill_rectangle(f->xcb.c, f->xcb.pixmap, gc, 1, &rect_coord);
148
149   xcb_map_window (f->xcb.c, f->xcb.draw);
150   xcb_flush (f->xcb.c);
151
152   f->xcb.cmap = xcb_generate_id (f->xcb.c);
153   xcb_create_colormap (f->xcb.c,
154                      XCB_COLORMAP_ALLOC_NONE,
155                      f->xcb.cmap,
156                      f->xcb.draw,
157                      screen->root_visual);
158
159   /* Allocation of the flame arrays */
160   flame_width  = BG_W >> 1;
161   flame_height = BG_H >> 1;
162   f->ws = ilog2 (flame_width);
163   size = (1 << f->ws) * flame_height * sizeof (unsigned int);
164   f->flame = (unsigned int *)malloc (size);
165   if (! f->flame)
166     {
167       xcb_disconnect (f->xcb.c);
168       free (f);
169       return NULL;
170     }
171   f->flame2 = (unsigned int *)malloc (size);
172   if (! f->flame2)
173     {
174       free (f->flame);
175       xcb_disconnect (f->xcb.c);
176       free (f);
177       return NULL;
178     }
179
180   /* allocation of the image */
181   f->ims = ilog2 (BG_W);
182
183   /* initialization of the palette */
184   flame_set_palette (f);
185
186   return f;
187 }
188
189 void
190 flame_shutdown (flame *f)
191 {
192   if (!f)
193     return;
194
195   free (f->flame2);
196   free (f->flame);
197   xcb_disconnect (f->xcb.c);
198   free (f);
199 }
200
201 int
202 main ()
203 {
204   flame *f;
205   xcb_generic_event_t *e;
206   xcb_gcontext_t gc = { 0 };
207
208   f = flame_init ();
209   if (!f)
210     {
211       printf ("Can't initialize global data\nExiting...\n");
212       return -1;
213     }
214
215   flame_set_flame_zero (f);
216   flame_set_random_flame_base (f);
217
218   xcb_atom_t deleteWindowAtom = xcb_atom_get(f->xcb.c, "WM_DELETE_WINDOW");
219   xcb_atom_t wmprotocolsAtom = xcb_atom_get(f->xcb.c, "WM_PROTOCOLS");
220   /* Listen to X client messages in order to be able to pickup
221      the "delete window" message that is generated for example
222      when someone clicks the top-right X button within the window
223      manager decoration (or when user hits ALT-F4). */
224   xcb_set_wm_protocols (f->xcb.c, wmprotocolsAtom, f->xcb.draw, 1, &deleteWindowAtom);
225
226   bool finished = false;
227   while (!finished)
228     {
229       if ((e = xcb_poll_for_event (f->xcb.c)))
230         {
231           switch (XCB_EVENT_RESPONSE_TYPE(e))
232             {
233             case XCB_EXPOSE:
234               xcb_copy_area(f->xcb.c, f->xcb.pixmap, f->xcb.draw, gc,
235                           0, 0, 0, 0, BG_W, BG_H);
236               xcb_flush (f->xcb.c);
237               break;
238             case XCB_CLIENT_MESSAGE:
239               if (((xcb_client_message_event_t *)e)->data.data32[0] == deleteWindowAtom)
240                 {
241                   finished = true;
242                 }
243               break;
244             case XCB_BUTTON_PRESS:
245               finished = true;
246               break;
247             }
248           free (e);
249         }
250       flame_draw_flame (f);
251       xcb_flush (f->xcb.c);
252     }
253
254   flame_shutdown (f);
255
256   return 0;
257 }
258
259 static void title_set (flame *f, const char *title)
260 {
261   xcb_intern_atom_reply_t *rep;
262   xcb_atom_t           encoding;
263   char             *atom_name;
264
265   /* encoding */
266   atom_name = "UTF8_STRING";
267   rep = xcb_intern_atom_reply (f->xcb.c,
268                             xcb_intern_atom (f->xcb.c,
269                                            0,
270                                            strlen (atom_name),
271                                            atom_name),
272                             NULL);
273   encoding = rep->atom;
274   free (rep);
275
276   /* ICCCM */
277 /*   SetWMName (f->xcb.c, f->xcb.draw.window, encoding, strlen (title), title); */
278
279   /* NETWM */
280   atom_name = "_NET_WM_NAME";
281   rep = xcb_intern_atom_reply (f->xcb.c,
282                             xcb_intern_atom (f->xcb.c,
283                                            0,
284                                            strlen (atom_name),
285                                            atom_name),
286                             NULL);
287   xcb_change_property(f->xcb.c, XCB_PROP_MODE_REPLACE,
288                     f->xcb.draw,
289                     rep->atom, encoding, 8, strlen (title), title);
290   free (rep);
291 }
292
293 static void
294 flame_draw_flame (flame *f)
295 {
296   xcb_image_t     *image;
297   unsigned int *ptr;
298   int           x;
299   int           y;
300   int           xx;
301   int           yy;
302   int           cl;
303   int           cl1;
304   int           cl2;
305   int           cl3;
306   int           cl4;
307
308   image = xcb_image_get (f->xcb.c, f->xcb.draw,
309                        0, 0, BG_W, BG_H,
310                        XCB_ALL_PLANES, XCB_IMAGE_FORMAT_Z_PIXMAP);
311   /* If the top-level window is minimized (iconic) then the xcb_image_get()
312      will return NULL. In this case, we'll skip both updating and drawing
313      the flame, and we will also do a small sleep so that the program doesn't
314      hog as much CPU while minimized. 
315    
316      Another (non-polling == cleaner) way to not hog the CPU while minimized 
317      would be to pass the XCB_EVENT_MASK_STRUCTURE_NOTIFY flag to
318      xcb_create_window(). This will give you XCB_UNMAP_NOTIFY and
319      XCB_MAP_NOTIFY events whenever the window is "minimized" (made iconic)
320      and "unminimized" (made normal again). This information would then be
321      used to make the main loop use the xcb_wait_for_event() instead of
322      xcb_poll_for_event() while the window is minimized (iconic).     */
323   if (image == NULL)
324     {
325       usleep (100000);
326       return;
327     }
328   f->im = (unsigned int *)image->data;
329
330   /* modify the base of the flame */
331   flame_modify_flame_base (f);
332   /* process the flame array, propagating the flames up the array */
333   flame_process_flame (f);
334
335   for (y = 0 ; y < ((BG_H >> 1) - 1) ; y++)
336     {
337       for (x = 0 ; x < ((BG_W >> 1) - 1) ; x++)
338         {
339           xx = x << 1;
340           yy = y << 1;
341
342           ptr = f->flame2 + (y << f->ws) + x;
343           cl1 = cl = (int)*ptr;
344           ptr = f->flame2 + (y << f->ws) + x + 1;
345           cl2 = (int)*ptr;
346           ptr = f->flame2 + ((y + 1) << f->ws) + x + 1;
347           cl3 = (int)*ptr;
348           ptr = f->flame2 + ((y + 1) << f->ws) + x;
349           cl4 = (int)*ptr;
350
351           
352           xcb_image_put_pixel (image,
353                             xx, yy,
354                             f->pal[cl]);
355           xcb_image_put_pixel (image,
356                             xx + 1, yy,
357                             f->pal[((cl1+cl2) >> 1)]);
358           xcb_image_put_pixel (image,
359                             xx, yy + 1,
360                             f->pal[((cl1 + cl3) >> 1)]);
361           xcb_image_put_pixel (image,
362                             xx + 1, yy + 1,
363                             f->pal[((cl1 + cl4) >> 1)]);
364         }
365     }
366   xcb_image_put (f->xcb.c, f->xcb.draw, f->xcb.gc, image,
367                0, 0, 0);
368   xcb_image_destroy (image);
369 }
370
371 /* set the flame palette */
372 static void
373 flame_set_palette (flame *f)
374 {
375   xcb_alloc_color_cookie_t cookies[IMAX];
376   xcb_alloc_color_reply_t *rep;
377   int               i;
378   int               r;
379   int               g;
380   int               b;
381
382   for (i = 0 ; i < IMAX ; i++)
383     {
384       r = i * 3;
385       g = (i - 80) * 3;
386       b = (i - 160) * 3;
387
388       if (r < 0)   r = 0;
389       if (r > 255) r = 255;
390       if (g < 0)   g = 0;
391       if (g > 255) g = 255;
392       if (b < 0)   b = 0;
393       if (b > 255) b = 255;
394
395       cookies[i] = xcb_alloc_color (f->xcb.c, f->xcb.cmap,
396                                   r << 8, g << 8, b << 8);
397     }
398
399   for (i = 0 ; i < IMAX ; i++)
400     {
401       rep = xcb_alloc_color_reply (f->xcb.c, cookies[i], NULL);
402       f->pal[i] = rep->pixel;
403       free (rep);
404     }
405 }
406
407 /* set the flame array to zero */
408 static void
409 flame_set_flame_zero (flame *f)
410 {
411   int           x;
412   int           y;
413   unsigned int *ptr;
414
415   for (y = 0 ; y < (BG_H >> 1) ; y++)
416     {
417       for (x = 0 ; x < (BG_W >> 1) ; x++)
418         {
419           ptr = f->flame + (y << f->ws) + x;
420           *ptr = 0;
421         }
422     }
423 }
424
425 static void
426 flame_set_random_flame_base (flame *f)
427 {
428   int           x;
429   int           y;
430   unsigned int *ptr;
431   
432   /* initialize a random number seed from the time, so we get random */
433   /* numbers each time */
434   srand (time(NULL));
435   y = (BG_H >> 1) - 1;
436   for (x = 0 ; x < (BG_W >> 1) ; x++)
437     {
438       ptr = f->flame + (y << f->ws) + x;
439       *ptr = rand ()%IMAX;
440     }
441 }
442
443 /* modify the base of the flame with random values */
444 static void
445 flame_modify_flame_base (flame *f)
446 {
447   int           x;
448   int           y;
449   unsigned int *ptr;
450   int           val;
451   
452   y = (BG_H >> 1) - 1;
453   for (x = 0 ; x < (BG_W >> 1) ; x++)
454     {
455       ptr = f->flame + (y << f->ws) + x;
456       *ptr += ((rand ()%VARIANCE) - VARTREND);
457       val = *ptr;
458       if (val > IMAX) *ptr = 0;
459       if (val < 0)    *ptr = 0;
460     }
461 }
462
463 /* process entire flame array */
464 static void
465 flame_process_flame (flame *f)
466 {
467   int           x;
468   int           y;
469   unsigned int *ptr;
470   unsigned int *p;
471   unsigned int  val;
472   unsigned int  tmp;
473   
474   for (y = ((BG_H >> 1) - 1) ; y >= 2 ; y--)
475     {
476       for (x = 1 ; x < ((BG_W >> 1) - 1) ; x++)
477         {
478           ptr = f->flame + (y << f->ws) + x;
479           val = (unsigned int)*ptr;
480           if (val > IMAX)
481             *ptr = (unsigned int)IMAX;
482           val = (unsigned int)*ptr;
483           if (val > 0)
484             {
485               tmp = (val * VSPREAD) >> 8;
486               p   = ptr - (2 << f->ws);
487               *p  = *p + (tmp >> 1);
488               p   = ptr - (1 << f->ws);
489               *p  = *p + tmp;
490               tmp = (val * HSPREAD) >> 8;
491               p   = ptr - (1 << f->ws) - 1;
492               *p  = *p + tmp;
493               p   = ptr - (1 << f->ws) + 1;
494               *p  = *p + tmp;
495               p   = ptr - 1;
496               *p  = *p + (tmp >>1 );
497               p   = ptr + 1;
498               *p  = *p + (tmp >> 1);
499               p   = f->flame2 + (y << f->ws) + x;
500               *p  = val;
501               if (y < ((BG_H >> 1) - 1))
502                 *ptr = (val * RESIDUAL) >> 8;
503             }
504         }
505     }
506 }
507
508 static int
509 ilog2 (unsigned int n)
510 {
511   int p = -1;
512
513   assert(n > 0);
514   while (n > 0) {
515     p++;
516     n >>= 1;
517   }
518
519   return p;
520 }