X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=gl_rmain.c;h=1d0bc1d2876cf27d7a75ee572198f40487e4617d;hp=fad13e4ce3bc53f32dfb42e906160cc0f75c3ae2;hb=17dc94051ad4df6553fc5e4694ca9b55d55cb612;hpb=cb312c5dacdb9cb93d05760eb3e58a47a0062e81 diff --git a/gl_rmain.c b/gl_rmain.c index fad13e4c..1d0bc1d2 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -25,19 +25,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // 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; @@ -50,8 +57,10 @@ vec3_t r_viewright; 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; @@ -89,6 +98,18 @@ cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"}; 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) { @@ -117,36 +138,6 @@ void R_FillColors(float *out, int verts, float r, float g, float b, float a) } } -/* -==================== -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; @@ -220,21 +211,71 @@ void FOG_registercvars(void) 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")) { @@ -256,7 +297,6 @@ void GL_Main_Init(void) 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); @@ -271,6 +311,11 @@ void GL_Main_Init(void) 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); @@ -308,11 +353,11 @@ static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip) 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; } @@ -367,6 +412,10 @@ void GL_Init (void) // 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) @@ -420,30 +469,48 @@ 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; + } + } } } @@ -469,30 +536,6 @@ int R_DrawBrushModelsSky (void) 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) { @@ -549,58 +592,219 @@ static void R_SetFrustum(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)); - m.pointer_vertex = vertex3f; - R_Mesh_State(&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_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_Print("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); @@ -612,22 +816,34 @@ R_RenderView */ 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); @@ -641,7 +857,7 @@ void R_RenderView(void) R_BlendView(); R_TimeReport("blendview"); - + GL_Scissor(0, 0, vid.realwidth, vid.realheight); GL_ScissorTest(false); } @@ -649,20 +865,20 @@ void R_RenderView(void) 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); @@ -671,27 +887,22 @@ void R_RenderScene(void) 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 (world->model && world->model->DrawSky) + if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky) { - world->model->DrawSky(world); + r_refdef.worldmodel->DrawSky(r_refdef.worldentity); R_TimeReport("worldsky"); } @@ -699,14 +910,14 @@ void R_RenderScene(void) R_TimeReport("bmodelsky"); GL_ShowTrisColor(0.05, 0.05, 0.05, 1); - if (world->model && world->model->Draw) + if (r_refdef.worldmodel && r_refdef.worldmodel->Draw) { - world->model->Draw(world); + 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); @@ -715,15 +926,15 @@ void R_RenderScene(void) 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_ShadowVolumeLighting(false); + R_ShadowVolumeLighting(false, false); 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); @@ -749,16 +960,16 @@ void R_RenderScene(void) R_MeshQueue_Render(); R_MeshQueue_EndScene(); - if (r_shadow_visiblevolumes.integer && !r_showtrispass) + if ((r_shadow_visiblelighting.integer || r_shadow_visiblevolumes.integer) && !r_showtrispass) { - R_ShadowVolumeLighting(true); + R_ShadowVolumeLighting(r_shadow_visiblelighting.integer, r_shadow_visiblevolumes.integer); R_TimeReport("shadowvolume"); } 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 (); } @@ -861,7 +1072,7 @@ void R_DrawNoModelCallback(const void *calldata1, int calldata2) GL_BlendFunc(GL_ONE, GL_ZERO); GL_DepthMask(true); } - GL_DepthTest(true); + GL_DepthTest(!(ent->effects & EF_NODEPTHTEST)); if (fogenabled) { memcpy(color4f, nomodelcolor4f, sizeof(float[6*4])); @@ -887,13 +1098,13 @@ void R_DrawNoModelCallback(const void *calldata1, int calldata2) else m.pointer_color = nomodelcolor4f; R_Mesh_State(&m); - R_Mesh_Draw(6, 8, nomodelelements); + 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); } @@ -903,17 +1114,16 @@ void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, flo 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]; @@ -966,6 +1176,6 @@ void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, int depth m.pointer_vertex = varray_vertex3f; R_Mesh_State(&m); GL_Color(cr, cg, cb, ca); - R_Mesh_Draw(4, 2, polygonelements); + R_Mesh_Draw(0, 4, 2, polygonelements); }