]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - gl_rsurf.c
ping command now works from server console
[xonotic/darkplaces.git] / gl_rsurf.c
index c038227c8db6317eb408199856648335cf440006..ffef01c8b69411433e4789a598ea5b17d005e12b 100644 (file)
@@ -27,8 +27,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 cvar_t r_ambient = {0, "r_ambient", "0"};
 cvar_t r_drawportals = {0, "r_drawportals", "0"};
-cvar_t r_testvis = {0, "r_testvis", "0"};
-cvar_t r_surfaceworldnode = {0, "r_surfaceworldnode", "0"};
+cvar_t r_lockpvs = {0, "r_lockpvs", "0"};
+cvar_t r_lockvisibility = {0, "r_lockvisibility", "0"};
+cvar_t r_useportalculling = {0, "r_useportalculling", "0"};
 cvar_t r_drawcollisionbrushes_polygonfactor = {0, "r_drawcollisionbrushes_polygonfactor", "-1"};
 cvar_t r_drawcollisionbrushes_polygonoffset = {0, "r_drawcollisionbrushes_polygonoffset", "0"};
 cvar_t r_q3bsp_renderskydepth = {0, "r_q3bsp_renderskydepth", "0"};
@@ -36,11 +37,11 @@ cvar_t r_q3bsp_renderskydepth = {0, "r_q3bsp_renderskydepth", "0"};
 // flag arrays used for visibility checking on world model
 // (all other entities have no per-surface/per-leaf visibility checks)
 // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_clusters
-qbyte r_pvsbits[(32768+7)>>3];
+unsigned char r_pvsbits[(32768+7)>>3];
 // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_leafs
-qbyte r_worldleafvisible[32768];
+unsigned char r_worldleafvisible[32768];
 // TODO: dynamic resize according to r_refdef.worldmodel->num_surfaces
-qbyte r_worldsurfacevisible[262144];
+unsigned char r_worldsurfacevisible[262144];
 
 /*
 ===============
@@ -53,9 +54,9 @@ void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface)
 {
        int smax, tmax, i, j, size, size3, maps, stride, l;
        unsigned int *bl, scale;
-       qbyte *lightmap, *out, *stain;
+       unsigned char *lightmap, *out, *stain;
        static unsigned int intblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
-       static qbyte templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4];
+       static unsigned char templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4];
 
        // update cached lighting info
        surface->cached_dlight = 0;
@@ -131,7 +132,7 @@ void R_StainNode (mnode_t *node, model_t *model, const vec3_t origin, float radi
        float ndist, a, ratio, maxdist, maxdist2, maxdist3, invradius, sdtable[256], td, dist2;
        msurface_t *surface, *endsurface;
        int i, s, t, smax, tmax, smax3, impacts, impactt, stained;
-       qbyte *bl;
+       unsigned char *bl;
        vec3_t impact;
 
        maxdist = radius * radius;
@@ -209,9 +210,9 @@ loc0:
                                                        {
                                                                if (a > 1)
                                                                        a = 1;
-                                                               bl[0] = (qbyte) ((float) bl[0] + a * ((fcolor[0] + ratio * fcolor[4]) - (float) bl[0]));
-                                                               bl[1] = (qbyte) ((float) bl[1] + a * ((fcolor[1] + ratio * fcolor[5]) - (float) bl[1]));
-                                                               bl[2] = (qbyte) ((float) bl[2] + a * ((fcolor[2] + ratio * fcolor[6]) - (float) bl[2]));
+                                                               bl[0] = (unsigned char) ((float) bl[0] + a * ((fcolor[0] + ratio * fcolor[4]) - (float) bl[0]));
+                                                               bl[1] = (unsigned char) ((float) bl[1] + a * ((fcolor[1] + ratio * fcolor[5]) - (float) bl[1]));
+                                                               bl[2] = (unsigned char) ((float) bl[2] + a * ((fcolor[2] + ratio * fcolor[6]) - (float) bl[2]));
                                                                stained = true;
                                                        }
                                                }
@@ -401,66 +402,94 @@ void R_WorldVisibility(void)
        // if possible find the leaf the view origin is in
        viewleaf = model->brush.PointInLeaf ? model->brush.PointInLeaf(model, r_vieworigin) : NULL;
        // if possible fetch the visible cluster bits
-       if (model->brush.FatPVS)
+       if (!r_lockpvs.integer && model->brush.FatPVS)
                model->brush.FatPVS(model, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
 
-       // clear the visible surface and leaf flags arrays
-       memset(r_worldsurfacevisible, 0, model->num_surfaces);
-       memset(r_worldleafvisible, 0, model->brush.num_leafs);
-
-       // if the user prefers surfaceworldnode (testing?) or the viewleaf could
-       // not be found, or the viewleaf is not part of the visible world
-       // (floating around in the void), use the pvs method
-       if (r_surfaceworldnode.integer || !viewleaf || viewleaf->clusterindex < 0)
+       if (!r_lockvisibility.integer)
        {
-               // pvs method:
-               // similar to quake's RecursiveWorldNode but without cache misses
-               for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++)
+               // clear the visible surface and leaf flags arrays
+               memset(r_worldsurfacevisible, 0, model->num_surfaces);
+               memset(r_worldleafvisible, 0, model->brush.num_leafs);
+
+               // if floating around in the void (no pvs data available, and no
+               // portals available), simply use all on-screen leafs.
+               if (!viewleaf || viewleaf->clusterindex < 0)
                {
-                       // if leaf is in current pvs and on the screen, mark its surfaces
-                       if (CHECKPVSBIT(r_pvsbits, leaf->clusterindex) && !R_CullBox(leaf->mins, leaf->maxs))
+                       // no visibility method: (used when floating around in the void)
+                       // simply cull each leaf to the frustum (view pyramid)
+                       // similar to quake's RecursiveWorldNode but without cache misses
+                       for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++)
                        {
-                               renderstats.world_leafs++;
-                               r_worldleafvisible[j] = true;
-                               if (leaf->numleafsurfaces)
-                                       for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
-                                               r_worldsurfacevisible[*mark] = true;
+                               // if leaf is in current pvs and on the screen, mark its surfaces
+                               if (!R_CullBox(leaf->mins, leaf->maxs))
+                               {
+                                       renderstats.world_leafs++;
+                                       r_worldleafvisible[j] = true;
+                                       if (leaf->numleafsurfaces)
+                                               for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
+                                                       r_worldsurfacevisible[*mark] = true;
+                               }
                        }
                }
-       }
-       else
-       {
-               int leafstackpos;
-               mportal_t *p;
-               mleaf_t *leafstack[8192];
-               // portal method:
-               // follows portals leading outward from viewleaf, does not venture
-               // offscreen or into leafs that are not visible, faster than Quake's
-               // RecursiveWorldNode and vastly better in unvised maps, often culls a
-               // lot of surface that pvs alone would miss
-               leafstack[0] = viewleaf;
-               leafstackpos = 1;
-               while (leafstackpos)
+               // if the user prefers to disable portal culling (testing?), simply
+               // use all on-screen leafs that are in the pvs.
+               else if (!r_useportalculling.integer)
                {
-                       renderstats.world_leafs++;
-                       leaf = leafstack[--leafstackpos];
-                       r_worldleafvisible[leaf - model->brush.data_leafs] = true;
-                       // mark any surfaces bounding this leaf
-                       if (leaf->numleafsurfaces)
-                               for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
-                                       r_worldsurfacevisible[*mark] = true;
-                       // follow portals into other leafs
-                       // the checks are:
-                       // if viewer is behind portal (portal faces outward into the scene)
-                       // and the portal polygon's bounding box is on the screen
-                       // and the leaf has not been visited yet
-                       // and the leaf is visible in the pvs
-                       // (the first two checks won't cause as many cache misses as the leaf checks)
-                       for (p = leaf->portals;p;p = p->next)
+                       // pvs method:
+                       // simply check if each leaf is in the Potentially Visible Set,
+                       // and cull to frustum (view pyramid)
+                       // similar to quake's RecursiveWorldNode but without cache misses
+                       for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++)
                        {
-                               renderstats.world_portals++;
-                               if (DotProduct(r_vieworigin, p->plane.normal) < (p->plane.dist + 1) && !R_CullBox(p->mins, p->maxs) && !r_worldleafvisible[p->past - model->brush.data_leafs] && CHECKPVSBIT(r_pvsbits, p->past->clusterindex))
-                                       leafstack[leafstackpos++] = p->past;
+                               // if leaf is in current pvs and on the screen, mark its surfaces
+                               if (CHECKPVSBIT(r_pvsbits, leaf->clusterindex) && !R_CullBox(leaf->mins, leaf->maxs))
+                               {
+                                       renderstats.world_leafs++;
+                                       r_worldleafvisible[j] = true;
+                                       if (leaf->numleafsurfaces)
+                                               for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
+                                                       r_worldsurfacevisible[*mark] = true;
+                               }
+                       }
+               }
+               // otherwise use a recursive portal flow, culling each portal to
+               // frustum and checking if the leaf the portal leads to is in the pvs
+               else
+               {
+                       int leafstackpos;
+                       mportal_t *p;
+                       mleaf_t *leafstack[8192];
+                       // simple-frustum portal method:
+                       // follows portals leading outward from viewleaf, does not venture
+                       // offscreen or into leafs that are not visible, faster than
+                       // Quake's RecursiveWorldNode and vastly better in unvised maps,
+                       // often culls some surfaces that pvs alone would miss
+                       // (such as a room in pvs that is hidden behind a wall, but the
+                       //  passage leading to the room is off-screen)
+                       leafstack[0] = viewleaf;
+                       leafstackpos = 1;
+                       while (leafstackpos)
+                       {
+                               renderstats.world_leafs++;
+                               leaf = leafstack[--leafstackpos];
+                               r_worldleafvisible[leaf - model->brush.data_leafs] = true;
+                               // mark any surfaces bounding this leaf
+                               if (leaf->numleafsurfaces)
+                                       for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
+                                               r_worldsurfacevisible[*mark] = true;
+                               // follow portals into other leafs
+                               // the checks are:
+                               // if viewer is behind portal (portal faces outward into the scene)
+                               // and the portal polygon's bounding box is on the screen
+                               // and the leaf has not been visited yet
+                               // and the leaf is visible in the pvs
+                               // (the first two checks won't cause as many cache misses as the leaf checks)
+                               for (p = leaf->portals;p;p = p->next)
+                               {
+                                       renderstats.world_portals++;
+                                       if (DotProduct(r_vieworigin, p->plane.normal) < (p->plane.dist + 1) && !R_CullBox(p->mins, p->maxs) && !r_worldleafvisible[p->past - model->brush.data_leafs] && CHECKPVSBIT(r_pvsbits, p->past->clusterindex))
+                                               leafstack[leafstackpos++] = p->past;
+                               }
                        }
                }
        }
@@ -510,16 +539,16 @@ typedef struct r_q1bsp_getlightinfo_s
        vec3_t relativelightorigin;
        float lightradius;
        int *outleaflist;
-       qbyte *outleafpvs;
+       unsigned char *outleafpvs;
        int outnumleafs;
        int *outsurfacelist;
-       qbyte *outsurfacepvs;
+       unsigned char *outsurfacepvs;
        int outnumsurfaces;
        vec3_t outmins;
        vec3_t outmaxs;
        vec3_t lightmins;
        vec3_t lightmaxs;
-       const qbyte *pvs;
+       const unsigned char *pvs;
 }
 r_q1bsp_getlightinfo_t;
 
@@ -529,18 +558,22 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node)
        mleaf_t *leaf;
        for (;;)
        {
-               if (!BoxesOverlap(info->lightmins, info->lightmaxs, node->mins, node->maxs))
-                       return;
-               if (!node->plane)
+               mplane_t *plane = node->plane;
+               //if (!BoxesOverlap(info->lightmins, info->lightmaxs, node->mins, node->maxs))
+               //      return;
+               if (!plane)
                        break;
-               sides = BoxOnPlaneSide(info->lightmins, info->lightmaxs, node->plane) - 1;
-               if (sides == 2)
+               if (plane->type < 3)
+                       sides = ((info->lightmaxs[plane->type] >= plane->dist) | ((info->lightmins[plane->type] < plane->dist) << 1));
+               else
+                       sides = BoxOnPlaneSide(info->lightmins, info->lightmaxs, plane);
+               if (sides == 3)
                {
                        R_Q1BSP_RecursiveGetLightInfo(info, node->children[0]);
                        node = node->children[1];
                }
                else
-                       node = node->children[sides];
+                       node = node->children[sides - 1];
        }
        leaf = (mleaf_t *)node;
        if (info->pvs == NULL || CHECKPVSBIT(info->pvs, leaf->clusterindex))
@@ -594,7 +627,7 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node)
        }
 }
 
-void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, qbyte *outleafpvs, int *outnumleafspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer)
+void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer)
 {
        r_q1bsp_getlightinfo_t info;
        VectorCopy(relativelightorigin, info.relativelightorigin);
@@ -842,8 +875,9 @@ void GL_Surf_Init(void)
 
        Cvar_RegisterVariable(&r_ambient);
        Cvar_RegisterVariable(&r_drawportals);
-       Cvar_RegisterVariable(&r_testvis);
-       Cvar_RegisterVariable(&r_surfaceworldnode);
+       Cvar_RegisterVariable(&r_lockpvs);
+       Cvar_RegisterVariable(&r_lockvisibility);
+       Cvar_RegisterVariable(&r_useportalculling);
        Cvar_RegisterVariable(&r_drawcollisionbrushes_polygonfactor);
        Cvar_RegisterVariable(&r_drawcollisionbrushes_polygonoffset);
        Cvar_RegisterVariable(&r_q3bsp_renderskydepth);