0f55ca010530420086b72fd680cde026a0c0faba
[xscreensaver] / utils / alpha.c
1 /* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
2  *  Jamie Zawinski <jwz@netscape.com>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  */
12
13 /* Beauty is only skin deep, unless you've got an alpha channel. */
14
15
16 #include "utils.h"
17 #include "alpha.h"
18 #include "hsv.h"
19 #include "yarandom.h"
20 #include "resources.h"
21
22 #ifndef countof
23 # define countof(x) (sizeof(*(x))/sizeof((x)))
24 #endif
25
26
27 /* I don't believe this fucking language doesn't have builtin exponentiation.
28    I further can't believe that the fucking ^ character means fucking XOR!! */
29 static int 
30 i_exp (int i, int j)
31 {
32   int k = 1;
33   while (j--) k *= i;
34   return k;
35 }
36
37
38 static void
39 merge_colors (int argc, XColor **argv, XColor *into_color, int mask,
40               Bool additive_p)
41 {
42   int j;
43   *into_color = *argv [0];
44   into_color->pixel |= mask;
45
46   for (j = 1; j < argc; j++)
47     {
48 # define SHORT_INC(x,y) (x = ((((x)+(y)) > 0xFFFF) ? 0xFFFF : ((x)+(y))))
49 # define SHORT_DEC(x,y) (x = ((((x)-(y)) < 0)      ? 0      : ((x)-(y))))
50       if (additive_p)
51         {
52           SHORT_INC (into_color->red,   argv[j]->red);
53           SHORT_INC (into_color->green, argv[j]->green);
54           SHORT_INC (into_color->blue,  argv[j]->blue);
55         }
56       else
57         {
58           SHORT_DEC (into_color->red,   argv[j]->red);
59           SHORT_DEC (into_color->green, argv[j]->green);
60           SHORT_DEC (into_color->blue,  argv[j]->blue);
61         }
62 # undef SHORT_INC
63 # undef SHORT_DEC
64     }
65 }
66
67 static void
68 permute_colors (XColor *pcolors, XColor *colors,
69                 int count,
70                 unsigned long *plane_masks,
71                 Bool additive_p)
72 {
73   int out = 0;
74   int max = i_exp (2, count);
75   if (count > 31) abort ();
76   for (out = 1; out < max; out++)
77     {
78       XColor *argv [32];
79       int this_mask = 0;
80       int argc = 0;
81       int bit;
82       for (bit = 0; bit < 32; bit++)
83         if (out & (1<<bit))
84           {
85             argv [argc++] = &pcolors [bit];
86             this_mask |= plane_masks [bit];
87           }
88       merge_colors (argc, argv, &colors [out-1], this_mask, additive_p);
89     }
90 }
91
92
93 int
94 allocate_color_planes (Display *dpy, Colormap cmap,
95                        int nplanes, unsigned long *plane_masks,
96                        unsigned long *base_pixel_ret)
97 {
98   while (nplanes > 1 &&
99          !XAllocColorCells (dpy, cmap, False, plane_masks, nplanes,
100                             base_pixel_ret, 1))
101     nplanes--;
102
103   return nplanes;
104 }
105                        
106
107 void
108 initialize_transparency_colormap (Display *dpy, Colormap cmap,
109                                   int nplanes,
110                                   unsigned long base_pixel,
111                                   unsigned long *plane_masks,
112                                   XColor *colors,
113                                   Bool additive_p)
114 {
115   int i;
116   int total_colors = i_exp (2, nplanes);
117   XColor *all_colors = (XColor *) calloc (total_colors, sizeof (XColor));
118
119   for (i = 0; i < nplanes; i++)
120     colors[i].pixel = base_pixel | plane_masks [i];
121   permute_colors (colors, all_colors, nplanes, plane_masks, additive_p);
122
123   /* clone the default background of the window into our "base" pixel */
124   all_colors [total_colors - 1].pixel =
125     get_pixel_resource ("background", "Background", dpy, cmap);
126   XQueryColor (dpy, cmap, &all_colors [total_colors - 1]);
127   all_colors [total_colors - 1].pixel = base_pixel;
128
129   for (i = 0; i < total_colors; i++)
130     all_colors[i].flags = DoRed|DoGreen|DoBlue;
131   XStoreColors (dpy, cmap, all_colors, total_colors);
132   XFree ((XPointer) all_colors);
133 }
134
135
136 Bool
137 allocate_alpha_colors (Display *dpy, Colormap cmap,
138                        int *nplanesP, Bool additive_p,
139                        unsigned long **plane_masks,
140                        unsigned long *base_pixelP)
141 {
142   XColor *colors;
143   int nplanes = *nplanesP;
144   int i;
145
146   if (nplanes > 31) nplanes = 31;
147   *plane_masks = (unsigned long *) malloc(sizeof(unsigned long) * nplanes);
148
149   nplanes = allocate_color_planes (dpy, cmap, nplanes, *plane_masks,
150                                    base_pixelP);
151   *nplanesP = nplanes;
152
153   if (nplanes <= 1)
154     {
155       free(*plane_masks);
156       *plane_masks = 0;
157       return False;
158     }
159
160   colors = (XColor *) calloc (nplanes, sizeof (XColor));
161   for (i = 0; i < nplanes; i++)
162     {
163       /* pick the base colors. If we are in subtractive mode, pick higher
164          intensities. */
165       hsv_to_rgb (random () % 360,
166                   frand (1.0),
167                   frand (0.5) + (additive_p ? 0.2 : 0.5),
168                   &colors[i].red,
169                   &colors[i].green,
170                   &colors[i].blue);
171     }
172   initialize_transparency_colormap (dpy, cmap, nplanes,
173                                     *base_pixelP, *plane_masks, colors,
174                                     additive_p);
175   XFree ((XPointer) colors);
176   return True;
177 }