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