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