// used for dlight push checking and other things
int r_framecount;
-// used for visibility checking
-qbyte r_pvsbits[(MAX_MAP_LEAFS+7)>>3];
-
mplane_t frustum[4];
matrix4x4_t r_identitymatrix;
-int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights;
+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;
// true during envmap command capture
qboolean envmap;
+// maximum visible distance (recalculated from world box each frame)
float r_farclip;
+// brightness of world lightmaps and related lighting
+// (often reduced when world rtlights are enabled)
+float r_lightmapintensity;
+// whether to draw world lights realtime, dlights realtime, and their shadows
+qboolean r_rtworld;
+qboolean r_rtworldshadows;
+qboolean r_rtdlight;
+qboolean r_rtdlightshadows;
+
// forces all rendering to draw triangle outlines
int r_showtrispass;
vec3_t r_viewup;
int r_view_x;
int r_view_y;
+int r_view_z;
int r_view_width;
int r_view_height;
+int r_view_depth;
float r_view_fov_x;
float r_view_fov_y;
matrix4x4_t r_view_matrix;
cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
cvar_t r_watershader = {CVAR_SAVE, "r_watershader", "1"};
+cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0"};
+cvar_t r_bloom_intensity = {CVAR_SAVE, "r_bloom_intensity", "2"};
+cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "8"};
+cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320"};
+cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "4"};
+rtexturepool_t *r_main_texturepool;
+rtexture_t *r_bloom_texture_screen;
+rtexture_t *r_bloom_texture_bloom;
+rtexture_t *r_texture_blanknormalmap;
+rtexture_t *r_texture_white;
+rtexture_t *r_texture_black;
+rtexture_t *r_texture_notexture;
void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
{
}
}
-/*
-====================
-R_TimeRefresh_f
-
-For program optimization
-====================
-*/
-qboolean intimerefresh = 0;
-static void R_TimeRefresh_f (void)
-{
- int i;
- float timestart, timedelta, oldangles[3];
-
- intimerefresh = 1;
- VectorCopy(cl.viewangles, oldangles);
- VectorClear(cl.viewangles);
-
- timestart = Sys_DoubleTime();
- for (i = 0;i < 128;i++)
- {
- Matrix4x4_CreateFromQuakeEntity(&r_refdef.viewentitymatrix, r_vieworigin[0], r_vieworigin[1], r_vieworigin[2], 0, i / 128.0 * 360.0, 0, 1);
- CL_UpdateScreen();
- }
- timedelta = Sys_DoubleTime() - timestart;
-
- VectorCopy(oldangles, cl.viewangles);
- intimerefresh = 0;
- Con_Printf ("%f seconds (%f fps)\n", timedelta, 128/timedelta);
-}
-
vec3_t fogcolor;
vec_t fogdensity;
float fog_density, fog_red, fog_green, fog_blue;
void gl_main_start(void)
{
+ int x, y;
+ qbyte pix[16][16][4];
+ qbyte data[4];
+ r_main_texturepool = R_AllocTexturePool();
+ r_bloom_texture_screen = NULL;
+ r_bloom_texture_bloom = NULL;
+ data[0] = 128; // normal X
+ data[1] = 128; // normal Y
+ data[2] = 255; // normal Z
+ data[3] = 128; // height
+ r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+ data[0] = 255;
+ data[1] = 255;
+ data[2] = 255;
+ data[3] = 255;
+ r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 255;
+ r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+ // this makes a light grey/dark grey checkerboard texture
+ for (y = 0;y < 16;y++)
+ {
+ for (x = 0;x < 16;x++)
+ {
+ if ((y < 8) ^ (x < 8))
+ {
+ pix[y][x][0] = 128;
+ pix[y][x][1] = 128;
+ pix[y][x][2] = 128;
+ pix[y][x][3] = 255;
+ }
+ else
+ {
+ pix[y][x][0] = 64;
+ pix[y][x][1] = 64;
+ pix[y][x][2] = 64;
+ pix[y][x][3] = 255;
+ }
+ }
+ }
+ r_texture_notexture = R_LoadTexture2D(mod_shared_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
}
void gl_main_shutdown(void)
{
+ R_FreeTexturePool(&r_main_texturepool);
+ r_bloom_texture_screen = NULL;
+ r_bloom_texture_bloom = NULL;
+ r_texture_blanknormalmap = NULL;
+ r_texture_white = NULL;
+ r_texture_black = NULL;
}
extern void CL_ParseEntityLump(char *entitystring);
void gl_main_newmap(void)
{
+ // FIXME: move this code to client
int l;
char *entities, entname[MAX_QPATH];
r_framecount = 1;
if (cl.worldmodel)
{
- strcpy(entname, cl.worldmodel->name);
+ strlcpy(entname, cl.worldmodel->name, sizeof(entname));
l = strlen(entname) - 4;
if (l >= 0 && !strcmp(entname + l, ".bsp"))
{
strcpy(entname + l, ".ent");
- if ((entities = FS_LoadFile(entname, true)))
+ if ((entities = FS_LoadFile(entname, tempmempool, true)))
{
CL_ParseEntityLump(entities);
Mem_Free(entities);
Matrix4x4_CreateIdentity(&r_identitymatrix);
// FIXME: move this to client?
FOG_registercvars();
- Cmd_AddCommand("timerefresh", R_TimeRefresh_f);
Cvar_RegisterVariable(&r_showtris);
Cvar_RegisterVariable(&r_drawentities);
Cvar_RegisterVariable(&r_drawviewmodel);
Cvar_RegisterVariable(&r_waterscroll);
Cvar_RegisterVariable(&r_watershader);
Cvar_RegisterVariable(&r_drawcollisionbrushes);
+ Cvar_RegisterVariable(&r_bloom);
+ Cvar_RegisterVariable(&r_bloom_intensity);
+ Cvar_RegisterVariable(&r_bloom_blur);
+ Cvar_RegisterVariable(&r_bloom_resolution);
+ Cvar_RegisterVariable(&r_bloom_power);
if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
Cvar_SetValue("r_fullbrights", 0);
R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
r_farclip_directionbit2 = r_farclip_direction[2] < 0;
r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
- if (cl.worldmodel)
- R_FarClip_Box(cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
+ if (r_refdef.worldmodel)
+ R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
for (i = 0;i < r_refdef.numentities;i++)
R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
-
+
return r_farclip_meshfarclip - r_farclip_directiondist;
}
// LordHavoc: report supported extensions
Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
+
+ // clear to black (loading plaque will be seen over this)
+ qglClearColor(0,0,0,1);
+ qglClear(GL_COLOR_BUFFER_BIT);
}
int R_CullBox(const vec3_t mins, const vec3_t maxs)
static void R_MarkEntities (void)
{
- int i;
+ int i, renderimask;
entity_render_t *ent;
- ent = &cl_entities[0].render;
- Matrix4x4_CreateIdentity(&ent->matrix);
- Matrix4x4_CreateIdentity(&ent->inversematrix);
-
if (!r_drawentities.integer)
return;
- for (i = 0;i < r_refdef.numentities;i++)
+ renderimask = envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
+ if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
{
- ent = r_refdef.entities[i];
- Mod_CheckLoaded(ent->model);
- // some of the renderer still relies on origin...
- Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
- // some of the renderer still relies on scale...
- ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
- R_LerpAnimation(ent);
- R_UpdateEntLights(ent);
- if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
- && !VIS_CullBox(ent->mins, ent->maxs)
- && (!envmap || !(ent->flags & (RENDER_VIEWMODEL | RENDER_EXTERIORMODEL))))
- ent->visframe = r_framecount;
+ // worldmodel can check visibility
+ for (i = 0;i < r_refdef.numentities;i++)
+ {
+ ent = r_refdef.entities[i];
+ Mod_CheckLoaded(ent->model);
+ // some of the renderer still relies on origin...
+ Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
+ // some of the renderer still relies on scale...
+ ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
+ 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)))
+ {
+ R_UpdateEntLights(ent);
+ ent->visframe = r_framecount;
+ }
+ }
+ }
+ else
+ {
+ // no worldmodel or it can't check visibility
+ for (i = 0;i < r_refdef.numentities;i++)
+ {
+ ent = r_refdef.entities[i];
+ Mod_CheckLoaded(ent->model);
+ // some of the renderer still relies on origin...
+ Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
+ // some of the renderer still relies on scale...
+ ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
+ if (!(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && (ent->effects & EF_NODEPTHTEST))
+ {
+ R_UpdateEntLights(ent);
+ ent->visframe = r_framecount;
+ }
+ }
}
}
return sky;
}
-/*
-=============
-R_DrawViewModel
-=============
-*/
-/*
-void R_DrawViewModel (void)
-{
- entity_render_t *ent;
-
- // FIXME: move these checks to client
- if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
- return;
-
- ent = &cl.viewent.render;
- Mod_CheckLoaded(ent->model);
- R_LerpAnimation(ent);
- Matrix4x4_CreateFromQuakeEntity(&ent->matrix, ent->origin[0], ent->origin[1], ent->origin[2], -ent->angles[0], ent->angles[1], ent->angles[2], ent->scale);
- Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix);
- R_UpdateEntLights(ent);
- ent->model->Draw(ent);
-}
-*/
-
void R_DrawNoModel(entity_render_t *ent);
void R_DrawModels(void)
{
static void R_BlendView(void)
{
rmeshstate_t m;
- float r;
- float vertex3f[3*3];
- if (r_refdef.viewblend[3] < 0.01f)
+ if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
return;
- R_Mesh_Matrix(&r_identitymatrix);
-
- memset(&m, 0, sizeof(m));
- R_Mesh_State_Texture(&m);
-
- GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
GL_DepthMask(true);
- GL_DepthTest(false); // magic
- GL_VertexPointer(vertex3f);
- GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
- r = 64;
- vertex3f[0] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r - r_viewup[0] * r;
- vertex3f[1] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r - r_viewup[1] * r;
- vertex3f[2] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r - r_viewup[2] * r;
- vertex3f[3] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r + r_viewup[0] * r * 3;
- vertex3f[4] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r + r_viewup[1] * r * 3;
- vertex3f[5] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r + r_viewup[2] * r * 3;
- vertex3f[6] = r_vieworigin[0] + r_viewforward[0] * 1.5 - r_viewleft[0] * r * 3 - r_viewup[0] * r;
- vertex3f[7] = r_vieworigin[1] + r_viewforward[1] * 1.5 - r_viewleft[1] * r * 3 - r_viewup[1] * r;
- vertex3f[8] = r_vieworigin[2] + r_viewforward[2] * 1.5 - r_viewleft[2] * r * 3 - r_viewup[2] * r;
- R_Mesh_Draw(3, 1, polygonelements);
-}
-
-void R_UpdateWorld(void)
-{
- if (!r_refdef.entities/* || !cl.worldmodel*/)
- return; //Host_Error ("R_RenderView: NULL worldmodel");
-
- if (r_shadow_realtime_world.integer && !gl_stencil)
+ GL_DepthTest(false);
+ R_Mesh_Matrix(&r_identitymatrix);
+ // vertex coordinates for a quad that covers the screen exactly
+ varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
+ varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
+ varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
+ varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
+ 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)
{
- Con_Printf("Realtime world lighting requires 32bit color; turning off r_shadow_realtime_world, please type vid_bitsperpixel 32;vid_restart and try again\n");
- Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
+ int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
+ float xoffset, yoffset, r;
+ c_bloom++;
+ // set the (poorly named) screenwidth and screenheight variables to
+ // a power of 2 at least as large as the screen, these will define the
+ // size of the texture to allocate
+ for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
+ for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
+ // allocate textures as needed
+ if (!r_bloom_texture_screen)
+ r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+ if (!r_bloom_texture_bloom)
+ r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+ // set bloomwidth and bloomheight to the bloom resolution that will be
+ // used (often less than the screen resolution for faster rendering)
+ bloomwidth = min(r_view_width, r_bloom_resolution.integer);
+ bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
+ // set up a texcoord array for the full resolution screen image
+ // (we have to keep this around to copy back during final render)
+ varray_texcoord2f[0][0] = 0;
+ varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
+ varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
+ varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
+ varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
+ varray_texcoord2f[0][5] = 0;
+ varray_texcoord2f[0][6] = 0;
+ varray_texcoord2f[0][7] = 0;
+ // set up a texcoord array for the reduced resolution bloom image
+ // (which will be additive blended over the screen image)
+ varray_texcoord2f[1][0] = 0;
+ varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
+ varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
+ varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
+ varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
+ varray_texcoord2f[1][5] = 0;
+ varray_texcoord2f[1][6] = 0;
+ varray_texcoord2f[1][7] = 0;
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = varray_vertex3f;
+ m.pointer_texcoord[0] = varray_texcoord2f[0];
+ m.tex[0] = R_GetTexture(r_bloom_texture_screen);
+ R_Mesh_State(&m);
+ // copy view into the full resolution screen image texture
+ GL_ActiveTexture(0);
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
+ c_bloomcopies++;
+ c_bloomcopypixels += r_view_width * r_view_height;
+ // now scale it down to the bloom size and raise to a power of itself
+ // to darken it (this leaves the really bright stuff bright, and
+ // everything else becomes very dark)
+ // TODO: optimize with multitexture or GLSL
+ qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_Color(1, 1, 1, 1);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+ c_bloomdraws++;
+ c_bloomdrawpixels += bloomwidth * bloomheight;
+ // render multiple times with a multiply blendfunc to raise to a power
+ GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
+ for (x = 1;x < r_bloom_power.integer;x++)
+ {
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+ c_bloomdraws++;
+ c_bloomdrawpixels += bloomwidth * bloomheight;
+ }
+ // we now have a darkened bloom image in the framebuffer, copy it into
+ // the bloom image texture for more processing
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = varray_vertex3f;
+ m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
+ m.pointer_texcoord[0] = varray_texcoord2f[2];
+ R_Mesh_State(&m);
+ GL_ActiveTexture(0);
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+ c_bloomcopies++;
+ c_bloomcopypixels += bloomwidth * bloomheight;
+ // blend on at multiple vertical offsets to achieve a vertical blur
+ // TODO: do offset blends using GLSL
+ range = r_bloom_blur.integer * bloomwidth / 320;
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ for (x = -range;x <= range;x++)
+ {
+ xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
+ yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
+ // compute a texcoord array with the specified x and y offset
+ varray_texcoord2f[2][0] = xoffset+0;
+ varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
+ varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
+ varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
+ varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
+ varray_texcoord2f[2][5] = yoffset+0;
+ varray_texcoord2f[2][6] = xoffset+0;
+ varray_texcoord2f[2][7] = yoffset+0;
+ // this r value looks like a 'dot' particle, fading sharply to
+ // black at the edges
+ // (probably not realistic but looks good enough)
+ r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
+ if (r < 0.01f)
+ continue;
+ GL_Color(r, r, r, 1);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+ c_bloomdraws++;
+ c_bloomdrawpixels += bloomwidth * bloomheight;
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ }
+ // copy the vertically blurred bloom view to a texture
+ GL_ActiveTexture(0);
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+ c_bloomcopies++;
+ c_bloomcopypixels += bloomwidth * bloomheight;
+ // blend the vertically blurred image at multiple offsets horizontally
+ // to finish the blur effect
+ // TODO: do offset blends using GLSL
+ range = r_bloom_blur.integer * bloomwidth / 320;
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ for (x = -range;x <= range;x++)
+ {
+ xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
+ yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
+ // compute a texcoord array with the specified x and y offset
+ varray_texcoord2f[2][0] = xoffset+0;
+ varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
+ varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
+ varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
+ varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
+ varray_texcoord2f[2][5] = yoffset+0;
+ varray_texcoord2f[2][6] = xoffset+0;
+ varray_texcoord2f[2][7] = yoffset+0;
+ // this r value looks like a 'dot' particle, fading sharply to
+ // black at the edges
+ // (probably not realistic but looks good enough)
+ r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
+ if (r < 0.01f)
+ continue;
+ GL_Color(r, r, r, 1);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+ c_bloomdraws++;
+ c_bloomdrawpixels += bloomwidth * bloomheight;
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ }
+ // copy the blurred bloom view to a texture
+ GL_ActiveTexture(0);
+ qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+ c_bloomcopies++;
+ c_bloomcopypixels += bloomwidth * bloomheight;
+ // go back to full view area
+ qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
+ // put the original screen image back in place and blend the bloom
+ // texture on it
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = varray_vertex3f;
+ m.tex[0] = R_GetTexture(r_bloom_texture_screen);
+ m.pointer_texcoord[0] = varray_texcoord2f[0];
+#if 0
+ dobloomblend = false;
+#else
+ // do both in one pass if possible
+ if (r_textureunits.integer >= 2 && gl_combine.integer)
+ {
+ dobloomblend = false;
+ m.texcombinergb[1] = GL_ADD;
+ m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
+ m.pointer_texcoord[1] = varray_texcoord2f[1];
+ }
+ else
+ dobloomblend = true;
+#endif
+ R_Mesh_State(&m);
+ GL_BlendFunc(GL_ONE, GL_ZERO);
+ GL_Color(1,1,1,1);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+ c_bloomdraws++;
+ c_bloomdrawpixels += r_view_width * r_view_height;
+ // now blend on the bloom texture if multipass
+ if (dobloomblend)
+ {
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = varray_vertex3f;
+ m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
+ m.pointer_texcoord[0] = varray_texcoord2f[1];
+ R_Mesh_State(&m);
+ GL_BlendFunc(GL_ONE, GL_ONE);
+ GL_Color(1,1,1,1);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
+ c_bloomdraws++;
+ c_bloomdrawpixels += r_view_width * r_view_height;
+ }
}
-
- // don't allow cheats in multiplayer
- if (!cl.islocalgame)
+ if (r_refdef.viewblend[3] >= 0.01f)
{
- if (r_fullbright.integer != 0)
- Cvar_Set ("r_fullbright", "0");
- if (r_ambient.value != 0)
- Cvar_Set ("r_ambient", "0");
+ // apply a color tint to the whole view
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = varray_vertex3f;
+ R_Mesh_State(&m);
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
}
-
- R_Textures_Frame();
- R_UpdateFog();
- R_UpdateLights();
}
void R_RenderScene(void);
*/
void R_RenderView(void)
{
- if (!r_refdef.entities/* || !cl.worldmodel*/)
+ if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
return; //Host_Error ("R_RenderView: NULL worldmodel");
-
+
r_view_width = bound(0, r_refdef.width, vid.realwidth);
r_view_height = bound(0, r_refdef.height, vid.realheight);
+ r_view_depth = 1;
r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
+ r_view_z = 0;
r_view_fov_x = bound(1, r_refdef.fov_x, 170);
r_view_fov_y = bound(1, r_refdef.fov_y, 170);
r_view_matrix = r_refdef.viewentitymatrix;
+ GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
+ r_rtworld = r_shadow_realtime_world.integer;
+ r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
+ r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
+ r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
+ r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
// GL is weird because it's bottom to top, r_view_y is top to bottom
qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
GL_ScissorTest(true);
+ GL_DepthMask(true);
R_ClearScreen();
+ R_Textures_Frame();
+ R_UpdateFog();
+ R_UpdateLights();
R_TimeReport("setup");
qglDepthFunc(GL_LEQUAL);
R_BlendView();
R_TimeReport("blendview");
-
+
GL_Scissor(0, 0, vid.realwidth, vid.realheight);
GL_ScissorTest(false);
}
extern void R_DrawLightningBeams (void);
void R_RenderScene(void)
{
- entity_render_t *world;
-
// don't let sound skip if going slow
- if (!intimerefresh && !r_speeds.integer)
+ if (r_refdef.extraupdate)
S_ExtraUpdate ();
r_framecount++;
+ R_MeshQueue_BeginScene();
+
GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
R_SetFrustum();
r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
- if (gl_stencil && ((r_shadow_realtime_world.integer && r_shadow_worldshadows.integer) || ((r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && r_shadow_dlightshadows.integer)))
+ if (r_rtworldshadows || r_rtdlightshadows)
GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
else
GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
R_SkyStartFrame();
- if (cl.worldmodel && cl.worldmodel->brush.FatPVS)
- cl.worldmodel->brush.FatPVS(cl.worldmodel, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
- world = &cl_entities[0].render;
- R_WorldVisibility(world);
+ R_WorldVisibility();
R_TimeReport("worldvis");
R_MarkEntities();
R_TimeReport("markentity");
- R_MeshQueue_BeginScene();
-
R_Shadow_UpdateWorldLightSelection();
// don't let sound skip if going slow
- if (!intimerefresh && !r_speeds.integer)
+ if (r_refdef.extraupdate)
S_ExtraUpdate ();
+ GL_ShowTrisColor(0.025, 0.025, 0, 1);
+ if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
+ {
+ r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
+ R_TimeReport("worldsky");
+ }
+
if (R_DrawBrushModelsSky())
R_TimeReport("bmodelsky");
- // must occur early because it can draw sky
- R_DrawWorld(world);
- R_TimeReport("world");
+ GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
+ if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
+ {
+ r_refdef.worldmodel->Draw(r_refdef.worldentity);
+ R_TimeReport("world");
+ }
// don't let sound skip if going slow
- if (!intimerefresh && !r_speeds.integer)
+ if (r_refdef.extraupdate)
S_ExtraUpdate ();
GL_ShowTrisColor(0, 0.015, 0, 1);
R_TimeReport("models");
// don't let sound skip if going slow
- if (!intimerefresh && !r_speeds.integer)
+ if (r_refdef.extraupdate)
S_ExtraUpdate ();
GL_ShowTrisColor(0, 0, 0.033, 1);
R_TimeReport("rtlights");
// don't let sound skip if going slow
- if (!intimerefresh && !r_speeds.integer)
+ if (r_refdef.extraupdate)
S_ExtraUpdate ();
GL_ShowTrisColor(0.1, 0, 0, 1);
GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
// don't let sound skip if going slow
- if (!intimerefresh && !r_speeds.integer)
+ if (r_refdef.extraupdate)
S_ExtraUpdate ();
}
GL_DepthTest(true);
R_Mesh_Matrix(&r_identitymatrix);
- memset(&m, 0, sizeof(m));
- R_Mesh_State_Texture(&m);
-
- R_Mesh_GetSpace(8);
vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
- GL_ColorPointer(color);
R_FillColors(color, 8, cr, cg, cb, ca);
if (fogenabled)
{
c[2] = c[2] * f1 + fogcolor[2] * f2;
}
}
+ memset(&m, 0, sizeof(m));
+ m.pointer_vertex = vertex3f;
+ m.pointer_color = color;
+ R_Mesh_State(&m);
R_Mesh_Draw(8, 12);
}
*/
R_Mesh_Matrix(&ent->matrix);
memset(&m, 0, sizeof(m));
- R_Mesh_State_Texture(&m);
+ m.pointer_vertex = nomodelvertex3f;
if (ent->flags & EF_ADDITIVE)
{
GL_BlendFunc(GL_ONE, GL_ZERO);
GL_DepthMask(true);
}
- GL_DepthTest(true);
- GL_VertexPointer(nomodelvertex3f);
+ GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
if (fogenabled)
{
memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
- GL_ColorPointer(color4f);
+ m.pointer_color = color4f;
VectorSubtract(ent->origin, r_vieworigin, diff);
f2 = exp(fogdensity/DotProduct(diff, diff));
f1 = 1 - f2;
else if (ent->alpha != 1)
{
memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
- GL_ColorPointer(color4f);
+ m.pointer_color = color4f;
for (i = 0, c = color4f;i < 6;i++, c += 4)
c[3] *= ent->alpha;
}
else
- GL_ColorPointer(nomodelcolor4f);
- R_Mesh_Draw(6, 8, nomodelelements);
+ m.pointer_color = nomodelcolor4f;
+ R_Mesh_State(&m);
+ R_Mesh_Draw(0, 6, 8, nomodelelements);
}
void R_DrawNoModel(entity_render_t *ent)
{
//if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
- R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
+ R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
//else
// R_DrawNoModelCallback(ent, 0);
}
vec3_t right1, right2, diff, normal;
VectorSubtract (org2, org1, normal);
- VectorNormalizeFast (normal);
// calculate 'right' vector for start
VectorSubtract (r_vieworigin, org1, diff);
- VectorNormalizeFast (diff);
CrossProduct (normal, diff, right1);
+ VectorNormalize (right1);
// calculate 'right' vector for end
VectorSubtract (r_vieworigin, org2, diff);
- VectorNormalizeFast (diff);
CrossProduct (normal, diff, right2);
+ VectorNormalize (right2);
vert[ 0] = org1[0] + width * right1[0];
vert[ 1] = org1[1] + width * right1[1];
}
R_Mesh_Matrix(&r_identitymatrix);
- GL_Color(cr, cg, cb, ca);
- GL_VertexPointer(varray_vertex3f);
GL_BlendFunc(blendfunc1, blendfunc2);
GL_DepthMask(false);
GL_DepthTest(!depthdisable);
- memset(&m, 0, sizeof(m));
- m.tex[0] = R_GetTexture(texture);
- m.pointer_texcoord[0] = spritetexcoord2f;
- R_Mesh_State_Texture(&m);
-
varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
- R_Mesh_Draw(4, 2, polygonelements);
+
+ memset(&m, 0, sizeof(m));
+ m.tex[0] = R_GetTexture(texture);
+ m.pointer_texcoord[0] = spritetexcoord2f;
+ m.pointer_vertex = varray_vertex3f;
+ R_Mesh_State(&m);
+ GL_Color(cr, cg, cb, ca);
+ R_Mesh_Draw(0, 4, 2, polygonelements);
}