#if 0 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; glb_data *d; } 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. */ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, glb_config.bubble_colour); 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_config.transparent_p) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glEnable(GL_LIGHT2); if (glb_config.transparent_p) glEnable(GL_BLEND); else glEnable(GL_DEPTH_TEST); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); if (glb_config.transparent_p) glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); 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]); c->d = glb_sphere_init(); 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--; } glb_sphere_end (c->d); free(c->bubble_list); free(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(c->d, 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(c->d, 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--; } } }