Updated to include tests for Gentoo installation
[crack-attack.git] / src / DrawGarbage.cxx
blob191926a02cbd9a05a21743dba448c4b0f6b5dc85
1 /*
2 * DrawGarbages.cxx
3 * Daniel Nelson - 9/1/0
5 * Copyright (C) 2000 Daniel Nelson
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * Daniel Nelson - aluminumangel.org
22 * 174 W. 18th Ave.
23 * Columbus, OH 43210
25 * Handle's the displaying of the garbage.
28 #define GL_GLEXT_LEGACY
29 #define GL_GLEXT_PROTOTYPES
31 #include <GL/glut.h>
32 #include <GL/glext.h>
34 #include "glext.h"
36 using namespace std;
38 #include "Game.h"
39 #include "Block.h"
40 #include "Creep.h"
41 #include "Displayer.h"
42 #include "Garbage.h"
43 #include "GarbageManager.h"
44 #include "LightManager.h"
45 #include "GarbageFlavorImage.h"
47 const GLfloat white[3]
48 = { 1.0f, 1.0f, 1.0f };
50 const GLfloat Displayer::garbage_colors[GF_NUMBER][3]
51 = { { 1.0f, 0.0f, 0.0f }, // normal
52 { 0.4f, 0.4f, 0.4f }, // gray
53 { 0.05f, 0.05f, 0.05f }, // black
54 { 0.95f, 0.95f, 0.95f }, // white
55 { 0.73f, 0.0f, 0.73f }, // purple
56 { 0.2f, 0.2f, 0.8f }, // blue
57 { 0.0f, 0.6f, 0.05f }, // green
58 { 0.85f, 0.85f, 0.0f }, // yellow
59 { 1.0f, 0.4f, 0.0f } }; // orange
61 const GLfloat xy_swap_matrix[]
62 = { 0.0f, 1.0f, 0.0f, 0.0f,
63 1.0f, 0.0f, 0.0f, 0.0f,
64 0.0f, 0.0f, -1.0f, 0.0f,
65 0.0f, 0.0f, 0.0f, 1.0f };
67 GLdouble shatter_clip_plane[4]
68 = { 0.0, 1.0, 0.0, 0.0 };
70 void Displayer::drawGarbage ( )
72 GLfloat x, y;
74 glBindTexture(GL_TEXTURE_2D, garbage_lightmap);
76 // blocks have already been drawn, so we use their material calls
78 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
80 #ifdef DC_CLIP_SHATTER
81 bool clipping = false;
82 #else
83 bool fading = false;
84 GLfloat alpha = 0.0f;
85 #endif
87 int c = GarbageManager::garbage_count;
88 for (int n = 0; c; n++)
89 if (GarbageManager::storeMap[n]) {
90 Garbage &garbage = GarbageManager::garbageStore[n];
91 c--;
93 if (garbage.y > GC_SAFE_HEIGHT) continue;
95 glPushMatrix();
97 y = garbage.y * DC_GRID_ELEMENT_LENGTH
98 + garbage.f_y * (DC_GRID_ELEMENT_LENGTH / (GLfloat) GC_STEPS_PER_GRID)
99 + play_offset_y;
100 x = garbage.x * DC_GRID_ELEMENT_LENGTH + DC_PLAY_OFFSET_X;
102 // awaking; it is assumed that awaking garbage is always grid wide
103 if (garbage.state & GS_AWAKING) {
105 // if still popping our internal sections
106 if (garbage.alarm - Game::time_step > DC_UNSHATTER_TIME) {
108 // no garbage lightmap for blocks
109 glDisable(GL_TEXTURE_2D);
111 int popped = garbage.sections_popped;
113 for (int h = 0; h < garbage.height; h++)
114 for (int w = 0; w < GC_PLAY_WIDTH; w++) {
116 glPushMatrix();
118 LightManager::setupBlockLights(x + w * DC_GRID_ELEMENT_LENGTH,
119 y + h * DC_GRID_ELEMENT_LENGTH);
120 glTranslatef(x + w * DC_GRID_ELEMENT_LENGTH,
121 y + h * DC_GRID_ELEMENT_LENGTH, DC_PLAY_OFFSET_Z);
123 // if this section is about to pop; this code here mimics code
124 // found in DrawBlocks.cxx
125 if (popped == 0
126 && garbage.pop_alarm - Game::time_step < DC_POP_ROTATE_TIME) {
127 GLfloat p = (garbage.pop_alarm - Game::time_step)
128 * (1.0f / (GLfloat) DC_POP_ROTATE_TIME);
130 // each block rotates a different direction
131 if (garbage.pop_direction & BR_DIRECTION_1) {
132 glRotatef(45.0f * p, 1.0f, 0.0f, 0.0f);
133 glRotatef(45.0f * p, 0.0f, 1.0f, 0.0f);
134 } else if (garbage.pop_direction & BR_DIRECTION_2) {
135 glRotatef(90.0f - 45.0f * p, 1.0f, 0.0f, 0.0f);
136 glRotatef(45.0f * p, 0.0f, 1.0f, 0.0f);
137 } else if (garbage.pop_direction & BR_DIRECTION_3) {
138 glRotatef(90.0f - 45.0f * p, 1.0f, 0.0f, 0.0f);
139 glRotatef(-45.0f * p, 0.0f, 1.0f, 0.0f);
140 } else {
141 glRotatef(45.0f * p, 1.0f, 0.0f, 0.0f);
142 glRotatef(-45.0f * p, 0.0f, 1.0f, 0.0f);
145 GLfloat scale = 1.0f - 0.5f * p;
146 glScalef(scale, scale, scale);
148 if (garbage.pop_color == garbage.flavor)
149 glColor3fv(garbage_colors[garbage.flavor]);
150 else
151 glColor3f( (1.0f - p) * garbage_colors[garbage.flavor][0]
152 + p * garbage_colors[garbage.pop_color][0],
153 (1.0f - p) * garbage_colors[garbage.flavor][1]
154 + p * garbage_colors[garbage.pop_color][1],
155 (1.0f - p) * garbage_colors[garbage.flavor][2]
156 + p * garbage_colors[garbage.pop_color][2]);
158 glEnable(rescale_method);
159 glCallList(block_list);
160 glDisable(rescale_method);
162 // if this section has popped
163 } else if (popped > 0) {
164 glColor3fv(garbage_colors[garbage.flavor]);
166 glCallList(block_list);
168 // if this section has not popped
169 } else {
170 glColor3fv(garbage_colors[garbage.pop_color]);
172 // the small block is pre-rotated
173 glCallList(small_block_list);
176 popped--;
177 glPopMatrix();
180 // don't draw a shell
181 glPopMatrix();
183 glEnable(GL_TEXTURE_2D);
185 continue;
187 // if we're about to awake; all sections have popped
188 } else {
189 // crunch our sections back up
191 // no garbage lightmap for blocks
192 glDisable(GL_TEXTURE_2D);
194 GLfloat p = (DC_UNSHATTER_TIME - garbage.alarm + Game::time_step)
195 * (1.0f / (GLfloat) DC_UNSHATTER_TIME);
196 GLfloat scale = 1.0f - 0.5f * p;
198 glColor3fv(garbage_colors[garbage.flavor]);
200 glEnable(rescale_method);
202 for (int h = 0; h < garbage.height; h++)
203 for (int w = 0; w < GC_PLAY_WIDTH; w++) {
205 glPushMatrix();
207 LightManager::setupBlockLights(x + w * DC_GRID_ELEMENT_LENGTH,
208 y + h * DC_GRID_ELEMENT_LENGTH);
209 glTranslatef(x + w * DC_GRID_ELEMENT_LENGTH,
210 y + h * DC_GRID_ELEMENT_LENGTH, DC_PLAY_OFFSET_Z);
212 glRotatef(45.0f * p, 1.0f, 0.0f, 0.0f);
213 glRotatef(45.0f * p, 0.0f, 1.0f, 0.0f);
215 glScalef(scale, scale, scale);
217 glCallList(block_list);
219 glPopMatrix();
222 glDisable(rescale_method);
224 glEnable(GL_TEXTURE_2D);
226 // if we're in the first half of the unshatter
227 if (garbage.alarm - Game::time_step > DC_UNSHATTER_TIME / 4) {
228 // don't draw a shell
229 glPopMatrix();
230 continue;
233 LightManager::setupGarbageLights(x, y, garbage.height,
234 garbage.width);
236 glTranslatef(x, y, DC_PLAY_OFFSET_Z);
238 // only push texture matrix once we know we're using it
239 glMatrixMode(GL_TEXTURE);
240 glPushMatrix();
241 glTranslatef(0.5f + x * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER,
242 0.5f + y * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f);
243 glMatrixMode(GL_MODELVIEW);
245 // clip pane into existance
247 #ifdef DC_CLIP_SHATTER
248 clipping = true;
249 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
250 glDisable(GL_CULL_FACE);
252 glEnable(GL_CLIP_PLANE_SHATTERING);
253 shatter_clip_plane[3] = -(garbage.alarm - Game::time_step)
254 * garbage.height * (DC_GRID_ELEMENT_LENGTH * 4.0f
255 / (GLfloat) DC_UNSHATTER_TIME)
256 + (DC_GRID_ELEMENT_LENGTH / 2.0f);
257 glClipPlane(GL_CLIP_PLANE_SHATTERING, shatter_clip_plane);
258 #else
259 fading = true;
260 alpha = (DC_UNSHATTER_TIME / 4 - garbage.alarm + Game::time_step)
261 * (4.0f / (GLfloat) DC_UNSHATTER_TIME);
262 glEnable(GL_BLEND);
263 #endif
266 } else {
267 LightManager::setupGarbageLights(x, y, garbage.height,
268 garbage.width);
270 glTranslatef(x, y, DC_PLAY_OFFSET_Z);
272 // only push texture matrix once we know we're using it
273 glMatrixMode(GL_TEXTURE);
274 glPushMatrix();
275 glTranslatef(0.5f + x * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER,
276 0.5f + y * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f);
277 glMatrixMode(GL_MODELVIEW);
280 // normal and shattering
282 // if we're shattering
283 if (garbage.state & GS_SHATTERING) {
285 // first we flash
286 if (Game::time_step - garbage.alarm
287 < (DC_SHATTER_FLASH_TIME - DC_SHATTER_TIME)) {
289 GLfloat flash = ((GLfloat) DC_SHATTER_TIME - garbage.alarm
290 + Game::time_step) * (4.0f / (GLfloat) DC_SHATTER_FLASH_TIME);
291 if (flash > 2.0f) flash = 4.0f - flash;
292 if (flash > 1.0f) flash = 2.0f - flash;
293 glColor3f(garbage_colors[garbage.flavor][0] + flash
294 * (DC_FLASH_COLOR_RED - garbage_colors[garbage.flavor][0]),
295 garbage_colors[garbage.flavor][1] + flash
296 * (DC_FLASH_COLOR_GREEN - garbage_colors[garbage.flavor][1]),
297 garbage_colors[garbage.flavor][2] + flash
298 * (DC_FLASH_COLOR_BLUE - garbage_colors[garbage.flavor][2]));
300 } else {
301 // then we clip plane away
303 #ifdef DC_CLIP_SHATTER
304 clipping = true;
305 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
306 glDisable(GL_CULL_FACE);
308 glEnable(GL_CLIP_PLANE_SHATTERING);
309 shatter_clip_plane[3] = -((DC_SHATTER_TIME - DC_SHATTER_FLASH_TIME)
310 - garbage.alarm + Game::time_step) * garbage.height
311 * (DC_GRID_ELEMENT_LENGTH / (GLfloat) (DC_SHATTER_TIME
312 - DC_SHATTER_FLASH_TIME))
313 + (DC_GRID_ELEMENT_LENGTH / 2.0f);
314 glClipPlane(GL_CLIP_PLANE_SHATTERING, shatter_clip_plane);
316 glColor3fv(garbage_colors[garbage.flavor]);
319 } else
320 glColor3fv(garbage_colors[garbage.flavor]);
321 #else
322 fading = true;
323 alpha = (garbage.alarm - Game::time_step)
324 * (1.0f / (GLfloat) (DC_SHATTER_TIME - DC_SHATTER_FLASH_TIME));
325 glEnable(GL_BLEND);
326 glColor4f(garbage_colors[garbage.flavor][0],
327 garbage_colors[garbage.flavor][1],
328 garbage_colors[garbage.flavor][2], alpha);
331 } else if (fading)
332 glColor4f(garbage_colors[garbage.flavor][0],
333 garbage_colors[garbage.flavor][1],
334 garbage_colors[garbage.flavor][2], alpha);
335 else
336 glColor3fv(garbage_colors[garbage.flavor]);
337 #endif
339 // thin garbage
340 if (garbage.height == 1) {
342 if (garbage.width != 1) {
344 glCallList(garbage_thin_cap_list);
345 for (int w = garbage.width - 1; --w; ) {
346 glTranslatef(DC_GRID_ELEMENT_LENGTH, 0.0f, 0.0f);
348 glMatrixMode(GL_TEXTURE);
349 glTranslatef(DC_GRID_ELEMENT_LENGTH
350 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f, 0.0f);
351 glMatrixMode(GL_MODELVIEW);
353 glCallList(garbage_thin_middle_list);
355 glTranslatef(DC_GRID_ELEMENT_LENGTH, 0.0f, 0.0f);
356 glScalef(-1.0f, 1.0f, -1.0f);
358 glMatrixMode(GL_TEXTURE);
359 glTranslatef(DC_GRID_ELEMENT_LENGTH
360 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f, 0.0f);
361 glScalef(-1.0f, 1.0f, -1.0f);
362 glMatrixMode(GL_MODELVIEW);
364 glCallList(garbage_thin_cap_list);
366 // tiny garbage
367 } else
368 glCallList(garbage_small_list);
370 // thick garbage
371 } else {
373 // draw the bottom
374 glPushMatrix();
376 glMatrixMode(GL_TEXTURE);
377 glPushMatrix();
379 glScalef(1.0f, -1.0f, -1.0f);
380 glMatrixMode(GL_MODELVIEW);
382 glScalef(1.0f, -1.0f, -1.0f);
384 glCallList(garbage_thick_corner_list);
385 for (int w = garbage.width - 1; --w; ) {
386 glTranslatef(DC_GRID_ELEMENT_LENGTH, 0.0f, 0.0f);
388 glMatrixMode(GL_TEXTURE);
389 glTranslatef(DC_GRID_ELEMENT_LENGTH
390 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f, 0.0f);
391 glMatrixMode(GL_MODELVIEW);
393 glCallList(garbage_thick_edge_list);
395 glTranslatef(DC_GRID_ELEMENT_LENGTH, 0.0f, 0.0f);
396 glScalef(-1.0f, 1.0f, -1.0f);
398 glMatrixMode(GL_TEXTURE);
399 glTranslatef(DC_GRID_ELEMENT_LENGTH
400 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f, 0.0f);
401 glScalef(-1.0f, 1.0f, -1.0f);
403 glCallList(garbage_thick_corner_list);
405 glPopMatrix();
406 glMatrixMode(GL_MODELVIEW);
408 glPopMatrix();
410 // draw the middle
411 for (int h = garbage.height - 1; --h;) {
412 glPushMatrix();
414 glMatrixMode(GL_TEXTURE);
415 glPushMatrix();
416 glMatrixMode(GL_MODELVIEW);
418 int w = garbage.width - 1;
419 glTranslatef(w * DC_GRID_ELEMENT_LENGTH,
420 h * DC_GRID_ELEMENT_LENGTH, 0.0f);
421 glMultMatrixf(xy_swap_matrix);
423 glMatrixMode(GL_TEXTURE);
424 glTranslatef(w * (DC_GRID_ELEMENT_LENGTH
425 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER), h
426 * (DC_GRID_ELEMENT_LENGTH * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER),
427 0.0f);
428 glMultMatrixf(xy_swap_matrix);
429 glMatrixMode(GL_MODELVIEW);
431 glCallList(garbage_thick_edge_list);
432 while (--w) {
433 glTranslatef(0.0f, -DC_GRID_ELEMENT_LENGTH, 0.0f);
435 glMatrixMode(GL_TEXTURE);
436 glTranslatef(0.0f, -DC_GRID_ELEMENT_LENGTH
437 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f);
438 glMatrixMode(GL_MODELVIEW);
440 glCallList(garbage_thick_middle_list);
442 glTranslatef(0.0f, -DC_GRID_ELEMENT_LENGTH, 0.0f);
443 glScalef(1.0f, -1.0f, -1.0f);
445 glMatrixMode(GL_TEXTURE);
446 glTranslatef(0.0f, -DC_GRID_ELEMENT_LENGTH
447 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f);
448 glScalef(1.0f, -1.0f, -1.0f);
449 glMatrixMode(GL_MODELVIEW);
451 glCallList(garbage_thick_edge_list);
453 glPopMatrix();
455 glMatrixMode(GL_TEXTURE);
456 glPopMatrix();
457 glMatrixMode(GL_MODELVIEW);
460 // draw the top
461 glPushMatrix();
463 glMatrixMode(GL_TEXTURE);
464 glPushMatrix();
466 glTranslatef(0.0f, (garbage.height - 1) * (DC_GRID_ELEMENT_LENGTH
467 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER), 0.0f);
469 glMatrixMode(GL_MODELVIEW);
470 glTranslatef(0.0f, (garbage.height - 1) * DC_GRID_ELEMENT_LENGTH,
471 0.0f);
473 glCallList(garbage_thick_corner_list);
474 for (int w = garbage.width - 1; --w; ) {
475 glTranslatef(DC_GRID_ELEMENT_LENGTH, 0.0f, 0.0f);
477 glMatrixMode(GL_TEXTURE);
478 glTranslatef(DC_GRID_ELEMENT_LENGTH
479 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f, 0.0f);
480 glMatrixMode(GL_MODELVIEW);
482 glCallList(garbage_thick_edge_list);
484 glTranslatef(DC_GRID_ELEMENT_LENGTH, 0.0f, 0.0f);
485 glScalef(-1.0f, 1.0f, -1.0f);
487 glMatrixMode(GL_TEXTURE);
488 glTranslatef(DC_GRID_ELEMENT_LENGTH
489 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f, 0.0f);
490 glScalef(-1.0f, 1.0f, -1.0f);
492 glCallList(garbage_thick_corner_list);
494 glPopMatrix();
495 glMatrixMode(GL_MODELVIEW);
497 glPopMatrix();
499 if (!(MetaState::mode & CM_REALLY_LOW_GRAPHICS)) {
500 // draw flavor image; if any
501 if (GarbageFlavorImage::associated_garbage_id == garbage.id) {
502 #ifndef NO_MULTITEXTURING
503 if (state & DS_MULTITEXTURING) {
504 glPushAttrib(GL_LIGHTING_BIT | GL_ENABLE_BIT);
506 glMatrixMode(GL_TEXTURE);
507 glLoadIdentity();
509 glBindTexture(GL_TEXTURE_2D, garbage_texture);
511 glActiveTextureARB(GL_TEXTURE1_ARB);
512 glPushMatrix();
513 glTranslatef(0.5f + (x + 2.0f * GarbageFlavorImage::x)
514 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER,
515 0.5f + (y + 2.0f * GarbageFlavorImage::y)
516 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f);
518 glEnable(GL_TEXTURE_2D);
519 glEnable(GL_BLEND);
521 glColor3fv(white);
523 glMatrixMode(GL_MODELVIEW);
524 glTranslatef(GarbageFlavorImage::x * DC_GRID_ELEMENT_LENGTH,
525 GarbageFlavorImage::y * DC_GRID_ELEMENT_LENGTH,
526 DC_GARBAGE_FLAVOR_TEX_OFFSET_Z);
528 glCallList(garbage_flavor_list);
530 glMatrixMode(GL_TEXTURE);
531 glPopMatrix();
532 glActiveTextureARB(GL_TEXTURE0_ARB);
533 glMatrixMode(GL_MODELVIEW);
535 glPopAttrib();
537 glBindTexture(GL_TEXTURE_2D, garbage_lightmap);
539 } else {
540 #endif
541 glPushAttrib(GL_LIGHTING_BIT | GL_ENABLE_BIT);
543 glMatrixMode(GL_TEXTURE);
544 glLoadIdentity();
546 glBindTexture(GL_TEXTURE_2D, garbage_texture);
548 glEnable(GL_BLEND);
550 glColor3fv(white);
552 glMatrixMode(GL_MODELVIEW);
553 glTranslatef(GarbageFlavorImage::x * DC_GRID_ELEMENT_LENGTH,
554 GarbageFlavorImage::y * DC_GRID_ELEMENT_LENGTH,
555 DC_GARBAGE_FLAVOR_TEX_OFFSET_Z);
557 glCallList(garbage_flavor_list);
559 glBindTexture(GL_TEXTURE_2D, garbage_lightmap);
561 glPopAttrib();
562 #ifndef NO_MULTITEXTURING
564 #endif
569 // turn off the clip plane
570 #ifdef DC_CLIP_SHATTER
571 if (clipping) {
572 clipping = false;
574 glDisable(GL_CLIP_PLANE_SHATTERING);
575 glEnable(GL_CULL_FACE);
576 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
577 #else
578 if (fading) {
579 fading = false;
581 glDisable(GL_BLEND);
582 #endif
584 // delete fully shattered garbage; note that we can't assume
585 // we'll display each time step
586 if (garbage.alarm <= Game::time_step)
587 GarbageManager::deleteGarbage(&garbage);
590 glPopMatrix();
591 glMatrixMode(GL_TEXTURE);
592 glPopMatrix();
593 glMatrixMode(GL_MODELVIEW);