ftp://ftp.smr.ru/pub/0/FreeBSD/releases/distfiles/xscreensaver-3.16.tar.gz
[xscreensaver] / hacks / glx / b_draw.c
diff --git a/hacks/glx/b_draw.c b/hacks/glx/b_draw.c
new file mode 100644 (file)
index 0000000..18c89d9
--- /dev/null
@@ -0,0 +1,260 @@
+#if !defined( lint ) && !defined( SABER )
+static const char sccsid[] = "@(#)b_draw.c  4.11 98/06/16 xlockmore";
+
+#endif
+
+/*-
+ * BUBBLE3D (C) 1998 Richard W.M. Jones.
+ * b_draw.c: This code creates new bubbles, manages them and controls
+ * them as they are drawn on the screen.
+ */
+
+#include "bubble3d.h"
+
+typedef struct draw_context {
+       /* The list of bubbles currently on the screen. */
+       void      **bubble_list;
+       int         nr_bubbles;
+
+       /* When was the last time we created a new bubble? */
+       int         bubble_count;
+} draw_context;
+
+void       *
+glb_draw_init(void)
+{
+       draw_context *c;
+
+       GLfloat     mat_specular[] =
+       {1, 1, 1, 1};
+       GLfloat     mat_emission[] =
+       {0, 0, 0, 1};
+       GLfloat     mat_shininess[] =
+       {100};
+       GLfloat     ambient[] =
+       {0.5, 0.5, 0.5, 1.0};
+       GLfloat     light_position[][4] =
+       {
+               {0, -1, 0, 0},
+               {1, 1, 0, 0},
+               {-1, 0, 1, 0}};
+       GLfloat     light_diffuse[][4] =
+       {
+               {1, 1, 1, 1},
+               {1, 1, 1, 1},
+               {1, 1, 1, 1}};
+       GLfloat     light_specular[][4] =
+       {
+               {1, 1, 1, 1},
+               {1, 1, 1, 1},
+               {1, 1, 1, 1}};
+
+       /* Initialize the context. */
+       c = (struct draw_context *) malloc(sizeof (struct draw_context));
+
+       if (c == 0)
+               return 0;
+       c->bubble_list = 0;
+       c->nr_bubbles = 0;
+       c->bubble_count = glb_config.create_bubbles_every;
+
+       /* Do some GL initialization. */
+       glClearColor(glb_config.bg_colour[0],
+                    glb_config.bg_colour[1],
+                    glb_config.bg_colour[2],
+                    glb_config.bg_colour[3]);
+#if 0
+       glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, glb_config.bubble_colour);
+#else
+       {
+               /* 
+                * E. Lassauge - 98/06/29
+                * Yeahh, cool ! Now that I know how to have random colors I 
+                * patch this pretty beautiful mode too !!
+                */
+               GLfloat     fred, fgreen, fblue;
+               GLfloat     params[4];
+
+               fred = ((float) (NRAND(100)) / 100.0);
+               fgreen = ((float) (NRAND(100)) / 100.0);
+               /* I keep more blue */
+               fblue = ((float) (NRAND(50)) / 100.0) + 0.50;
+
+               params[0] = fred;
+               params[1] = fgreen;
+               params[2] = fblue;
+               /* For the moment don't play with ALPHA channel */
+               params[3] = glb_config.bubble_colour[3];
+               glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, params);
+       }
+#endif
+       glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+       glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mat_emission);
+       glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+
+#if GLB_USE_BLENDING
+       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+#endif
+
+       glEnable(GL_LIGHTING);
+       glEnable(GL_LIGHT0);
+       glEnable(GL_LIGHT1);
+       glEnable(GL_LIGHT2);
+#if GLB_USE_BLENDING
+       glEnable(GL_BLEND);
+#else
+       glEnable(GL_DEPTH_TEST);
+#endif
+       glEnable(GL_AUTO_NORMAL);
+       glEnable(GL_NORMALIZE);
+
+#if GLB_USE_BLENDING
+       glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
+#endif
+       glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
+       glLightfv(GL_LIGHT0, GL_POSITION, light_position[0]);
+       glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse[0]);
+       glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular[0]);
+       glLightfv(GL_LIGHT1, GL_POSITION, light_position[1]);
+       glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse[1]);
+       glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular[1]);
+       glLightfv(GL_LIGHT2, GL_POSITION, light_position[2]);
+       glLightfv(GL_LIGHT2, GL_DIFFUSE, light_diffuse[2]);
+       glLightfv(GL_LIGHT2, GL_SPECULAR, light_specular[2]);
+
+       return c;
+}
+
+static void
+delete_bubble(draw_context * c, int j)
+{
+       int         i;
+
+       glb_bubble_delete(c->bubble_list[j]);
+
+       for (i = j; i < c->nr_bubbles - 1; ++i)
+               c->bubble_list[i] = c->bubble_list[i + 1];
+
+       c->nr_bubbles--;
+}
+
+void
+glb_draw_end(void *cc)
+{
+       draw_context *c = (draw_context *) cc;
+       int         i;
+
+       for (i = 0; i < c->nr_bubbles; ++i) {
+               delete_bubble(c, i);
+               i--;
+       }
+       (void) free((void *) c->bubble_list);
+       (void) free((void *) c);
+}
+
+static int
+create_new_bubbles(draw_context * c)
+{
+       int         n, i;
+       double      r = glb_drand();
+       GLfloat     size, speed, scale_incr, x, y, z;
+       void       *b[4];
+       void      **old_bubble_list;
+
+       /* How many bubbles to make? */
+       if (r < glb_config.p_bubble_group[0])
+               n = 1;
+       else if (r < glb_config.p_bubble_group[1])
+               n = 2;
+       else if (r < glb_config.p_bubble_group[2])
+               n = 3;
+       else
+               n = 4;
+
+       /* Initial position of top-most bubble in group. */
+       x = glb_drand() * 4 - 2;
+       y = glb_config.screen_bottom;
+       z = glb_drand() * 2 - 2;
+
+       /* What size? */
+       size = glb_config.min_size
+               + glb_drand() * (glb_config.max_size - glb_config.min_size);
+
+       /* What speed? */
+       speed = glb_config.min_speed
+               + glb_drand() * (glb_config.max_speed - glb_config.min_speed);
+
+       /* Work out the scaling increment. Bubbles should increase by scale_factor
+        * as they go from bottom to top of screen.
+        */
+       scale_incr = (size * glb_config.scale_factor - size)
+               / ((glb_config.screen_top - glb_config.screen_bottom) / speed);
+
+       /* Create the bubble(s). */
+       for (i = 0; i < n; ++i) {
+               if ((b[i] = glb_bubble_new(x, y, z, size, speed, scale_incr)) == 0) {
+                       /* Out of memory - recover. */
+                       i--;
+                       while (i >= 0)
+                               glb_bubble_delete(b[i]);
+                       return 0;
+               }
+               /* Create the next bubble below the last bubble. */
+               y -= size * 3;
+       }
+
+       /* Add the bubbles to the list. */
+       c->nr_bubbles += n;
+       old_bubble_list = c->bubble_list;
+       if (c->bubble_list == 0) {
+               c->bubble_list = (void **) malloc(c->nr_bubbles * sizeof (void *));
+       } else {
+               c->bubble_list = (void **) realloc(c->bubble_list,
+                                           c->nr_bubbles * sizeof (void *));
+       }
+
+       if (c->bubble_list == 0) {
+               /* Out of memory - recover. */
+               for (i = 0; i < n; ++i)
+                       glb_bubble_delete(b[i]);
+               c->bubble_list = old_bubble_list;
+               c->nr_bubbles -= n;
+               return 0;
+       }
+       for (i = 0; i < n; ++i)
+               c->bubble_list[c->nr_bubbles - i - 1] = b[i];
+
+       return 1;
+}
+
+void
+glb_draw_step(void *cc)
+{
+       draw_context *c = (draw_context *) cc;
+       int         i;
+
+       /* Consider creating a new bubble or bubbles. */
+       if (c->nr_bubbles < glb_config.max_bubbles &&
+           c->bubble_count++ > glb_config.create_bubbles_every) {
+               if (create_new_bubbles(c))
+                       c->bubble_count = 0;
+       }
+       /* Clear the display. */
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+       /* XXX Draw the background here ... */
+
+       /* Draw all the bubbles on the display. */
+       for (i = 0; i < c->nr_bubbles; ++i) {
+               void       *b = c->bubble_list[i];
+
+               glb_bubble_step(b);
+               glb_bubble_draw(b);
+
+               /* Has the bubble reached the top of the screen? */
+               if (glb_bubble_get_y(b) >= glb_config.screen_top) {
+                       delete_bubble(c, i);
+                       i--;
+               }
+       }
+}