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