]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_models.c
8a8e3fab5481b8502aa515ca290609ac53ace028
[divverent/darkplaces.git] / gl_models.c
1
2 #include "quakedef.h"
3 #include "cl_collision.h"
4 #include "r_shadow.h"
5
6 typedef struct
7 {
8         float m[3][4];
9 } zymbonematrix;
10
11 // LordHavoc: vertex arrays
12
13 float *aliasvertcolorbuf;
14 float *aliasvertcolor; // this may point at aliasvertcolorbuf or at vertex arrays in the mesh backend
15 float *aliasvert_svectors;
16 float *aliasvert_tvectors;
17 float *aliasvert_normals;
18
19 float *aliasvertcolor2;
20 int *aliasvertusage;
21 zymbonematrix *zymbonepose;
22
23 mempool_t *gl_models_mempool;
24
25 void gl_models_start(void)
26 {
27         // allocate vertex processing arrays
28         gl_models_mempool = Mem_AllocPool("GL_Models");
29         aliasvertcolor = aliasvertcolorbuf = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][4]));
30         aliasvert_svectors = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][4]));
31         aliasvert_tvectors = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][4]));
32         aliasvert_normals = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][4]));
33         aliasvertcolor2 = Mem_Alloc(gl_models_mempool, sizeof(float[MD2MAX_VERTS][4])); // used temporarily for tinted coloring
34         zymbonepose = Mem_Alloc(gl_models_mempool, sizeof(zymbonematrix[256]));
35         aliasvertusage = Mem_Alloc(gl_models_mempool, sizeof(int[MD2MAX_VERTS]));
36 }
37
38 void gl_models_shutdown(void)
39 {
40         Mem_FreePool(&gl_models_mempool);
41 }
42
43 void gl_models_newmap(void)
44 {
45 }
46
47 void GL_Models_Init(void)
48 {
49         R_RegisterModule("GL_Models", gl_models_start, gl_models_shutdown, gl_models_newmap);
50 }
51
52 void R_Model_Alias_GetVerts(const entity_render_t *ent, float *vertices, float *normals, float *svectors, float *tvectors)
53 {
54         int i, vertcount;
55         float vlerp1, nlerp1, vlerp2, nlerp2, vlerp3, nlerp3, vlerp4, nlerp4;
56         const aliasvertex_t *verts1, *verts2, *verts3, *verts4;
57
58         if (vertices == NULL)
59                 Host_Error("R_Model_Alias_GetVerts: vertices == NULL.\n");
60         if (svectors != NULL && (tvectors == NULL || normals == NULL))
61                 Host_Error("R_Model_Alias_GetVerts: svectors requires tvectors and normals.\n");
62         if (tvectors != NULL && (svectors == NULL || normals == NULL))
63                 Host_Error("R_Model_Alias_GetVerts: tvectors requires svectors and normals.\n");
64
65         vertcount = ent->model->numverts;
66         verts1 = ent->model->mdlmd2data_pose + ent->frameblend[0].frame * vertcount;
67         vlerp1 = ent->frameblend[0].lerp * (1.0f / 16.0f);
68         nlerp1 = ent->frameblend[0].lerp * (1.0f / 127.0f);
69         if (ent->frameblend[1].lerp)
70         {
71                 verts2 = ent->model->mdlmd2data_pose + ent->frameblend[1].frame * vertcount;
72                 vlerp2 = ent->frameblend[1].lerp * (1.0f / 16.0f);
73                 nlerp2 = ent->frameblend[1].lerp * (1.0f / 127.0f);
74                 if (ent->frameblend[2].lerp)
75                 {
76                         verts3 = ent->model->mdlmd2data_pose + ent->frameblend[2].frame * vertcount;
77                         vlerp3 = ent->frameblend[2].lerp * (1.0f / 16.0f);
78                         nlerp3 = ent->frameblend[2].lerp * (1.0f / 127.0f);
79                         if (ent->frameblend[3].lerp)
80                         {
81                                 verts4 = ent->model->mdlmd2data_pose + ent->frameblend[3].frame * vertcount;
82                                 vlerp4 = ent->frameblend[3].lerp * (1.0f / 16.0f);
83                                 nlerp4 = ent->frameblend[3].lerp * (1.0f / 127.0f);
84                                 // generate vertices
85                                 if (svectors != NULL)
86                                 {
87                                         for (i = 0;i < vertcount;i++, vertices += 4, normals += 4, svectors += 4, tvectors += 4, verts1++, verts2++, verts3++, verts4++)
88                                         {
89                                                 VectorMAMAMAM(vlerp1, verts1->origin, vlerp2, verts2->origin, vlerp3, verts3->origin, vlerp4, verts4->origin, vertices);
90                                                 VectorMAMAMAM(nlerp1, verts1->normal, nlerp2, verts2->normal, nlerp3, verts3->normal, nlerp4, verts4->normal, normals);
91                                                 VectorMAMAMAM(nlerp1, verts1->svector, nlerp2, verts2->svector, nlerp3, verts3->svector, nlerp4, verts4->svector, svectors);
92                                                 CrossProduct(svectors, normals, tvectors);
93                                         }
94                                 }
95                                 else if (normals != NULL)
96                                 {
97                                         for (i = 0;i < vertcount;i++, vertices += 4, normals += 4, verts1++, verts2++, verts3++, verts4++)
98                                         {
99                                                 VectorMAMAMAM(vlerp1, verts1->origin, vlerp2, verts2->origin, vlerp3, verts3->origin, vlerp4, verts4->origin, vertices);
100                                                 VectorMAMAMAM(nlerp1, verts1->normal, nlerp2, verts2->normal, nlerp3, verts3->normal, nlerp4, verts4->normal, normals);
101                                         }
102                                 }
103                                 else
104                                         for (i = 0;i < vertcount;i++, vertices += 4, verts1++, verts2++, verts3++, verts4++)
105                                                 VectorMAMAMAM(vlerp1, verts1->origin, vlerp2, verts2->origin, vlerp3, verts3->origin, vlerp4, verts4->origin, vertices);
106                         }
107                         else
108                         {
109                                 // generate vertices
110                                 if (svectors != NULL)
111                                 {
112                                         for (i = 0;i < vertcount;i++, vertices += 4, normals += 4, svectors += 4, tvectors += 4, verts1++, verts2++, verts3++)
113                                         {
114                                                 VectorMAMAM(vlerp1, verts1->origin, vlerp2, verts2->origin, vlerp3, verts3->origin, vertices);
115                                                 VectorMAMAM(nlerp1, verts1->normal, nlerp2, verts2->normal, nlerp3, verts3->normal, normals);
116                                                 VectorMAMAM(nlerp1, verts1->svector, nlerp2, verts2->svector, nlerp3, verts3->svector, svectors);
117                                                 CrossProduct(svectors, normals, tvectors);
118                                         }
119                                 }
120                                 else if (normals != NULL)
121                                 {
122                                         for (i = 0;i < vertcount;i++, vertices += 4, normals += 4, verts1++, verts2++, verts3++)
123                                         {
124                                                 VectorMAMAM(vlerp1, verts1->origin, vlerp2, verts2->origin, vlerp3, verts3->origin, vertices);
125                                                 VectorMAMAM(nlerp1, verts1->normal, nlerp2, verts2->normal, nlerp3, verts3->normal, normals);
126                                         }
127                                 }
128                                 else
129                                         for (i = 0;i < vertcount;i++, vertices += 4, verts1++, verts2++, verts3++)
130                                                 VectorMAMAM(vlerp1, verts1->origin, vlerp2, verts2->origin, vlerp3, verts3->origin, vertices);
131                         }
132                 }
133                 else
134                 {
135                         // generate vertices
136                         if (svectors != NULL)
137                         {
138                                 for (i = 0;i < vertcount;i++, vertices += 4, normals += 4, svectors += 4, tvectors += 4, verts1++, verts2++)
139                                 {
140                                         VectorMAM(vlerp1, verts1->origin, vlerp2, verts2->origin, vertices);
141                                         VectorMAM(nlerp1, verts1->normal, nlerp2, verts2->normal, normals);
142                                         VectorMAM(nlerp1, verts1->svector, nlerp2, verts2->svector, svectors);
143                                         CrossProduct(svectors, normals, tvectors);
144                                 }
145                         }
146                         else if (normals != NULL)
147                         {
148                                 for (i = 0;i < vertcount;i++, vertices += 4, normals += 4, verts1++, verts2++)
149                                 {
150                                         VectorMAM(vlerp1, verts1->origin, vlerp2, verts2->origin, vertices);
151                                         VectorMAM(nlerp1, verts1->normal, nlerp2, verts2->normal, normals);
152                                 }
153                         }
154                         else
155                                 for (i = 0;i < vertcount;i++, vertices += 4, verts1++, verts2++)
156                                         VectorMAM(vlerp1, verts1->origin, vlerp2, verts2->origin, vertices);
157                 }
158         }
159         else
160         {
161                 // generate vertices
162                 if (svectors != NULL)
163                 {
164                         for (i = 0;i < vertcount;i++, vertices += 4, normals += 4, svectors += 4, tvectors += 4, verts1++)
165                         {
166                                 VectorM(vlerp1, verts1->origin, vertices);
167                                 VectorM(nlerp1, verts1->normal, normals);
168                                 VectorM(nlerp1, verts1->svector, svectors);
169                                 CrossProduct(svectors, normals, tvectors);
170                         }
171                 }
172                 else if (normals != NULL)
173                 {
174                         for (i = 0;i < vertcount;i++, vertices += 4, normals += 4, verts1++)
175                         {
176                                 VectorM(vlerp1, verts1->origin, vertices);
177                                 VectorM(nlerp1, verts1->normal, normals);
178                         }
179                 }
180                 else
181                         for (i = 0;i < vertcount;i++, vertices += 4, verts1++)
182                                 VectorM(vlerp1, verts1->origin, vertices);
183         }
184 }
185
186 skinframe_t *R_FetchSkinFrame(const entity_render_t *ent)
187 {
188         model_t *model = ent->model;
189         int s = ent->skinnum;
190         if ((unsigned int)s >= (unsigned int)model->numskins)
191                 s = 0;
192         if (model->skinscenes[s].framecount > 1)
193                 return &model->skinframes[model->skinscenes[s].firstframe + (int) (cl.time * 10) % model->skinscenes[s].framecount];
194         else
195                 return &model->skinframes[model->skinscenes[s].firstframe];
196 }
197
198 void R_DrawAliasModelCallback (const void *calldata1, int calldata2)
199 {
200         int i, c, fullbright, pantsfullbright, shirtfullbright, colormapped, tex;
201         float pantscolor[3], shirtcolor[3];
202         float fog, ifog, colorscale;
203         vec3_t diff;
204         qbyte *bcolor;
205         rmeshstate_t m;
206         model_t *model;
207         skinframe_t *skinframe;
208         const entity_render_t *ent = calldata1;
209         int blendfunc1, blendfunc2;
210
211         R_Mesh_Matrix(&ent->matrix);
212
213         model = ent->model;
214         R_Mesh_ResizeCheck(model->numverts);
215
216         skinframe = R_FetchSkinFrame(ent);
217
218         fullbright = (ent->effects & EF_FULLBRIGHT) != 0;
219
220         fog = 0;
221         if (fogenabled)
222         {
223                 VectorSubtract(ent->origin, r_origin, diff);
224                 fog = DotProduct(diff,diff);
225                 if (fog < 0.01f)
226                         fog = 0.01f;
227                 fog = exp(fogdensity/fog);
228                 if (fog > 1)
229                         fog = 1;
230                 if (fog < 0.01f)
231                         fog = 0;
232                 // fog method: darken, additive fog
233                 // 1. render model as normal, scaled by inverse of fog alpha (darkens it)
234                 // 2. render fog as additive
235         }
236         ifog = 1 - fog;
237
238         if (ent->effects & EF_ADDITIVE)
239         {
240                 blendfunc1 = GL_SRC_ALPHA;
241                 blendfunc2 = GL_ONE;
242         }
243         else if (ent->alpha != 1.0 || skinframe->fog != NULL)
244         {
245                 blendfunc1 = GL_SRC_ALPHA;
246                 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
247         }
248         else
249         {
250                 blendfunc1 = GL_ONE;
251                 blendfunc2 = GL_ZERO;
252         }
253
254         R_Model_Alias_GetVerts(ent, varray_vertex, aliasvert_normals, NULL, NULL);
255         memcpy(varray_texcoord[0], model->mdlmd2data_texcoords, model->numverts * sizeof(float[4]));
256         if (!skinframe->base && !skinframe->pants && !skinframe->shirt && !skinframe->glow)
257         {
258                 // untextured
259                 memset(&m, 0, sizeof(m));
260                 m.blendfunc1 = blendfunc1;
261                 m.blendfunc2 = blendfunc2;
262                 colorscale = r_colorscale;
263                 if (gl_combine.integer)
264                 {
265                         colorscale *= 0.25f;
266                         m.texrgbscale[0] = 4;
267                 }
268                 m.tex[0] = R_GetTexture(r_notexture);
269                 R_Mesh_State(&m);
270                 c_alias_polys += model->numtris;
271                 for (i = 0;i < model->numverts * 4;i += 4)
272                 {
273                         varray_texcoord[0][i + 0] *= 8.0f;
274                         varray_texcoord[0][i + 1] *= 8.0f;
275                 }
276                 R_LightModel(ent, model->numverts, varray_vertex, aliasvert_normals, varray_color, colorscale, colorscale, colorscale, false);
277                 R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
278                 return;
279         }
280
281         colormapped = !skinframe->merged || (ent->colormap >= 0 && skinframe->base && (skinframe->pants || skinframe->shirt));
282         if (colormapped)
283         {
284                 // 128-224 are backwards ranges
285                 c = (ent->colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12;
286                 bcolor = (qbyte *) (&palette_complete[c]);
287                 pantsfullbright = c >= 224;
288                 VectorScale(bcolor, (1.0f / 255.0f), pantscolor);
289                 c = (ent->colormap & 0xF0);c += (c >= 128 && c < 224) ? 4 : 12;
290                 bcolor = (qbyte *) (&palette_complete[c]);
291                 shirtfullbright = c >= 224;
292                 VectorScale(bcolor, (1.0f / 255.0f), shirtcolor);
293         }
294         else
295         {
296                 pantscolor[0] = pantscolor[1] = pantscolor[2] = shirtcolor[0] = shirtcolor[1] = shirtcolor[2] = 1;
297                 pantsfullbright = shirtfullbright = false;
298         }
299
300         tex = colormapped ? R_GetTexture(skinframe->base) : R_GetTexture(skinframe->merged);
301         if (tex)
302         {
303                 memset(&m, 0, sizeof(m));
304                 m.blendfunc1 = blendfunc1;
305                 m.blendfunc2 = blendfunc2;
306                 colorscale = r_colorscale;
307                 if (gl_combine.integer)
308                 {
309                         colorscale *= 0.25f;
310                         m.texrgbscale[0] = 4;
311                 }
312                 m.tex[0] = tex;
313                 R_Mesh_State(&m);
314                 if (fullbright)
315                         GL_Color(colorscale * ifog, colorscale * ifog, colorscale * ifog, ent->alpha);
316                 else
317                         R_LightModel(ent, model->numverts, varray_vertex, aliasvert_normals, varray_color, colorscale * ifog, colorscale * ifog, colorscale * ifog, false);
318                 R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
319                 c_alias_polys += model->numtris;
320                 blendfunc1 = GL_SRC_ALPHA;
321                 blendfunc2 = GL_ONE;
322         }
323
324         if (colormapped)
325         {
326                 if (skinframe->pants)
327                 {
328                         tex = R_GetTexture(skinframe->pants);
329                         if (tex)
330                         {
331                                 memset(&m, 0, sizeof(m));
332                                 m.blendfunc1 = blendfunc1;
333                                 m.blendfunc2 = blendfunc2;
334                                 colorscale = r_colorscale;
335                                 if (gl_combine.integer)
336                                 {
337                                         colorscale *= 0.25f;
338                                         m.texrgbscale[0] = 4;
339                                 }
340                                 m.tex[0] = tex;
341                                 R_Mesh_State(&m);
342                                 if (pantsfullbright)
343                                         GL_Color(pantscolor[0] * colorscale * ifog, pantscolor[1] * colorscale * ifog, pantscolor[2] * colorscale * ifog, ent->alpha);
344                                 else
345                                         R_LightModel(ent, model->numverts, varray_vertex, aliasvert_normals, varray_color, pantscolor[0] * colorscale * ifog, pantscolor[1] * colorscale * ifog, pantscolor[2] * colorscale * ifog, false);
346                                 R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
347                                 c_alias_polys += model->numtris;
348                                 blendfunc1 = GL_SRC_ALPHA;
349                                 blendfunc2 = GL_ONE;
350                         }
351                 }
352                 if (skinframe->shirt)
353                 {
354                         tex = R_GetTexture(skinframe->shirt);
355                         if (tex)
356                         {
357                                 memset(&m, 0, sizeof(m));
358                                 m.blendfunc1 = blendfunc1;
359                                 m.blendfunc2 = blendfunc2;
360                                 colorscale = r_colorscale;
361                                 if (gl_combine.integer)
362                                 {
363                                         colorscale *= 0.25f;
364                                         m.texrgbscale[0] = 4;
365                                 }
366                                 m.tex[0] = tex;
367                                 R_Mesh_State(&m);
368                                 if (shirtfullbright)
369                                         GL_Color(shirtcolor[0] * colorscale * ifog, shirtcolor[1] * colorscale * ifog, shirtcolor[2] * colorscale * ifog, ent->alpha);
370                                 else
371                                         R_LightModel(ent, model->numverts, varray_vertex, aliasvert_normals, varray_color, shirtcolor[0] * colorscale * ifog, shirtcolor[1] * colorscale * ifog, shirtcolor[2] * colorscale * ifog, false);
372                                 R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
373                                 c_alias_polys += model->numtris;
374                                 blendfunc1 = GL_SRC_ALPHA;
375                                 blendfunc2 = GL_ONE;
376                         }
377                 }
378         }
379         if (skinframe->glow)
380         {
381                 tex = R_GetTexture(skinframe->glow);
382                 if (tex)
383                 {
384                         memset(&m, 0, sizeof(m));
385                         m.blendfunc1 = blendfunc1;
386                         m.blendfunc2 = blendfunc2;
387                         m.tex[0] = tex;
388                         R_Mesh_State(&m);
389
390                         blendfunc1 = GL_SRC_ALPHA;
391                         blendfunc2 = GL_ONE;
392                         c_alias_polys += model->numtris;
393                         GL_Color(ifog * r_colorscale, ifog * r_colorscale, ifog * r_colorscale, ent->alpha);
394                         R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
395                 }
396         }
397         if (fog)
398         {
399                 memset(&m, 0, sizeof(m));
400                 m.blendfunc1 = GL_SRC_ALPHA;
401                 m.blendfunc2 = GL_ONE;
402                 m.tex[0] = R_GetTexture(skinframe->fog);
403                 R_Mesh_State(&m);
404
405                 c_alias_polys += model->numtris;
406                 GL_Color(fogcolor[0] * fog * r_colorscale, fogcolor[1] * fog * r_colorscale, fogcolor[2] * fog * r_colorscale, ent->alpha);
407                 R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
408         }
409 }
410
411 void R_Model_Alias_Draw(entity_render_t *ent)
412 {
413         if (ent->alpha < (1.0f / 64.0f))
414                 return; // basically completely transparent
415
416         c_models++;
417
418         if (ent->effects & EF_ADDITIVE || ent->alpha != 1.0 || R_FetchSkinFrame(ent)->fog != NULL)
419                 R_MeshQueue_AddTransparent(ent->origin, R_DrawAliasModelCallback, ent, 0);
420         else
421                 R_DrawAliasModelCallback(ent, 0);
422 }
423
424 void R_Model_Alias_DrawFakeShadow (entity_render_t *ent)
425 {
426         int i;
427         rmeshstate_t m;
428         model_t *model;
429         float *v, planenormal[3], planedist, dist, projection[3], floororigin[3], surfnormal[3], lightdirection[3], v2[3];
430
431         lightdirection[0] = 0.5;
432         lightdirection[1] = 0.2;
433         lightdirection[2] = -1;
434         VectorNormalizeFast(lightdirection);
435
436         VectorMA(ent->origin, 65536.0f, lightdirection, v2);
437         if (CL_TraceLine(ent->origin, v2, floororigin, surfnormal, 0, false, NULL) == 1)
438                 return;
439
440         R_Mesh_Matrix(&ent->matrix);
441
442         model = ent->model;
443         R_Mesh_ResizeCheck(model->numverts);
444
445         memset(&m, 0, sizeof(m));
446         m.blendfunc1 = GL_SRC_ALPHA;
447         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
448         R_Mesh_State(&m);
449
450         c_alias_polys += model->numtris;
451         R_Model_Alias_GetVerts(ent, varray_vertex, NULL, NULL, NULL);
452
453         // put a light direction in the entity's coordinate space
454         Matrix4x4_Transform3x3(&ent->inversematrix, lightdirection, projection);
455         VectorNormalizeFast(projection);
456
457         // put the plane's normal in the entity's coordinate space
458         Matrix4x4_Transform3x3(&ent->inversematrix, surfnormal, planenormal);
459         VectorNormalizeFast(planenormal);
460
461         // put the plane's distance in the entity's coordinate space
462         VectorSubtract(floororigin, ent->origin, floororigin);
463         planedist = DotProduct(floororigin, surfnormal) + 2;
464
465         dist = -1.0f / DotProduct(projection, planenormal);
466         VectorScale(projection, dist, projection);
467         for (i = 0, v = varray_vertex;i < model->numverts;i++, v += 4)
468         {
469                 dist = DotProduct(v, planenormal) - planedist;
470                 if (dist > 0)
471                 //if (i & 1)
472                         VectorMA(v, dist, projection, v);
473         }
474         GL_Color(0, 0, 0, 0.5);
475         R_Mesh_Draw(model->numverts, model->numtris, model->mdlmd2data_indices);
476 }
477
478 void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius)
479 {
480         float projectdistance;
481         projectdistance = lightradius + ent->model->radius - sqrt(DotProduct(relativelightorigin, relativelightorigin));
482         if (projectdistance > 0.1)
483         {
484                 R_Mesh_Matrix(&ent->matrix);
485                 R_Mesh_ResizeCheck(ent->model->numverts * 2);
486                 R_Model_Alias_GetVerts(ent, varray_vertex, NULL, NULL, NULL);
487                 R_Shadow_Volume(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, ent->model->mdlmd2data_triangleneighbors, relativelightorigin, lightradius, projectdistance);
488         }
489 }
490
491 void R_Model_Alias_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor)
492 {
493         int c;
494         float lightcolor2[3];
495         qbyte *bcolor;
496         skinframe_t *skinframe;
497         R_Mesh_Matrix(&ent->matrix);
498         R_Mesh_ResizeCheck(ent->model->numverts);
499         R_Model_Alias_GetVerts(ent, varray_vertex, aliasvert_normals, aliasvert_svectors, aliasvert_tvectors);
500         skinframe = R_FetchSkinFrame(ent);
501
502         // note: to properly handle fog this should scale the lightcolor into lightcolor2 according to 1-fog scaling
503
504         R_Shadow_SpecularLighting(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, ent->model->mdlmd2data_texcoords, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, NULL, NULL, NULL);
505
506         if (!skinframe->base && !skinframe->pants && !skinframe->shirt && !skinframe->glow)
507         {
508                 R_Shadow_DiffuseLighting(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, ent->model->mdlmd2data_texcoords, relativelightorigin, lightradius, lightcolor, r_notexture, NULL, NULL);
509                 return;
510         }
511
512         if (!skinframe->merged || (ent->colormap >= 0 && skinframe->base && (skinframe->pants || skinframe->shirt)))
513         {
514                 // 128-224 are backwards ranges
515                 // we only render non-fullbright ranges here
516                 if (skinframe->pants && (ent->colormap & 0xF) < 0xE)
517                 {
518                         c = (ent->colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12;
519                         bcolor = (qbyte *) (&palette_complete[c]);
520                         lightcolor2[0] = lightcolor[0] * bcolor[0] * (1.0f / 255.0f);
521                         lightcolor2[1] = lightcolor[1] * bcolor[1] * (1.0f / 255.0f);
522                         lightcolor2[2] = lightcolor[2] * bcolor[2] * (1.0f / 255.0f);
523                         R_Shadow_DiffuseLighting(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, ent->model->mdlmd2data_texcoords, relativelightorigin, lightradius, lightcolor2, skinframe->pants, skinframe->nmap, NULL);
524                 }
525
526                 // we only render non-fullbright ranges here
527                 if (skinframe->shirt && (ent->colormap & 0xF0) < 0xE0)
528                 {
529                         c = (ent->colormap & 0xF0);c += (c >= 128 && c < 224) ? 4 : 12;
530                         bcolor = (qbyte *) (&palette_complete[c]);
531                         lightcolor2[0] = lightcolor[0] * bcolor[0] * (1.0f / 255.0f);
532                         lightcolor2[1] = lightcolor[1] * bcolor[1] * (1.0f / 255.0f);
533                         lightcolor2[2] = lightcolor[2] * bcolor[2] * (1.0f / 255.0f);
534                         R_Shadow_DiffuseLighting(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, ent->model->mdlmd2data_texcoords, relativelightorigin, lightradius, lightcolor2, skinframe->shirt, skinframe->nmap, NULL);
535                 }
536
537                 if (skinframe->base)
538                         R_Shadow_DiffuseLighting(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, ent->model->mdlmd2data_texcoords, relativelightorigin, lightradius, lightcolor, skinframe->base, skinframe->nmap, NULL);
539         }
540         else
541                 if (skinframe->merged)
542                         R_Shadow_DiffuseLighting(ent->model->numverts, ent->model->numtris, ent->model->mdlmd2data_indices, aliasvert_svectors, aliasvert_tvectors, aliasvert_normals, ent->model->mdlmd2data_texcoords, relativelightorigin, lightradius, lightcolor, skinframe->merged, skinframe->nmap, NULL);
543 }
544
545 int ZymoticLerpBones(int count, const zymbonematrix *bonebase, const frameblend_t *blend, const zymbone_t *bone)
546 {
547         int i;
548         float lerp1, lerp2, lerp3, lerp4;
549         zymbonematrix *out, rootmatrix, m;
550         const zymbonematrix *bone1, *bone2, *bone3, *bone4;
551
552         rootmatrix.m[0][0] = 1;
553         rootmatrix.m[0][1] = 0;
554         rootmatrix.m[0][2] = 0;
555         rootmatrix.m[0][3] = 0;
556         rootmatrix.m[1][0] = 0;
557         rootmatrix.m[1][1] = 1;
558         rootmatrix.m[1][2] = 0;
559         rootmatrix.m[1][3] = 0;
560         rootmatrix.m[2][0] = 0;
561         rootmatrix.m[2][1] = 0;
562         rootmatrix.m[2][2] = 1;
563         rootmatrix.m[2][3] = 0;
564
565         bone1 = bonebase + blend[0].frame * count;
566         lerp1 = blend[0].lerp;
567         if (blend[1].lerp)
568         {
569                 bone2 = bonebase + blend[1].frame * count;
570                 lerp2 = blend[1].lerp;
571                 if (blend[2].lerp)
572                 {
573                         bone3 = bonebase + blend[2].frame * count;
574                         lerp3 = blend[2].lerp;
575                         if (blend[3].lerp)
576                         {
577                                 // 4 poses
578                                 bone4 = bonebase + blend[3].frame * count;
579                                 lerp4 = blend[3].lerp;
580                                 for (i = 0, out = zymbonepose;i < count;i++, out++)
581                                 {
582                                         // interpolate matrices
583                                         m.m[0][0] = bone1->m[0][0] * lerp1 + bone2->m[0][0] * lerp2 + bone3->m[0][0] * lerp3 + bone4->m[0][0] * lerp4;
584                                         m.m[0][1] = bone1->m[0][1] * lerp1 + bone2->m[0][1] * lerp2 + bone3->m[0][1] * lerp3 + bone4->m[0][1] * lerp4;
585                                         m.m[0][2] = bone1->m[0][2] * lerp1 + bone2->m[0][2] * lerp2 + bone3->m[0][2] * lerp3 + bone4->m[0][2] * lerp4;
586                                         m.m[0][3] = bone1->m[0][3] * lerp1 + bone2->m[0][3] * lerp2 + bone3->m[0][3] * lerp3 + bone4->m[0][3] * lerp4;
587                                         m.m[1][0] = bone1->m[1][0] * lerp1 + bone2->m[1][0] * lerp2 + bone3->m[1][0] * lerp3 + bone4->m[1][0] * lerp4;
588                                         m.m[1][1] = bone1->m[1][1] * lerp1 + bone2->m[1][1] * lerp2 + bone3->m[1][1] * lerp3 + bone4->m[1][1] * lerp4;
589                                         m.m[1][2] = bone1->m[1][2] * lerp1 + bone2->m[1][2] * lerp2 + bone3->m[1][2] * lerp3 + bone4->m[1][2] * lerp4;
590                                         m.m[1][3] = bone1->m[1][3] * lerp1 + bone2->m[1][3] * lerp2 + bone3->m[1][3] * lerp3 + bone4->m[1][3] * lerp4;
591                                         m.m[2][0] = bone1->m[2][0] * lerp1 + bone2->m[2][0] * lerp2 + bone3->m[2][0] * lerp3 + bone4->m[2][0] * lerp4;
592                                         m.m[2][1] = bone1->m[2][1] * lerp1 + bone2->m[2][1] * lerp2 + bone3->m[2][1] * lerp3 + bone4->m[2][1] * lerp4;
593                                         m.m[2][2] = bone1->m[2][2] * lerp1 + bone2->m[2][2] * lerp2 + bone3->m[2][2] * lerp3 + bone4->m[2][2] * lerp4;
594                                         m.m[2][3] = bone1->m[2][3] * lerp1 + bone2->m[2][3] * lerp2 + bone3->m[2][3] * lerp3 + bone4->m[2][3] * lerp4;
595                                         if (bone->parent >= 0)
596                                                 R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &m.m[0][0], &out->m[0][0]);
597                                         else
598                                                 R_ConcatTransforms(&rootmatrix.m[0][0], &m.m[0][0], &out->m[0][0]);
599                                         bone1++;
600                                         bone2++;
601                                         bone3++;
602                                         bone4++;
603                                         bone++;
604                                 }
605                         }
606                         else
607                         {
608                                 // 3 poses
609                                 for (i = 0, out = zymbonepose;i < count;i++, out++)
610                                 {
611                                         // interpolate matrices
612                                         m.m[0][0] = bone1->m[0][0] * lerp1 + bone2->m[0][0] * lerp2 + bone3->m[0][0] * lerp3;
613                                         m.m[0][1] = bone1->m[0][1] * lerp1 + bone2->m[0][1] * lerp2 + bone3->m[0][1] * lerp3;
614                                         m.m[0][2] = bone1->m[0][2] * lerp1 + bone2->m[0][2] * lerp2 + bone3->m[0][2] * lerp3;
615                                         m.m[0][3] = bone1->m[0][3] * lerp1 + bone2->m[0][3] * lerp2 + bone3->m[0][3] * lerp3;
616                                         m.m[1][0] = bone1->m[1][0] * lerp1 + bone2->m[1][0] * lerp2 + bone3->m[1][0] * lerp3;
617                                         m.m[1][1] = bone1->m[1][1] * lerp1 + bone2->m[1][1] * lerp2 + bone3->m[1][1] * lerp3;
618                                         m.m[1][2] = bone1->m[1][2] * lerp1 + bone2->m[1][2] * lerp2 + bone3->m[1][2] * lerp3;
619                                         m.m[1][3] = bone1->m[1][3] * lerp1 + bone2->m[1][3] * lerp2 + bone3->m[1][3] * lerp3;
620                                         m.m[2][0] = bone1->m[2][0] * lerp1 + bone2->m[2][0] * lerp2 + bone3->m[2][0] * lerp3;
621                                         m.m[2][1] = bone1->m[2][1] * lerp1 + bone2->m[2][1] * lerp2 + bone3->m[2][1] * lerp3;
622                                         m.m[2][2] = bone1->m[2][2] * lerp1 + bone2->m[2][2] * lerp2 + bone3->m[2][2] * lerp3;
623                                         m.m[2][3] = bone1->m[2][3] * lerp1 + bone2->m[2][3] * lerp2 + bone3->m[2][3] * lerp3;
624                                         if (bone->parent >= 0)
625                                                 R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &m.m[0][0], &out->m[0][0]);
626                                         else
627                                                 R_ConcatTransforms(&rootmatrix.m[0][0], &m.m[0][0], &out->m[0][0]);
628                                         bone1++;
629                                         bone2++;
630                                         bone3++;
631                                         bone++;
632                                 }
633                         }
634                 }
635                 else
636                 {
637                         // 2 poses
638                         for (i = 0, out = zymbonepose;i < count;i++, out++)
639                         {
640                                 // interpolate matrices
641                                 m.m[0][0] = bone1->m[0][0] * lerp1 + bone2->m[0][0] * lerp2;
642                                 m.m[0][1] = bone1->m[0][1] * lerp1 + bone2->m[0][1] * lerp2;
643                                 m.m[0][2] = bone1->m[0][2] * lerp1 + bone2->m[0][2] * lerp2;
644                                 m.m[0][3] = bone1->m[0][3] * lerp1 + bone2->m[0][3] * lerp2;
645                                 m.m[1][0] = bone1->m[1][0] * lerp1 + bone2->m[1][0] * lerp2;
646                                 m.m[1][1] = bone1->m[1][1] * lerp1 + bone2->m[1][1] * lerp2;
647                                 m.m[1][2] = bone1->m[1][2] * lerp1 + bone2->m[1][2] * lerp2;
648                                 m.m[1][3] = bone1->m[1][3] * lerp1 + bone2->m[1][3] * lerp2;
649                                 m.m[2][0] = bone1->m[2][0] * lerp1 + bone2->m[2][0] * lerp2;
650                                 m.m[2][1] = bone1->m[2][1] * lerp1 + bone2->m[2][1] * lerp2;
651                                 m.m[2][2] = bone1->m[2][2] * lerp1 + bone2->m[2][2] * lerp2;
652                                 m.m[2][3] = bone1->m[2][3] * lerp1 + bone2->m[2][3] * lerp2;
653                                 if (bone->parent >= 0)
654                                         R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &m.m[0][0], &out->m[0][0]);
655                                 else
656                                         R_ConcatTransforms(&rootmatrix.m[0][0], &m.m[0][0], &out->m[0][0]);
657                                 bone1++;
658                                 bone2++;
659                                 bone++;
660                         }
661                 }
662         }
663         else
664         {
665                 // 1 pose
666                 if (lerp1 != 1)
667                 {
668                         // lerp != 1.0
669                         for (i = 0, out = zymbonepose;i < count;i++, out++)
670                         {
671                                 // interpolate matrices
672                                 m.m[0][0] = bone1->m[0][0] * lerp1;
673                                 m.m[0][1] = bone1->m[0][1] * lerp1;
674                                 m.m[0][2] = bone1->m[0][2] * lerp1;
675                                 m.m[0][3] = bone1->m[0][3] * lerp1;
676                                 m.m[1][0] = bone1->m[1][0] * lerp1;
677                                 m.m[1][1] = bone1->m[1][1] * lerp1;
678                                 m.m[1][2] = bone1->m[1][2] * lerp1;
679                                 m.m[1][3] = bone1->m[1][3] * lerp1;
680                                 m.m[2][0] = bone1->m[2][0] * lerp1;
681                                 m.m[2][1] = bone1->m[2][1] * lerp1;
682                                 m.m[2][2] = bone1->m[2][2] * lerp1;
683                                 m.m[2][3] = bone1->m[2][3] * lerp1;
684                                 if (bone->parent >= 0)
685                                         R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &m.m[0][0], &out->m[0][0]);
686                                 else
687                                         R_ConcatTransforms(&rootmatrix.m[0][0], &m.m[0][0], &out->m[0][0]);
688                                 bone1++;
689                                 bone++;
690                         }
691                 }
692                 else
693                 {
694                         // lerp == 1.0
695                         for (i = 0, out = zymbonepose;i < count;i++, out++)
696                         {
697                                 if (bone->parent >= 0)
698                                         R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &bone1->m[0][0], &out->m[0][0]);
699                                 else
700                                         R_ConcatTransforms(&rootmatrix.m[0][0], &bone1->m[0][0], &out->m[0][0]);
701                                 bone1++;
702                                 bone++;
703                         }
704                 }
705         }
706         return true;
707 }
708
709 void ZymoticTransformVerts(int vertcount, float *vertex, int *bonecounts, zymvertex_t *vert)
710 {
711         int c;
712         float *out = vertex;
713         zymbonematrix *matrix;
714         while(vertcount--)
715         {
716                 c = *bonecounts++;
717                 // FIXME: validate bonecounts at load time (must be >= 1)
718                 // FIXME: need 4th component in origin, for how much of the translate to blend in
719                 if (c == 1)
720                 {
721                         matrix = &zymbonepose[vert->bonenum];
722                         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];
723                         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];
724                         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];
725                         vert++;
726                 }
727                 else
728                 {
729                         VectorClear(out);
730                         while(c--)
731                         {
732                                 matrix = &zymbonepose[vert->bonenum];
733                                 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];
734                                 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];
735                                 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];
736                                 vert++;
737                         }
738                 }
739                 out += 4;
740         }
741 }
742
743 void ZymoticCalcNormals(int vertcount, float *vertex, float *normals, int shadercount, int *renderlist)
744 {
745         int a, b, c, d;
746         float *out, v1[3], v2[3], normal[3], s;
747         int *u;
748         // clear normals
749         memset(normals, 0, sizeof(float) * vertcount * 3);
750         memset(aliasvertusage, 0, sizeof(int) * vertcount);
751         // parse render list and accumulate surface normals
752         while(shadercount--)
753         {
754                 d = *renderlist++;
755                 while (d--)
756                 {
757                         a = renderlist[0]*4;
758                         b = renderlist[1]*4;
759                         c = renderlist[2]*4;
760                         v1[0] = vertex[a+0] - vertex[b+0];
761                         v1[1] = vertex[a+1] - vertex[b+1];
762                         v1[2] = vertex[a+2] - vertex[b+2];
763                         v2[0] = vertex[c+0] - vertex[b+0];
764                         v2[1] = vertex[c+1] - vertex[b+1];
765                         v2[2] = vertex[c+2] - vertex[b+2];
766                         CrossProduct(v1, v2, normal);
767                         VectorNormalizeFast(normal);
768                         // add surface normal to vertices
769                         a = renderlist[0] * 3;
770                         normals[a+0] += normal[0];
771                         normals[a+1] += normal[1];
772                         normals[a+2] += normal[2];
773                         aliasvertusage[renderlist[0]]++;
774                         a = renderlist[1] * 3;
775                         normals[a+0] += normal[0];
776                         normals[a+1] += normal[1];
777                         normals[a+2] += normal[2];
778                         aliasvertusage[renderlist[1]]++;
779                         a = renderlist[2] * 3;
780                         normals[a+0] += normal[0];
781                         normals[a+1] += normal[1];
782                         normals[a+2] += normal[2];
783                         aliasvertusage[renderlist[2]]++;
784                         renderlist += 3;
785                 }
786         }
787         // FIXME: precalc this
788         // average surface normals
789         out = normals;
790         u = aliasvertusage;
791         while(vertcount--)
792         {
793                 if (*u > 1)
794                 {
795                         s = ixtable[*u];
796                         out[0] *= s;
797                         out[1] *= s;
798                         out[2] *= s;
799                 }
800                 u++;
801                 out += 3;
802         }
803 }
804
805 void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2)
806 {
807         float fog, ifog, colorscale;
808         vec3_t diff;
809         int i, *renderlist, *elements;
810         rtexture_t *texture;
811         rmeshstate_t mstate;
812         const entity_render_t *ent = calldata1;
813         int shadernum = calldata2;
814         int numverts, numtriangles;
815
816         R_Mesh_Matrix(&ent->matrix);
817
818         // find the vertex index list and texture
819         renderlist = ent->model->zymdata_renderlist;
820         for (i = 0;i < shadernum;i++)
821                 renderlist += renderlist[0] * 3 + 1;
822         texture = ent->model->zymdata_textures[shadernum];
823
824         numverts = ent->model->zymnum_verts;
825         numtriangles = *renderlist++;
826         elements = renderlist;
827         R_Mesh_ResizeCheck(numverts);
828
829         fog = 0;
830         if (fogenabled)
831         {
832                 VectorSubtract(ent->origin, r_origin, diff);
833                 fog = DotProduct(diff,diff);
834                 if (fog < 0.01f)
835                         fog = 0.01f;
836                 fog = exp(fogdensity/fog);
837                 if (fog > 1)
838                         fog = 1;
839                 if (fog < 0.01f)
840                         fog = 0;
841                 // fog method: darken, additive fog
842                 // 1. render model as normal, scaled by inverse of fog alpha (darkens it)
843                 // 2. render fog as additive
844         }
845         ifog = 1 - fog;
846
847         memset(&mstate, 0, sizeof(mstate));
848         if (ent->effects & EF_ADDITIVE)
849         {
850                 mstate.blendfunc1 = GL_SRC_ALPHA;
851                 mstate.blendfunc2 = GL_ONE;
852         }
853         else if (ent->alpha != 1.0 || R_TextureHasAlpha(texture))
854         {
855                 mstate.blendfunc1 = GL_SRC_ALPHA;
856                 mstate.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
857         }
858         else
859         {
860                 mstate.blendfunc1 = GL_ONE;
861                 mstate.blendfunc2 = GL_ZERO;
862         }
863         colorscale = r_colorscale;
864         if (gl_combine.integer)
865         {
866                 mstate.texrgbscale[0] = 4;
867                 colorscale *= 0.25f;
868         }
869         mstate.tex[0] = R_GetTexture(texture);
870         R_Mesh_State(&mstate);
871         ZymoticLerpBones(ent->model->zymnum_bones, (zymbonematrix *) ent->model->zymdata_poses, ent->frameblend, ent->model->zymdata_bones);
872         ZymoticTransformVerts(numverts, varray_vertex, ent->model->zymdata_vertbonecounts, ent->model->zymdata_verts);
873         ZymoticCalcNormals(numverts, varray_vertex, aliasvert_normals, ent->model->zymnum_shaders, ent->model->zymdata_renderlist);
874         memcpy(varray_texcoord[0], ent->model->zymdata_texcoords, ent->model->zymnum_verts * sizeof(float[4]));
875         GL_UseColorArray();
876         R_LightModel(ent, numverts, varray_vertex, aliasvert_normals, varray_color, ifog * colorscale, ifog * colorscale, ifog * colorscale, false);
877         R_Mesh_Draw(numverts, numtriangles, elements);
878         c_alias_polys += numtriangles;
879
880         if (fog)
881         {
882                 memset(&mstate, 0, sizeof(mstate));
883                 mstate.blendfunc1 = GL_SRC_ALPHA;
884                 mstate.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
885                 // FIXME: need alpha mask for fogging...
886                 //mstate.tex[0] = R_GetTexture(texture);
887                 R_Mesh_State(&mstate);
888                 GL_Color(fogcolor[0] * r_colorscale, fogcolor[1] * r_colorscale, fogcolor[2] * r_colorscale, ent->alpha * fog);
889                 R_Mesh_Draw(numverts, numtriangles, elements);
890                 c_alias_polys += numtriangles;
891         }
892 }
893
894 void R_Model_Zymotic_Draw(entity_render_t *ent)
895 {
896         int i;
897
898         if (ent->alpha < (1.0f / 64.0f))
899                 return; // basically completely transparent
900
901         c_models++;
902
903         for (i = 0;i < ent->model->zymnum_shaders;i++)
904         {
905                 if (ent->effects & EF_ADDITIVE || ent->alpha != 1.0 || R_TextureHasAlpha(ent->model->zymdata_textures[i]))
906                         R_MeshQueue_AddTransparent(ent->origin, R_DrawZymoticModelMeshCallback, ent, i);
907                 else
908                         R_DrawZymoticModelMeshCallback(ent, i);
909         }
910 }
911
912 void R_Model_Zymotic_DrawFakeShadow(entity_render_t *ent)
913 {
914         // FIXME
915 }
916
917 void R_Model_Zymotic_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor)
918 {
919         // FIXME
920 }
921
922 void R_Model_Zymotic_DrawOntoLight(entity_render_t *ent)
923 {
924         // FIXME
925 }