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.
25 // used for dlight push checking and other things
30 matrix4x4_t r_identitymatrix;
32 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 // true during envmap command capture
37 // maximum visible distance (recalculated from world box each frame)
39 // brightness of world lightmaps and related lighting
40 // (often reduced when world rtlights are enabled)
41 float r_lightmapintensity;
42 // whether to draw world lights realtime, dlights realtime, and their shadows
44 qboolean r_rtworldshadows;
46 qboolean r_rtdlightshadows;
49 // forces all rendering to draw triangle outlines
66 matrix4x4_t r_view_matrix;
73 // 8.8 fraction of base light value
74 unsigned short d_lightstylevalue[256];
76 cvar_t r_showtris = {0, "r_showtris", "0"};
77 cvar_t r_drawentities = {0, "r_drawentities","1"};
78 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
79 cvar_t r_speeds = {0, "r_speeds","0"};
80 cvar_t r_fullbright = {0, "r_fullbright","0"};
81 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
82 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
83 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
84 cvar_t r_drawcollisionbrushes = {0, "r_drawcollisionbrushes", "0"};
86 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
87 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
88 cvar_t gl_fogred = {0, "gl_fogred","0.3"};
89 cvar_t gl_foggreen = {0, "gl_foggreen","0.3"};
90 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
91 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
92 cvar_t gl_fogend = {0, "gl_fogend","0"};
94 cvar_t r_textureunits = {0, "r_textureunits", "32"};
96 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1"};
97 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"};
98 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
99 cvar_t r_watershader = {CVAR_SAVE, "r_watershader", "1"};
101 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0"};
102 cvar_t r_bloom_intensity = {CVAR_SAVE, "r_bloom_intensity", "2"};
103 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "8"};
104 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320"};
105 cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "4"};
107 cvar_t developer_texturelogging = {0, "developer_texturelogging", "1"};
109 rtexturepool_t *r_main_texturepool;
110 rtexture_t *r_bloom_texture_screen;
111 rtexture_t *r_bloom_texture_bloom;
112 rtexture_t *r_texture_blanknormalmap;
113 rtexture_t *r_texture_white;
114 rtexture_t *r_texture_black;
115 rtexture_t *r_texture_notexture;
116 rtexture_t *r_texture_whitecube;
117 rtexture_t *r_texture_normalizationcube;
118 rtexture_t *r_texture_detailtextures[NUM_DETAILTEXTURES];
119 rtexture_t *r_texture_distorttexture[64];
121 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
124 for (i = 0;i < verts;i++)
135 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
138 for (i = 0;i < verts;i++)
150 float fog_density, fog_red, fog_green, fog_blue;
152 qboolean oldgl_fogenable;
153 void R_UpdateFog(void)
155 if (gamemode == GAME_NEHAHRA)
157 if (gl_fogenable.integer)
159 oldgl_fogenable = true;
160 fog_density = gl_fogdensity.value;
161 fog_red = gl_fogred.value;
162 fog_green = gl_foggreen.value;
163 fog_blue = gl_fogblue.value;
165 else if (oldgl_fogenable)
167 oldgl_fogenable = false;
176 fogcolor[0] = fog_red = bound(0.0f, fog_red , 1.0f);
177 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
178 fogcolor[2] = fog_blue = bound(0.0f, fog_blue , 1.0f);
183 fogdensity = -4000.0f / (fog_density * fog_density);
184 // fog color was already set
190 // FIXME: move this to client?
193 if (gamemode == GAME_NEHAHRA)
195 Cvar_Set("gl_fogenable", "0");
196 Cvar_Set("gl_fogdensity", "0.2");
197 Cvar_Set("gl_fogred", "0.3");
198 Cvar_Set("gl_foggreen", "0.3");
199 Cvar_Set("gl_fogblue", "0.3");
201 fog_density = fog_red = fog_green = fog_blue = 0.0f;
204 // FIXME: move this to client?
205 void FOG_registercvars(void)
207 if (gamemode == GAME_NEHAHRA)
209 Cvar_RegisterVariable (&gl_fogenable);
210 Cvar_RegisterVariable (&gl_fogdensity);
211 Cvar_RegisterVariable (&gl_fogred);
212 Cvar_RegisterVariable (&gl_foggreen);
213 Cvar_RegisterVariable (&gl_fogblue);
214 Cvar_RegisterVariable (&gl_fogstart);
215 Cvar_RegisterVariable (&gl_fogend);
219 static void R_BuildDetailTextures (void)
222 float vc[3], vx[3], vy[3], vn[3], lightdir[3];
223 #define DETAILRESOLUTION 256
224 qbyte data[DETAILRESOLUTION][DETAILRESOLUTION][4], noise[DETAILRESOLUTION][DETAILRESOLUTION];
228 VectorNormalize(lightdir);
229 for (i = 0;i < NUM_DETAILTEXTURES;i++)
231 fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4);
232 for (y = 0;y < DETAILRESOLUTION;y++)
234 for (x = 0;x < DETAILRESOLUTION;x++)
238 vc[2] = noise[y][x] * (1.0f / 32.0f);
241 vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f);
244 vy[2] = noise[(y + 1) % DETAILRESOLUTION][x] * (1.0f / 32.0f);
245 VectorSubtract(vx, vc, vx);
246 VectorSubtract(vy, vc, vy);
247 CrossProduct(vx, vy, vn);
249 light = 128 - DotProduct(vn, lightdir) * 128;
250 light = bound(0, light, 255);
251 data[y][x][0] = data[y][x][1] = data[y][x][2] = light;
255 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);
259 static qbyte R_MorphDistortTexture (double y0, double y1, double y2, double y3, double morph)
261 int m = (int)(((y1 + y3 - (y0 + y2)) * morph * morph * morph) +
262 ((2 * (y0 - y1) + y2 - y3) * morph * morph) +
263 ((y2 - y0) * morph) +
265 return (qbyte)bound(0, m, 255);
268 static void R_BuildDistortTexture (void)
271 #define DISTORTRESOLUTION 32
272 qbyte data[5][DISTORTRESOLUTION][DISTORTRESOLUTION][2];
276 for (y=0; y<DISTORTRESOLUTION; y++)
278 for (x=0; x<DISTORTRESOLUTION; x++)
280 data[i][y][x][0] = rand () & 255;
281 data[i][y][x][1] = rand () & 255;
290 r_texture_distorttexture[i*16+j] = NULL;
291 if (gl_textureshader)
293 for (y=0; y<DISTORTRESOLUTION; y++)
295 for (x=0; x<DISTORTRESOLUTION; x++)
297 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);
298 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);
301 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);
307 static void R_BuildBlankTextures(void)
310 data[0] = 128; // normal X
311 data[1] = 128; // normal Y
312 data[2] = 255; // normal Z
313 data[3] = 128; // height
314 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
319 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
324 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
327 static void R_BuildNoTexture(void)
330 qbyte pix[16][16][4];
331 // this makes a light grey/dark grey checkerboard texture
332 for (y = 0;y < 16;y++)
334 for (x = 0;x < 16;x++)
336 if ((y < 8) ^ (x < 8))
352 r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
355 static void R_BuildWhiteCube(void)
358 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
359 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
360 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
361 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
362 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
363 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
364 r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
367 static void R_BuildNormalizationCube(void)
371 vec_t s, t, intensity;
373 qbyte data[6][NORMSIZE][NORMSIZE][4];
374 for (side = 0;side < 6;side++)
376 for (y = 0;y < NORMSIZE;y++)
378 for (x = 0;x < NORMSIZE;x++)
380 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
381 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
415 intensity = 127.0f / sqrt(DotProduct(v, v));
416 data[side][y][x][0] = 128.0f + intensity * v[0];
417 data[side][y][x][1] = 128.0f + intensity * v[1];
418 data[side][y][x][2] = 128.0f + intensity * v[2];
419 data[side][y][x][3] = 255;
423 r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
426 void gl_main_start(void)
428 r_main_texturepool = R_AllocTexturePool();
429 r_bloom_texture_screen = NULL;
430 r_bloom_texture_bloom = NULL;
431 R_BuildBlankTextures();
433 R_BuildDetailTextures();
434 R_BuildDistortTexture();
435 if (gl_texturecubemap)
438 R_BuildNormalizationCube();
442 void gl_main_shutdown(void)
444 R_FreeTexturePool(&r_main_texturepool);
445 r_bloom_texture_screen = NULL;
446 r_bloom_texture_bloom = NULL;
447 r_texture_blanknormalmap = NULL;
448 r_texture_white = NULL;
449 r_texture_black = NULL;
450 r_texture_whitecube = NULL;
451 r_texture_normalizationcube = NULL;
454 extern void CL_ParseEntityLump(char *entitystring);
455 void gl_main_newmap(void)
457 // FIXME: move this code to client
459 char *entities, entname[MAX_QPATH];
463 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
464 l = strlen(entname) - 4;
465 if (l >= 0 && !strcmp(entname + l, ".bsp"))
467 strcpy(entname + l, ".ent");
468 if ((entities = FS_LoadFile(entname, tempmempool, true)))
470 CL_ParseEntityLump(entities);
475 if (cl.worldmodel->brush.entities)
476 CL_ParseEntityLump(cl.worldmodel->brush.entities);
480 void GL_Main_Init(void)
482 Matrix4x4_CreateIdentity(&r_identitymatrix);
483 // FIXME: move this to client?
485 Cvar_RegisterVariable(&r_showtris);
486 Cvar_RegisterVariable(&r_drawentities);
487 Cvar_RegisterVariable(&r_drawviewmodel);
488 Cvar_RegisterVariable(&r_speeds);
489 Cvar_RegisterVariable(&r_fullbrights);
490 Cvar_RegisterVariable(&r_wateralpha);
491 Cvar_RegisterVariable(&r_dynamic);
492 Cvar_RegisterVariable(&r_fullbright);
493 Cvar_RegisterVariable(&r_textureunits);
494 Cvar_RegisterVariable(&r_lerpsprites);
495 Cvar_RegisterVariable(&r_lerpmodels);
496 Cvar_RegisterVariable(&r_waterscroll);
497 Cvar_RegisterVariable(&r_watershader);
498 Cvar_RegisterVariable(&r_drawcollisionbrushes);
499 Cvar_RegisterVariable(&r_bloom);
500 Cvar_RegisterVariable(&r_bloom_intensity);
501 Cvar_RegisterVariable(&r_bloom_blur);
502 Cvar_RegisterVariable(&r_bloom_resolution);
503 Cvar_RegisterVariable(&r_bloom_power);
504 Cvar_RegisterVariable(&developer_texturelogging);
505 if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
506 Cvar_SetValue("r_fullbrights", 0);
507 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
510 static vec3_t r_farclip_origin;
511 static vec3_t r_farclip_direction;
512 static vec_t r_farclip_directiondist;
513 static vec_t r_farclip_meshfarclip;
514 static int r_farclip_directionbit0;
515 static int r_farclip_directionbit1;
516 static int r_farclip_directionbit2;
518 // enlarge farclip to accomodate box
519 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
522 d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
523 + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
524 + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
525 if (r_farclip_meshfarclip < d)
526 r_farclip_meshfarclip = d;
529 // return farclip value
530 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
534 VectorCopy(origin, r_farclip_origin);
535 VectorCopy(direction, r_farclip_direction);
536 r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
537 r_farclip_directionbit0 = r_farclip_direction[0] < 0;
538 r_farclip_directionbit1 = r_farclip_direction[1] < 0;
539 r_farclip_directionbit2 = r_farclip_direction[2] < 0;
540 r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
542 if (r_refdef.worldmodel)
543 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
544 for (i = 0;i < r_refdef.numentities;i++)
545 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
547 return r_farclip_meshfarclip - r_farclip_directiondist;
550 extern void R_Textures_Init(void);
551 extern void Mod_RenderInit(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 GL_Models_Init(void);
556 extern void R_Sky_Init(void);
557 extern void GL_Surf_Init(void);
558 extern void R_Crosshairs_Init(void);
559 extern void R_Light_Init(void);
560 extern void R_Particles_Init(void);
561 extern void R_Explosion_Init(void);
562 extern void ui_init(void);
563 extern void gl_backend_init(void);
564 extern void Sbar_Init(void);
565 extern void R_LightningBeams_Init(void);
567 void Render_Init(void)
586 R_LightningBeams_Init();
594 extern char *ENGINE_EXTENSIONS;
597 VID_CheckExtensions();
599 // LordHavoc: report supported extensions
600 Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
602 // clear to black (loading plaque will be seen over this)
603 qglClearColor(0,0,0,1);
604 qglClear(GL_COLOR_BUFFER_BIT);
607 int R_CullBox(const vec3_t mins, const vec3_t maxs)
611 for (i = 0;i < 4;i++)
618 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
622 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
626 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
630 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
634 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
638 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
642 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
646 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
654 //==================================================================================
656 static void R_MarkEntities (void)
659 entity_render_t *ent;
661 if (!r_drawentities.integer)
664 r_refdef.worldentity->visframe = r_framecount;
665 renderimask = envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
666 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
668 // worldmodel can check visibility
669 for (i = 0;i < r_refdef.numentities;i++)
671 ent = r_refdef.entities[i];
672 Mod_CheckLoaded(ent->model);
673 // some of the renderer still relies on origin...
674 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
675 // some of the renderer still relies on scale...
676 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
677 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)))
679 R_UpdateEntLights(ent);
680 ent->visframe = r_framecount;
686 // no worldmodel or it can't check visibility
687 for (i = 0;i < r_refdef.numentities;i++)
689 ent = r_refdef.entities[i];
690 Mod_CheckLoaded(ent->model);
691 // some of the renderer still relies on origin...
692 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
693 // some of the renderer still relies on scale...
694 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
695 if (!(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && (ent->effects & EF_NODEPTHTEST))
697 R_UpdateEntLights(ent);
698 ent->visframe = r_framecount;
704 // only used if skyrendermasked, and normally returns false
705 int R_DrawBrushModelsSky (void)
708 entity_render_t *ent;
710 if (!r_drawentities.integer)
714 for (i = 0;i < r_refdef.numentities;i++)
716 ent = r_refdef.entities[i];
717 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
719 ent->model->DrawSky(ent);
726 void R_DrawNoModel(entity_render_t *ent);
727 void R_DrawModels(void)
730 entity_render_t *ent;
732 if (!r_drawentities.integer)
735 for (i = 0;i < r_refdef.numentities;i++)
737 ent = r_refdef.entities[i];
738 if (ent->visframe == r_framecount)
740 if (ent->model && ent->model->Draw != NULL)
741 ent->model->Draw(ent);
748 static void R_SetFrustum(void)
750 // break apart the view matrix into vectors for various purposes
751 Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
752 VectorNegate(r_viewleft, r_viewright);
754 // LordHavoc: note to all quake engine coders, the special case for 90
755 // degrees assumed a square view (wrong), so I removed it, Quake2 has it
758 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
759 RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
760 frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
761 PlaneClassify(&frustum[0]);
763 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
764 RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
765 frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
766 PlaneClassify(&frustum[1]);
768 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
769 RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
770 frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
771 PlaneClassify(&frustum[2]);
773 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
774 RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
775 frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
776 PlaneClassify(&frustum[3]);
779 static void R_BlendView(void)
783 if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
786 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
789 R_Mesh_Matrix(&r_identitymatrix);
790 // vertex coordinates for a quad that covers the screen exactly
791 varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
792 varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
793 varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
794 varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
795 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)
797 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
798 float xoffset, yoffset, r;
800 // set the (poorly named) screenwidth and screenheight variables to
801 // a power of 2 at least as large as the screen, these will define the
802 // size of the texture to allocate
803 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
804 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
805 // allocate textures as needed
806 if (!r_bloom_texture_screen)
807 r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
808 if (!r_bloom_texture_bloom)
809 r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
810 // set bloomwidth and bloomheight to the bloom resolution that will be
811 // used (often less than the screen resolution for faster rendering)
812 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
813 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
814 // set up a texcoord array for the full resolution screen image
815 // (we have to keep this around to copy back during final render)
816 varray_texcoord2f[0][0] = 0;
817 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
818 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
819 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
820 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
821 varray_texcoord2f[0][5] = 0;
822 varray_texcoord2f[0][6] = 0;
823 varray_texcoord2f[0][7] = 0;
824 // set up a texcoord array for the reduced resolution bloom image
825 // (which will be additive blended over the screen image)
826 varray_texcoord2f[1][0] = 0;
827 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
828 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
829 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
830 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
831 varray_texcoord2f[1][5] = 0;
832 varray_texcoord2f[1][6] = 0;
833 varray_texcoord2f[1][7] = 0;
834 memset(&m, 0, sizeof(m));
835 m.pointer_vertex = varray_vertex3f;
836 m.pointer_texcoord[0] = varray_texcoord2f[0];
837 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
839 // copy view into the full resolution screen image texture
841 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
843 c_bloomcopypixels += r_view_width * r_view_height;
844 // now scale it down to the bloom size and raise to a power of itself
845 // to darken it (this leaves the really bright stuff bright, and
846 // everything else becomes very dark)
847 // TODO: optimize with multitexture or GLSL
848 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
849 GL_BlendFunc(GL_ONE, GL_ZERO);
850 GL_Color(1, 1, 1, 1);
851 R_Mesh_Draw(0, 4, 2, polygonelements);
853 c_bloomdrawpixels += bloomwidth * bloomheight;
854 // render multiple times with a multiply blendfunc to raise to a power
855 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
856 for (x = 1;x < r_bloom_power.integer;x++)
858 R_Mesh_Draw(0, 4, 2, polygonelements);
860 c_bloomdrawpixels += bloomwidth * bloomheight;
862 // we now have a darkened bloom image in the framebuffer, copy it into
863 // the bloom image texture for more processing
864 memset(&m, 0, sizeof(m));
865 m.pointer_vertex = varray_vertex3f;
866 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
867 m.pointer_texcoord[0] = varray_texcoord2f[2];
870 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
872 c_bloomcopypixels += bloomwidth * bloomheight;
873 // blend on at multiple vertical offsets to achieve a vertical blur
874 // TODO: do offset blends using GLSL
875 range = r_bloom_blur.integer * bloomwidth / 320;
876 GL_BlendFunc(GL_ONE, GL_ZERO);
877 for (x = -range;x <= range;x++)
879 xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
880 yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
881 // compute a texcoord array with the specified x and y offset
882 varray_texcoord2f[2][0] = xoffset+0;
883 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
884 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
885 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
886 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
887 varray_texcoord2f[2][5] = yoffset+0;
888 varray_texcoord2f[2][6] = xoffset+0;
889 varray_texcoord2f[2][7] = yoffset+0;
890 // this r value looks like a 'dot' particle, fading sharply to
891 // black at the edges
892 // (probably not realistic but looks good enough)
893 r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
896 GL_Color(r, r, r, 1);
897 R_Mesh_Draw(0, 4, 2, polygonelements);
899 c_bloomdrawpixels += bloomwidth * bloomheight;
900 GL_BlendFunc(GL_ONE, GL_ONE);
902 // copy the vertically blurred bloom view to a texture
904 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
906 c_bloomcopypixels += bloomwidth * bloomheight;
907 // blend the vertically blurred image at multiple offsets horizontally
908 // to finish the blur effect
909 // TODO: do offset blends using GLSL
910 range = r_bloom_blur.integer * bloomwidth / 320;
911 GL_BlendFunc(GL_ONE, GL_ZERO);
912 for (x = -range;x <= range;x++)
914 xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
915 yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
916 // compute a texcoord array with the specified x and y offset
917 varray_texcoord2f[2][0] = xoffset+0;
918 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
919 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
920 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
921 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
922 varray_texcoord2f[2][5] = yoffset+0;
923 varray_texcoord2f[2][6] = xoffset+0;
924 varray_texcoord2f[2][7] = yoffset+0;
925 // this r value looks like a 'dot' particle, fading sharply to
926 // black at the edges
927 // (probably not realistic but looks good enough)
928 r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
931 GL_Color(r, r, r, 1);
932 R_Mesh_Draw(0, 4, 2, polygonelements);
934 c_bloomdrawpixels += bloomwidth * bloomheight;
935 GL_BlendFunc(GL_ONE, GL_ONE);
937 // copy the blurred bloom view to a texture
939 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
941 c_bloomcopypixels += bloomwidth * bloomheight;
942 // go back to full view area
943 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
944 // put the original screen image back in place and blend the bloom
946 memset(&m, 0, sizeof(m));
947 m.pointer_vertex = varray_vertex3f;
948 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
949 m.pointer_texcoord[0] = varray_texcoord2f[0];
951 dobloomblend = false;
953 // do both in one pass if possible
954 if (r_textureunits.integer >= 2 && gl_combine.integer)
956 dobloomblend = false;
957 m.texcombinergb[1] = GL_ADD;
958 m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
959 m.pointer_texcoord[1] = varray_texcoord2f[1];
965 GL_BlendFunc(GL_ONE, GL_ZERO);
967 R_Mesh_Draw(0, 4, 2, polygonelements);
969 c_bloomdrawpixels += r_view_width * r_view_height;
970 // now blend on the bloom texture if multipass
973 memset(&m, 0, sizeof(m));
974 m.pointer_vertex = varray_vertex3f;
975 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
976 m.pointer_texcoord[0] = varray_texcoord2f[1];
978 GL_BlendFunc(GL_ONE, GL_ONE);
980 R_Mesh_Draw(0, 4, 2, polygonelements);
982 c_bloomdrawpixels += r_view_width * r_view_height;
985 if (r_refdef.viewblend[3] >= 0.01f)
987 // apply a color tint to the whole view
988 memset(&m, 0, sizeof(m));
989 m.pointer_vertex = varray_vertex3f;
991 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
992 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
993 R_Mesh_Draw(0, 4, 2, polygonelements);
997 void R_RenderScene(void);
1004 void R_RenderView(void)
1006 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
1007 return; //Host_Error ("R_RenderView: NULL worldmodel");
1009 r_view_width = bound(0, r_refdef.width, vid.realwidth);
1010 r_view_height = bound(0, r_refdef.height, vid.realheight);
1012 r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
1013 r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
1015 r_view_fov_x = bound(1, r_refdef.fov_x, 170);
1016 r_view_fov_y = bound(1, r_refdef.fov_y, 170);
1017 r_view_matrix = r_refdef.viewentitymatrix;
1018 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1019 r_rtworld = r_shadow_realtime_world.integer;
1020 r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
1021 r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
1022 r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
1023 r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
1025 // GL is weird because it's bottom to top, r_view_y is top to bottom
1026 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
1027 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1028 GL_ScissorTest(true);
1034 R_TimeReport("setup");
1036 qglDepthFunc(GL_LEQUAL);
1037 qglPolygonOffset(0, 0);
1038 qglEnable(GL_POLYGON_OFFSET_FILL);
1042 qglPolygonOffset(0, 0);
1043 qglDisable(GL_POLYGON_OFFSET_FILL);
1046 R_TimeReport("blendview");
1048 GL_Scissor(0, 0, vid.realwidth, vid.realheight);
1049 GL_ScissorTest(false);
1052 extern void R_DrawLightningBeams (void);
1053 void R_RenderScene(void)
1055 // don't let sound skip if going slow
1056 if (r_refdef.extraupdate)
1061 R_MeshQueue_BeginScene();
1063 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1067 r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
1068 if (r_rtworldshadows || r_rtdlightshadows)
1069 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
1071 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
1073 GL_SetupView_Orientation_FromEntity(&r_view_matrix);
1077 R_WorldVisibility();
1078 R_TimeReport("worldvis");
1081 R_TimeReport("markentity");
1083 R_Shadow_UpdateWorldLightSelection();
1085 // don't let sound skip if going slow
1086 if (r_refdef.extraupdate)
1089 GL_ShowTrisColor(0.025, 0.025, 0, 1);
1090 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
1092 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
1093 R_TimeReport("worldsky");
1096 if (R_DrawBrushModelsSky())
1097 R_TimeReport("bmodelsky");
1099 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1100 if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
1102 r_refdef.worldmodel->Draw(r_refdef.worldentity);
1103 R_TimeReport("world");
1106 // don't let sound skip if going slow
1107 if (r_refdef.extraupdate)
1110 GL_ShowTrisColor(0, 0.015, 0, 1);
1113 R_TimeReport("models");
1115 // don't let sound skip if going slow
1116 if (r_refdef.extraupdate)
1119 GL_ShowTrisColor(0, 0, 0.033, 1);
1120 R_ShadowVolumeLighting(false);
1121 R_TimeReport("rtlights");
1123 // don't let sound skip if going slow
1124 if (r_refdef.extraupdate)
1127 GL_ShowTrisColor(0.1, 0, 0, 1);
1129 R_DrawLightningBeams();
1130 R_TimeReport("lightning");
1133 R_TimeReport("particles");
1136 R_TimeReport("explosions");
1138 R_MeshQueue_RenderTransparent();
1139 R_TimeReport("drawtrans");
1142 R_TimeReport("coronas");
1144 R_DrawWorldCrosshair();
1145 R_TimeReport("crosshair");
1147 R_MeshQueue_Render();
1148 R_MeshQueue_EndScene();
1150 if ((r_shadow_visiblelighting.integer || r_shadow_visiblevolumes.integer) && !r_showtrispass)
1152 R_ShadowVolumeLighting(true);
1153 R_TimeReport("visiblevolume");
1156 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1158 // don't let sound skip if going slow
1159 if (r_refdef.extraupdate)
1164 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
1167 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
1169 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1170 GL_DepthMask(false);
1172 R_Mesh_Matrix(&r_identitymatrix);
1174 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
1175 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
1176 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
1177 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
1178 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
1179 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
1180 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
1181 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
1182 R_FillColors(color, 8, cr, cg, cb, ca);
1185 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
1187 VectorSubtract(v, r_vieworigin, diff);
1188 f2 = exp(fogdensity/DotProduct(diff, diff));
1190 c[0] = c[0] * f1 + fogcolor[0] * f2;
1191 c[1] = c[1] * f1 + fogcolor[1] * f2;
1192 c[2] = c[2] * f1 + fogcolor[2] * f2;
1195 memset(&m, 0, sizeof(m));
1196 m.pointer_vertex = vertex3f;
1197 m.pointer_color = color;
1203 int nomodelelements[24] =
1215 float nomodelvertex3f[6*3] =
1225 float nomodelcolor4f[6*4] =
1227 0.0f, 0.0f, 0.5f, 1.0f,
1228 0.0f, 0.0f, 0.5f, 1.0f,
1229 0.0f, 0.5f, 0.0f, 1.0f,
1230 0.0f, 0.5f, 0.0f, 1.0f,
1231 0.5f, 0.0f, 0.0f, 1.0f,
1232 0.5f, 0.0f, 0.0f, 1.0f
1235 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1237 const entity_render_t *ent = calldata1;
1239 float f1, f2, *c, diff[3];
1242 R_Mesh_Matrix(&ent->matrix);
1244 memset(&m, 0, sizeof(m));
1245 m.pointer_vertex = nomodelvertex3f;
1247 if (ent->flags & EF_ADDITIVE)
1249 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1250 GL_DepthMask(false);
1252 else if (ent->alpha < 1)
1254 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1255 GL_DepthMask(false);
1259 GL_BlendFunc(GL_ONE, GL_ZERO);
1262 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
1265 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1266 m.pointer_color = color4f;
1267 VectorSubtract(ent->origin, r_vieworigin, diff);
1268 f2 = exp(fogdensity/DotProduct(diff, diff));
1270 for (i = 0, c = color4f;i < 6;i++, c += 4)
1272 c[0] = (c[0] * f1 + fogcolor[0] * f2);
1273 c[1] = (c[1] * f1 + fogcolor[1] * f2);
1274 c[2] = (c[2] * f1 + fogcolor[2] * f2);
1278 else if (ent->alpha != 1)
1280 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1281 m.pointer_color = color4f;
1282 for (i = 0, c = color4f;i < 6;i++, c += 4)
1286 m.pointer_color = nomodelcolor4f;
1288 R_Mesh_Draw(0, 6, 8, nomodelelements);
1291 void R_DrawNoModel(entity_render_t *ent)
1293 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1294 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1296 // R_DrawNoModelCallback(ent, 0);
1299 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1301 vec3_t right1, right2, diff, normal;
1303 VectorSubtract (org2, org1, normal);
1305 // calculate 'right' vector for start
1306 VectorSubtract (r_vieworigin, org1, diff);
1307 CrossProduct (normal, diff, right1);
1308 VectorNormalize (right1);
1310 // calculate 'right' vector for end
1311 VectorSubtract (r_vieworigin, org2, diff);
1312 CrossProduct (normal, diff, right2);
1313 VectorNormalize (right2);
1315 vert[ 0] = org1[0] + width * right1[0];
1316 vert[ 1] = org1[1] + width * right1[1];
1317 vert[ 2] = org1[2] + width * right1[2];
1318 vert[ 3] = org1[0] - width * right1[0];
1319 vert[ 4] = org1[1] - width * right1[1];
1320 vert[ 5] = org1[2] - width * right1[2];
1321 vert[ 6] = org2[0] - width * right2[0];
1322 vert[ 7] = org2[1] - width * right2[1];
1323 vert[ 8] = org2[2] - width * right2[2];
1324 vert[ 9] = org2[0] + width * right2[0];
1325 vert[10] = org2[1] + width * right2[1];
1326 vert[11] = org2[2] + width * right2[2];
1329 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1331 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)
1338 VectorSubtract(origin, r_vieworigin, diff);
1339 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1342 R_Mesh_Matrix(&r_identitymatrix);
1343 GL_BlendFunc(blendfunc1, blendfunc2);
1344 GL_DepthMask(false);
1345 GL_DepthTest(!depthdisable);
1347 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1348 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1349 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1350 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1351 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1352 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1353 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1354 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1355 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1356 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1357 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1358 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1360 memset(&m, 0, sizeof(m));
1361 m.tex[0] = R_GetTexture(texture);
1362 m.pointer_texcoord[0] = spritetexcoord2f;
1363 m.pointer_vertex = varray_vertex3f;
1365 GL_Color(cr, cg, cb, ca);
1366 R_Mesh_Draw(0, 4, 2, polygonelements);