]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_models.c
added support for gl_mesh_copyarrays 0 mode in most shaders
[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, 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], *fcolor;
165         vec3_t diff;
166         qbyte *bcolor;
167         rmeshstate_t m;
168         const entity_render_t *ent = calldata1;
169         aliasmesh_t *mesh = ent->model->aliasdata_meshes + calldata2;
170         aliaslayer_t *layer;
171         aliasskin_t *skin;
172         rcachearrayrequest_t request;
173
174         R_Mesh_Matrix(&ent->matrix);
175
176         fog = 0;
177         if (fogenabled)
178         {
179                 VectorSubtract(ent->origin, r_origin, diff);
180                 fog = DotProduct(diff,diff);
181                 if (fog < 0.01f)
182                         fog = 0.01f;
183                 fog = exp(fogdensity/fog);
184                 if (fog > 1)
185                         fog = 1;
186                 if (fog < 0.01f)
187                         fog = 0;
188                 // fog method: darken, additive fog
189                 // 1. render model as normal, scaled by inverse of fog alpha (darkens it)
190                 // 2. render fog as additive
191         }
192         ifog = 1 - fog;
193
194         firstpass = true;
195         skin = R_FetchAliasSkin(ent, mesh);
196         for (layernum = 0, layer = skin->data_layers;layernum < skin->num_layers;layernum++, layer++)
197         {
198                 if (!(layer->flags & ALIASLAYER_FORCEDRAW_IF_FIRSTPASS) || !firstpass)
199                 {
200                         if (((layer->flags & ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED) && ent->colormap < 0)
201                          || ((layer->flags & ALIASLAYER_NODRAW_IF_COLORMAPPED) && ent->colormap >= 0)
202                          || ((layer->flags & ALIASLAYER_FOG) && !fogenabled)
203                          ||  (layer->flags & ALIASLAYER_SPECULAR)
204                          || ((layer->flags & ALIASLAYER_DIFFUSE) && (r_shadow_realtime_world.integer && r_ambient.integer <= 0 && r_fullbright.integer == 0 && !(ent->effects & EF_FULLBRIGHT))))
205                                 continue;
206                 }
207                 memset(&m, 0, sizeof(m));
208                 if (!firstpass || (ent->effects & EF_ADDITIVE))
209                 {
210                         m.blendfunc1 = GL_SRC_ALPHA;
211                         m.blendfunc2 = GL_ONE;
212                 }
213                 else if ((skin->flags & ALIASSKIN_TRANSPARENT) || ent->alpha != 1.0)
214                 {
215                         m.blendfunc1 = GL_SRC_ALPHA;
216                         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
217                 }
218                 else
219                 {
220                         m.blendfunc1 = GL_ONE;
221                         m.blendfunc2 = GL_ZERO;
222                 }
223                 firstpass = false;
224                 expandaliasvert(mesh->num_vertices);
225                 colorscale = r_colorscale;
226                 m.texrgbscale[0] = 1;
227                 m.tex[0] = R_GetTexture(layer->texture);
228                 if (gl_combine.integer && layer->flags & (ALIASLAYER_DIFFUSE | ALIASLAYER_SPECULAR))
229                 {
230                         colorscale *= 0.25f;
231                         m.texrgbscale[0] = 4;
232                 }
233                 c_alias_polys += mesh->num_triangles;
234                 if (gl_mesh_copyarrays.integer)
235                 {
236                         R_Mesh_State(&m);
237                         R_Mesh_GetSpace(mesh->num_vertices);
238                         if (layer->texture != NULL)
239                                 R_Mesh_CopyTexCoord2f(0, mesh->data_texcoord2f, mesh->num_vertices);
240                         R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, varray_vertex3f);
241                 }
242                 else
243                 {
244                         m.pointervertexcount = mesh->num_vertices;
245                         memset(&request, 0, sizeof(request));
246                         request.data_size = mesh->num_vertices * sizeof(float[3]);
247                         request.id_pointer2 = mesh->data_aliasvertex3f;
248                         request.id_number1 = layernum;
249                         request.id_number2 = 0;
250                         request.id_number3 = CRC_Block((void *)ent->frameblend, sizeof(ent->frameblend));
251                         if (R_Mesh_CacheArray(&request))
252                                 R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, request.data);
253                         m.pointer_vertex = request.data;
254                         m.pointer_texcoord[0] = layer->texture != NULL ? mesh->data_texcoord2f : NULL;
255                 }
256                 if (layer->flags & ALIASLAYER_FOG)
257                 {
258                         colorscale *= fog;
259                         GL_Color(fogcolor[0] * colorscale, fogcolor[1] * colorscale, fogcolor[2] * colorscale, ent->alpha);
260                 }
261                 else
262                 {
263                         if (layer->flags & (ALIASLAYER_COLORMAP_PANTS | ALIASLAYER_COLORMAP_SHIRT))
264                         {
265                                 // 128-224 are backwards ranges
266                                 if (layer->flags & ALIASLAYER_COLORMAP_PANTS)
267                                         c = (ent->colormap & 0xF) << 4;
268                                 else //if (layer->flags & ALIASLAYER_COLORMAP_SHIRT)
269                                         c = (ent->colormap & 0xF0);
270                                 c += (c >= 128 && c < 224) ? 4 : 12;
271                                 bcolor = (qbyte *) (&palette_complete[c]);
272                                 fullbright = c >= 224;
273                                 VectorScale(bcolor, (1.0f / 255.0f), tint);
274                         }
275                         else
276                         {
277                                 tint[0] = tint[1] = tint[2] = 1;
278                                 fullbright = false;
279                         }
280                         colorscale *= ifog;
281                         if (fullbright || !(layer->flags & ALIASLAYER_DIFFUSE) || r_fullbright.integer || (ent->effects & EF_FULLBRIGHT))
282                                 GL_Color(tint[0] * colorscale, tint[1] * colorscale, tint[2] * colorscale, ent->alpha);
283                         else if (r_shadow_realtime_world.integer)
284                         {
285                                 colorscale *= r_ambient.value * (2.0f / 128.0f);
286                                 GL_Color(tint[0] * colorscale, tint[1] * colorscale, tint[2] * colorscale, ent->alpha);
287                         }
288                         else
289                         {
290                                 if (R_LightModel(ambientcolor4f, ent, tint[0] * colorscale, tint[1] * colorscale, tint[2] * colorscale, ent->alpha, false))
291                                 {
292                                         GL_UseColorArray();
293                                         if (gl_mesh_copyarrays.integer)
294                                         {
295                                                 R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_NORMAL, aliasvert_normal3f);
296                                                 R_LightModel_CalcVertexColors(ambientcolor4f, mesh->num_vertices, varray_vertex3f, aliasvert_normal3f, varray_color4f);
297                                         }
298                                         else
299                                         {
300                                                 // request color4f cache
301                                                 request.data_size = mesh->num_vertices * sizeof(float[4]);
302                                                 request.id_pointer1 = ent;
303                                                 request.id_number2 = 2;
304                                                 request.id_number3 = CRC_Block((void *)ent->frameblend, sizeof(ent->frameblend)) + CRC_Block((void *)&ent->entlightstime, sizeof(ent->entlightstime));
305                                                 if (R_Mesh_CacheArray(&request))
306                                                 {
307                                                         // save off the color pointer before we blow away the request
308                                                         fcolor = request.data;
309                                                         m.pointer_color = fcolor;
310                                                         // request normal3f cache
311                                                         request.data_size = mesh->num_vertices * sizeof(float[3]);
312                                                         request.id_pointer1 = NULL;
313                                                         request.id_number2 = 3;
314                                                         request.id_number3 = CRC_Block((void *)ent->frameblend, sizeof(ent->frameblend));
315                                                         if (R_Mesh_CacheArray(&request))
316                                                                 R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_NORMAL, request.data);
317                                                         R_LightModel_CalcVertexColors(ambientcolor4f, mesh->num_vertices, m.pointer_vertex, request.data, fcolor);
318                                                 }
319                                                 else
320                                                         m.pointer_color = request.data;
321                                         }
322                                 }
323                                 else
324                                         GL_Color(ambientcolor4f[0], ambientcolor4f[1], ambientcolor4f[2], ambientcolor4f[3]);
325                         }
326                 }
327                 if (!gl_mesh_copyarrays.integer)
328                         R_Mesh_State(&m);
329                 R_Mesh_Draw(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
330         }
331 }
332
333 void R_Model_Alias_Draw(entity_render_t *ent)
334 {
335         int meshnum;
336         aliasmesh_t *mesh;
337         if (ent->alpha < (1.0f / 64.0f))
338                 return; // basically completely transparent
339
340         c_models++;
341
342         for (meshnum = 0, mesh = ent->model->aliasdata_meshes;meshnum < ent->model->aliasnum_meshes;meshnum++, mesh++)
343         {
344                 if (ent->effects & EF_ADDITIVE || ent->alpha != 1.0 || R_FetchAliasSkin(ent, mesh)->flags & ALIASSKIN_TRANSPARENT)
345                         R_MeshQueue_AddTransparent(ent->origin, R_DrawAliasModelCallback, ent, meshnum);
346                 else
347                         R_DrawAliasModelCallback(ent, meshnum);
348         }
349 }
350
351 void R_Model_Alias_DrawFakeShadow (entity_render_t *ent)
352 {
353         int i, meshnum;
354         aliasmesh_t *mesh;
355         aliasskin_t *skin;
356         rmeshstate_t m;
357         float *v, plane[4], dist, projection[3], floororigin[3], surfnormal[3], lightdirection[3], v2[3];
358         rcachearrayrequest_t request;
359
360         if ((ent->effects & EF_ADDITIVE) || ent->alpha < 1)
361                 return;
362
363         lightdirection[0] = 0.5;
364         lightdirection[1] = 0.2;
365         lightdirection[2] = -1;
366         VectorNormalizeFast(lightdirection);
367
368         VectorMA(ent->origin, 65536.0f, lightdirection, v2);
369         if (CL_TraceLine(ent->origin, v2, floororigin, surfnormal, 0, false, NULL) == 1)
370                 return;
371
372         R_Mesh_Matrix(&ent->matrix);
373
374         memset(&m, 0, sizeof(m));
375         m.blendfunc1 = GL_SRC_ALPHA;
376         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
377         if (gl_mesh_copyarrays.integer)
378                 R_Mesh_State(&m);
379         GL_Color(0, 0, 0, 0.5);
380
381         // put a light direction in the entity's coordinate space
382         Matrix4x4_Transform3x3(&ent->inversematrix, lightdirection, projection);
383         VectorNormalizeFast(projection);
384
385         // put the plane's normal in the entity's coordinate space
386         Matrix4x4_Transform3x3(&ent->inversematrix, surfnormal, plane);
387         VectorNormalizeFast(plane);
388
389         // put the plane's distance in the entity's coordinate space
390         VectorSubtract(floororigin, ent->origin, floororigin);
391         plane[3] = DotProduct(floororigin, surfnormal) + 2;
392
393         dist = -1.0f / DotProduct(projection, plane);
394         VectorScale(projection, dist, projection);
395         memset(&request, 0, sizeof(request));
396         for (meshnum = 0, mesh = ent->model->aliasdata_meshes;meshnum < ent->model->aliasnum_meshes;meshnum++)
397         {
398                 skin = R_FetchAliasSkin(ent, mesh);
399                 if (skin->flags & ALIASSKIN_TRANSPARENT)
400                         continue;
401                 if (gl_mesh_copyarrays.integer)
402                 {
403                         R_Mesh_GetSpace(mesh->num_vertices);
404                         R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, varray_vertex3f);
405                         for (i = 0, v = varray_vertex3f;i < mesh->num_vertices;i++, v += 3)
406                         {
407                                 dist = DotProduct(v, plane) - plane[3];
408                                 if (dist > 0)
409                                         VectorMA(v, dist, projection, v);
410                         }
411                 }
412                 else
413                 {
414                         request.data_size = mesh->num_vertices * sizeof(float[3]);
415                         request.id_pointer1 = mesh;
416                         request.id_number1 = CRC_Block((void *)&ent->matrix, sizeof(ent->matrix));
417                         request.id_number2 = CRC_Block((void *)&plane, sizeof(plane));
418                         request.id_number3 = CRC_Block((void *)&ent->frameblend, sizeof(ent->frameblend));
419                         m.pointervertexcount = mesh->num_vertices;
420                         if (R_Mesh_CacheArray(&request))
421                         {
422                                 R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, request.data);
423                                 for (i = 0, v = request.data;i < mesh->num_vertices;i++, v += 3)
424                                 {
425                                         dist = DotProduct(v, plane) - plane[3];
426                                         if (dist > 0)
427                                                 VectorMA(v, dist, projection, v);
428                                 }
429                         }
430                         m.pointer_vertex = request.data;
431                         R_Mesh_State(&m);
432                 }
433                 c_alias_polys += mesh->num_triangles;
434                 R_Mesh_Draw(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
435         }
436 }
437
438 void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius)
439 {
440         int meshnum;
441         aliasmesh_t *mesh;
442         aliasskin_t *skin;
443         float projectdistance;
444         if (ent->effects & EF_ADDITIVE || ent->alpha < 1)
445                 return;
446         projectdistance = lightradius + ent->model->radius - sqrt(DotProduct(relativelightorigin, relativelightorigin));
447         if (projectdistance > 0.1)
448         {
449                 R_Mesh_Matrix(&ent->matrix);
450                 for (meshnum = 0, mesh = ent->model->aliasdata_meshes;meshnum < ent->model->aliasnum_meshes;meshnum++, mesh++)
451                 {
452                         skin = R_FetchAliasSkin(ent, mesh);
453                         if (skin->flags & ALIASSKIN_TRANSPARENT)
454                                 continue;
455                         R_Mesh_GetSpace(mesh->num_vertices * 2);
456                         R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, varray_vertex3f);
457                         R_Shadow_Volume(mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, mesh->data_neighbor3i, relativelightorigin, lightradius, projectdistance);
458                 }
459         }
460 }
461
462 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)
463 {
464         int c, meshnum, layernum;
465         float fog, ifog, lightcolor2[3];
466         vec3_t diff;
467         qbyte *bcolor;
468         aliasmesh_t *mesh;
469         aliaslayer_t *layer;
470         aliasskin_t *skin;
471
472         if (ent->effects & (EF_ADDITIVE | EF_FULLBRIGHT) || ent->alpha < 1)
473                 return;
474
475         R_Mesh_Matrix(&ent->matrix);
476
477         fog = 0;
478         if (fogenabled)
479         {
480                 VectorSubtract(ent->origin, r_origin, diff);
481                 fog = DotProduct(diff,diff);
482                 if (fog < 0.01f)
483                         fog = 0.01f;
484                 fog = exp(fogdensity/fog);
485                 if (fog > 1)
486                         fog = 1;
487                 if (fog < 0.01f)
488                         fog = 0;
489                 // fog method: darken, additive fog
490                 // 1. render model as normal, scaled by inverse of fog alpha (darkens it)
491                 // 2. render fog as additive
492         }
493         ifog = 1 - fog;
494
495         for (meshnum = 0, mesh = ent->model->aliasdata_meshes;meshnum < ent->model->aliasnum_meshes;meshnum++, mesh++)
496         {
497                 skin = R_FetchAliasSkin(ent, mesh);
498                 if (skin->flags & ALIASSKIN_TRANSPARENT)
499                         continue;
500                 expandaliasvert(mesh->num_vertices);
501                 R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_VERTEX, aliasvert_vertex3f);
502                 R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_SVECTOR, aliasvert_svector3f);
503                 R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_TVECTOR, aliasvert_tvector3f);
504                 R_Model_Alias_GetMesh_Array3f(ent, mesh, MODELARRAY_NORMAL, aliasvert_normal3f);
505                 for (layernum = 0, layer = skin->data_layers;layernum < skin->num_layers;layernum++, layer++)
506                 {
507                         if (!(layer->flags & (ALIASLAYER_DIFFUSE | ALIASLAYER_SPECULAR))
508                          || ((layer->flags & ALIASLAYER_NODRAW_IF_NOTCOLORMAPPED) && ent->colormap < 0)
509                          || ((layer->flags & ALIASLAYER_NODRAW_IF_COLORMAPPED) && ent->colormap >= 0))
510                                 continue;
511                         lightcolor2[0] = lightcolor[0] * ifog;
512                         lightcolor2[1] = lightcolor[1] * ifog;
513                         lightcolor2[2] = lightcolor[2] * ifog;
514                         if (layer->flags & ALIASLAYER_SPECULAR)
515                         {
516                                 c_alias_polys += mesh->num_triangles;
517                                 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);
518                         }
519                         else if (layer->flags & ALIASLAYER_DIFFUSE)
520                         {
521                                 if (layer->flags & ALIASLAYER_COLORMAP_PANTS)
522                                 {
523                                         // 128-224 are backwards ranges
524                                         c = (ent->colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12;
525                                         // fullbright passes were already taken care of, so skip them in realtime lighting passes
526                                         if (c >= 224)
527                                                 continue;
528                                         bcolor = (qbyte *) (&palette_complete[c]);
529                                         lightcolor2[0] *= bcolor[0] * (1.0f / 255.0f);
530                                         lightcolor2[1] *= bcolor[1] * (1.0f / 255.0f);
531                                         lightcolor2[2] *= bcolor[2] * (1.0f / 255.0f);
532                                 }
533                                 else if (layer->flags & ALIASLAYER_COLORMAP_SHIRT)
534                                 {
535                                         // 128-224 are backwards ranges
536                                         c = (ent->colormap & 0xF0);c += (c >= 128 && c < 224) ? 4 : 12;
537                                         // fullbright passes were already taken care of, so skip them in realtime lighting passes
538                                         if (c >= 224)
539                                                 continue;
540                                         bcolor = (qbyte *) (&palette_complete[c]);
541                                         lightcolor2[0] *= bcolor[0] * (1.0f / 255.0f);
542                                         lightcolor2[1] *= bcolor[1] * (1.0f / 255.0f);
543                                         lightcolor2[2] *= bcolor[2] * (1.0f / 255.0f);
544                                 }
545                                 c_alias_polys += mesh->num_triangles;
546                                 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);
547                         }
548                 }
549         }
550 }
551
552 int ZymoticLerpBones(int count, const zymbonematrix *bonebase, const frameblend_t *blend, const zymbone_t *bone)
553 {
554         int i;
555         float lerp1, lerp2, lerp3, lerp4;
556         zymbonematrix *out, rootmatrix, m;
557         const zymbonematrix *bone1, *bone2, *bone3, *bone4;
558
559         rootmatrix.m[0][0] = 1;
560         rootmatrix.m[0][1] = 0;
561         rootmatrix.m[0][2] = 0;
562         rootmatrix.m[0][3] = 0;
563         rootmatrix.m[1][0] = 0;
564         rootmatrix.m[1][1] = 1;
565         rootmatrix.m[1][2] = 0;
566         rootmatrix.m[1][3] = 0;
567         rootmatrix.m[2][0] = 0;
568         rootmatrix.m[2][1] = 0;
569         rootmatrix.m[2][2] = 1;
570         rootmatrix.m[2][3] = 0;
571
572         bone1 = bonebase + blend[0].frame * count;
573         lerp1 = blend[0].lerp;
574         if (blend[1].lerp)
575         {
576                 bone2 = bonebase + blend[1].frame * count;
577                 lerp2 = blend[1].lerp;
578                 if (blend[2].lerp)
579                 {
580                         bone3 = bonebase + blend[2].frame * count;
581                         lerp3 = blend[2].lerp;
582                         if (blend[3].lerp)
583                         {
584                                 // 4 poses
585                                 bone4 = bonebase + blend[3].frame * count;
586                                 lerp4 = blend[3].lerp;
587                                 for (i = 0, out = zymbonepose;i < count;i++, out++)
588                                 {
589                                         // interpolate matrices
590                                         m.m[0][0] = bone1->m[0][0] * lerp1 + bone2->m[0][0] * lerp2 + bone3->m[0][0] * lerp3 + bone4->m[0][0] * lerp4;
591                                         m.m[0][1] = bone1->m[0][1] * lerp1 + bone2->m[0][1] * lerp2 + bone3->m[0][1] * lerp3 + bone4->m[0][1] * lerp4;
592                                         m.m[0][2] = bone1->m[0][2] * lerp1 + bone2->m[0][2] * lerp2 + bone3->m[0][2] * lerp3 + bone4->m[0][2] * lerp4;
593                                         m.m[0][3] = bone1->m[0][3] * lerp1 + bone2->m[0][3] * lerp2 + bone3->m[0][3] * lerp3 + bone4->m[0][3] * lerp4;
594                                         m.m[1][0] = bone1->m[1][0] * lerp1 + bone2->m[1][0] * lerp2 + bone3->m[1][0] * lerp3 + bone4->m[1][0] * lerp4;
595                                         m.m[1][1] = bone1->m[1][1] * lerp1 + bone2->m[1][1] * lerp2 + bone3->m[1][1] * lerp3 + bone4->m[1][1] * lerp4;
596                                         m.m[1][2] = bone1->m[1][2] * lerp1 + bone2->m[1][2] * lerp2 + bone3->m[1][2] * lerp3 + bone4->m[1][2] * lerp4;
597                                         m.m[1][3] = bone1->m[1][3] * lerp1 + bone2->m[1][3] * lerp2 + bone3->m[1][3] * lerp3 + bone4->m[1][3] * lerp4;
598                                         m.m[2][0] = bone1->m[2][0] * lerp1 + bone2->m[2][0] * lerp2 + bone3->m[2][0] * lerp3 + bone4->m[2][0] * lerp4;
599                                         m.m[2][1] = bone1->m[2][1] * lerp1 + bone2->m[2][1] * lerp2 + bone3->m[2][1] * lerp3 + bone4->m[2][1] * lerp4;
600                                         m.m[2][2] = bone1->m[2][2] * lerp1 + bone2->m[2][2] * lerp2 + bone3->m[2][2] * lerp3 + bone4->m[2][2] * lerp4;
601                                         m.m[2][3] = bone1->m[2][3] * lerp1 + bone2->m[2][3] * lerp2 + bone3->m[2][3] * lerp3 + bone4->m[2][3] * lerp4;
602                                         if (bone->parent >= 0)
603                                                 R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &m.m[0][0], &out->m[0][0]);
604                                         else
605                                                 R_ConcatTransforms(&rootmatrix.m[0][0], &m.m[0][0], &out->m[0][0]);
606                                         bone1++;
607                                         bone2++;
608                                         bone3++;
609                                         bone4++;
610                                         bone++;
611                                 }
612                         }
613                         else
614                         {
615                                 // 3 poses
616                                 for (i = 0, out = zymbonepose;i < count;i++, out++)
617                                 {
618                                         // interpolate matrices
619                                         m.m[0][0] = bone1->m[0][0] * lerp1 + bone2->m[0][0] * lerp2 + bone3->m[0][0] * lerp3;
620                                         m.m[0][1] = bone1->m[0][1] * lerp1 + bone2->m[0][1] * lerp2 + bone3->m[0][1] * lerp3;
621                                         m.m[0][2] = bone1->m[0][2] * lerp1 + bone2->m[0][2] * lerp2 + bone3->m[0][2] * lerp3;
622                                         m.m[0][3] = bone1->m[0][3] * lerp1 + bone2->m[0][3] * lerp2 + bone3->m[0][3] * lerp3;
623                                         m.m[1][0] = bone1->m[1][0] * lerp1 + bone2->m[1][0] * lerp2 + bone3->m[1][0] * lerp3;
624                                         m.m[1][1] = bone1->m[1][1] * lerp1 + bone2->m[1][1] * lerp2 + bone3->m[1][1] * lerp3;
625                                         m.m[1][2] = bone1->m[1][2] * lerp1 + bone2->m[1][2] * lerp2 + bone3->m[1][2] * lerp3;
626                                         m.m[1][3] = bone1->m[1][3] * lerp1 + bone2->m[1][3] * lerp2 + bone3->m[1][3] * lerp3;
627                                         m.m[2][0] = bone1->m[2][0] * lerp1 + bone2->m[2][0] * lerp2 + bone3->m[2][0] * lerp3;
628                                         m.m[2][1] = bone1->m[2][1] * lerp1 + bone2->m[2][1] * lerp2 + bone3->m[2][1] * lerp3;
629                                         m.m[2][2] = bone1->m[2][2] * lerp1 + bone2->m[2][2] * lerp2 + bone3->m[2][2] * lerp3;
630                                         m.m[2][3] = bone1->m[2][3] * lerp1 + bone2->m[2][3] * lerp2 + bone3->m[2][3] * lerp3;
631                                         if (bone->parent >= 0)
632                                                 R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &m.m[0][0], &out->m[0][0]);
633                                         else
634                                                 R_ConcatTransforms(&rootmatrix.m[0][0], &m.m[0][0], &out->m[0][0]);
635                                         bone1++;
636                                         bone2++;
637                                         bone3++;
638                                         bone++;
639                                 }
640                         }
641                 }
642                 else
643                 {
644                         // 2 poses
645                         for (i = 0, out = zymbonepose;i < count;i++, out++)
646                         {
647                                 // interpolate matrices
648                                 m.m[0][0] = bone1->m[0][0] * lerp1 + bone2->m[0][0] * lerp2;
649                                 m.m[0][1] = bone1->m[0][1] * lerp1 + bone2->m[0][1] * lerp2;
650                                 m.m[0][2] = bone1->m[0][2] * lerp1 + bone2->m[0][2] * lerp2;
651                                 m.m[0][3] = bone1->m[0][3] * lerp1 + bone2->m[0][3] * lerp2;
652                                 m.m[1][0] = bone1->m[1][0] * lerp1 + bone2->m[1][0] * lerp2;
653                                 m.m[1][1] = bone1->m[1][1] * lerp1 + bone2->m[1][1] * lerp2;
654                                 m.m[1][2] = bone1->m[1][2] * lerp1 + bone2->m[1][2] * lerp2;
655                                 m.m[1][3] = bone1->m[1][3] * lerp1 + bone2->m[1][3] * lerp2;
656                                 m.m[2][0] = bone1->m[2][0] * lerp1 + bone2->m[2][0] * lerp2;
657                                 m.m[2][1] = bone1->m[2][1] * lerp1 + bone2->m[2][1] * lerp2;
658                                 m.m[2][2] = bone1->m[2][2] * lerp1 + bone2->m[2][2] * lerp2;
659                                 m.m[2][3] = bone1->m[2][3] * lerp1 + bone2->m[2][3] * lerp2;
660                                 if (bone->parent >= 0)
661                                         R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &m.m[0][0], &out->m[0][0]);
662                                 else
663                                         R_ConcatTransforms(&rootmatrix.m[0][0], &m.m[0][0], &out->m[0][0]);
664                                 bone1++;
665                                 bone2++;
666                                 bone++;
667                         }
668                 }
669         }
670         else
671         {
672                 // 1 pose
673                 if (lerp1 != 1)
674                 {
675                         // lerp != 1.0
676                         for (i = 0, out = zymbonepose;i < count;i++, out++)
677                         {
678                                 // interpolate matrices
679                                 m.m[0][0] = bone1->m[0][0] * lerp1;
680                                 m.m[0][1] = bone1->m[0][1] * lerp1;
681                                 m.m[0][2] = bone1->m[0][2] * lerp1;
682                                 m.m[0][3] = bone1->m[0][3] * lerp1;
683                                 m.m[1][0] = bone1->m[1][0] * lerp1;
684                                 m.m[1][1] = bone1->m[1][1] * lerp1;
685                                 m.m[1][2] = bone1->m[1][2] * lerp1;
686                                 m.m[1][3] = bone1->m[1][3] * lerp1;
687                                 m.m[2][0] = bone1->m[2][0] * lerp1;
688                                 m.m[2][1] = bone1->m[2][1] * lerp1;
689                                 m.m[2][2] = bone1->m[2][2] * lerp1;
690                                 m.m[2][3] = bone1->m[2][3] * lerp1;
691                                 if (bone->parent >= 0)
692                                         R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &m.m[0][0], &out->m[0][0]);
693                                 else
694                                         R_ConcatTransforms(&rootmatrix.m[0][0], &m.m[0][0], &out->m[0][0]);
695                                 bone1++;
696                                 bone++;
697                         }
698                 }
699                 else
700                 {
701                         // lerp == 1.0
702                         for (i = 0, out = zymbonepose;i < count;i++, out++)
703                         {
704                                 if (bone->parent >= 0)
705                                         R_ConcatTransforms(&zymbonepose[bone->parent].m[0][0], &bone1->m[0][0], &out->m[0][0]);
706                                 else
707                                         R_ConcatTransforms(&rootmatrix.m[0][0], &bone1->m[0][0], &out->m[0][0]);
708                                 bone1++;
709                                 bone++;
710                         }
711                 }
712         }
713         return true;
714 }
715
716 void ZymoticTransformVerts(int vertcount, float *vertex, int *bonecounts, zymvertex_t *vert)
717 {
718         int c;
719         float *out = vertex;
720         zymbonematrix *matrix;
721         while(vertcount--)
722         {
723                 c = *bonecounts++;
724                 // FIXME: validate bonecounts at load time (must be >= 1)
725                 // FIXME: need 4th component in origin, for how much of the translate to blend in
726                 if (c == 1)
727                 {
728                         matrix = &zymbonepose[vert->bonenum];
729                         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];
730                         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];
731                         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];
732                         vert++;
733                 }
734                 else
735                 {
736                         VectorClear(out);
737                         while(c--)
738                         {
739                                 matrix = &zymbonepose[vert->bonenum];
740                                 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];
741                                 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];
742                                 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];
743                                 vert++;
744                         }
745                 }
746                 out += 3;
747         }
748 }
749
750 void ZymoticCalcNormal3f(int vertcount, float *vertex3f, float *normal3f, int shadercount, int *renderlist)
751 {
752         int a, b, c, d;
753         float *out, v1[3], v2[3], normal[3], s;
754         int *u;
755         // clear normals
756         memset(normal3f, 0, sizeof(float) * vertcount * 3);
757         memset(aliasvertusage, 0, sizeof(int) * vertcount);
758         // parse render list and accumulate surface normals
759         while(shadercount--)
760         {
761                 d = *renderlist++;
762                 while (d--)
763                 {
764                         a = renderlist[0]*4;
765                         b = renderlist[1]*4;
766                         c = renderlist[2]*4;
767                         v1[0] = vertex3f[a+0] - vertex3f[b+0];
768                         v1[1] = vertex3f[a+1] - vertex3f[b+1];
769                         v1[2] = vertex3f[a+2] - vertex3f[b+2];
770                         v2[0] = vertex3f[c+0] - vertex3f[b+0];
771                         v2[1] = vertex3f[c+1] - vertex3f[b+1];
772                         v2[2] = vertex3f[c+2] - vertex3f[b+2];
773                         CrossProduct(v1, v2, normal);
774                         VectorNormalizeFast(normal);
775                         // add surface normal to vertices
776                         a = renderlist[0] * 3;
777                         normal3f[a+0] += normal[0];
778                         normal3f[a+1] += normal[1];
779                         normal3f[a+2] += normal[2];
780                         aliasvertusage[renderlist[0]]++;
781                         a = renderlist[1] * 3;
782                         normal3f[a+0] += normal[0];
783                         normal3f[a+1] += normal[1];
784                         normal3f[a+2] += normal[2];
785                         aliasvertusage[renderlist[1]]++;
786                         a = renderlist[2] * 3;
787                         normal3f[a+0] += normal[0];
788                         normal3f[a+1] += normal[1];
789                         normal3f[a+2] += normal[2];
790                         aliasvertusage[renderlist[2]]++;
791                         renderlist += 3;
792                 }
793         }
794         // FIXME: precalc this
795         // average surface normals
796         out = normal3f;
797         u = aliasvertusage;
798         while(vertcount--)
799         {
800                 if (*u > 1)
801                 {
802                         s = ixtable[*u];
803                         out[0] *= s;
804                         out[1] *= s;
805                         out[2] *= s;
806                 }
807                 u++;
808                 out += 3;
809         }
810 }
811
812 void R_DrawZymoticModelMeshCallback (const void *calldata1, int calldata2)
813 {
814         float fog, ifog, colorscale, ambientcolor4f[4];
815         vec3_t diff;
816         int i, *renderlist, *elements;
817         rtexture_t *texture;
818         rmeshstate_t mstate;
819         const entity_render_t *ent = calldata1;
820         int shadernum = calldata2;
821         int numverts, numtriangles;
822
823         R_Mesh_Matrix(&ent->matrix);
824
825         // find the vertex index list and texture
826         renderlist = ent->model->zymdata_renderlist;
827         for (i = 0;i < shadernum;i++)
828                 renderlist += renderlist[0] * 3 + 1;
829         texture = ent->model->zymdata_textures[shadernum];
830
831         numverts = ent->model->zymnum_verts;
832         numtriangles = *renderlist++;
833         elements = renderlist;
834
835         expandaliasvert(numverts);
836
837         fog = 0;
838         if (fogenabled)
839         {
840                 VectorSubtract(ent->origin, r_origin, diff);
841                 fog = DotProduct(diff,diff);
842                 if (fog < 0.01f)
843                         fog = 0.01f;
844                 fog = exp(fogdensity/fog);
845                 if (fog > 1)
846                         fog = 1;
847                 if (fog < 0.01f)
848                         fog = 0;
849                 // fog method: darken, additive fog
850                 // 1. render model as normal, scaled by inverse of fog alpha (darkens it)
851                 // 2. render fog as additive
852         }
853         ifog = 1 - fog;
854
855         memset(&mstate, 0, sizeof(mstate));
856         if (ent->effects & EF_ADDITIVE)
857         {
858                 mstate.blendfunc1 = GL_SRC_ALPHA;
859                 mstate.blendfunc2 = GL_ONE;
860         }
861         else if (ent->alpha != 1.0 || R_TextureHasAlpha(texture))
862         {
863                 mstate.blendfunc1 = GL_SRC_ALPHA;
864                 mstate.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
865         }
866         else
867         {
868                 mstate.blendfunc1 = GL_ONE;
869                 mstate.blendfunc2 = GL_ZERO;
870         }
871         colorscale = r_colorscale;
872         if (gl_combine.integer)
873         {
874                 mstate.texrgbscale[0] = 4;
875                 colorscale *= 0.25f;
876         }
877         mstate.tex[0] = R_GetTexture(texture);
878         R_Mesh_State(&mstate);
879         ZymoticLerpBones(ent->model->zymnum_bones, (zymbonematrix *) ent->model->zymdata_poses, ent->frameblend, ent->model->zymdata_bones);
880
881         R_Mesh_GetSpace(numverts);
882         ZymoticTransformVerts(numverts, varray_vertex3f, ent->model->zymdata_vertbonecounts, ent->model->zymdata_verts);
883         R_Mesh_CopyTexCoord2f(0, ent->model->zymdata_texcoords, ent->model->zymnum_verts);
884         ZymoticCalcNormal3f(numverts, varray_vertex3f, aliasvert_normal3f, ent->model->zymnum_shaders, ent->model->zymdata_renderlist);
885         if (R_LightModel(ambientcolor4f, ent, ifog * colorscale, ifog * colorscale, ifog * colorscale, ent->alpha, false))
886         {
887                 GL_UseColorArray();
888                 R_LightModel_CalcVertexColors(ambientcolor4f, numverts, varray_vertex3f, aliasvert_normal3f, varray_color4f);
889         }
890         else
891                 GL_Color(ambientcolor4f[0], ambientcolor4f[1], ambientcolor4f[2], ambientcolor4f[3]);
892         R_Mesh_Draw(numverts, numtriangles, elements);
893         c_alias_polys += numtriangles;
894
895         if (fog)
896         {
897                 memset(&mstate, 0, sizeof(mstate));
898                 mstate.blendfunc1 = GL_SRC_ALPHA;
899                 mstate.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
900                 // FIXME: need alpha mask for fogging...
901                 //mstate.tex[0] = R_GetTexture(texture);
902                 R_Mesh_State(&mstate);
903                 GL_Color(fogcolor[0] * r_colorscale, fogcolor[1] * r_colorscale, fogcolor[2] * r_colorscale, ent->alpha * fog);
904                 R_Mesh_GetSpace(numverts);
905                 ZymoticTransformVerts(numverts, varray_vertex3f, ent->model->zymdata_vertbonecounts, ent->model->zymdata_verts);
906                 R_Mesh_Draw(numverts, numtriangles, elements);
907                 c_alias_polys += numtriangles;
908         }
909 }
910
911 void R_Model_Zymotic_Draw(entity_render_t *ent)
912 {
913         int i;
914
915         if (ent->alpha < (1.0f / 64.0f))
916                 return; // basically completely transparent
917
918         c_models++;
919
920         for (i = 0;i < ent->model->zymnum_shaders;i++)
921         {
922                 if (ent->effects & EF_ADDITIVE || ent->alpha != 1.0 || R_TextureHasAlpha(ent->model->zymdata_textures[i]))
923                         R_MeshQueue_AddTransparent(ent->origin, R_DrawZymoticModelMeshCallback, ent, i);
924                 else
925                         R_DrawZymoticModelMeshCallback(ent, i);
926         }
927 }
928
929 void R_Model_Zymotic_DrawFakeShadow(entity_render_t *ent)
930 {
931         // FIXME
932 }
933
934 void R_Model_Zymotic_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor)
935 {
936         // FIXME
937 }
938
939 void R_Model_Zymotic_DrawOntoLight(entity_render_t *ent)
940 {
941         // FIXME
942 }
943