]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rmain.c
Updated the embedded font to contain the 2 top rows of signs/chars/thingies. Also...
[divverent/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25
26 // used for dlight push checking and other things
27 int r_framecount;
28
29 mplane_t frustum[5];
30
31 matrix4x4_t r_identitymatrix;
32
33 int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights, c_meshs, c_meshelements, c_rt_lights, c_rt_clears, c_rt_scissored, c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris, c_rtcached_shadowmeshes, c_rtcached_shadowtris, c_bloom, c_bloomcopies, c_bloomcopypixels, c_bloomdraws, c_bloomdrawpixels;
34
35 // true during envmap command capture
36 qboolean envmap;
37
38 // maximum visible distance (recalculated from world box each frame)
39 float r_farclip;
40 // brightness of world lightmaps and related lighting
41 // (often reduced when world rtlights are enabled)
42 float r_lightmapintensity;
43 // whether to draw world lights realtime, dlights realtime, and their shadows
44 qboolean r_rtworld;
45 qboolean r_rtworldshadows;
46 qboolean r_rtdlight;
47 qboolean r_rtdlightshadows;
48
49
50 // forces all rendering to draw triangle outlines
51 int r_showtrispass;
52
53 // view origin
54 vec3_t r_vieworigin;
55 vec3_t r_viewforward;
56 vec3_t r_viewleft;
57 vec3_t r_viewright;
58 vec3_t r_viewup;
59 int r_view_x;
60 int r_view_y;
61 int r_view_z;
62 int r_view_width;
63 int r_view_height;
64 int r_view_depth;
65 float r_view_fov_x;
66 float r_view_fov_y;
67 matrix4x4_t r_view_matrix;
68
69 //
70 // screen size info
71 //
72 refdef_t r_refdef;
73
74 // 8.8 fraction of base light value
75 unsigned short d_lightstylevalue[256];
76
77 cvar_t r_showtris = {0, "r_showtris", "0"};
78 cvar_t r_drawentities = {0, "r_drawentities","1"};
79 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
80 cvar_t r_speeds = {0, "r_speeds","0"};
81 cvar_t r_fullbright = {0, "r_fullbright","0"};
82 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
83 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
84 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
85 cvar_t r_drawcollisionbrushes = {0, "r_drawcollisionbrushes", "0"};
86
87 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
88 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
89 cvar_t gl_fogred = {0, "gl_fogred","0.3"};
90 cvar_t gl_foggreen = {0, "gl_foggreen","0.3"};
91 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
92 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
93 cvar_t gl_fogend = {0, "gl_fogend","0"};
94
95 cvar_t r_textureunits = {0, "r_textureunits", "32"};
96
97 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1"};
98 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"};
99 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
100 cvar_t r_watershader = {CVAR_SAVE, "r_watershader", "1"};
101
102 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0"};
103 cvar_t r_bloom_intensity = {CVAR_SAVE, "r_bloom_intensity", "2"};
104 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "8"};
105 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320"};
106 cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "4"};
107
108 cvar_t developer_texturelogging = {0, "developer_texturelogging", "1"};
109
110 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0"};
111
112 rtexturepool_t *r_main_texturepool;
113 rtexture_t *r_bloom_texture_screen;
114 rtexture_t *r_bloom_texture_bloom;
115 rtexture_t *r_texture_blanknormalmap;
116 rtexture_t *r_texture_white;
117 rtexture_t *r_texture_black;
118 rtexture_t *r_texture_notexture;
119 rtexture_t *r_texture_whitecube;
120 rtexture_t *r_texture_normalizationcube;
121 rtexture_t *r_texture_detailtextures[NUM_DETAILTEXTURES];
122 rtexture_t *r_texture_distorttexture[64];
123
124 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
125 {
126         int i;
127         for (i = 0;i < verts;i++)
128         {
129                 out[0] = in[0] * r;
130                 out[1] = in[1] * g;
131                 out[2] = in[2] * b;
132                 out[3] = in[3];
133                 in += 4;
134                 out += 4;
135         }
136 }
137
138 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
139 {
140         int i;
141         for (i = 0;i < verts;i++)
142         {
143                 out[0] = r;
144                 out[1] = g;
145                 out[2] = b;
146                 out[3] = a;
147                 out += 4;
148         }
149 }
150
151 vec3_t fogcolor;
152 vec_t fogdensity;
153 float fog_density, fog_red, fog_green, fog_blue;
154 qboolean fogenabled;
155 qboolean oldgl_fogenable;
156 void R_UpdateFog(void)
157 {
158         if (gamemode == GAME_NEHAHRA)
159         {
160                 if (gl_fogenable.integer)
161                 {
162                         oldgl_fogenable = true;
163                         fog_density = gl_fogdensity.value;
164                         fog_red = gl_fogred.value;
165                         fog_green = gl_foggreen.value;
166                         fog_blue = gl_fogblue.value;
167                 }
168                 else if (oldgl_fogenable)
169                 {
170                         oldgl_fogenable = false;
171                         fog_density = 0;
172                         fog_red = 0;
173                         fog_green = 0;
174                         fog_blue = 0;
175                 }
176         }
177         if (fog_density)
178         {
179                 fogcolor[0] = fog_red   = bound(0.0f, fog_red  , 1.0f);
180                 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
181                 fogcolor[2] = fog_blue  = bound(0.0f, fog_blue , 1.0f);
182         }
183         if (fog_density)
184         {
185                 fogenabled = true;
186                 fogdensity = -4000.0f / (fog_density * fog_density);
187                 // fog color was already set
188         }
189         else
190                 fogenabled = false;
191 }
192
193 // FIXME: move this to client?
194 void FOG_clear(void)
195 {
196         if (gamemode == GAME_NEHAHRA)
197         {
198                 Cvar_Set("gl_fogenable", "0");
199                 Cvar_Set("gl_fogdensity", "0.2");
200                 Cvar_Set("gl_fogred", "0.3");
201                 Cvar_Set("gl_foggreen", "0.3");
202                 Cvar_Set("gl_fogblue", "0.3");
203         }
204         fog_density = fog_red = fog_green = fog_blue = 0.0f;
205 }
206
207 // FIXME: move this to client?
208 void FOG_registercvars(void)
209 {
210         if (gamemode == GAME_NEHAHRA)
211         {
212                 Cvar_RegisterVariable (&gl_fogenable);
213                 Cvar_RegisterVariable (&gl_fogdensity);
214                 Cvar_RegisterVariable (&gl_fogred);
215                 Cvar_RegisterVariable (&gl_foggreen);
216                 Cvar_RegisterVariable (&gl_fogblue);
217                 Cvar_RegisterVariable (&gl_fogstart);
218                 Cvar_RegisterVariable (&gl_fogend);
219         }
220 }
221
222 static void R_BuildDetailTextures (void)
223 {
224         int i, x, y, light;
225         float vc[3], vx[3], vy[3], vn[3], lightdir[3];
226 #define DETAILRESOLUTION 256
227         qbyte (*data)[DETAILRESOLUTION][4];
228         qbyte (*noise)[DETAILRESOLUTION];
229
230         // Allocate the buffers dynamically to avoid having such big guys on the stack
231         data = Mem_Alloc(tempmempool, DETAILRESOLUTION * sizeof(*data));
232         noise = Mem_Alloc(tempmempool, DETAILRESOLUTION * sizeof(*noise));
233
234         lightdir[0] = 0.5;
235         lightdir[1] = 1;
236         lightdir[2] = -0.25;
237         VectorNormalize(lightdir);
238         for (i = 0;i < NUM_DETAILTEXTURES;i++)
239         {
240                 fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4);
241                 for (y = 0;y < DETAILRESOLUTION;y++)
242                 {
243                         for (x = 0;x < DETAILRESOLUTION;x++)
244                         {
245                                 vc[0] = x;
246                                 vc[1] = y;
247                                 vc[2] = noise[y][x] * (1.0f / 32.0f);
248                                 vx[0] = x + 1;
249                                 vx[1] = y;
250                                 vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f);
251                                 vy[0] = x;
252                                 vy[1] = y + 1;
253                                 vy[2] = noise[(y + 1) % DETAILRESOLUTION][x] * (1.0f / 32.0f);
254                                 VectorSubtract(vx, vc, vx);
255                                 VectorSubtract(vy, vc, vy);
256                                 CrossProduct(vx, vy, vn);
257                                 VectorNormalize(vn);
258                                 light = 128 - DotProduct(vn, lightdir) * 128;
259                                 light = bound(0, light, 255);
260                                 data[y][x][0] = data[y][x][1] = data[y][x][2] = light;
261                                 data[y][x][3] = 255;
262                         }
263                 }
264                 r_texture_detailtextures[i] = R_LoadTexture2D(r_main_texturepool, va("detailtexture%i", i), DETAILRESOLUTION, DETAILRESOLUTION, &data[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_PRECACHE, NULL);
265         }
266
267         Mem_Free(noise);
268         Mem_Free(data);
269 }
270
271 static qbyte R_MorphDistortTexture (double y0, double y1, double y2, double y3, double morph)
272 {
273         int m = (int)(((y1 + y3 - (y0 + y2)) * morph * morph * morph) +
274                         ((2 * (y0 - y1) + y2 - y3) * morph * morph) +
275                         ((y2 - y0) * morph) +
276                         (y1));
277         return (qbyte)bound(0, m, 255);
278 }
279
280 static void R_BuildDistortTexture (void)
281 {
282         int x, y, i, j;
283 #define DISTORTRESOLUTION 32
284         qbyte data[5][DISTORTRESOLUTION][DISTORTRESOLUTION][2];
285
286         for (i=0; i<4; i++)
287         {
288                 for (y=0; y<DISTORTRESOLUTION; y++)
289                 {
290                         for (x=0; x<DISTORTRESOLUTION; x++)
291                         {
292                                 data[i][y][x][0] = rand () & 255;
293                                 data[i][y][x][1] = rand () & 255;
294                         }
295                 }
296         }
297
298         for (i=0; i<4; i++)
299         {
300                 for (j=0; j<16; j++)
301                 {
302                         r_texture_distorttexture[i*16+j] = NULL;
303                         if (gl_textureshader)
304                         {
305                                 for (y=0; y<DISTORTRESOLUTION; y++)
306                                 {
307                                         for (x=0; x<DISTORTRESOLUTION; x++)
308                                         {
309                                                 data[4][y][x][0] = R_MorphDistortTexture (data[(i-1)&3][y][x][0], data[i][y][x][0], data[(i+1)&3][y][x][0], data[(i+2)&3][y][x][0], 0.0625*j);
310                                                 data[4][y][x][1] = R_MorphDistortTexture (data[(i-1)&3][y][x][1], data[i][y][x][1], data[(i+1)&3][y][x][1], data[(i+2)&3][y][x][1], 0.0625*j);
311                                         }
312                                 }
313                                 r_texture_distorttexture[i*16+j] = R_LoadTexture2D(r_main_texturepool, va("distorttexture%i", i*16+j), DISTORTRESOLUTION, DISTORTRESOLUTION, &data[4][0][0][0], TEXTYPE_DSDT, TEXF_PRECACHE, NULL);
314                         }
315                 }
316         }
317 }
318
319 static void R_BuildBlankTextures(void)
320 {
321         qbyte data[4];
322         data[0] = 128; // normal X
323         data[1] = 128; // normal Y
324         data[2] = 255; // normal Z
325         data[3] = 128; // height
326         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
327         data[0] = 255;
328         data[1] = 255;
329         data[2] = 255;
330         data[3] = 255;
331         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
332         data[0] = 0;
333         data[1] = 0;
334         data[2] = 0;
335         data[3] = 255;
336         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
337 }
338
339 static void R_BuildNoTexture(void)
340 {
341         int x, y;
342         qbyte pix[16][16][4];
343         // this makes a light grey/dark grey checkerboard texture
344         for (y = 0;y < 16;y++)
345         {
346                 for (x = 0;x < 16;x++)
347                 {
348                         if ((y < 8) ^ (x < 8))
349                         {
350                                 pix[y][x][0] = 128;
351                                 pix[y][x][1] = 128;
352                                 pix[y][x][2] = 128;
353                                 pix[y][x][3] = 255;
354                         }
355                         else
356                         {
357                                 pix[y][x][0] = 64;
358                                 pix[y][x][1] = 64;
359                                 pix[y][x][2] = 64;
360                                 pix[y][x][3] = 255;
361                         }
362                 }
363         }
364         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
365 }
366
367 static void R_BuildWhiteCube(void)
368 {
369         qbyte data[6*1*1*4];
370         data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
371         data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
372         data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
373         data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
374         data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
375         data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
376         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
377 }
378
379 static void R_BuildNormalizationCube(void)
380 {
381         int x, y, side;
382         vec3_t v;
383         vec_t s, t, intensity;
384 #define NORMSIZE 64
385         qbyte data[6][NORMSIZE][NORMSIZE][4];
386         for (side = 0;side < 6;side++)
387         {
388                 for (y = 0;y < NORMSIZE;y++)
389                 {
390                         for (x = 0;x < NORMSIZE;x++)
391                         {
392                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
393                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
394                                 switch(side)
395                                 {
396                                 case 0:
397                                         v[0] = 1;
398                                         v[1] = -t;
399                                         v[2] = -s;
400                                         break;
401                                 case 1:
402                                         v[0] = -1;
403                                         v[1] = -t;
404                                         v[2] = s;
405                                         break;
406                                 case 2:
407                                         v[0] = s;
408                                         v[1] = 1;
409                                         v[2] = t;
410                                         break;
411                                 case 3:
412                                         v[0] = s;
413                                         v[1] = -1;
414                                         v[2] = -t;
415                                         break;
416                                 case 4:
417                                         v[0] = s;
418                                         v[1] = -t;
419                                         v[2] = 1;
420                                         break;
421                                 case 5:
422                                         v[0] = -s;
423                                         v[1] = -t;
424                                         v[2] = -1;
425                                         break;
426                                 }
427                                 intensity = 127.0f / sqrt(DotProduct(v, v));
428                                 data[side][y][x][0] = 128.0f + intensity * v[0];
429                                 data[side][y][x][1] = 128.0f + intensity * v[1];
430                                 data[side][y][x][2] = 128.0f + intensity * v[2];
431                                 data[side][y][x][3] = 255;
432                         }
433                 }
434         }
435         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
436 }
437
438 void gl_main_start(void)
439 {
440         r_main_texturepool = R_AllocTexturePool();
441         r_bloom_texture_screen = NULL;
442         r_bloom_texture_bloom = NULL;
443         R_BuildBlankTextures();
444         R_BuildNoTexture();
445         R_BuildDetailTextures();
446         R_BuildDistortTexture();
447         if (gl_texturecubemap)
448         {
449                 R_BuildWhiteCube();
450                 R_BuildNormalizationCube();
451         }
452 }
453
454 void gl_main_shutdown(void)
455 {
456         R_FreeTexturePool(&r_main_texturepool);
457         r_bloom_texture_screen = NULL;
458         r_bloom_texture_bloom = NULL;
459         r_texture_blanknormalmap = NULL;
460         r_texture_white = NULL;
461         r_texture_black = NULL;
462         r_texture_whitecube = NULL;
463         r_texture_normalizationcube = NULL;
464 }
465
466 extern void CL_ParseEntityLump(char *entitystring);
467 void gl_main_newmap(void)
468 {
469         // FIXME: move this code to client
470         int l;
471         char *entities, entname[MAX_QPATH];
472         r_framecount = 1;
473         if (cl.worldmodel)
474         {
475                 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
476                 l = strlen(entname) - 4;
477                 if (l >= 0 && !strcmp(entname + l, ".bsp"))
478                 {
479                         strcpy(entname + l, ".ent");
480                         if ((entities = FS_LoadFile(entname, tempmempool, true)))
481                         {
482                                 CL_ParseEntityLump(entities);
483                                 Mem_Free(entities);
484                                 return;
485                         }
486                 }
487                 if (cl.worldmodel->brush.entities)
488                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
489         }
490 }
491
492 void GL_Main_Init(void)
493 {
494         Matrix4x4_CreateIdentity(&r_identitymatrix);
495 // FIXME: move this to client?
496         FOG_registercvars();
497         Cvar_RegisterVariable(&r_showtris);
498         Cvar_RegisterVariable(&r_drawentities);
499         Cvar_RegisterVariable(&r_drawviewmodel);
500         Cvar_RegisterVariable(&r_speeds);
501         Cvar_RegisterVariable(&r_fullbrights);
502         Cvar_RegisterVariable(&r_wateralpha);
503         Cvar_RegisterVariable(&r_dynamic);
504         Cvar_RegisterVariable(&r_fullbright);
505         Cvar_RegisterVariable(&r_textureunits);
506         Cvar_RegisterVariable(&r_lerpsprites);
507         Cvar_RegisterVariable(&r_lerpmodels);
508         Cvar_RegisterVariable(&r_waterscroll);
509         Cvar_RegisterVariable(&r_watershader);
510         Cvar_RegisterVariable(&r_drawcollisionbrushes);
511         Cvar_RegisterVariable(&r_bloom);
512         Cvar_RegisterVariable(&r_bloom_intensity);
513         Cvar_RegisterVariable(&r_bloom_blur);
514         Cvar_RegisterVariable(&r_bloom_resolution);
515         Cvar_RegisterVariable(&r_bloom_power);
516         Cvar_RegisterVariable(&developer_texturelogging);
517         Cvar_RegisterVariable(&gl_lightmaps);
518         if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
519                 Cvar_SetValue("r_fullbrights", 0);
520         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
521 }
522
523 static vec3_t r_farclip_origin;
524 static vec3_t r_farclip_direction;
525 static vec_t r_farclip_directiondist;
526 static vec_t r_farclip_meshfarclip;
527 static int r_farclip_directionbit0;
528 static int r_farclip_directionbit1;
529 static int r_farclip_directionbit2;
530
531 // enlarge farclip to accomodate box
532 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
533 {
534         float d;
535         d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
536           + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
537           + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
538         if (r_farclip_meshfarclip < d)
539                 r_farclip_meshfarclip = d;
540 }
541
542 // return farclip value
543 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
544 {
545         int i;
546
547         VectorCopy(origin, r_farclip_origin);
548         VectorCopy(direction, r_farclip_direction);
549         r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
550         r_farclip_directionbit0 = r_farclip_direction[0] < 0;
551         r_farclip_directionbit1 = r_farclip_direction[1] < 0;
552         r_farclip_directionbit2 = r_farclip_direction[2] < 0;
553         r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
554
555         if (r_refdef.worldmodel)
556                 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
557         for (i = 0;i < r_refdef.numentities;i++)
558                 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
559
560         return r_farclip_meshfarclip - r_farclip_directiondist;
561 }
562
563 extern void R_Textures_Init(void);
564 extern void GL_Draw_Init(void);
565 extern void GL_Main_Init(void);
566 extern void R_Shadow_Init(void);
567 extern void R_Sky_Init(void);
568 extern void GL_Surf_Init(void);
569 extern void R_Crosshairs_Init(void);
570 extern void R_Light_Init(void);
571 extern void R_Particles_Init(void);
572 extern void R_Explosion_Init(void);
573 extern void gl_backend_init(void);
574 extern void Sbar_Init(void);
575 extern void R_LightningBeams_Init(void);
576 extern void Mod_RenderInit(void);
577
578 void Render_Init(void)
579 {
580         gl_backend_init();
581         R_Textures_Init();
582         Mod_RenderInit();
583         R_MeshQueue_Init();
584         GL_Main_Init();
585         GL_Draw_Init();
586         R_Shadow_Init();
587         R_Sky_Init();
588         GL_Surf_Init();
589         R_Crosshairs_Init();
590         R_Light_Init();
591         R_Particles_Init();
592         R_Explosion_Init();
593         UI_Init();
594         Sbar_Init();
595         R_LightningBeams_Init();
596 }
597
598 /*
599 ===============
600 GL_Init
601 ===============
602 */
603 extern char *ENGINE_EXTENSIONS;
604 void GL_Init (void)
605 {
606         VID_CheckExtensions();
607
608         // LordHavoc: report supported extensions
609         Con_DPrintf("\nengine extensions: %s\n", vm_sv_extensions );
610
611         // clear to black (loading plaque will be seen over this)
612         qglClearColor(0,0,0,1);
613         qglClear(GL_COLOR_BUFFER_BIT);
614 }
615
616 int R_CullBox(const vec3_t mins, const vec3_t maxs)
617 {
618         int i;
619         mplane_t *p;
620         for (i = 0;i < 4;i++)
621         {
622                 p = frustum + i;
623                 switch(p->signbits)
624                 {
625                 default:
626                 case 0:
627                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
628                                 return true;
629                         break;
630                 case 1:
631                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
632                                 return true;
633                         break;
634                 case 2:
635                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
636                                 return true;
637                         break;
638                 case 3:
639                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
640                                 return true;
641                         break;
642                 case 4:
643                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
644                                 return true;
645                         break;
646                 case 5:
647                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
648                                 return true;
649                         break;
650                 case 6:
651                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
652                                 return true;
653                         break;
654                 case 7:
655                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
656                                 return true;
657                         break;
658                 }
659         }
660         return false;
661 }
662
663 //==================================================================================
664
665 static void R_MarkEntities (void)
666 {
667         int i, renderimask;
668         entity_render_t *ent;
669
670         if (!r_drawentities.integer)
671                 return;
672
673         r_refdef.worldentity->visframe = r_framecount;
674         renderimask = envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
675         if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
676         {
677                 // worldmodel can check visibility
678                 for (i = 0;i < r_refdef.numentities;i++)
679                 {
680                         ent = r_refdef.entities[i];
681                         Mod_CheckLoaded(ent->model);
682                         // some of the renderer still relies on origin...
683                         Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
684                         // some of the renderer still relies on scale...
685                         ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
686                         if (!(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && ((ent->effects & EF_NODEPTHTEST) || r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.worldmodel, r_worldleafvisible, ent->mins, ent->maxs)))
687                         {
688                                 R_UpdateEntLights(ent);
689                                 ent->visframe = r_framecount;
690                         }
691                 }
692         }
693         else
694         {
695                 // no worldmodel or it can't check visibility
696                 for (i = 0;i < r_refdef.numentities;i++)
697                 {
698                         ent = r_refdef.entities[i];
699                         Mod_CheckLoaded(ent->model);
700                         // some of the renderer still relies on origin...
701                         Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
702                         // some of the renderer still relies on scale...
703                         ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
704                         if (!(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && (ent->effects & EF_NODEPTHTEST))
705                         {
706                                 R_UpdateEntLights(ent);
707                                 ent->visframe = r_framecount;
708                         }
709                 }
710         }
711 }
712
713 // only used if skyrendermasked, and normally returns false
714 int R_DrawBrushModelsSky (void)
715 {
716         int i, sky;
717         entity_render_t *ent;
718
719         if (!r_drawentities.integer)
720                 return false;
721
722         sky = false;
723         for (i = 0;i < r_refdef.numentities;i++)
724         {
725                 ent = r_refdef.entities[i];
726                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
727                 {
728                         ent->model->DrawSky(ent);
729                         sky = true;
730                 }
731         }
732         return sky;
733 }
734
735 void R_DrawNoModel(entity_render_t *ent);
736 void R_DrawModels(void)
737 {
738         int i;
739         entity_render_t *ent;
740
741         if (!r_drawentities.integer)
742                 return;
743
744         for (i = 0;i < r_refdef.numentities;i++)
745         {
746                 ent = r_refdef.entities[i];
747                 if (ent->visframe == r_framecount)
748                 {
749                         if (ent->model && ent->model->Draw != NULL)
750                                 ent->model->Draw(ent);
751                         else
752                                 R_DrawNoModel(ent);
753                 }
754         }
755 }
756
757 static void R_SetFrustum(void)
758 {
759         // break apart the view matrix into vectors for various purposes
760         Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
761         VectorNegate(r_viewleft, r_viewright);
762
763         // LordHavoc: note to all quake engine coders, the special case for 90
764         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
765         // disabled as well.
766
767         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
768         RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
769         frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
770         PlaneClassify(&frustum[0]);
771
772         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
773         RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
774         frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
775         PlaneClassify(&frustum[1]);
776
777         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
778         RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
779         frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
780         PlaneClassify(&frustum[2]);
781
782         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
783         RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
784         frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
785         PlaneClassify(&frustum[3]);
786
787         // nearclip plane
788         VectorCopy(r_viewforward, frustum[4].normal);
789         frustum[4].dist = DotProduct (r_vieworigin, frustum[4].normal) + 1.0f;
790         PlaneClassify(&frustum[4]);
791 }
792
793 static void R_BlendView(void)
794 {
795         rmeshstate_t m;
796
797         if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
798                 return;
799
800         GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
801         GL_DepthMask(true);
802         GL_DepthTest(false);
803         R_Mesh_Matrix(&r_identitymatrix);
804         // vertex coordinates for a quad that covers the screen exactly
805         varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
806         varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
807         varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
808         varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
809         if (r_bloom.integer && r_bloom_resolution.value >= 32 && r_bloom_power.integer >= 1 && r_bloom_power.integer < 100 && r_bloom_blur.value >= 0 && r_bloom_blur.value < 512)
810         {
811                 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
812                 float xoffset, yoffset, r;
813                 c_bloom++;
814                 // set the (poorly named) screenwidth and screenheight variables to
815                 // a power of 2 at least as large as the screen, these will define the
816                 // size of the texture to allocate
817                 for (screenwidth = 1;screenwidth < vid.width;screenwidth *= 2);
818                 for (screenheight = 1;screenheight < vid.height;screenheight *= 2);
819                 // allocate textures as needed
820                 if (!r_bloom_texture_screen)
821                         r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
822                 if (!r_bloom_texture_bloom)
823                         r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
824                 // set bloomwidth and bloomheight to the bloom resolution that will be
825                 // used (often less than the screen resolution for faster rendering)
826                 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
827                 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
828                 // set up a texcoord array for the full resolution screen image
829                 // (we have to keep this around to copy back during final render)
830                 varray_texcoord2f[0][0] = 0;
831                 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
832                 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
833                 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
834                 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
835                 varray_texcoord2f[0][5] = 0;
836                 varray_texcoord2f[0][6] = 0;
837                 varray_texcoord2f[0][7] = 0;
838                 // set up a texcoord array for the reduced resolution bloom image
839                 // (which will be additive blended over the screen image)
840                 varray_texcoord2f[1][0] = 0;
841                 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
842                 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
843                 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
844                 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
845                 varray_texcoord2f[1][5] = 0;
846                 varray_texcoord2f[1][6] = 0;
847                 varray_texcoord2f[1][7] = 0;
848                 memset(&m, 0, sizeof(m));
849                 m.pointer_vertex = varray_vertex3f;
850                 m.pointer_texcoord[0] = varray_texcoord2f[0];
851                 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
852                 R_Mesh_State(&m);
853                 // copy view into the full resolution screen image texture
854                 GL_ActiveTexture(0);
855                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.height - (r_view_y + r_view_height), r_view_width, r_view_height);
856                 c_bloomcopies++;
857                 c_bloomcopypixels += r_view_width * r_view_height;
858                 // now scale it down to the bloom size and raise to a power of itself
859                 // to darken it (this leaves the really bright stuff bright, and
860                 // everything else becomes very dark)
861                 // TODO: optimize with multitexture or GLSL
862                 qglViewport(r_view_x, vid.height - (r_view_y + bloomheight), bloomwidth, bloomheight);
863                 GL_BlendFunc(GL_ONE, GL_ZERO);
864                 GL_Color(1, 1, 1, 1);
865                 R_Mesh_Draw(0, 4, 2, polygonelements);
866                 c_bloomdraws++;
867                 c_bloomdrawpixels += bloomwidth * bloomheight;
868                 // render multiple times with a multiply blendfunc to raise to a power
869                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
870                 for (x = 1;x < r_bloom_power.integer;x++)
871                 {
872                         R_Mesh_Draw(0, 4, 2, polygonelements);
873                         c_bloomdraws++;
874                         c_bloomdrawpixels += bloomwidth * bloomheight;
875                 }
876                 // we now have a darkened bloom image in the framebuffer, copy it into
877                 // the bloom image texture for more processing
878                 memset(&m, 0, sizeof(m));
879                 m.pointer_vertex = varray_vertex3f;
880                 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
881                 m.pointer_texcoord[0] = varray_texcoord2f[2];
882                 R_Mesh_State(&m);
883                 GL_ActiveTexture(0);
884                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.height - (r_view_y + bloomheight), bloomwidth, bloomheight);
885                 c_bloomcopies++;
886                 c_bloomcopypixels += bloomwidth * bloomheight;
887                 // blend on at multiple vertical offsets to achieve a vertical blur
888                 // TODO: do offset blends using GLSL
889                 range = r_bloom_blur.integer * bloomwidth / 320;
890                 GL_BlendFunc(GL_ONE, GL_ZERO);
891                 for (x = -range;x <= range;x++)
892                 {
893                         xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
894                         yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
895                         // compute a texcoord array with the specified x and y offset
896                         varray_texcoord2f[2][0] = xoffset+0;
897                         varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
898                         varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
899                         varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
900                         varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
901                         varray_texcoord2f[2][5] = yoffset+0;
902                         varray_texcoord2f[2][6] = xoffset+0;
903                         varray_texcoord2f[2][7] = yoffset+0;
904                         // this r value looks like a 'dot' particle, fading sharply to
905                         // black at the edges
906                         // (probably not realistic but looks good enough)
907                         r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
908                         if (r < 0.01f)
909                                 continue;
910                         GL_Color(r, r, r, 1);
911                         R_Mesh_Draw(0, 4, 2, polygonelements);
912                         c_bloomdraws++;
913                         c_bloomdrawpixels += bloomwidth * bloomheight;
914                         GL_BlendFunc(GL_ONE, GL_ONE);
915                 }
916                 // copy the vertically blurred bloom view to a texture
917                 GL_ActiveTexture(0);
918                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.height - (r_view_y + bloomheight), bloomwidth, bloomheight);
919                 c_bloomcopies++;
920                 c_bloomcopypixels += bloomwidth * bloomheight;
921                 // blend the vertically blurred image at multiple offsets horizontally
922                 // to finish the blur effect
923                 // TODO: do offset blends using GLSL
924                 range = r_bloom_blur.integer * bloomwidth / 320;
925                 GL_BlendFunc(GL_ONE, GL_ZERO);
926                 for (x = -range;x <= range;x++)
927                 {
928                         xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
929                         yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
930                         // compute a texcoord array with the specified x and y offset
931                         varray_texcoord2f[2][0] = xoffset+0;
932                         varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
933                         varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
934                         varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
935                         varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
936                         varray_texcoord2f[2][5] = yoffset+0;
937                         varray_texcoord2f[2][6] = xoffset+0;
938                         varray_texcoord2f[2][7] = yoffset+0;
939                         // this r value looks like a 'dot' particle, fading sharply to
940                         // black at the edges
941                         // (probably not realistic but looks good enough)
942                         r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
943                         if (r < 0.01f)
944                                 continue;
945                         GL_Color(r, r, r, 1);
946                         R_Mesh_Draw(0, 4, 2, polygonelements);
947                         c_bloomdraws++;
948                         c_bloomdrawpixels += bloomwidth * bloomheight;
949                         GL_BlendFunc(GL_ONE, GL_ONE);
950                 }
951                 // copy the blurred bloom view to a texture
952                 GL_ActiveTexture(0);
953                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.height - (r_view_y + bloomheight), bloomwidth, bloomheight);
954                 c_bloomcopies++;
955                 c_bloomcopypixels += bloomwidth * bloomheight;
956                 // go back to full view area
957                 qglViewport(r_view_x, vid.height - (r_view_y + r_view_height), r_view_width, r_view_height);
958                 // put the original screen image back in place and blend the bloom
959                 // texture on it
960                 memset(&m, 0, sizeof(m));
961                 m.pointer_vertex = varray_vertex3f;
962                 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
963                 m.pointer_texcoord[0] = varray_texcoord2f[0];
964 #if 0
965                 dobloomblend = false;
966 #else
967                 // do both in one pass if possible
968                 if (r_textureunits.integer >= 2 && gl_combine.integer)
969                 {
970                         dobloomblend = false;
971                         m.texcombinergb[1] = GL_ADD;
972                         m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
973                         m.pointer_texcoord[1] = varray_texcoord2f[1];
974                 }
975                 else
976                         dobloomblend = true;
977 #endif
978                 R_Mesh_State(&m);
979                 GL_BlendFunc(GL_ONE, GL_ZERO);
980                 GL_Color(1,1,1,1);
981                 R_Mesh_Draw(0, 4, 2, polygonelements);
982                 c_bloomdraws++;
983                 c_bloomdrawpixels += r_view_width * r_view_height;
984                 // now blend on the bloom texture if multipass
985                 if (dobloomblend)
986                 {
987                         memset(&m, 0, sizeof(m));
988                         m.pointer_vertex = varray_vertex3f;
989                         m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
990                         m.pointer_texcoord[0] = varray_texcoord2f[1];
991                         R_Mesh_State(&m);
992                         GL_BlendFunc(GL_ONE, GL_ONE);
993                         GL_Color(1,1,1,1);
994                         R_Mesh_Draw(0, 4, 2, polygonelements);
995                         c_bloomdraws++;
996                         c_bloomdrawpixels += r_view_width * r_view_height;
997                 }
998         }
999         if (r_refdef.viewblend[3] >= 0.01f)
1000         {
1001                 // apply a color tint to the whole view
1002                 memset(&m, 0, sizeof(m));
1003                 m.pointer_vertex = varray_vertex3f;
1004                 R_Mesh_State(&m);
1005                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1006                 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
1007                 R_Mesh_Draw(0, 4, 2, polygonelements);
1008         }
1009 }
1010
1011 void R_RenderScene(void);
1012
1013 matrix4x4_t r_waterscrollmatrix;
1014
1015 /*
1016 ================
1017 R_RenderView
1018 ================
1019 */
1020 void R_RenderView(void)
1021 {
1022         if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
1023                 return; //Host_Error ("R_RenderView: NULL worldmodel");
1024
1025         r_view_width = bound(0, r_refdef.width, vid.width);
1026         r_view_height = bound(0, r_refdef.height, vid.height);
1027         r_view_depth = 1;
1028         r_view_x = bound(0, r_refdef.x, vid.width - r_refdef.width);
1029         r_view_y = bound(0, r_refdef.y, vid.height - r_refdef.height);
1030         r_view_z = 0;
1031         r_view_fov_x = bound(1, r_refdef.fov_x, 170);
1032         r_view_fov_y = bound(1, r_refdef.fov_y, 170);
1033         r_view_matrix = r_refdef.viewentitymatrix;
1034         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1035         r_rtworld = r_shadow_realtime_world.integer;
1036         r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
1037         r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
1038         r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
1039         r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
1040
1041         // GL is weird because it's bottom to top, r_view_y is top to bottom
1042         qglViewport(r_view_x, vid.height - (r_view_y + r_view_height), r_view_width, r_view_height);
1043         GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1044         GL_ScissorTest(true);
1045         GL_DepthMask(true);
1046         R_ClearScreen();
1047         R_Textures_Frame();
1048         R_UpdateFog();
1049         R_UpdateLights();
1050         R_TimeReport("setup");
1051
1052         qglDepthFunc(GL_LEQUAL);
1053         qglPolygonOffset(0, 0);
1054         qglEnable(GL_POLYGON_OFFSET_FILL);
1055
1056         R_RenderScene();
1057
1058         qglPolygonOffset(0, 0);
1059         qglDisable(GL_POLYGON_OFFSET_FILL);
1060
1061         R_BlendView();
1062         R_TimeReport("blendview");
1063
1064         GL_Scissor(0, 0, vid.width, vid.height);
1065         GL_ScissorTest(false);
1066 }
1067
1068 extern void R_DrawLightningBeams (void);
1069 void R_RenderScene(void)
1070 {
1071         // don't let sound skip if going slow
1072         if (r_refdef.extraupdate)
1073                 S_ExtraUpdate ();
1074
1075         r_framecount++;
1076
1077         R_MeshQueue_BeginScene();
1078
1079         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1080
1081         R_SetFrustum();
1082
1083         r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
1084         if (r_rtworldshadows || r_rtdlightshadows)
1085                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
1086         else
1087                 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
1088
1089         GL_SetupView_Orientation_FromEntity(&r_view_matrix);
1090
1091         Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
1092
1093         R_SkyStartFrame();
1094
1095         R_WorldVisibility();
1096         R_TimeReport("worldvis");
1097
1098         R_MarkEntities();
1099         R_TimeReport("markentity");
1100
1101         R_Shadow_UpdateWorldLightSelection();
1102
1103         // don't let sound skip if going slow
1104         if (r_refdef.extraupdate)
1105                 S_ExtraUpdate ();
1106
1107         GL_ShowTrisColor(0.025, 0.025, 0, 1);
1108         if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
1109         {
1110                 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
1111                 R_TimeReport("worldsky");
1112         }
1113
1114         if (R_DrawBrushModelsSky())
1115                 R_TimeReport("bmodelsky");
1116
1117         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1118         if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
1119         {
1120                 r_refdef.worldmodel->Draw(r_refdef.worldentity);
1121                 R_TimeReport("world");
1122         }
1123
1124         // don't let sound skip if going slow
1125         if (r_refdef.extraupdate)
1126                 S_ExtraUpdate ();
1127
1128         GL_ShowTrisColor(0, 0.015, 0, 1);
1129
1130         R_DrawModels();
1131         R_TimeReport("models");
1132
1133         // don't let sound skip if going slow
1134         if (r_refdef.extraupdate)
1135                 S_ExtraUpdate ();
1136
1137         GL_ShowTrisColor(0, 0, 0.033, 1);
1138         R_ShadowVolumeLighting(false);
1139         R_TimeReport("rtlights");
1140
1141         // don't let sound skip if going slow
1142         if (r_refdef.extraupdate)
1143                 S_ExtraUpdate ();
1144
1145         GL_ShowTrisColor(0.1, 0, 0, 1);
1146
1147         R_DrawLightningBeams();
1148         R_TimeReport("lightning");
1149
1150         R_DrawParticles();
1151         R_TimeReport("particles");
1152
1153         R_DrawExplosions();
1154         R_TimeReport("explosions");
1155
1156         R_MeshQueue_RenderTransparent();
1157         R_TimeReport("drawtrans");
1158
1159         R_DrawCoronas();
1160         R_TimeReport("coronas");
1161
1162         R_DrawWorldCrosshair();
1163         R_TimeReport("crosshair");
1164
1165         R_MeshQueue_Render();
1166         R_MeshQueue_EndScene();
1167
1168         if ((r_shadow_visiblelighting.integer || r_shadow_visiblevolumes.integer) && !r_showtrispass)
1169         {
1170                 R_ShadowVolumeLighting(true);
1171                 R_TimeReport("visiblevolume");
1172         }
1173
1174         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1175
1176         // don't let sound skip if going slow
1177         if (r_refdef.extraupdate)
1178                 S_ExtraUpdate ();
1179 }
1180
1181 /*
1182 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
1183 {
1184         int i;
1185         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
1186         rmeshstate_t m;
1187         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1188         GL_DepthMask(false);
1189         GL_DepthTest(true);
1190         R_Mesh_Matrix(&r_identitymatrix);
1191
1192         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
1193         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
1194         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
1195         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
1196         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
1197         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
1198         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
1199         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
1200         R_FillColors(color, 8, cr, cg, cb, ca);
1201         if (fogenabled)
1202         {
1203                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
1204                 {
1205                         VectorSubtract(v, r_vieworigin, diff);
1206                         f2 = exp(fogdensity/DotProduct(diff, diff));
1207                         f1 = 1 - f2;
1208                         c[0] = c[0] * f1 + fogcolor[0] * f2;
1209                         c[1] = c[1] * f1 + fogcolor[1] * f2;
1210                         c[2] = c[2] * f1 + fogcolor[2] * f2;
1211                 }
1212         }
1213         memset(&m, 0, sizeof(m));
1214         m.pointer_vertex = vertex3f;
1215         m.pointer_color = color;
1216         R_Mesh_State(&m);
1217         R_Mesh_Draw(8, 12);
1218 }
1219 */
1220
1221 int nomodelelements[24] =
1222 {
1223         5, 2, 0,
1224         5, 1, 2,
1225         5, 0, 3,
1226         5, 3, 1,
1227         0, 2, 4,
1228         2, 1, 4,
1229         3, 0, 4,
1230         1, 3, 4
1231 };
1232
1233 float nomodelvertex3f[6*3] =
1234 {
1235         -16,   0,   0,
1236          16,   0,   0,
1237           0, -16,   0,
1238           0,  16,   0,
1239           0,   0, -16,
1240           0,   0,  16
1241 };
1242
1243 float nomodelcolor4f[6*4] =
1244 {
1245         0.0f, 0.0f, 0.5f, 1.0f,
1246         0.0f, 0.0f, 0.5f, 1.0f,
1247         0.0f, 0.5f, 0.0f, 1.0f,
1248         0.0f, 0.5f, 0.0f, 1.0f,
1249         0.5f, 0.0f, 0.0f, 1.0f,
1250         0.5f, 0.0f, 0.0f, 1.0f
1251 };
1252
1253 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1254 {
1255         const entity_render_t *ent = calldata1;
1256         int i;
1257         float f1, f2, *c, diff[3];
1258         float color4f[6*4];
1259         rmeshstate_t m;
1260         R_Mesh_Matrix(&ent->matrix);
1261
1262         memset(&m, 0, sizeof(m));
1263         m.pointer_vertex = nomodelvertex3f;
1264
1265         if (ent->flags & EF_ADDITIVE)
1266         {
1267                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1268                 GL_DepthMask(false);
1269         }
1270         else if (ent->alpha < 1)
1271         {
1272                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1273                 GL_DepthMask(false);
1274         }
1275         else
1276         {
1277                 GL_BlendFunc(GL_ONE, GL_ZERO);
1278                 GL_DepthMask(true);
1279         }
1280         GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
1281         if (fogenabled)
1282         {
1283                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1284                 m.pointer_color = color4f;
1285                 VectorSubtract(ent->origin, r_vieworigin, diff);
1286                 f2 = exp(fogdensity/DotProduct(diff, diff));
1287                 f1 = 1 - f2;
1288                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1289                 {
1290                         c[0] = (c[0] * f1 + fogcolor[0] * f2);
1291                         c[1] = (c[1] * f1 + fogcolor[1] * f2);
1292                         c[2] = (c[2] * f1 + fogcolor[2] * f2);
1293                         c[3] *= ent->alpha;
1294                 }
1295         }
1296         else if (ent->alpha != 1)
1297         {
1298                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1299                 m.pointer_color = color4f;
1300                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1301                         c[3] *= ent->alpha;
1302         }
1303         else
1304                 m.pointer_color = nomodelcolor4f;
1305         R_Mesh_State(&m);
1306         R_Mesh_Draw(0, 6, 8, nomodelelements);
1307 }
1308
1309 void R_DrawNoModel(entity_render_t *ent)
1310 {
1311         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1312                 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1313         //else
1314         //      R_DrawNoModelCallback(ent, 0);
1315 }
1316
1317 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1318 {
1319         vec3_t right1, right2, diff, normal;
1320
1321         VectorSubtract (org2, org1, normal);
1322
1323         // calculate 'right' vector for start
1324         VectorSubtract (r_vieworigin, org1, diff);
1325         CrossProduct (normal, diff, right1);
1326         VectorNormalize (right1);
1327
1328         // calculate 'right' vector for end
1329         VectorSubtract (r_vieworigin, org2, diff);
1330         CrossProduct (normal, diff, right2);
1331         VectorNormalize (right2);
1332
1333         vert[ 0] = org1[0] + width * right1[0];
1334         vert[ 1] = org1[1] + width * right1[1];
1335         vert[ 2] = org1[2] + width * right1[2];
1336         vert[ 3] = org1[0] - width * right1[0];
1337         vert[ 4] = org1[1] - width * right1[1];
1338         vert[ 5] = org1[2] - width * right1[2];
1339         vert[ 6] = org2[0] - width * right2[0];
1340         vert[ 7] = org2[1] - width * right2[1];
1341         vert[ 8] = org2[2] - width * right2[2];
1342         vert[ 9] = org2[0] + width * right2[0];
1343         vert[10] = org2[1] + width * right2[1];
1344         vert[11] = org2[2] + width * right2[2];
1345 }
1346
1347 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1348
1349 void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, int depthdisable, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2, float cr, float cg, float cb, float ca)
1350 {
1351         float diff[3];
1352         rmeshstate_t m;
1353
1354         if (fogenabled)
1355         {
1356                 VectorSubtract(origin, r_vieworigin, diff);
1357                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1358         }
1359
1360         R_Mesh_Matrix(&r_identitymatrix);
1361         GL_BlendFunc(blendfunc1, blendfunc2);
1362         GL_DepthMask(false);
1363         GL_DepthTest(!depthdisable);
1364
1365         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1366         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1367         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1368         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1369         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1370         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1371         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1372         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1373         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1374         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1375         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1376         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1377
1378         memset(&m, 0, sizeof(m));
1379         m.tex[0] = R_GetTexture(texture);
1380         m.pointer_texcoord[0] = spritetexcoord2f;
1381         m.pointer_vertex = varray_vertex3f;
1382         R_Mesh_State(&m);
1383         GL_Color(cr, cg, cb, ca);
1384         R_Mesh_Draw(0, 4, 2, polygonelements);
1385 }
1386
1387 int R_Mesh_AddVertex3f(rmesh_t *mesh, const float *v)
1388 {
1389         int i;
1390         float *vertex3f;
1391         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
1392                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
1393                         break;
1394         if (i == mesh->numvertices)
1395         {
1396                 if (mesh->numvertices < mesh->maxvertices)
1397                 {
1398                         VectorCopy(v, vertex3f);
1399                         mesh->numvertices++;
1400                 }
1401                 return mesh->numvertices;
1402         }
1403         else
1404                 return i;
1405 }
1406
1407 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
1408 {
1409         int i;
1410         int *e, element[3];
1411         element[0] = R_Mesh_AddVertex3f(mesh, vertex3f);vertex3f += 3;
1412         element[1] = R_Mesh_AddVertex3f(mesh, vertex3f);vertex3f += 3;
1413         e = mesh->element3i + mesh->numtriangles * 3;
1414         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
1415         {
1416                 element[2] = R_Mesh_AddVertex3f(mesh, vertex3f);
1417                 if (mesh->numtriangles < mesh->maxtriangles)
1418                 {
1419                         *e++ = element[0];
1420                         *e++ = element[1];
1421                         *e++ = element[2];
1422                         mesh->numtriangles++;
1423                 }
1424                 element[1] = element[2];
1425         }
1426 }
1427
1428 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
1429 {
1430         int planenum, planenum2;
1431         int w;
1432         int tempnumpoints;
1433         mplane_t *plane, *plane2;
1434         float temppoints[2][256*3];
1435         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
1436         {
1437                 w = 0;
1438                 tempnumpoints = 4;
1439                 PolygonF_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->normal[3], 1024.0*1024.0*1024.0);
1440                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
1441                 {
1442                         if (planenum2 == planenum)
1443                                 continue;
1444                         PolygonF_Divide(tempnumpoints, temppoints[w], plane2->normal[0], plane2->normal[1], plane2->normal[2], plane2->dist, 1.0/32.0, 0, NULL, NULL, 256, temppoints[!w], &tempnumpoints);
1445                         w = !w;
1446                 }
1447                 if (tempnumpoints < 3)
1448                         continue;
1449                 // generate elements forming a triangle fan for this polygon
1450                 R_Mesh_AddPolygon3f(mesh, tempnumpoints, temppoints[w]);
1451         }
1452 }
1453
1454 void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
1455 {
1456         texture_t *texture = t;
1457         model_t *model = ent->model;
1458         int s = ent->skinnum;
1459         if ((unsigned int)s >= (unsigned int)model->numskins)
1460                 s = 0;
1461         if (s >= 1)
1462                 c_models++;
1463         if (model->skinscenes)
1464         {
1465                 if (model->skinscenes[s].framecount > 1)
1466                         s = model->skinscenes[s].firstframe + (unsigned int) (r_refdef.time * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
1467                 else
1468                         s = model->skinscenes[s].firstframe;
1469         }
1470         if (s > 0)
1471                 t = t + s * model->num_surfaces;
1472         if (t->animated)
1473                 t = t->anim_frames[ent->frame != 0][(t->anim_total[ent->frame != 0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[ent->frame != 0]) : 0];
1474         texture->currentframe = t;
1475         t->currentmaterialflags = t->basematerialflags;
1476         t->currentalpha = ent->alpha;
1477         if (t->basematerialflags & MATERIALFLAG_WATERALPHA)
1478                 t->currentalpha *= r_wateralpha.value;
1479         if (!(ent->flags & RENDER_LIGHT))
1480                 t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
1481         if (ent->effects & EF_ADDITIVE)
1482                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_TRANSPARENT;
1483         else if (t->currentalpha < 1)
1484                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
1485         if (ent->effects & EF_NODEPTHTEST)
1486                 t->currentmaterialflags |= MATERIALFLAG_NODEPTHTEST;
1487 }
1488
1489 void R_UpdateAllTextureInfo(entity_render_t *ent)
1490 {
1491         int i;
1492         if (ent->model)
1493                 for (i = 0;i < ent->model->num_textures;i++)
1494                         R_UpdateTextureInfo(ent, ent->model->data_textures + i);
1495 }
1496
1497 float *rsurface_vertex3f;
1498 float *rsurface_svector3f;
1499 float *rsurface_tvector3f;
1500 float *rsurface_normal3f;
1501 float *rsurface_lightmapcolor4f;
1502
1503 void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg)
1504 {
1505         int i, j;
1506         float center[3], forward[3], right[3], up[3], v[4][3];
1507         matrix4x4_t matrix1, imatrix1;
1508         if ((ent->frameblend[0].lerp != 1 || ent->frameblend[0].frame != 0) && (surface->groupmesh->data_morphvertex3f || surface->groupmesh->data_vertexboneweights))
1509         {
1510                 rsurface_vertex3f = varray_vertex3f;
1511                 rsurface_svector3f = NULL;
1512                 rsurface_tvector3f = NULL;
1513                 rsurface_normal3f = NULL;
1514                 Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, surface->groupmesh, rsurface_vertex3f);
1515         }
1516         else
1517         {
1518                 rsurface_vertex3f = surface->groupmesh->data_vertex3f;
1519                 rsurface_svector3f = surface->groupmesh->data_svector3f;
1520                 rsurface_tvector3f = surface->groupmesh->data_tvector3f;
1521                 rsurface_normal3f = surface->groupmesh->data_normal3f;
1522         }
1523         if (texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE2)
1524         {
1525                 if (!rsurface_svector3f)
1526                 {
1527                         rsurface_svector3f = varray_svector3f;
1528                         rsurface_tvector3f = varray_tvector3f;
1529                         rsurface_normal3f = varray_normal3f;
1530                         Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f);
1531                 }
1532                 // a single autosprite surface can contain multiple sprites...
1533                 VectorClear(forward);
1534                 VectorClear(right);
1535                 VectorSet(up, 0, 0, 1);
1536                 for (j = 0;j < surface->num_vertices - 3;j += 4)
1537                 {
1538                         VectorClear(center);
1539                         for (i = 0;i < 4;i++)
1540                                 VectorAdd(center, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
1541                         VectorScale(center, 0.25f, center);
1542                         // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out?
1543                         Matrix4x4_FromVectors(&matrix1, (rsurface_normal3f + 3 * surface->num_firstvertex) + j*3, (rsurface_svector3f + 3 * surface->num_firstvertex) + j*3, (rsurface_tvector3f + 3 * surface->num_firstvertex) + j*3, center);
1544                         Matrix4x4_Invert_Simple(&imatrix1, &matrix1);
1545                         for (i = 0;i < 4;i++)
1546                                 Matrix4x4_Transform(&imatrix1, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, v[i]);
1547                         forward[0] = modelorg[0] - center[0];
1548                         forward[1] = modelorg[1] - center[1];
1549                         VectorNormalize(forward);
1550                         right[0] = forward[1];
1551                         right[1] = -forward[0];
1552                         for (i = 0;i < 4;i++)
1553                                 VectorMAMAMAM(1, center, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (surface->num_firstvertex+i+j) * 3);
1554                 }
1555                 rsurface_vertex3f = varray_vertex3f;
1556                 rsurface_svector3f = NULL;
1557                 rsurface_tvector3f = NULL;
1558                 rsurface_normal3f = NULL;
1559         }
1560         else if (texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE)
1561         {
1562                 if (!rsurface_svector3f)
1563                 {
1564                         rsurface_svector3f = varray_svector3f;
1565                         rsurface_tvector3f = varray_tvector3f;
1566                         rsurface_normal3f = varray_normal3f;
1567                         Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_texcoordtexture2f, surface->groupmesh->data_element3i + surface->num_firsttriangle * 3, rsurface_svector3f, rsurface_tvector3f, rsurface_normal3f);
1568                 }
1569                 Matrix4x4_Transform(&ent->inversematrix, r_viewforward, forward);
1570                 Matrix4x4_Transform(&ent->inversematrix, r_viewright, right);
1571                 Matrix4x4_Transform(&ent->inversematrix, r_viewup, up);
1572                 // a single autosprite surface can contain multiple sprites...
1573                 for (j = 0;j < surface->num_vertices - 3;j += 4)
1574                 {
1575                         VectorClear(center);
1576                         for (i = 0;i < 4;i++)
1577                                 VectorAdd(center, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
1578                         VectorScale(center, 0.25f, center);
1579                         // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out?
1580                         Matrix4x4_FromVectors(&matrix1, (rsurface_normal3f + 3 * surface->num_firstvertex) + j*3, (rsurface_svector3f + 3 * surface->num_firstvertex) + j*3, (rsurface_tvector3f + 3 * surface->num_firstvertex) + j*3, center);
1581                         Matrix4x4_Invert_Simple(&imatrix1, &matrix1);
1582                         for (i = 0;i < 4;i++)
1583                                 Matrix4x4_Transform(&imatrix1, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, v[i]);
1584                         for (i = 0;i < 4;i++)
1585                                 VectorMAMAMAM(1, center, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (surface->num_firstvertex+i+j) * 3);
1586                 }
1587                 rsurface_vertex3f = varray_vertex3f;
1588                 rsurface_svector3f = NULL;
1589                 rsurface_tvector3f = NULL;
1590                 rsurface_normal3f = NULL;
1591         }
1592         R_Mesh_VertexPointer(rsurface_vertex3f);
1593 }
1594
1595 void RSurf_SetColorPointer(const entity_render_t *ent, const msurface_t *surface, const vec3_t modelorg, float r, float g, float b, float a, qboolean lightmodel, qboolean vertexlight, qboolean applycolor, qboolean applyfog)
1596 {
1597         int i;
1598         float f;
1599         float *v, *c, *c2;
1600         vec3_t diff;
1601         if (lightmodel)
1602         {
1603                 vec4_t ambientcolor4f;
1604                 vec3_t diffusecolor;
1605                 vec3_t diffusenormal;
1606                 if (R_LightModel(ambientcolor4f, diffusecolor, diffusenormal, ent, r, g, b, a, false))
1607                 {
1608                         rsurface_lightmapcolor4f = varray_color4f;
1609                         if (rsurface_normal3f == NULL)
1610                         {
1611                                 rsurface_normal3f = varray_normal3f;
1612                                 Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle, rsurface_normal3f);
1613                         }
1614                         R_LightModel_CalcVertexColors(ambientcolor4f, diffusecolor, diffusenormal, surface->groupmesh->num_vertices, rsurface_vertex3f + 3 * surface->num_firstvertex, rsurface_normal3f + 3 * surface->num_firstvertex, rsurface_lightmapcolor4f + 4 * surface->num_firstvertex);
1615                         r = 1;
1616                         g = 1;
1617                         b = 1;
1618                         a = 1;
1619                         applycolor = false;
1620                 }
1621                 else
1622                 {
1623                         r = ambientcolor4f[0];
1624                         g = ambientcolor4f[1];
1625                         b = ambientcolor4f[2];
1626                         a = ambientcolor4f[3];
1627                         rsurface_lightmapcolor4f = NULL;
1628                 }
1629         }
1630         else if (vertexlight)
1631         {
1632                 if (surface->lightmapinfo)
1633                 {
1634                         rsurface_lightmapcolor4f = varray_color4f;
1635                         for (i = 0, c = rsurface_lightmapcolor4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1636                         {
1637                                 const qbyte *lm = surface->lightmapinfo->samples + (surface->groupmesh->data_lightmapoffsets + surface->num_firstvertex)[i];
1638                                 float scale = d_lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
1639                                 VectorScale(lm, scale, c);
1640                                 if (surface->lightmapinfo->styles[1] != 255)
1641                                 {
1642                                         int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
1643                                         lm += size3;
1644                                         scale = d_lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
1645                                         VectorMA(c, scale, lm, c);
1646                                         if (surface->lightmapinfo->styles[2] != 255)
1647                                         {
1648                                                 lm += size3;
1649                                                 scale = d_lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
1650                                                 VectorMA(c, scale, lm, c);
1651                                                 if (surface->lightmapinfo->styles[3] != 255)
1652                                                 {
1653                                                         lm += size3;
1654                                                         scale = d_lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
1655                                                         VectorMA(c, scale, lm, c);
1656                                                 }
1657                                         }
1658                                 }
1659                         }
1660                 }
1661                 else
1662                         rsurface_lightmapcolor4f = surface->groupmesh->data_lightmapcolor4f;
1663         }
1664         else
1665                 rsurface_lightmapcolor4f = NULL;
1666         if (applyfog)
1667         {
1668                 if (rsurface_lightmapcolor4f)
1669                 {
1670                         for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
1671                         {
1672                                 VectorSubtract(v, modelorg, diff);
1673                                 f = 1 - exp(fogdensity/DotProduct(diff, diff));
1674                                 c2[0] = c[0] * f;
1675                                 c2[1] = c[1] * f;
1676                                 c2[2] = c[2] * f;
1677                                 c2[3] = c[3];
1678                         }
1679                 }
1680                 else
1681                 {
1682                         for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c2 = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4)
1683                         {
1684                                 VectorSubtract(v, modelorg, diff);
1685                                 f = 1 - exp(fogdensity/DotProduct(diff, diff));
1686                                 c2[0] = f;
1687                                 c2[1] = f;
1688                                 c2[2] = f;
1689                                 c2[3] = 1;
1690                         }
1691                 }
1692                 rsurface_lightmapcolor4f = varray_color4f;
1693         }
1694         if (applycolor && rsurface_lightmapcolor4f)
1695         {
1696                 for (i = 0, c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4)
1697                 {
1698                         c2[0] = c[0] * r;
1699                         c2[1] = c[1] * g;
1700                         c2[2] = c[2] * b;
1701                         c2[3] = c[3] * a;
1702                 }
1703         }
1704         R_Mesh_ColorPointer(rsurface_lightmapcolor4f);
1705         GL_Color(r, g, b, a);
1706 }
1707
1708
1709 static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg)
1710 {
1711         int i;
1712         int texturesurfaceindex;
1713         const float *v;
1714         float *c;
1715         float diff[3];
1716         float colorpants[3], colorshirt[3];
1717         float f, r, g, b, a, colorscale;
1718         const msurface_t *surface;
1719         qboolean dolightmap;
1720         qboolean doambient;
1721         qboolean dodetail;
1722         qboolean doglow;
1723         qboolean dofogpass;
1724         qboolean fogallpasses;
1725         qboolean waterscrolling;
1726         qboolean dopants;
1727         qboolean doshirt;
1728         qboolean dofullbrightpants;
1729         qboolean dofullbrightshirt;
1730         qboolean applycolor;
1731         qboolean lightmodel = false;
1732         rtexture_t *basetexture;
1733         rmeshstate_t m;
1734         if (texture->currentmaterialflags & MATERIALFLAG_NODRAW)
1735                 return;
1736         c_faces += texturenumsurfaces;
1737         // FIXME: identify models using a better check than ent->model->shadowmesh
1738         if (!(ent->effects & EF_FULLBRIGHT) && !ent->model->brush.shadowmesh)
1739                 lightmodel = true;
1740         // gl_lightmaps debugging mode skips normal texturing
1741         if (gl_lightmaps.integer)
1742         {
1743                 GL_BlendFunc(GL_ONE, GL_ZERO);
1744                 GL_DepthMask(true);
1745                 GL_DepthTest(true);
1746                 qglDisable(GL_CULL_FACE);
1747                 GL_Color(1, 1, 1, 1);
1748                 memset(&m, 0, sizeof(m));
1749                 R_Mesh_State(&m);
1750                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1751                 {
1752                         surface = texturesurfacelist[texturesurfaceindex];
1753                         R_Mesh_TexBind(0, R_GetTexture(surface->lightmaptexture));
1754                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f);
1755                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1756                         RSurf_SetColorPointer(ent, surface, modelorg, 1, 1, 1, 1, lightmodel, !surface->lightmaptexture, false, false);
1757                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1758                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
1759                         GL_LockArrays(0, 0);
1760                 }
1761                 qglEnable(GL_CULL_FACE);
1762                 return;
1763         }
1764         GL_DepthTest(!(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
1765         GL_DepthMask(!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT));
1766         if (texture->currentmaterialflags & MATERIALFLAG_ADD)
1767                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1768         else if (texture->currentmaterialflags & MATERIALFLAG_ALPHA)
1769                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1770         else
1771                 GL_BlendFunc(GL_ONE, GL_ZERO);
1772         // water waterscrolling in texture matrix
1773         waterscrolling = (texture->currentmaterialflags & MATERIALFLAG_WATER) && r_waterscroll.value != 0;
1774         if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
1775                 qglDisable(GL_CULL_FACE);
1776         if (texture->currentmaterialflags & MATERIALFLAG_SKY)
1777         {
1778                 if (skyrendernow)
1779                 {
1780                         skyrendernow = false;
1781                         if (skyrendermasked)
1782                                 R_Sky();
1783                 }
1784                 // LordHavoc: HalfLife maps have freaky skypolys...
1785                 //if (!ent->model->brush.ishlbsp)
1786                 {
1787                         R_Mesh_Matrix(&ent->matrix);
1788                         GL_Color(fogcolor[0], fogcolor[1], fogcolor[2], 1);
1789                         if (skyrendermasked)
1790                         {
1791                                 // depth-only (masking)
1792                                 GL_ColorMask(0,0,0,0);
1793                                 // just to make sure that braindead drivers don't draw anything
1794                                 // despite that colormask...
1795                                 GL_BlendFunc(GL_ZERO, GL_ONE);
1796                         }
1797                         else
1798                         {
1799                                 // fog sky
1800                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1801                         }
1802                         GL_DepthMask(true);
1803                         GL_DepthTest(true);
1804                         memset(&m, 0, sizeof(m));
1805                         R_Mesh_State(&m);
1806                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1807                         {
1808                                 surface = texturesurfacelist[texturesurfaceindex];
1809                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1810                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1811                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
1812                                 GL_LockArrays(0, 0);
1813                         }
1814                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1815                 }
1816         }
1817         else if ((texture->currentmaterialflags & MATERIALFLAG_WATER) && r_watershader.value && gl_textureshader && !texture->skin.glow && !fogenabled && ent->colormod[0] == 1 && ent->colormod[1] == 1 && ent->colormod[2] == 1)
1818         {
1819                 // NVIDIA Geforce3 distortion texture shader on water
1820                 float args[4] = {0.05f,0,0,0.04f};
1821                 memset(&m, 0, sizeof(m));
1822                 m.tex[0] = R_GetTexture(r_texture_distorttexture[(int)(r_refdef.time * 16)&63]);
1823                 m.tex[1] = R_GetTexture(texture->skin.base);
1824                 m.texcombinergb[0] = GL_REPLACE;
1825                 m.texcombinergb[1] = GL_REPLACE;
1826                 Matrix4x4_CreateFromQuakeEntity(&m.texmatrix[0], 0, 0, 0, 0, 0, 0, r_watershader.value);
1827                 m.texmatrix[1] = r_waterscrollmatrix;
1828                 R_Mesh_State(&m);
1829
1830                 GL_Color(1, 1, 1, texture->currentalpha);
1831                 GL_ActiveTexture(0);
1832                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
1833                 GL_ActiveTexture(1);
1834                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_OFFSET_TEXTURE_2D_NV);
1835                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB);
1836                 qglTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, &args[0]);
1837                 qglEnable(GL_TEXTURE_SHADER_NV);
1838
1839                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1840                 {
1841                         surface = texturesurfacelist[texturesurfaceindex];
1842                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1843                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
1844                         R_Mesh_TexCoordPointer(1, 2, surface->groupmesh->data_texcoordtexture2f);
1845                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1846                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
1847                         GL_LockArrays(0, 0);
1848                 }
1849
1850                 qglDisable(GL_TEXTURE_SHADER_NV);
1851                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
1852                 GL_ActiveTexture(0);
1853         }
1854         else if (texture->currentmaterialflags & (MATERIALFLAG_WATER | MATERIALFLAG_WALL))
1855         {
1856                 // normal surface (wall or water)
1857                 dolightmap = !(texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT);
1858                 doambient = r_ambient.value >= (1/64.0f);
1859                 dodetail = r_detailtextures.integer && texture->skin.detail != NULL && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT);
1860                 doglow = texture->skin.glow != NULL;
1861                 dofogpass = fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_ADD);
1862                 fogallpasses = fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT);
1863                 if (ent->colormap >= 0)
1864                 {
1865                         int b;
1866                         qbyte *bcolor;
1867                         basetexture = texture->skin.base;
1868                         dopants = texture->skin.pants != NULL;
1869                         doshirt = texture->skin.shirt != NULL;
1870                         // 128-224 are backwards ranges
1871                         b = (ent->colormap & 0xF) << 4;b += (b >= 128 && b < 224) ? 4 : 12;
1872                         dofullbrightpants = b >= 224;
1873                         bcolor = (qbyte *) (&palette_complete[b]);
1874                         VectorScale(bcolor, (1.0f / 255.0f), colorpants);
1875                         // 128-224 are backwards ranges
1876                         b = (ent->colormap & 0xF0);b += (b >= 128 && b < 224) ? 4 : 12;
1877                         dofullbrightshirt = b >= 224;
1878                         bcolor = (qbyte *) (&palette_complete[b]);
1879                         VectorScale(bcolor, (1.0f / 255.0f), colorshirt);
1880                 }
1881                 else
1882                 {
1883                         basetexture = texture->skin.merged ? texture->skin.merged : texture->skin.base;
1884                         dopants = false;
1885                         doshirt = false;
1886                         dofullbrightshirt = false;
1887                         dofullbrightpants = false;
1888                 }
1889                 if (dolightmap && r_textureunits.integer >= 2 && gl_combine.integer)
1890                 {
1891                         memset(&m, 0, sizeof(m));
1892                         m.tex[1] = R_GetTexture(basetexture);
1893                         if (waterscrolling)
1894                                 m.texmatrix[1] = r_waterscrollmatrix;
1895                         m.texrgbscale[1] = 2;
1896                         m.pointer_color = varray_color4f;
1897                         R_Mesh_State(&m);
1898                         // transparent is not affected by r_lightmapintensity
1899                         if (!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1900                                 colorscale = r_lightmapintensity;
1901                         else
1902                                 colorscale = 1;
1903                         r = ent->colormod[0] * colorscale;
1904                         g = ent->colormod[1] * colorscale;
1905                         b = ent->colormod[2] * colorscale;
1906                         a = texture->currentalpha;
1907                         // q3bsp has no lightmap updates, so the lightstylevalue that
1908                         // would normally be baked into the lightmaptexture must be
1909                         // applied to the color
1910                         if (ent->model->brushq3.data_lightmaps)
1911                         {
1912                                 float scale = d_lightstylevalue[0] * (1.0f / 128.0f);
1913                                 r *= scale;
1914                                 g *= scale;
1915                                 b *= scale;
1916                         }
1917                         applycolor = r != 1 || g != 1 || b != 1 || a != 1;
1918                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1919                         {
1920                                 surface = texturesurfacelist[texturesurfaceindex];
1921                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1922                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f);
1923                                 R_Mesh_TexCoordPointer(1, 2, surface->groupmesh->data_texcoordtexture2f);
1924                                 if (surface->lightmaptexture)
1925                                         R_Mesh_TexBind(0, R_GetTexture(surface->lightmaptexture));
1926                                 else
1927                                         R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
1928                                 RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, lightmodel, !surface->lightmaptexture, applycolor, fogallpasses);
1929                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1930                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
1931                                 GL_LockArrays(0, 0);
1932                         }
1933                 }
1934                 else if (dolightmap && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT) && !lightmodel)
1935                 {
1936                         // single texture
1937                         GL_BlendFunc(GL_ONE, GL_ZERO);
1938                         GL_DepthMask(true);
1939                         GL_Color(1, 1, 1, 1);
1940                         memset(&m, 0, sizeof(m));
1941                         R_Mesh_State(&m);
1942                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1943                         {
1944                                 surface = texturesurfacelist[texturesurfaceindex];
1945                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1946                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f);
1947                                 if (surface->lightmaptexture)
1948                                 {
1949                                         R_Mesh_TexBind(0, R_GetTexture(surface->lightmaptexture));
1950                                         R_Mesh_ColorPointer(NULL);
1951                                 }
1952                                 else
1953                                 {
1954                                         R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
1955                                         R_Mesh_ColorPointer(surface->groupmesh->data_lightmapcolor4f);
1956                                 }
1957                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1958                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
1959                                 GL_LockArrays(0, 0);
1960                         }
1961                         GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
1962                         GL_DepthMask(false);
1963                         GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1);
1964                         memset(&m, 0, sizeof(m));
1965                         m.tex[0] = R_GetTexture(basetexture);
1966                         if (waterscrolling)
1967                                 m.texmatrix[0] = r_waterscrollmatrix;
1968                         R_Mesh_State(&m);
1969                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1970                         {
1971                                 surface = texturesurfacelist[texturesurfaceindex];
1972                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1973                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
1974                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1975                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
1976                                 GL_LockArrays(0, 0);
1977                         }
1978                 }
1979                 else
1980                 {
1981                         memset(&m, 0, sizeof(m));
1982                         m.tex[0] = R_GetTexture(basetexture);
1983                         if (waterscrolling)
1984                                 m.texmatrix[0] = r_waterscrollmatrix;
1985                         m.pointer_color = varray_color4f;
1986                         colorscale = 2;
1987                         if (gl_combine.integer)
1988                         {
1989                                 m.texrgbscale[0] = 2;
1990                                 colorscale = 1;
1991                         }
1992                         // transparent is not affected by r_lightmapintensity
1993                         if (!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1994                                 colorscale *= r_lightmapintensity;
1995                         R_Mesh_State(&m);
1996                         r = ent->colormod[0] * colorscale;
1997                         g = ent->colormod[1] * colorscale;
1998                         b = ent->colormod[2] * colorscale;
1999                         a = texture->currentalpha;
2000                         if (dolightmap)
2001                         {
2002                                 // q3bsp has no lightmap updates, so the lightstylevalue that
2003                                 // would normally be baked into the lightmaptexture must be
2004                                 // applied to the color
2005                                 if (ent->model->brushq3.data_lightmaps)
2006                                 {
2007                                         float scale = d_lightstylevalue[0] * (1.0f / 128.0f);
2008                                         r *= scale;
2009                                         g *= scale;
2010                                         b *= scale;
2011                                 }
2012                                 applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2013                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2014                                 {
2015                                         surface = texturesurfacelist[texturesurfaceindex];
2016                                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2017                                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2018                                         RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, lightmodel, true, applycolor, fogallpasses);
2019                                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2020                                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2021                                         GL_LockArrays(0, 0);
2022                                 }
2023                         }
2024                         else
2025                         {
2026                                 applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2027                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2028                                 {
2029                                         surface = texturesurfacelist[texturesurfaceindex];
2030                                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2031                                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2032                                         RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
2033                                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2034                                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2035                                         GL_LockArrays(0, 0);
2036                                 }
2037                         }
2038                 }
2039                 if (dopants)
2040                 {
2041                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2042                         memset(&m, 0, sizeof(m));
2043                         m.tex[0] = R_GetTexture(texture->skin.pants);
2044                         if (waterscrolling)
2045                                 m.texmatrix[0] = r_waterscrollmatrix;
2046                         m.pointer_color = varray_color4f;
2047                         colorscale = 1;
2048                         if (gl_combine.integer)
2049                         {
2050                                 m.texrgbscale[0] = 2;
2051                                 colorscale *= 0.5f;
2052                         }
2053                         // transparent is not affected by r_lightmapintensity
2054                         if (!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
2055                                 colorscale *= r_lightmapintensity;
2056                         R_Mesh_State(&m);
2057                         r = ent->colormod[0] * colorpants[0] * colorscale;
2058                         g = ent->colormod[1] * colorpants[1] * colorscale;
2059                         b = ent->colormod[2] * colorpants[2] * colorscale;
2060                         a = texture->currentalpha;
2061                         if (dolightmap && !dofullbrightpants)
2062                         {
2063                                 // q3bsp has no lightmap updates, so the lightstylevalue that
2064                                 // would normally be baked into the lightmaptexture must be
2065                                 // applied to the color
2066                                 if (ent->model->brushq3.data_lightmaps)
2067                                 {
2068                                         float scale = d_lightstylevalue[0] * (1.0f / 128.0f);
2069                                         r *= scale;
2070                                         g *= scale;
2071                                         b *= scale;
2072                                 }
2073                                 applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2074                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2075                                 {
2076                                         surface = texturesurfacelist[texturesurfaceindex];
2077                                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2078                                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2079                                         RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, lightmodel, true, applycolor, fogallpasses);
2080                                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2081                                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2082                                         GL_LockArrays(0, 0);
2083                                 }
2084                         }
2085                         else
2086                         {
2087                                 applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2088                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2089                                 {
2090                                         surface = texturesurfacelist[texturesurfaceindex];
2091                                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2092                                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2093                                         RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
2094                                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2095                                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2096                                         GL_LockArrays(0, 0);
2097                                 }
2098                         }
2099                 }
2100                 if (doshirt)
2101                 {
2102                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2103                         memset(&m, 0, sizeof(m));
2104                         m.tex[0] = R_GetTexture(texture->skin.shirt);
2105                         if (waterscrolling)
2106                                 m.texmatrix[0] = r_waterscrollmatrix;
2107                         m.pointer_color = varray_color4f;
2108                         colorscale = 1;
2109                         if (gl_combine.integer)
2110                         {
2111                                 m.texrgbscale[0] = 2;
2112                                 colorscale *= 0.5f;
2113                         }
2114                         // transparent is not affected by r_lightmapintensity
2115                         if (!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
2116                                 colorscale *= r_lightmapintensity;
2117                         R_Mesh_State(&m);
2118                         r = ent->colormod[0] * colorshirt[0] * colorscale;
2119                         g = ent->colormod[1] * colorshirt[1] * colorscale;
2120                         b = ent->colormod[2] * colorshirt[2] * colorscale;
2121                         a = texture->currentalpha;
2122                         if (dolightmap && !dofullbrightshirt)
2123                         {
2124                                 // q3bsp has no lightmap updates, so the lightstylevalue that
2125                                 // would normally be baked into the lightmaptexture must be
2126                                 // applied to the color
2127                                 if (ent->model->brushq3.data_lightmaps)
2128                                 {
2129                                         float scale = d_lightstylevalue[0] * (1.0f / 128.0f);
2130                                         r *= scale;
2131                                         g *= scale;
2132                                         b *= scale;
2133                                 }
2134                                 applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2135                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2136                                 {
2137                                         surface = texturesurfacelist[texturesurfaceindex];
2138                                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2139                                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2140                                         RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, lightmodel, true, applycolor, fogallpasses);
2141                                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2142                                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2143                                         GL_LockArrays(0, 0);
2144                                 }
2145                         }
2146                         else
2147                         {
2148                                 applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2149                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2150                                 {
2151                                         surface = texturesurfacelist[texturesurfaceindex];
2152                                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2153                                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2154                                         RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
2155                                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2156                                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2157                                         GL_LockArrays(0, 0);
2158                                 }
2159                         }
2160                 }
2161                 if (doambient)
2162                 {
2163                         doambient = false;
2164                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2165                         GL_DepthMask(false);
2166                         memset(&m, 0, sizeof(m));
2167                         m.tex[0] = R_GetTexture(texture->skin.base);
2168                         if (waterscrolling)
2169                                 m.texmatrix[0] = r_waterscrollmatrix;
2170                         m.pointer_color = varray_color4f;
2171                         colorscale = 1;
2172                         if (gl_combine.integer)
2173                         {
2174                                 m.texrgbscale[0] = 2;
2175                                 colorscale *= 0.5f;
2176                         }
2177                         R_Mesh_State(&m);
2178                         colorscale *= r_ambient.value * (1.0f / 64.0f);
2179                         r = ent->colormod[0] * colorscale;
2180                         g = ent->colormod[1] * colorscale;
2181                         b = ent->colormod[2] * colorscale;
2182                         a = texture->currentalpha;
2183                         applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2184                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2185                         {
2186                                 surface = texturesurfacelist[texturesurfaceindex];
2187                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2188                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2189                                 RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
2190                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2191                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2192                                 GL_LockArrays(0, 0);
2193                         }
2194                 }
2195                 if (dodetail)
2196                 {
2197                         GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
2198                         GL_DepthMask(false);
2199                         GL_Color(1, 1, 1, 1);
2200                         memset(&m, 0, sizeof(m));
2201                         m.tex[0] = R_GetTexture(texture->skin.detail);
2202                         R_Mesh_State(&m);
2203                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2204                         {
2205                                 surface = texturesurfacelist[texturesurfaceindex];
2206                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2207                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoorddetail2f);
2208                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2209                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2210                                 GL_LockArrays(0, 0);
2211                         }
2212                 }
2213                 if (doglow)
2214                 {
2215                         // if glow was not already done using multitexture, do it now.
2216                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2217                         GL_DepthMask(false);
2218                         memset(&m, 0, sizeof(m));
2219                         m.tex[0] = R_GetTexture(texture->skin.glow);
2220                         if (waterscrolling)
2221                                 m.texmatrix[0] = r_waterscrollmatrix;
2222                         m.pointer_color = varray_color4f;
2223                         R_Mesh_State(&m);
2224                         colorscale = 1;
2225                         r = ent->colormod[0] * colorscale;
2226                         g = ent->colormod[1] * colorscale;
2227                         b = ent->colormod[2] * colorscale;
2228                         a = texture->currentalpha;
2229                         applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2230                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2231                         {
2232                                 surface = texturesurfacelist[texturesurfaceindex];
2233                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2234                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2235                                 RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
2236                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2237                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2238                                 GL_LockArrays(0, 0);
2239                         }
2240                 }
2241                 if (dofogpass)
2242                 {
2243                         // if this is opaque use alpha blend which will darken the earlier
2244                         // passes cheaply.
2245                         //
2246                         // if this is an alpha blended material, all the earlier passes
2247                         // were darkened by fog already, so we only need to add the fog
2248                         // color ontop through the fog mask texture
2249                         //
2250                         // if this is an additive blended material, all the earlier passes
2251                         // were darkened by fog already, and we should not add fog color
2252                         // (because the background was not darkened, there is no fog color
2253                         // that was lost behind it).
2254                         if (fogallpasses)
2255                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2256                         else
2257                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2258                         GL_DepthMask(false);
2259                         memset(&m, 0, sizeof(m));
2260                         m.tex[0] = R_GetTexture(texture->skin.fog);
2261                         if (waterscrolling)
2262                                 m.texmatrix[0] = r_waterscrollmatrix;
2263                         R_Mesh_State(&m);
2264                         r = fogcolor[0];
2265                         g = fogcolor[1];
2266                         b = fogcolor[2];
2267                         a = texture->currentalpha;
2268                         applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2269                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2270                         {
2271                                 surface = texturesurfacelist[texturesurfaceindex];
2272                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2273                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2274                                 R_Mesh_ColorPointer(varray_color4f);
2275                                 //RSurf_FogPassColors_Vertex3f_Color4f((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex), varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], texture->currentalpha, 1, surface->num_vertices, modelorg);
2276                                 if (!surface->lightmaptexture && surface->groupmesh->data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
2277                                 {
2278                                         for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
2279                                         {
2280                                                 VectorSubtract(v, modelorg, diff);
2281                                                 f = exp(fogdensity/DotProduct(diff, diff));
2282                                                 c[0] = r;
2283                                                 c[1] = g;
2284                                                 c[2] = b;
2285                                                 c[3] = (surface->groupmesh->data_lightmapcolor4f + 4 * surface->num_firstvertex)[i*4+3] * f * a;
2286                                         }
2287                                 }
2288                                 else
2289                                 {
2290                                         for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (varray_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
2291                                         {
2292                                                 VectorSubtract(v, modelorg, diff);
2293                                                 f = exp(fogdensity/DotProduct(diff, diff));
2294                                                 c[0] = r;
2295                                                 c[1] = g;
2296                                                 c[2] = b;
2297                                                 c[3] = f * a;
2298                                         }
2299                                 }
2300                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2301                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2302                                 GL_LockArrays(0, 0);
2303                         }
2304                 }
2305         }
2306         if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
2307                 qglEnable(GL_CULL_FACE);
2308 }
2309
2310 static void RSurfShader_Transparent_Callback(const void *calldata1, int calldata2)
2311 {
2312         const entity_render_t *ent = calldata1;
2313         const msurface_t *surface = ent->model->data_surfaces + calldata2;
2314         vec3_t modelorg;
2315         texture_t *texture;
2316
2317         texture = surface->texture;
2318         if (texture->basematerialflags & MATERIALFLAG_SKY)
2319                 return; // transparent sky is too difficult
2320         R_UpdateTextureInfo(ent, texture);
2321
2322         R_Mesh_Matrix(&ent->matrix);
2323         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
2324         R_DrawTextureSurfaceList(ent, texture->currentframe, 1, &surface, modelorg);
2325 }
2326
2327 void R_QueueTextureSurfaceList(entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg)
2328 {
2329         int texturesurfaceindex;
2330         const msurface_t *surface;
2331         vec3_t tempcenter, center;
2332         if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
2333         {
2334                 // drawing sky transparently would be too difficult
2335                 if (!(texture->currentmaterialflags & MATERIALFLAG_SKY))
2336                 {
2337                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2338                         {
2339                                 surface = texturesurfacelist[texturesurfaceindex];
2340                                 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
2341                                 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
2342                                 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
2343                                 Matrix4x4_Transform(&ent->matrix, tempcenter, center);
2344                                 R_MeshQueue_AddTransparent(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_vieworigin : center, RSurfShader_Transparent_Callback, ent, surface - ent->model->data_surfaces);
2345                         }
2346                 }
2347         }
2348         else
2349                 R_DrawTextureSurfaceList(ent, texture, texturenumsurfaces, texturesurfacelist, modelorg);
2350 }
2351
2352 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
2353 void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
2354 {
2355         int i, j, f, flagsmask;
2356         msurface_t *surface, **surfacechain;
2357         texture_t *t, *texture;
2358         model_t *model = ent->model;
2359         vec3_t modelorg;
2360         const int maxsurfacelist = 1024;
2361         int numsurfacelist = 0;
2362         const msurface_t *surfacelist[1024];
2363         if (model == NULL)
2364                 return;
2365         R_Mesh_Matrix(&ent->matrix);
2366         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
2367
2368         // update light styles
2369         if (!skysurfaces && model->brushq1.light_styleupdatechains)
2370         {
2371                 for (i = 0;i < model->brushq1.light_styles;i++)
2372                 {
2373                         if (model->brushq1.light_stylevalue[i] != d_lightstylevalue[model->brushq1.light_style[i]])
2374                         {
2375                                 model->brushq1.light_stylevalue[i] = d_lightstylevalue[model->brushq1.light_style[i]];
2376                                 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
2377                                         for (;(surface = *surfacechain);surfacechain++)
2378                                                 surface->cached_dlight = true;
2379                         }
2380                 }
2381         }
2382
2383         R_UpdateAllTextureInfo(ent);
2384         flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
2385         f = 0;
2386         t = NULL;
2387         texture = NULL;
2388         numsurfacelist = 0;
2389         if (ent == r_refdef.worldentity)
2390         {
2391                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
2392                 {
2393                         if (!r_worldsurfacevisible[j])
2394                                 continue;
2395                         if (t != surface->texture)
2396                         {
2397                                 if (numsurfacelist)
2398                                 {
2399                                         R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
2400                                         numsurfacelist = 0;
2401                                 }
2402                                 t = surface->texture;
2403                                 texture = t->currentframe;
2404                                 f = texture->currentmaterialflags & flagsmask;
2405                         }
2406                         if (f && surface->num_triangles)
2407                         {
2408                                 // if lightmap parameters changed, rebuild lightmap texture
2409                                 if (surface->cached_dlight && surface->lightmapinfo->samples)
2410                                         R_BuildLightMap(ent, surface);
2411                                 // add face to draw list
2412                                 surfacelist[numsurfacelist++] = surface;
2413                                 if (numsurfacelist >= maxsurfacelist)
2414                                 {
2415                                         R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
2416                                         numsurfacelist = 0;
2417                                 }
2418                         }
2419                 }
2420         }
2421         else
2422         {
2423                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
2424                 {
2425                         if (t != surface->texture)
2426                         {
2427                                 if (numsurfacelist)
2428                                 {
2429                                         R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
2430                                         numsurfacelist = 0;
2431                                 }
2432                                 t = surface->texture;
2433                                 texture = t->currentframe;
2434                                 f = texture->currentmaterialflags & flagsmask;
2435                         }
2436                         if (f && surface->num_triangles)
2437                         {
2438                                 // if lightmap parameters changed, rebuild lightmap texture
2439                                 if (surface->cached_dlight && surface->lightmapinfo->samples)
2440                                         R_BuildLightMap(ent, surface);
2441                                 // add face to draw list
2442                                 surfacelist[numsurfacelist++] = surface;
2443                                 if (numsurfacelist >= maxsurfacelist)
2444                                 {
2445                                         R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
2446                                         numsurfacelist = 0;
2447                                 }
2448                         }
2449                 }
2450         }
2451         if (numsurfacelist)
2452                 R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
2453 }
2454