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