850e90dfe500f3ffd25fff7eacf110b2c8db8598
[xonotic/darkplaces.git] / gl_models.c
1
2 #include "quakedef.h"
3 #include "r_shadow.h"
4
5 static texture_t r_aliasnotexture;
6 static texture_t *R_FetchAliasSkin(const entity_render_t *ent, const aliasmesh_t *mesh)
7 {
8         model_t *model = ent->model;
9         if (model->numskins)
10         {
11                 int s = ent->skinnum;
12                 if ((unsigned int)s >= (unsigned int)model->numskins)
13                         s = 0;
14                 if (model->skinscenes[s].framecount > 1)
15                         s = model->skinscenes[s].firstframe + (unsigned int) (r_refdef.time * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
16                 else
17                         s = model->skinscenes[s].firstframe;
18                 if (s >= mesh->num_skins)
19                         s = 0;
20                 return mesh->data_skins + s;
21         }
22         else
23         {
24                 memset(&r_aliasnotexture, 0, sizeof(r_aliasnotexture));
25                 r_aliasnotexture.skin.base = r_texture_notexture;
26                 return &r_aliasnotexture;
27         }
28 }
29
30 static void R_DrawAliasModelCallback (const void *calldata1, int calldata2)
31 {
32         int c, fbbase, fbpants, fbshirt, doglow;
33         float tint[3], fog, ifog, colorscale, ambientcolor4f[4], diffusecolor[3], diffusenormal[3], colorbase[3], colorpants[3], colorshirt[3];
34         float *vertex3f, *normal3f;
35         vec3_t diff;
36         qbyte *bcolor;
37         rmeshstate_t m;
38         const entity_render_t *ent = calldata1;
39         aliasmesh_t *mesh = ent->model->alias.aliasdata_meshes + calldata2;
40         texture_t *texture;
41
42         R_Mesh_Matrix(&ent->matrix);
43
44         fog = 0;
45         if (fogenabled)
46         {
47                 VectorSubtract(ent->origin, r_vieworigin, diff);
48                 fog = DotProduct(diff,diff);
49                 if (fog < 0.01f)
50                         fog = 0.01f;
51                 fog = exp(fogdensity/fog);
52                 if (fog > 1)
53                         fog = 1;
54                 if (fog < 0.01f)
55                         fog = 0;
56                 // fog method: darken, additive fog
57                 // 1. render model as normal, scaled by inverse of fog alpha (darkens it)
58                 // 2. render fog as additive
59         }
60         ifog = 1 - fog;
61
62         VectorScale(ent->colormod, ifog, colorbase);
63         VectorClear(colorpants);
64         VectorClear(colorshirt);
65         fbbase = ent->effects & EF_FULLBRIGHT;
66         fbpants = fbbase;
67         fbshirt = fbbase;
68         if (ent->colormap >= 0)
69         {
70                 // 128-224 are backwards ranges
71                 c = (ent->colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12;
72                 if (c >= 224)
73                         fbpants = true;
74                 bcolor = (qbyte *) (&palette_complete[c]);
75                 colorpants[0] = colorbase[0] * bcolor[0] * (1.0f / 255.0f);
76                 colorpants[1] = colorbase[1] * bcolor[1] * (1.0f / 255.0f);
77                 colorpants[2] = colorbase[2] * bcolor[2] * (1.0f / 255.0f);
78                 // 128-224 are backwards ranges
79                 c = (ent->colormap & 0xF0);c += (c >= 128 && c < 224) ? 4 : 12;
80                 if (c >= 224)
81                         fbshirt = true;
82                 bcolor = (qbyte *) (&palette_complete[c]);
83                 colorshirt[0] = colorbase[0] * bcolor[0] * (1.0f / 255.0f);
84                 colorshirt[1] = colorbase[1] * bcolor[1] * (1.0f / 255.0f);
85                 colorshirt[2] = colorbase[2] * bcolor[2] * (1.0f / 255.0f);
86         }
87
88         texture = R_FetchAliasSkin(ent, mesh);
89
90         if ((ent->effects & EF_ADDITIVE))
91         {
92                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
93                 GL_DepthMask(false);
94         }
95         else if (texture->skin.fog || ent->alpha != 1.0)
96         {
97                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
98                 GL_DepthMask(false);
99         }
100         else
101         {
102                 GL_BlendFunc(GL_ONE, GL_ZERO);
103                 GL_DepthMask(true);
104         }
105         GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
106         colorscale = 1.0f;
107         if (ent->frameblend[0].frame == 0 && ent->frameblend[0].lerp == 1)
108         {
109                 vertex3f = mesh->data_basevertex3f;
110                 normal3f = mesh->data_basenormal3f;
111         }
112         else
113         {
114                 vertex3f = varray_vertex3f;
115                 Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, mesh, vertex3f);
116                 normal3f = NULL;
117         }
118
119         doglow = texture->skin.glow != NULL;
120
121         memset(&m, 0, sizeof(m));
122         m.pointer_vertex = vertex3f;
123         m.pointer_texcoord[0] = mesh->data_texcoord2f;
124         if (gl_combine.integer)
125         {
126                 colorscale *= 0.25f;
127                 m.texrgbscale[0] = 4;
128         }
129
130         m.tex[0] = R_GetTexture((ent->colormap >= 0 || !texture->skin.merged) ? texture->skin.base : texture->skin.merged);
131         VectorScale(colorbase, colorscale, tint);
132         m.pointer_color = NULL;
133         if (fbbase)
134                 GL_Color(tint[0], tint[1], tint[2], ent->alpha);
135         else if (R_LightModel(ambientcolor4f, diffusecolor, diffusenormal, ent, tint[0], tint[1], tint[2], ent->alpha, false))
136         {
137                 m.pointer_color = varray_color4f;
138                 if (normal3f == NULL)
139                 {
140                         normal3f = varray_normal3f;
141                         Mod_BuildNormals(0, mesh->num_vertices, mesh->num_triangles, vertex3f, mesh->data_element3i, normal3f);
142                 }
143                 R_LightModel_CalcVertexColors(ambientcolor4f, diffusecolor, diffusenormal, mesh->num_vertices, vertex3f, normal3f, varray_color4f);
144         }
145         else
146                 GL_Color(ambientcolor4f[0], ambientcolor4f[1], ambientcolor4f[2], ambientcolor4f[3]);
147         if (gl_combine.integer && doglow)
148         {
149                 doglow = false;
150                 m.tex[1] = R_GetTexture(texture->skin.glow);
151                 m.pointer_texcoord[1] = mesh->data_texcoord2f;
152                 m.texcombinergb[1] = GL_ADD;
153         }
154         R_Mesh_State(&m);
155         c_alias_polys += mesh->num_triangles;
156         GL_LockArrays(0, mesh->num_vertices);
157         R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
158         GL_LockArrays(0, 0);
159         m.tex[1] = 0;
160         m.pointer_texcoord[1] = NULL;
161         m.texcombinergb[1] = 0;
162
163         VectorScale(colorpants, colorscale, tint);
164         if (ent->colormap >= 0 && texture->skin.pants && VectorLength2(tint) >= 0.001)
165         {
166                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
167                 GL_DepthMask(false);
168                 m.tex[0] = R_GetTexture(texture->skin.pants);
169                 m.pointer_color = NULL;
170                 if (fbpants)
171                         GL_Color(tint[0], tint[1], tint[2], ent->alpha);
172                 else if (R_LightModel(ambientcolor4f, diffusecolor, diffusenormal, ent, tint[0], tint[1], tint[2], ent->alpha, false))
173                 {
174                         m.pointer_color = varray_color4f;
175                         if (normal3f == NULL)
176                         {
177                                 normal3f = varray_normal3f;
178                                 Mod_BuildNormals(0, mesh->num_vertices, mesh->num_triangles, vertex3f, mesh->data_element3i, normal3f);
179                         }
180                         R_LightModel_CalcVertexColors(ambientcolor4f, diffusecolor, diffusenormal, mesh->num_vertices, vertex3f, normal3f, varray_color4f);
181                 }
182                 else
183                         GL_Color(ambientcolor4f[0], ambientcolor4f[1], ambientcolor4f[2], ambientcolor4f[3]);
184                 R_Mesh_State(&m);
185                 c_alias_polys += mesh->num_triangles;
186                 GL_LockArrays(0, mesh->num_vertices);
187                 R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
188                 GL_LockArrays(0, 0);
189         }
190
191         VectorScale(colorshirt, colorscale, tint);
192         if (ent->colormap >= 0 && texture->skin.shirt && VectorLength2(tint) >= 0.001)
193         {
194                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
195                 GL_DepthMask(false);
196                 m.tex[0] = R_GetTexture(texture->skin.shirt);
197                 m.pointer_color = NULL;
198                 if (fbshirt)
199                         GL_Color(tint[0], tint[1], tint[2], ent->alpha);
200                 else if (R_LightModel(ambientcolor4f, diffusecolor, diffusenormal, ent, tint[0], tint[1], tint[2], ent->alpha, false))
201                 {
202                         m.pointer_color = varray_color4f;
203                         if (normal3f == NULL)
204                         {
205                                 normal3f = varray_normal3f;
206                                 Mod_BuildNormals(0, mesh->num_vertices, mesh->num_triangles, vertex3f, mesh->data_element3i, normal3f);
207                         }
208                         R_LightModel_CalcVertexColors(ambientcolor4f, diffusecolor, diffusenormal, mesh->num_vertices, vertex3f, normal3f, varray_color4f);
209                 }
210                 else
211                         GL_Color(ambientcolor4f[0], ambientcolor4f[1], ambientcolor4f[2], ambientcolor4f[3]);
212                 R_Mesh_State(&m);
213                 c_alias_polys += mesh->num_triangles;
214                 GL_LockArrays(0, mesh->num_vertices);
215                 R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
216                 GL_LockArrays(0, 0);
217         }
218
219         colorscale = 1;
220         m.texrgbscale[0] = 0;
221         m.pointer_color = NULL;
222
223         if (doglow)
224         {
225                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
226                 GL_DepthMask(false);
227                 m.tex[0] = R_GetTexture(texture->skin.glow);
228                 GL_Color(1, 1, 1, ent->alpha);
229                 R_Mesh_State(&m);
230                 c_alias_polys += mesh->num_triangles;
231                 GL_LockArrays(0, mesh->num_vertices);
232                 R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
233                 GL_LockArrays(0, 0);
234         }
235
236         if (fog > 0)
237         {
238                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
239                 GL_DepthMask(false);
240                 m.tex[0] = R_GetTexture(texture->skin.fog);
241                 GL_Color(fogcolor[0], fogcolor[1], fogcolor[2], fog * ent->alpha);
242                 R_Mesh_State(&m);
243                 c_alias_polys += mesh->num_triangles;
244                 GL_LockArrays(0, mesh->num_vertices);
245                 R_Mesh_Draw(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i);
246                 GL_LockArrays(0, 0);
247         }
248 }
249
250 void R_Model_Alias_Draw(entity_render_t *ent)
251 {
252         int meshnum;
253         aliasmesh_t *mesh;
254         if (ent->alpha < (1.0f / 64.0f))
255                 return; // basically completely transparent
256
257         c_models++;
258
259         for (meshnum = 0, mesh = ent->model->alias.aliasdata_meshes;meshnum < ent->model->alias.aliasnum_meshes;meshnum++, mesh++)
260         {
261                 if (ent->effects & EF_ADDITIVE || ent->alpha != 1.0 || R_FetchAliasSkin(ent, mesh)->skin.fog)
262                         R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawAliasModelCallback, ent, meshnum);
263                 else
264                         R_DrawAliasModelCallback(ent, meshnum);
265         }
266 }
267
268 void R_Model_Alias_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs)
269 {
270         int meshnum;
271         aliasmesh_t *mesh;
272         texture_t *texture;
273         float projectdistance, *vertex3f;
274         if (!(ent->flags & RENDER_SHADOW))
275                 return;
276         // check the box in modelspace, it was already checked in worldspace
277         if (!BoxesOverlap(ent->model->normalmins, ent->model->normalmaxs, lightmins, lightmaxs))
278                 return;
279         projectdistance = lightradius + ent->model->radius;// - sqrt(DotProduct(relativelightorigin, relativelightorigin));
280         if (projectdistance > 0.1)
281         {
282                 for (meshnum = 0, mesh = ent->model->alias.aliasdata_meshes;meshnum < ent->model->alias.aliasnum_meshes;meshnum++, mesh++)
283                 {
284                         texture = R_FetchAliasSkin(ent, mesh);
285                         if (texture->skin.fog)
286                                 continue;
287                         if (ent->frameblend[0].frame == 0 && ent->frameblend[0].lerp == 1)
288                                 vertex3f = mesh->data_basevertex3f;
289                         else
290                         {
291                                 vertex3f = varray_vertex3f;
292                                 Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, mesh, vertex3f);
293                         }
294                         // identify lit faces within the bounding box
295                         R_Shadow_PrepareShadowMark(mesh->num_triangles);
296                         R_Shadow_MarkVolumeFromBox(0, mesh->num_triangles, vertex3f, mesh->data_element3i, relativelightorigin, lightmins, lightmaxs, ent->model->normalmins, ent->model->normalmaxs);
297                         R_Shadow_VolumeFromList(mesh->num_vertices, mesh->num_triangles, vertex3f, mesh->data_element3i, mesh->data_neighbor3i, relativelightorigin, projectdistance, numshadowmark, shadowmarklist);
298                 }
299         }
300 }
301
302 void R_Model_Alias_DrawLight(entity_render_t *ent, float *lightcolor, int numsurfaces, const int *surfacelist)
303 {
304         int c, meshnum;
305         float fog, ifog, lightcolorbase[3], lightcolorpants[3], lightcolorshirt[3];
306         float *vertex3f, *svector3f, *tvector3f, *normal3f;
307         vec3_t diff;
308         qbyte *bcolor;
309         aliasmesh_t *mesh;
310         texture_t *texture;
311
312         fog = 0;
313         if (fogenabled)
314         {
315                 VectorSubtract(ent->origin, r_vieworigin, diff);
316                 fog = DotProduct(diff,diff);
317                 if (fog < 0.01f)
318                         fog = 0.01f;
319                 fog = exp(fogdensity/fog);
320                 if (fog > 1)
321                         fog = 1;
322                 if (fog < 0.01f)
323                         fog = 0;
324                 // fog method: darken, additive fog
325                 // 1. render model as normal, scaled by inverse of fog alpha (darkens it)
326                 // 2. render fog as additive
327         }
328         ifog = 1 - fog;
329
330         VectorScale(lightcolor, ifog, lightcolorbase);
331         if (VectorLength2(lightcolorbase) < 0.001)
332                 return;
333         VectorClear(lightcolorpants);
334         VectorClear(lightcolorshirt);
335         if (ent->colormap >= 0)
336         {
337                 // 128-224 are backwards ranges
338                 c = (ent->colormap & 0xF) << 4;c += (c >= 128 && c < 224) ? 4 : 12;
339                 // fullbright passes were already taken care of, so skip them in realtime lighting passes
340                 if (c < 224)
341                 {
342                         bcolor = (qbyte *) (&palette_complete[c]);
343                         lightcolorpants[0] = lightcolorbase[0] * bcolor[0] * (1.0f / 255.0f);
344                         lightcolorpants[1] = lightcolorbase[1] * bcolor[1] * (1.0f / 255.0f);
345                         lightcolorpants[2] = lightcolorbase[2] * bcolor[2] * (1.0f / 255.0f);
346                 }
347                 // 128-224 are backwards ranges
348                 c = (ent->colormap & 0xF0);c += (c >= 128 && c < 224) ? 4 : 12;
349                 // fullbright passes were already taken care of, so skip them in realtime lighting passes
350                 if (c < 224)
351                 {
352                         bcolor = (qbyte *) (&palette_complete[c]);
353                         lightcolorshirt[0] = lightcolorbase[0] * bcolor[0] * (1.0f / 255.0f);
354                         lightcolorshirt[1] = lightcolorbase[1] * bcolor[1] * (1.0f / 255.0f);
355                         lightcolorshirt[2] = lightcolorbase[2] * bcolor[2] * (1.0f / 255.0f);
356                 }
357         }
358
359         for (meshnum = 0, mesh = ent->model->alias.aliasdata_meshes;meshnum < ent->model->alias.aliasnum_meshes;meshnum++, mesh++)
360         {
361                 texture = R_FetchAliasSkin(ent, mesh);
362                 // FIXME: transparent skins need to be lit during the transparent render
363                 if (texture->skin.fog)
364                         continue;
365                 if (ent->frameblend[0].frame == 0 && ent->frameblend[0].lerp == 1)
366                 {
367                         vertex3f = mesh->data_basevertex3f;
368                         svector3f = mesh->data_basesvector3f;
369                         tvector3f = mesh->data_basetvector3f;
370                         normal3f = mesh->data_basenormal3f;
371                 }
372                 else
373                 {
374                         vertex3f = varray_vertex3f;
375                         svector3f = varray_svector3f;
376                         tvector3f = varray_tvector3f;
377                         normal3f = varray_normal3f;
378                         Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, mesh, vertex3f);
379                         Mod_BuildTextureVectorsAndNormals(0, mesh->num_vertices, mesh->num_triangles, vertex3f, mesh->data_texcoord2f, mesh->data_element3i, svector3f, tvector3f, normal3f);
380                 }
381                 c_alias_polys += mesh->num_triangles;
382                 R_Shadow_RenderLighting(0, mesh->num_vertices, mesh->num_triangles, mesh->data_element3i, vertex3f, svector3f, tvector3f, normal3f, mesh->data_texcoord2f, lightcolorbase, lightcolorpants, lightcolorshirt, (ent->colormap >= 0 || !texture->skin.merged) ? texture->skin.base : texture->skin.merged, ent->colormap >= 0 ? texture->skin.pants : 0, ent->colormap >= 0 ? texture->skin.shirt : 0, texture->skin.nmap, texture->skin.gloss);
383         }
384 }
385