2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
26 // used for dlight push checking and other things
31 matrix4x4_t r_identitymatrix;
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;
35 // true during envmap command capture
38 // maximum visible distance (recalculated from world box each frame)
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
45 qboolean r_rtworldshadows;
47 qboolean r_rtdlightshadows;
50 // forces all rendering to draw triangle outlines
67 matrix4x4_t r_view_matrix;
74 // 8.8 fraction of base light value
75 unsigned short d_lightstylevalue[256];
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"};
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"};
95 cvar_t r_textureunits = {0, "r_textureunits", "32"};
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"};
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"};
108 cvar_t developer_texturelogging = {0, "developer_texturelogging", "1"};
110 rtexturepool_t *r_main_texturepool;
111 rtexture_t *r_bloom_texture_screen;
112 rtexture_t *r_bloom_texture_bloom;
113 rtexture_t *r_texture_blanknormalmap;
114 rtexture_t *r_texture_white;
115 rtexture_t *r_texture_black;
116 rtexture_t *r_texture_notexture;
117 rtexture_t *r_texture_whitecube;
118 rtexture_t *r_texture_normalizationcube;
119 rtexture_t *r_texture_detailtextures[NUM_DETAILTEXTURES];
120 rtexture_t *r_texture_distorttexture[64];
122 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
125 for (i = 0;i < verts;i++)
136 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
139 for (i = 0;i < verts;i++)
151 float fog_density, fog_red, fog_green, fog_blue;
153 qboolean oldgl_fogenable;
154 void R_UpdateFog(void)
156 if (gamemode == GAME_NEHAHRA)
158 if (gl_fogenable.integer)
160 oldgl_fogenable = true;
161 fog_density = gl_fogdensity.value;
162 fog_red = gl_fogred.value;
163 fog_green = gl_foggreen.value;
164 fog_blue = gl_fogblue.value;
166 else if (oldgl_fogenable)
168 oldgl_fogenable = false;
177 fogcolor[0] = fog_red = bound(0.0f, fog_red , 1.0f);
178 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
179 fogcolor[2] = fog_blue = bound(0.0f, fog_blue , 1.0f);
184 fogdensity = -4000.0f / (fog_density * fog_density);
185 // fog color was already set
191 // FIXME: move this to client?
194 if (gamemode == GAME_NEHAHRA)
196 Cvar_Set("gl_fogenable", "0");
197 Cvar_Set("gl_fogdensity", "0.2");
198 Cvar_Set("gl_fogred", "0.3");
199 Cvar_Set("gl_foggreen", "0.3");
200 Cvar_Set("gl_fogblue", "0.3");
202 fog_density = fog_red = fog_green = fog_blue = 0.0f;
205 // FIXME: move this to client?
206 void FOG_registercvars(void)
208 if (gamemode == GAME_NEHAHRA)
210 Cvar_RegisterVariable (&gl_fogenable);
211 Cvar_RegisterVariable (&gl_fogdensity);
212 Cvar_RegisterVariable (&gl_fogred);
213 Cvar_RegisterVariable (&gl_foggreen);
214 Cvar_RegisterVariable (&gl_fogblue);
215 Cvar_RegisterVariable (&gl_fogstart);
216 Cvar_RegisterVariable (&gl_fogend);
220 static void R_BuildDetailTextures (void)
223 float vc[3], vx[3], vy[3], vn[3], lightdir[3];
224 #define DETAILRESOLUTION 256
225 qbyte (*data)[DETAILRESOLUTION][4];
226 qbyte (*noise)[DETAILRESOLUTION];
228 // Allocate the buffers dynamically to avoid having such big guys on the stack
229 data = Mem_Alloc(tempmempool, DETAILRESOLUTION * sizeof(*data));
230 noise = Mem_Alloc(tempmempool, DETAILRESOLUTION * sizeof(*noise));
235 VectorNormalize(lightdir);
236 for (i = 0;i < NUM_DETAILTEXTURES;i++)
238 fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4);
239 for (y = 0;y < DETAILRESOLUTION;y++)
241 for (x = 0;x < DETAILRESOLUTION;x++)
245 vc[2] = noise[y][x] * (1.0f / 32.0f);
248 vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f);
251 vy[2] = noise[(y + 1) % DETAILRESOLUTION][x] * (1.0f / 32.0f);
252 VectorSubtract(vx, vc, vx);
253 VectorSubtract(vy, vc, vy);
254 CrossProduct(vx, vy, vn);
256 light = 128 - DotProduct(vn, lightdir) * 128;
257 light = bound(0, light, 255);
258 data[y][x][0] = data[y][x][1] = data[y][x][2] = light;
262 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);
269 static qbyte R_MorphDistortTexture (double y0, double y1, double y2, double y3, double morph)
271 int m = (int)(((y1 + y3 - (y0 + y2)) * morph * morph * morph) +
272 ((2 * (y0 - y1) + y2 - y3) * morph * morph) +
273 ((y2 - y0) * morph) +
275 return (qbyte)bound(0, m, 255);
278 static void R_BuildDistortTexture (void)
281 #define DISTORTRESOLUTION 32
282 qbyte data[5][DISTORTRESOLUTION][DISTORTRESOLUTION][2];
286 for (y=0; y<DISTORTRESOLUTION; y++)
288 for (x=0; x<DISTORTRESOLUTION; x++)
290 data[i][y][x][0] = rand () & 255;
291 data[i][y][x][1] = rand () & 255;
300 r_texture_distorttexture[i*16+j] = NULL;
301 if (gl_textureshader)
303 for (y=0; y<DISTORTRESOLUTION; y++)
305 for (x=0; x<DISTORTRESOLUTION; x++)
307 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);
308 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 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);
317 static void R_BuildBlankTextures(void)
320 data[0] = 128; // normal X
321 data[1] = 128; // normal Y
322 data[2] = 255; // normal Z
323 data[3] = 128; // height
324 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
329 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
334 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
337 static void R_BuildNoTexture(void)
340 qbyte pix[16][16][4];
341 // this makes a light grey/dark grey checkerboard texture
342 for (y = 0;y < 16;y++)
344 for (x = 0;x < 16;x++)
346 if ((y < 8) ^ (x < 8))
362 r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
365 static void R_BuildWhiteCube(void)
368 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
369 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
370 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
371 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
372 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
373 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
374 r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
377 static void R_BuildNormalizationCube(void)
381 vec_t s, t, intensity;
383 qbyte data[6][NORMSIZE][NORMSIZE][4];
384 for (side = 0;side < 6;side++)
386 for (y = 0;y < NORMSIZE;y++)
388 for (x = 0;x < NORMSIZE;x++)
390 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
391 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
425 intensity = 127.0f / sqrt(DotProduct(v, v));
426 data[side][y][x][0] = 128.0f + intensity * v[0];
427 data[side][y][x][1] = 128.0f + intensity * v[1];
428 data[side][y][x][2] = 128.0f + intensity * v[2];
429 data[side][y][x][3] = 255;
433 r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
436 void gl_main_start(void)
438 r_main_texturepool = R_AllocTexturePool();
439 r_bloom_texture_screen = NULL;
440 r_bloom_texture_bloom = NULL;
441 R_BuildBlankTextures();
443 R_BuildDetailTextures();
444 R_BuildDistortTexture();
445 if (gl_texturecubemap)
448 R_BuildNormalizationCube();
452 void gl_main_shutdown(void)
454 R_FreeTexturePool(&r_main_texturepool);
455 r_bloom_texture_screen = NULL;
456 r_bloom_texture_bloom = NULL;
457 r_texture_blanknormalmap = NULL;
458 r_texture_white = NULL;
459 r_texture_black = NULL;
460 r_texture_whitecube = NULL;
461 r_texture_normalizationcube = NULL;
464 extern void CL_ParseEntityLump(char *entitystring);
465 void gl_main_newmap(void)
467 // FIXME: move this code to client
469 char *entities, entname[MAX_QPATH];
473 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
474 l = strlen(entname) - 4;
475 if (l >= 0 && !strcmp(entname + l, ".bsp"))
477 strcpy(entname + l, ".ent");
478 if ((entities = FS_LoadFile(entname, tempmempool, true)))
480 CL_ParseEntityLump(entities);
485 if (cl.worldmodel->brush.entities)
486 CL_ParseEntityLump(cl.worldmodel->brush.entities);
490 void GL_Main_Init(void)
492 Matrix4x4_CreateIdentity(&r_identitymatrix);
493 // FIXME: move this to client?
495 Cvar_RegisterVariable(&r_showtris);
496 Cvar_RegisterVariable(&r_drawentities);
497 Cvar_RegisterVariable(&r_drawviewmodel);
498 Cvar_RegisterVariable(&r_speeds);
499 Cvar_RegisterVariable(&r_fullbrights);
500 Cvar_RegisterVariable(&r_wateralpha);
501 Cvar_RegisterVariable(&r_dynamic);
502 Cvar_RegisterVariable(&r_fullbright);
503 Cvar_RegisterVariable(&r_textureunits);
504 Cvar_RegisterVariable(&r_lerpsprites);
505 Cvar_RegisterVariable(&r_lerpmodels);
506 Cvar_RegisterVariable(&r_waterscroll);
507 Cvar_RegisterVariable(&r_watershader);
508 Cvar_RegisterVariable(&r_drawcollisionbrushes);
509 Cvar_RegisterVariable(&r_bloom);
510 Cvar_RegisterVariable(&r_bloom_intensity);
511 Cvar_RegisterVariable(&r_bloom_blur);
512 Cvar_RegisterVariable(&r_bloom_resolution);
513 Cvar_RegisterVariable(&r_bloom_power);
514 Cvar_RegisterVariable(&developer_texturelogging);
515 if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
516 Cvar_SetValue("r_fullbrights", 0);
517 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
520 static vec3_t r_farclip_origin;
521 static vec3_t r_farclip_direction;
522 static vec_t r_farclip_directiondist;
523 static vec_t r_farclip_meshfarclip;
524 static int r_farclip_directionbit0;
525 static int r_farclip_directionbit1;
526 static int r_farclip_directionbit2;
528 // enlarge farclip to accomodate box
529 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
532 d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
533 + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
534 + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
535 if (r_farclip_meshfarclip < d)
536 r_farclip_meshfarclip = d;
539 // return farclip value
540 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
544 VectorCopy(origin, r_farclip_origin);
545 VectorCopy(direction, r_farclip_direction);
546 r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
547 r_farclip_directionbit0 = r_farclip_direction[0] < 0;
548 r_farclip_directionbit1 = r_farclip_direction[1] < 0;
549 r_farclip_directionbit2 = r_farclip_direction[2] < 0;
550 r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
552 if (r_refdef.worldmodel)
553 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
554 for (i = 0;i < r_refdef.numentities;i++)
555 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
557 return r_farclip_meshfarclip - r_farclip_directiondist;
560 extern void R_Textures_Init(void);
561 extern void GL_Draw_Init(void);
562 extern void GL_Main_Init(void);
563 extern void R_Shadow_Init(void);
564 extern void R_Sky_Init(void);
565 extern void GL_Surf_Init(void);
566 extern void R_Crosshairs_Init(void);
567 extern void R_Light_Init(void);
568 extern void R_Particles_Init(void);
569 extern void R_Explosion_Init(void);
570 extern void gl_backend_init(void);
571 extern void Sbar_Init(void);
572 extern void R_LightningBeams_Init(void);
573 extern void Mod_RenderInit(void);
575 void Render_Init(void)
592 R_LightningBeams_Init();
600 extern char *ENGINE_EXTENSIONS;
603 VID_CheckExtensions();
605 // LordHavoc: report supported extensions
606 Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
608 // clear to black (loading plaque will be seen over this)
609 qglClearColor(0,0,0,1);
610 qglClear(GL_COLOR_BUFFER_BIT);
613 int R_CullBox(const vec3_t mins, const vec3_t maxs)
617 for (i = 0;i < 4;i++)
624 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
628 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
632 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
636 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
640 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
644 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
648 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
652 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
660 //==================================================================================
662 static void R_MarkEntities (void)
665 entity_render_t *ent;
667 if (!r_drawentities.integer)
670 r_refdef.worldentity->visframe = r_framecount;
671 renderimask = envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
672 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
674 // worldmodel can check visibility
675 for (i = 0;i < r_refdef.numentities;i++)
677 ent = r_refdef.entities[i];
678 Mod_CheckLoaded(ent->model);
679 // some of the renderer still relies on origin...
680 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
681 // some of the renderer still relies on scale...
682 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
683 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)))
685 R_UpdateEntLights(ent);
686 ent->visframe = r_framecount;
692 // no worldmodel or it can't check visibility
693 for (i = 0;i < r_refdef.numentities;i++)
695 ent = r_refdef.entities[i];
696 Mod_CheckLoaded(ent->model);
697 // some of the renderer still relies on origin...
698 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
699 // some of the renderer still relies on scale...
700 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
701 if (!(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && (ent->effects & EF_NODEPTHTEST))
703 R_UpdateEntLights(ent);
704 ent->visframe = r_framecount;
710 // only used if skyrendermasked, and normally returns false
711 int R_DrawBrushModelsSky (void)
714 entity_render_t *ent;
716 if (!r_drawentities.integer)
720 for (i = 0;i < r_refdef.numentities;i++)
722 ent = r_refdef.entities[i];
723 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
725 ent->model->DrawSky(ent);
732 void R_DrawNoModel(entity_render_t *ent);
733 void R_DrawModels(void)
736 entity_render_t *ent;
738 if (!r_drawentities.integer)
741 for (i = 0;i < r_refdef.numentities;i++)
743 ent = r_refdef.entities[i];
744 if (ent->visframe == r_framecount)
746 if (ent->model && ent->model->Draw != NULL)
747 ent->model->Draw(ent);
754 static void R_SetFrustum(void)
756 // break apart the view matrix into vectors for various purposes
757 Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
758 VectorNegate(r_viewleft, r_viewright);
760 // LordHavoc: note to all quake engine coders, the special case for 90
761 // degrees assumed a square view (wrong), so I removed it, Quake2 has it
764 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
765 RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
766 frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
767 PlaneClassify(&frustum[0]);
769 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
770 RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
771 frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
772 PlaneClassify(&frustum[1]);
774 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
775 RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
776 frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
777 PlaneClassify(&frustum[2]);
779 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
780 RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
781 frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
782 PlaneClassify(&frustum[3]);
785 VectorCopy(r_viewforward, frustum[4].normal);
786 frustum[4].dist = DotProduct (r_vieworigin, frustum[4].normal) + 1.0f;
787 PlaneClassify(&frustum[4]);
790 static void R_BlendView(void)
794 if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
797 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
800 R_Mesh_Matrix(&r_identitymatrix);
801 // vertex coordinates for a quad that covers the screen exactly
802 varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
803 varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
804 varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
805 varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
806 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)
808 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
809 float xoffset, yoffset, r;
811 // set the (poorly named) screenwidth and screenheight variables to
812 // a power of 2 at least as large as the screen, these will define the
813 // size of the texture to allocate
814 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
815 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
816 // allocate textures as needed
817 if (!r_bloom_texture_screen)
818 r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
819 if (!r_bloom_texture_bloom)
820 r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
821 // set bloomwidth and bloomheight to the bloom resolution that will be
822 // used (often less than the screen resolution for faster rendering)
823 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
824 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
825 // set up a texcoord array for the full resolution screen image
826 // (we have to keep this around to copy back during final render)
827 varray_texcoord2f[0][0] = 0;
828 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
829 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
830 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
831 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
832 varray_texcoord2f[0][5] = 0;
833 varray_texcoord2f[0][6] = 0;
834 varray_texcoord2f[0][7] = 0;
835 // set up a texcoord array for the reduced resolution bloom image
836 // (which will be additive blended over the screen image)
837 varray_texcoord2f[1][0] = 0;
838 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
839 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
840 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
841 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
842 varray_texcoord2f[1][5] = 0;
843 varray_texcoord2f[1][6] = 0;
844 varray_texcoord2f[1][7] = 0;
845 memset(&m, 0, sizeof(m));
846 m.pointer_vertex = varray_vertex3f;
847 m.pointer_texcoord[0] = varray_texcoord2f[0];
848 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
850 // copy view into the full resolution screen image texture
852 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
854 c_bloomcopypixels += r_view_width * r_view_height;
855 // now scale it down to the bloom size and raise to a power of itself
856 // to darken it (this leaves the really bright stuff bright, and
857 // everything else becomes very dark)
858 // TODO: optimize with multitexture or GLSL
859 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
860 GL_BlendFunc(GL_ONE, GL_ZERO);
861 GL_Color(1, 1, 1, 1);
862 R_Mesh_Draw(0, 4, 2, polygonelements);
864 c_bloomdrawpixels += bloomwidth * bloomheight;
865 // render multiple times with a multiply blendfunc to raise to a power
866 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
867 for (x = 1;x < r_bloom_power.integer;x++)
869 R_Mesh_Draw(0, 4, 2, polygonelements);
871 c_bloomdrawpixels += bloomwidth * bloomheight;
873 // we now have a darkened bloom image in the framebuffer, copy it into
874 // the bloom image texture for more processing
875 memset(&m, 0, sizeof(m));
876 m.pointer_vertex = varray_vertex3f;
877 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
878 m.pointer_texcoord[0] = varray_texcoord2f[2];
881 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
883 c_bloomcopypixels += bloomwidth * bloomheight;
884 // blend on at multiple vertical offsets to achieve a vertical blur
885 // TODO: do offset blends using GLSL
886 range = r_bloom_blur.integer * bloomwidth / 320;
887 GL_BlendFunc(GL_ONE, GL_ZERO);
888 for (x = -range;x <= range;x++)
890 xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
891 yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
892 // compute a texcoord array with the specified x and y offset
893 varray_texcoord2f[2][0] = xoffset+0;
894 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
895 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
896 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
897 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
898 varray_texcoord2f[2][5] = yoffset+0;
899 varray_texcoord2f[2][6] = xoffset+0;
900 varray_texcoord2f[2][7] = yoffset+0;
901 // this r value looks like a 'dot' particle, fading sharply to
902 // black at the edges
903 // (probably not realistic but looks good enough)
904 r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
907 GL_Color(r, r, r, 1);
908 R_Mesh_Draw(0, 4, 2, polygonelements);
910 c_bloomdrawpixels += bloomwidth * bloomheight;
911 GL_BlendFunc(GL_ONE, GL_ONE);
913 // copy the vertically blurred bloom view to a texture
915 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
917 c_bloomcopypixels += bloomwidth * bloomheight;
918 // blend the vertically blurred image at multiple offsets horizontally
919 // to finish the blur effect
920 // TODO: do offset blends using GLSL
921 range = r_bloom_blur.integer * bloomwidth / 320;
922 GL_BlendFunc(GL_ONE, GL_ZERO);
923 for (x = -range;x <= range;x++)
925 xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
926 yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
927 // compute a texcoord array with the specified x and y offset
928 varray_texcoord2f[2][0] = xoffset+0;
929 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
930 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
931 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
932 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
933 varray_texcoord2f[2][5] = yoffset+0;
934 varray_texcoord2f[2][6] = xoffset+0;
935 varray_texcoord2f[2][7] = yoffset+0;
936 // this r value looks like a 'dot' particle, fading sharply to
937 // black at the edges
938 // (probably not realistic but looks good enough)
939 r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
942 GL_Color(r, r, r, 1);
943 R_Mesh_Draw(0, 4, 2, polygonelements);
945 c_bloomdrawpixels += bloomwidth * bloomheight;
946 GL_BlendFunc(GL_ONE, GL_ONE);
948 // copy the blurred bloom view to a texture
950 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
952 c_bloomcopypixels += bloomwidth * bloomheight;
953 // go back to full view area
954 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
955 // put the original screen image back in place and blend the bloom
957 memset(&m, 0, sizeof(m));
958 m.pointer_vertex = varray_vertex3f;
959 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
960 m.pointer_texcoord[0] = varray_texcoord2f[0];
962 dobloomblend = false;
964 // do both in one pass if possible
965 if (r_textureunits.integer >= 2 && gl_combine.integer)
967 dobloomblend = false;
968 m.texcombinergb[1] = GL_ADD;
969 m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
970 m.pointer_texcoord[1] = varray_texcoord2f[1];
976 GL_BlendFunc(GL_ONE, GL_ZERO);
978 R_Mesh_Draw(0, 4, 2, polygonelements);
980 c_bloomdrawpixels += r_view_width * r_view_height;
981 // now blend on the bloom texture if multipass
984 memset(&m, 0, sizeof(m));
985 m.pointer_vertex = varray_vertex3f;
986 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
987 m.pointer_texcoord[0] = varray_texcoord2f[1];
989 GL_BlendFunc(GL_ONE, GL_ONE);
991 R_Mesh_Draw(0, 4, 2, polygonelements);
993 c_bloomdrawpixels += r_view_width * r_view_height;
996 if (r_refdef.viewblend[3] >= 0.01f)
998 // apply a color tint to the whole view
999 memset(&m, 0, sizeof(m));
1000 m.pointer_vertex = varray_vertex3f;
1002 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1003 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
1004 R_Mesh_Draw(0, 4, 2, polygonelements);
1008 void R_RenderScene(void);
1015 void R_RenderView(void)
1017 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
1018 return; //Host_Error ("R_RenderView: NULL worldmodel");
1020 r_view_width = bound(0, r_refdef.width, vid.realwidth);
1021 r_view_height = bound(0, r_refdef.height, vid.realheight);
1023 r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
1024 r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
1026 r_view_fov_x = bound(1, r_refdef.fov_x, 170);
1027 r_view_fov_y = bound(1, r_refdef.fov_y, 170);
1028 r_view_matrix = r_refdef.viewentitymatrix;
1029 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1030 r_rtworld = r_shadow_realtime_world.integer;
1031 r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
1032 r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
1033 r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
1034 r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
1036 // GL is weird because it's bottom to top, r_view_y is top to bottom
1037 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
1038 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1039 GL_ScissorTest(true);
1045 R_TimeReport("setup");
1047 qglDepthFunc(GL_LEQUAL);
1048 qglPolygonOffset(0, 0);
1049 qglEnable(GL_POLYGON_OFFSET_FILL);
1053 qglPolygonOffset(0, 0);
1054 qglDisable(GL_POLYGON_OFFSET_FILL);
1057 R_TimeReport("blendview");
1059 GL_Scissor(0, 0, vid.realwidth, vid.realheight);
1060 GL_ScissorTest(false);
1063 extern void R_DrawLightningBeams (void);
1064 void R_RenderScene(void)
1066 // don't let sound skip if going slow
1067 if (r_refdef.extraupdate)
1072 R_MeshQueue_BeginScene();
1074 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1078 r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
1079 if (r_rtworldshadows || r_rtdlightshadows)
1080 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
1082 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
1084 GL_SetupView_Orientation_FromEntity(&r_view_matrix);
1088 R_WorldVisibility();
1089 R_TimeReport("worldvis");
1092 R_TimeReport("markentity");
1094 R_Shadow_UpdateWorldLightSelection();
1096 // don't let sound skip if going slow
1097 if (r_refdef.extraupdate)
1100 GL_ShowTrisColor(0.025, 0.025, 0, 1);
1101 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
1103 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
1104 R_TimeReport("worldsky");
1107 if (R_DrawBrushModelsSky())
1108 R_TimeReport("bmodelsky");
1110 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1111 if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
1113 r_refdef.worldmodel->Draw(r_refdef.worldentity);
1114 R_TimeReport("world");
1117 // don't let sound skip if going slow
1118 if (r_refdef.extraupdate)
1121 GL_ShowTrisColor(0, 0.015, 0, 1);
1124 R_TimeReport("models");
1126 // don't let sound skip if going slow
1127 if (r_refdef.extraupdate)
1130 GL_ShowTrisColor(0, 0, 0.033, 1);
1131 R_ShadowVolumeLighting(false);
1132 R_TimeReport("rtlights");
1134 // don't let sound skip if going slow
1135 if (r_refdef.extraupdate)
1138 GL_ShowTrisColor(0.1, 0, 0, 1);
1140 R_DrawLightningBeams();
1141 R_TimeReport("lightning");
1144 R_TimeReport("particles");
1147 R_TimeReport("explosions");
1149 R_MeshQueue_RenderTransparent();
1150 R_TimeReport("drawtrans");
1153 R_TimeReport("coronas");
1155 R_DrawWorldCrosshair();
1156 R_TimeReport("crosshair");
1158 R_MeshQueue_Render();
1159 R_MeshQueue_EndScene();
1161 if ((r_shadow_visiblelighting.integer || r_shadow_visiblevolumes.integer) && !r_showtrispass)
1163 R_ShadowVolumeLighting(true);
1164 R_TimeReport("visiblevolume");
1167 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1169 // don't let sound skip if going slow
1170 if (r_refdef.extraupdate)
1175 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
1178 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
1180 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1181 GL_DepthMask(false);
1183 R_Mesh_Matrix(&r_identitymatrix);
1185 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
1186 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
1187 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
1188 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
1189 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
1190 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
1191 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
1192 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
1193 R_FillColors(color, 8, cr, cg, cb, ca);
1196 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
1198 VectorSubtract(v, r_vieworigin, diff);
1199 f2 = exp(fogdensity/DotProduct(diff, diff));
1201 c[0] = c[0] * f1 + fogcolor[0] * f2;
1202 c[1] = c[1] * f1 + fogcolor[1] * f2;
1203 c[2] = c[2] * f1 + fogcolor[2] * f2;
1206 memset(&m, 0, sizeof(m));
1207 m.pointer_vertex = vertex3f;
1208 m.pointer_color = color;
1214 int nomodelelements[24] =
1226 float nomodelvertex3f[6*3] =
1236 float nomodelcolor4f[6*4] =
1238 0.0f, 0.0f, 0.5f, 1.0f,
1239 0.0f, 0.0f, 0.5f, 1.0f,
1240 0.0f, 0.5f, 0.0f, 1.0f,
1241 0.0f, 0.5f, 0.0f, 1.0f,
1242 0.5f, 0.0f, 0.0f, 1.0f,
1243 0.5f, 0.0f, 0.0f, 1.0f
1246 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1248 const entity_render_t *ent = calldata1;
1250 float f1, f2, *c, diff[3];
1253 R_Mesh_Matrix(&ent->matrix);
1255 memset(&m, 0, sizeof(m));
1256 m.pointer_vertex = nomodelvertex3f;
1258 if (ent->flags & EF_ADDITIVE)
1260 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1261 GL_DepthMask(false);
1263 else if (ent->alpha < 1)
1265 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1266 GL_DepthMask(false);
1270 GL_BlendFunc(GL_ONE, GL_ZERO);
1273 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
1276 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1277 m.pointer_color = color4f;
1278 VectorSubtract(ent->origin, r_vieworigin, diff);
1279 f2 = exp(fogdensity/DotProduct(diff, diff));
1281 for (i = 0, c = color4f;i < 6;i++, c += 4)
1283 c[0] = (c[0] * f1 + fogcolor[0] * f2);
1284 c[1] = (c[1] * f1 + fogcolor[1] * f2);
1285 c[2] = (c[2] * f1 + fogcolor[2] * f2);
1289 else if (ent->alpha != 1)
1291 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1292 m.pointer_color = color4f;
1293 for (i = 0, c = color4f;i < 6;i++, c += 4)
1297 m.pointer_color = nomodelcolor4f;
1299 R_Mesh_Draw(0, 6, 8, nomodelelements);
1302 void R_DrawNoModel(entity_render_t *ent)
1304 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1305 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1307 // R_DrawNoModelCallback(ent, 0);
1310 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1312 vec3_t right1, right2, diff, normal;
1314 VectorSubtract (org2, org1, normal);
1316 // calculate 'right' vector for start
1317 VectorSubtract (r_vieworigin, org1, diff);
1318 CrossProduct (normal, diff, right1);
1319 VectorNormalize (right1);
1321 // calculate 'right' vector for end
1322 VectorSubtract (r_vieworigin, org2, diff);
1323 CrossProduct (normal, diff, right2);
1324 VectorNormalize (right2);
1326 vert[ 0] = org1[0] + width * right1[0];
1327 vert[ 1] = org1[1] + width * right1[1];
1328 vert[ 2] = org1[2] + width * right1[2];
1329 vert[ 3] = org1[0] - width * right1[0];
1330 vert[ 4] = org1[1] - width * right1[1];
1331 vert[ 5] = org1[2] - width * right1[2];
1332 vert[ 6] = org2[0] - width * right2[0];
1333 vert[ 7] = org2[1] - width * right2[1];
1334 vert[ 8] = org2[2] - width * right2[2];
1335 vert[ 9] = org2[0] + width * right2[0];
1336 vert[10] = org2[1] + width * right2[1];
1337 vert[11] = org2[2] + width * right2[2];
1340 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1342 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)
1349 VectorSubtract(origin, r_vieworigin, diff);
1350 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1353 R_Mesh_Matrix(&r_identitymatrix);
1354 GL_BlendFunc(blendfunc1, blendfunc2);
1355 GL_DepthMask(false);
1356 GL_DepthTest(!depthdisable);
1358 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1359 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1360 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1361 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1362 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1363 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1364 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1365 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1366 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1367 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1368 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1369 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1371 memset(&m, 0, sizeof(m));
1372 m.tex[0] = R_GetTexture(texture);
1373 m.pointer_texcoord[0] = spritetexcoord2f;
1374 m.pointer_vertex = varray_vertex3f;
1376 GL_Color(cr, cg, cb, ca);
1377 R_Mesh_Draw(0, 4, 2, polygonelements);
1380 int R_Mesh_AddVertex3f(rmesh_t *mesh, const float *v)
1384 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
1385 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
1387 if (i == mesh->numvertices)
1389 if (mesh->numvertices < mesh->maxvertices)
1391 VectorCopy(v, vertex3f);
1392 mesh->numvertices++;
1394 return mesh->numvertices;
1400 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
1404 element[0] = R_Mesh_AddVertex3f(mesh, vertex3f);vertex3f += 3;
1405 element[1] = R_Mesh_AddVertex3f(mesh, vertex3f);vertex3f += 3;
1406 e = mesh->element3i + mesh->numtriangles * 3;
1407 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
1409 element[2] = R_Mesh_AddVertex3f(mesh, vertex3f);
1410 if (mesh->numtriangles < mesh->maxtriangles)
1415 mesh->numtriangles++;
1417 element[1] = element[2];
1421 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
1423 int planenum, planenum2;
1426 mplane_t *plane, *plane2;
1427 float temppoints[2][256*3];
1428 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
1432 PolygonF_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->normal[3], 1024.0*1024.0*1024.0);
1433 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
1435 if (planenum2 == planenum)
1437 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);
1440 if (tempnumpoints < 3)
1442 // generate elements forming a triangle fan for this polygon
1443 R_Mesh_AddPolygon3f(mesh, tempnumpoints, temppoints[w]);