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][DETAILRESOLUTION][4], noise[DETAILRESOLUTION][DETAILRESOLUTION];
229 VectorNormalize(lightdir);
230 for (i = 0;i < NUM_DETAILTEXTURES;i++)
232 fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4);
233 for (y = 0;y < DETAILRESOLUTION;y++)
235 for (x = 0;x < DETAILRESOLUTION;x++)
239 vc[2] = noise[y][x] * (1.0f / 32.0f);
242 vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f);
245 vy[2] = noise[(y + 1) % DETAILRESOLUTION][x] * (1.0f / 32.0f);
246 VectorSubtract(vx, vc, vx);
247 VectorSubtract(vy, vc, vy);
248 CrossProduct(vx, vy, vn);
250 light = 128 - DotProduct(vn, lightdir) * 128;
251 light = bound(0, light, 255);
252 data[y][x][0] = data[y][x][1] = data[y][x][2] = light;
256 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);
260 static qbyte R_MorphDistortTexture (double y0, double y1, double y2, double y3, double morph)
262 int m = (int)(((y1 + y3 - (y0 + y2)) * morph * morph * morph) +
263 ((2 * (y0 - y1) + y2 - y3) * morph * morph) +
264 ((y2 - y0) * morph) +
266 return (qbyte)bound(0, m, 255);
269 static void R_BuildDistortTexture (void)
272 #define DISTORTRESOLUTION 32
273 qbyte data[5][DISTORTRESOLUTION][DISTORTRESOLUTION][2];
277 for (y=0; y<DISTORTRESOLUTION; y++)
279 for (x=0; x<DISTORTRESOLUTION; x++)
281 data[i][y][x][0] = rand () & 255;
282 data[i][y][x][1] = rand () & 255;
291 r_texture_distorttexture[i*16+j] = NULL;
292 if (gl_textureshader)
294 for (y=0; y<DISTORTRESOLUTION; y++)
296 for (x=0; x<DISTORTRESOLUTION; x++)
298 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);
299 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);
302 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);
308 static void R_BuildBlankTextures(void)
311 data[0] = 128; // normal X
312 data[1] = 128; // normal Y
313 data[2] = 255; // normal Z
314 data[3] = 128; // height
315 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
320 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
325 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
328 static void R_BuildNoTexture(void)
331 qbyte pix[16][16][4];
332 // this makes a light grey/dark grey checkerboard texture
333 for (y = 0;y < 16;y++)
335 for (x = 0;x < 16;x++)
337 if ((y < 8) ^ (x < 8))
353 r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
356 static void R_BuildWhiteCube(void)
359 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
360 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
361 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
362 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
363 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
364 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
365 r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
368 static void R_BuildNormalizationCube(void)
372 vec_t s, t, intensity;
374 qbyte data[6][NORMSIZE][NORMSIZE][4];
375 for (side = 0;side < 6;side++)
377 for (y = 0;y < NORMSIZE;y++)
379 for (x = 0;x < NORMSIZE;x++)
381 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
382 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
416 intensity = 127.0f / sqrt(DotProduct(v, v));
417 data[side][y][x][0] = 128.0f + intensity * v[0];
418 data[side][y][x][1] = 128.0f + intensity * v[1];
419 data[side][y][x][2] = 128.0f + intensity * v[2];
420 data[side][y][x][3] = 255;
424 r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
427 void gl_main_start(void)
429 r_main_texturepool = R_AllocTexturePool();
430 r_bloom_texture_screen = NULL;
431 r_bloom_texture_bloom = NULL;
432 R_BuildBlankTextures();
434 R_BuildDetailTextures();
435 R_BuildDistortTexture();
436 if (gl_texturecubemap)
439 R_BuildNormalizationCube();
443 void gl_main_shutdown(void)
445 R_FreeTexturePool(&r_main_texturepool);
446 r_bloom_texture_screen = NULL;
447 r_bloom_texture_bloom = NULL;
448 r_texture_blanknormalmap = NULL;
449 r_texture_white = NULL;
450 r_texture_black = NULL;
451 r_texture_whitecube = NULL;
452 r_texture_normalizationcube = NULL;
455 extern void CL_ParseEntityLump(char *entitystring);
456 void gl_main_newmap(void)
458 // FIXME: move this code to client
460 char *entities, entname[MAX_QPATH];
464 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
465 l = strlen(entname) - 4;
466 if (l >= 0 && !strcmp(entname + l, ".bsp"))
468 strcpy(entname + l, ".ent");
469 if ((entities = FS_LoadFile(entname, tempmempool, true)))
471 CL_ParseEntityLump(entities);
476 if (cl.worldmodel->brush.entities)
477 CL_ParseEntityLump(cl.worldmodel->brush.entities);
481 void GL_Main_Init(void)
483 Matrix4x4_CreateIdentity(&r_identitymatrix);
484 // FIXME: move this to client?
486 Cvar_RegisterVariable(&r_showtris);
487 Cvar_RegisterVariable(&r_drawentities);
488 Cvar_RegisterVariable(&r_drawviewmodel);
489 Cvar_RegisterVariable(&r_speeds);
490 Cvar_RegisterVariable(&r_fullbrights);
491 Cvar_RegisterVariable(&r_wateralpha);
492 Cvar_RegisterVariable(&r_dynamic);
493 Cvar_RegisterVariable(&r_fullbright);
494 Cvar_RegisterVariable(&r_textureunits);
495 Cvar_RegisterVariable(&r_lerpsprites);
496 Cvar_RegisterVariable(&r_lerpmodels);
497 Cvar_RegisterVariable(&r_waterscroll);
498 Cvar_RegisterVariable(&r_watershader);
499 Cvar_RegisterVariable(&r_drawcollisionbrushes);
500 Cvar_RegisterVariable(&r_bloom);
501 Cvar_RegisterVariable(&r_bloom_intensity);
502 Cvar_RegisterVariable(&r_bloom_blur);
503 Cvar_RegisterVariable(&r_bloom_resolution);
504 Cvar_RegisterVariable(&r_bloom_power);
505 Cvar_RegisterVariable(&developer_texturelogging);
506 if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
507 Cvar_SetValue("r_fullbrights", 0);
508 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
511 static vec3_t r_farclip_origin;
512 static vec3_t r_farclip_direction;
513 static vec_t r_farclip_directiondist;
514 static vec_t r_farclip_meshfarclip;
515 static int r_farclip_directionbit0;
516 static int r_farclip_directionbit1;
517 static int r_farclip_directionbit2;
519 // enlarge farclip to accomodate box
520 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
523 d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
524 + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
525 + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
526 if (r_farclip_meshfarclip < d)
527 r_farclip_meshfarclip = d;
530 // return farclip value
531 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
535 VectorCopy(origin, r_farclip_origin);
536 VectorCopy(direction, r_farclip_direction);
537 r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
538 r_farclip_directionbit0 = r_farclip_direction[0] < 0;
539 r_farclip_directionbit1 = r_farclip_direction[1] < 0;
540 r_farclip_directionbit2 = r_farclip_direction[2] < 0;
541 r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
543 if (r_refdef.worldmodel)
544 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
545 for (i = 0;i < r_refdef.numentities;i++)
546 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
548 return r_farclip_meshfarclip - r_farclip_directiondist;
551 extern void R_Textures_Init(void);
552 extern void GL_Draw_Init(void);
553 extern void GL_Main_Init(void);
554 extern void R_Shadow_Init(void);
555 extern void R_Sky_Init(void);
556 extern void GL_Surf_Init(void);
557 extern void R_Crosshairs_Init(void);
558 extern void R_Light_Init(void);
559 extern void R_Particles_Init(void);
560 extern void R_Explosion_Init(void);
561 extern void gl_backend_init(void);
562 extern void Sbar_Init(void);
563 extern void R_LightningBeams_Init(void);
564 extern void Mod_RenderInit(void);
566 void Render_Init(void)
583 R_LightningBeams_Init();
591 extern char *ENGINE_EXTENSIONS;
594 VID_CheckExtensions();
596 // LordHavoc: report supported extensions
597 Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
599 // clear to black (loading plaque will be seen over this)
600 qglClearColor(0,0,0,1);
601 qglClear(GL_COLOR_BUFFER_BIT);
604 int R_CullBox(const vec3_t mins, const vec3_t maxs)
608 for (i = 0;i < 4;i++)
615 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
619 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
623 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
627 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
631 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
635 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
639 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
643 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
651 //==================================================================================
653 static void R_MarkEntities (void)
656 entity_render_t *ent;
658 if (!r_drawentities.integer)
661 r_refdef.worldentity->visframe = r_framecount;
662 renderimask = envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
663 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
665 // worldmodel can check visibility
666 for (i = 0;i < r_refdef.numentities;i++)
668 ent = r_refdef.entities[i];
669 Mod_CheckLoaded(ent->model);
670 // some of the renderer still relies on origin...
671 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
672 // some of the renderer still relies on scale...
673 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
674 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)))
676 R_UpdateEntLights(ent);
677 ent->visframe = r_framecount;
683 // no worldmodel or it can't check visibility
684 for (i = 0;i < r_refdef.numentities;i++)
686 ent = r_refdef.entities[i];
687 Mod_CheckLoaded(ent->model);
688 // some of the renderer still relies on origin...
689 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
690 // some of the renderer still relies on scale...
691 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
692 if (!(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && (ent->effects & EF_NODEPTHTEST))
694 R_UpdateEntLights(ent);
695 ent->visframe = r_framecount;
701 // only used if skyrendermasked, and normally returns false
702 int R_DrawBrushModelsSky (void)
705 entity_render_t *ent;
707 if (!r_drawentities.integer)
711 for (i = 0;i < r_refdef.numentities;i++)
713 ent = r_refdef.entities[i];
714 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
716 ent->model->DrawSky(ent);
723 void R_DrawNoModel(entity_render_t *ent);
724 void R_DrawModels(void)
727 entity_render_t *ent;
729 if (!r_drawentities.integer)
732 for (i = 0;i < r_refdef.numentities;i++)
734 ent = r_refdef.entities[i];
735 if (ent->visframe == r_framecount)
737 if (ent->model && ent->model->Draw != NULL)
738 ent->model->Draw(ent);
745 static void R_SetFrustum(void)
747 // break apart the view matrix into vectors for various purposes
748 Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
749 VectorNegate(r_viewleft, r_viewright);
751 // LordHavoc: note to all quake engine coders, the special case for 90
752 // degrees assumed a square view (wrong), so I removed it, Quake2 has it
755 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
756 RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
757 frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
758 PlaneClassify(&frustum[0]);
760 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
761 RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
762 frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
763 PlaneClassify(&frustum[1]);
765 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
766 RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
767 frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
768 PlaneClassify(&frustum[2]);
770 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
771 RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
772 frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
773 PlaneClassify(&frustum[3]);
776 VectorCopy(r_viewforward, frustum[4].normal);
777 frustum[4].dist = DotProduct (r_vieworigin, frustum[4].normal) + 1.0f;
778 PlaneClassify(&frustum[4]);
781 static void R_BlendView(void)
785 if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
788 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
791 R_Mesh_Matrix(&r_identitymatrix);
792 // vertex coordinates for a quad that covers the screen exactly
793 varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
794 varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
795 varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
796 varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
797 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)
799 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
800 float xoffset, yoffset, r;
802 // set the (poorly named) screenwidth and screenheight variables to
803 // a power of 2 at least as large as the screen, these will define the
804 // size of the texture to allocate
805 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
806 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
807 // allocate textures as needed
808 if (!r_bloom_texture_screen)
809 r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
810 if (!r_bloom_texture_bloom)
811 r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
812 // set bloomwidth and bloomheight to the bloom resolution that will be
813 // used (often less than the screen resolution for faster rendering)
814 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
815 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
816 // set up a texcoord array for the full resolution screen image
817 // (we have to keep this around to copy back during final render)
818 varray_texcoord2f[0][0] = 0;
819 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
820 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
821 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
822 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
823 varray_texcoord2f[0][5] = 0;
824 varray_texcoord2f[0][6] = 0;
825 varray_texcoord2f[0][7] = 0;
826 // set up a texcoord array for the reduced resolution bloom image
827 // (which will be additive blended over the screen image)
828 varray_texcoord2f[1][0] = 0;
829 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
830 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
831 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
832 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
833 varray_texcoord2f[1][5] = 0;
834 varray_texcoord2f[1][6] = 0;
835 varray_texcoord2f[1][7] = 0;
836 memset(&m, 0, sizeof(m));
837 m.pointer_vertex = varray_vertex3f;
838 m.pointer_texcoord[0] = varray_texcoord2f[0];
839 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
841 // copy view into the full resolution screen image texture
843 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
845 c_bloomcopypixels += r_view_width * r_view_height;
846 // now scale it down to the bloom size and raise to a power of itself
847 // to darken it (this leaves the really bright stuff bright, and
848 // everything else becomes very dark)
849 // TODO: optimize with multitexture or GLSL
850 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
851 GL_BlendFunc(GL_ONE, GL_ZERO);
852 GL_Color(1, 1, 1, 1);
853 R_Mesh_Draw(0, 4, 2, polygonelements);
855 c_bloomdrawpixels += bloomwidth * bloomheight;
856 // render multiple times with a multiply blendfunc to raise to a power
857 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
858 for (x = 1;x < r_bloom_power.integer;x++)
860 R_Mesh_Draw(0, 4, 2, polygonelements);
862 c_bloomdrawpixels += bloomwidth * bloomheight;
864 // we now have a darkened bloom image in the framebuffer, copy it into
865 // the bloom image texture for more processing
866 memset(&m, 0, sizeof(m));
867 m.pointer_vertex = varray_vertex3f;
868 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
869 m.pointer_texcoord[0] = varray_texcoord2f[2];
872 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
874 c_bloomcopypixels += bloomwidth * bloomheight;
875 // blend on at multiple vertical offsets to achieve a vertical blur
876 // TODO: do offset blends using GLSL
877 range = r_bloom_blur.integer * bloomwidth / 320;
878 GL_BlendFunc(GL_ONE, GL_ZERO);
879 for (x = -range;x <= range;x++)
881 xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
882 yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
883 // compute a texcoord array with the specified x and y offset
884 varray_texcoord2f[2][0] = xoffset+0;
885 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
886 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
887 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
888 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
889 varray_texcoord2f[2][5] = yoffset+0;
890 varray_texcoord2f[2][6] = xoffset+0;
891 varray_texcoord2f[2][7] = yoffset+0;
892 // this r value looks like a 'dot' particle, fading sharply to
893 // black at the edges
894 // (probably not realistic but looks good enough)
895 r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
898 GL_Color(r, r, r, 1);
899 R_Mesh_Draw(0, 4, 2, polygonelements);
901 c_bloomdrawpixels += bloomwidth * bloomheight;
902 GL_BlendFunc(GL_ONE, GL_ONE);
904 // copy the vertically blurred bloom view to a texture
906 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
908 c_bloomcopypixels += bloomwidth * bloomheight;
909 // blend the vertically blurred image at multiple offsets horizontally
910 // to finish the blur effect
911 // TODO: do offset blends using GLSL
912 range = r_bloom_blur.integer * bloomwidth / 320;
913 GL_BlendFunc(GL_ONE, GL_ZERO);
914 for (x = -range;x <= range;x++)
916 xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
917 yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
918 // compute a texcoord array with the specified x and y offset
919 varray_texcoord2f[2][0] = xoffset+0;
920 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
921 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
922 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
923 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
924 varray_texcoord2f[2][5] = yoffset+0;
925 varray_texcoord2f[2][6] = xoffset+0;
926 varray_texcoord2f[2][7] = yoffset+0;
927 // this r value looks like a 'dot' particle, fading sharply to
928 // black at the edges
929 // (probably not realistic but looks good enough)
930 r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
933 GL_Color(r, r, r, 1);
934 R_Mesh_Draw(0, 4, 2, polygonelements);
936 c_bloomdrawpixels += bloomwidth * bloomheight;
937 GL_BlendFunc(GL_ONE, GL_ONE);
939 // copy the blurred bloom view to a texture
941 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
943 c_bloomcopypixels += bloomwidth * bloomheight;
944 // go back to full view area
945 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
946 // put the original screen image back in place and blend the bloom
948 memset(&m, 0, sizeof(m));
949 m.pointer_vertex = varray_vertex3f;
950 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
951 m.pointer_texcoord[0] = varray_texcoord2f[0];
953 dobloomblend = false;
955 // do both in one pass if possible
956 if (r_textureunits.integer >= 2 && gl_combine.integer)
958 dobloomblend = false;
959 m.texcombinergb[1] = GL_ADD;
960 m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
961 m.pointer_texcoord[1] = varray_texcoord2f[1];
967 GL_BlendFunc(GL_ONE, GL_ZERO);
969 R_Mesh_Draw(0, 4, 2, polygonelements);
971 c_bloomdrawpixels += r_view_width * r_view_height;
972 // now blend on the bloom texture if multipass
975 memset(&m, 0, sizeof(m));
976 m.pointer_vertex = varray_vertex3f;
977 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
978 m.pointer_texcoord[0] = varray_texcoord2f[1];
980 GL_BlendFunc(GL_ONE, GL_ONE);
982 R_Mesh_Draw(0, 4, 2, polygonelements);
984 c_bloomdrawpixels += r_view_width * r_view_height;
987 if (r_refdef.viewblend[3] >= 0.01f)
989 // apply a color tint to the whole view
990 memset(&m, 0, sizeof(m));
991 m.pointer_vertex = varray_vertex3f;
993 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
994 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
995 R_Mesh_Draw(0, 4, 2, polygonelements);
999 void R_RenderScene(void);
1006 void R_RenderView(void)
1008 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
1009 return; //Host_Error ("R_RenderView: NULL worldmodel");
1011 r_view_width = bound(0, r_refdef.width, vid.realwidth);
1012 r_view_height = bound(0, r_refdef.height, vid.realheight);
1014 r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
1015 r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
1017 r_view_fov_x = bound(1, r_refdef.fov_x, 170);
1018 r_view_fov_y = bound(1, r_refdef.fov_y, 170);
1019 r_view_matrix = r_refdef.viewentitymatrix;
1020 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1021 r_rtworld = r_shadow_realtime_world.integer;
1022 r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
1023 r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
1024 r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
1025 r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
1027 // GL is weird because it's bottom to top, r_view_y is top to bottom
1028 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
1029 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1030 GL_ScissorTest(true);
1036 R_TimeReport("setup");
1038 qglDepthFunc(GL_LEQUAL);
1039 qglPolygonOffset(0, 0);
1040 qglEnable(GL_POLYGON_OFFSET_FILL);
1044 qglPolygonOffset(0, 0);
1045 qglDisable(GL_POLYGON_OFFSET_FILL);
1048 R_TimeReport("blendview");
1050 GL_Scissor(0, 0, vid.realwidth, vid.realheight);
1051 GL_ScissorTest(false);
1054 extern void R_DrawLightningBeams (void);
1055 void R_RenderScene(void)
1057 // don't let sound skip if going slow
1058 if (r_refdef.extraupdate)
1063 R_MeshQueue_BeginScene();
1065 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1069 r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
1070 if (r_rtworldshadows || r_rtdlightshadows)
1071 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
1073 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
1075 GL_SetupView_Orientation_FromEntity(&r_view_matrix);
1079 R_WorldVisibility();
1080 R_TimeReport("worldvis");
1083 R_TimeReport("markentity");
1085 R_Shadow_UpdateWorldLightSelection();
1087 // don't let sound skip if going slow
1088 if (r_refdef.extraupdate)
1091 GL_ShowTrisColor(0.025, 0.025, 0, 1);
1092 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
1094 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
1095 R_TimeReport("worldsky");
1098 if (R_DrawBrushModelsSky())
1099 R_TimeReport("bmodelsky");
1101 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1102 if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
1104 r_refdef.worldmodel->Draw(r_refdef.worldentity);
1105 R_TimeReport("world");
1108 // don't let sound skip if going slow
1109 if (r_refdef.extraupdate)
1112 GL_ShowTrisColor(0, 0.015, 0, 1);
1115 R_TimeReport("models");
1117 // don't let sound skip if going slow
1118 if (r_refdef.extraupdate)
1121 GL_ShowTrisColor(0, 0, 0.033, 1);
1122 R_ShadowVolumeLighting(false);
1123 R_TimeReport("rtlights");
1125 // don't let sound skip if going slow
1126 if (r_refdef.extraupdate)
1129 GL_ShowTrisColor(0.1, 0, 0, 1);
1131 R_DrawLightningBeams();
1132 R_TimeReport("lightning");
1135 R_TimeReport("particles");
1138 R_TimeReport("explosions");
1140 R_MeshQueue_RenderTransparent();
1141 R_TimeReport("drawtrans");
1144 R_TimeReport("coronas");
1146 R_DrawWorldCrosshair();
1147 R_TimeReport("crosshair");
1149 R_MeshQueue_Render();
1150 R_MeshQueue_EndScene();
1152 if ((r_shadow_visiblelighting.integer || r_shadow_visiblevolumes.integer) && !r_showtrispass)
1154 R_ShadowVolumeLighting(true);
1155 R_TimeReport("visiblevolume");
1158 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1160 // don't let sound skip if going slow
1161 if (r_refdef.extraupdate)
1166 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
1169 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
1171 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1172 GL_DepthMask(false);
1174 R_Mesh_Matrix(&r_identitymatrix);
1176 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
1177 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
1178 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
1179 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
1180 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
1181 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
1182 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
1183 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
1184 R_FillColors(color, 8, cr, cg, cb, ca);
1187 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
1189 VectorSubtract(v, r_vieworigin, diff);
1190 f2 = exp(fogdensity/DotProduct(diff, diff));
1192 c[0] = c[0] * f1 + fogcolor[0] * f2;
1193 c[1] = c[1] * f1 + fogcolor[1] * f2;
1194 c[2] = c[2] * f1 + fogcolor[2] * f2;
1197 memset(&m, 0, sizeof(m));
1198 m.pointer_vertex = vertex3f;
1199 m.pointer_color = color;
1205 int nomodelelements[24] =
1217 float nomodelvertex3f[6*3] =
1227 float nomodelcolor4f[6*4] =
1229 0.0f, 0.0f, 0.5f, 1.0f,
1230 0.0f, 0.0f, 0.5f, 1.0f,
1231 0.0f, 0.5f, 0.0f, 1.0f,
1232 0.0f, 0.5f, 0.0f, 1.0f,
1233 0.5f, 0.0f, 0.0f, 1.0f,
1234 0.5f, 0.0f, 0.0f, 1.0f
1237 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1239 const entity_render_t *ent = calldata1;
1241 float f1, f2, *c, diff[3];
1244 R_Mesh_Matrix(&ent->matrix);
1246 memset(&m, 0, sizeof(m));
1247 m.pointer_vertex = nomodelvertex3f;
1249 if (ent->flags & EF_ADDITIVE)
1251 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1252 GL_DepthMask(false);
1254 else if (ent->alpha < 1)
1256 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1257 GL_DepthMask(false);
1261 GL_BlendFunc(GL_ONE, GL_ZERO);
1264 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
1267 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1268 m.pointer_color = color4f;
1269 VectorSubtract(ent->origin, r_vieworigin, diff);
1270 f2 = exp(fogdensity/DotProduct(diff, diff));
1272 for (i = 0, c = color4f;i < 6;i++, c += 4)
1274 c[0] = (c[0] * f1 + fogcolor[0] * f2);
1275 c[1] = (c[1] * f1 + fogcolor[1] * f2);
1276 c[2] = (c[2] * f1 + fogcolor[2] * f2);
1280 else if (ent->alpha != 1)
1282 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1283 m.pointer_color = color4f;
1284 for (i = 0, c = color4f;i < 6;i++, c += 4)
1288 m.pointer_color = nomodelcolor4f;
1290 R_Mesh_Draw(0, 6, 8, nomodelelements);
1293 void R_DrawNoModel(entity_render_t *ent)
1295 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1296 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1298 // R_DrawNoModelCallback(ent, 0);
1301 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1303 vec3_t right1, right2, diff, normal;
1305 VectorSubtract (org2, org1, normal);
1307 // calculate 'right' vector for start
1308 VectorSubtract (r_vieworigin, org1, diff);
1309 CrossProduct (normal, diff, right1);
1310 VectorNormalize (right1);
1312 // calculate 'right' vector for end
1313 VectorSubtract (r_vieworigin, org2, diff);
1314 CrossProduct (normal, diff, right2);
1315 VectorNormalize (right2);
1317 vert[ 0] = org1[0] + width * right1[0];
1318 vert[ 1] = org1[1] + width * right1[1];
1319 vert[ 2] = org1[2] + width * right1[2];
1320 vert[ 3] = org1[0] - width * right1[0];
1321 vert[ 4] = org1[1] - width * right1[1];
1322 vert[ 5] = org1[2] - width * right1[2];
1323 vert[ 6] = org2[0] - width * right2[0];
1324 vert[ 7] = org2[1] - width * right2[1];
1325 vert[ 8] = org2[2] - width * right2[2];
1326 vert[ 9] = org2[0] + width * right2[0];
1327 vert[10] = org2[1] + width * right2[1];
1328 vert[11] = org2[2] + width * right2[2];
1331 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1333 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)
1340 VectorSubtract(origin, r_vieworigin, diff);
1341 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1344 R_Mesh_Matrix(&r_identitymatrix);
1345 GL_BlendFunc(blendfunc1, blendfunc2);
1346 GL_DepthMask(false);
1347 GL_DepthTest(!depthdisable);
1349 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1350 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1351 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1352 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1353 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1354 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1355 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1356 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1357 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1358 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1359 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1360 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1362 memset(&m, 0, sizeof(m));
1363 m.tex[0] = R_GetTexture(texture);
1364 m.pointer_texcoord[0] = spritetexcoord2f;
1365 m.pointer_vertex = varray_vertex3f;
1367 GL_Color(cr, cg, cb, ca);
1368 R_Mesh_Draw(0, 4, 2, polygonelements);
1371 int R_Mesh_AddVertex3f(rmesh_t *mesh, const float *v)
1375 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
1376 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
1378 if (i == mesh->numvertices)
1380 if (mesh->numvertices < mesh->maxvertices)
1382 VectorCopy(v, vertex3f);
1383 mesh->numvertices++;
1385 return mesh->numvertices;
1391 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
1395 element[0] = R_Mesh_AddVertex3f(mesh, vertex3f);vertex3f += 3;
1396 element[1] = R_Mesh_AddVertex3f(mesh, vertex3f);vertex3f += 3;
1397 e = mesh->element3i + mesh->numtriangles * 3;
1398 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
1400 element[2] = R_Mesh_AddVertex3f(mesh, vertex3f);
1401 if (mesh->numtriangles < mesh->maxtriangles)
1406 mesh->numtriangles++;
1408 element[1] = element[2];
1412 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
1414 int planenum, planenum2;
1417 mplane_t *plane, *plane2;
1418 float temppoints[2][256*3];
1419 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
1423 PolygonF_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->normal[3], 1024.0*1024.0*1024.0);
1424 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
1426 if (planenum2 == planenum)
1428 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);
1431 if (tempnumpoints < 3)
1433 // generate elements forming a triangle fan for this polygon
1434 R_Mesh_AddPolygon3f(mesh, tempnumpoints, temppoints[w]);