]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_models.c
f8ca7646f89ae297938e2e31b88d35ab809ecd26
[xonotic/darkplaces.git] / gl_models.c
1
2 #include "quakedef.h"
3
4 //cvar_t gl_transform = {0, "gl_transform", "1"};
5 cvar_t r_quickmodels = {0, "r_quickmodels", "1"};
6
7 typedef struct
8 {
9         float m[3][4];
10 } zymbonematrix;
11
12 // LordHavoc: vertex arrays
13
14 float *aliasvertbuf;
15 float *aliasvertcolorbuf;
16 float *aliasvert; // this may point at aliasvertbuf or at vertex arrays in the mesh backend
17 float *aliasvertcolor; // this may point at aliasvertcolorbuf or at vertex arrays in the mesh backend
18
19 float *aliasvertcolor2;
20 float *aliasvertnorm;
21 int *aliasvertusage;
22 zymbonematrix *zymbonepose;
23
24 rmeshinfo_t aliasmeshinfo;
25
26 /*
27 void GL_SetupModelTransform (vec3_t origin, vec3_t angles, vec_t scale)
28 {
29         qglTranslatef (origin[0], origin[1], origin[2]);
30
31         if (scale != 1)
32                 qglScalef (scale, scale, scale);
33         if (angles[1])
34             qglRotatef (angles[1],  0, 0, 1);
35         if (angles[0])
36             qglRotatef (-angles[0],  0, 1, 0);
37         if (angles[2])
38             qglRotatef (angles[2],  1, 0, 0);
39 }
40 */
41
42 /*
43 rtexturepool_t *chrometexturepool;
44 rtexture_t *chrometexture;
45
46 // currently unused reflection effect texture
47 void makechrometexture(void)
48 {
49         int i;
50         qbyte noise[64*64];
51         qbyte data[64*64][4];
52
53         fractalnoise(noise, 64, 8);
54
55         // convert to RGBA data
56         for (i = 0;i < 64*64;i++)
57         {
58                 data[i][0] = data[i][1] = data[i][2] = noise[i];
59                 data[i][3] = 255;
60         }
61
62         chrometexture = R_LoadTexture (chrometexturepool, "chrometexture", 64, 64, &data[0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_PRECACHE);
63 }
64 */
65
66 mempool_t *gl_models_mempool;
67
68 void gl_models_start(void)
69 {
70         // allocate vertex processing arrays
71         gl_models_mempool = Mem_AllocPool("GL_Models");
72         aliasvert = aliasvertbuf = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][4]));
73         aliasvertcolor = aliasvertcolorbuf = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][4]));
74         aliasvertnorm = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][3]));
75         aliasvertcolor2 = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][4])); // used temporarily for tinted coloring
76         zymbonepose = Mem_Alloc(gl_models_mempool, sizeof(zymbonematrix[256]));
77         aliasvertusage = Mem_Alloc(gl_models_mempool, sizeof(int[MD2MAX_VERTS]));
78         //chrometexturepool = R_AllocTexturePool();
79         //makechrometexture();
80 }
81
82 void gl_models_shutdown(void)
83 {
84         //R_FreeTexturePool(&chrometexturepool);
85         Mem_FreePool(&gl_models_mempool);
86 }
87
88 void gl_models_newmap(void)
89 {
90 }
91
92 void GL_Models_Init(void)
93 {
94 //      Cvar_RegisterVariable(&gl_transform);
95         Cvar_RegisterVariable(&r_quickmodels);
96
97         R_RegisterModule("GL_Models", gl_models_start, gl_models_shutdown, gl_models_newmap);
98 }
99
100 void R_AliasTransformVerts(int vertcount)
101 {
102         vec3_t point;
103         float *av;
104 //      float *avn;
105         av = aliasvert;
106 //      avn = aliasvertnorm;
107         while (vertcount >= 4)
108         {
109                 VectorCopy(av, point);softwaretransform(point, av);av += 4;
110                 VectorCopy(av, point);softwaretransform(point, av);av += 4;
111                 VectorCopy(av, point);softwaretransform(point, av);av += 4;
112                 VectorCopy(av, point);softwaretransform(point, av);av += 4;
113 //              VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
114 //              VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
115 //              VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
116 //              VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
117                 vertcount -= 4;
118         }
119         while(vertcount > 0)
120         {
121                 VectorCopy(av, point);softwaretransform(point, av);av += 4;
122 //              VectorCopy(avn, point);softwaretransformdirection(point, avn);avn += 3;
123                 vertcount--;
124         }
125 }
126
127 void R_AliasLerpVerts(int vertcount,
128                                           float lerp1, trivertx_t *verts1, vec3_t fscale1, vec3_t translate1,
129                                           float lerp2, trivertx_t *verts2, vec3_t fscale2, vec3_t translate2,
130                                           float lerp3, trivertx_t *verts3, vec3_t fscale3, vec3_t translate3,
131                                           float lerp4, trivertx_t *verts4, vec3_t fscale4, vec3_t translate4)
132 {
133         int i;
134         vec3_t scale1, scale2, scale3, scale4, translate;
135         float *n1, *n2, *n3, *n4;
136         float *av, *avn;
137         av = aliasvert;
138         avn = aliasvertnorm;
139         VectorScale(fscale1, lerp1, scale1);
140         if (lerp2)
141         {
142                 VectorScale(fscale2, lerp2, scale2);
143                 if (lerp3)
144                 {
145                         VectorScale(fscale3, lerp3, scale3);
146                         if (lerp4)
147                         {
148                                 VectorScale(fscale4, lerp4, scale4);
149                                 translate[0] = translate1[0] * lerp1 + translate2[0] * lerp2 + translate3[0] * lerp3 + translate4[0] * lerp4;
150                                 translate[1] = translate1[1] * lerp1 + translate2[1] * lerp2 + translate3[1] * lerp3 + translate4[1] * lerp4;
151                                 translate[2] = translate1[2] * lerp1 + translate2[2] * lerp2 + translate3[2] * lerp3 + translate4[2] * lerp4;
152                                 // generate vertices
153                                 for (i = 0;i < vertcount;i++)
154                                 {
155                                         av[0] = verts1->v[0] * scale1[0] + verts2->v[0] * scale2[0] + verts3->v[0] * scale3[0] + verts4->v[0] * scale4[0] + translate[0];
156                                         av[1] = verts1->v[1] * scale1[1] + verts2->v[1] * scale2[1] + verts3->v[1] * scale3[1] + verts4->v[1] * scale4[1] + translate[1];
157                                         av[2] = verts1->v[2] * scale1[2] + verts2->v[2] * scale2[2] + verts3->v[2] * scale3[2] + verts4->v[2] * scale4[2] + translate[2];
158                                         n1 = m_bytenormals[verts1->lightnormalindex];
159                                         n2 = m_bytenormals[verts2->lightnormalindex];
160                                         n3 = m_bytenormals[verts3->lightnormalindex];
161                                         n4 = m_bytenormals[verts4->lightnormalindex];
162                                         avn[0] = n1[0] * lerp1 + n2[0] * lerp2 + n3[0] * lerp3 + n4[0] * lerp4;
163                                         avn[1] = n1[1] * lerp1 + n2[1] * lerp2 + n3[1] * lerp3 + n4[1] * lerp4;
164                                         avn[2] = n1[2] * lerp1 + n2[2] * lerp2 + n3[2] * lerp3 + n4[2] * lerp4;
165                                         av += 4;
166                                         avn += 3;
167                                         verts1++;verts2++;verts3++;verts4++;
168                                 }
169                         }
170                         else
171                         {
172                                 translate[0] = translate1[0] * lerp1 + translate2[0] * lerp2 + translate3[0] * lerp3;
173                                 translate[1] = translate1[1] * lerp1 + translate2[1] * lerp2 + translate3[1] * lerp3;
174                                 translate[2] = translate1[2] * lerp1 + translate2[2] * lerp2 + translate3[2] * lerp3;
175                                 // generate vertices
176                                 for (i = 0;i < vertcount;i++)
177                                 {
178                                         av[0] = verts1->v[0] * scale1[0] + verts2->v[0] * scale2[0] + verts3->v[0] * scale3[0] + translate[0];
179                                         av[1] = verts1->v[1] * scale1[1] + verts2->v[1] * scale2[1] + verts3->v[1] * scale3[1] + translate[1];
180                                         av[2] = verts1->v[2] * scale1[2] + verts2->v[2] * scale2[2] + verts3->v[2] * scale3[2] + translate[2];
181                                         n1 = m_bytenormals[verts1->lightnormalindex];
182                                         n2 = m_bytenormals[verts2->lightnormalindex];
183                                         n3 = m_bytenormals[verts3->lightnormalindex];
184                                         avn[0] = n1[0] * lerp1 + n2[0] * lerp2 + n3[0] * lerp3;
185                                         avn[1] = n1[1] * lerp1 + n2[1] * lerp2 + n3[1] * lerp3;
186                                         avn[2] = n1[2] * lerp1 + n2[2] * lerp2 + n3[2] * lerp3;
187                                         av += 4;
188                                         avn += 3;
189                                         verts1++;verts2++;verts3++;
190                                 }
191                         }
192                 }
193                 else
194                 {
195                         translate[0] = translate1[0] * lerp1 + translate2[0] * lerp2;
196                         translate[1] = translate1[1] * lerp1 + translate2[1] * lerp2;
197                         translate[2] = translate1[2] * lerp1 + translate2[2] * lerp2;
198                         // generate vertices
199                         for (i = 0;i < vertcount;i++)
200                         {
201                                 av[0] = verts1->v[0] * scale1[0] + verts2->v[0] * scale2[0] + translate[0];
202                                 av[1] = verts1->v[1] * scale1[1] + verts2->v[1] * scale2[1] + translate[1];
203                                 av[2] = verts1->v[2] * scale1[2] + verts2->v[2] * scale2[2] + translate[2];
204                                 n1 = m_bytenormals[verts1->lightnormalindex];
205                                 n2 = m_bytenormals[verts2->lightnormalindex];
206                                 avn[0] = n1[0] * lerp1 + n2[0] * lerp2;
207                                 avn[1] = n1[1] * lerp1 + n2[1] * lerp2;
208                                 avn[2] = n1[2] * lerp1 + n2[2] * lerp2;
209                                 av += 4;
210                                 avn += 3;
211                                 verts1++;verts2++;
212                         }
213                 }
214         }
215         else
216         {
217                 translate[0] = translate1[0] * lerp1;
218                 translate[1] = translate1[1] * lerp1;
219                 translate[2] = translate1[2] * lerp1;
220                 // generate vertices
221                 if (lerp1 != 1)
222                 {
223                         // general but almost never used case
224                         for (i = 0;i < vertcount;i++)
225                         {
226                                 av[0] = verts1->v[0] * scale1[0] + translate[0];
227                                 av[1] = verts1->v[1] * scale1[1] + translate[1];
228                                 av[2] = verts1->v[2] * scale1[2] + translate[2];
229                                 n1 = m_bytenormals[verts1->lightnormalindex];
230                                 avn[0] = n1[0] * lerp1;
231                                 avn[1] = n1[1] * lerp1;
232                                 avn[2] = n1[2] * lerp1;
233                                 av += 4;
234                                 avn += 3;
235                                 verts1++;
236                         }
237                 }
238                 else
239                 {
240                         // fast normal case
241                         for (i = 0;i < vertcount;i++)
242                         {
243                                 av[0] = verts1->v[0] * scale1[0] + translate[0];
244                                 av[1] = verts1->v[1] * scale1[1] + translate[1];
245                                 av[2] = verts1->v[2] * scale1[2] + translate[2];
246                                 VectorCopy(m_bytenormals[verts1->lightnormalindex], avn);
247                                 av += 4;
248                                 avn += 3;
249                                 verts1++;
250                         }
251                 }
252         }
253 }
254
255 void R_DrawModelMesh(rtexture_t *skin, float *colors, float cred, float cgreen, float cblue)
256 {
257         aliasmeshinfo.tex[0] = R_GetTexture(skin);
258         aliasmeshinfo.color = colors;
259         if (colors == NULL)
260         {
261                 aliasmeshinfo.cr = cred;
262                 aliasmeshinfo.cg = cgreen;
263                 aliasmeshinfo.cb = cblue;
264                 aliasmeshinfo.ca = currentrenderentity->alpha;
265         }
266
267         c_alias_polys += aliasmeshinfo.numtriangles;
268         R_Mesh_Draw(&aliasmeshinfo);
269
270         // leave it in a state for additional passes
271         aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
272         aliasmeshinfo.blendfunc2 = GL_ONE;
273 }
274
275 void R_TintModel(float *in, float *out, int verts, float r, float g, float b)
276 {
277         int i;
278         for (i = 0;i < verts;i++)
279         {
280                 out[0] = in[0] * r;
281                 out[1] = in[1] * g;
282                 out[2] = in[2] * b;
283                 out[3] = in[3];
284                 in += 4;
285                 out += 4;
286         }
287 }
288
289 skinframe_t *R_FetchSkinFrame(void)
290 {
291         model_t *model = currentrenderentity->model;
292         if (model->skinscenes[currentrenderentity->skinnum].framecount > 1)
293                 return &model->skinframes[model->skinscenes[currentrenderentity->skinnum].firstframe + (int) (cl.time * 10) % model->skinscenes[currentrenderentity->skinnum].framecount];
294         else
295                 return &model->skinframes[model->skinscenes[currentrenderentity->skinnum].firstframe];
296 }
297
298 void R_SetupMDLMD2Frames(float colorr, float colorg, float colorb)
299 {
300         md2frame_t *frame1, *frame2, *frame3, *frame4;
301         trivertx_t *frame1verts, *frame2verts, *frame3verts, *frame4verts;
302         model_t *model;
303         model = currentrenderentity->model;
304
305         frame1 = &model->mdlmd2data_frames[currentrenderentity->frameblend[0].frame];
306         frame2 = &model->mdlmd2data_frames[currentrenderentity->frameblend[1].frame];
307         frame3 = &model->mdlmd2data_frames[currentrenderentity->frameblend[2].frame];
308         frame4 = &model->mdlmd2data_frames[currentrenderentity->frameblend[3].frame];
309         frame1verts = &model->mdlmd2data_pose[currentrenderentity->frameblend[0].frame * model->numverts];
310         frame2verts = &model->mdlmd2data_pose[currentrenderentity->frameblend[1].frame * model->numverts];
311         frame3verts = &model->mdlmd2data_pose[currentrenderentity->frameblend[2].frame * model->numverts];
312         frame4verts = &model->mdlmd2data_pose[currentrenderentity->frameblend[3].frame * model->numverts];
313         R_AliasLerpVerts(model->numverts,
314                 currentrenderentity->frameblend[0].lerp, frame1verts, frame1->scale, frame1->translate,
315                 currentrenderentity->frameblend[1].lerp, frame2verts, frame2->scale, frame2->translate,
316                 currentrenderentity->frameblend[2].lerp, frame3verts, frame3->scale, frame3->translate,
317                 currentrenderentity->frameblend[3].lerp, frame4verts, frame4->scale, frame4->translate);
318
319         R_LightModel(model->numverts, colorr, colorg, colorb, false);
320
321         R_AliasTransformVerts(model->numverts);
322 }
323
324 void R_DrawQ1Q2AliasModel (float fog)
325 {
326         model_t *model;
327         skinframe_t *skinframe;
328
329         model = currentrenderentity->model;
330
331         skinframe = R_FetchSkinFrame();
332         if (fog && !(currentrenderentity->effects & EF_ADDITIVE))
333         {
334                 R_SetupMDLMD2Frames(1 - fog, 1 - fog, 1 - fog);
335
336                 memset(&aliasmeshinfo, 0, sizeof(aliasmeshinfo));
337
338                 aliasmeshinfo.vertex = aliasvert;
339                 aliasmeshinfo.vertexstep = sizeof(float[4]);
340                 aliasmeshinfo.numverts = model->numverts;
341                 aliasmeshinfo.numtriangles = model->numtris;
342                 aliasmeshinfo.index = model->mdlmd2data_indices;
343                 aliasmeshinfo.colorstep = sizeof(float[4]);
344                 aliasmeshinfo.texcoords[0] = model->mdlmd2data_texcoords;
345                 aliasmeshinfo.texcoordstep[0] = sizeof(float[2]);
346
347                 if (currentrenderentity->effects & EF_ADDITIVE)
348                 {
349                         aliasmeshinfo.transparent = true;
350                         aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
351                         aliasmeshinfo.blendfunc2 = GL_ONE;
352                 }
353                 else if (currentrenderentity->alpha != 1.0 || skinframe->fog != NULL)
354                 {
355                         aliasmeshinfo.transparent = true;
356                         aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
357                         aliasmeshinfo.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
358                 }
359                 else
360                 {
361                         aliasmeshinfo.transparent = false;
362                         aliasmeshinfo.blendfunc1 = GL_ONE;
363                         aliasmeshinfo.blendfunc2 = GL_ZERO;
364                 }
365
366                 if (skinframe->base || skinframe->pants || skinframe->shirt || skinframe->glow || skinframe->merged)
367                 {
368                         if (currentrenderentity->colormap >= 0 && (skinframe->base || skinframe->pants || skinframe->shirt))
369                         {
370                                 int c;
371                                 qbyte *color;
372                                 if (skinframe->base)
373                                         R_DrawModelMesh(skinframe->base, aliasvertcolor, 0, 0, 0);
374                                 if (skinframe->pants)
375                                 {
376                                         c = (currentrenderentity->colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
377                                         color = (qbyte *) (&d_8to24table[c]);
378                                         if (c >= 224) // fullbright ranges
379                                                 R_DrawModelMesh(skinframe->pants, NULL, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
380                                         else
381                                         {
382                                                 R_TintModel(aliasvertcolor, aliasvertcolor2, model->numverts, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
383                                                 R_DrawModelMesh(skinframe->pants, aliasvertcolor2, 0, 0, 0);
384                                         }
385                                 }
386                                 if (skinframe->shirt)
387                                 {
388                                         c = currentrenderentity->colormap & 0xF0      ;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
389                                         color = (qbyte *) (&d_8to24table[c]);
390                                         if (c >= 224) // fullbright ranges
391                                                 R_DrawModelMesh(skinframe->shirt, NULL, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
392                                         else
393                                         {
394                                                 R_TintModel(aliasvertcolor, aliasvertcolor2, model->numverts, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
395                                                 R_DrawModelMesh(skinframe->shirt, aliasvertcolor2, 0, 0, 0);
396                                         }
397                                 }
398                         }
399                         else
400                         {
401                                 if (skinframe->merged)
402                                         R_DrawModelMesh(skinframe->merged, aliasvertcolor, 0, 0, 0);
403                                 else
404                                 {
405                                         if (skinframe->base) R_DrawModelMesh(skinframe->base, aliasvertcolor, 0, 0, 0);
406                                         if (skinframe->pants) R_DrawModelMesh(skinframe->pants, aliasvertcolor, 0, 0, 0);
407                                         if (skinframe->shirt) R_DrawModelMesh(skinframe->shirt, aliasvertcolor, 0, 0, 0);
408                                 }
409                         }
410                         if (skinframe->glow) R_DrawModelMesh(skinframe->glow, NULL, 1 - fog, 1 - fog, 1 - fog);
411                 }
412                 else
413                         R_DrawModelMesh(0, NULL, 1 - fog, 1 - fog, 1 - fog);
414
415                 aliasmeshinfo.tex[0] = R_GetTexture(skinframe->fog);
416                 aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
417                 aliasmeshinfo.blendfunc2 = GL_ONE;
418                 aliasmeshinfo.color = NULL;
419
420                 aliasmeshinfo.cr = fogcolor[0];
421                 aliasmeshinfo.cg = fogcolor[1];
422                 aliasmeshinfo.cb = fogcolor[2];
423                 aliasmeshinfo.ca = currentrenderentity->alpha * fog;
424
425                 c_alias_polys += aliasmeshinfo.numtriangles;
426                 R_Mesh_Draw(&aliasmeshinfo);
427         }
428         else if (currentrenderentity->colormap >= 0 || !skinframe->merged || skinframe->glow || !r_quickmodels.integer)
429         {
430                 R_SetupMDLMD2Frames(1 - fog, 1 - fog, 1 - fog);
431
432                 memset(&aliasmeshinfo, 0, sizeof(aliasmeshinfo));
433
434                 aliasmeshinfo.vertex = aliasvert;
435                 aliasmeshinfo.vertexstep = sizeof(float[4]);
436                 aliasmeshinfo.numverts = model->numverts;
437                 aliasmeshinfo.numtriangles = model->numtris;
438                 aliasmeshinfo.index = model->mdlmd2data_indices;
439                 aliasmeshinfo.colorstep = sizeof(float[4]);
440                 aliasmeshinfo.texcoords[0] = model->mdlmd2data_texcoords;
441                 aliasmeshinfo.texcoordstep[0] = sizeof(float[2]);
442
443                 if (currentrenderentity->effects & EF_ADDITIVE)
444                 {
445                         aliasmeshinfo.transparent = true;
446                         aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
447                         aliasmeshinfo.blendfunc2 = GL_ONE;
448                 }
449                 else if (currentrenderentity->alpha != 1.0 || skinframe->fog != NULL)
450                 {
451                         aliasmeshinfo.transparent = true;
452                         aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
453                         aliasmeshinfo.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
454                 }
455                 else
456                 {
457                         aliasmeshinfo.transparent = false;
458                         aliasmeshinfo.blendfunc1 = GL_ONE;
459                         aliasmeshinfo.blendfunc2 = GL_ZERO;
460                 }
461
462                 if (skinframe->base || skinframe->pants || skinframe->shirt || skinframe->glow || skinframe->merged)
463                 {
464                         if (currentrenderentity->colormap >= 0 && (skinframe->base || skinframe->pants || skinframe->shirt))
465                         {
466                                 int c;
467                                 qbyte *color;
468                                 if (skinframe->base)
469                                         R_DrawModelMesh(skinframe->base, aliasvertcolor, 0, 0, 0);
470                                 if (skinframe->pants)
471                                 {
472                                         c = (currentrenderentity->colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
473                                         color = (qbyte *) (&d_8to24table[c]);
474                                         if (c >= 224) // fullbright ranges
475                                                 R_DrawModelMesh(skinframe->pants, NULL, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
476                                         else
477                                         {
478                                                 R_TintModel(aliasvertcolor, aliasvertcolor2, model->numverts, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
479                                                 R_DrawModelMesh(skinframe->pants, aliasvertcolor2, 0, 0, 0);
480                                         }
481                                 }
482                                 if (skinframe->shirt)
483                                 {
484                                         c = currentrenderentity->colormap & 0xF0      ;c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges
485                                         color = (qbyte *) (&d_8to24table[c]);
486                                         if (c >= 224) // fullbright ranges
487                                                 R_DrawModelMesh(skinframe->shirt, NULL, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
488                                         else
489                                         {
490                                                 R_TintModel(aliasvertcolor, aliasvertcolor2, model->numverts, color[0] * (1.0f / 255.0f), color[1] * (1.0f / 255.0f), color[2] * (1.0f / 255.0f));
491                                                 R_DrawModelMesh(skinframe->shirt, aliasvertcolor2, 0, 0, 0);
492                                         }
493                                 }
494                         }
495                         else
496                         {
497                                 if (skinframe->merged)
498                                         R_DrawModelMesh(skinframe->merged, aliasvertcolor, 0, 0, 0);
499                                 else
500                                 {
501                                         if (skinframe->base) R_DrawModelMesh(skinframe->base, aliasvertcolor, 0, 0, 0);
502                                         if (skinframe->pants) R_DrawModelMesh(skinframe->pants, aliasvertcolor, 0, 0, 0);
503                                         if (skinframe->shirt) R_DrawModelMesh(skinframe->shirt, aliasvertcolor, 0, 0, 0);
504                                 }
505                         }
506                         if (skinframe->glow) R_DrawModelMesh(skinframe->glow, NULL, 1 - fog, 1 - fog, 1 - fog);
507                 }
508                 else
509                         R_DrawModelMesh(0, NULL, 1 - fog, 1 - fog, 1 - fog);
510         }
511         else
512         {
513                 rmeshbufferinfo_t bufmesh;
514                 memset(&bufmesh, 0, sizeof(bufmesh));
515                 if (currentrenderentity->effects & EF_ADDITIVE)
516                 {
517                         bufmesh.transparent = true;
518                         bufmesh.blendfunc1 = GL_SRC_ALPHA;
519                         bufmesh.blendfunc2 = GL_ONE;
520                 }
521                 else if (currentrenderentity->alpha != 1.0 || skinframe->fog != NULL)
522                 {
523                         bufmesh.transparent = true;
524                         bufmesh.blendfunc1 = GL_SRC_ALPHA;
525                         bufmesh.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
526                 }
527                 else
528                 {
529                         bufmesh.transparent = false;
530                         bufmesh.blendfunc1 = GL_ONE;
531                         bufmesh.blendfunc2 = GL_ZERO;
532                 }
533                 bufmesh.numtriangles = model->numtris;
534                 bufmesh.numverts = model->numverts;
535                 bufmesh.tex[0] = R_GetTexture(skinframe->merged);
536
537                 R_Mesh_Draw_GetBuffer(&bufmesh);
538
539                 aliasvert = bufmesh.vertex;
540                 aliasvertcolor = bufmesh.color;
541                 memcpy(bufmesh.index, model->mdlmd2data_indices, bufmesh.numtriangles * sizeof(int[3]));
542                 memcpy(bufmesh.texcoords[0], model->mdlmd2data_texcoords, bufmesh.numverts * sizeof(float[2]));
543
544                 fog = bufmesh.colorscale * (1 - fog);
545                 R_SetupMDLMD2Frames(fog, fog, fog);
546
547                 aliasvert = aliasvertbuf;
548                 aliasvertcolor = aliasvertcolorbuf;
549         }
550 }
551
552 int ZymoticLerpBones(int count, zymbonematrix *bonebase, frameblend_t *blend, zymbone_t *bone)
553 {
554         int i;
555         float lerp1, lerp2, lerp3, lerp4;
556         zymbonematrix *out, rootmatrix, m, *bone1, *bone2, *bone3, *bone4;
557
558         /*
559         m.m[0][0] = 0;
560         m.m[0][1] = -1;
561         m.m[0][2] = 0;
562         m.m[0][3] = 0;
563         m.m[1][0] = 1;
564         m.m[1][1] = 0;
565         m.m[1][2] = 0;
566         m.m[1][3] = 0;
567         m.m[2][0] = 0;
568         m.m[2][1] = 0;
569         m.m[2][2] = 1;
570         m.m[2][3] = 0;
571         R_ConcatTransforms(&softwaretransform_matrix[0], &m.m[0][0], &rootmatrix.m[0][0]);
572         */
573
574         // LordHavoc: combine transform from zym coordinate space to quake coordinate space with model to world transform matrix
575         rootmatrix.m[0][0] = softwaretransform_matrix[0][1];
576         rootmatrix.m[0][1] = -softwaretransform_matrix[0][0];
577         rootmatrix.m[0][2] = softwaretransform_matrix[0][2];
578         rootmatrix.m[0][3] = softwaretransform_matrix[0][3];
579         rootmatrix.m[1][0] = softwaretransform_matrix[1][1];
580         rootmatrix.m[1][1] = -softwaretransform_matrix[1][0];
581         rootmatrix.m[1][2] = softwaretransform_matrix[1][2];
582         rootmatrix.m[1][3] = softwaretransform_matrix[1][3];
583         rootmatrix.m[2][0] = softwaretransform_matrix[2][1];
584         rootmatrix.m[2][1] = -softwaretransform_matrix[2][0];
585         rootmatrix.m[2][2] = softwaretransform_matrix[2][2];
586         rootmatrix.m[2][3] = softwaretransform_matrix[2][3];
587
588         bone1 = bonebase + blend[0].frame * count;
589         lerp1 = blend[0].lerp;
590         if (blend[1].lerp)
591         {
592                 bone2 = bonebase + blend[1].frame * count;
593                 lerp2 = blend[1].lerp;
594                 if (blend[2].lerp)
595                 {
596                         bone3 = bonebase + blend[2].frame * count;
597                         lerp3 = blend[2].lerp;
598                         if (blend[3].lerp)
599                         {
600                                 // 4 poses
601                                 bone4 = bonebase + blend[3].frame * count;
602                                 lerp4 = blend[3].lerp;
603                                 for (i = 0, out = zymbonepose;i < count;i++, out++)
604                                 {
605                                         // interpolate matrices
606                                         m.m[0][0] = bone1->m[0][0] * lerp1 + bone2->m[0][0] * lerp2 + bone3->m[0][0] * lerp3 + bone4->m[0][0] * lerp4;
607                                         m.m[0][1] = bone1->m[0][1] * lerp1 + bone2->m[0][1] * lerp2 + bone3->m[0][1] * lerp3 + bone4->m[0][1] * lerp4;
608                                         m.m[0][2] = bone1->m[0][2] * lerp1 + bone2->m[0][2] * lerp2 + bone3->m[0][2] * lerp3 + bone4->m[0][2] * lerp4;
609                                         m.m[0][3] = bone1->m[0][3] * lerp1 + bone2->m[0][3] * lerp2 + bone3->m[0][3] * lerp3 + bone4->m[0][3] * lerp4;
610                                         m.m[1][0] = bone1->m[1][0] * lerp1 + bone2->m[1][0] * lerp2 + bone3->m[1][0] * lerp3 + bone4->m[1][0] * lerp4;
611                                         m.m[1][1] = bone1->m[1][1] * lerp1 + bone2->m[1][1] * lerp2 + bone3->m[1][1] * lerp3 + bone4->m[1][1] * lerp4;
612                                         m.m[1][2] = bone1->m[1][2] * lerp1 + bone2->m[1][2] * lerp2 + bone3->m[1][2] * lerp3 + bone4->m[1][2] * lerp4;
613                                         m.m[1][3] = bone1->m[1][3] * lerp1 + bone2->m[1][3] * lerp2 + bone3->m[1][3] * lerp3 + bone4->m[1][3] * lerp4;
614                                         m.m[2][0] = bone1->m[2][0] * lerp1 + bone2->m[2][0] * lerp2 + bone3->m[2][0] * lerp3 + bone4->m[2][0] * lerp4;
615                                         m.m[2][1] = bone1->m[2][1] * lerp1 + bone2->m[2][1] * lerp2 + bone3->m[2][1] * lerp3 + bone4->m[2][1] * lerp4;
616                                         m.m[2][2] = bone1->m[2][2] * lerp1 + bone2->m[2][2] * lerp2 + bone3->m[2][2] * lerp3 + bone4->m[2][2] * lerp4;
617                                         m.m[2][3] = bone1->m[2][3] * lerp1 + bone2->m[2][3] * lerp2 + bone3->m[2][3] * lerp3 + bone4->m[2][3] * lerp4;
618                                         if (bone->parent >= 0)
619                                                 R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &m.m[0][0], &out->m[0][0]);
620                                         else
621                                                 R_ConcatTransforms(&rootmatrix.m[0][0], &m.m[0][0], &out->m[0][0]);
622                                         bone1++;
623                                         bone2++;
624                                         bone3++;
625                                         bone4++;
626                                         bone++;
627                                 }
628                         }
629                         else
630                         {
631                                 // 3 poses
632                                 for (i = 0, out = zymbonepose;i < count;i++, out++)
633                                 {
634                                         // interpolate matrices
635                                         m.m[0][0] = bone1->m[0][0] * lerp1 + bone2->m[0][0] * lerp2 + bone3->m[0][0] * lerp3;
636                                         m.m[0][1] = bone1->m[0][1] * lerp1 + bone2->m[0][1] * lerp2 + bone3->m[0][1] * lerp3;
637                                         m.m[0][2] = bone1->m[0][2] * lerp1 + bone2->m[0][2] * lerp2 + bone3->m[0][2] * lerp3;
638                                         m.m[0][3] = bone1->m[0][3] * lerp1 + bone2->m[0][3] * lerp2 + bone3->m[0][3] * lerp3;
639                                         m.m[1][0] = bone1->m[1][0] * lerp1 + bone2->m[1][0] * lerp2 + bone3->m[1][0] * lerp3;
640                                         m.m[1][1] = bone1->m[1][1] * lerp1 + bone2->m[1][1] * lerp2 + bone3->m[1][1] * lerp3;
641                                         m.m[1][2] = bone1->m[1][2] * lerp1 + bone2->m[1][2] * lerp2 + bone3->m[1][2] * lerp3;
642                                         m.m[1][3] = bone1->m[1][3] * lerp1 + bone2->m[1][3] * lerp2 + bone3->m[1][3] * lerp3;
643                                         m.m[2][0] = bone1->m[2][0] * lerp1 + bone2->m[2][0] * lerp2 + bone3->m[2][0] * lerp3;
644                                         m.m[2][1] = bone1->m[2][1] * lerp1 + bone2->m[2][1] * lerp2 + bone3->m[2][1] * lerp3;
645                                         m.m[2][2] = bone1->m[2][2] * lerp1 + bone2->m[2][2] * lerp2 + bone3->m[2][2] * lerp3;
646                                         m.m[2][3] = bone1->m[2][3] * lerp1 + bone2->m[2][3] * lerp2 + bone3->m[2][3] * lerp3;
647                                         if (bone->parent >= 0)
648                                                 R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &m.m[0][0], &out->m[0][0]);
649                                         else
650                                                 R_ConcatTransforms(&rootmatrix.m[0][0], &m.m[0][0], &out->m[0][0]);
651                                         bone1++;
652                                         bone2++;
653                                         bone3++;
654                                         bone++;
655                                 }
656                         }
657                 }
658                 else
659                 {
660                         // 2 poses
661                         for (i = 0, out = zymbonepose;i < count;i++, out++)
662                         {
663                                 // interpolate matrices
664                                 m.m[0][0] = bone1->m[0][0] * lerp1 + bone2->m[0][0] * lerp2;
665                                 m.m[0][1] = bone1->m[0][1] * lerp1 + bone2->m[0][1] * lerp2;
666                                 m.m[0][2] = bone1->m[0][2] * lerp1 + bone2->m[0][2] * lerp2;
667                                 m.m[0][3] = bone1->m[0][3] * lerp1 + bone2->m[0][3] * lerp2;
668                                 m.m[1][0] = bone1->m[1][0] * lerp1 + bone2->m[1][0] * lerp2;
669                                 m.m[1][1] = bone1->m[1][1] * lerp1 + bone2->m[1][1] * lerp2;
670                                 m.m[1][2] = bone1->m[1][2] * lerp1 + bone2->m[1][2] * lerp2;
671                                 m.m[1][3] = bone1->m[1][3] * lerp1 + bone2->m[1][3] * lerp2;
672                                 m.m[2][0] = bone1->m[2][0] * lerp1 + bone2->m[2][0] * lerp2;
673                                 m.m[2][1] = bone1->m[2][1] * lerp1 + bone2->m[2][1] * lerp2;
674                                 m.m[2][2] = bone1->m[2][2] * lerp1 + bone2->m[2][2] * lerp2;
675                                 m.m[2][3] = bone1->m[2][3] * lerp1 + bone2->m[2][3] * lerp2;
676                                 if (bone->parent >= 0)
677                                         R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &m.m[0][0], &out->m[0][0]);
678                                 else
679                                         R_ConcatTransforms(&rootmatrix.m[0][0], &m.m[0][0], &out->m[0][0]);
680                                 bone1++;
681                                 bone2++;
682                                 bone++;
683                         }
684                 }
685         }
686         else
687         {
688                 // 1 pose
689                 if (lerp1 != 1)
690                 {
691                         // lerp != 1.0
692                         for (i = 0, out = zymbonepose;i < count;i++, out++)
693                         {
694                                 // interpolate matrices
695                                 m.m[0][0] = bone1->m[0][0] * lerp1;
696                                 m.m[0][1] = bone1->m[0][1] * lerp1;
697                                 m.m[0][2] = bone1->m[0][2] * lerp1;
698                                 m.m[0][3] = bone1->m[0][3] * lerp1;
699                                 m.m[1][0] = bone1->m[1][0] * lerp1;
700                                 m.m[1][1] = bone1->m[1][1] * lerp1;
701                                 m.m[1][2] = bone1->m[1][2] * lerp1;
702                                 m.m[1][3] = bone1->m[1][3] * lerp1;
703                                 m.m[2][0] = bone1->m[2][0] * lerp1;
704                                 m.m[2][1] = bone1->m[2][1] * lerp1;
705                                 m.m[2][2] = bone1->m[2][2] * lerp1;
706                                 m.m[2][3] = bone1->m[2][3] * lerp1;
707                                 if (bone->parent >= 0)
708                                         R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &m.m[0][0], &out->m[0][0]);
709                                 else
710                                         R_ConcatTransforms(&rootmatrix.m[0][0], &m.m[0][0], &out->m[0][0]);
711                                 bone1++;
712                                 bone++;
713                         }
714                 }
715                 else
716                 {
717                         // lerp == 1.0
718                         for (i = 0, out = zymbonepose;i < count;i++, out++)
719                         {
720                                 if (bone->parent >= 0)
721                                         R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &bone1->m[0][0], &out->m[0][0]);
722                                 else
723                                         R_ConcatTransforms(&rootmatrix.m[0][0], &bone1->m[0][0], &out->m[0][0]);
724                                 bone1++;
725                                 bone++;
726                         }
727                 }
728         }
729         return true;
730 }
731
732 void ZymoticTransformVerts(int vertcount, int *bonecounts, zymvertex_t *vert)
733 {
734         int c;
735         float *out = aliasvert;
736         zymbonematrix *matrix;
737         while(vertcount--)
738         {
739                 c = *bonecounts++;
740                 // FIXME: validate bonecounts at load time (must be >= 1)
741                 // FIXME: need 4th component in origin, for how much of the translate to blend in
742                 if (c == 1)
743                 {
744                         matrix = &zymbonepose[vert->bonenum];
745                         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];
746                         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];
747                         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];
748                         vert++;
749                 }
750                 else
751                 {
752                         VectorClear(out);
753                         while(c--)
754                         {
755                                 matrix = &zymbonepose[vert->bonenum];
756                                 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];
757                                 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];
758                                 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];
759                                 vert++;
760                         }
761                 }
762                 out += 4;
763         }
764 }
765
766 void ZymoticCalcNormals(int vertcount, int shadercount, int *renderlist)
767 {
768         int a, b, c, d;
769         float *out, v1[3], v2[3], normal[3], s;
770         int *u;
771         // clear normals
772         memset(aliasvertnorm, 0, sizeof(float) * vertcount * 3);
773         memset(aliasvertusage, 0, sizeof(int) * vertcount);
774         // parse render list and accumulate surface normals
775         while(shadercount--)
776         {
777                 d = *renderlist++;
778                 while (d--)
779                 {
780                         a = renderlist[0]*4;
781                         b = renderlist[1]*4;
782                         c = renderlist[2]*4;
783                         v1[0] = aliasvert[a+0] - aliasvert[b+0];
784                         v1[1] = aliasvert[a+1] - aliasvert[b+1];
785                         v1[2] = aliasvert[a+2] - aliasvert[b+2];
786                         v2[0] = aliasvert[c+0] - aliasvert[b+0];
787                         v2[1] = aliasvert[c+1] - aliasvert[b+1];
788                         v2[2] = aliasvert[c+2] - aliasvert[b+2];
789                         CrossProduct(v1, v2, normal);
790                         VectorNormalizeFast(normal);
791                         // add surface normal to vertices
792                         a = renderlist[0] * 3;
793                         aliasvertnorm[a+0] += normal[0];
794                         aliasvertnorm[a+1] += normal[1];
795                         aliasvertnorm[a+2] += normal[2];
796                         aliasvertusage[renderlist[0]]++;
797                         a = renderlist[1] * 3;
798                         aliasvertnorm[a+0] += normal[0];
799                         aliasvertnorm[a+1] += normal[1];
800                         aliasvertnorm[a+2] += normal[2];
801                         aliasvertusage[renderlist[1]]++;
802                         a = renderlist[2] * 3;
803                         aliasvertnorm[a+0] += normal[0];
804                         aliasvertnorm[a+1] += normal[1];
805                         aliasvertnorm[a+2] += normal[2];
806                         aliasvertusage[renderlist[2]]++;
807                         renderlist += 3;
808                 }
809         }
810         // FIXME: precalc this
811         // average surface normals
812         out = aliasvertnorm;
813         u = aliasvertusage;
814         while(vertcount--)
815         {
816                 if (*u > 1)
817                 {
818                         s = ixtable[*u];
819                         out[0] *= s;
820                         out[1] *= s;
821                         out[2] *= s;
822                 }
823                 u++;
824                 out += 3;
825         }
826 }
827
828 void R_DrawZymoticModelMesh(zymtype1header_t *m)
829 {
830         int i, *renderlist;
831         rtexture_t **texture;
832
833         // FIXME: do better fog
834         renderlist = (int *)(m->lump_render.start + (int) m);
835         texture = (rtexture_t **)(m->lump_shaders.start + (int) m);
836
837         aliasmeshinfo.vertex = aliasvert;
838         aliasmeshinfo.vertexstep = sizeof(float[4]);
839         aliasmeshinfo.color = aliasvertcolor;
840         aliasmeshinfo.colorstep = sizeof(float[4]);
841         aliasmeshinfo.texcoords[0] = (float *)(m->lump_texcoords.start + (int) m);
842         aliasmeshinfo.texcoordstep[0] = sizeof(float[2]);
843
844         for (i = 0;i < m->numshaders;i++)
845         {
846                 aliasmeshinfo.tex[0] = R_GetTexture(texture[i]);
847                 if (currentrenderentity->effects & EF_ADDITIVE)
848                 {
849                         aliasmeshinfo.transparent = true;
850                         aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
851                         aliasmeshinfo.blendfunc2 = GL_ONE;
852                 }
853                 else if (currentrenderentity->alpha != 1.0 || R_TextureHasAlpha(texture[i]))
854                 {
855                         aliasmeshinfo.transparent = true;
856                         aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
857                         aliasmeshinfo.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
858                 }
859                 else
860                 {
861                         aliasmeshinfo.transparent = false;
862                         aliasmeshinfo.blendfunc1 = GL_ONE;
863                         aliasmeshinfo.blendfunc2 = GL_ZERO;
864                 }
865                 aliasmeshinfo.numtriangles = *renderlist++;
866                 aliasmeshinfo.index = renderlist;
867                 c_alias_polys += aliasmeshinfo.numtriangles;
868                 R_Mesh_Draw(&aliasmeshinfo);
869                 renderlist += aliasmeshinfo.numtriangles * 3;
870         }
871 }
872
873 void R_DrawZymoticModelMeshFog(vec3_t org, zymtype1header_t *m, float fog)
874 {
875         int i, *renderlist;
876
877         // FIXME: do better fog
878         renderlist = (int *)(m->lump_render.start + (int) m);
879
880         aliasmeshinfo.tex[0] = 0;
881         aliasmeshinfo.blendfunc1 = GL_SRC_ALPHA;
882         aliasmeshinfo.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
883
884         aliasmeshinfo.cr = fogcolor[0];
885         aliasmeshinfo.cg = fogcolor[1];
886         aliasmeshinfo.cb = fogcolor[2];
887         aliasmeshinfo.ca = currentrenderentity->alpha * fog;
888
889         for (i = 0;i < m->numshaders;i++)
890         {
891                 aliasmeshinfo.numtriangles = *renderlist++;
892                 aliasmeshinfo.index = renderlist;
893                 c_alias_polys += aliasmeshinfo.numtriangles;
894                 R_Mesh_Draw(&aliasmeshinfo);
895                 renderlist += aliasmeshinfo.numtriangles * 3;
896         }
897 }
898
899 void R_DrawZymoticModel (float fog)
900 {
901         zymtype1header_t *m;
902
903         // FIXME: do better fog
904         m = currentrenderentity->model->zymdata_header;
905         ZymoticLerpBones(m->numbones, (zymbonematrix *)(m->lump_poses.start + (int) m), currentrenderentity->frameblend, (zymbone_t *)(m->lump_bones.start + (int) m));
906         ZymoticTransformVerts(m->numverts, (int *)(m->lump_vertbonecounts.start + (int) m), (zymvertex_t *)(m->lump_verts.start + (int) m));
907         ZymoticCalcNormals(m->numverts, m->numshaders, (int *)(m->lump_render.start + (int) m));
908
909         R_LightModel(m->numverts, 1 - fog, 1 - fog, 1 - fog, true);
910
911         memset(&aliasmeshinfo, 0, sizeof(aliasmeshinfo));
912         aliasmeshinfo.numverts = m->numverts;
913
914         R_DrawZymoticModelMesh(m);
915
916         if (fog)
917                 R_DrawZymoticModelMeshFog(currentrenderentity->origin, m, fog);
918 }
919
920 void R_DrawAliasModel (void)
921 {
922         float fog;
923         vec3_t diff;
924
925         if (currentrenderentity->alpha < (1.0f / 64.0f))
926                 return; // basically completely transparent
927
928         c_models++;
929
930         softwaretransformforentity(currentrenderentity);
931
932         fog = 0;
933         if (fogenabled)
934         {
935                 VectorSubtract(currentrenderentity->origin, r_origin, diff);
936                 fog = DotProduct(diff,diff);
937                 if (fog < 0.01f)
938                         fog = 0.01f;
939                 fog = exp(fogdensity/fog);
940                 if (fog > 1)
941                         fog = 1;
942                 if (fog < 0.01f)
943                         fog = 0;
944                 // fog method: darken, additive fog
945                 // 1. render model as normal, scaled by inverse of fog alpha (darkens it)
946                 // 2. render fog as additive
947         }
948
949         if (currentrenderentity->model->aliastype == ALIASTYPE_ZYM)
950                 R_DrawZymoticModel(fog);
951         else
952                 R_DrawQ1Q2AliasModel(fog);
953 }