]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
vid: misc updates to comments, console prints, func naming
[xonotic/darkplaces.git] / gl_rmain.c
index 747c5f0ed0889c3aa286d95f4515f0763e9190b8..a8a92dd1b6fa63ec91ad7491417689ea105b5df3 100644 (file)
@@ -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,7 +254,7 @@ 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 | CF_ARCHIVE, "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_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"};
 
@@ -535,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)
@@ -1025,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];
@@ -1046,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)
@@ -1100,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++)
@@ -1110,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
                {
@@ -1361,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
@@ -1420,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;
@@ -1924,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);
@@ -2262,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;
@@ -2991,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;
 }
@@ -3070,9 +3069,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;
@@ -3197,7 +3193,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_client);
+       R_GLSL_Restart_f(cmd_local);
 
        r_glsl_permutation = NULL;
        memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
@@ -3334,8 +3330,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);
@@ -3346,7 +3340,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);
@@ -3367,6 +3360,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);
@@ -3446,107 +3440,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
@@ -3894,7 +3829,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);
@@ -4018,13 +3953,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];
@@ -4035,8 +3970,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++)
@@ -4088,7 +4028,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;
                }
@@ -4100,7 +4040,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;
                }
        }
@@ -4440,7 +4380,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);
@@ -4448,21 +4388,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
@@ -4477,15 +4409,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.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);
 }
@@ -4515,11 +4448,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.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);
@@ -4923,10 +4860,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]);
@@ -4991,10 +4925,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]);
@@ -5041,7 +4972,7 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t
                                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);
                        }
-                       
+
                        // 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
@@ -5055,7 +4986,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);
 
@@ -5067,7 +4998,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:
@@ -5299,35 +5230,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);
@@ -5347,7 +5300,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)
                {
@@ -5368,6 +5321,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)
        {
@@ -5389,11 +5352,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)
@@ -5550,6 +5513,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)
        {
@@ -5682,6 +5650,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();
@@ -5692,7 +5661,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_client);
+               R_GLSL_Restart_f(cmd_local);
 
        if (!r_drawentities.integer)
                r_refdef.scene.numentities = 0;
@@ -5756,9 +5725,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];
@@ -5788,7 +5769,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");
 
@@ -5807,14 +5788,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");
 
@@ -6064,7 +6047,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 },
@@ -6183,7 +6166,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)
@@ -6579,7 +6562,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);
@@ -8627,14 +8610,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);
 }
 
@@ -8649,7 +8632,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
@@ -8805,6 +8788,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);
@@ -8812,18 +8797,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();
@@ -8832,7 +8869,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);
@@ -8894,7 +8931,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);
@@ -8968,7 +9005,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);
@@ -9835,7 +9872,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)
                        {
@@ -10065,7 +10102,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qbool skysurfaces, qbool writedep
        }
        else if (ui)
        {
-               // for ui we have to preserve the order of surfaces (not using sortedmodelsurfaces)
+               // 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;
        }
@@ -10101,7 +10138,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qbool skysurfaces, qbool writedep
                // 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