http://www.jwz.org/xscreensaver/xscreensaver-5.13.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
21         glb_data *d;
22
23 } draw_context;
24
25 void       *
26 glb_draw_init(void)
27 {
28         draw_context *c;
29
30         GLfloat     mat_specular[] =
31         {1, 1, 1, 1};
32         GLfloat     mat_emission[] =
33         {0, 0, 0, 1};
34         GLfloat     mat_shininess[] =
35         {100};
36         GLfloat     ambient[] =
37         {0.5, 0.5, 0.5, 1.0};
38         GLfloat     light_position[][4] =
39         {
40                 {0, -1, 0, 0},
41                 {1, 1, 0, 0},
42                 {-1, 0, 1, 0}};
43         GLfloat     light_diffuse[][4] =
44         {
45                 {1, 1, 1, 1},
46                 {1, 1, 1, 1},
47                 {1, 1, 1, 1}};
48         GLfloat     light_specular[][4] =
49         {
50                 {1, 1, 1, 1},
51                 {1, 1, 1, 1},
52                 {1, 1, 1, 1}};
53
54         /* Initialize the context. */
55         c = (struct draw_context *) malloc(sizeof (struct draw_context));
56
57         if (c == 0)
58                 return 0;
59         c->bubble_list = 0;
60         c->nr_bubbles = 0;
61         c->bubble_count = glb_config.create_bubbles_every;
62
63         /* Do some GL initialization. */
64         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, glb_config.bubble_colour);
65         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
66         glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mat_emission);
67         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
68
69         if (glb_config.transparent_p)
70           glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
71
72         glEnable(GL_LIGHTING);
73         glEnable(GL_LIGHT0);
74         glEnable(GL_LIGHT1);
75         glEnable(GL_LIGHT2);
76
77         if (glb_config.transparent_p)
78           glEnable(GL_BLEND);
79         else
80           glEnable(GL_DEPTH_TEST);
81
82         glEnable(GL_AUTO_NORMAL);
83         glEnable(GL_NORMALIZE);
84
85         if (glb_config.transparent_p)
86           glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
87
88         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
89         glLightfv(GL_LIGHT0, GL_POSITION, light_position[0]);
90         glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse[0]);
91         glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular[0]);
92         glLightfv(GL_LIGHT1, GL_POSITION, light_position[1]);
93         glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse[1]);
94         glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular[1]);
95         glLightfv(GL_LIGHT2, GL_POSITION, light_position[2]);
96         glLightfv(GL_LIGHT2, GL_DIFFUSE, light_diffuse[2]);
97         glLightfv(GL_LIGHT2, GL_SPECULAR, light_specular[2]);
98
99         c->d = glb_sphere_init();
100
101         return c;
102 }
103
104 static void
105 delete_bubble(draw_context * c, int j)
106 {
107         int         i;
108
109         glb_bubble_delete(c->bubble_list[j]);
110
111         for (i = j; i < c->nr_bubbles - 1; ++i)
112                 c->bubble_list[i] = c->bubble_list[i + 1];
113
114         c->nr_bubbles--;
115 }
116
117 void
118 glb_draw_end(void *cc)
119 {
120         draw_context *c = (draw_context *) cc;
121         int         i;
122
123         for (i = 0; i < c->nr_bubbles; ++i) {
124                 delete_bubble(c, i);
125                 i--;
126         }
127
128         glb_sphere_end (c->d);
129
130         (void) free((void *) c->bubble_list);
131         (void) free((void *) c);
132 }
133
134 static int
135 create_new_bubbles(draw_context * c)
136 {
137         int         n, i;
138         double      r = glb_drand();
139         GLfloat     size, speed, scale_incr, x, y, z;
140         void       *b[4];
141         void      **old_bubble_list;
142
143         /* How many bubbles to make? */
144         if (r < glb_config.p_bubble_group[0])
145                 n = 1;
146         else if (r < glb_config.p_bubble_group[1])
147                 n = 2;
148         else if (r < glb_config.p_bubble_group[2])
149                 n = 3;
150         else
151                 n = 4;
152
153         /* Initial position of top-most bubble in group. */
154         x = glb_drand() * 4 - 2;
155         y = glb_config.screen_bottom;
156         z = glb_drand() * 2 - 2;
157
158         /* What size? */
159         size = glb_config.min_size
160                 + glb_drand() * (glb_config.max_size - glb_config.min_size);
161
162         /* What speed? */
163         speed = glb_config.min_speed
164                 + glb_drand() * (glb_config.max_speed - glb_config.min_speed);
165
166         /* Work out the scaling increment. Bubbles should increase by scale_factor
167          * as they go from bottom to top of screen.
168          */
169         scale_incr = (size * glb_config.scale_factor - size)
170                 / ((glb_config.screen_top - glb_config.screen_bottom) / speed);
171
172         /* Create the bubble(s). */
173         for (i = 0; i < n; ++i) {
174                 if ((b[i] = glb_bubble_new(c->d, x, y, z, size, speed, scale_incr)) == 0) {
175                         /* Out of memory - recover. */
176                         i--;
177                         while (i >= 0)
178                                 glb_bubble_delete(b[i]);
179                         return 0;
180                 }
181                 /* Create the next bubble below the last bubble. */
182                 y -= size * 3;
183         }
184
185         /* Add the bubbles to the list. */
186         c->nr_bubbles += n;
187         old_bubble_list = c->bubble_list;
188         if (c->bubble_list == 0) {
189                 c->bubble_list = (void **) malloc(c->nr_bubbles * sizeof (void *));
190         } else {
191                 c->bubble_list = (void **) realloc(c->bubble_list,
192                                             c->nr_bubbles * sizeof (void *));
193         }
194
195         if (c->bubble_list == 0) {
196                 /* Out of memory - recover. */
197                 for (i = 0; i < n; ++i)
198                         glb_bubble_delete(b[i]);
199                 c->bubble_list = old_bubble_list;
200                 c->nr_bubbles -= n;
201                 return 0;
202         }
203         for (i = 0; i < n; ++i)
204                 c->bubble_list[c->nr_bubbles - i - 1] = b[i];
205
206         return 1;
207 }
208
209 void
210 glb_draw_step(void *cc)
211 {
212         draw_context *c = (draw_context *) cc;
213         int         i;
214
215         /* Consider creating a new bubble or bubbles. */
216         if (c->nr_bubbles < glb_config.max_bubbles &&
217             c->bubble_count++ > glb_config.create_bubbles_every) {
218                 if (create_new_bubbles(c))
219                         c->bubble_count = 0;
220         }
221         /* Clear the display. */
222         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
223
224         /* XXX Draw the background here ... */
225
226         /* Draw all the bubbles on the display. */
227         for (i = 0; i < c->nr_bubbles; ++i) {
228                 void       *b = c->bubble_list[i];
229
230                 glb_bubble_step(b);
231                 glb_bubble_draw(c->d, b);
232
233                 /* Has the bubble reached the top of the screen? */
234                 if (glb_bubble_get_y(b) >= glb_config.screen_top) {
235                         delete_bubble(c, i);
236                         i--;
237                 }
238         }
239 }