Exemple #1
0
        /*
         * =============================================================================
         *
         * DYNAMIC LIGHTS
         *
         * =============================================================================
         */

        /*
         * =============
         * R_MarkLights
         * =============
         */
        static void R_MarkLights(client.dlight_t light, int bit, model.node_or_leaf_t _node)
        {
            model.mplane_t splitplane;
            double         dist;

            model.msurface_t surf;
            int i;

            if (_node.contents < 0)
            {
                return;
            }

            model.mnode_t node = (model.mnode_t)_node;
            splitplane = node.plane;
            dist       = mathlib.DotProduct(light.origin, splitplane.normal) - splitplane.dist;

            if (dist > light.radius)
            {
                R_MarkLights(light, bit, node.children[0]);
                return;
            }
            if (dist < -light.radius)
            {
                R_MarkLights(light, bit, node.children[1]);
                return;
            }

            // mark the polygons
            for (i = 0; i < node.numsurfaces; i++)
            {
                surf = client.cl.worldmodel.surfaces[node.firstsurface + i];
                if (surf.dlightframe != r_dlightframecount)
                {
                    surf.dlightbits  = 0;
                    surf.dlightframe = r_dlightframecount;
                }
                surf.dlightbits |= bit;
            }

            R_MarkLights(light, bit, node.children[0]);
            R_MarkLights(light, bit, node.children[1]);
        }
Exemple #2
0
        /*
         * ===================
         * R_SplitEntityOnNode2
         * ===================
         */
        static void R_SplitEntityOnNode2(model.node_or_leaf_t node)
        {
            model.mplane_t splitplane;
            int            sides;

            if (node.visframe != r_visframecount)
            {
                return;
            }

            if (node.contents < 0)
            {
                if (node.contents != bspfile.CONTENTS_SOLID)
                {
                    r_pefragtopnode = node; // we've reached a non-solid leaf, so it's
                }
                //  visible and not BSP clipped
                return;
            }

            model.mnode_t _node = (model.mnode_t)node;
            splitplane = _node.plane;
            sides      = mathlib.BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);

            if (sides == 3)
            {
                // remember first splitter
                r_pefragtopnode = node;
                return;
            }

            // not split yet; recurse down the contacted side
            if ((sides & 1) != 0)
            {
                R_SplitEntityOnNode2(_node.children[0]);
            }
            else
            {
                R_SplitEntityOnNode2(_node.children[1]);
            }
        }
Exemple #3
0
        /*
         * =============================================================================
         *
         * LIGHT SAMPLING
         *
         * =============================================================================
         */

        static int RecursiveLightPoint(model.node_or_leaf_t _node, double[] start, double[] end)
        {
            int    r;
            double front, back, frac;
            bool   side;

            model.mplane_t   plane;
            double[]         mid = new double[3];
            model.msurface_t surf;
            int s, t, ds, dt;
            int i;

            model.mtexinfo_t tex;
            int  lightmap;
            uint scale;
            int  maps;

            if (_node.contents < 0)
            {
                return(-1);                     // didn't hit anything
            }
            model.mnode_t node = (model.mnode_t)_node;
            // calculate mid point

            // FIXME: optimize for axial
            plane = node.plane;
            front = mathlib.DotProduct(start, plane.normal) - plane.dist;
            back  = mathlib.DotProduct(end, plane.normal) - plane.dist;
            side  = (front < 0);

            if ((back < 0) == side)
            {
                return(RecursiveLightPoint(node.children[side ? 1 : 0], start, end));
            }

            frac   = front / (front - back);
            mid[0] = start[0] + (end[0] - start[0]) * frac;
            mid[1] = start[1] + (end[1] - start[1]) * frac;
            mid[2] = start[2] + (end[2] - start[2]) * frac;

            // go down front side
            r = RecursiveLightPoint(node.children[side ? 1 : 0], start, mid);
            if (r >= 0)
            {
                return(r);                      // hit something
            }
            if ((back < 0) == side)
            {
                return(-1);                     // didn't hit anuthing
            }
            // check for impact on this node

            for (i = 0; i < node.numsurfaces; i++)
            {
                surf = client.cl.worldmodel.surfaces[node.firstsurface + i];
                if ((surf.flags & model.SURF_DRAWTILED) != 0)
                {
                    continue;                   // no lightmaps
                }
                tex = surf.texinfo;

                s = (int)(mathlib.DotProduct(mid, tex.vecs[0]) + tex.vecs[0][3]);
                t = (int)(mathlib.DotProduct(mid, tex.vecs[1]) + tex.vecs[1][3]);

                if (s < surf.texturemins[0] ||
                    t < surf.texturemins[1])
                {
                    continue;
                }

                ds = s - surf.texturemins[0];
                dt = t - surf.texturemins[1];

                if (ds > surf.extents[0] || dt > surf.extents[1])
                {
                    continue;
                }

                if (surf.samples == null)
                {
                    return(0);
                }

                ds >>= 4;
                dt >>= 4;

                lightmap = surf.samples.ofs;
                r        = 0;
                if (surf.samples != null)
                {
                    lightmap += dt * ((surf.extents[0] >> 4) + 1) + ds;

                    for (maps = 0; maps < bspfile.MAXLIGHTMAPS && surf.styles[maps] != 255;
                         maps++)
                    {
                        scale     = (uint)d_lightstylevalue[surf.styles[maps]];
                        r        += (int)(surf.samples.buffer[lightmap] * scale);
                        lightmap += ((surf.extents[0] >> 4) + 1) *
                                    ((surf.extents[1] >> 4) + 1);
                    }

                    r >>= 8;
                }

                return(r);
            }

            // go down back side
            return(RecursiveLightPoint(node.children[!side ? 1 : 0], mid, end));
        }
Exemple #4
0
        /*
         * ================
         * R_RecursiveWorldNode
         * ================
         */
        static void R_RecursiveWorldNode(model.node_or_leaf_t node, int clipflags)
        {
            int i, c, side, pindex;

            double[]         acceptpt = new double[3], rejectpt = new double[3];
            model.mplane_t   plane;
            model.msurface_t surf, mark;
            model.mleaf_t    pleaf;
            double           d, dot;
            int surfofs;

            if (node.contents == bspfile.CONTENTS_SOLID)
            {
                return;                 // solid
            }
            if (node.visframe != r_visframecount)
            {
                return;
            }

            // cull the clipping planes if not trivial accept
            // FIXME: the compiler is doing a lousy job of optimizing here; it could be
            //  twice as fast in ASM
            if (clipflags != 0)
            {
                for (i = 0; i < 4; i++)
                {
                    if ((clipflags & (1 << i)) == 0)
                    {
                        continue;                       // don't need to clip against it
                    }
                    // generate accept and reject points
                    // FIXME: do with fast look-ups or integer tests based on the sign bit
                    // of the floating point values

                    pindex = pfrustum_indexes[i];

                    rejectpt[0] = (double)node.minmaxs[r_frustum_indexes[pindex + 0]];
                    rejectpt[1] = (double)node.minmaxs[r_frustum_indexes[pindex + 1]];
                    rejectpt[2] = (double)node.minmaxs[r_frustum_indexes[pindex + 2]];

                    d  = mathlib.DotProduct(rejectpt, view_clipplanes[i].normal);
                    d -= view_clipplanes[i].dist;

                    if (d <= 0)
                    {
                        return;
                    }

                    acceptpt[0] = (double)node.minmaxs[r_frustum_indexes[pindex + 3 + 0]];
                    acceptpt[1] = (double)node.minmaxs[r_frustum_indexes[pindex + 3 + 1]];
                    acceptpt[2] = (double)node.minmaxs[r_frustum_indexes[pindex + 3 + 2]];

                    d  = mathlib.DotProduct(acceptpt, view_clipplanes[i].normal);
                    d -= view_clipplanes[i].dist;

                    if (d >= 0)
                    {
                        clipflags &= ~(1 << i);                 // node is entirely on screen
                    }
                }
            }

            // if a leaf node, draw stuff
            if (node.contents < 0)
            {
                pleaf = (model.mleaf_t)node;

                helper.ObjectBuffer _mark = pleaf.firstmarksurface;
                int ofs = _mark.ofs;
                mark = (model.msurface_t)_mark.buffer[ofs];
                c    = pleaf.nummarksurfaces;

                if (c != 0)
                {
                    do
                    {
                        mark.visframe = r_framecount;
                        mark          = (model.msurface_t)_mark.buffer[++ofs];
                    } while (--c != 0);
                }

                // deal with model fragments in this leaf
                if (pleaf.efrags != null)
                {
                    R_StoreEfrags(ref pleaf.efrags);
                }

                pleaf.key = r_currentkey;
                r_currentkey++;                 // all bmodels in a leaf share the same key
            }
            else
            {
                model.mnode_t _node = (model.mnode_t)node;
                // node is just a decision point, so go down the apropriate sides

                // find which side of the node we are on
                plane = _node.plane;

                switch (plane.type)
                {
                case bspfile.PLANE_X:
                    dot = modelorg[0] - plane.dist;
                    break;

                case bspfile.PLANE_Y:
                    dot = modelorg[1] - plane.dist;
                    break;

                case bspfile.PLANE_Z:
                    dot = modelorg[2] - plane.dist;
                    break;

                default:
                    dot = mathlib.DotProduct(modelorg, plane.normal) - plane.dist;
                    break;
                }

                if (dot >= 0)
                {
                    side = 0;
                }
                else
                {
                    side = 1;
                }

                // recurse down the children, front side first
                R_RecursiveWorldNode(_node.children[side], clipflags);

                // draw stuff
                c = _node.numsurfaces;

                if (c != 0)
                {
                    surf    = client.cl.worldmodel.surfaces[_node.firstsurface];
                    surfofs = _node.firstsurface;

                    if (dot < -BACKFACE_EPSILON)
                    {
                        do
                        {
                            if ((surf.flags & model.SURF_PLANEBACK) != 0 &&
                                (surf.visframe == r_framecount))
                            {
                                if (r_drawpolys)
                                {
                                    if (r_worldpolysbacktofront)
                                    {
                                        if (numbtofpolys < MAX_BTOFPOLYS)
                                        {
                                            pbtofpolys[numbtofpolys].clipflags =
                                                clipflags;
                                            pbtofpolys[numbtofpolys].psurf = surf;
                                            numbtofpolys++;
                                        }
                                    }
                                    else
                                    {
                                        R_RenderPoly(surf, clipflags);
                                    }
                                }
                                else
                                {
                                    R_RenderFace(surf, clipflags);
                                }
                            }

                            surf = client.cl.worldmodel.surfaces[++surfofs];
                        } while (--c != 0);
                    }
                    else if (dot > BACKFACE_EPSILON)
                    {
                        do
                        {
                            if ((surf.flags & model.SURF_PLANEBACK) == 0 &&
                                (surf.visframe == r_framecount))
                            {
                                if (r_drawpolys)
                                {
                                    if (r_worldpolysbacktofront)
                                    {
                                        if (numbtofpolys < MAX_BTOFPOLYS)
                                        {
                                            pbtofpolys[numbtofpolys].clipflags =
                                                clipflags;
                                            pbtofpolys[numbtofpolys].psurf = surf;
                                            numbtofpolys++;
                                        }
                                    }
                                    else
                                    {
                                        R_RenderPoly(surf, clipflags);
                                    }
                                }
                                else
                                {
                                    R_RenderFace(surf, clipflags);
                                }
                            }

                            surf = client.cl.worldmodel.surfaces[++surfofs];
                        } while (--c != 0);
                    }

                    // all surfaces on the same node share the same sequence number
                    r_currentkey++;
                }

                // recurse down the back side
                R_RecursiveWorldNode(_node.children[side == 0 ? 1 : 0], clipflags);
            }
        }
Exemple #5
0
        /*
         * ================
         * R_RecursiveClipBPoly
         * ================
         */
        static void R_RecursiveClipBPoly(bedge_t pedges, model.mnode_t pnode, model.msurface_t psurf)
        {
            bedge_t[] psideedges = new bedge_t[2];
            bedge_t   pnextedge, ptedge;
            int       i, side, lastside;
            double    dist, frac, lastdist;

            model.mplane_t       splitplane, tplane = new model.mplane_t();
            model.mvertex_t      pvert, plastvert, ptvert;
            model.node_or_leaf_t pn;

            psideedges[0] = psideedges[1] = null;

            makeclippededge = false;

            // transform the BSP plane into model space
            // FIXME: cache these?
            splitplane  = pnode.plane;
            tplane.dist = splitplane.dist -
                          mathlib.DotProduct(r_entorigin, splitplane.normal);
            tplane.normal[0] = mathlib.DotProduct(entity_rotation[0], splitplane.normal);
            tplane.normal[1] = mathlib.DotProduct(entity_rotation[1], splitplane.normal);
            tplane.normal[2] = mathlib.DotProduct(entity_rotation[2], splitplane.normal);

            // clip edges to BSP plane
            for ( ; pedges != null; pedges = pnextedge)
            {
                pnextedge = pedges.pnext;

                // set the status for the last point as the previous point
                // FIXME: cache this stuff somehow?
                plastvert = pedges.v[0];
                lastdist  = mathlib.DotProduct(plastvert.position, tplane.normal) -
                            tplane.dist;

                if (lastdist > 0)
                {
                    lastside = 0;
                }
                else
                {
                    lastside = 1;
                }

                pvert = pedges.v[1];

                dist = mathlib.DotProduct(pvert.position, tplane.normal) - tplane.dist;

                if (dist > 0)
                {
                    side = 0;
                }
                else
                {
                    side = 1;
                }

                if (side != lastside)
                {
                    // clipped
                    if (numbverts >= MAX_BMODEL_VERTS)
                    {
                        return;
                    }

                    // generate the clipped vertex
                    frac               = lastdist / (lastdist - dist);
                    ptvert             = pbverts[numbverts++];
                    ptvert.position[0] = plastvert.position[0] +
                                         frac * (pvert.position[0] -
                                                 plastvert.position[0]);
                    ptvert.position[1] = plastvert.position[1] +
                                         frac * (pvert.position[1] -
                                                 plastvert.position[1]);
                    ptvert.position[2] = plastvert.position[2] +
                                         frac * (pvert.position[2] -
                                                 plastvert.position[2]);

                    // split into two edges, one on each side, and remember entering
                    // and exiting points
                    // FIXME: share the clip edge by having a winding direction flag?
                    if (numbedges >= (MAX_BMODEL_EDGES - 1))
                    {
                        console.Con_Printf("Out of edges for bmodel\n");
                        return;
                    }

                    ptedge               = pbedges[numbedges];
                    ptedge.pnext         = psideedges[lastside];
                    psideedges[lastside] = ptedge;
                    ptedge.v[0]          = plastvert;
                    ptedge.v[1]          = ptvert;

                    ptedge           = pbedges[numbedges + 1];
                    ptedge.pnext     = psideedges[side];
                    psideedges[side] = ptedge;
                    ptedge.v[0]      = ptvert;
                    ptedge.v[1]      = pvert;

                    numbedges += 2;

                    if (side == 0)
                    {
                        // entering for front, exiting for back
                        pfrontenter     = ptvert;
                        makeclippededge = true;
                    }
                    else
                    {
                        pfrontexit      = ptvert;
                        makeclippededge = true;
                    }
                }
                else
                {
                    // add the edge to the appropriate side
                    pedges.pnext     = psideedges[side];
                    psideedges[side] = pedges;
                }
            }

            // if anything was clipped, reconstitute and add the edges along the clip
            // plane to both sides (but in opposite directions)
            if (makeclippededge)
            {
                if (numbedges >= (MAX_BMODEL_EDGES - 2))
                {
                    console.Con_Printf("Out of edges for bmodel\n");
                    return;
                }

                ptedge        = pbedges[numbedges];
                ptedge.pnext  = psideedges[0];
                psideedges[0] = ptedge;
                ptedge.v[0]   = pfrontexit;
                ptedge.v[1]   = pfrontenter;

                ptedge        = pbedges[numbedges + 1];
                ptedge.pnext  = psideedges[1];
                psideedges[1] = ptedge;
                ptedge.v[0]   = pfrontenter;
                ptedge.v[1]   = pfrontexit;

                numbedges += 2;
            }

            // draw or recurse further
            for (i = 0; i < 2; i++)
            {
                if (psideedges[i] != null)
                {
                    // draw if we've reached a non-solid leaf, done if all that's left is a
                    // solid leaf, and continue down the tree if it's not a leaf
                    pn = pnode.children[i];

                    // we're done with this branch if the node or leaf isn't in the PVS
                    if (pn.visframe == r_visframecount)
                    {
                        if (pn.contents < 0)
                        {
                            if (pn.contents != bspfile.CONTENTS_SOLID)
                            {
                                r_currentbkey = ((model.mleaf_t)pn).key;
                                R_RenderBmodelFace(psideedges[i], psurf);
                            }
                        }
                        else
                        {
                            R_RecursiveClipBPoly(psideedges[i], (model.mnode_t)pnode.children[i],
                                                 psurf);
                        }
                    }
                }
            }
        }
Exemple #6
0
        /*
         * ===================
         * R_SplitEntityOnNode
         * ===================
         */
        static void R_SplitEntityOnNode(model.node_or_leaf_t node)
        {
            efrag_t ef;

            model.mplane_t splitplane;
            model.mleaf_t  leaf;
            int            sides;

            if (node.contents == bspfile.CONTENTS_SOLID)
            {
                return;
            }

            // add an efrag if the node is a leaf

            if (node.contents < 0)
            {
                if (r_pefragtopnode == null)
                {
                    r_pefragtopnode = node;
                }

                leaf = (model.mleaf_t)node;

                // grab an efrag off the free list
                ef = client.cl.free_efrags;
                if (ef == null)
                {
                    console.Con_Printf("Too many efrags!\n");
                    return;             // no free fragments...
                }
                client.cl.free_efrags = client.cl.free_efrags.entnext;

                ef.entity = r_addent;

                // add the entity link
                if (lastlink == null)
                {
                    r_addent.efrag = ef;
                }
                else
                {
                    lastlink.entnext = ef;
                }
                lastlink   = ef;
                ef.entnext = null;

                // set the leaf links
                ef.leaf     = leaf;
                ef.leafnext = leaf.efrags;
                leaf.efrags = ef;

                return;
            }

            // NODE_MIXED
            model.mnode_t _node = (model.mnode_t)node;
            splitplane = _node.plane;
            sides      = mathlib.BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);

            if (sides == 3)
            {
                // split on this plane
                // if this is the first splitter of this bmodel, remember it
                if (r_pefragtopnode == null)
                {
                    r_pefragtopnode = node;
                }
            }

            // recurse down the contacted sides
            if ((sides & 1) != 0)
            {
                R_SplitEntityOnNode(_node.children[0]);
            }

            if ((sides & 2) != 0)
            {
                R_SplitEntityOnNode(_node.children[1]);
            }
        }