X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=gl_rmain.c;h=a8a92dd1b6fa63ec91ad7491417689ea105b5df3;hb=HEAD;hp=2e2db42446095a53872568be42ebcd4e106f49d9;hpb=00969f81f23de7332fb49cd42bce9f2b03bff676;p=xonotic%2Fdarkplaces.git diff --git a/gl_rmain.c b/gl_rmain.c index 2e2db424..7113caca 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -82,7 +82,7 @@ cvar_t r_transparent_useplanardistance = {CF_CLIENT, "r_transparent_useplanardis cvar_t r_showoverdraw = {CF_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"}; cvar_t r_showbboxes = {CF_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%, 10 = 100%)"}; cvar_t r_showbboxes_client = {CF_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%, 10 = 100%)"}; -cvar_t r_showsurfaces = {CF_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"}; +cvar_t r_showsurfaces = {CF_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 3 shows an approximation to vertex or object color (for a very approximate view of the game)"}; cvar_t r_showtris = {CF_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"}; cvar_t r_shownormals = {CF_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"}; cvar_t r_showlighting = {CF_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"}; @@ -156,12 +156,8 @@ cvar_t gl_skyclip = {CF_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance cvar_t r_texture_dds_load = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"}; cvar_t r_texture_dds_save = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"}; -cvar_t r_textureunits = {CF_CLIENT, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"}; -static cvar_t gl_combine = {CF_CLIENT | CF_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"}; -static cvar_t r_glsl = {CF_CLIENT | CF_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"}; - cvar_t r_usedepthtextures = {CF_CLIENT | CF_ARCHIVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"}; -cvar_t r_viewfbo = {CF_CLIENT | CF_ARCHIVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"}; +cvar_t r_viewfbo = {CF_CLIENT | CF_ARCHIVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode; the default setting of 0 uses a framebuffer render when required, and renders directly to the screen otherwise"}; cvar_t r_rendertarget_debug = {CF_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"}; cvar_t r_viewscale = {CF_CLIENT | CF_ARCHIVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"}; cvar_t r_viewscale_fpsscaling = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"}; @@ -191,6 +187,7 @@ cvar_t r_glsl_postprocess_uservec2_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_pos cvar_t r_glsl_postprocess_uservec3_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"}; cvar_t r_glsl_postprocess_uservec4_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"}; cvar_t r_colorfringe = {CF_CLIENT | CF_ARCHIVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"}; +cvar_t r_fxaa = {CF_CLIENT | CF_ARCHIVE, "r_fxaa", "0", "fast approximate anti aliasing"}; cvar_t r_water = {CF_CLIENT | CF_ARCHIVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"}; cvar_t r_water_cameraentitiesonly = {CF_CLIENT | CF_ARCHIVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"}; @@ -247,6 +244,7 @@ cvar_t r_glsl_saturation_redcompensate = {CF_CLIENT | CF_ARCHIVE, "r_glsl_satura cvar_t r_glsl_vertextextureblend_usebothalphas = {CF_CLIENT | CF_ARCHIVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."}; +// FIXME: This cvar would grow to a ridiculous size after several launches and clean exits when used during surface sorting. cvar_t r_framedatasize = {CF_CLIENT | CF_ARCHIVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"}; cvar_t r_buffermegs[R_BUFFERDATA_COUNT] = { @@ -256,6 +254,10 @@ cvar_t r_buffermegs[R_BUFFERDATA_COUNT] = {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"}, }; +cvar_t r_q1bsp_lightmap_updates_enabled = {CF_CLIENT, "r_q1bsp_lightmap_updates_enabled", "1", "allow lightmaps to be updated on Q1BSP maps (don't turn this off except for debugging)"}; +cvar_t r_q1bsp_lightmap_updates_combine = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_combine", "2", "combine lightmap texture updates to make fewer glTexSubImage2D calls, modes: 0 = immediately upload lightmaps (may be thousands of small 3x3 updates), 1 = combine to one call, 2 = combine to one full texture update (glTexImage2D) which tells the driver it does not need to lock the resource (faster on most drivers)"}; +cvar_t r_q1bsp_lightmap_updates_hidden_surfaces = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_hidden_surfaces", "0", "update lightmaps on surfaces that are not visible, so that updates only occur on frames where lightstyles changed value (animation or light switches), only makes sense with combine = 2"}; + extern cvar_t v_glslgamma_2d; extern qbool v_flipped_state; @@ -511,8 +513,8 @@ static void R_BuildFogTexture(void) } if (r_texture_fogattenuation) { - R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1); - //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1); + R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0); + //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0); } else { @@ -531,7 +533,7 @@ static void R_BuildFogHeightTexture(void) float c[4]; float f; inpixels = NULL; - strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename)); + dp_strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename)); if (r_refdef.fogheighttexturename[0]) inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL); if (!inpixels) @@ -843,9 +845,10 @@ enum SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math) SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines) - SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing + SHADERSTATICPARM_FXAA = 13, ///< fast approximate anti aliasing + SHADERSTATICPARM_COLORFRINGE = 14 ///< colorfringe (chromatic aberration) }; -#define SHADERSTATICPARMS_COUNT 14 +#define SHADERSTATICPARMS_COUNT 15 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT]; static int shaderstaticparms_count = 0; @@ -894,6 +897,8 @@ qbool R_CompileShader_CheckStaticParms(void) R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING); if (r_celoutlines.integer) R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES); + if (r_colorfringe.value) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_COLORFRINGE); return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0; } @@ -922,6 +927,7 @@ static void R_CompileShader_AddStaticParms(unsigned int mode, uint64_t permutati R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING"); R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES"); R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_COLORFRINGE, "USECOLORFRINGE"); } /// information about each possible shader permutation @@ -1017,7 +1023,7 @@ static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qbool prin static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, uint64_t permutation) { - int i; + unsigned i; int ubibind; int sampler; shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode]; @@ -1038,7 +1044,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode permutationname[0] = 0; sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false); - strlcat(permutationname, modeinfo->filename, sizeof(permutationname)); + dp_strlcat(permutationname, modeinfo->filename, sizeof(permutationname)); // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object) if(vid.support.glshaderversion >= 140) @@ -1092,7 +1098,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode vertstrings_list[vertstrings_count++] = modeinfo->pretext; geomstrings_list[geomstrings_count++] = modeinfo->pretext; fragstrings_list[fragstrings_count++] = modeinfo->pretext; - strlcat(permutationname, modeinfo->name, sizeof(permutationname)); + dp_strlcat(permutationname, modeinfo->name, sizeof(permutationname)); // now add all the permutation pretexts for (i = 0;i < SHADERPERMUTATION_COUNT;i++) @@ -1102,7 +1108,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext; geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext; fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext; - strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname)); + dp_strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname)); } else { @@ -1353,7 +1359,7 @@ static void R_SetupShader_SetPermutationGLSL(unsigned int mode, uint64_t permuta if (!r_glsl_permutation->program) { // remove features until we find a valid permutation - int i; + unsigned i; for (i = 0;i < SHADERPERMUTATION_COUNT;i++) { // reduce i more quickly whenever it would not remove any bits @@ -1412,7 +1418,8 @@ void R_GLSL_Restart_f(cmd_state_t *cmd) static void R_GLSL_DumpShader_f(cmd_state_t *cmd) { - int i, language, mode, dupe; + unsigned i; + int language, mode, dupe; char *text; shadermodeinfo_t *modeinfo; qfile_t *file; @@ -1553,7 +1560,7 @@ static int R_BlendFuncFlags(int src, int dst) return r; } -void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qbool notrippy) +void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qbool notrippy, qbool ui) { // select a permutation of the lighting shader appropriate to this // combination of texture, entity, light source, and fogging, only use the @@ -1820,7 +1827,7 @@ void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdif // lightmapped wall if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer) permutation |= SHADERPERMUTATION_GLOW; - if (r_refdef.fogenabled && !notrippy) + if (r_refdef.fogenabled && !ui) permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE); if (t->colormapping) permutation |= SHADERPERMUTATION_COLORMAPPING; @@ -1892,7 +1899,7 @@ void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdif } if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG)) permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE); - if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA && !notrippy) + if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA && !ui) permutation |= SHADERPERMUTATION_FOGALPHAHACK; switch(vid.renderpath) { @@ -1916,7 +1923,7 @@ void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdif if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]); if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]); if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]); - + // additive passes are only darkened by fog, not tinted if (r_glsl_permutation->loc_FogColor >= 0) qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0); @@ -1954,7 +1961,7 @@ void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdif if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]); } // additive passes are only darkened by fog, not tinted - if (r_glsl_permutation->loc_FogColor >= 0 && !notrippy) + if (r_glsl_permutation->loc_FogColor >= 0 && !ui) { if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0) qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0); @@ -2254,7 +2261,7 @@ skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewid return NULL; item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array); memset(item, 0, sizeof(*item)); - strlcpy(item->basename, basename, sizeof(item->basename)); + dp_strlcpy(item->basename, basename, sizeof(item->basename)); item->textureflags = compareflags; item->comparewidth = comparewidth; item->compareheight = compareheight; @@ -2983,7 +2990,7 @@ rtexture_t *R_GetCubemap(const char *basename) return r_texture_whitecube; r_texture_numcubemaps++; r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t)); - strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename)); + dp_strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename)); r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename); return r_texture_cubemaps[i]->texture; } @@ -3004,8 +3011,6 @@ static void R_Main_FreeViewCache(void) static void R_Main_ResizeViewCache(void) { int numentities = r_refdef.scene.numentities; - int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1; - int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1; int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1; int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1; if (r_refdef.viewcache.maxentities < numentities) @@ -3015,14 +3020,7 @@ static void R_Main_ResizeViewCache(void) Mem_Free(r_refdef.viewcache.entityvisible); r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities); } - if (r_refdef.viewcache.world_numclusters != numclusters) - { - r_refdef.viewcache.world_numclusters = numclusters; - r_refdef.viewcache.world_numclusterbytes = numclusterbytes; - if (r_refdef.viewcache.world_pvsbits) - Mem_Free(r_refdef.viewcache.world_pvsbits); - r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes); - } + // bones_was_here: r_refdef.viewcache.world_pvsbits was (re)allocated here, now done in Mod_BSP_FatPVS() if (r_refdef.viewcache.world_numleafs != numleafs) { r_refdef.viewcache.world_numleafs = numleafs; @@ -3062,9 +3060,6 @@ static void gl_main_start(void) { case RENDERPATH_GL32: case RENDERPATH_GLES2: - Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS); - Cvar_SetValueQuick(&gl_combine, 1); - Cvar_SetValueQuick(&r_glsl, 1); r_loadnormalmap = true; r_loadgloss = true; r_loadfog = false; @@ -3189,7 +3184,7 @@ static void gl_main_shutdown(void) r_texture_numcubemaps = 0; //r_texture_fogintensity = NULL; memset(&r_fb, 0, sizeof(r_fb)); - R_GLSL_Restart_f(&cmd_local); + R_GLSL_Restart_f(cmd_local); r_glsl_permutation = NULL; memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash)); @@ -3326,8 +3321,6 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_transparent_sortarraysize); Cvar_RegisterVariable(&r_texture_dds_load); Cvar_RegisterVariable(&r_texture_dds_save); - Cvar_RegisterVariable(&r_textureunits); - Cvar_RegisterVariable(&gl_combine); Cvar_RegisterVariable(&r_usedepthtextures); Cvar_RegisterVariable(&r_viewfbo); Cvar_RegisterVariable(&r_rendertarget_debug); @@ -3338,7 +3331,6 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize); Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax); Cvar_RegisterVariable(&r_viewscale_fpsscaling_target); - Cvar_RegisterVariable(&r_glsl); Cvar_RegisterVariable(&r_glsl_deluxemapping); Cvar_RegisterVariable(&r_glsl_offsetmapping); Cvar_RegisterVariable(&r_glsl_offsetmapping_steps); @@ -3359,6 +3351,7 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable); Cvar_RegisterVariable(&r_celshading); Cvar_RegisterVariable(&r_celoutlines); + Cvar_RegisterVariable(&r_fxaa); Cvar_RegisterVariable(&r_water); Cvar_RegisterVariable(&r_water_cameraentitiesonly); @@ -3409,6 +3402,9 @@ void GL_Main_Init(void) for (i = 0;i < R_BUFFERDATA_COUNT;i++) Cvar_RegisterVariable(&r_buffermegs[i]); Cvar_RegisterVariable(&r_batch_dynamicbuffer); + Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_enabled); + Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_combine); + Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_hidden_surfaces); if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE) Cvar_SetValue(&cvars_all, "r_fullbrights", 0); #ifdef DP_MOBILETOUCH @@ -3435,107 +3431,48 @@ void Render_Init(void) R_Particles_Init(); R_Explosion_Init(); R_LightningBeams_Init(); + CL_MeshEntities_Init(); Mod_RenderInit(); } -int R_CullBox(const vec3_t mins, const vec3_t maxs) +static void R_GetCornerOfBox(vec3_t out, const vec3_t mins, const vec3_t maxs, int signbits) { - int i; - mplane_t *p; - if (r_trippy.integer) - return false; - for (i = 0;i < r_refdef.view.numfrustumplanes;i++) - { - p = r_refdef.view.frustum + i; - switch(p->signbits) - { - default: - case 0: - if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist) - return true; - break; - case 1: - if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist) - return true; - break; - case 2: - if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist) - return true; - break; - case 3: - if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist) - return true; - break; - case 4: - if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist) - return true; - break; - case 5: - if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist) - return true; - break; - case 6: - if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist) - return true; - break; - case 7: - if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist) - return true; - break; - } - } - return false; + out[0] = ((signbits & 1) ? mins : maxs)[0]; + out[1] = ((signbits & 2) ? mins : maxs)[1]; + out[2] = ((signbits & 4) ? mins : maxs)[2]; } -int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes) +static qbool _R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes, int ignore) { int i; const mplane_t *p; + vec3_t corner; if (r_trippy.integer) return false; for (i = 0;i < numplanes;i++) { + if(i == ignore) + continue; p = planes + i; - switch(p->signbits) - { - default: - case 0: - if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist) - return true; - break; - case 1: - if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist) - return true; - break; - case 2: - if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist) - return true; - break; - case 3: - if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist) - return true; - break; - case 4: - if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist) - return true; - break; - case 5: - if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist) - return true; - break; - case 6: - if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist) - return true; - break; - case 7: - if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist) - return true; - break; - } + R_GetCornerOfBox(corner, mins, maxs, p->signbits); + if (DotProduct(p->normal, corner) < p->dist) + return true; } return false; } +qbool R_CullFrustum(const vec3_t mins, const vec3_t maxs) +{ + // skip nearclip plane, it often culls portals when you are very close, and is almost never useful + return _R_CullBox(mins, maxs, r_refdef.view.numfrustumplanes, r_refdef.view.frustum, 4); +} + +qbool R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes) +{ + // nothing to ignore + return _R_CullBox(mins, maxs, numplanes, planes, -1); +} + //================================================================================== // LadyHavoc: this stores temporary data used within the same frame @@ -3883,7 +3820,7 @@ qbool R_AnimCache_GetEntity(entity_render_t *ent, qbool wantnormals, qbool wantt r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones; r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones); ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones); - Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); + Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); // note: this can fail if the buffer is at the grow limit ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones; ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset); @@ -4007,13 +3944,13 @@ qbool R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t en if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs)) return true; + VectorCopy(eye, start); // try specific positions in the box first - note that these can be cached if (r_cullentities_trace_entityocclusion.integer) { for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++) { trace_t trace; - VectorCopy(eye, start); end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0]; end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1]; end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2]; @@ -4024,8 +3961,13 @@ qbool R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t en return true; } } - else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs)) - return true; + else + { + // try center + VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end); + if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs)) + return true; + } // try various random positions for (j = 0; j < numsamples; j++) @@ -4077,7 +4019,7 @@ static void R_View_UpdateEntityVisible (void) continue; } if (!(ent->flags & renderimask)) - if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE))) + if (!R_CullFrustum(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE))) if ((ent->flags & (RENDER_NODEPTHTEST | RENDER_WORLDOBJECT | RENDER_VIEWMODEL)) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs)) r_refdef.viewcache.entityvisible[i] = true; } @@ -4089,7 +4031,7 @@ static void R_View_UpdateEntityVisible (void) { ent = r_refdef.scene.entities[i]; if (!(ent->flags & renderimask)) - if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE))) + if (!R_CullFrustum(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE))) r_refdef.viewcache.entityvisible[i] = true; } } @@ -4249,7 +4191,7 @@ static void R_View_SetFrustum(const int *scissor) int i; double fpx = +1, fnx = -1, fpy = +1, fny = -1; vec3_t forward, left, up, origin, v; - if(r_lockvisibility.integer || r_lockpvs.integer) + if(r_lockvisibility.integer) return; if(scissor) { @@ -4429,7 +4371,7 @@ static void R_View_SetFrustum(const int *scissor) //PlaneClassify(&frustum[4]); } -static void R_View_UpdateWithScissor(const int *myscissor) +static void R_View_Update(const int *myscissor) { R_Main_ResizeViewCache(); R_View_SetFrustum(myscissor); @@ -4437,21 +4379,13 @@ static void R_View_UpdateWithScissor(const int *myscissor) R_View_UpdateEntityVisible(); } -static void R_View_Update(void) -{ - R_Main_ResizeViewCache(); - R_View_SetFrustum(NULL); - R_View_WorldVisibility(!r_refdef.view.usevieworiginculling); - R_View_UpdateEntityVisible(); -} - float viewscalefpsadjusted = 1.0f; void R_SetupView(qbool allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight) { const float *customclipplane = NULL; float plane[4]; - int /*rtwidth,*/ rtheight; + int viewy_adjusted; if (r_refdef.view.useclipplane && allowwaterclippingplane) { // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST @@ -4466,15 +4400,16 @@ void R_SetupView(qbool allowwaterclippingplane, int viewfbo, rtexture_t *viewdep customclipplane = plane; } - //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width; - rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height; + // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom. + // Unless the render target is a FBO... + viewy_adjusted = viewfbo ? viewy : vid.mode.height - viewheight - viewy; if (!r_refdef.view.useperspective) - R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane); + R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane); else if (vid.stencil && r_useinfinitefarclip.integer) - R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane); + R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane); else - R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane); + R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane); R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL); R_SetViewport(&r_refdef.view.viewport); } @@ -4504,11 +4439,15 @@ void R_EntityMatrix(const matrix4x4_t *matrix) void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2) { r_viewport_t viewport; + int viewy_adjusted; CHECKGLERROR - // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom - R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL); + // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom. + // Unless the render target is a FBO... + viewy_adjusted = viewfbo ? viewy : vid.mode.height - viewheight - viewy; + + R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, viewy_adjusted, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL); R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL); R_SetViewport(&viewport); GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height); @@ -4806,7 +4745,7 @@ void R_Water_AddWaterPlane(msurface_t *surface, int entno) if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0) { - r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid); + r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, &p->pvsbits, r_main_mempool, p->pvsvalid); p->pvsvalid = true; } } @@ -4912,10 +4851,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t GL_ScissorTest(false); R_ClearScreen(r_refdef.fogenabled); GL_ScissorTest(true); - if(r_water_scissormode.integer & 2) - R_View_UpdateWithScissor(myscissor); - else - R_View_Update(); + R_View_Update(r_water_scissormode.integer & 2 ? myscissor : NULL); R_AnimCache_CacheVisibleEntities(); if(r_water_scissormode.integer & 1) GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]); @@ -4970,7 +4906,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS) { r_refdef.view.usecustompvs = true; - r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false); + r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, &r_refdef.viewcache.world_pvsbits, r_main_mempool, false); } } @@ -4980,10 +4916,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t GL_ScissorTest(false); R_ClearScreen(r_refdef.fogenabled); GL_ScissorTest(true); - if(r_water_scissormode.integer & 2) - R_View_UpdateWithScissor(myscissor); - else - R_View_Update(); + R_View_Update(r_water_scissormode.integer & 2 ? myscissor : NULL); R_AnimCache_CacheVisibleEntities(); if(r_water_scissormode.integer & 1) GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]); @@ -5028,9 +4961,9 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS) { r_refdef.view.usecustompvs = true; - r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false); + r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, &r_refdef.viewcache.world_pvsbits, r_main_mempool, false); } - + // camera needs no clipplane r_refdef.view.useclipplane = false; // TODO: is the camera origin always valid? if so we don't need to clear this @@ -5044,7 +4977,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t GL_ScissorTest(false); R_ClearScreen(r_refdef.fogenabled); GL_ScissorTest(true); - R_View_Update(); + R_View_Update(NULL); R_AnimCache_CacheVisibleEntities(); R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight); @@ -5056,7 +4989,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t r_fb.water.renderingscene = false; r_refdef.view = originalview; R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight); - R_View_Update(); + R_View_Update(NULL); R_AnimCache_CacheVisibleEntities(); goto finish; error: @@ -5128,8 +5061,8 @@ static void R_Bloom_StartFrame(void) viewscalefpsadjusted = 1.0f; scale = r_viewscale.value * sqrt(viewscalefpsadjusted); - if (vid.samples) - scale *= sqrt(vid.samples); // supersampling + if (vid.mode.samples) + scale *= sqrt(vid.mode.samples); // supersampling scale = bound(0.03125f, scale, 4.0f); screentexturewidth = (int)ceil(r_refdef.view.width * scale); screentextureheight = (int)ceil(r_refdef.view.height * scale); @@ -5288,35 +5221,57 @@ static void R_Bloom_MakeTexture(void) r_fb.rt_bloom = cur; } -static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight) +static qbool R_BlendView_IsTrivial(int viewwidth, int viewheight, int width, int height) { - uint64_t permutation; - float uservecs[4][4]; - rtexture_t *viewtexture; - rtexture_t *bloomtexture; + // Scaling requested? + if (viewwidth != width || viewheight != height) + return false; + // Higher bit depth or explicit FBO requested? + if (r_viewfbo.integer) + return false; + // Non-trivial postprocessing shader permutation? + if (r_fb.bloomwidth + || r_refdef.viewblend[3] > 0 + || !vid_gammatables_trivial + || r_glsl_postprocess.integer + || ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1))) + return false; + // Other reasons for a non-trivial default postprocessing shader? + // (See R_CompileShader_CheckStaticParms but only those relevant for MODE_POSTPROCESS in shader_glsl.h) + // Skip: if (r_glsl_saturation_redcompensate.integer) (already covered by saturation above). + // Skip: if (r_glsl_postprocess.integer) (already covered by r_glsl_postprocess above). + // Skip: if (r_glsl_postprocess_uservec1_enable.integer) (already covered by r_glsl_postprocessing above). + if (r_fxaa.integer) + return false; + if (r_colorfringe.value) + return false; + return true; +} +static void R_MotionBlurView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight) +{ R_EntityMatrix(&identitymatrix); - if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture) + if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || (r_damageblur.value > 0 && cl.cshifts[CSHIFT_DAMAGE].percent != 0)) && r_fb.ghosttexture) { // declare variables float blur_factor, blur_mouseaccel, blur_velocity; - static float blur_average; + static float blur_average; static vec3_t blur_oldangles; // used to see how quickly the mouse is moving // set a goal for the factoring - blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) + blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1); - blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) + blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1); - blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) + blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) + (blur_mouseaccel * r_motionblur_mousefactor.value)); // from the goal, pick an averaged value between goal and last value cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1); blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha; - // enforce minimum amount of blur + // enforce minimum amount of blur blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value; //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel); @@ -5336,7 +5291,7 @@ static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *v cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value); cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value); - // apply the blur + // apply the blur on top of the current view R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight); if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid) { @@ -5357,6 +5312,16 @@ static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *v r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight; r_fb.ghosttexture_valid = true; } +} + +static void R_BlendView(rtexture_t *viewcolortexture, int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height) +{ + uint64_t permutation; + float uservecs[4][4]; + rtexture_t *viewtexture; + rtexture_t *bloomtexture; + + R_EntityMatrix(&identitymatrix); if (r_fb.bloomwidth) { @@ -5378,11 +5343,11 @@ static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *v sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]); // render to the screen fbo - R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight); + R_ResetViewRendering2D(fbo, depthtexture, colortexture, x, y, width, height); GL_Color(1, 1, 1, 1); GL_BlendFunc(GL_ONE, GL_ZERO); - viewtexture = r_fb.rt_screen->colortexture[0]; + viewtexture = viewcolortexture; bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL; if (r_rendertarget_debug.integer >= 0) @@ -5539,6 +5504,11 @@ void R_UpdateVariables(void) if (r_refdef.scene.worldmodel) { r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale; + + // Apply the default lightstyle to the lightmap even on q3bsp + if (cl.worldmodel && cl.worldmodel->type == mod_brushq3) { + r_refdef.scene.lightmapintensity *= r_refdef.scene.rtlightstylevalue[0]; + } } if (r_showsurfaces.integer) { @@ -5577,7 +5547,7 @@ void R_UpdateVariables(void) } if (r_texture_gammaramps) { - R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1); + R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1, 0); } else { @@ -5671,6 +5641,7 @@ void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, i rtexture_t *viewdepthtexture = NULL; rtexture_t *viewcolortexture = NULL; int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height; + qbool skipblend; // finish any 2D rendering that was queued DrawQ_Finish(); @@ -5681,7 +5652,7 @@ void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, i rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity if(R_CompileShader_CheckStaticParms()) - R_GLSL_Restart_f(&cmd_local); + R_GLSL_Restart_f(cmd_local); if (!r_drawentities.integer) r_refdef.scene.numentities = 0; @@ -5745,9 +5716,21 @@ void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, i if(r_fb.rt_bloom) r_refdef.view.colorscale *= r_bloom_scenebrightness.value; - // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView - if (r_fb.rt_screen) + skipblend = R_BlendView_IsTrivial(r_fb.rt_screen->texturewidth, r_fb.rt_screen->textureheight, width, height); + if (skipblend) { + // Render to the screen right away. + viewfbo = fbo; + viewdepthtexture = depthtexture; + viewcolortexture = colortexture; + viewx = x; + viewy = y; + viewwidth = width; + viewheight = height; + } + else if (r_fb.rt_screen) + { + // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView viewfbo = r_fb.rt_screen->fbo; viewdepthtexture = r_fb.rt_screen->depthtexture; viewcolortexture = r_fb.rt_screen->colortexture[0]; @@ -5777,7 +5760,7 @@ void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, i r_refdef.view.showdebug = true; - R_View_Update(); + R_View_Update(NULL); if (r_timereport_active) R_TimeReport("visibility"); @@ -5796,14 +5779,16 @@ void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, i // test needs to be on if (r_fb.rt_screen) GL_ScissorTest(true); - GL_Scissor(viewx, viewy, viewwidth, viewheight); + GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight); r_fb.water.numwaterplanes = 0; // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring GL_ScissorTest(false); - R_BlendView(fbo, depthtexture, colortexture, x, y, width, height); + R_MotionBlurView(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight); + if (!skipblend) + R_BlendView(viewcolortexture, fbo, depthtexture, colortexture, x, y, width, height); if (r_timereport_active) R_TimeReport("blendview"); @@ -6053,7 +6038,7 @@ static const unsigned short bboxelements[36] = }; #define BBOXEDGES 13 -static const float bboxedges[BBOXEDGES][6] = +static const float bboxedges[BBOXEDGES][6] = { // whole box { 0, 0, 0, 1, 1, 1 }, @@ -6172,7 +6157,7 @@ static void R_DrawEntityBBoxes(prvm_prog_t *prog) for (i = 0; i < prog->num_edicts; i++) { edict = PRVM_EDICT_NUM(i); - if (edict->priv.server->free) + if (edict->free) continue; // exclude the following for now, as they don't live in world coordinate space and can't be solid: if (PRVM_gameedictedict(edict, tag_entity) != 0) @@ -6568,7 +6553,7 @@ static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname) char name[MAX_QPATH]; skinframe_t *skinframe; unsigned char pixels[296*194]; - strlcpy(cache->name, skinname, sizeof(cache->name)); + dp_strlcpy(cache->name, skinname, sizeof(cache->name)); dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name); if (developer_loading.integer) Con_Printf("loading %s\n", name); @@ -8616,14 +8601,14 @@ static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface) // render multiple smaller batches } -void RSurf_SetupDepthAndCulling(void) +void RSurf_SetupDepthAndCulling(bool ui) { // submodels are biased to avoid z-fighting with world surfaces that they // may be exactly overlapping (avoids z-fighting artifacts on certain // doors and things in Quake maps) GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1); GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset); - GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); + GL_DepthTest(!ui && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back); } @@ -8638,7 +8623,7 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_ return; R_SetupShader_Generic_NoTexture(false, false); skyrenderlater = true; - RSurf_SetupDepthAndCulling(); + RSurf_SetupDepthAndCulling(false); GL_DepthMask(true); // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later @@ -8734,7 +8719,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface { // render screenspace normalmap to texture GL_DepthMask(true); - R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false); + R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false, false); RSurf_DrawBatch(); return; } @@ -8762,18 +8747,18 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface { // render water or distortion background GL_DepthMask(true); - R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false); + R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false); RSurf_DrawBatch(); // blend surface on top GL_DepthMask(false); - R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false); + R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false, false); RSurf_DrawBatch(); } else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)) { // render surface with reflection texture as input GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED)); - R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false); + R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false); RSurf_DrawBatch(); } } @@ -8782,7 +8767,7 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface // render surface batch normally GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED)); - R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui); + R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui, ui); RSurf_DrawBatch(); } @@ -8794,6 +8779,8 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const int k; const msurface_t *surface; float surfacecolor4f[4]; + float c[4]; + texture_t *t = rsurface.texture; // R_Mesh_ResetTextureState(); R_SetupShader_Generic_NoTexture(false, false); @@ -8801,18 +8788,70 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const GL_BlendFunc(GL_ONE, GL_ZERO); GL_DepthMask(writedepth); - RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist); - vi = 0; - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + switch (r_showsurfaces.integer) { - surface = texturesurfacelist[texturesurfaceindex]; - k = (int)(((size_t)surface) / sizeof(msurface_t)); - Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1); - for (j = 0;j < surface->num_vertices;j++) - { - Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi); - vi++; - } + case 1: + default: + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist); + vi = 0; + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + k = (int)(((size_t)surface) / sizeof(msurface_t)); + Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1); + for (j = 0;j < surface->num_vertices;j++) + { + Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi); + vi++; + } + } + break; + case 3: + if(t && t->currentskinframe) + { + Vector4Copy(t->currentskinframe->avgcolor, c); + c[3] *= t->currentalpha; + } + else + { + Vector4Set(c, 1, 0, 1, 1); + } + if (t && (t->pantstexture || t->shirttexture)) + { + VectorMAM(0.7, t->render_colormap_pants, 0.3, t->render_colormap_shirt, c); + } + VectorScale(c, 2 * r_refdef.view.colorscale, c); + if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA) + c[3] *= r_wateralpha.value; + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist); + vi = 0; + if (rsurface.modellightmapcolor4f) + { + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + for (j = 0;j < surface->num_vertices;j++) + { + float *ptr = rsurface.batchlightmapcolor4f + 4 * vi; + Vector4Multiply(ptr, c, ptr); + vi++; + } + } + } + else + { + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + for (j = 0;j < surface->num_vertices;j++) + { + float *ptr = rsurface.batchlightmapcolor4f + 4 * vi; + Vector4Copy(c, ptr); + vi++; + } + } + } + break; } R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f); RSurf_DrawBatch(); @@ -8821,7 +8860,7 @@ static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui) { CHECKGLERROR - RSurf_SetupDepthAndCulling(); + RSurf_SetupDepthAndCulling(ui); if (r_showsurfaces.integer && r_refdef.view.showdebug) { R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth); @@ -8883,7 +8922,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const GL_DepthMask(true); // R_Mesh_ResetTextureState(); } - RSurf_SetupDepthAndCulling(); + RSurf_SetupDepthAndCulling(false); RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4); R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); @@ -8957,7 +8996,7 @@ static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msu return; if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))) return; - RSurf_SetupDepthAndCulling(); + RSurf_SetupDepthAndCulling(false); RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist); R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4); @@ -9308,11 +9347,8 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor model_t *model; const msurface_t *surface; const msurface_t *surfaces; - const int *surfacelist; const texture_t *texture; int numtriangles; - int numsurfacelist; - int surfacelistindex; int surfaceindex; int triangleindex; float localorigin[3]; @@ -9405,8 +9441,6 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor #endif dynamic = model->surfmesh.isanimated; - numsurfacelist = model->nummodelsurfaces; - surfacelist = model->sortedmodelsurfaces; surfaces = model->data_surfaces; bih = NULL; @@ -9442,9 +9476,8 @@ static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldor } else { - for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++) + for (surfaceindex = model->submodelsurfaces_start;surfaceindex < model->submodelsurfaces_end;surfaceindex++) { - surfaceindex = surfacelist[surfacelistindex]; surface = surfaces + surfaceindex; // check cull box first because it rejects more than any other check if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs)) @@ -9770,7 +9803,7 @@ static void R_DrawModelDecals(void) static void R_DrawDebugModel(void) { entity_render_t *ent = rsurface.entity; - int i, j, flagsmask; + int j, flagsmask; const msurface_t *surface; model_t *model = ent->model; @@ -9786,10 +9819,11 @@ static void R_DrawDebugModel(void) GL_DepthMask(false); GL_DepthRange(0, 1); GL_BlendFunc(GL_ONE, GL_ONE); - for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++) + for (j = model->submodelsurfaces_start;j < model->submodelsurfaces_end;j++) { if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j]) continue; + surface = model->data_surfaces + j; rsurface.texture = R_GetCurrentTexture(surface->texture); if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles) { @@ -9829,7 +9863,7 @@ static void R_DrawDebugModel(void) GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value); for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++) { - if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs)) + if (cullbox && R_CullFrustum(bihleaf->mins, bihleaf->maxs)) continue; switch (bihleaf->type) { @@ -9880,10 +9914,11 @@ static void R_DrawDebugModel(void) GL_DepthMask(true); } qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR - for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++) + for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++) { if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j]) continue; + surface = model->data_surfaces + j; rsurface.texture = R_GetCurrentTexture(surface->texture); if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles) { @@ -9918,10 +9953,11 @@ static void R_DrawDebugModel(void) GL_BlendFunc(GL_ONE, GL_ZERO); GL_DepthMask(true); } - for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++) + for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++) { if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j]) continue; + surface = model->data_surfaces + j; rsurface.texture = R_GetCurrentTexture(surface->texture); if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles) { @@ -9989,7 +10025,7 @@ int r_maxsurfacelist = 0; const msurface_t **r_surfacelist = NULL; void R_DrawModelSurfaces(entity_render_t *ent, qbool skysurfaces, qbool writedepth, qbool depthonly, qbool debug, qbool prepass, qbool ui) { - int i, j, endj, flagsmask; + int i, j, flagsmask; model_t *model = ent->model; msurface_t *surfaces; unsigned char *update; @@ -10017,26 +10053,6 @@ void R_DrawModelSurfaces(entity_render_t *ent, qbool skysurfaces, qbool writedep surfaces = model->data_surfaces; update = model->brushq1.lightmapupdateflags; - // update light styles - if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0) - { - model_brush_lightstyleinfo_t *style; - // Iterate over each active style - for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++) - { - if (style->value != r_refdef.scene.lightstylevalue[style->style]) - { - int *list = style->surfacelist; - style->value = r_refdef.scene.lightstylevalue[style->style]; - // Iterate over every surface this style applies to - for (j = 0;j < style->numsurfaces;j++) - // Update brush entities even if not visible otherwise they'll render solid black. - if(r_refdef.viewcache.world_surfacevisible[list[j]] || ent != r_refdef.scene.worldentity) - update[list[j]] = true; - } - } - } - flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL; if (debug) @@ -10046,48 +10062,88 @@ void R_DrawModelSurfaces(entity_render_t *ent, qbool skysurfaces, qbool writedep return; } + // check if this is an empty model + if (model->submodelsurfaces_start >= model->submodelsurfaces_end) + return; + rsurface.lightmaptexture = NULL; rsurface.deluxemaptexture = NULL; rsurface.uselightmaptexture = false; rsurface.texture = NULL; rsurface.rtlight = NULL; numsurfacelist = 0; + // add visible surfaces to draw list if (ent == r_refdef.scene.worldentity) { // for the world entity, check surfacevisible - for (i = 0;i < model->nummodelsurfaces;i++) + for (i = model->submodelsurfaces_start;i < model->submodelsurfaces_end;i++) { - j = model->sortedmodelsurfaces[i]; + j = model->modelsurfaces_sorted[i]; if (r_refdef.viewcache.world_surfacevisible[j]) r_surfacelist[numsurfacelist++] = surfaces + j; } + + // don't do anything if there were no surfaces added (none of the world entity is visible) + if (!numsurfacelist) + { + rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity + return; + } } else if (ui) { - // for ui we have to preserve the order of surfaces - for (i = 0; i < model->nummodelsurfaces; i++) - r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i; + // for ui we have to preserve the order of surfaces (not using modelsurfaces_sorted) + for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++) + r_surfacelist[numsurfacelist++] = surfaces + i; } else { // add all surfaces - for (i = 0; i < model->nummodelsurfaces; i++) - r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i]; + for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++) + r_surfacelist[numsurfacelist++] = surfaces + model->modelsurfaces_sorted[i]; } - // don't do anything if there were no surfaces - if (!numsurfacelist) - { - rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity - return; - } - // update lightmaps if needed - if (update) + + /* + * Mark lightmaps as dirty if their lightstyle's value changed. We do this by + * using style chains because most styles do not change on most frames, and most + * surfaces do not have styles on them. Mods like Arcane Dimensions (e.g. ad_necrokeep) + * break this rule and animate most surfaces. + */ + if (update && !skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0 && r_q1bsp_lightmap_updates_enabled.integer) { - for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++) + model_brush_lightstyleinfo_t *style; + + // For each lightstyle, check if its value changed and mark the lightmaps as dirty if so + for (i = 0, style = model->brushq1.data_lightstyleinfo; i < model->brushq1.num_lightstyles; i++, style++) + { + if (style->value != r_refdef.scene.lightstylevalue[style->style]) + { + int* list = style->surfacelist; + style->value = r_refdef.scene.lightstylevalue[style->style]; + // Value changed - mark the surfaces belonging to this style chain as dirty + for (j = 0; j < style->numsurfaces; j++) + update[list[j]] = true; + } + } + // Now check if update flags are set on any surfaces that are visible + if (r_q1bsp_lightmap_updates_hidden_surfaces.integer) + { + /* + * We can do less frequent texture uploads (approximately 10hz for animated + * lightstyles) by rebuilding lightmaps on surfaces that are not currently visible. + * For optimal efficiency, this includes the submodels of the worldmodel, so we + * use model->num_surfaces, not nummodelsurfaces. + */ + for (i = 0; i < model->num_surfaces;i++) + if (update[i]) + R_BuildLightMap(ent, surfaces + i, r_q1bsp_lightmap_updates_combine.integer); + } + else { - if (update[j]) - R_BuildLightMap(ent, surfaces + j); + for (i = 0; i < numsurfacelist; i++) + if (update[r_surfacelist[i] - surfaces]) + R_BuildLightMap(ent, (msurface_t *)r_surfacelist[i], r_q1bsp_lightmap_updates_combine.integer); } } @@ -10119,10 +10175,10 @@ void R_DebugLine(vec3_t start, vec3_t end) Vector4Set(w[1], end[0], end[1], end[2], 1); R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]); R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]); - x1 = s[0][0] * vid_conwidth.value / vid.width; - y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height; - x2 = s[1][0] * vid_conwidth.value / vid.width; - y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height; + x1 = s[0][0] * vid_conwidth.value / vid.mode.width; + y1 = (vid.mode.height - s[0][1]) * vid_conheight.value / vid.mode.height; + x2 = s[1][0] * vid_conwidth.value / vid.mode.width; + y2 = (vid.mode.height - s[1][1]) * vid_conheight.value / vid.mode.height; //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2); // add the line to the UI mesh for drawing later @@ -10131,11 +10187,11 @@ void R_DebugLine(vec3_t start, vec3_t end) if (fabs(x2 - x1) > fabs(y2 - y1)) { offsetx = 0; - offsety = 0.5f * width * vid_conheight.value / vid.height; + offsety = 0.5f * width * vid_conheight.value / vid.mode.height; } else { - offsetx = 0.5f * width * vid_conwidth.value / vid.width; + offsetx = 0.5f * width * vid_conwidth.value / vid.mode.width; offsety = 0; } surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW), true);