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