]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rmain.c
added a firstvertex parameter to R_Mesh_DrawMesh
[xonotic/darkplaces.git] / gl_rmain.c
index 4c73adcf48262927dace2309909d5e9863262440..6cac87e5e8dd6cdab416ad746a85ad8cc089e5e1 100644 (file)
@@ -25,9 +25,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // used for dlight push checking and other things
 int r_framecount;
 
-// used for visibility checking
-qbyte r_pvsbits[(MAX_MAP_LEAFS+7)>>3];
-
 mplane_t frustum[4];
 
 matrix4x4_t r_identitymatrix;
@@ -104,11 +101,15 @@ 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", "256"};
+cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320"};
 cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "4"};
 rtexturepool_t *r_main_texturepool;
 rtexture_t *r_bloom_texture_screen;
 rtexture_t *r_bloom_texture_bloom;
+rtexture_t *r_texture_blanknormalmap;
+rtexture_t *r_texture_white;
+rtexture_t *r_texture_black;
+rtexture_t *r_texture_notexture;
 
 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
 {
@@ -210,18 +211,59 @@ void FOG_registercvars(void)
 
 void gl_main_start(void)
 {
+       int x, y;
+       qbyte pix[16][16][4];
+       qbyte data[4];
        r_main_texturepool = R_AllocTexturePool();
        r_bloom_texture_screen = NULL;
        r_bloom_texture_bloom = NULL;
+       data[0] = 128; // normal X
+       data[1] = 128; // normal Y
+       data[2] = 255; // normal Z
+       data[3] = 128; // height
+       r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+       data[0] = 255;
+       data[1] = 255;
+       data[2] = 255;
+       data[3] = 255;
+       r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+       data[0] = 0;
+       data[1] = 0;
+       data[2] = 0;
+       data[3] = 255;
+       r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
+       // this makes a light grey/dark grey checkerboard texture
+       for (y = 0;y < 16;y++)
+       {
+               for (x = 0;x < 16;x++)
+               {
+                       if ((y < 8) ^ (x < 8))
+                       {
+                               pix[y][x][0] = 128;
+                               pix[y][x][1] = 128;
+                               pix[y][x][2] = 128;
+                               pix[y][x][3] = 255;
+                       }
+                       else
+                       {
+                               pix[y][x][0] = 64;
+                               pix[y][x][1] = 64;
+                               pix[y][x][2] = 64;
+                               pix[y][x][3] = 255;
+                       }
+               }
+       }
+       r_texture_notexture = R_LoadTexture2D(mod_shared_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
 }
 
 void gl_main_shutdown(void)
 {
-       // this seems to cause a already freed crash after a couple vid_restarts...
-       //R_FreeTexturePool(&r_main_texturepool);
-       r_main_texturepool = NULL;
+       R_FreeTexturePool(&r_main_texturepool);
        r_bloom_texture_screen = NULL;
        r_bloom_texture_bloom = NULL;
+       r_texture_blanknormalmap = NULL;
+       r_texture_white = NULL;
+       r_texture_black = NULL;
 }
 
 extern void CL_ParseEntityLump(char *entitystring);
@@ -315,7 +357,7 @@ static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
                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;
 }
 
@@ -427,25 +469,48 @@ int R_CullBox(const vec3_t mins, const vec3_t maxs)
 
 static void R_MarkEntities (void)
 {
-       int i;
+       int i, renderimask;
        entity_render_t *ent;
 
        if (!r_drawentities.integer)
                return;
 
-       for (i = 0;i < r_refdef.numentities;i++)
+       renderimask = envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
+       if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
        {
-               ent = r_refdef.entities[i];
-               Mod_CheckLoaded(ent->model);
-               // some of the renderer still relies on origin...
-               Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
-               // some of the renderer still relies on scale...
-               ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
-               R_UpdateEntLights(ent);
-               if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
-                && (!VIS_CullBox(ent->mins, ent->maxs) || (ent->effects & EF_NODEPTHTEST))
-                && (!envmap || !(ent->flags & (RENDER_VIEWMODEL | RENDER_EXTERIORMODEL))))
-                       ent->visframe = r_framecount;
+               // worldmodel can check visibility
+               for (i = 0;i < r_refdef.numentities;i++)
+               {
+                       ent = r_refdef.entities[i];
+                       Mod_CheckLoaded(ent->model);
+                       // some of the renderer still relies on origin...
+                       Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
+                       // some of the renderer still relies on scale...
+                       ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
+                       if (!(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && ((ent->effects & EF_NODEPTHTEST) || r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.worldmodel, r_worldleafvisible, ent->mins, ent->maxs)))
+                       {
+                               R_UpdateEntLights(ent);
+                               ent->visframe = r_framecount;
+                       }
+               }
+       }
+       else
+       {
+               // no worldmodel or it can't check visibility
+               for (i = 0;i < r_refdef.numentities;i++)
+               {
+                       ent = r_refdef.entities[i];
+                       Mod_CheckLoaded(ent->model);
+                       // some of the renderer still relies on origin...
+                       Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
+                       // some of the renderer still relies on scale...
+                       ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
+                       if (!(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && (ent->effects & EF_NODEPTHTEST))
+                       {
+                               R_UpdateEntLights(ent);
+                               ent->visframe = r_framecount;
+                       }
+               }
        }
 }
 
@@ -535,6 +600,7 @@ static void R_BlendView(void)
        GL_DepthMask(true);
        GL_DepthTest(false);
        R_Mesh_Matrix(&r_identitymatrix);
+       // vertex coordinates for a quad that covers the screen exactly
        varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
        varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
        varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
@@ -544,10 +610,22 @@ static void R_BlendView(void)
                int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
                float xoffset, yoffset, r;
                c_bloom++;
+               // set the (poorly named) screenwidth and screenheight variables to
+               // a power of 2 at least as large as the screen, these will define the
+               // size of the texture to allocate
                for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
                for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
+               // allocate textures as needed
+               if (!r_bloom_texture_screen)
+                       r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+               if (!r_bloom_texture_bloom)
+                       r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
+               // set bloomwidth and bloomheight to the bloom resolution that will be
+               // used (often less than the screen resolution for faster rendering)
                bloomwidth = min(r_view_width, r_bloom_resolution.integer);
-               bloomheight = min(r_view_height, r_bloom_resolution.integer);
+               bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
+               // set up a texcoord array for the full resolution screen image
+               // (we have to keep this around to copy back during final render)
                varray_texcoord2f[0][0] = 0;
                varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
                varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
@@ -556,6 +634,8 @@ static void R_BlendView(void)
                varray_texcoord2f[0][5] = 0;
                varray_texcoord2f[0][6] = 0;
                varray_texcoord2f[0][7] = 0;
+               // set up a texcoord array for the reduced resolution bloom image
+               // (which will be additive blended over the screen image)
                varray_texcoord2f[1][0] = 0;
                varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
                varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
@@ -564,36 +644,36 @@ static void R_BlendView(void)
                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
+               // copy view into the full resolution screen image texture
                GL_ActiveTexture(0);
                qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
                c_bloomcopies++;
                c_bloomcopypixels += r_view_width * r_view_height;
                // now scale it down to the bloom size and raise to a power of itself
-               qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
+               // to darken it (this leaves the really bright stuff bright, and
+               // everything else becomes very dark)
                // TODO: optimize with multitexture or GLSL
+               qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
                GL_BlendFunc(GL_ONE, GL_ZERO);
                GL_Color(1, 1, 1, 1);
-               R_Mesh_Draw(4, 2, polygonelements);
+               R_Mesh_Draw(0, 4, 2, polygonelements);
                c_bloomdraws++;
                c_bloomdrawpixels += bloomwidth * bloomheight;
+               // render multiple times with a multiply blendfunc to raise to a power
                GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
                for (x = 1;x < r_bloom_power.integer;x++)
                {
-                       R_Mesh_Draw(4, 2, polygonelements);
+                       R_Mesh_Draw(0, 4, 2, polygonelements);
                        c_bloomdraws++;
                        c_bloomdrawpixels += bloomwidth * bloomheight;
                }
-               // copy the bloom view to a texture
+               // we now have a darkened bloom image in the framebuffer, copy it into
+               // the bloom image texture for more processing
                memset(&m, 0, sizeof(m));
                m.pointer_vertex = varray_vertex3f;
                m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
@@ -603,14 +683,15 @@ static void R_BlendView(void)
                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
+               // blend on at multiple vertical offsets to achieve a vertical blur
                // TODO: do offset blends using GLSL
-               range = r_bloom_blur.integer;//(int)(r_bloom_blur.value * bloomwidth / 320);
+               range = r_bloom_blur.integer * bloomwidth / 320;
                GL_BlendFunc(GL_ONE, GL_ZERO);
                for (x = -range;x <= range;x++)
                {
                        xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
                        yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
+                       // compute a texcoord array with the specified x and y offset
                        varray_texcoord2f[2][0] = xoffset+0;
                        varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
                        varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
@@ -619,28 +700,33 @@ static void R_BlendView(void)
                        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));
+                       // this r value looks like a 'dot' particle, fading sharply to
+                       // black at the edges
+                       // (probably not realistic but looks good enough)
+                       r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
                        if (r < 0.01f)
                                continue;
                        GL_Color(r, r, r, 1);
-                       R_Mesh_Draw(4, 2, polygonelements);
+                       R_Mesh_Draw(0, 4, 2, polygonelements);
                        c_bloomdraws++;
                        c_bloomdrawpixels += bloomwidth * bloomheight;
                        GL_BlendFunc(GL_ONE, GL_ONE);
                }
-               // copy the blurred bloom view to a texture
+               // copy the vertically blurred bloom view to a texture
                GL_ActiveTexture(0);
                qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
                c_bloomcopies++;
                c_bloomcopypixels += bloomwidth * bloomheight;
-               // blend on at multiple offsets horizontally
+               // blend the vertically blurred image at multiple offsets horizontally
+               // to finish the blur effect
                // TODO: do offset blends using GLSL
-               range = r_bloom_blur.integer * bloomheight / r_view_height;//(int)(r_bloom_blur.value * bloomwidth / 320);
+               range = r_bloom_blur.integer * bloomwidth / 320;
                GL_BlendFunc(GL_ONE, GL_ZERO);
                for (x = -range;x <= range;x++)
                {
                        xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
                        yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
+                       // compute a texcoord array with the specified x and y offset
                        varray_texcoord2f[2][0] = xoffset+0;
                        varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
                        varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
@@ -649,11 +735,14 @@ static void R_BlendView(void)
                        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));
+                       // this r value looks like a 'dot' particle, fading sharply to
+                       // black at the edges
+                       // (probably not realistic but looks good enough)
+                       r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
                        if (r < 0.01f)
                                continue;
                        GL_Color(r, r, r, 1);
-                       R_Mesh_Draw(4, 2, polygonelements);
+                       R_Mesh_Draw(0, 4, 2, polygonelements);
                        c_bloomdraws++;
                        c_bloomdrawpixels += bloomwidth * bloomheight;
                        GL_BlendFunc(GL_ONE, GL_ONE);
@@ -665,7 +754,8 @@ static void R_BlendView(void)
                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
+               // put the original screen image back in place and blend the bloom
+               // texture on it
                memset(&m, 0, sizeof(m));
                m.pointer_vertex = varray_vertex3f;
                m.tex[0] = R_GetTexture(r_bloom_texture_screen);
@@ -687,7 +777,7 @@ static void R_BlendView(void)
                R_Mesh_State(&m);
                GL_BlendFunc(GL_ONE, GL_ZERO);
                GL_Color(1,1,1,1);
-               R_Mesh_Draw(4, 2, polygonelements);
+               R_Mesh_Draw(0, 4, 2, polygonelements);
                c_bloomdraws++;
                c_bloomdrawpixels += r_view_width * r_view_height;
                // now blend on the bloom texture if multipass
@@ -700,7 +790,7 @@ static void R_BlendView(void)
                        R_Mesh_State(&m);
                        GL_BlendFunc(GL_ONE, GL_ONE);
                        GL_Color(1,1,1,1);
-                       R_Mesh_Draw(4, 2, polygonelements);
+                       R_Mesh_Draw(0, 4, 2, polygonelements);
                        c_bloomdraws++;
                        c_bloomdrawpixels += r_view_width * r_view_height;
                }
@@ -713,7 +803,7 @@ static void R_BlendView(void)
                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_Mesh_Draw(0, 4, 2, polygonelements);
        }
 }
 
@@ -741,7 +831,7 @@ void R_RenderView(void)
        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;
+       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;
 
@@ -767,7 +857,7 @@ void R_RenderView(void)
 
        R_BlendView();
        R_TimeReport("blendview");
-       
+
        GL_Scissor(0, 0, vid.realwidth, vid.realheight);
        GL_ScissorTest(false);
 }
@@ -797,8 +887,6 @@ void R_RenderScene(void)
 
        R_SkyStartFrame();
 
-       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");
 
@@ -1010,7 +1098,7 @@ void R_DrawNoModelCallback(const void *calldata1, int calldata2)
        else
                m.pointer_color = nomodelcolor4f;
        R_Mesh_State(&m);
-       R_Mesh_Draw(6, 8, nomodelelements);
+       R_Mesh_Draw(0, 6, 8, nomodelelements);
 }
 
 void R_DrawNoModel(entity_render_t *ent)
@@ -1026,17 +1114,16 @@ void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, flo
        vec3_t right1, right2, diff, normal;
 
        VectorSubtract (org2, org1, normal);
-       VectorNormalizeFast (normal);
 
        // calculate 'right' vector for start
        VectorSubtract (r_vieworigin, org1, diff);
-       VectorNormalizeFast (diff);
        CrossProduct (normal, diff, right1);
+       VectorNormalize (right1);
 
        // calculate 'right' vector for end
        VectorSubtract (r_vieworigin, org2, diff);
-       VectorNormalizeFast (diff);
        CrossProduct (normal, diff, right2);
+       VectorNormalize (right2);
 
        vert[ 0] = org1[0] + width * right1[0];
        vert[ 1] = org1[1] + width * right1[1];
@@ -1089,6 +1176,6 @@ void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, int depth
        m.pointer_vertex = varray_vertex3f;
        R_Mesh_State(&m);
        GL_Color(cr, cg, cb, ca);
-       R_Mesh_Draw(4, 2, polygonelements);
+       R_Mesh_Draw(0, 4, 2, polygonelements);
 }