improved TraceLine in chase.c to be more generally useful (should move it to another...
[divverent/darkplaces.git] / gl_models.c
1
2 #include "quakedef.h"
3
4 typedef struct
5 {
6         float m[3][4];
7 } zymbonematrix;
8
9 // LordHavoc: vertex array
10 float *aliasvert;
11 float *modelaliasvert;
12 float *aliasvertnorm;
13 byte *aliasvertcolor;
14 byte *aliasvertcolor2;
15 zymbonematrix *zymbonepose;
16 int *aliasvertusage;
17
18 int chrometexture;
19
20 void makechrometexture()
21 {
22         int i;
23         byte noise[64*64];
24         byte data[64*64][4];
25
26         fractalnoise(noise, 64, 16);
27
28         // convert to RGBA data
29         for (i = 0;i < 64*64;i++)
30         {
31                 data[i][0] = data[i][1] = data[i][2] = noise[i];
32                 data[i][3] = 255;
33         }
34
35         chrometexture = GL_LoadTexture ("chrometexture", 64, 64, &data[0][0], true, false, 4);
36 }
37
38 void gl_models_start()
39 {
40         // allocate vertex processing arrays
41         aliasvert = qmalloc(sizeof(float[MD2MAX_VERTS][3]));
42         modelaliasvert = qmalloc(sizeof(float[MD2MAX_VERTS][3]));
43         aliasvertnorm = qmalloc(sizeof(float[MD2MAX_VERTS][3]));
44         aliasvertcolor = qmalloc(sizeof(byte[MD2MAX_VERTS][4]));
45         aliasvertcolor2 = qmalloc(sizeof(byte[MD2MAX_VERTS][4])); // used temporarily for tinted coloring
46         zymbonepose = qmalloc(sizeof(zymbonematrix[256]));
47         aliasvertusage = qmalloc(sizeof(int[MD2MAX_VERTS]));
48         makechrometexture();
49 }
50
51 void gl_models_shutdown()
52 {
53         qfree(aliasvert);
54         qfree(aliasvertnorm);
55         qfree(aliasvertcolor);
56         qfree(aliasvertcolor2);
57         qfree(zymbonepose);
58         qfree(aliasvertusage);
59 }
60
61 void GL_Models_Init()
62 {
63         R_RegisterModule("GL_Models", gl_models_start, gl_models_shutdown);
64 }
65
66 extern vec3_t softwaretransform_x;
67 extern vec3_t softwaretransform_y;
68 extern vec3_t softwaretransform_z;
69 extern vec_t softwaretransform_scale;
70 extern vec3_t softwaretransform_offset;
71 extern cvar_t r_modelsdonttransformnormals;
72 void R_AliasLerpVerts(int vertcount, float lerp, trivert2 *verts1, vec3_t scale1, vec3_t translate1, trivert2 *verts2, vec3_t scale2, vec3_t translate2)
73 {
74         int i;
75         vec3_t point, matrix_x, matrix_y, matrix_z;
76         float *av, *avn;
77         av = aliasvert;
78         avn = aliasvertnorm;
79         VectorScale(softwaretransform_x, softwaretransform_scale, matrix_x);
80         VectorScale(softwaretransform_y, softwaretransform_scale, matrix_y);
81         VectorScale(softwaretransform_z, softwaretransform_scale, matrix_z);
82         if (lerp < 0) lerp = 0;
83         if (lerp > 1) lerp = 1;
84         if (lerp != 0)
85         {
86                 float ilerp, ilerp127, lerp127, scalex1, scalex2, translatex, scaley1, scaley2, translatey, scalez1, scalez2, translatez;
87                 ilerp = 1 - lerp;
88                 ilerp127 = ilerp * (1.0 / 127.0);
89                 lerp127 = lerp * (1.0 / 127.0);
90                 // calculate combined interpolation variables
91                 scalex1 = scale1[0] * ilerp;scalex2 = scale2[0] *  lerp;translatex = translate1[0] * ilerp + translate2[0] *  lerp;
92                 scaley1 = scale1[1] * ilerp;scaley2 = scale2[1] *  lerp;translatey = translate1[1] * ilerp + translate2[1] *  lerp;
93                 scalez1 = scale1[2] * ilerp;scalez2 = scale2[2] *  lerp;translatez = translate1[2] * ilerp + translate2[2] *  lerp;
94                 // generate vertices
95                 if (r_modelsdonttransformnormals.value)
96                 {
97                         float *modelav = modelaliasvert;
98                         for (i = 0;i < vertcount;i++)
99                         {
100                                 // rotate, scale, and translate the vertex locations
101                                 point[0] = verts1->v[0] * scalex1 + verts2->v[0] * scalex2 + translatex;
102                                 point[1] = verts1->v[1] * scaley1 + verts2->v[1] * scaley2 + translatey;
103                                 point[2] = verts1->v[2] * scalez1 + verts2->v[2] * scalez2 + translatez;
104                                 // save mostly un-transformed copy for lighting
105                                 modelav[0] = point[0] * softwaretransform_scale;
106                                 modelav[1] = point[1] * softwaretransform_scale;
107                                 modelav[2] = point[2] * softwaretransform_scale;
108                                 av[0] = point[0] * matrix_x[0] + point[1] * matrix_y[0] + point[2] * matrix_z[0] + softwaretransform_offset[0];
109                                 av[1] = point[0] * matrix_x[1] + point[1] * matrix_y[1] + point[2] * matrix_z[1] + softwaretransform_offset[1];
110                                 av[2] = point[0] * matrix_x[2] + point[1] * matrix_y[2] + point[2] * matrix_z[2] + softwaretransform_offset[2];
111                                 // decompress but do not transform the normals
112                                 avn[0] = verts1->n[0] * ilerp127 + verts2->n[0] * lerp127;
113                                 avn[1] = verts1->n[1] * ilerp127 + verts2->n[1] * lerp127;
114                                 avn[2] = verts1->n[2] * ilerp127 + verts2->n[2] * lerp127;
115                                 modelav += 3;
116                                 av += 3;
117                                 avn += 3;
118                                 verts1++;verts2++;
119                         }
120                 }
121                 else
122                 {
123                         for (i = 0;i < vertcount;i++)
124                         {
125                                 // rotate, scale, and translate the vertex locations
126                                 point[0] = verts1->v[0] * scalex1 + verts2->v[0] * scalex2 + translatex;
127                                 point[1] = verts1->v[1] * scaley1 + verts2->v[1] * scaley2 + translatey;
128                                 point[2] = verts1->v[2] * scalez1 + verts2->v[2] * scalez2 + translatez;
129                                 av[0] = point[0] * matrix_x[0] + point[1] * matrix_y[0] + point[2] * matrix_z[0] + softwaretransform_offset[0];
130                                 av[1] = point[0] * matrix_x[1] + point[1] * matrix_y[1] + point[2] * matrix_z[1] + softwaretransform_offset[1];
131                                 av[2] = point[0] * matrix_x[2] + point[1] * matrix_y[2] + point[2] * matrix_z[2] + softwaretransform_offset[2];
132                                 // rotate the normals
133                                 point[0] = verts1->n[0] * ilerp127 + verts2->n[0] * lerp127;
134                                 point[1] = verts1->n[1] * ilerp127 + verts2->n[1] * lerp127;
135                                 point[2] = verts1->n[2] * ilerp127 + verts2->n[2] * lerp127;
136                                 avn[0] = point[0] * softwaretransform_x[0] + point[1] * softwaretransform_y[0] + point[2] * softwaretransform_z[0];
137                                 avn[1] = point[0] * softwaretransform_x[1] + point[1] * softwaretransform_y[1] + point[2] * softwaretransform_z[1];
138                                 avn[2] = point[0] * softwaretransform_x[2] + point[1] * softwaretransform_y[2] + point[2] * softwaretransform_z[2];
139                                 av += 3;
140                                 avn += 3;
141                                 verts1++;verts2++;
142                         }
143                 }
144         }
145         else
146         {
147                 // generate vertices
148                 if (r_modelsdonttransformnormals.value)
149                 {
150                         float *modelav = modelaliasvert;
151                         for (i = 0;i < vertcount;i++)
152                         {
153                                 // rotate, scale, and translate the vertex locations
154                                 point[0] = verts1->v[0] * scale1[0] + translate1[0];
155                                 point[1] = verts1->v[1] * scale1[1] + translate1[1];
156                                 point[2] = verts1->v[2] * scale1[2] + translate1[2];
157                                 // save mostly un-transformed copy for lighting
158                                 modelav[0] = point[0] * softwaretransform_scale;
159                                 modelav[1] = point[1] * softwaretransform_scale;
160                                 modelav[2] = point[2] * softwaretransform_scale;
161                                 av[0] = point[0] * matrix_x[0] + point[1] * matrix_y[0] + point[2] * matrix_z[0] + softwaretransform_offset[0];
162                                 av[1] = point[0] * matrix_x[1] + point[1] * matrix_y[1] + point[2] * matrix_z[1] + softwaretransform_offset[1];
163                                 av[2] = point[0] * matrix_x[2] + point[1] * matrix_y[2] + point[2] * matrix_z[2] + softwaretransform_offset[2];
164                                 // decompress normal but do not rotate it
165                                 avn[0] = verts1->n[0] * (1.0f / 127.0f);
166                                 avn[1] = verts1->n[1] * (1.0f / 127.0f);
167                                 avn[2] = verts1->n[2] * (1.0f / 127.0f);
168                                 modelav += 3;
169                                 av += 3;
170                                 avn += 3;
171                                 verts1++;
172                         }
173                 }
174                 else
175                 {
176                         for (i = 0;i < vertcount;i++)
177                         {
178                                 // rotate, scale, and translate the vertex locations
179                                 point[0] = verts1->v[0] * scale1[0] + translate1[0];
180                                 point[1] = verts1->v[1] * scale1[1] + translate1[1];
181                                 point[2] = verts1->v[2] * scale1[2] + translate1[2];
182                                 av[0] = point[0] * matrix_x[0] + point[1] * matrix_y[0] + point[2] * matrix_z[0] + softwaretransform_offset[0];
183                                 av[1] = point[0] * matrix_x[1] + point[1] * matrix_y[1] + point[2] * matrix_z[1] + softwaretransform_offset[1];
184                                 av[2] = point[0] * matrix_x[2] + point[1] * matrix_y[2] + point[2] * matrix_z[2] + softwaretransform_offset[2];
185                                 // rotate the normals
186                                 point[0] = verts1->n[0] * (1.0f / 127.0f);
187                                 point[1] = verts1->n[1] * (1.0f / 127.0f);
188                                 point[2] = verts1->n[2] * (1.0f / 127.0f);
189                                 avn[0] = point[0] * softwaretransform_x[0] + point[1] * softwaretransform_y[0] + point[2] * softwaretransform_z[0];
190                                 avn[1] = point[0] * softwaretransform_x[1] + point[1] * softwaretransform_y[1] + point[2] * softwaretransform_z[1];
191                                 avn[2] = point[0] * softwaretransform_x[2] + point[1] * softwaretransform_y[2] + point[2] * softwaretransform_z[2];
192                                 av += 3;
193                                 avn += 3;
194                                 verts1++;
195                         }
196                 }
197         }
198 }
199
200 float R_CalcAnimLerp(entity_t *ent, int pose, float lerpscale)
201 {
202         if (ent->draw_lastmodel == ent->model && ent->draw_lerpstart <= cl.time)
203         {
204                 if (pose != ent->draw_pose)
205                 {
206                         ent->draw_lastpose = ent->draw_pose;
207                         ent->draw_pose = pose;
208                         ent->draw_lerpstart = cl.time;
209                         return 0;
210                 }
211                 else
212                         return ((cl.time - ent->draw_lerpstart) * lerpscale);
213         }
214         else // uninitialized
215         {
216                 ent->draw_lastmodel = ent->model;
217                 ent->draw_lastpose = ent->draw_pose = pose;
218                 ent->draw_lerpstart = cl.time;
219                 return 0;
220         }
221 }
222
223 void GL_DrawModelMesh(int skin, byte *colors, maliashdr_t *maliashdr)
224 {
225         int i;
226         if (!r_render.value)
227                 return;
228         glBindTexture(GL_TEXTURE_2D, skin);
229         if (!colors)
230         {
231                 if (lighthalf)
232                         glColor3f(0.5f, 0.5f, 0.5f);
233                 else
234                         glColor3f(1.0f, 1.0f, 1.0f);
235         }
236         if (gl_vertexarrays.value)
237         {
238                 if (colors)
239                 {
240                         qglColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
241                         glEnableClientState(GL_COLOR_ARRAY);
242                 }
243
244                 qglTexCoordPointer(2, GL_FLOAT, 0, (void *)((int) maliashdr->texdata + (int) maliashdr));
245                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
246
247                 qglDrawElements(GL_TRIANGLES, maliashdr->numtris * 3, GL_UNSIGNED_SHORT, (void *)((int) maliashdr + maliashdr->tridata));
248
249                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
250
251                 if (colors)
252                         glDisableClientState(GL_COLOR_ARRAY);
253         }
254         else
255         {
256                 unsigned short *in, index;
257                 float *tex;
258                 in = (void *)((int) maliashdr + maliashdr->tridata);
259                 glBegin(GL_TRIANGLES);
260                 tex = (void *)((int) maliashdr + maliashdr->texdata);
261                 for (i = 0;i < maliashdr->numtris * 3;i++)
262                 {
263                         index = *in++;
264                         glTexCoord2f(tex[index*2], tex[index*2+1]);
265                         if (colors)
266                                 glColor4f(colors[index*4] * (1.0f / 255.0f), colors[index*4+1] * (1.0f / 255.0f), colors[index*4+2] * (1.0f / 255.0f), colors[index*4+3] * (1.0f / 255.0f));
267                         glVertex3fv(&aliasvert[index*3]);
268                 }
269                 glEnd();
270         }
271         // leave it in a state for additional passes
272         glDepthMask(0);
273         glEnable(GL_BLEND);
274         glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive
275 }
276
277 void R_TintModel(byte *in, byte *out, int verts, byte *color)
278 {
279         int i;
280         byte r = color[0];
281         byte g = color[1];
282         byte b = color[2];
283         for (i = 0;i < verts;i++)
284         {
285                 out[0] = (byte) ((in[0] * r) >> 8);
286                 out[1] = (byte) ((in[1] * g) >> 8);
287                 out[2] = (byte) ((in[2] * b) >> 8);
288                 out[3] =          in[3];
289                 in += 4;
290                 out += 4;
291         }
292 }
293
294 /*
295 =================
296 R_DrawAliasFrame
297
298 =================
299 */
300 extern vec3_t lightspot;
301 void R_LightModel(int numverts, vec3_t center, vec3_t basecolor);
302 void R_DrawAliasFrame (maliashdr_t *maliashdr, float alpha, vec3_t color, entity_t *ent, int shadow, vec3_t org, vec3_t angles, int frame, int *skin, int colormap, int effects, int flags)
303 {
304         int             i, pose;
305         float   lerpscale, lerp;
306         maliasframe_t *frameinfo;
307
308         softwaretransformforentity(ent);
309
310         if ((frame >= maliashdr->numframes) || (frame < 0))
311         {
312                 Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);
313                 frame = 0;
314         }
315
316         frameinfo = ((maliasframe_t *)((int) maliashdr + maliashdr->framedata)) + frame;
317         pose = frameinfo->start;
318
319         if (frameinfo->length > 1)
320         {
321                 lerpscale = frameinfo->rate;
322                 pose += (int)(cl.time * frameinfo->rate) % frameinfo->length;
323         }
324         else
325                 lerpscale = 10.0f;
326
327         lerp = R_CalcAnimLerp(ent, pose, lerpscale);
328
329         R_AliasLerpVerts(maliashdr->numverts, lerp, (trivert2 *)((int) maliashdr + maliashdr->posedata) + ent->draw_lastpose * maliashdr->numverts, maliashdr->scale, maliashdr->scale_origin, (trivert2 *)((int) maliashdr + maliashdr->posedata) + ent->draw_pose * maliashdr->numverts, maliashdr->scale, maliashdr->scale_origin);
330
331         // prep the vertex array as early as possible
332         if (r_render.value)
333         {
334                 if (gl_vertexarrays.value)
335                 {
336                         qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
337                         glEnableClientState(GL_VERTEX_ARRAY);
338                 }
339         }
340
341         R_LightModel(maliashdr->numverts, org, color);
342
343         if (!r_render.value)
344                 return;
345         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
346         glShadeModel(GL_SMOOTH);
347         if (effects & EF_ADDITIVE)
348         {
349                 glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive rendering
350                 glEnable(GL_BLEND);
351                 glDepthMask(0);
352         }
353         else if (alpha != 1.0)
354         {
355                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
356                 glEnable(GL_BLEND);
357                 glDepthMask(0);
358         }
359         else
360         {
361                 glDisable(GL_BLEND);
362                 glDepthMask(1);
363         }
364
365         if (colormap >= 0)
366         {
367                 if (!skin[0] && !skin[1] && !skin[2] && !skin[3])
368                         GL_DrawModelMesh(0, NULL, maliashdr);
369                 else
370                 {
371                         int c;
372                         if (skin[0])
373                                 GL_DrawModelMesh(skin[0], aliasvertcolor, maliashdr);
374                         if (skin[1])
375                         {
376                                 c = (colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
377                                 R_TintModel(aliasvertcolor, aliasvertcolor2, maliashdr->numverts, (byte *) (&d_8to24table[c]));
378                                 GL_DrawModelMesh(skin[1], aliasvertcolor2, maliashdr);
379                         }
380                         if (skin[2])
381                         {
382                                 c = colormap & 0xF0      ;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
383                                 R_TintModel(aliasvertcolor, aliasvertcolor2, maliashdr->numverts, (byte *) (&d_8to24table[c]));
384                                 GL_DrawModelMesh(skin[2], aliasvertcolor2, maliashdr);
385                         }
386                         if (skin[3]) GL_DrawModelMesh(skin[3], NULL, maliashdr);
387                 }
388         }
389         else
390         {
391                 if (!skin[3] && !skin[4])
392                         GL_DrawModelMesh(0, NULL, maliashdr);
393                 else
394                 {
395                         if (skin[4]) GL_DrawModelMesh(skin[4], aliasvertcolor, maliashdr);
396                         if (skin[3]) GL_DrawModelMesh(skin[3], NULL, maliashdr);
397                 }
398         }
399
400         if (fogenabled)
401         {
402                 vec3_t diff;
403                 glDisable (GL_TEXTURE_2D);
404                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
405                 glEnable (GL_BLEND);
406                 glDepthMask(0); // disable zbuffer updates
407
408                 VectorSubtract(org, r_refdef.vieworg, diff);
409                 glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
410
411                 if (gl_vertexarrays.value)
412                 {
413                         qglDrawElements(GL_TRIANGLES, maliashdr->numtris * 3, GL_UNSIGNED_SHORT, (void *)((int) maliashdr + maliashdr->tridata));
414                 }
415                 else
416                 {
417                         unsigned short *in;
418                         in = (void *)((int) maliashdr + maliashdr->tridata);
419                         glBegin(GL_TRIANGLES);
420                         for (i = 0;i < maliashdr->numtris * 3;i++)
421                                 glVertex3fv(&aliasvert[*in++ * 3]);
422                         glEnd();
423                 }
424
425                 glEnable (GL_TEXTURE_2D);
426                 glColor3f (1,1,1);
427         }
428         if (gl_vertexarrays.value)
429                 glDisableClientState(GL_VERTEX_ARRAY);
430
431         if (!fogenabled && r_shadows.value && !(effects & EF_ADDITIVE) && shadow)
432         {
433                 // flatten it to make a shadow
434                 float *av = aliasvert + 2, l = lightspot[2] + 0.125;
435                 av = aliasvert + 2;
436                 for (i = 0;i < maliashdr->numverts;i++, av+=3)
437                         if (*av > l)
438                                 *av = l;
439                 glDisable (GL_TEXTURE_2D);
440                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
441                 glEnable (GL_BLEND);
442                 glDepthMask(0); // disable zbuffer updates
443                 glColor4f (0,0,0,0.5 * alpha);
444
445                 if (gl_vertexarrays.value)
446                 {
447                         qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
448                         glEnableClientState(GL_VERTEX_ARRAY);
449                         qglDrawElements(GL_TRIANGLES, maliashdr->numtris * 3, GL_UNSIGNED_SHORT, (void *)((int) maliashdr + maliashdr->tridata));
450                         glDisableClientState(GL_VERTEX_ARRAY);
451                 }
452                 else
453                 {
454                         unsigned short *in;
455                         in = (void *)((int) maliashdr + maliashdr->tridata);
456                         glBegin(GL_TRIANGLES);
457                         for (i = 0;i < maliashdr->numtris * 3;i++)
458                                 glVertex3fv(&aliasvert[*in++ * 3]);
459                         glEnd();
460                 }
461
462                 glEnable (GL_TEXTURE_2D);
463                 glColor3f (1,1,1);
464         }
465
466         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
467         glEnable (GL_BLEND);
468         glDepthMask(1);
469 }
470
471 /*
472 =================
473 R_DrawQ2AliasFrame
474
475 =================
476 */
477 void R_DrawQ2AliasFrame (md2mem_t *pheader, float alpha, vec3_t color, entity_t *ent, int shadow, vec3_t org, vec3_t angles, int frame, int skin, int effects, int flags)
478 {
479         int *order, count;
480         float lerp;
481         md2memframe_t *frame1, *frame2;
482
483         if (r_render.value)
484                 glBindTexture(GL_TEXTURE_2D, skin);
485
486         softwaretransformforentity(ent);
487
488         if ((frame >= pheader->num_frames) || (frame < 0))
489         {
490                 Con_DPrintf ("R_SetupQ2AliasFrame: no such frame %d\n", frame);
491                 frame = 0;
492         }
493
494         lerp = R_CalcAnimLerp(ent, frame, 10);
495
496         frame1 = (void *)((int) pheader + pheader->ofs_frames + (pheader->framesize * ent->draw_lastpose));
497         frame2 = (void *)((int) pheader + pheader->ofs_frames + (pheader->framesize * ent->draw_pose));
498         R_AliasLerpVerts(pheader->num_xyz, lerp, frame1->verts, frame1->scale, frame1->translate, frame2->verts, frame2->scale, frame2->translate);
499
500         R_LightModel(pheader->num_xyz, org, color);
501
502         if (!r_render.value)
503                 return;
504         if (gl_vertexarrays.value)
505         {
506                 // LordHavoc: big mess...
507                 // using arrays only slightly, although it is enough to prevent duplicates
508                 // (saving half the transforms)
509                 qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
510                 qglColorPointer(4, GL_UNSIGNED_BYTE, 0, aliasvertcolor);
511                 glEnableClientState(GL_VERTEX_ARRAY);
512                 glEnableClientState(GL_COLOR_ARRAY);
513
514                 order = (int *)((int)pheader + pheader->ofs_glcmds);
515                 while(1)
516                 {
517                         if (!(count = *order++))
518                                 break;
519                         if (count > 0)
520                                 glBegin(GL_TRIANGLE_STRIP);
521                         else
522                         {
523                                 glBegin(GL_TRIANGLE_FAN);
524                                 count = -count;
525                         }
526                         do
527                         {
528                                 glTexCoord2f(((float *)order)[0], ((float *)order)[1]);
529                                 qglArrayElement(order[2]);
530                                 order += 3;
531                         }
532                         while (count--);
533                 }
534
535                 glDisableClientState(GL_COLOR_ARRAY);
536                 glDisableClientState(GL_VERTEX_ARRAY);
537         }
538         else
539         {
540                 order = (int *)((int)pheader + pheader->ofs_glcmds);
541                 while(1)
542                 {
543                         if (!(count = *order++))
544                                 break;
545                         if (count > 0)
546                                 glBegin(GL_TRIANGLE_STRIP);
547                         else
548                         {
549                                 glBegin(GL_TRIANGLE_FAN);
550                                 count = -count;
551                         }
552                         do
553                         {
554                                 glTexCoord2f(((float *)order)[0], ((float *)order)[1]);
555                                 glColor4f(aliasvertcolor[order[2] * 4] * (1.0f / 255.0f), aliasvertcolor[order[2] * 4 + 1] * (1.0f / 255.0f), aliasvertcolor[order[2] * 4 + 2] * (1.0f / 255.0f), aliasvertcolor[order[2] * 4 + 3] * (1.0f / 255.0f));
556                                 glVertex3fv(&aliasvert[order[2] * 3]);
557                                 order += 3;
558                         }
559                         while (count--);
560                 }
561         }
562
563         if (fogenabled)
564         {
565                 glDisable (GL_TEXTURE_2D);
566                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
567                 glEnable (GL_BLEND);
568                 glDepthMask(0); // disable zbuffer updates
569                 {
570                         vec3_t diff;
571                         VectorSubtract(org, r_refdef.vieworg, diff);
572                         glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
573                 }
574
575                 if (gl_vertexarrays.value)
576                 {
577                         // LordHavoc: big mess...
578                         // using arrays only slightly, although it is enough to prevent duplicates
579                         // (saving half the transforms)
580                         qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
581                         glEnableClientState(GL_VERTEX_ARRAY);
582
583                         order = (int *)((int)pheader + pheader->ofs_glcmds);
584                         while(1)
585                         {
586                                 if (!(count = *order++))
587                                         break;
588                                 if (count > 0)
589                                         glBegin(GL_TRIANGLE_STRIP);
590                                 else
591                                 {
592                                         glBegin(GL_TRIANGLE_FAN);
593                                         count = -count;
594                                 }
595                                 do
596                                 {
597                                         qglArrayElement(order[2]);
598                                         order += 3;
599                                 }
600                                 while (count--);
601                         }
602
603                         glDisableClientState(GL_VERTEX_ARRAY);
604                 }
605                 else
606                 {
607                         order = (int *)((int)pheader + pheader->ofs_glcmds);
608                         while(1)
609                         {
610                                 if (!(count = *order++))
611                                         break;
612                                 if (count > 0)
613                                         glBegin(GL_TRIANGLE_STRIP);
614                                 else
615                                 {
616                                         glBegin(GL_TRIANGLE_FAN);
617                                         count = -count;
618                                 }
619                                 do
620                                 {
621                                         glVertex3fv(&aliasvert[order[2] * 3]);
622                                         order += 3;
623                                 }
624                                 while (count--);
625                         }
626                 }
627
628                 glEnable (GL_TEXTURE_2D);
629                 glColor3f (1,1,1);
630         }
631
632         if (!fogenabled && r_shadows.value && !(effects & EF_ADDITIVE) && shadow)
633         {
634                 int i;
635                 float *av = aliasvert + 2, l = lightspot[2] + 0.125;
636                 av = aliasvert + 2;
637                 for (i = 0;i < pheader->num_xyz;i++, av+=3)
638                         if (*av > l)
639                                 *av = l;
640                 glDisable (GL_TEXTURE_2D);
641                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
642                 glEnable (GL_BLEND);
643                 glDepthMask(0); // disable zbuffer updates
644                 glColor4f (0,0,0,0.5 * alpha);
645
646                 if (gl_vertexarrays.value)
647                 {
648                         qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
649                         glEnableClientState(GL_VERTEX_ARRAY);
650                                                 
651                         while(1)
652                         {
653                                 if (!(count = *order++))
654                                         break;
655                                 if (count > 0)
656                                         glBegin(GL_TRIANGLE_STRIP);
657                                 else
658                                 {
659                                         glBegin(GL_TRIANGLE_FAN);
660                                         count = -count;
661                                 }
662                                 do
663                                 {
664                                         qglArrayElement(order[2]);
665                                         order += 3;
666                                 }
667                                 while (count--);
668                         }
669
670                         glDisableClientState(GL_VERTEX_ARRAY);
671                 }
672                 else
673                 {
674                         while(1)
675                         {
676                                 if (!(count = *order++))
677                                         break;
678                                 if (count > 0)
679                                         glBegin(GL_TRIANGLE_STRIP);
680                                 else
681                                 {
682                                         glBegin(GL_TRIANGLE_FAN);
683                                         count = -count;
684                                 }
685                                 do
686                                 {
687                                         glVertex3fv(&aliasvert[order[2] * 3]);
688                                         order += 3;
689                                 }
690                                 while (count--);
691                         }
692                 }
693
694                 glEnable (GL_TEXTURE_2D);
695                 glColor3f (1,1,1);
696         }
697
698         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
699         glEnable (GL_BLEND);
700         glDepthMask(1);
701 }
702
703 void ZymoticLerpBones(int count, float lerp2, zymbonematrix *bone1, zymbonematrix *bone2, zymbone_t *bone, float rootorigin[3], float rootangles[3])
704 {
705         float lerp1;
706         zymbonematrix *out, rootmatrix, m;
707         lerp1 = 1 - lerp2;
708         out = zymbonepose;
709         AngleVectors(rootangles, rootmatrix.m[0], rootmatrix.m[1], rootmatrix.m[2]);
710         rootmatrix.m[0][3] = rootorigin[0];
711         rootmatrix.m[1][3] = rootorigin[1];
712         rootmatrix.m[2][3] = rootorigin[2];
713         if (lerp1 != 1) // interpolation
714         {
715                 while(count--)
716                 {
717                         // interpolate matrices
718                         m.m[0][0] = bone1->m[0][0] * lerp1 + bone2->m[0][0] * lerp2;
719                         m.m[0][1] = bone1->m[0][1] * lerp1 + bone2->m[0][1] * lerp2;
720                         m.m[0][2] = bone1->m[0][2] * lerp1 + bone2->m[0][2] * lerp2;
721                         m.m[0][3] = bone1->m[0][3] * lerp1 + bone2->m[0][3] * lerp2;
722                         m.m[1][0] = bone1->m[1][0] * lerp1 + bone2->m[1][0] * lerp2;
723                         m.m[1][1] = bone1->m[1][1] * lerp1 + bone2->m[1][1] * lerp2;
724                         m.m[1][2] = bone1->m[1][2] * lerp1 + bone2->m[1][2] * lerp2;
725                         m.m[1][3] = bone1->m[1][3] * lerp1 + bone2->m[1][3] * lerp2;
726                         m.m[2][0] = bone1->m[2][0] * lerp1 + bone2->m[2][0] * lerp2;
727                         m.m[2][1] = bone1->m[2][1] * lerp1 + bone2->m[2][1] * lerp2;
728                         m.m[2][2] = bone1->m[2][2] * lerp1 + bone2->m[2][2] * lerp2;
729                         m.m[2][3] = bone1->m[2][3] * lerp1 + bone2->m[2][3] * lerp2;
730                         if (bone->parent >= 0)
731                                 R_ConcatTransforms(&zymbonepose[bone->parent].m[0], &m.m[0], &out->m[0]);
732                         else
733                                 R_ConcatTransforms(&rootmatrix.m[0], &m.m[0], &out->m[0]);
734                         bone1++;
735                         bone2++;
736                         bone++;
737                         out++;
738                 }
739         }
740         else // no interpolation
741         {
742                 while(count--)
743                 {
744                         if (bone->parent >= 0)
745                                 R_ConcatTransforms(&zymbonepose[bone->parent].m[0], &bone1->m[0], &out->m[0]);
746                         else
747                                 R_ConcatTransforms(&rootmatrix.m[0], &bone1->m[0], &out->m[0]);
748                         bone1++;
749                         bone++;
750                         out++;
751                 }
752         }
753 }
754
755 void ZymoticTransformVerts(int vertcount, int *bonecounts, zymvertex_t *vert)
756 {
757         int c;
758         float *out = aliasvert;
759         zymbonematrix *matrix;
760         while(vertcount--)
761         {
762                 c = *bonecounts++;
763                 if (c == 1)
764                 {
765                         matrix = &zymbonepose[vert->bonenum];
766                         out[0] = vert->origin[0] * matrix->m[0][0] + vert->origin[1] * matrix->m[0][1] + vert->origin[2] * matrix->m[0][2] + matrix->m[0][3];
767                         out[1] = vert->origin[0] * matrix->m[1][0] + vert->origin[1] * matrix->m[1][1] + vert->origin[2] * matrix->m[1][2] + matrix->m[1][3];
768                         out[2] = vert->origin[0] * matrix->m[2][0] + vert->origin[1] * matrix->m[2][1] + vert->origin[2] * matrix->m[2][2] + matrix->m[2][3];
769                         vert++;
770                 }
771                 else
772                 {
773                         VectorClear(out);
774                         while(c--)
775                         {
776                                 matrix = &zymbonepose[vert->bonenum];
777                                 out[0] += vert->origin[0] * matrix->m[0][0] + vert->origin[1] * matrix->m[0][1] + vert->origin[2] * matrix->m[0][2] + matrix->m[0][3];
778                                 out[1] += vert->origin[0] * matrix->m[1][0] + vert->origin[1] * matrix->m[1][1] + vert->origin[2] * matrix->m[1][2] + matrix->m[1][3];
779                                 out[2] += vert->origin[0] * matrix->m[2][0] + vert->origin[1] * matrix->m[2][1] + vert->origin[2] * matrix->m[2][2] + matrix->m[2][3];
780                                 vert++;
781                         }
782                 }
783                 out += 3;
784         }
785 }
786
787 float ixtable[4096];
788
789 void ZymoticCalcNormals(int vertcount, int shadercount, int *renderlist)
790 {
791         int a, b, c, d;
792         float *out, v1[3], v2[3], normal[3];
793         int *u;
794         if (!ixtable[1])
795         {
796                 ixtable[0] = 0;
797                 for (a = 1;a < 4096;a++)
798                         ixtable[a] = 1.0f / a;
799         }
800         // clear normals
801         memset(aliasvertnorm, 0, sizeof(float[3]) * vertcount);
802         memset(aliasvertusage, 0, sizeof(int) * vertcount);
803         // parse render list and accumulate surface normals
804         while(shadercount--)
805         {
806                 d = *renderlist++;
807                 while (d--)
808                 {
809                         a = renderlist[0]*3;
810                         b = renderlist[1]*3;
811                         c = renderlist[2]*3;
812                         v1[0] = aliasvert[a+0] - aliasvert[b+0];
813                         v1[1] = aliasvert[a+1] - aliasvert[b+1];
814                         v1[2] = aliasvert[a+2] - aliasvert[b+2];
815                         v2[0] = aliasvert[c+0] - aliasvert[b+0];
816                         v2[1] = aliasvert[c+1] - aliasvert[b+1];
817                         v2[2] = aliasvert[c+2] - aliasvert[b+2];
818                         CrossProduct(v1, v2, normal);
819                         VectorNormalize(normal);
820                         // add surface normal to vertices
821                         aliasvertnorm[a+0] += normal[0];
822                         aliasvertnorm[a+1] += normal[1];
823                         aliasvertnorm[a+2] += normal[2];
824                         aliasvertusage[a]++;
825                         aliasvertnorm[b+0] += normal[0];
826                         aliasvertnorm[b+1] += normal[1];
827                         aliasvertnorm[b+2] += normal[2];
828                         aliasvertusage[b]++;
829                         aliasvertnorm[c+0] += normal[0];
830                         aliasvertnorm[c+1] += normal[1];
831                         aliasvertnorm[c+2] += normal[2];
832                         aliasvertusage[c]++;
833                         renderlist += 3;
834                 }
835         }
836         // average surface normals
837         out = aliasvertnorm;
838         u = aliasvertusage;
839         while(vertcount--)
840         {
841                 if (*u > 1)
842                 {
843                         a = ixtable[*u];
844                         out[0] *= a;
845                         out[1] *= a;
846                         out[2] *= a;
847                 }
848                 u++;
849                 out += 3;
850         }
851 }
852
853 void GL_DrawZymoticModelMesh(byte *colors, zymtype1header_t *m)
854 {
855         int i, c, *renderlist, *texturenum;
856         if (!r_render.value)
857                 return;
858         renderlist = (int *)(m->lump_render.start + (int) m);
859         texturenum = (int *)(m->lump_shaders.start + (int) m);
860         if (gl_vertexarrays.value)
861         {
862                 qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
863                 glEnableClientState(GL_VERTEX_ARRAY);
864
865                 qglColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
866                 glEnableClientState(GL_COLOR_ARRAY);
867
868                 qglTexCoordPointer(2, GL_FLOAT, 0, (float *)(m->lump_texcoords.start + (int) m));
869                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
870
871                 for (i = 0;i < m->numshaders;i++)
872                 {
873                         c = (*renderlist++) * 3;
874                         glBindTexture(GL_TEXTURE_2D, *texturenum++);
875                         qglDrawElements(GL_TRIANGLES, c, GL_UNSIGNED_INT, renderlist);
876                         renderlist += c;
877                 }
878
879                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
880
881                 glDisableClientState(GL_COLOR_ARRAY);
882
883                 glDisableClientState(GL_VERTEX_ARRAY);
884         }
885         else
886         {
887                 int index;
888                 float *tex;
889                 tex = (float *)(m->lump_texcoords.start + (int) m);
890
891                 for (i = 0;i < m->numshaders;i++)
892                 {
893                         c = *renderlist++;
894                         glBindTexture(GL_TEXTURE_2D, *texturenum++);
895                         glBegin(GL_TRIANGLES);
896                         while (c--)
897                         {
898                                 index = *renderlist++;
899                                 glTexCoord2fv(tex + index*2);
900                                 glColor4ubv(colors + index*4);
901                                 glVertex3fv(aliasvert + index*3);
902                                 index = *renderlist++;
903                                 glTexCoord2fv(tex + index*2);
904                                 glColor4ubv(colors + index*4);
905                                 glVertex3fv(aliasvert + index*3);
906                                 index = *renderlist++;
907                                 glTexCoord2fv(tex + index*2);
908                                 glColor4ubv(colors + index*4);
909                                 glVertex3fv(aliasvert + index*3);
910                         }
911                         glEnd();
912                 }
913         }
914 }
915
916 void GL_DrawZymoticModelMeshFog(vec3_t org, zymtype1header_t *m)
917 {
918         vec3_t diff;
919         int i, c, *renderlist;
920         if (!r_render.value)
921                 return;
922         renderlist = (int *)(m->lump_render.start + (int) m);
923         glDisable(GL_TEXTURE_2D);
924         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
925         glEnable (GL_BLEND);
926         glDepthMask(0); // disable zbuffer updates
927
928         VectorSubtract(org, r_refdef.vieworg, diff);
929         glColor4f(fogcolor[0], fogcolor[1], fogcolor[2], exp(fogdensity/DotProduct(diff,diff)));
930         if (gl_vertexarrays.value)
931         {
932                 qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
933                 glEnableClientState(GL_VERTEX_ARRAY);
934
935                 for (i = 0;i < m->numshaders;i++)
936                 {
937                         c = (*renderlist++) * 3;
938                         qglDrawElements(GL_TRIANGLES, c, GL_UNSIGNED_INT, renderlist);
939                         renderlist += c;
940                 }
941
942                 glDisableClientState(GL_VERTEX_ARRAY);
943         }
944         else
945         {
946                 int index;
947                 float *tex;
948                 tex = (float *)(m->lump_texcoords.start + (int) m);
949
950                 glBegin(GL_TRIANGLES);
951                 for (i = 0;i < m->numshaders;i++)
952                 {
953                         c = *renderlist++;
954                         while (c--)
955                         {
956                                 index = *renderlist++;
957                                 glVertex3fv(aliasvert + index*3);
958                                 index = *renderlist++;
959                                 glVertex3fv(aliasvert + index*3);
960                                 index = *renderlist++;
961                                 glVertex3fv(aliasvert + index*3);
962                         }
963                 }
964                 glEnd();
965         }
966         glEnable(GL_TEXTURE_2D);
967         glColor3f (1,1,1);
968 }
969
970 void GL_DrawZymoticModelMeshShadow(zymtype1header_t *m)
971 {
972         int i, c, *renderlist;
973         float *av, l;
974         if (!r_render.value)
975                 return;
976
977         // flatten it to make a shadow
978         av = aliasvert + 2;
979         l = lightspot[2] + 0.125;
980         for (i = 0;i < m->numverts;i++, av+=3)
981                 if (*av > l)
982                         *av = l;
983
984         renderlist = (int *)(m->lump_render.start + (int) m);
985         glDisable(GL_TEXTURE_2D);
986         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
987         glEnable (GL_BLEND);
988         glDepthMask(0); // disable zbuffer updates
989
990         glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
991         if (gl_vertexarrays.value)
992         {
993                 qglVertexPointer(3, GL_FLOAT, 0, aliasvert);
994                 glEnableClientState(GL_VERTEX_ARRAY);
995
996                 for (i = 0;i < m->numshaders;i++)
997                 {
998                         c = (*renderlist++) * 3;
999                         qglDrawElements(GL_TRIANGLES, c, GL_UNSIGNED_INT, renderlist);
1000                         renderlist += c;
1001                 }
1002
1003                 glDisableClientState(GL_VERTEX_ARRAY);
1004         }
1005         else
1006         {
1007                 int index;
1008                 float *tex;
1009                 tex = (float *)(m->lump_texcoords.start + (int) m);
1010
1011                 glBegin(GL_TRIANGLES);
1012                 for (i = 0;i < m->numshaders;i++)
1013                 {
1014                         c = *renderlist++;
1015                         while (c--)
1016                         {
1017                                 index = *renderlist++;
1018                                 glVertex3fv(aliasvert + index*3);
1019                                 index = *renderlist++;
1020                                 glVertex3fv(aliasvert + index*3);
1021                                 index = *renderlist++;
1022                                 glVertex3fv(aliasvert + index*3);
1023                         }
1024                 }
1025                 glEnd();
1026         }
1027         glEnable(GL_TEXTURE_2D);
1028         glColor3f (1,1,1);
1029 }
1030
1031 /*
1032 =================
1033 R_DrawZymoticFrame
1034 =================
1035 */
1036 void R_DrawZymoticFrame (zymtype1header_t *m, float alpha, vec3_t color, entity_t *ent, int shadow, vec3_t org, vec3_t angles, int frame, int skinblah, int effects, int flags)
1037 {
1038         zymscene_t *scene;
1039         float scenetime, scenefrac;
1040         int sceneframe1, sceneframe2;
1041         zymbonematrix *basebonepose;
1042         if ((frame >= m->numscenes) || (frame < 0))
1043         {
1044                 Con_DPrintf ("R_ZymoticSetupFrame: no such frame %d\n", frame);
1045                 frame = 0;
1046         }
1047
1048         scene = (zymscene_t *)(m->lump_scenes.start + (int) m) + frame;
1049         if (ent->draw_lastmodel != ent->model || ent->draw_pose != frame || ent->draw_lerpstart >= cl.time)
1050         {
1051                 ent->draw_lastmodel = ent->model;
1052                 ent->draw_lastpose = -1;
1053                 ent->draw_pose = frame;
1054                 ent->draw_lerpstart = cl.time;
1055         }
1056         scenetime = (cl.time - ent->draw_lerpstart) * scene->framerate;
1057         sceneframe1 = (int) scenetime;
1058         sceneframe2 = sceneframe1 + 1;
1059         scenefrac = scenetime - sceneframe1;
1060         if (scene->flags & ZYMSCENEFLAG_NOLOOP)
1061         {
1062                 if (sceneframe1 > (scene->length - 1))
1063                         sceneframe1 = (scene->length - 1);
1064                 if (sceneframe2 > (scene->length - 1))
1065                         sceneframe2 = (scene->length - 1);
1066         }
1067         else
1068         {
1069                 sceneframe1 %= scene->length;
1070                 sceneframe2 %= scene->length;
1071         }
1072         if (sceneframe2 == sceneframe1)
1073                 scenefrac = 0;
1074
1075         basebonepose = (zymbonematrix *)(m->lump_poses.start + (int) m);
1076         ZymoticLerpBones(m->numbones, scenefrac, basebonepose + sceneframe1 * m->numbones, basebonepose + sceneframe2 * m->numbones, (zymbone_t *)(m->lump_bones.start + (int) m), org, angles);
1077         ZymoticTransformVerts(m->numverts, (int *)(m->lump_vertbonecounts.start + (int) m), (zymvertex_t *)(m->lump_verts.start + (int) m));
1078         ZymoticCalcNormals(m->numverts, m->numshaders, (int *)(m->lump_render.start + (int) m));
1079
1080         R_LightModel(m->numverts, org, color);
1081
1082         if (!r_render.value)
1083                 return;
1084         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1085         glShadeModel(GL_SMOOTH);
1086         if (effects & EF_ADDITIVE)
1087         {
1088                 glBlendFunc(GL_SRC_ALPHA, GL_ONE); // additive rendering
1089                 glEnable(GL_BLEND);
1090                 glDepthMask(0);
1091         }
1092         else if (alpha != 1.0)
1093         {
1094                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1095                 glEnable(GL_BLEND);
1096                 glDepthMask(0);
1097         }
1098         else
1099         {
1100                 glDisable(GL_BLEND);
1101                 glDepthMask(1);
1102         }
1103
1104         GL_DrawZymoticModelMesh(aliasvertcolor, m);
1105
1106         if (fogenabled)
1107                 GL_DrawZymoticModelMeshFog(org, m);
1108
1109         if (!fogenabled && r_shadows.value && !(effects & EF_ADDITIVE) && shadow)
1110                 GL_DrawZymoticModelMeshShadow(m);
1111
1112         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1113         glEnable (GL_BLEND);
1114         glDepthMask(1);
1115 }
1116
1117 int modeldlightbits[8];
1118 extern int r_dlightframecount;
1119
1120 /*
1121 =================
1122 R_DrawAliasModel
1123
1124 =================
1125 */
1126 void R_DrawAliasModel (entity_t *ent, int cull, float alpha, model_t *clmodel, int frame, int skin, vec3_t org, vec3_t angles, int effects, int flags, int colormap)
1127 {
1128         int                     i;
1129         vec3_t          mins, maxs, color;
1130         mleaf_t         *leaf;
1131         void            *modelheader;
1132         int                     *skinset;
1133
1134         if (alpha < (1.0 / 64.0))
1135                 return; // basically completely transparent
1136
1137         VectorAdd (org, clmodel->mins, mins);
1138         VectorAdd (org, clmodel->maxs, maxs);
1139
1140         if (cull && R_CullBox (mins, maxs))
1141                 return;
1142
1143         c_models++;
1144
1145         leaf = Mod_PointInLeaf (org, cl.worldmodel);
1146         if (leaf->dlightframe == r_dlightframecount)
1147                 for (i = 0;i < 8;i++)
1148                         modeldlightbits[i] = leaf->dlightbits[i];
1149         else
1150                 for (i = 0;i < 8;i++)
1151                         modeldlightbits[i] = 0;
1152
1153         // get lighting information
1154
1155         if ((flags & EF_FULLBRIGHT) || (effects & EF_FULLBRIGHT))
1156                 color[0] = color[1] = color[2] = 256;
1157         else
1158                 R_LightPoint (color, org);
1159
1160         if (r_render.value)
1161                 glDisable(GL_ALPHA_TEST);
1162
1163         if (frame < 0 || frame >= clmodel->numframes)
1164         {
1165                 frame = 0;
1166                 Con_DPrintf("invalid skin number %d for model %s\n", frame, clmodel->name);
1167         }
1168
1169         if (skin < 0 || skin >= clmodel->numskins)
1170         {
1171                 skin = 0;
1172                 Con_DPrintf("invalid skin number %d for model %s\n", skin, clmodel->name);
1173         }
1174
1175         modelheader = Mod_Extradata (clmodel);
1176
1177         {
1178 //              int *skinanimrange = (int *) (clmodel->skinanimrange + (int) modelheader) + skin * 2;
1179 //              int *skinanim = (int *) (clmodel->skinanim + (int) modelheader);
1180                 int *skinanimrange = clmodel->skinanimrange + skin * 2;
1181                 int *skinanim = clmodel->skinanim;
1182                 i = skinanimrange[0];
1183                 if (skinanimrange[1] > 1) // animated
1184                         i += ((int) (cl.time * 10) % skinanimrange[1]);
1185                 skinset = skinanim + i*5;
1186         }
1187
1188         if (r_render.value)
1189                 glEnable (GL_TEXTURE_2D);
1190
1191         c_alias_polys += clmodel->numtris;
1192         if (clmodel->aliastype == ALIASTYPE_ZYM)
1193                 R_DrawZymoticFrame (modelheader, alpha, color, ent, ent != &cl.viewent, org, angles, frame, 0, effects, flags);
1194         else if (clmodel->aliastype == ALIASTYPE_MD2)
1195                 R_DrawQ2AliasFrame (modelheader, alpha, color, ent, ent != &cl.viewent, org, angles, frame, skinset[0], effects, flags);
1196         else
1197                 R_DrawAliasFrame (modelheader, alpha, color, ent, ent != &cl.viewent, org, angles, frame, skinset, colormap, effects, flags);
1198 }