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