probable fix for severe model rendering bugs in 3DFX voodoo4/5 win32 drivers, and...
[divverent/darkplaces.git] / r_explosion.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22
23 float TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal);
24
25 #define MAX_EXPLOSIONS 64
26 #define EXPLOSIONGRID 16
27 #define EXPLOSIONVERTS ((EXPLOSIONGRID+1)*(EXPLOSIONGRID+1))
28 #define EXPLOSIONTRIS (EXPLOSIONVERTS*2)
29 #define EXPLOSIONSTARTRADIUS (0.0f)
30 #define EXPLOSIONSTARTVELOCITY (500.0f)
31 #define EXPLOSIONFADESTART (1.5f)
32 #define EXPLOSIONFADERATE (6.0f)
33
34 vec3_t explosionspherevert[EXPLOSIONVERTS];
35 vec3_t explosionspherevertvel[EXPLOSIONVERTS];
36 float explosiontexcoords[EXPLOSIONVERTS][2];
37 int explosiontris[EXPLOSIONTRIS][3];
38 int explosionnoiseindex[EXPLOSIONVERTS];
39 vec3_t explosionpoint[EXPLOSIONVERTS];
40
41 typedef struct explosion_s
42 {
43         float starttime;
44         float alpha;
45         vec3_t vert[EXPLOSIONVERTS];
46         vec3_t vertvel[EXPLOSIONVERTS];
47 }
48 explosion_t;
49
50 explosion_t explosion[128];
51
52 rtexture_t      *explosiontexture;
53 rtexture_t      *explosiontexturefog;
54
55 cvar_t r_explosionclip = {"r_explosionclip", "0", true};
56 cvar_t r_drawexplosions = {"r_drawexplosions", "1"};
57
58 int R_ExplosionVert(int column, int row)
59 {
60         int i;
61         float a, b, c;
62         i = row * (EXPLOSIONGRID + 1) + column;
63         a = row * M_PI * 2 / EXPLOSIONGRID;
64         b = column * M_PI * 2 / EXPLOSIONGRID;
65         c = cos(b);
66         explosionpoint[i][0] = cos(a) * c;
67         explosionpoint[i][1] = sin(a) * c;
68         explosionpoint[i][2] = -sin(b);
69         explosionnoiseindex[i] = (row & (EXPLOSIONGRID - 1)) * EXPLOSIONGRID + (column & (EXPLOSIONGRID - 1));
70         explosiontexcoords[i][0] = (float) column / (float) EXPLOSIONGRID;
71         explosiontexcoords[i][1] = (float) row / (float) EXPLOSIONGRID;
72         return i;
73 }
74
75 void r_explosion_start(void)
76 {
77         int x, y;
78         byte noise1[128][128], noise2[128][128], data[128][128][4];
79         fractalnoise(&noise1[0][0], 128, 2);
80         fractalnoise(&noise2[0][0], 128, 2);
81         for (y = 0;y < 128;y++)
82         {
83                 for (x = 0;x < 128;x++)
84                 {
85                         int j, r, g, b, a;
86                         j = noise1[y][x] * 3 - 128;
87                         r = (j * 512) / 256;
88                         g = (j * 256) / 256;
89                         b = (j * 128) / 256;
90                         a = noise2[y][x];
91                         data[y][x][0] = bound(0, r, 255);
92                         data[y][x][1] = bound(0, g, 255);
93                         data[y][x][2] = bound(0, b, 255);
94                         data[y][x][3] = bound(0, a, 255);
95                 }
96         }
97         explosiontexture = R_LoadTexture ("explosiontexture", 128, 128, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
98         for (y = 0;y < 128;y++)
99                 for (x = 0;x < 128;x++)
100                         data[y][x][0] = data[y][x][1] = data[y][x][2] = 255;
101         explosiontexturefog = R_LoadTexture ("explosiontexturefog", 128, 128, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
102 }
103
104 void r_explosion_shutdown(void)
105 {
106 }
107
108 void r_explosion_newmap(void)
109 {
110         memset(explosion, 0, sizeof(explosion));
111 }
112
113 void R_Explosion_Init(void)
114 {
115         int i, x, y;
116         i = 0;
117         for (y = 0;y < EXPLOSIONGRID;y++)
118         {
119                 for (x = 0;x < EXPLOSIONGRID;x++)
120                 {
121                         explosiontris[i][0] = R_ExplosionVert(x    , y    );
122                         explosiontris[i][1] = R_ExplosionVert(x + 1, y    );
123                         explosiontris[i][2] = R_ExplosionVert(x    , y + 1);
124                         i++;
125                         explosiontris[i][0] = R_ExplosionVert(x + 1, y    );
126                         explosiontris[i][1] = R_ExplosionVert(x + 1, y + 1);
127                         explosiontris[i][2] = R_ExplosionVert(x    , y + 1);
128                         i++;
129                 }
130         }
131         for (i = 0;i < EXPLOSIONVERTS;i++)
132         {
133                 explosionspherevert[i][0] = explosionpoint[i][0] * EXPLOSIONSTARTRADIUS;
134                 explosionspherevert[i][1] = explosionpoint[i][1] * EXPLOSIONSTARTRADIUS;
135                 explosionspherevert[i][2] = explosionpoint[i][2] * EXPLOSIONSTARTRADIUS;
136                 explosionspherevertvel[i][0] = explosionpoint[i][0] * EXPLOSIONSTARTVELOCITY;
137                 explosionspherevertvel[i][1] = explosionpoint[i][1] * EXPLOSIONSTARTVELOCITY;
138                 explosionspherevertvel[i][2] = explosionpoint[i][2] * EXPLOSIONSTARTVELOCITY;
139         }
140
141         Cvar_RegisterVariable(&r_explosionclip);
142         Cvar_RegisterVariable(&r_drawexplosions);
143
144         R_RegisterModule("R_Explosions", r_explosion_start, r_explosion_shutdown, r_explosion_newmap);
145 }
146
147 void R_NewExplosion(vec3_t org)
148 {
149         int i, j;
150         float dist;
151         byte noise[EXPLOSIONGRID*EXPLOSIONGRID];
152         fractalnoise(noise, EXPLOSIONGRID, 2);
153         for (i = 0;i < MAX_EXPLOSIONS;i++)
154         {
155                 if (explosion[i].alpha <= 0.0f)
156                 {
157                         explosion[i].alpha = EXPLOSIONFADESTART;
158                         for (j = 0;j < EXPLOSIONVERTS;j++)
159                         {
160                                 dist = noise[explosionnoiseindex[j]] * (1.0f / 512.0f) + 0.5;
161                                 explosion[i].vert[j][0] = explosionspherevert[j][0] * dist + org[0];
162                                 explosion[i].vert[j][1] = explosionspherevert[j][1] * dist + org[1];
163                                 explosion[i].vert[j][2] = explosionspherevert[j][2] * dist + org[2];
164                                 explosion[i].vertvel[j][0] = explosionspherevertvel[j][0] * dist;
165                                 explosion[i].vertvel[j][1] = explosionspherevertvel[j][1] * dist;
166                                 explosion[i].vertvel[j][2] = explosionspherevertvel[j][2] * dist;
167                         }
168                         break;
169                 }
170         }
171 }
172
173 void R_DrawExplosion(explosion_t *e)
174 {
175         int i, index, *indexlist = &explosiontris[0][0], alpha = bound(0, e->alpha * 128.0f, 128), texnum, fogtexnum;
176         float s, t;
177 //      s = cl.time * 1;
178 //      t = cl.time * 0.75;
179 //      s -= (int) s;
180 //      t -= (int) t;
181         s = 0;
182         t = 0;
183         /*
184         glColor4f(1,1,1,e->alpha);
185         glDisable(GL_TEXTURE_2D);
186 //      glBindTexture(GL_TEXTURE_2D, explosiontexture);
187         glVertexPointer(3, GL_FLOAT, sizeof(float[3]), (float *) &e->vert[0][0]);
188 //      glTexCoordPointer(2, GL_FLOAT, sizeof(float[2]), (float *) &explosiontexcoords[0][0]);
189         glEnableClientState(GL_VERTEX_ARRAY);
190 //      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
191         glDrawElements(GL_TRIANGLES, EXPLOSIONTRIS, GL_UNSIGNED_INT, indexlist);
192 //      glDisableClientState(GL_TEXTURE_COORD_ARRAY);
193         glDisableClientState(GL_VERTEX_ARRAY);
194         glEnable(GL_TEXTURE_2D);
195         */
196         texnum = R_GetTexture(explosiontexture);
197         fogtexnum = R_GetTexture(explosiontexturefog);
198         for (i = 0;i < EXPLOSIONTRIS;i++)
199         {
200                 transpolybegin(texnum, 0, fogtexnum, TPOLYTYPE_ALPHA);
201                 index = *indexlist++;transpolyvert(e->vert[index][0], e->vert[index][1], e->vert[index][2], explosiontexcoords[index][0] + s, explosiontexcoords[index][1] + t, 255, 255, 255, alpha);
202                 index = *indexlist++;transpolyvert(e->vert[index][0], e->vert[index][1], e->vert[index][2], explosiontexcoords[index][0] + s, explosiontexcoords[index][1] + t, 255, 255, 255, alpha);
203                 index = *indexlist++;transpolyvert(e->vert[index][0], e->vert[index][1], e->vert[index][2], explosiontexcoords[index][0] + s, explosiontexcoords[index][1] + t, 255, 255, 255, alpha);
204                 transpolyend();
205         }
206 }
207
208 void R_MoveExplosion(explosion_t *e, float frametime)
209 {
210         int i;
211         vec3_t end;
212         e->alpha -= frametime * EXPLOSIONFADERATE;
213         for (i = 0;i < EXPLOSIONVERTS;i++)
214         {
215                 if (e->vertvel[i][0] || e->vertvel[i][1] || e->vertvel[i][2])
216                 {
217                         end[0] = e->vert[i][0] + frametime * e->vertvel[i][0];
218                         end[1] = e->vert[i][1] + frametime * e->vertvel[i][1];
219                         end[2] = e->vert[i][2] + frametime * e->vertvel[i][2];
220                         if (r_explosionclip.value)
221                         {
222                                 float f, dot;
223                                 vec3_t impact, normal;
224                                 f = TraceLine(e->vert[i], end, impact, normal);
225                                 VectorCopy(impact, e->vert[i]);
226                                 if (f < 1)
227                                 {
228                                         // clip velocity against the wall
229                                         dot = -DotProduct(e->vertvel[i], normal);
230                                         e->vertvel[i][0] += normal[0] * dot;
231                                         e->vertvel[i][1] += normal[1] * dot;
232                                         e->vertvel[i][2] += normal[2] * dot;
233                                 }
234                         }
235                         else
236                         {
237                                 VectorCopy(end, e->vert[i]);
238                         }
239                 }
240         }
241 }
242
243 void R_MoveExplosions(void)
244 {
245         int i;
246         float frametime;
247         frametime = cl.time - cl.oldtime;
248         for (i = 0;i < MAX_EXPLOSIONS;i++)
249         {
250                 if (explosion[i].alpha > 0.0f)
251                 {
252                         if (explosion[i].starttime > cl.time)
253                         {
254                                 explosion[i].alpha = 0;
255                                 continue;
256                         }
257                         R_MoveExplosion(&explosion[i], frametime);
258                 }
259         }
260 }
261
262 void R_DrawExplosions(void)
263 {
264         int i;
265         if (!r_drawexplosions.value)
266                 return;
267         for (i = 0;i < MAX_EXPLOSIONS;i++)
268         {
269                 if (explosion[i].alpha > 0.0f)
270                 {
271                         R_DrawExplosion(&explosion[i]);
272                 }
273         }
274 }