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