desktop file ended up in the wrong place.
[crack-attack.git] / src / DrawGarbage.cxx
blobdd6d4e37ac63ec79e9f30a61ce678cb212a9a099
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 #ifndef _WIN32
35 #else
36 # include <glext.h>
37 #endif
39 using namespace std;
41 #include "Game.h"
42 #include "Block.h"
43 #include "Creep.h"
44 #include "Displayer.h"
45 #include "Garbage.h"
46 #include "GarbageManager.h"
47 #include "LightManager.h"
48 #include "GarbageFlavorImage.h"
50 const GLfloat white[3]
51 = { 1.0f, 1.0f, 1.0f };
53 const GLfloat Displayer::garbage_colors[GF_NUMBER][3]
54 = { { 1.0f, 0.0f, 0.0f }, // normal
55 { 0.4f, 0.4f, 0.4f }, // gray
56 { 0.05f, 0.05f, 0.05f }, // black
57 { 0.95f, 0.95f, 0.95f }, // white
58 { 0.73f, 0.0f, 0.73f }, // purple
59 { 0.2f, 0.2f, 0.8f }, // blue
60 { 0.0f, 0.6f, 0.05f }, // green
61 { 0.85f, 0.85f, 0.0f }, // yellow
62 { 1.0f, 0.4f, 0.0f } }; // orange
64 const GLfloat xy_swap_matrix[]
65 = { 0.0f, 1.0f, 0.0f, 0.0f,
66 1.0f, 0.0f, 0.0f, 0.0f,
67 0.0f, 0.0f, -1.0f, 0.0f,
68 0.0f, 0.0f, 0.0f, 1.0f };
70 GLdouble shatter_clip_plane[4]
71 = { 0.0, 1.0, 0.0, 0.0 };
73 void Displayer::drawGarbage ( )
75 GLfloat x, y;
77 glBindTexture(GL_TEXTURE_2D, garbage_lightmap);
79 // blocks have already been drawn, so we use their material calls
81 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
83 #ifdef DC_CLIP_SHATTER
84 bool clipping = false;
85 #else
86 bool fading = false;
87 GLfloat alpha = 0.0f;
88 #endif
90 int c = GarbageManager::garbage_count;
91 for (int n = 0; c; n++)
92 if (GarbageManager::storeMap[n]) {
93 Garbage &garbage = GarbageManager::garbageStore[n];
94 c--;
96 if (garbage.y > GC_SAFE_HEIGHT) continue;
98 glPushMatrix();
100 y = garbage.y * DC_GRID_ELEMENT_LENGTH
101 + garbage.f_y * (DC_GRID_ELEMENT_LENGTH / (GLfloat) GC_STEPS_PER_GRID)
102 + play_offset_y;
103 x = garbage.x * DC_GRID_ELEMENT_LENGTH + DC_PLAY_OFFSET_X;
105 // awaking; it is assumed that awaking garbage is always grid wide
106 if (garbage.state & GS_AWAKING) {
108 // if still popping our internal sections
109 if (garbage.alarm - Game::time_step > DC_UNSHATTER_TIME) {
111 // no garbage lightmap for blocks
112 glDisable(GL_TEXTURE_2D);
114 int popped = garbage.sections_popped;
116 for (int h = 0; h < garbage.height; h++)
117 for (int w = 0; w < GC_PLAY_WIDTH; w++) {
119 glPushMatrix();
121 LightManager::setupBlockLights(x + w * DC_GRID_ELEMENT_LENGTH,
122 y + h * DC_GRID_ELEMENT_LENGTH);
123 glTranslatef(x + w * DC_GRID_ELEMENT_LENGTH,
124 y + h * DC_GRID_ELEMENT_LENGTH, DC_PLAY_OFFSET_Z);
126 // if this section is about to pop; this code here mimics code
127 // found in DrawBlocks.cxx
128 if (popped == 0
129 && garbage.pop_alarm - Game::time_step < DC_POP_ROTATE_TIME) {
130 GLfloat p = (garbage.pop_alarm - Game::time_step)
131 * (1.0f / (GLfloat) DC_POP_ROTATE_TIME);
133 // each block rotates a different direction
134 if (garbage.pop_direction & BR_DIRECTION_1) {
135 glRotatef(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_2) {
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 if (garbage.pop_direction & BR_DIRECTION_3) {
141 glRotatef(90.0f - 45.0f * p, 1.0f, 0.0f, 0.0f);
142 glRotatef(-45.0f * p, 0.0f, 1.0f, 0.0f);
143 } else {
144 glRotatef(45.0f * p, 1.0f, 0.0f, 0.0f);
145 glRotatef(-45.0f * p, 0.0f, 1.0f, 0.0f);
148 GLfloat scale = 1.0f - 0.5f * p;
149 glScalef(scale, scale, scale);
151 if (garbage.pop_color == garbage.flavor)
152 glColor3fv(garbage_colors[garbage.flavor]);
153 else
154 glColor3f( (1.0f - p) * garbage_colors[garbage.flavor][0]
155 + p * garbage_colors[garbage.pop_color][0],
156 (1.0f - p) * garbage_colors[garbage.flavor][1]
157 + p * garbage_colors[garbage.pop_color][1],
158 (1.0f - p) * garbage_colors[garbage.flavor][2]
159 + p * garbage_colors[garbage.pop_color][2]);
161 glEnable(rescale_method);
162 glCallList(block_list);
163 glDisable(rescale_method);
165 // if this section has popped
166 } else if (popped > 0) {
167 glColor3fv(garbage_colors[garbage.flavor]);
169 glCallList(block_list);
171 // if this section has not popped
172 } else {
173 glColor3fv(garbage_colors[garbage.pop_color]);
175 // the small block is pre-rotated
176 glCallList(small_block_list);
179 popped--;
180 glPopMatrix();
183 // don't draw a shell
184 glPopMatrix();
186 glEnable(GL_TEXTURE_2D);
188 continue;
190 // if we're about to awake; all sections have popped
191 } else {
192 // crunch our sections back up
194 // no garbage lightmap for blocks
195 glDisable(GL_TEXTURE_2D);
197 GLfloat p = (DC_UNSHATTER_TIME - garbage.alarm + Game::time_step)
198 * (1.0f / (GLfloat) DC_UNSHATTER_TIME);
199 GLfloat scale = 1.0f - 0.5f * p;
201 glColor3fv(garbage_colors[garbage.flavor]);
203 glEnable(rescale_method);
205 for (int h = 0; h < garbage.height; h++)
206 for (int w = 0; w < GC_PLAY_WIDTH; w++) {
208 glPushMatrix();
210 LightManager::setupBlockLights(x + w * DC_GRID_ELEMENT_LENGTH,
211 y + h * DC_GRID_ELEMENT_LENGTH);
212 glTranslatef(x + w * DC_GRID_ELEMENT_LENGTH,
213 y + h * DC_GRID_ELEMENT_LENGTH, DC_PLAY_OFFSET_Z);
215 glRotatef(45.0f * p, 1.0f, 0.0f, 0.0f);
216 glRotatef(45.0f * p, 0.0f, 1.0f, 0.0f);
218 glScalef(scale, scale, scale);
220 glCallList(block_list);
222 glPopMatrix();
225 glDisable(rescale_method);
227 glEnable(GL_TEXTURE_2D);
229 // if we're in the first half of the unshatter
230 if (garbage.alarm - Game::time_step > DC_UNSHATTER_TIME / 4) {
231 // don't draw a shell
232 glPopMatrix();
233 continue;
236 LightManager::setupGarbageLights(x, y, garbage.height,
237 garbage.width);
239 glTranslatef(x, y, DC_PLAY_OFFSET_Z);
241 // only push texture matrix once we know we're using it
242 glMatrixMode(GL_TEXTURE);
243 glPushMatrix();
244 glTranslatef(0.5f + x * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER,
245 0.5f + y * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f);
246 glMatrixMode(GL_MODELVIEW);
248 // clip pane into existance
250 #ifdef DC_CLIP_SHATTER
251 clipping = true;
252 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
253 glDisable(GL_CULL_FACE);
255 glEnable(GL_CLIP_PLANE_SHATTERING);
256 shatter_clip_plane[3] = -(garbage.alarm - Game::time_step)
257 * garbage.height * (DC_GRID_ELEMENT_LENGTH * 4.0f
258 / (GLfloat) DC_UNSHATTER_TIME)
259 + (DC_GRID_ELEMENT_LENGTH / 2.0f);
260 glClipPlane(GL_CLIP_PLANE_SHATTERING, shatter_clip_plane);
261 #else
262 fading = true;
263 alpha = (DC_UNSHATTER_TIME / 4 - garbage.alarm + Game::time_step)
264 * (4.0f / (GLfloat) DC_UNSHATTER_TIME);
265 glEnable(GL_BLEND);
266 #endif
269 } else {
270 LightManager::setupGarbageLights(x, y, garbage.height,
271 garbage.width);
273 glTranslatef(x, y, DC_PLAY_OFFSET_Z);
275 // only push texture matrix once we know we're using it
276 glMatrixMode(GL_TEXTURE);
277 glPushMatrix();
278 glTranslatef(0.5f + x * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER,
279 0.5f + y * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f);
280 glMatrixMode(GL_MODELVIEW);
283 // normal and shattering
285 // if we're shattering
286 if (garbage.state & GS_SHATTERING) {
288 // first we flash
289 if (Game::time_step - garbage.alarm
290 < (DC_SHATTER_FLASH_TIME - DC_SHATTER_TIME)) {
292 GLfloat flash = ((GLfloat) DC_SHATTER_TIME - garbage.alarm
293 + Game::time_step) * (4.0f / (GLfloat) DC_SHATTER_FLASH_TIME);
294 if (flash > 2.0f) flash = 4.0f - flash;
295 if (flash > 1.0f) flash = 2.0f - flash;
296 glColor3f(garbage_colors[garbage.flavor][0] + flash
297 * (DC_FLASH_COLOR_RED - garbage_colors[garbage.flavor][0]),
298 garbage_colors[garbage.flavor][1] + flash
299 * (DC_FLASH_COLOR_GREEN - garbage_colors[garbage.flavor][1]),
300 garbage_colors[garbage.flavor][2] + flash
301 * (DC_FLASH_COLOR_BLUE - garbage_colors[garbage.flavor][2]));
303 } else {
304 // then we clip plane away
306 #ifdef DC_CLIP_SHATTER
307 clipping = true;
308 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
309 glDisable(GL_CULL_FACE);
311 glEnable(GL_CLIP_PLANE_SHATTERING);
312 shatter_clip_plane[3] = -((DC_SHATTER_TIME - DC_SHATTER_FLASH_TIME)
313 - garbage.alarm + Game::time_step) * garbage.height
314 * (DC_GRID_ELEMENT_LENGTH / (GLfloat) (DC_SHATTER_TIME
315 - DC_SHATTER_FLASH_TIME))
316 + (DC_GRID_ELEMENT_LENGTH / 2.0f);
317 glClipPlane(GL_CLIP_PLANE_SHATTERING, shatter_clip_plane);
319 glColor3fv(garbage_colors[garbage.flavor]);
322 } else
323 glColor3fv(garbage_colors[garbage.flavor]);
324 #else
325 fading = true;
326 alpha = (garbage.alarm - Game::time_step)
327 * (1.0f / (GLfloat) (DC_SHATTER_TIME - DC_SHATTER_FLASH_TIME));
328 glEnable(GL_BLEND);
329 glColor4f(garbage_colors[garbage.flavor][0],
330 garbage_colors[garbage.flavor][1],
331 garbage_colors[garbage.flavor][2], alpha);
334 } else if (fading)
335 glColor4f(garbage_colors[garbage.flavor][0],
336 garbage_colors[garbage.flavor][1],
337 garbage_colors[garbage.flavor][2], alpha);
338 else
339 glColor3fv(garbage_colors[garbage.flavor]);
340 #endif
342 // thin garbage
343 if (garbage.height == 1) {
345 if (garbage.width != 1) {
347 glCallList(garbage_thin_cap_list);
348 for (int w = garbage.width - 1; --w; ) {
349 glTranslatef(DC_GRID_ELEMENT_LENGTH, 0.0f, 0.0f);
351 glMatrixMode(GL_TEXTURE);
352 glTranslatef(DC_GRID_ELEMENT_LENGTH
353 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f, 0.0f);
354 glMatrixMode(GL_MODELVIEW);
356 glCallList(garbage_thin_middle_list);
358 glTranslatef(DC_GRID_ELEMENT_LENGTH, 0.0f, 0.0f);
359 glScalef(-1.0f, 1.0f, -1.0f);
361 glMatrixMode(GL_TEXTURE);
362 glTranslatef(DC_GRID_ELEMENT_LENGTH
363 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f, 0.0f);
364 glScalef(-1.0f, 1.0f, -1.0f);
365 glMatrixMode(GL_MODELVIEW);
367 glCallList(garbage_thin_cap_list);
369 // tiny garbage
370 } else
371 glCallList(garbage_small_list);
373 // thick garbage
374 } else {
376 // draw the bottom
377 glPushMatrix();
379 glMatrixMode(GL_TEXTURE);
380 glPushMatrix();
382 glScalef(1.0f, -1.0f, -1.0f);
383 glMatrixMode(GL_MODELVIEW);
385 glScalef(1.0f, -1.0f, -1.0f);
387 glCallList(garbage_thick_corner_list);
388 for (int w = garbage.width - 1; --w; ) {
389 glTranslatef(DC_GRID_ELEMENT_LENGTH, 0.0f, 0.0f);
391 glMatrixMode(GL_TEXTURE);
392 glTranslatef(DC_GRID_ELEMENT_LENGTH
393 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f, 0.0f);
394 glMatrixMode(GL_MODELVIEW);
396 glCallList(garbage_thick_edge_list);
398 glTranslatef(DC_GRID_ELEMENT_LENGTH, 0.0f, 0.0f);
399 glScalef(-1.0f, 1.0f, -1.0f);
401 glMatrixMode(GL_TEXTURE);
402 glTranslatef(DC_GRID_ELEMENT_LENGTH
403 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f, 0.0f);
404 glScalef(-1.0f, 1.0f, -1.0f);
406 glCallList(garbage_thick_corner_list);
408 glPopMatrix();
409 glMatrixMode(GL_MODELVIEW);
411 glPopMatrix();
413 // draw the middle
414 for (int h = garbage.height - 1; --h;) {
415 glPushMatrix();
417 glMatrixMode(GL_TEXTURE);
418 glPushMatrix();
419 glMatrixMode(GL_MODELVIEW);
421 int w = garbage.width - 1;
422 glTranslatef(w * DC_GRID_ELEMENT_LENGTH,
423 h * DC_GRID_ELEMENT_LENGTH, 0.0f);
424 glMultMatrixf(xy_swap_matrix);
426 glMatrixMode(GL_TEXTURE);
427 glTranslatef(w * (DC_GRID_ELEMENT_LENGTH
428 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER), h
429 * (DC_GRID_ELEMENT_LENGTH * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER),
430 0.0f);
431 glMultMatrixf(xy_swap_matrix);
432 glMatrixMode(GL_MODELVIEW);
434 glCallList(garbage_thick_edge_list);
435 while (--w) {
436 glTranslatef(0.0f, -DC_GRID_ELEMENT_LENGTH, 0.0f);
438 glMatrixMode(GL_TEXTURE);
439 glTranslatef(0.0f, -DC_GRID_ELEMENT_LENGTH
440 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f);
441 glMatrixMode(GL_MODELVIEW);
443 glCallList(garbage_thick_middle_list);
445 glTranslatef(0.0f, -DC_GRID_ELEMENT_LENGTH, 0.0f);
446 glScalef(1.0f, -1.0f, -1.0f);
448 glMatrixMode(GL_TEXTURE);
449 glTranslatef(0.0f, -DC_GRID_ELEMENT_LENGTH
450 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f);
451 glScalef(1.0f, -1.0f, -1.0f);
452 glMatrixMode(GL_MODELVIEW);
454 glCallList(garbage_thick_edge_list);
456 glPopMatrix();
458 glMatrixMode(GL_TEXTURE);
459 glPopMatrix();
460 glMatrixMode(GL_MODELVIEW);
463 // draw the top
464 glPushMatrix();
466 glMatrixMode(GL_TEXTURE);
467 glPushMatrix();
469 glTranslatef(0.0f, (garbage.height - 1) * (DC_GRID_ELEMENT_LENGTH
470 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER), 0.0f);
472 glMatrixMode(GL_MODELVIEW);
473 glTranslatef(0.0f, (garbage.height - 1) * DC_GRID_ELEMENT_LENGTH,
474 0.0f);
476 glCallList(garbage_thick_corner_list);
477 for (int w = garbage.width - 1; --w; ) {
478 glTranslatef(DC_GRID_ELEMENT_LENGTH, 0.0f, 0.0f);
480 glMatrixMode(GL_TEXTURE);
481 glTranslatef(DC_GRID_ELEMENT_LENGTH
482 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f, 0.0f);
483 glMatrixMode(GL_MODELVIEW);
485 glCallList(garbage_thick_edge_list);
487 glTranslatef(DC_GRID_ELEMENT_LENGTH, 0.0f, 0.0f);
488 glScalef(-1.0f, 1.0f, -1.0f);
490 glMatrixMode(GL_TEXTURE);
491 glTranslatef(DC_GRID_ELEMENT_LENGTH
492 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f, 0.0f);
493 glScalef(-1.0f, 1.0f, -1.0f);
495 glCallList(garbage_thick_corner_list);
497 glPopMatrix();
498 glMatrixMode(GL_MODELVIEW);
500 glPopMatrix();
502 if (!(MetaState::mode & CM_REALLY_LOW_GRAPHICS)) {
503 // draw flavor image; if any
504 if (GarbageFlavorImage::associated_garbage_id == garbage.id) {
505 #ifndef NO_MULTITEXTURING
506 if (state & DS_MULTITEXTURING) {
507 glPushAttrib(GL_LIGHTING_BIT | GL_ENABLE_BIT);
509 glMatrixMode(GL_TEXTURE);
510 glLoadIdentity();
512 glBindTexture(GL_TEXTURE_2D, garbage_texture);
514 glActiveTextureARB(GL_TEXTURE1_ARB);
515 glPushMatrix();
516 glTranslatef(0.5f + (x + 2.0f * GarbageFlavorImage::x)
517 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER,
518 0.5f + (y + 2.0f * GarbageFlavorImage::y)
519 * DC_GARBAGE_LIGHTMAP_COORD_CONVERTER, 0.0f);
521 glEnable(GL_TEXTURE_2D);
522 glEnable(GL_BLEND);
524 glColor3fv(white);
526 glMatrixMode(GL_MODELVIEW);
527 glTranslatef(GarbageFlavorImage::x * DC_GRID_ELEMENT_LENGTH,
528 GarbageFlavorImage::y * DC_GRID_ELEMENT_LENGTH,
529 DC_GARBAGE_FLAVOR_TEX_OFFSET_Z);
531 glCallList(garbage_flavor_list);
533 glMatrixMode(GL_TEXTURE);
534 glPopMatrix();
535 glActiveTextureARB(GL_TEXTURE0_ARB);
536 glMatrixMode(GL_MODELVIEW);
538 glPopAttrib();
540 glBindTexture(GL_TEXTURE_2D, garbage_lightmap);
542 } else {
543 #endif
544 glPushAttrib(GL_LIGHTING_BIT | GL_ENABLE_BIT);
546 glMatrixMode(GL_TEXTURE);
547 glLoadIdentity();
549 glBindTexture(GL_TEXTURE_2D, garbage_texture);
551 glEnable(GL_BLEND);
553 glColor3fv(white);
555 glMatrixMode(GL_MODELVIEW);
556 glTranslatef(GarbageFlavorImage::x * DC_GRID_ELEMENT_LENGTH,
557 GarbageFlavorImage::y * DC_GRID_ELEMENT_LENGTH,
558 DC_GARBAGE_FLAVOR_TEX_OFFSET_Z);
560 glCallList(garbage_flavor_list);
562 glBindTexture(GL_TEXTURE_2D, garbage_lightmap);
564 glPopAttrib();
565 #ifndef NO_MULTITEXTURING
567 #endif
572 // turn off the clip plane
573 #ifdef DC_CLIP_SHATTER
574 if (clipping) {
575 clipping = false;
577 glDisable(GL_CLIP_PLANE_SHATTERING);
578 glEnable(GL_CULL_FACE);
579 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
580 #else
581 if (fading) {
582 fading = false;
584 glDisable(GL_BLEND);
585 #endif
587 // delete fully shattered garbage; note that we can't assume
588 // we'll display each time step
589 if (garbage.alarm <= Game::time_step)
590 GarbageManager::deleteGarbage(&garbage);
593 glPopMatrix();
594 glMatrixMode(GL_TEXTURE);
595 glPopMatrix();
596 glMatrixMode(GL_MODELVIEW);