]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rmain.c
gl_combine cvar is no longer saved
[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", ENGINE_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 }
1486
1487 void R_UpdateAllTextureInfo(entity_render_t *ent)
1488 {
1489         int i;
1490         if (ent->model)
1491                 for (i = 0;i < ent->model->num_textures;i++)
1492                         R_UpdateTextureInfo(ent, ent->model->data_textures + i);
1493 }
1494
1495 float *rsurface_vertex3f;
1496 float *rsurface_svector3f;
1497 float *rsurface_tvector3f;
1498 float *rsurface_normal3f;
1499 float *rsurface_lightmapcolor4f;
1500
1501 void RSurf_SetVertexPointer(const entity_render_t *ent, const texture_t *texture, const msurface_t *surface, const vec3_t modelorg)
1502 {
1503         int i, j;
1504         float center[3], forward[3], right[3], up[3], v[4][3];
1505         matrix4x4_t matrix1, imatrix1;
1506         if ((ent->frameblend[0].lerp != 1 || ent->frameblend[0].frame != 0) && (surface->groupmesh->data_morphvertex3f || surface->groupmesh->data_vertexboneweights))
1507         {
1508                 rsurface_vertex3f = varray_vertex3f;
1509                 rsurface_svector3f = NULL;
1510                 rsurface_tvector3f = NULL;
1511                 rsurface_normal3f = NULL;
1512                 Mod_Alias_GetMesh_Vertex3f(ent->model, ent->frameblend, surface->groupmesh, rsurface_vertex3f);
1513         }
1514         else
1515         {
1516                 rsurface_vertex3f = surface->groupmesh->data_vertex3f;
1517                 rsurface_svector3f = surface->groupmesh->data_svector3f;
1518                 rsurface_tvector3f = surface->groupmesh->data_tvector3f;
1519                 rsurface_normal3f = surface->groupmesh->data_normal3f;
1520         }
1521         if (texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE2)
1522         {
1523                 if (!rsurface_svector3f)
1524                 {
1525                         rsurface_svector3f = varray_svector3f;
1526                         rsurface_tvector3f = varray_tvector3f;
1527                         rsurface_normal3f = varray_normal3f;
1528                         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);
1529                 }
1530                 // a single autosprite surface can contain multiple sprites...
1531                 VectorClear(forward);
1532                 VectorClear(right);
1533                 VectorSet(up, 0, 0, 1);
1534                 for (j = 0;j < surface->num_vertices - 3;j += 4)
1535                 {
1536                         VectorClear(center);
1537                         for (i = 0;i < 4;i++)
1538                                 VectorAdd(center, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
1539                         VectorScale(center, 0.25f, center);
1540                         // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out?
1541                         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);
1542                         Matrix4x4_Invert_Simple(&imatrix1, &matrix1);
1543                         for (i = 0;i < 4;i++)
1544                                 Matrix4x4_Transform(&imatrix1, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, v[i]);
1545                         forward[0] = modelorg[0] - center[0];
1546                         forward[1] = modelorg[1] - center[1];
1547                         VectorNormalize(forward);
1548                         right[0] = forward[1];
1549                         right[1] = -forward[0];
1550                         for (i = 0;i < 4;i++)
1551                                 VectorMAMAMAM(1, center, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (surface->num_firstvertex+i+j) * 3);
1552                 }
1553                 rsurface_vertex3f = varray_vertex3f;
1554                 rsurface_svector3f = NULL;
1555                 rsurface_tvector3f = NULL;
1556                 rsurface_normal3f = NULL;
1557         }
1558         else if (texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE)
1559         {
1560                 if (!rsurface_svector3f)
1561                 {
1562                         rsurface_svector3f = varray_svector3f;
1563                         rsurface_tvector3f = varray_tvector3f;
1564                         rsurface_normal3f = varray_normal3f;
1565                         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);
1566                 }
1567                 Matrix4x4_Transform(&ent->inversematrix, r_viewforward, forward);
1568                 Matrix4x4_Transform(&ent->inversematrix, r_viewright, right);
1569                 Matrix4x4_Transform(&ent->inversematrix, r_viewup, up);
1570                 // a single autosprite surface can contain multiple sprites...
1571                 for (j = 0;j < surface->num_vertices - 3;j += 4)
1572                 {
1573                         VectorClear(center);
1574                         for (i = 0;i < 4;i++)
1575                                 VectorAdd(center, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
1576                         VectorScale(center, 0.25f, center);
1577                         // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out?
1578                         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);
1579                         Matrix4x4_Invert_Simple(&imatrix1, &matrix1);
1580                         for (i = 0;i < 4;i++)
1581                                 Matrix4x4_Transform(&imatrix1, (rsurface_vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, v[i]);
1582                         for (i = 0;i < 4;i++)
1583                                 VectorMAMAMAM(1, center, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (surface->num_firstvertex+i+j) * 3);
1584                 }
1585                 rsurface_vertex3f = varray_vertex3f;
1586                 rsurface_svector3f = NULL;
1587                 rsurface_tvector3f = NULL;
1588                 rsurface_normal3f = NULL;
1589         }
1590         R_Mesh_VertexPointer(rsurface_vertex3f);
1591 }
1592
1593 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)
1594 {
1595         int i;
1596         float f;
1597         float *v, *c, *c2;
1598         vec3_t diff;
1599         if (lightmodel)
1600         {
1601                 vec4_t ambientcolor4f;
1602                 vec3_t diffusecolor;
1603                 vec3_t diffusenormal;
1604                 if (R_LightModel(ambientcolor4f, diffusecolor, diffusenormal, ent, r, g, b, a, false))
1605                 {
1606                         rsurface_lightmapcolor4f = varray_color4f;
1607                         if (rsurface_normal3f == NULL)
1608                         {
1609                                 rsurface_normal3f = varray_normal3f;
1610                                 Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_vertex3f, surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle, rsurface_normal3f);
1611                         }
1612                         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);
1613                         r = 1;
1614                         g = 1;
1615                         b = 1;
1616                         a = 1;
1617                         applycolor = false;
1618                 }
1619                 else
1620                 {
1621                         r = ambientcolor4f[0];
1622                         g = ambientcolor4f[1];
1623                         b = ambientcolor4f[2];
1624                         a = ambientcolor4f[3];
1625                         rsurface_lightmapcolor4f = NULL;
1626                 }
1627         }
1628         else if (vertexlight)
1629         {
1630                 if (surface->lightmapinfo)
1631                 {
1632                         rsurface_lightmapcolor4f = varray_color4f;
1633                         for (i = 0, c = rsurface_lightmapcolor4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
1634                         {
1635                                 const qbyte *lm = surface->lightmapinfo->samples + (surface->groupmesh->data_lightmapoffsets + surface->num_firstvertex)[i];
1636                                 float scale = d_lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
1637                                 VectorScale(lm, scale, c);
1638                                 if (surface->lightmapinfo->styles[1] != 255)
1639                                 {
1640                                         int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
1641                                         lm += size3;
1642                                         scale = d_lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
1643                                         VectorMA(c, scale, lm, c);
1644                                         if (surface->lightmapinfo->styles[2] != 255)
1645                                         {
1646                                                 lm += size3;
1647                                                 scale = d_lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
1648                                                 VectorMA(c, scale, lm, c);
1649                                                 if (surface->lightmapinfo->styles[3] != 255)
1650                                                 {
1651                                                         lm += size3;
1652                                                         scale = d_lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
1653                                                         VectorMA(c, scale, lm, c);
1654                                                 }
1655                                         }
1656                                 }
1657                         }
1658                 }
1659                 else
1660                         rsurface_lightmapcolor4f = surface->groupmesh->data_lightmapcolor4f;
1661         }
1662         else
1663                 rsurface_lightmapcolor4f = NULL;
1664         if (applyfog)
1665         {
1666                 if (rsurface_lightmapcolor4f)
1667                 {
1668                         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)
1669                         {
1670                                 VectorSubtract(v, modelorg, diff);
1671                                 f = 1 - exp(fogdensity/DotProduct(diff, diff));
1672                                 c2[0] = c[0] * f;
1673                                 c2[1] = c[1] * f;
1674                                 c2[2] = c[2] * f;
1675                                 c2[3] = c[3];
1676                         }
1677                 }
1678                 else
1679                 {
1680                         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)
1681                         {
1682                                 VectorSubtract(v, modelorg, diff);
1683                                 f = 1 - exp(fogdensity/DotProduct(diff, diff));
1684                                 c2[0] = f;
1685                                 c2[1] = f;
1686                                 c2[2] = f;
1687                                 c2[3] = 1;
1688                         }
1689                 }
1690                 rsurface_lightmapcolor4f = varray_color4f;
1691         }
1692         if (applycolor && rsurface_lightmapcolor4f)
1693         {
1694                 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)
1695                 {
1696                         c2[0] = c[0] * r;
1697                         c2[1] = c[1] * g;
1698                         c2[2] = c[2] * b;
1699                         c2[3] = c[3] * a;
1700                 }
1701         }
1702         R_Mesh_ColorPointer(rsurface_lightmapcolor4f);
1703         GL_Color(r, g, b, a);
1704 }
1705
1706
1707 static void R_DrawTextureSurfaceList(const entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg)
1708 {
1709         int i;
1710         int texturesurfaceindex;
1711         const float *v;
1712         float *c;
1713         float diff[3];
1714         float colorpants[3], colorshirt[3];
1715         float f, r, g, b, a, base, colorscale;
1716         const msurface_t *surface;
1717         qboolean dolightmap;
1718         qboolean doambient;
1719         qboolean dodetail;
1720         qboolean doglow;
1721         qboolean dofogpass;
1722         qboolean fogallpasses;
1723         qboolean waterscrolling;
1724         qboolean dopants;
1725         qboolean doshirt;
1726         qboolean dofullbrightpants;
1727         qboolean dofullbrightshirt;
1728         qboolean applycolor;
1729         qboolean lightmodel = false;
1730         rtexture_t *basetexture;
1731         rmeshstate_t m;
1732         if (texture->currentmaterialflags & MATERIALFLAG_NODRAW)
1733                 return;
1734         c_faces += texturenumsurfaces;
1735         // FIXME: identify models using a better check than ent->model->shadowmesh
1736         if (!(ent->effects & EF_FULLBRIGHT) && !ent->model->brush.shadowmesh)
1737                 lightmodel = true;
1738         // gl_lightmaps debugging mode skips normal texturing
1739         if (gl_lightmaps.integer)
1740         {
1741                 GL_BlendFunc(GL_ONE, GL_ZERO);
1742                 GL_DepthMask(true);
1743                 GL_DepthTest(true);
1744                 qglDisable(GL_CULL_FACE);
1745                 GL_Color(1, 1, 1, 1);
1746                 memset(&m, 0, sizeof(m));
1747                 R_Mesh_State(&m);
1748                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1749                 {
1750                         surface = texturesurfacelist[texturesurfaceindex];
1751                         R_Mesh_TexBind(0, R_GetTexture(surface->lightmaptexture));
1752                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f);
1753                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1754                         RSurf_SetColorPointer(ent, surface, modelorg, 1, 1, 1, 1, lightmodel, !surface->lightmaptexture, false, false);
1755                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1756                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
1757                         GL_LockArrays(0, 0);
1758                 }
1759                 qglEnable(GL_CULL_FACE);
1760                 return;
1761         }
1762         GL_DepthTest(!(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
1763         GL_DepthMask(!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT));
1764         if (texture->currentmaterialflags & MATERIALFLAG_ADD)
1765                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1766         else if (texture->currentmaterialflags & MATERIALFLAG_ALPHA)
1767                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1768         else
1769                 GL_BlendFunc(GL_ONE, GL_ZERO);
1770         // water waterscrolling in texture matrix
1771         waterscrolling = (texture->currentmaterialflags & MATERIALFLAG_WATER) && r_waterscroll.value != 0;
1772         if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
1773                 qglDisable(GL_CULL_FACE);
1774         if (texture->currentmaterialflags & MATERIALFLAG_SKY)
1775         {
1776                 if (skyrendernow)
1777                 {
1778                         skyrendernow = false;
1779                         if (skyrendermasked)
1780                                 R_Sky();
1781                 }
1782                 // LordHavoc: HalfLife maps have freaky skypolys...
1783                 //if (!ent->model->brush.ishlbsp)
1784                 {
1785                         R_Mesh_Matrix(&ent->matrix);
1786                         GL_Color(fogcolor[0], fogcolor[1], fogcolor[2], 1);
1787                         if (skyrendermasked)
1788                         {
1789                                 // depth-only (masking)
1790                                 GL_ColorMask(0,0,0,0);
1791                                 // just to make sure that braindead drivers don't draw anything
1792                                 // despite that colormask...
1793                                 GL_BlendFunc(GL_ZERO, GL_ONE);
1794                         }
1795                         else
1796                         {
1797                                 // fog sky
1798                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1799                         }
1800                         GL_DepthMask(true);
1801                         GL_DepthTest(true);
1802                         memset(&m, 0, sizeof(m));
1803                         R_Mesh_State(&m);
1804                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1805                         {
1806                                 surface = texturesurfacelist[texturesurfaceindex];
1807                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1808                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1809                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
1810                                 GL_LockArrays(0, 0);
1811                         }
1812                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1813                 }
1814         }
1815         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)
1816         {
1817                 // NVIDIA Geforce3 distortion texture shader on water
1818                 float args[4] = {0.05f,0,0,0.04f};
1819                 memset(&m, 0, sizeof(m));
1820                 m.tex[0] = R_GetTexture(r_texture_distorttexture[(int)(r_refdef.time * 16)&63]);
1821                 m.tex[1] = R_GetTexture(texture->skin.base);
1822                 m.texcombinergb[0] = GL_REPLACE;
1823                 m.texcombinergb[1] = GL_REPLACE;
1824                 Matrix4x4_CreateFromQuakeEntity(&m.texmatrix[0], 0, 0, 0, 0, 0, 0, r_watershader.value);
1825                 m.texmatrix[1] = r_waterscrollmatrix;
1826                 R_Mesh_State(&m);
1827
1828                 GL_Color(1, 1, 1, texture->currentalpha);
1829                 GL_ActiveTexture(0);
1830                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
1831                 GL_ActiveTexture(1);
1832                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_OFFSET_TEXTURE_2D_NV);
1833                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB);
1834                 qglTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, &args[0]);
1835                 qglEnable(GL_TEXTURE_SHADER_NV);
1836
1837                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1838                 {
1839                         surface = texturesurfacelist[texturesurfaceindex];
1840                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1841                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
1842                         R_Mesh_TexCoordPointer(1, 2, surface->groupmesh->data_texcoordtexture2f);
1843                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1844                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
1845                         GL_LockArrays(0, 0);
1846                 }
1847
1848                 qglDisable(GL_TEXTURE_SHADER_NV);
1849                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
1850                 GL_ActiveTexture(0);
1851         }
1852         else if (texture->currentmaterialflags & (MATERIALFLAG_WATER | MATERIALFLAG_WALL))
1853         {
1854                 // normal surface (wall or water)
1855                 dolightmap = !(texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT);
1856                 doambient = r_ambient.value >= (1/64.0f);
1857                 dodetail = r_detailtextures.integer && texture->skin.detail != NULL && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT);
1858                 doglow = texture->skin.glow != NULL;
1859                 dofogpass = fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_ADD);
1860                 fogallpasses = fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT);
1861                 if (ent->colormap >= 0)
1862                 {
1863                         int b;
1864                         qbyte *bcolor;
1865                         basetexture = texture->skin.base;
1866                         dopants = texture->skin.pants != NULL;
1867                         doshirt = texture->skin.shirt != NULL;
1868                         // 128-224 are backwards ranges
1869                         b = (ent->colormap & 0xF) << 4;b += (b >= 128 && b < 224) ? 4 : 12;
1870                         dofullbrightpants = b >= 224;
1871                         bcolor = (qbyte *) (&palette_complete[b]);
1872                         VectorScale(bcolor, (1.0f / 255.0f), colorpants);
1873                         // 128-224 are backwards ranges
1874                         b = (ent->colormap & 0xF0);b += (b >= 128 && b < 224) ? 4 : 12;
1875                         dofullbrightshirt = b >= 224;
1876                         bcolor = (qbyte *) (&palette_complete[b]);
1877                         VectorScale(bcolor, (1.0f / 255.0f), colorshirt);
1878                 }
1879                 else
1880                 {
1881                         basetexture = texture->skin.merged ? texture->skin.merged : texture->skin.base;
1882                         dopants = false;
1883                         doshirt = false;
1884                         dofullbrightshirt = false;
1885                         dofullbrightpants = false;
1886                 }
1887                 if (dolightmap && r_textureunits.integer >= 2 && gl_combine.integer)
1888                 {
1889                         memset(&m, 0, sizeof(m));
1890                         m.tex[1] = R_GetTexture(basetexture);
1891                         if (waterscrolling)
1892                                 m.texmatrix[1] = r_waterscrollmatrix;
1893                         m.texrgbscale[1] = 2;
1894                         m.pointer_color = varray_color4f;
1895                         R_Mesh_State(&m);
1896                         // transparent is not affected by r_lightmapintensity
1897                         if (!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1898                                 colorscale = r_lightmapintensity;
1899                         else
1900                                 colorscale = 1;
1901                         r = ent->colormod[0] * colorscale;
1902                         g = ent->colormod[1] * colorscale;
1903                         b = ent->colormod[2] * colorscale;
1904                         a = texture->currentalpha;
1905                         base = r_ambient.value * (1.0f / 64.0f);
1906                         // q3bsp has no lightmap updates, so the lightstylevalue that
1907                         // would normally be baked into the lightmaptexture must be
1908                         // applied to the color
1909                         if (ent->model->brushq3.data_lightmaps)
1910                         {
1911                                 float scale = d_lightstylevalue[0] * (1.0f / 128.0f);
1912                                 r *= scale;
1913                                 g *= scale;
1914                                 b *= scale;
1915                         }
1916                         applycolor = r != 1 || g != 1 || b != 1 || a != 1;
1917                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1918                         {
1919                                 surface = texturesurfacelist[texturesurfaceindex];
1920                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1921                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f);
1922                                 R_Mesh_TexCoordPointer(1, 2, surface->groupmesh->data_texcoordtexture2f);
1923                                 if (surface->lightmaptexture)
1924                                         R_Mesh_TexBind(0, R_GetTexture(surface->lightmaptexture));
1925                                 else
1926                                         R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
1927                                 RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, lightmodel, !surface->lightmaptexture, applycolor, fogallpasses);
1928                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1929                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
1930                                 GL_LockArrays(0, 0);
1931                         }
1932                 }
1933                 else if (dolightmap && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT) && !lightmodel)
1934                 {
1935                         // single texture
1936                         GL_BlendFunc(GL_ONE, GL_ZERO);
1937                         GL_DepthMask(true);
1938                         GL_Color(1, 1, 1, 1);
1939                         memset(&m, 0, sizeof(m));
1940                         R_Mesh_State(&m);
1941                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1942                         {
1943                                 surface = texturesurfacelist[texturesurfaceindex];
1944                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1945                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordlightmap2f);
1946                                 if (surface->lightmaptexture)
1947                                 {
1948                                         R_Mesh_TexBind(0, R_GetTexture(surface->lightmaptexture));
1949                                         R_Mesh_ColorPointer(NULL);
1950                                 }
1951                                 else
1952                                 {
1953                                         R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
1954                                         R_Mesh_ColorPointer(surface->groupmesh->data_lightmapcolor4f);
1955                                 }
1956                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1957                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
1958                                 GL_LockArrays(0, 0);
1959                         }
1960                         GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
1961                         GL_DepthMask(false);
1962                         GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1);
1963                         memset(&m, 0, sizeof(m));
1964                         m.tex[0] = R_GetTexture(basetexture);
1965                         if (waterscrolling)
1966                                 m.texmatrix[0] = r_waterscrollmatrix;
1967                         R_Mesh_State(&m);
1968                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1969                         {
1970                                 surface = texturesurfacelist[texturesurfaceindex];
1971                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
1972                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
1973                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
1974                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
1975                                 GL_LockArrays(0, 0);
1976                         }
1977                 }
1978                 else
1979                 {
1980                         memset(&m, 0, sizeof(m));
1981                         m.tex[0] = R_GetTexture(basetexture);
1982                         if (waterscrolling)
1983                                 m.texmatrix[0] = r_waterscrollmatrix;
1984                         m.pointer_color = varray_color4f;
1985                         colorscale = 2;
1986                         if (gl_combine.integer)
1987                         {
1988                                 m.texrgbscale[0] = 2;
1989                                 colorscale = 1;
1990                         }
1991                         // transparent is not affected by r_lightmapintensity
1992                         if (!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1993                                 colorscale *= r_lightmapintensity;
1994                         R_Mesh_State(&m);
1995                         r = ent->colormod[0] * colorscale;
1996                         g = ent->colormod[1] * colorscale;
1997                         b = ent->colormod[2] * colorscale;
1998                         a = texture->currentalpha;
1999                         if (dolightmap)
2000                         {
2001                                 // q3bsp has no lightmap updates, so the lightstylevalue that
2002                                 // would normally be baked into the lightmaptexture must be
2003                                 // applied to the color
2004                                 if (ent->model->brushq3.data_lightmaps)
2005                                 {
2006                                         float scale = d_lightstylevalue[0] * (1.0f / 128.0f);
2007                                         r *= scale;
2008                                         g *= scale;
2009                                         b *= scale;
2010                                 }
2011                                 applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2012                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2013                                 {
2014                                         surface = texturesurfacelist[texturesurfaceindex];
2015                                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2016                                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2017                                         RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, lightmodel, true, applycolor, fogallpasses);
2018                                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2019                                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2020                                         GL_LockArrays(0, 0);
2021                                 }
2022                         }
2023                         else
2024                         {
2025                                 applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2026                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2027                                 {
2028                                         surface = texturesurfacelist[texturesurfaceindex];
2029                                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2030                                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2031                                         RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
2032                                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2033                                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2034                                         GL_LockArrays(0, 0);
2035                                 }
2036                         }
2037                 }
2038                 if (dopants)
2039                 {
2040                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2041                         memset(&m, 0, sizeof(m));
2042                         m.tex[0] = R_GetTexture(texture->skin.pants);
2043                         if (waterscrolling)
2044                                 m.texmatrix[0] = r_waterscrollmatrix;
2045                         m.pointer_color = varray_color4f;
2046                         colorscale = 1;
2047                         if (gl_combine.integer)
2048                         {
2049                                 m.texrgbscale[0] = 2;
2050                                 colorscale *= 0.5f;
2051                         }
2052                         // transparent is not affected by r_lightmapintensity
2053                         if (!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
2054                                 colorscale *= r_lightmapintensity;
2055                         R_Mesh_State(&m);
2056                         r = ent->colormod[0] * colorpants[0] * colorscale;
2057                         g = ent->colormod[1] * colorpants[1] * colorscale;
2058                         b = ent->colormod[2] * colorpants[2] * colorscale;
2059                         a = texture->currentalpha;
2060                         if (dolightmap && !dofullbrightpants)
2061                         {
2062                                 // q3bsp has no lightmap updates, so the lightstylevalue that
2063                                 // would normally be baked into the lightmaptexture must be
2064                                 // applied to the color
2065                                 if (ent->model->brushq3.data_lightmaps)
2066                                 {
2067                                         float scale = d_lightstylevalue[0] * (1.0f / 128.0f);
2068                                         r *= scale;
2069                                         g *= scale;
2070                                         b *= scale;
2071                                 }
2072                                 applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2073                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2074                                 {
2075                                         surface = texturesurfacelist[texturesurfaceindex];
2076                                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2077                                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2078                                         RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, lightmodel, true, applycolor, fogallpasses);
2079                                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2080                                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2081                                         GL_LockArrays(0, 0);
2082                                 }
2083                         }
2084                         else
2085                         {
2086                                 applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2087                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2088                                 {
2089                                         surface = texturesurfacelist[texturesurfaceindex];
2090                                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2091                                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2092                                         RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
2093                                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2094                                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2095                                         GL_LockArrays(0, 0);
2096                                 }
2097                         }
2098                 }
2099                 if (doshirt)
2100                 {
2101                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2102                         memset(&m, 0, sizeof(m));
2103                         m.tex[0] = R_GetTexture(texture->skin.shirt);
2104                         if (waterscrolling)
2105                                 m.texmatrix[0] = r_waterscrollmatrix;
2106                         m.pointer_color = varray_color4f;
2107                         colorscale = 1;
2108                         if (gl_combine.integer)
2109                         {
2110                                 m.texrgbscale[0] = 2;
2111                                 colorscale *= 0.5f;
2112                         }
2113                         // transparent is not affected by r_lightmapintensity
2114                         if (!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
2115                                 colorscale *= r_lightmapintensity;
2116                         R_Mesh_State(&m);
2117                         r = ent->colormod[0] * colorshirt[0] * colorscale;
2118                         g = ent->colormod[1] * colorshirt[1] * colorscale;
2119                         b = ent->colormod[2] * colorshirt[2] * colorscale;
2120                         a = texture->currentalpha;
2121                         if (dolightmap && !dofullbrightshirt)
2122                         {
2123                                 // q3bsp has no lightmap updates, so the lightstylevalue that
2124                                 // would normally be baked into the lightmaptexture must be
2125                                 // applied to the color
2126                                 if (ent->model->brushq3.data_lightmaps)
2127                                 {
2128                                         float scale = d_lightstylevalue[0] * (1.0f / 128.0f);
2129                                         r *= scale;
2130                                         g *= scale;
2131                                         b *= scale;
2132                                 }
2133                                 applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2134                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2135                                 {
2136                                         surface = texturesurfacelist[texturesurfaceindex];
2137                                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2138                                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2139                                         RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, lightmodel, true, applycolor, fogallpasses);
2140                                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2141                                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2142                                         GL_LockArrays(0, 0);
2143                                 }
2144                         }
2145                         else
2146                         {
2147                                 applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2148                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2149                                 {
2150                                         surface = texturesurfacelist[texturesurfaceindex];
2151                                         RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2152                                         R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2153                                         RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
2154                                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2155                                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2156                                         GL_LockArrays(0, 0);
2157                                 }
2158                         }
2159                 }
2160                 if (doambient)
2161                 {
2162                         doambient = false;
2163                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2164                         GL_DepthMask(false);
2165                         memset(&m, 0, sizeof(m));
2166                         m.tex[0] = R_GetTexture(texture->skin.base);
2167                         if (waterscrolling)
2168                                 m.texmatrix[0] = r_waterscrollmatrix;
2169                         m.pointer_color = varray_color4f;
2170                         colorscale = 1;
2171                         if (gl_combine.integer)
2172                         {
2173                                 m.texrgbscale[0] = 2;
2174                                 colorscale *= 0.5f;
2175                         }
2176                         R_Mesh_State(&m);
2177                         base = r_ambient.value * (1.0f / 64.0f);
2178                         r = ent->colormod[0] * colorscale * base;
2179                         g = ent->colormod[1] * colorscale * base;
2180                         b = ent->colormod[2] * colorscale * base;
2181                         a = texture->currentalpha;
2182                         applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2183                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2184                         {
2185                                 surface = texturesurfacelist[texturesurfaceindex];
2186                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2187                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2188                                 RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
2189                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2190                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2191                                 GL_LockArrays(0, 0);
2192                         }
2193                 }
2194                 if (dodetail)
2195                 {
2196                         GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
2197                         GL_DepthMask(false);
2198                         GL_Color(1, 1, 1, 1);
2199                         memset(&m, 0, sizeof(m));
2200                         m.tex[0] = R_GetTexture(texture->skin.detail);
2201                         R_Mesh_State(&m);
2202                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2203                         {
2204                                 surface = texturesurfacelist[texturesurfaceindex];
2205                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2206                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoorddetail2f);
2207                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2208                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2209                                 GL_LockArrays(0, 0);
2210                         }
2211                 }
2212                 if (doglow)
2213                 {
2214                         // if glow was not already done using multitexture, do it now.
2215                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2216                         GL_DepthMask(false);
2217                         memset(&m, 0, sizeof(m));
2218                         m.tex[0] = R_GetTexture(texture->skin.glow);
2219                         if (waterscrolling)
2220                                 m.texmatrix[0] = r_waterscrollmatrix;
2221                         m.pointer_color = varray_color4f;
2222                         R_Mesh_State(&m);
2223                         colorscale = 1;
2224                         r = ent->colormod[0] * colorscale;
2225                         g = ent->colormod[1] * colorscale;
2226                         b = ent->colormod[2] * colorscale;
2227                         a = texture->currentalpha;
2228                         applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2229                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2230                         {
2231                                 surface = texturesurfacelist[texturesurfaceindex];
2232                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2233                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2234                                 RSurf_SetColorPointer(ent, surface, modelorg, r, g, b, a, false, false, applycolor, fogallpasses);
2235                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2236                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2237                                 GL_LockArrays(0, 0);
2238                         }
2239                 }
2240                 if (dofogpass)
2241                 {
2242                         // if this is opaque use alpha blend which will darken the earlier
2243                         // passes cheaply.
2244                         //
2245                         // if this is an alpha blended material, all the earlier passes
2246                         // were darkened by fog already, so we only need to add the fog
2247                         // color ontop through the fog mask texture
2248                         //
2249                         // if this is an additive blended material, all the earlier passes
2250                         // were darkened by fog already, and we should not add fog color
2251                         // (because the background was not darkened, there is no fog color
2252                         // that was lost behind it).
2253                         if (fogallpasses)
2254                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2255                         else
2256                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2257                         GL_DepthMask(false);
2258                         memset(&m, 0, sizeof(m));
2259                         m.tex[0] = R_GetTexture(texture->skin.fog);
2260                         if (waterscrolling)
2261                                 m.texmatrix[0] = r_waterscrollmatrix;
2262                         R_Mesh_State(&m);
2263                         r = fogcolor[0];
2264                         g = fogcolor[1];
2265                         b = fogcolor[2];
2266                         a = texture->currentalpha;
2267                         applycolor = r != 1 || g != 1 || b != 1 || a != 1;
2268                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2269                         {
2270                                 surface = texturesurfacelist[texturesurfaceindex];
2271                                 RSurf_SetVertexPointer(ent, texture, surface, modelorg);
2272                                 R_Mesh_TexCoordPointer(0, 2, surface->groupmesh->data_texcoordtexture2f);
2273                                 R_Mesh_ColorPointer(varray_color4f);
2274                                 //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);
2275                                 if (!surface->lightmaptexture && surface->groupmesh->data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
2276                                 {
2277                                         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)
2278                                         {
2279                                                 VectorSubtract(v, modelorg, diff);
2280                                                 f = exp(fogdensity/DotProduct(diff, diff));
2281                                                 c[0] = r;
2282                                                 c[1] = g;
2283                                                 c[2] = b;
2284                                                 c[3] = (surface->groupmesh->data_lightmapcolor4f + 4 * surface->num_firstvertex)[i*4+3] * f * a;
2285                                         }
2286                                 }
2287                                 else
2288                                 {
2289                                         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)
2290                                         {
2291                                                 VectorSubtract(v, modelorg, diff);
2292                                                 f = exp(fogdensity/DotProduct(diff, diff));
2293                                                 c[0] = r;
2294                                                 c[1] = g;
2295                                                 c[2] = b;
2296                                                 c[3] = f * a;
2297                                         }
2298                                 }
2299                                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
2300                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
2301                                 GL_LockArrays(0, 0);
2302                         }
2303                 }
2304         }
2305         if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
2306                 qglEnable(GL_CULL_FACE);
2307 }
2308
2309 static void RSurfShader_Transparent_Callback(const void *calldata1, int calldata2)
2310 {
2311         const entity_render_t *ent = calldata1;
2312         const msurface_t *surface = ent->model->data_surfaces + calldata2;
2313         vec3_t modelorg;
2314         texture_t *texture;
2315
2316         texture = surface->texture;
2317         if (texture->basematerialflags & MATERIALFLAG_SKY)
2318                 return; // transparent sky is too difficult
2319         R_UpdateTextureInfo(ent, texture);
2320
2321         R_Mesh_Matrix(&ent->matrix);
2322         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
2323         R_DrawTextureSurfaceList(ent, texture->currentframe, 1, &surface, modelorg);
2324 }
2325
2326 void R_QueueTextureSurfaceList(entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg)
2327 {
2328         int texturesurfaceindex;
2329         const msurface_t *surface;
2330         vec3_t tempcenter, center;
2331         if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
2332         {
2333                 // drawing sky transparently would be too difficult
2334                 if (!(texture->currentmaterialflags & MATERIALFLAG_SKY))
2335                 {
2336                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2337                         {
2338                                 surface = texturesurfacelist[texturesurfaceindex];
2339                                 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
2340                                 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
2341                                 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
2342                                 Matrix4x4_Transform(&ent->matrix, tempcenter, center);
2343                                 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : center, RSurfShader_Transparent_Callback, ent, surface - ent->model->data_surfaces);
2344                         }
2345                 }
2346         }
2347         else
2348                 R_DrawTextureSurfaceList(ent, texture, texturenumsurfaces, texturesurfacelist, modelorg);
2349 }
2350
2351 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
2352 void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
2353 {
2354         int i, j, f, flagsmask;
2355         msurface_t *surface, **surfacechain;
2356         texture_t *t, *texture;
2357         model_t *model = ent->model;
2358         vec3_t modelorg;
2359         const int maxsurfacelist = 1024;
2360         int numsurfacelist = 0;
2361         const msurface_t *surfacelist[1024];
2362         if (model == NULL)
2363                 return;
2364         R_Mesh_Matrix(&ent->matrix);
2365         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
2366
2367         // update light styles
2368         if (!skysurfaces && model->brushq1.light_styleupdatechains)
2369         {
2370                 for (i = 0;i < model->brushq1.light_styles;i++)
2371                 {
2372                         if (model->brushq1.light_stylevalue[i] != d_lightstylevalue[model->brushq1.light_style[i]])
2373                         {
2374                                 model->brushq1.light_stylevalue[i] = d_lightstylevalue[model->brushq1.light_style[i]];
2375                                 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
2376                                         for (;(surface = *surfacechain);surfacechain++)
2377                                                 surface->cached_dlight = true;
2378                         }
2379                 }
2380         }
2381
2382         R_UpdateAllTextureInfo(ent);
2383         flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
2384         f = 0;
2385         t = NULL;
2386         texture = NULL;
2387         numsurfacelist = 0;
2388         if (ent == r_refdef.worldentity)
2389         {
2390                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
2391                 {
2392                         if (!r_worldsurfacevisible[j])
2393                                 continue;
2394                         if (t != surface->texture)
2395                         {
2396                                 if (numsurfacelist)
2397                                 {
2398                                         R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
2399                                         numsurfacelist = 0;
2400                                 }
2401                                 t = surface->texture;
2402                                 texture = t->currentframe;
2403                                 f = texture->currentmaterialflags & flagsmask;
2404                         }
2405                         if (f && surface->num_triangles)
2406                         {
2407                                 // if lightmap parameters changed, rebuild lightmap texture
2408                                 if (surface->cached_dlight && surface->lightmapinfo->samples)
2409                                         R_BuildLightMap(ent, surface);
2410                                 // add face to draw list
2411                                 surfacelist[numsurfacelist++] = surface;
2412                                 if (numsurfacelist >= maxsurfacelist)
2413                                 {
2414                                         R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
2415                                         numsurfacelist = 0;
2416                                 }
2417                         }
2418                 }
2419         }
2420         else
2421         {
2422                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
2423                 {
2424                         if (t != surface->texture)
2425                         {
2426                                 if (numsurfacelist)
2427                                 {
2428                                         R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
2429                                         numsurfacelist = 0;
2430                                 }
2431                                 t = surface->texture;
2432                                 texture = t->currentframe;
2433                                 f = texture->currentmaterialflags & flagsmask;
2434                         }
2435                         if (f && surface->num_triangles)
2436                         {
2437                                 // if lightmap parameters changed, rebuild lightmap texture
2438                                 if (surface->cached_dlight && surface->lightmapinfo->samples)
2439                                         R_BuildLightMap(ent, surface);
2440                                 // add face to draw list
2441                                 surfacelist[numsurfacelist++] = surface;
2442                                 if (numsurfacelist >= maxsurfacelist)
2443                                 {
2444                                         R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
2445                                         numsurfacelist = 0;
2446                                 }
2447                         }
2448                 }
2449         }
2450         if (numsurfacelist)
2451                 R_QueueTextureSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
2452 }
2453