1 /*
2 * Copyright(c) 1997-2001 Id Software, Inc.
3 * Copyright(c) 2002 The Quakeforge Project.
4 * Copyright(c) 2006 Quetoo.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or(at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 *
15 * See the GNU General Public License for more details.
16 *
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.
20 */
21
22 #include "video.h"
23
24 /*
25
26 ALIAS MODELS
27
28 */
29
30 #define NUMVERTEXNORMALS 162
31
32 float r_avertexnormals[NUMVERTEXNORMALS][3] = {
33 #include "anorms.h"
34 };
35
36 typedef float vec4_t[4];
37
38 static vec4_t s_lerped[MAX_VERTS];
39
40 vec3_t shadevector;
41 float shadelight[3];
42
43 // precalculated dot products for quantized angles
44 #define SHADEDOT_QUANT 16
45
46 float r_avertexnormal_dots[SHADEDOT_QUANT][256] =
47 #include "anormtab.h"
48 ;
49
50 float *shadedots = r_avertexnormal_dots[0];
51
GL_LerpVerts(int nverts,dtrivertx_t * v,dtrivertx_t * ov,dtrivertx_t * verts,float * lerp,float move[3],float frontv[3],float backv[3])52 void GL_LerpVerts(int nverts, dtrivertx_t *v, dtrivertx_t *ov, dtrivertx_t *verts, float *lerp, float move[3], float frontv[3], float backv[3]){
53 int i;
54
55 if(currententity->flags &(RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE)){
56 for(i = 0; i < nverts; i++, v++, ov++, lerp += 4){
57 float * normal = r_avertexnormals[verts[i].lightnormalindex];
58
59 lerp[0] = move[0] + ov->v[0] * backv[0] + v->v[0] * frontv[0] + normal[0] * POWERSUIT_SCALE;
60 lerp[1] = move[1] + ov->v[1] * backv[1] + v->v[1] * frontv[1] + normal[1] * POWERSUIT_SCALE;
61 lerp[2] = move[2] + ov->v[2] * backv[2] + v->v[2] * frontv[2] + normal[2] * POWERSUIT_SCALE;
62 }
63 } else {
64 for(i = 0; i < nverts; i++, v++, ov++, lerp += 4){
65 lerp[0] = move[0] + ov->v[0] * backv[0] + v->v[0] * frontv[0];
66 lerp[1] = move[1] + ov->v[1] * backv[1] + v->v[1] * frontv[1];
67 lerp[2] = move[2] + ov->v[2] * backv[2] + v->v[2] * frontv[2];
68 }
69 }
70 }
71
72 /*
73 GL_DrawAliasFrameLerp
74
75 interpolates between two frames and origins
76 FIXME: batch lerp all vertexes
77 */
GL_DrawAliasFrameLerp(dmdl_t * paliashdr,float backlerp)78 void GL_DrawAliasFrameLerp(dmdl_t *paliashdr, float backlerp){
79 float l;
80 daliasframe_t *frame, *oldframe;
81 dtrivertx_t *v, *ov, *verts;
82 int *order;
83 int count;
84 float frontlerp;
85 float alpha;
86 vec3_t move, delta, vectors[3];
87 vec3_t frontv, backv;
88 int i;
89 int index_xyz;
90 float *lerp;
91
92 frame =(daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames
93 + currententity->frame * paliashdr->framesize);
94 verts = v = frame->verts;
95
96 oldframe =(daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames
97 + currententity->oldframe * paliashdr->framesize);
98 ov = oldframe->verts;
99
100 order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds);
101
102 if(currententity->flags & RF_TRANSLUCENT)
103 alpha = currententity->alpha;
104 else
105 alpha = 1.0;
106
107 if(currententity->flags &(RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE))
108 qglDisable(GL_TEXTURE_2D);
109
110 frontlerp = 1.0 - backlerp;
111
112 // move should be the delta back to the previous frame * backlerp
113 VectorSubtract(currententity->oldorigin, currententity->origin, delta);
114 AngleVectors(currententity->angles, vectors[0], vectors[1], vectors[2]);
115
116 move[0] = DotProduct(delta, vectors[0]); // forward
117 move[1] = -DotProduct(delta, vectors[1]); // left
118 move[2] = DotProduct(delta, vectors[2]); // up
119
120 VectorAdd(move, oldframe->translate, move);
121
122 for(i = 0; i < 3; i++){
123 move[i] = backlerp * move[i] + frontlerp * frame->translate[i];
124 }
125
126 for(i = 0; i < 3; i++){
127 frontv[i] = frontlerp * frame->scale[i];
128 backv[i] = backlerp * oldframe->scale[i];
129 }
130
131 lerp = s_lerped[0];
132
133 GL_LerpVerts(paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv);
134
135 if(gl_vertex_arrays->value){
136 float colorArray[MAX_VERTS * 4];
137
138 qglEnableClientState(GL_VERTEX_ARRAY);
139 qglVertexPointer(3, GL_FLOAT, 16, s_lerped); // padded for SIMD
140
141 if(currententity->flags &(RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE)){
142 qglColor4f(shadelight[0], shadelight[1], shadelight[2], alpha);
143 } else {
144 qglEnableClientState(GL_COLOR_ARRAY);
145 qglColorPointer(3, GL_FLOAT, 0, colorArray);
146
147 // pre light everything
148 for(i = 0; i < paliashdr->num_xyz; i++){
149 float l = shadedots[verts[i].lightnormalindex];
150
151 colorArray[i * 3 + 0] = l * shadelight[0];
152 colorArray[i * 3 + 1] = l * shadelight[1];
153 colorArray[i * 3 + 2] = l * shadelight[2];
154 }
155 }
156
157 if(qglLockArraysEXT != 0)
158 qglLockArraysEXT(0, paliashdr->num_xyz);
159
160 while(1){
161 // get the vertex count and primitive type
162 count = *order++;
163 if(!count)
164 break; // done
165 if(count < 0){
166 count = -count;
167 qglBegin(GL_TRIANGLE_FAN);
168 } else {
169 qglBegin(GL_TRIANGLE_STRIP);
170 }
171
172 if(currententity->flags &(RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE)){
173 do {
174 index_xyz = order[2];
175 order += 3;
176
177 qglVertex3fv(s_lerped[index_xyz]);
178
179 } while(--count);
180 } else {
181 do {
182 // texture coordinates come from the draw list
183 qglTexCoord2f(((float *)order)[0],((float *)order)[1]);
184 index_xyz = order[2];
185
186 order += 3;
187
188 qglArrayElement(index_xyz);
189
190 } while(--count);
191 }
192 qglEnd();
193 }
194
195 if(qglUnlockArraysEXT != 0)
196 qglUnlockArraysEXT();
197 } else {
198 while(1){
199 // get the vertex count and primitive type
200 count = *order++;
201 if(!count)
202 break; // done
203 if(count < 0){
204 count = -count;
205 qglBegin(GL_TRIANGLE_FAN);
206 } else {
207 qglBegin(GL_TRIANGLE_STRIP);
208 }
209
210 if(currententity->flags &(RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE)){
211 do {
212 index_xyz = order[2];
213 order += 3;
214
215 qglColor4f(shadelight[0], shadelight[1], shadelight[2], alpha);
216 qglVertex3fv(s_lerped[index_xyz]);
217
218 } while(--count);
219 } else {
220 do {
221 // texture coordinates come from the draw list
222 qglTexCoord2f(((float *)order)[0],((float *)order)[1]);
223 index_xyz = order[2];
224 order += 3;
225
226 // normals and vertexes come from the frame list
227 l = shadedots[verts[index_xyz].lightnormalindex];
228
229 qglColor4f(l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha);
230 qglVertex3fv(s_lerped[index_xyz]);
231 } while(--count);
232 }
233
234 qglEnd();
235 }
236 }
237
238 if(currententity->flags &(RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE))
239 qglEnable(GL_TEXTURE_2D);
240 }
241
242
243 /*
244 GL_CullAliasModel
245 */
GL_CullAliasModel(vec3_t bbox[8],entity_t * e)246 static qboolean GL_CullAliasModel(vec3_t bbox[8], entity_t *e){
247 int i;
248 vec3_t mins, maxs;
249 dmdl_t *paliashdr;
250 vec3_t vectors[3];
251 vec3_t thismins, oldmins, thismaxs, oldmaxs;
252 daliasframe_t *pframe, *poldframe;
253 vec3_t angles;
254
255 paliashdr = (dmdl_t *)currentmodel->extradata;
256
257 if((e->frame >= paliashdr->num_frames) ||(e->frame < 0)){
258 Com_Printf("GL_CullAliasModel %s: no such frame %d\n",
259 currentmodel->name, e->frame);
260 e->frame = 0;
261 }
262 if((e->oldframe >= paliashdr->num_frames) ||(e->oldframe < 0)){
263 Com_Printf("GL_CullAliasModel %s: no such oldframe %d\n",
264 currentmodel->name, e->oldframe);
265 e->oldframe = 0;
266 }
267
268 pframe = (daliasframe_t *)((byte *) paliashdr +
269 paliashdr->ofs_frames +
270 e->frame * paliashdr->framesize);
271
272 poldframe = (daliasframe_t *)((byte *) paliashdr +
273 paliashdr->ofs_frames +
274 e->oldframe * paliashdr->framesize);
275
276 // compute axially aligned mins and maxs
277 if(pframe == poldframe){
278 for(i = 0; i < 3; i++){
279 mins[i] = pframe->translate[i];
280 maxs[i] = mins[i] + pframe->scale[i] * 255;
281 }
282 } else {
283 for(i = 0; i < 3; i++){
284 thismins[i] = pframe->translate[i];
285 thismaxs[i] = thismins[i] + pframe->scale[i] * 255;
286
287 oldmins[i] = poldframe->translate[i];
288 oldmaxs[i] = oldmins[i] + poldframe->scale[i] * 255;
289
290 if(thismins[i] < oldmins[i])
291 mins[i] = thismins[i];
292 else
293 mins[i] = oldmins[i];
294
295 if(thismaxs[i] > oldmaxs[i])
296 maxs[i] = thismaxs[i];
297 else
298 maxs[i] = oldmaxs[i];
299 }
300 }
301
302 // compute a full bounding box
303 for(i = 0; i < 8; i++){
304 vec3_t tmp;
305
306 if(i & 1)
307 tmp[0] = mins[0];
308 else
309 tmp[0] = maxs[0];
310
311 if(i & 2)
312 tmp[1] = mins[1];
313 else
314 tmp[1] = maxs[1];
315
316 if(i & 4)
317 tmp[2] = mins[2];
318 else
319 tmp[2] = maxs[2];
320
321 VectorCopy(tmp, bbox[i]);
322 }
323
324 // rotate the bounding box
325 VectorCopy(e->angles, angles);
326 angles[YAW] = -angles[YAW];
327 AngleVectors(angles, vectors[0], vectors[1], vectors[2]);
328
329 for(i = 0; i < 8; i++){
330 vec3_t tmp;
331
332 VectorCopy(bbox[i], tmp);
333
334 bbox[i][0] = DotProduct(vectors[0], tmp);
335 bbox[i][1] = -DotProduct(vectors[1], tmp);
336 bbox[i][2] = DotProduct(vectors[2], tmp);
337
338 VectorAdd(e->origin, bbox[i], bbox[i]);
339 }
340
341 {
342 int p, f, aggregatemask = ~0;
343
344 for(p = 0; p < 8; p++){
345 int mask = 0;
346
347 for(f = 0; f < 4; f++){
348 float dp = DotProduct(frustum[f].normal, bbox[p]);
349
350 if((dp - frustum[f].dist) < 0){
351 mask |=(1 << f);
352 }
353 }
354
355 aggregatemask &= mask;
356 }
357
358 if(aggregatemask){
359 return true;
360 }
361
362 return false;
363 }
364 }
365
366 /*
367 GL_DrawAliasModel
368 */
GL_DrawAliasModel(entity_t * e)369 void GL_DrawAliasModel(entity_t *e){
370 int i;
371 dmdl_t *paliashdr;
372 float an;
373 vec3_t bbox[8];
374 image_t *skin;
375
376 if(GL_CullAliasModel(bbox, e))
377 return;
378
379 paliashdr = (dmdl_t *)currentmodel->extradata;
380
381 // get lighting information
382 if(currententity->flags & (RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE)){
383 VectorClear(shadelight);
384 if(currententity->flags & RF_SHELL_RED)
385 shadelight[0] = 1.0;
386 if(currententity->flags & RF_SHELL_GREEN)
387 shadelight[1] = 1.0;
388 if(currententity->flags & RF_SHELL_BLUE)
389 shadelight[2] = 1.0;
390 } else if(currententity->flags & RF_FULLBRIGHT || r_fullbright->value){
391 shadelight[0] = 1.0; shadelight[1] = 1.0; shadelight[2] = 1.0;
392 } else {
393 GL_LightPoint(currententity->origin, shadelight);
394 }
395
396 if(currententity->flags & RF_MINLIGHT){
397 for(i = 0; i < 3; i++)
398 if(shadelight[i] > 0.1)
399 break;
400 if(i == 3){
401 shadelight[0] = 0.1;
402 shadelight[1] = 0.1;
403 shadelight[2] = 0.1;
404 }
405 }
406
407 // lets not draw anything black
408 if(shadelight[0] == 0 && shadelight[1] == 0 && shadelight[2] == 0)
409 shadelight[0] = shadelight[1] = shadelight[2] = .4;
410
411 shadedots = r_avertexnormal_dots[((int)(currententity->angles[1] *
412 (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];
413
414 an = currententity->angles[1] / 180 * M_PI;
415 shadevector[0] = cos(-an);
416 shadevector[1] = sin(-an);
417 shadevector[2] = 1;
418 VectorNormalize(shadevector);
419
420 // locate the proper data
421 c_alias_polys += paliashdr->num_tris;
422
423 // draw all the triangles
424 qglPushMatrix();
425 e->angles[PITCH] = -e->angles[PITCH]; // sigh.
426 GL_RotateForEntity(e);
427 e->angles[PITCH] = -e->angles[PITCH]; // sigh.
428
429 // select skin
430 if(currententity->skin)
431 skin = currententity->skin; // custom player skin
432 else {
433 if(currententity->skinnum >= MAX_MD2SKINS)
434 skin = currentmodel->skins[0];
435 else {
436 skin = currentmodel->skins[currententity->skinnum];
437 if(!skin)
438 skin = currentmodel->skins[0];
439 }
440 }
441 if(!skin) skin = r_notexture; // fallback
442 GL_Bind(skin->texnum);
443
444 // draw it
445 qglShadeModel(GL_SMOOTH);
446
447 GL_TexEnv(GL_MODULATE);
448 if(currententity->flags & RF_TRANSLUCENT){
449 qglEnable(GL_BLEND);
450 }
451
452 if((currententity->frame >= paliashdr->num_frames) || (currententity->frame < 0)){
453 Com_Printf( "GL_DrawAliasModel %s: no such frame %d\n",
454 currentmodel->name, currententity->frame);
455 currententity->frame = 0;
456 currententity->oldframe = 0;
457 }
458
459 if((currententity->oldframe >= paliashdr->num_frames) || (currententity->oldframe < 0)){
460 Com_Printf( "GL_DrawAliasModel %s: no such oldframe %d\n",
461 currentmodel->name, currententity->oldframe);
462 currententity->frame = 0;
463 currententity->oldframe = 0;
464 }
465
466 if(!r_lerpmodels->value)
467 currententity->backlerp = 0;
468
469 GL_DrawAliasFrameLerp(paliashdr, currententity->backlerp);
470
471 GL_TexEnv(GL_REPLACE);
472 qglShadeModel(GL_FLAT);
473
474 qglPopMatrix();
475
476 if(currententity->flags & RF_TRANSLUCENT){
477 qglDisable(GL_BLEND);
478 }
479
480 qglColor4ubv(color_white);
481 }
482