http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / glx / b_draw.c
1 #if 0
2 static const char sccsid[] = "@(#)b_draw.c  4.11 98/06/16 xlockmore";
3 #endif
4
5 /*-
6  * BUBBLE3D (C) 1998 Richard W.M. Jones.
7  * b_draw.c: This code creates new bubbles, manages them and controls
8  * them as they are drawn on the screen.
9  */
10
11 #include "bubble3d.h"
12
13 typedef struct draw_context {
14         /* The list of bubbles currently on the screen. */
15         void      **bubble_list;
16         int         nr_bubbles;
17
18         /* When was the last time we created a new bubble? */
19         int         bubble_count;
20 } draw_context;
21
22 void       *
23 glb_draw_init(void)
24 {
25         draw_context *c;
26
27         GLfloat     mat_specular[] =
28         {1, 1, 1, 1};
29         GLfloat     mat_emission[] =
30         {0, 0, 0, 1};
31         GLfloat     mat_shininess[] =
32         {100};
33         GLfloat     ambient[] =
34         {0.5, 0.5, 0.5, 1.0};
35         GLfloat     light_position[][4] =
36         {
37                 {0, -1, 0, 0},
38                 {1, 1, 0, 0},
39                 {-1, 0, 1, 0}};
40         GLfloat     light_diffuse[][4] =
41         {
42                 {1, 1, 1, 1},
43                 {1, 1, 1, 1},
44                 {1, 1, 1, 1}};
45         GLfloat     light_specular[][4] =
46         {
47                 {1, 1, 1, 1},
48                 {1, 1, 1, 1},
49                 {1, 1, 1, 1}};
50
51         /* Initialize the context. */
52         c = (struct draw_context *) malloc(sizeof (struct draw_context));
53
54         if (c == 0)
55                 return 0;
56         c->bubble_list = 0;
57         c->nr_bubbles = 0;
58         c->bubble_count = glb_config.create_bubbles_every;
59
60         /* Do some GL initialization. */
61         glClearColor(glb_config.bg_colour[0],
62                      glb_config.bg_colour[1],
63                      glb_config.bg_colour[2],
64                      glb_config.bg_colour[3]);
65 #if 0
66         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, glb_config.bubble_colour);
67 #else
68         {
69                 /* 
70                  * E. Lassauge - 98/06/29
71                  * Yeahh, cool ! Now that I know how to have random colors I 
72                  * patch this pretty beautiful mode too !!
73                  */
74                 GLfloat     fred, fgreen, fblue;
75                 GLfloat     params[4];
76
77                 fred = ((float) (NRAND(100)) / 100.0);
78                 fgreen = ((float) (NRAND(100)) / 100.0);
79                 /* I keep more blue */
80                 fblue = ((float) (NRAND(50)) / 100.0) + 0.50;
81
82                 params[0] = fred;
83                 params[1] = fgreen;
84                 params[2] = fblue;
85                 /* For the moment don't play with ALPHA channel */
86                 params[3] = glb_config.bubble_colour[3];
87                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, params);
88         }
89 #endif
90         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
91         glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mat_emission);
92         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
93
94 #if GLB_USE_BLENDING
95         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
96 #endif
97
98         glEnable(GL_LIGHTING);
99         glEnable(GL_LIGHT0);
100         glEnable(GL_LIGHT1);
101         glEnable(GL_LIGHT2);
102 #if GLB_USE_BLENDING
103         glEnable(GL_BLEND);
104 #else
105         glEnable(GL_DEPTH_TEST);
106 #endif
107         glEnable(GL_AUTO_NORMAL);
108         glEnable(GL_NORMALIZE);
109
110 #if GLB_USE_BLENDING
111         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
112 #endif
113         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
114         glLightfv(GL_LIGHT0, GL_POSITION, light_position[0]);
115         glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse[0]);
116         glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular[0]);
117         glLightfv(GL_LIGHT1, GL_POSITION, light_position[1]);
118         glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse[1]);
119         glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular[1]);
120         glLightfv(GL_LIGHT2, GL_POSITION, light_position[2]);
121         glLightfv(GL_LIGHT2, GL_DIFFUSE, light_diffuse[2]);
122         glLightfv(GL_LIGHT2, GL_SPECULAR, light_specular[2]);
123
124         return c;
125 }
126
127 static void
128 delete_bubble(draw_context * c, int j)
129 {
130         int         i;
131
132         glb_bubble_delete(c->bubble_list[j]);
133
134         for (i = j; i < c->nr_bubbles - 1; ++i)
135                 c->bubble_list[i] = c->bubble_list[i + 1];
136
137         c->nr_bubbles--;
138 }
139
140 void
141 glb_draw_end(void *cc)
142 {
143         draw_context *c = (draw_context *) cc;
144         int         i;
145
146         for (i = 0; i < c->nr_bubbles; ++i) {
147                 delete_bubble(c, i);
148                 i--;
149         }
150         (void) free((void *) c->bubble_list);
151         (void) free((void *) c);
152 }
153
154 static int
155 create_new_bubbles(draw_context * c)
156 {
157         int         n, i;
158         double      r = glb_drand();
159         GLfloat     size, speed, scale_incr, x, y, z;
160         void       *b[4];
161         void      **old_bubble_list;
162
163         /* How many bubbles to make? */
164         if (r < glb_config.p_bubble_group[0])
165                 n = 1;
166         else if (r < glb_config.p_bubble_group[1])
167                 n = 2;
168         else if (r < glb_config.p_bubble_group[2])
169                 n = 3;
170         else
171                 n = 4;
172
173         /* Initial position of top-most bubble in group. */
174         x = glb_drand() * 4 - 2;
175         y = glb_config.screen_bottom;
176         z = glb_drand() * 2 - 2;
177
178         /* What size? */
179         size = glb_config.min_size
180                 + glb_drand() * (glb_config.max_size - glb_config.min_size);
181
182         /* What speed? */
183         speed = glb_config.min_speed
184                 + glb_drand() * (glb_config.max_speed - glb_config.min_speed);
185
186         /* Work out the scaling increment. Bubbles should increase by scale_factor
187          * as they go from bottom to top of screen.
188          */
189         scale_incr = (size * glb_config.scale_factor - size)
190                 / ((glb_config.screen_top - glb_config.screen_bottom) / speed);
191
192         /* Create the bubble(s). */
193         for (i = 0; i < n; ++i) {
194                 if ((b[i] = glb_bubble_new(x, y, z, size, speed, scale_incr)) == 0) {
195                         /* Out of memory - recover. */
196                         i--;
197                         while (i >= 0)
198                                 glb_bubble_delete(b[i]);
199                         return 0;
200                 }
201                 /* Create the next bubble below the last bubble. */
202                 y -= size * 3;
203         }
204
205         /* Add the bubbles to the list. */
206         c->nr_bubbles += n;
207         old_bubble_list = c->bubble_list;
208         if (c->bubble_list == 0) {
209                 c->bubble_list = (void **) malloc(c->nr_bubbles * sizeof (void *));
210         } else {
211                 c->bubble_list = (void **) realloc(c->bubble_list,
212                                             c->nr_bubbles * sizeof (void *));
213         }
214
215         if (c->bubble_list == 0) {
216                 /* Out of memory - recover. */
217                 for (i = 0; i < n; ++i)
218                         glb_bubble_delete(b[i]);
219                 c->bubble_list = old_bubble_list;
220                 c->nr_bubbles -= n;
221                 return 0;
222         }
223         for (i = 0; i < n; ++i)
224                 c->bubble_list[c->nr_bubbles - i - 1] = b[i];
225
226         return 1;
227 }
228
229 void
230 glb_draw_step(void *cc)
231 {
232         draw_context *c = (draw_context *) cc;
233         int         i;
234
235         /* Consider creating a new bubble or bubbles. */
236         if (c->nr_bubbles < glb_config.max_bubbles &&
237             c->bubble_count++ > glb_config.create_bubbles_every) {
238                 if (create_new_bubbles(c))
239                         c->bubble_count = 0;
240         }
241         /* Clear the display. */
242         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
243
244         /* XXX Draw the background here ... */
245
246         /* Draw all the bubbles on the display. */
247         for (i = 0; i < c->nr_bubbles; ++i) {
248                 void       *b = c->bubble_list[i];
249
250                 glb_bubble_step(b);
251                 glb_bubble_draw(b);
252
253                 /* Has the bubble reached the top of the screen? */
254                 if (glb_bubble_get_y(b) >= glb_config.screen_top) {
255                         delete_bubble(c, i);
256                         i--;
257                 }
258         }
259 }