X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=gl_rmain.c;h=8dc3369796969bf2889407bf3c6a89a0504ad90c;hp=53f424335d6c7db7f30beac5b9747766d80d1c45;hb=76f3774756ad46db130ec7c8d67b3845e984c06d;hpb=e3398d6d0804cacfeca760a45db71ed26c25cbd7 diff --git a/gl_rmain.c b/gl_rmain.c index 53f42433..8dc33697 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; @@ -91,6 +98,25 @@ 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"}; + +cvar_t developer_texturelogging = {0, "developer_texturelogging", "1"}; + +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; +rtexture_t *r_texture_whitecube; +rtexture_t *r_texture_normalizationcube; +rtexture_t *r_texture_detailtextures[NUM_DETAILTEXTURES]; +rtexture_t *r_texture_distorttexture[64]; void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b) { @@ -119,36 +145,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,23 +216,251 @@ void FOG_registercvars(void) } } +static void R_BuildDetailTextures (void) +{ + int i, x, y, light; + float vc[3], vx[3], vy[3], vn[3], lightdir[3]; +#define DETAILRESOLUTION 256 + qbyte data[DETAILRESOLUTION][DETAILRESOLUTION][4], noise[DETAILRESOLUTION][DETAILRESOLUTION]; + lightdir[0] = 0.5; + lightdir[1] = 1; + lightdir[2] = -0.25; + VectorNormalize(lightdir); + for (i = 0;i < NUM_DETAILTEXTURES;i++) + { + fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4); + for (y = 0;y < DETAILRESOLUTION;y++) + { + for (x = 0;x < DETAILRESOLUTION;x++) + { + vc[0] = x; + vc[1] = y; + vc[2] = noise[y][x] * (1.0f / 32.0f); + vx[0] = x + 1; + vx[1] = y; + vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f); + vy[0] = x; + vy[1] = y + 1; + vy[2] = noise[(y + 1) % DETAILRESOLUTION][x] * (1.0f / 32.0f); + VectorSubtract(vx, vc, vx); + VectorSubtract(vy, vc, vy); + CrossProduct(vx, vy, vn); + VectorNormalize(vn); + light = 128 - DotProduct(vn, lightdir) * 128; + light = bound(0, light, 255); + data[y][x][0] = data[y][x][1] = data[y][x][2] = light; + data[y][x][3] = 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); + } +} + +static qbyte R_MorphDistortTexture (double y0, double y1, double y2, double y3, double morph) +{ + int m = (int)(((y1 + y3 - (y0 + y2)) * morph * morph * morph) + + ((2 * (y0 - y1) + y2 - y3) * morph * morph) + + ((y2 - y0) * morph) + + (y1)); + return (qbyte)bound(0, m, 255); +} + +static void R_BuildDistortTexture (void) +{ + int x, y, i, j; +#define DISTORTRESOLUTION 32 + qbyte data[5][DISTORTRESOLUTION][DISTORTRESOLUTION][2]; + + for (i=0; i<4; i++) + { + for (y=0; yname); + strlcpy(entname, cl.worldmodel->name, sizeof(entname)); l = strlen(entname) - 4; if (l >= 0 && !strcmp(entname + l, ".bsp")) { @@ -258,7 +482,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); @@ -273,6 +496,12 @@ 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); + Cvar_RegisterVariable(&developer_texturelogging); 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); @@ -310,11 +539,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; } @@ -369,6 +598,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) @@ -422,30 +655,49 @@ 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++) + r_refdef.worldentity->visframe = r_framecount; + 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; + } + } } } @@ -471,30 +723,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) { @@ -551,58 +779,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 && cl.worldmodel) + 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); @@ -614,9 +1003,9 @@ 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; @@ -626,12 +1015,22 @@ void R_RenderView(void) 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); @@ -645,7 +1044,7 @@ void R_RenderView(void) R_BlendView(); R_TimeReport("blendview"); - + GL_Scissor(0, 0, vid.realwidth, vid.realheight); GL_ScissorTest(false); } @@ -653,20 +1052,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_realtime_dlight.integer && r_shadow_realtime_dlight_shadows.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); @@ -675,27 +1074,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"); } @@ -703,14 +1097,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); @@ -719,7 +1113,7 @@ 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); @@ -727,7 +1121,7 @@ void R_RenderScene(void) 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); @@ -753,16 +1147,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_TimeReport("shadowvolume"); + R_TimeReport("visiblevolume"); } 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 (); } @@ -865,7 +1259,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])); @@ -891,13 +1285,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); } @@ -907,17 +1301,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]; @@ -970,6 +1363,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); }