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