]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
got rid of node->contents, leaf->contents kept (only needed temporarily during loadin...
[xonotic/darkplaces.git] / gl_rmain.c
index 5216f4b2ae0baf60719cd2e89084221d52f07551..b73e5fbc57a96edf73876de051692c1342e230e1 100644 (file)
@@ -28,16 +28,30 @@ int r_framecount;
 // used for visibility checking
 qbyte r_pvsbits[(MAX_MAP_LEAFS+7)>>3];
 
+// TODO: dynamic resize?  65536 seems enough because q1bsp can't have more
+// than 32768, and q3bsp compilers have more like a 4096 limit
+qbyte r_worldsurfacevisible[MAX_MAP_LEAFS];
+
 mplane_t frustum[4];
 
 matrix4x4_t r_identitymatrix;
 
-int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights;
+int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights, c_meshs, c_meshelements, c_rt_lights, c_rt_clears, c_rt_scissored, c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris, c_rtcached_shadowmeshes, c_rtcached_shadowtris, c_bloom, c_bloomcopies, c_bloomcopypixels, c_bloomdraws, c_bloomdrawpixels;
 
 // true during envmap command capture
 qboolean envmap;
 
+// maximum visible distance (recalculated from world box each frame)
 float r_farclip;
+// brightness of world lightmaps and related lighting
+// (often reduced when world rtlights are enabled)
+float r_lightmapintensity;
+// whether to draw world lights realtime, dlights realtime, and their shadows
+qboolean r_rtworld;
+qboolean r_rtworldshadows;
+qboolean r_rtdlight;
+qboolean r_rtdlightshadows;
+
 
 // forces all rendering to draw triangle outlines
 int r_showtrispass;
@@ -50,8 +64,10 @@ vec3_t r_viewright;
 vec3_t r_viewup;
 int r_view_x;
 int r_view_y;
+int r_view_z;
 int r_view_width;
 int r_view_height;
+int r_view_depth;
 float r_view_fov_x;
 float r_view_fov_y;
 matrix4x4_t r_view_matrix;
@@ -89,6 +105,14 @@ cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"};
 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
 cvar_t r_watershader = {CVAR_SAVE, "r_watershader", "1"};
 
+cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0"};
+cvar_t r_bloom_intensity = {CVAR_SAVE, "r_bloom_intensity", "2"};
+cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "8"};
+cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320"};
+cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "4"};
+rtexturepool_t *r_main_texturepool;
+rtexture_t *r_bloom_texture_screen;
+rtexture_t *r_bloom_texture_bloom;
 
 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
 {
@@ -117,36 +141,6 @@ void R_FillColors(float *out, int verts, float r, float g, float b, float a)
        }
 }
 
-/*
-====================
-R_TimeRefresh_f
-
-For program optimization
-====================
-*/
-qboolean intimerefresh = 0;
-static void R_TimeRefresh_f (void)
-{
-       int i;
-       float timestart, timedelta, oldangles[3];
-
-       intimerefresh = 1;
-       VectorCopy(cl.viewangles, oldangles);
-       VectorClear(cl.viewangles);
-
-       timestart = Sys_DoubleTime();
-       for (i = 0;i < 128;i++)
-       {
-               Matrix4x4_CreateFromQuakeEntity(&r_refdef.viewentitymatrix, r_vieworigin[0], r_vieworigin[1], r_vieworigin[2], 0, i / 128.0 * 360.0, 0, 1);
-               CL_UpdateScreen();
-       }
-       timedelta = Sys_DoubleTime() - timestart;
-
-       VectorCopy(oldangles, cl.viewangles);
-       intimerefresh = 0;
-       Con_Printf("%f seconds (%f fps)\n", timedelta, 128/timedelta);
-}
-
 vec3_t fogcolor;
 vec_t fogdensity;
 float fog_density, fog_red, fog_green, fog_blue;
@@ -220,26 +214,33 @@ void FOG_registercvars(void)
 
 void gl_main_start(void)
 {
+       r_main_texturepool = R_AllocTexturePool();
+       r_bloom_texture_screen = NULL;
+       r_bloom_texture_bloom = NULL;
 }
 
 void gl_main_shutdown(void)
 {
+       R_FreeTexturePool(&r_main_texturepool);
+       r_bloom_texture_screen = NULL;
+       r_bloom_texture_bloom = NULL;
 }
 
 extern void CL_ParseEntityLump(char *entitystring);
 void gl_main_newmap(void)
 {
+       // FIXME: move this code to client
        int l;
        char *entities, entname[MAX_QPATH];
        r_framecount = 1;
        if (cl.worldmodel)
        {
-               strcpy(entname, cl.worldmodel->name);
+               strlcpy(entname, cl.worldmodel->name, sizeof(entname));
                l = strlen(entname) - 4;
                if (l >= 0 && !strcmp(entname + l, ".bsp"))
                {
                        strcpy(entname + l, ".ent");
-                       if ((entities = FS_LoadFile(entname, true)))
+                       if ((entities = FS_LoadFile(entname, tempmempool, true)))
                        {
                                CL_ParseEntityLump(entities);
                                Mem_Free(entities);
@@ -256,7 +257,6 @@ void GL_Main_Init(void)
        Matrix4x4_CreateIdentity(&r_identitymatrix);
 // FIXME: move this to client?
        FOG_registercvars();
-       Cmd_AddCommand("timerefresh", R_TimeRefresh_f);
        Cvar_RegisterVariable(&r_showtris);
        Cvar_RegisterVariable(&r_drawentities);
        Cvar_RegisterVariable(&r_drawviewmodel);
@@ -271,6 +271,11 @@ void GL_Main_Init(void)
        Cvar_RegisterVariable(&r_waterscroll);
        Cvar_RegisterVariable(&r_watershader);
        Cvar_RegisterVariable(&r_drawcollisionbrushes);
+       Cvar_RegisterVariable(&r_bloom);
+       Cvar_RegisterVariable(&r_bloom_intensity);
+       Cvar_RegisterVariable(&r_bloom_blur);
+       Cvar_RegisterVariable(&r_bloom_resolution);
+       Cvar_RegisterVariable(&r_bloom_power);
        if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
                Cvar_SetValue("r_fullbrights", 0);
        R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
@@ -308,11 +313,11 @@ static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
        r_farclip_directionbit2 = r_farclip_direction[2] < 0;
        r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
 
-       if (cl.worldmodel)
-               R_FarClip_Box(cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
+       if (r_refdef.worldmodel)
+               R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
        for (i = 0;i < r_refdef.numentities;i++)
                R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
-       
+
        return r_farclip_meshfarclip - r_farclip_directiondist;
 }
 
@@ -367,6 +372,10 @@ void GL_Init (void)
 
        // LordHavoc: report supported extensions
        Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
+
+       // clear to black (loading plaque will be seen over this)
+       qglClearColor(0,0,0,1);
+       qglClear(GL_COLOR_BUFFER_BIT);
 }
 
 int R_CullBox(const vec3_t mins, const vec3_t maxs)
@@ -423,10 +432,6 @@ static void R_MarkEntities (void)
        int i;
        entity_render_t *ent;
 
-       ent = &cl_entities[0].render;
-       Matrix4x4_CreateIdentity(&ent->matrix);
-       Matrix4x4_CreateIdentity(&ent->inversematrix);
-
        if (!r_drawentities.integer)
                return;
 
@@ -438,10 +443,9 @@ static void R_MarkEntities (void)
                Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
                // some of the renderer still relies on scale...
                ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
-               R_LerpAnimation(ent);
                R_UpdateEntLights(ent);
                if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
-                && !VIS_CullBox(ent->mins, ent->maxs)
+                && (!VIS_CullBox(ent->mins, ent->maxs) || (ent->effects & EF_NODEPTHTEST))
                 && (!envmap || !(ent->flags & (RENDER_VIEWMODEL | RENDER_EXTERIORMODEL))))
                        ent->visframe = r_framecount;
        }
@@ -469,30 +473,6 @@ int R_DrawBrushModelsSky (void)
        return sky;
 }
 
-/*
-=============
-R_DrawViewModel
-=============
-*/
-/*
-void R_DrawViewModel (void)
-{
-       entity_render_t *ent;
-
-       // FIXME: move these checks to client
-       if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
-               return;
-
-       ent = &cl.viewent.render;
-       Mod_CheckLoaded(ent->model);
-       R_LerpAnimation(ent);
-       Matrix4x4_CreateFromQuakeEntity(&ent->matrix, ent->origin[0], ent->origin[1], ent->origin[2], -ent->angles[0], ent->angles[1], ent->angles[2], ent->scale);
-       Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix);
-       R_UpdateEntLights(ent);
-       ent->model->Draw(ent);
-}
-*/
-
 void R_DrawNoModel(entity_render_t *ent);
 void R_DrawModels(void)
 {
@@ -549,59 +529,194 @@ static void R_SetFrustum(void)
 static void R_BlendView(void)
 {
        rmeshstate_t m;
-       float r;
-       float vertex3f[3*3];
 
-       if (r_refdef.viewblend[3] < 0.01f)
+       if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
                return;
 
-       R_Mesh_Matrix(&r_identitymatrix);
-
-       memset(&m, 0, sizeof(m));
-       R_Mesh_State_Texture(&m);
-
-       GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+       GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
        GL_DepthMask(true);
-       GL_DepthTest(false); // magic
-       GL_VertexPointer(vertex3f);
-       GL_ColorPointer(NULL);
-       GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
-       r = 64;
-       vertex3f[0] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r - r_viewup[0] * r;
-       vertex3f[1] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r - r_viewup[1] * r;
-       vertex3f[2] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r - r_viewup[2] * r;
-       vertex3f[3] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r + r_viewup[0] * r * 3;
-       vertex3f[4] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r + r_viewup[1] * r * 3;
-       vertex3f[5] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r + r_viewup[2] * r * 3;
-       vertex3f[6] = r_vieworigin[0] + r_viewforward[0] * 1.5 - r_viewleft[0] * r * 3 - r_viewup[0] * r;
-       vertex3f[7] = r_vieworigin[1] + r_viewforward[1] * 1.5 - r_viewleft[1] * r * 3 - r_viewup[1] * r;
-       vertex3f[8] = r_vieworigin[2] + r_viewforward[2] * 1.5 - r_viewleft[2] * r * 3 - r_viewup[2] * r;
-       R_Mesh_Draw(3, 1, polygonelements);
-}
-
-void R_UpdateWorld(void)
-{
-       if (!r_refdef.entities/* || !cl.worldmodel*/)
-               return; //Host_Error ("R_RenderView: NULL worldmodel");
-
-       if (r_shadow_realtime_world.integer && !gl_stencil)
+       GL_DepthTest(false);
+       R_Mesh_Matrix(&r_identitymatrix);
+       varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
+       varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
+       varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
+       varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
+       if (r_bloom.integer && r_bloom_resolution.value >= 32 && r_bloom_power.integer >= 1 && r_bloom_power.integer < 100 && r_bloom_blur.value >= 0 && r_bloom_blur.value < 512)
        {
-               Con_Print("Realtime world lighting requires 32bit color; turning off r_shadow_realtime_world, please type vid_bitsperpixel 32;vid_restart and try again\n");
-               Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
+               int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
+               float xoffset, yoffset, r;
+               c_bloom++;
+               for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
+               for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
+               bloomwidth = min(r_view_width, r_bloom_resolution.integer);
+               bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
+               varray_texcoord2f[0][0] = 0;
+               varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
+               varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
+               varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
+               varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
+               varray_texcoord2f[0][5] = 0;
+               varray_texcoord2f[0][6] = 0;
+               varray_texcoord2f[0][7] = 0;
+               varray_texcoord2f[1][0] = 0;
+               varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
+               varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
+               varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
+               varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
+               varray_texcoord2f[1][5] = 0;
+               varray_texcoord2f[1][6] = 0;
+               varray_texcoord2f[1][7] = 0;
+               if (!r_bloom_texture_screen)
+                       r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+               if (!r_bloom_texture_bloom)
+                       r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = varray_vertex3f;
+               m.pointer_texcoord[0] = varray_texcoord2f[0];
+               m.tex[0] = R_GetTexture(r_bloom_texture_screen);
+               R_Mesh_State(&m);
+               // copy view to a texture
+               GL_ActiveTexture(0);
+               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
+               c_bloomcopies++;
+               c_bloomcopypixels += r_view_width * r_view_height;
+               // now scale it down to the bloom size and raise to a power of itself
+               qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+               // TODO: optimize with multitexture or GLSL
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_Color(1, 1, 1, 1);
+               R_Mesh_Draw(4, 2, polygonelements);
+               c_bloomdraws++;
+               c_bloomdrawpixels += bloomwidth * bloomheight;
+               GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
+               for (x = 1;x < r_bloom_power.integer;x++)
+               {
+                       R_Mesh_Draw(4, 2, polygonelements);
+                       c_bloomdraws++;
+                       c_bloomdrawpixels += bloomwidth * bloomheight;
+               }
+               // copy the bloom view to a texture
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = varray_vertex3f;
+               m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
+               m.pointer_texcoord[0] = varray_texcoord2f[2];
+               R_Mesh_State(&m);
+               GL_ActiveTexture(0);
+               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+               c_bloomcopies++;
+               c_bloomcopypixels += bloomwidth * bloomheight;
+               // blend on at multiple offsets vertically
+               // TODO: do offset blends using GLSL
+               range = r_bloom_blur.integer * bloomwidth / 320;
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               for (x = -range;x <= range;x++)
+               {
+                       xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
+                       yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
+                       varray_texcoord2f[2][0] = xoffset+0;
+                       varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
+                       varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
+                       varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
+                       varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
+                       varray_texcoord2f[2][5] = yoffset+0;
+                       varray_texcoord2f[2][6] = xoffset+0;
+                       varray_texcoord2f[2][7] = yoffset+0;
+                       r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
+                       if (r < 0.01f)
+                               continue;
+                       GL_Color(r, r, r, 1);
+                       R_Mesh_Draw(4, 2, polygonelements);
+                       c_bloomdraws++;
+                       c_bloomdrawpixels += bloomwidth * bloomheight;
+                       GL_BlendFunc(GL_ONE, GL_ONE);
+               }
+               // copy the blurred bloom view to a texture
+               GL_ActiveTexture(0);
+               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+               c_bloomcopies++;
+               c_bloomcopypixels += bloomwidth * bloomheight;
+               // blend on at multiple offsets horizontally
+               // TODO: do offset blends using GLSL
+               range = r_bloom_blur.integer * bloomwidth / 320;
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               for (x = -range;x <= range;x++)
+               {
+                       xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
+                       yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
+                       varray_texcoord2f[2][0] = xoffset+0;
+                       varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
+                       varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
+                       varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
+                       varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
+                       varray_texcoord2f[2][5] = yoffset+0;
+                       varray_texcoord2f[2][6] = xoffset+0;
+                       varray_texcoord2f[2][7] = yoffset+0;
+                       r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
+                       if (r < 0.01f)
+                               continue;
+                       GL_Color(r, r, r, 1);
+                       R_Mesh_Draw(4, 2, polygonelements);
+                       c_bloomdraws++;
+                       c_bloomdrawpixels += bloomwidth * bloomheight;
+                       GL_BlendFunc(GL_ONE, GL_ONE);
+               }
+               // copy the blurred bloom view to a texture
+               GL_ActiveTexture(0);
+               qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+               c_bloomcopies++;
+               c_bloomcopypixels += bloomwidth * bloomheight;
+               // go back to full view area
+               qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
+               // put the original view back in place
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = varray_vertex3f;
+               m.tex[0] = R_GetTexture(r_bloom_texture_screen);
+               m.pointer_texcoord[0] = varray_texcoord2f[0];
+#if 0
+               dobloomblend = false;
+#else
+               // do both in one pass if possible
+               if (r_textureunits.integer >= 2 && gl_combine.integer)
+               {
+                       dobloomblend = false;
+                       m.texcombinergb[1] = GL_ADD;
+                       m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
+                       m.pointer_texcoord[1] = varray_texcoord2f[1];
+               }
+               else
+                       dobloomblend = true;
+#endif
+               R_Mesh_State(&m);
+               GL_BlendFunc(GL_ONE, GL_ZERO);
+               GL_Color(1,1,1,1);
+               R_Mesh_Draw(4, 2, polygonelements);
+               c_bloomdraws++;
+               c_bloomdrawpixels += r_view_width * r_view_height;
+               // now blend on the bloom texture if multipass
+               if (dobloomblend)
+               {
+                       memset(&m, 0, sizeof(m));
+                       m.pointer_vertex = varray_vertex3f;
+                       m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
+                       m.pointer_texcoord[0] = varray_texcoord2f[1];
+                       R_Mesh_State(&m);
+                       GL_BlendFunc(GL_ONE, GL_ONE);
+                       GL_Color(1,1,1,1);
+                       R_Mesh_Draw(4, 2, polygonelements);
+                       c_bloomdraws++;
+                       c_bloomdrawpixels += r_view_width * r_view_height;
+               }
        }
-
-       // don't allow cheats in multiplayer
-       if (!cl.islocalgame)
+       if (r_refdef.viewblend[3] >= 0.01f)
        {
-               if (r_fullbright.integer != 0)
-                       Cvar_Set ("r_fullbright", "0");
-               if (r_ambient.value != 0)
-                       Cvar_Set ("r_ambient", "0");
+               // apply a color tint to the whole view
+               memset(&m, 0, sizeof(m));
+               m.pointer_vertex = varray_vertex3f;
+               R_Mesh_State(&m);
+               GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
+               R_Mesh_Draw(4, 2, polygonelements);
        }
-
-       R_Textures_Frame();
-       R_UpdateFog();
-       R_UpdateLights();
 }
 
 void R_RenderScene(void);
@@ -613,22 +728,34 @@ R_RenderView
 */
 void R_RenderView(void)
 {
-       if (!r_refdef.entities/* || !cl.worldmodel*/)
+       if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
                return; //Host_Error ("R_RenderView: NULL worldmodel");
-       
+
        r_view_width = bound(0, r_refdef.width, vid.realwidth);
        r_view_height = bound(0, r_refdef.height, vid.realheight);
+       r_view_depth = 1;
        r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
        r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
+       r_view_z = 0;
        r_view_fov_x = bound(1, r_refdef.fov_x, 170);
        r_view_fov_y = bound(1, r_refdef.fov_y, 170);
        r_view_matrix = r_refdef.viewentitymatrix;
+       GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
+       r_rtworld = r_shadow_realtime_world.integer;
+       r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
+       r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
+       r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
+       r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
 
        // GL is weird because it's bottom to top, r_view_y is top to bottom
        qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
        GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
        GL_ScissorTest(true);
+       GL_DepthMask(true);
        R_ClearScreen();
+       R_Textures_Frame();
+       R_UpdateFog();
+       R_UpdateLights();
        R_TimeReport("setup");
 
        qglDepthFunc(GL_LEQUAL);
@@ -642,7 +769,7 @@ void R_RenderView(void)
 
        R_BlendView();
        R_TimeReport("blendview");
-       
+
        GL_Scissor(0, 0, vid.realwidth, vid.realheight);
        GL_ScissorTest(false);
 }
@@ -650,20 +777,20 @@ void R_RenderView(void)
 extern void R_DrawLightningBeams (void);
 void R_RenderScene(void)
 {
-       entity_render_t *world;
-       
        // don't let sound skip if going slow
-       if (!intimerefresh && !r_speeds.integer)
+       if (r_refdef.extraupdate)
                S_ExtraUpdate ();
 
        r_framecount++;
 
+       R_MeshQueue_BeginScene();
+
        GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
 
        R_SetFrustum();
 
        r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
-       if (gl_stencil && ((r_shadow_realtime_world.integer && r_shadow_worldshadows.integer) || ((r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && r_shadow_dlightshadows.integer)))
+       if (r_rtworldshadows || r_rtdlightshadows)
                GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
        else
                GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
@@ -672,32 +799,39 @@ void R_RenderScene(void)
 
        R_SkyStartFrame();
 
-       if (cl.worldmodel && cl.worldmodel->brush.FatPVS)
-               cl.worldmodel->brush.FatPVS(cl.worldmodel, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
-       world = &cl_entities[0].render;
-       R_WorldVisibility(world);
+       if (r_refdef.worldmodel && r_refdef.worldmodel->brush.FatPVS)
+               r_refdef.worldmodel->brush.FatPVS(r_refdef.worldmodel, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
+       R_WorldVisibility();
        R_TimeReport("worldvis");
 
        R_MarkEntities();
        R_TimeReport("markentity");
 
-       R_MeshQueue_BeginScene();
-
        R_Shadow_UpdateWorldLightSelection();
 
        // don't let sound skip if going slow
-       if (!intimerefresh && !r_speeds.integer)
+       if (r_refdef.extraupdate)
                S_ExtraUpdate ();
 
+       GL_ShowTrisColor(0.025, 0.025, 0, 1);
+       if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
+       {
+               r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
+               R_TimeReport("worldsky");
+       }
+
        if (R_DrawBrushModelsSky())
                R_TimeReport("bmodelsky");
 
-       // must occur early because it can draw sky
-       R_DrawWorld(world);
-       R_TimeReport("world");
+       GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
+       if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
+       {
+               r_refdef.worldmodel->Draw(r_refdef.worldentity);
+               R_TimeReport("world");
+       }
 
        // don't let sound skip if going slow
-       if (!intimerefresh && !r_speeds.integer)
+       if (r_refdef.extraupdate)
                S_ExtraUpdate ();
 
        GL_ShowTrisColor(0, 0.015, 0, 1);
@@ -706,7 +840,7 @@ void R_RenderScene(void)
        R_TimeReport("models");
 
        // don't let sound skip if going slow
-       if (!intimerefresh && !r_speeds.integer)
+       if (r_refdef.extraupdate)
                S_ExtraUpdate ();
 
        GL_ShowTrisColor(0, 0, 0.033, 1);
@@ -714,7 +848,7 @@ void R_RenderScene(void)
        R_TimeReport("rtlights");
 
        // don't let sound skip if going slow
-       if (!intimerefresh && !r_speeds.integer)
+       if (r_refdef.extraupdate)
                S_ExtraUpdate ();
 
        GL_ShowTrisColor(0.1, 0, 0, 1);
@@ -749,7 +883,7 @@ void R_RenderScene(void)
        GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
 
        // don't let sound skip if going slow
-       if (!intimerefresh && !r_speeds.integer)
+       if (r_refdef.extraupdate)
                S_ExtraUpdate ();
 }
 
@@ -764,10 +898,6 @@ void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, floa
        GL_DepthTest(true);
        R_Mesh_Matrix(&r_identitymatrix);
 
-       memset(&m, 0, sizeof(m));
-       R_Mesh_State_Texture(&m);
-
-       R_Mesh_GetSpace(8);
        vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
        vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
        vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
@@ -776,7 +906,6 @@ void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, floa
        vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
        vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
        vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
-       GL_ColorPointer(color);
        R_FillColors(color, 8, cr, cg, cb, ca);
        if (fogenabled)
        {
@@ -790,6 +919,10 @@ void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, floa
                        c[2] = c[2] * f1 + fogcolor[2] * f2;
                }
        }
+       memset(&m, 0, sizeof(m));
+       m.pointer_vertex = vertex3f;
+       m.pointer_color = color;
+       R_Mesh_State(&m);
        R_Mesh_Draw(8, 12);
 }
 */
@@ -836,7 +969,7 @@ void R_DrawNoModelCallback(const void *calldata1, int calldata2)
        R_Mesh_Matrix(&ent->matrix);
 
        memset(&m, 0, sizeof(m));
-       R_Mesh_State_Texture(&m);
+       m.pointer_vertex = nomodelvertex3f;
 
        if (ent->flags & EF_ADDITIVE)
        {
@@ -853,12 +986,11 @@ void R_DrawNoModelCallback(const void *calldata1, int calldata2)
                GL_BlendFunc(GL_ONE, GL_ZERO);
                GL_DepthMask(true);
        }
-       GL_DepthTest(true);
-       GL_VertexPointer(nomodelvertex3f);
+       GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
        if (fogenabled)
        {
                memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
-               GL_ColorPointer(color4f);
+               m.pointer_color = color4f;
                VectorSubtract(ent->origin, r_vieworigin, diff);
                f2 = exp(fogdensity/DotProduct(diff, diff));
                f1 = 1 - f2;
@@ -873,19 +1005,20 @@ void R_DrawNoModelCallback(const void *calldata1, int calldata2)
        else if (ent->alpha != 1)
        {
                memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
-               GL_ColorPointer(color4f);
+               m.pointer_color = color4f;
                for (i = 0, c = color4f;i < 6;i++, c += 4)
                        c[3] *= ent->alpha;
        }
        else
-               GL_ColorPointer(nomodelcolor4f);
+               m.pointer_color = nomodelcolor4f;
+       R_Mesh_State(&m);
        R_Mesh_Draw(6, 8, nomodelelements);
 }
 
 void R_DrawNoModel(entity_render_t *ent)
 {
        //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
-               R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
+               R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
        //else
        //      R_DrawNoModelCallback(ent, 0);
 }
@@ -895,17 +1028,16 @@ void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, flo
        vec3_t right1, right2, diff, normal;
 
        VectorSubtract (org2, org1, normal);
-       VectorNormalizeFast (normal);
 
        // calculate 'right' vector for start
        VectorSubtract (r_vieworigin, org1, diff);
-       VectorNormalizeFast (diff);
        CrossProduct (normal, diff, right1);
+       VectorNormalize (right1);
 
        // calculate 'right' vector for end
        VectorSubtract (r_vieworigin, org2, diff);
-       VectorNormalizeFast (diff);
        CrossProduct (normal, diff, right2);
+       VectorNormalize (right2);
 
        vert[ 0] = org1[0] + width * right1[0];
        vert[ 1] = org1[1] + width * right1[1];
@@ -935,18 +1067,10 @@ void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, int depth
        }
 
        R_Mesh_Matrix(&r_identitymatrix);
-       GL_ColorPointer(NULL);
-       GL_Color(cr, cg, cb, ca);
-       GL_VertexPointer(varray_vertex3f);
        GL_BlendFunc(blendfunc1, blendfunc2);
        GL_DepthMask(false);
        GL_DepthTest(!depthdisable);
 
-       memset(&m, 0, sizeof(m));
-       m.tex[0] = R_GetTexture(texture);
-       m.pointer_texcoord[0] = spritetexcoord2f;
-       R_Mesh_State_Texture(&m);
-
        varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
        varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
        varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
@@ -959,6 +1083,13 @@ void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, int depth
        varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
        varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
        varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
+
+       memset(&m, 0, sizeof(m));
+       m.tex[0] = R_GetTexture(texture);
+       m.pointer_texcoord[0] = spritetexcoord2f;
+       m.pointer_vertex = varray_vertex3f;
+       R_Mesh_State(&m);
+       GL_Color(cr, cg, cb, ca);
        R_Mesh_Draw(4, 2, polygonelements);
 }