示例#1
0
    public static BspNode AddNode(BspNode inParent, BspNode.EBspLocation inLocation, CSGFace inFace, int inFlags)
    {
        BspNode newNode = new BspNode();

        newNode.plane = inFace.GetPlane();
        newNode.face  = inFace;
        newNode.front = newNode.back = newNode.planar = null;
        newNode.flags = inFlags;

        if (inLocation == BspNode.EBspLocation.BspLocation_Front)
        {
            // check that front node is null
            inParent.front = newNode;
        }
        else if (inLocation == BspNode.EBspLocation.BspLocation_Back)
        {
            // TODO: check that back node is null
            inParent.back = newNode;
        }
        else if (inLocation == BspNode.EBspLocation.BspLocation_Planar)
        {
            // go to the last planar node
            BspNode lastPlanar = inParent;

            while (lastPlanar.planar != null)
            {
                lastPlanar = lastPlanar.planar;
            }

            // add planar node
            lastPlanar.planar = newNode;
        }

        return(newNode);
    }
示例#2
0
    /// <summary>
    /// Imports the sub mesh.
    /// </summary>
    /// <param name='inMesh'>
    /// In mesh.
    /// </param>
    /// <param name='inSubMesh'>
    /// In sub mesh.
    /// </param>
    /// <param name='inMaterial'>
    /// In material.
    /// </param>
    private void ImportSubMesh(Mesh inMesh, int inSubMesh, Material inMaterial)
    {
        //
        int[] tris = inMesh.GetTriangles(inSubMesh);


        for (int i = 0; i < tris.Length; i += 3)
        {
            CSGFace newFace = new CSGFace();

            // copy triangle
            newFace.vertices    = new Vector3[3];
            newFace.vertices[0] = inMesh.vertices[tris[i + 0]];
            newFace.vertices[1] = inMesh.vertices[tris[i + 1]];
            newFace.vertices[2] = inMesh.vertices[tris[i + 2]];

            // copy triangle uv
            newFace.uv    = new Vector2[3];
            newFace.uv[0] = inMesh.uv[tris[i + 0]];
            newFace.uv[1] = inMesh.uv[tris[i + 1]];
            newFace.uv[2] = inMesh.uv[tris[i + 2]];

            // set material
            newFace.material = inMaterial;

            // add to face list
            faces.Add(newFace);
        }
    }
示例#3
0
 /// <summary>
 /// Optimize this instance.
 /// </summary>
 public void Optimize()
 {
     //
     CSGFace.MergeCoplanars(faces);
     //
     TransferFacesToMesh();
 }
示例#4
0
    /// <summary>
    /// Single Mesh importing, do not support Sub Meshes.
    /// </summary>
    /// <param name='inMesh'>
    /// In mesh.
    /// </param>
    /// <param name='inMaterial'>
    /// In material.
    /// </param>
    private void ImportMesh(Mesh inMesh, Material inMaterial)
    {
        // ONLY SUPPORTS TRIANGLES AT THE MOMENT
        faces = new List <CSGFace>();

        for (int i = 0; i < inMesh.triangles.Length; i += 3)
        {
            CSGFace newFace = new CSGFace();

            // copy triangle
            newFace.vertices    = new Vector3[3];
            newFace.vertices[0] = inMesh.vertices[inMesh.triangles[i + 0]];
            newFace.vertices[1] = inMesh.vertices[inMesh.triangles[i + 1]];
            newFace.vertices[2] = inMesh.vertices[inMesh.triangles[i + 2]];

            // copy triangle uv
            newFace.uv    = new Vector2[3];
            newFace.uv[0] = inMesh.uv[inMesh.triangles[i + 0]];
            newFace.uv[1] = inMesh.uv[inMesh.triangles[i + 1]];
            newFace.uv[2] = inMesh.uv[inMesh.triangles[i + 2]];

            // set material
            newFace.material = inMaterial;

            // add to face list
            faces.Add(newFace);
        }
    }
示例#5
0
    public void AddDeferredFace(CSGFace inFace)
    {
        // add to deferred faces
        DeferredFace defFace;

        defFace.face = inFace;
        defFace.node = currentNode;
        deferredFaces.Add(defFace);
    }
示例#6
0
 //
 void RouteOper(BspNode inNode, CSGFace inFace, EPolySide inSide, OperationInfo info)
 {
     if (processState == EProcessState.Process_Master)
     {
         csgVisitor.ProcessMaster(this, inFace, inSide, info);
     }
     else
     {
         csgVisitor.ProcessSlave(this, inFace, inSide, info);
     }
 }
示例#7
0
    // TODO

    public void ProcessMaster(CsgOperation inOperation, CSGFace inFace, CsgOperation.EPolySide inSide, CsgOperation.OperationInfo info)
    {
        switch (inSide)
        {
        case CsgOperation.EPolySide.PolySide_Outside:
        case CsgOperation.EPolySide.PolySide_Planar_Outside:
        case CsgOperation.EPolySide.PolySide_CoPlanar_Outside:
        case CsgOperation.EPolySide.PolySide_CoPlanar_Inside:
            break;

        case CsgOperation.EPolySide.PolySide_Inside:
        case CsgOperation.EPolySide.PolySide_Planar_Inside:
            // add to deferred faces
            inOperation.AddDeferredFace(inFace);
            break;
        }
    }
示例#8
0
    public object Clone()
    {
        // create new Clone
        CSGFace clone = new CSGFace();

        // copy vertices
        clone.vertices = new Vector3[vertices.Length];
        System.Array.Copy(vertices, clone.vertices, vertices.Length);

        // copy uvs
        clone.uv = new Vector2[uv.Length];
        System.Array.Copy(uv, clone.uv, uv.Length);
        // copy material
        clone.material = material;
        // FIXME: clone flags???
        clone.flags = 0;
        return(clone);
    }
示例#9
0
    //
    public void Perform(ECsgOperation inOper, CSGObject inMaster, CSGObject inSlave)
    {
        // we are processing our slave faces
        processState = EProcessState.Process_Slave;

        // process faces against master tree
        PerformFaces(inMaster.rootNode, inSlave.faces);

        // process face from master tree
        processState = EProcessState.Process_Master;

        // perform master faces on slave bsp tree
        PerformTree(inMaster.rootNode, inSlave.rootNode);

        // check if how do we need to process generated faces
        if (inOper == ECsgOperation.CsgOper_Additive || inOper == ECsgOperation.CsgOper_Subtractive)
        {
            // add deferred faces to master tree...
            for (int i = 0; i < deferredFaces.Count; i++)
            {
                CSGFace defFace   = ((DeferredFace)deferredFaces[i]).face;
                BspNode startNode = ((DeferredFace)deferredFaces[i]).node;

                // testing
                startNode = inMaster.rootNode;
                // add node to master tree
                BspGen.AddNodeRecursive(startNode, defFace, BspNode.BspFlags_IsNew);
            }
        }
        else
        {
            // clear old faces list
            inMaster.faces.Clear();

            // copy created faces
            for (int i = 0; i < deferredFaces.Count; i++)
            {
                inMaster.faces.Add(deferredFaces[i].face);
            }
        }

        // clear deferred faces
        deferredFaces.Clear();
    }
示例#10
0
    public void ProcessSlave(CsgOperation inOperation, CSGFace inFace, CsgOperation.EPolySide inSide, CsgOperation.OperationInfo info)
    {
        switch (inSide)
        {
        case CsgOperation.EPolySide.PolySide_Outside:
        case CsgOperation.EPolySide.PolySide_Planar_Outside:
        case CsgOperation.EPolySide.PolySide_CoPlanar_Outside:
        case CsgOperation.EPolySide.PolySide_CoPlanar_Inside:
            break;

        case CsgOperation.EPolySide.PolySide_Inside:
        case CsgOperation.EPolySide.PolySide_Planar_Inside:
            // clone face
            CSGFace newFace = (CSGFace)inFace.Clone();
            newFace.Reverse();
            // add to deferred faces
            inOperation.AddDeferredFace(newFace);
            break;
        }
    }
示例#11
0
    public void ProcessMaster(CsgOperation inOperation, CSGFace inFace, CsgOperation.EPolySide inSide, CsgOperation.OperationInfo info)
    {
        switch (inSide)
        {
        case CsgOperation.EPolySide.PolySide_Outside:
        case CsgOperation.EPolySide.PolySide_Planar_Outside:
        case CsgOperation.EPolySide.PolySide_CoPlanar_Inside:
            // add cutted polygons
            if ((inFace.flags & CSGFace.FaceFlags_WasCutted) != 0)
            {
                inOperation.AddPlanarFace(inFace);
            }
            break;

        case CsgOperation.EPolySide.PolySide_Inside:
        case CsgOperation.EPolySide.PolySide_Planar_Inside:
        case CsgOperation.EPolySide.PolySide_CoPlanar_Outside:
            // discard node
            inOperation.MarkNodeAsDestroyed();
            break;
        }
    }
示例#12
0
    private void PerformNode(BspNode inNode, CSGFace inFace, int nodeSide, OperationInfo info)
    {
        while (inNode != null)
        {
            CSGFace.EPlaneSide side = inFace.Side(inNode.plane);

            switch (side)
            {
            case CSGFace.EPlaneSide.Side_Front:

                //
                nodeSide = nodeSide | (inNode.IsCsg() ? 1 : 0);

                // leaf node
                if (inNode.front == null)
                {
                    // set operation infos
                    info.leafNode     = inNode;
                    info.leafLocation = BspNode.EBspLocation.BspLocation_Front;

                    // we are done, process face
                    ProcessFace(inFace, SIDE_Outside, info);
                }

                // get to next front node (if any)
                inNode = inNode.front;

                break;

            case CSGFace.EPlaneSide.Side_Back:

                int backSide = inNode.IsCsg() ? 0 : 1;
                //
                nodeSide = nodeSide & backSide;

                // leaf node
                if (inNode.back == null)
                {
                    // set leaf infos
                    info.leafNode     = inNode;
                    info.leafLocation = BspNode.EBspLocation.BspLocation_Back;

                    // we are done, process face
                    ProcessFace(inFace, SIDE_Inside, info);
                }

                // get to next front node (if any)
                inNode = inNode.back;
                break;

            case CSGFace.EPlaneSide.Side_Split:

                // split face and process front and back
                CSGFace frontFace, backFace;

                //
                inFace.Split(inNode.plane, out frontFace, out backFace);

                // TODO: set polygon cutted flags
                frontFace.flags |= CSGFace.FaceFlags_WasCutted;
                backFace.flags  |= CSGFace.FaceFlags_WasCutted;


                // front node is a leaf node
                if (inNode.front == null)
                {
                    //
                    info.leafNode     = inNode;
                    info.leafLocation = BspNode.EBspLocation.BspLocation_Front;


                    ProcessFace(frontFace, SIDE_Outside, info);
                }
                else
                {
                    PerformNode(inNode.front, frontFace, nodeSide, info);
                }

                // Prcess back node with back face
                if (inNode.back == null)
                {
                    //
                    info.leafNode     = inNode;
                    info.leafLocation = BspNode.EBspLocation.BspLocation_Back;


                    ProcessFace(backFace, SIDE_Inside, info);
                }
                else
                {
                    // process back node with new face
                    PerformNode(inNode.back, backFace, nodeSide, info);
                }

                // stop loop
                inNode = null;
                break;

            case CSGFace.EPlaneSide.Side_Planar:

                BspNode front, back;

                if (info.wasPlanar == true)
                {
                    Debug.Log("Reentering Planar Nodes!");
                }


                // set operation infos
                info.wasPlanar      = true;
                info.backNode       = null;
                info.processingBack = false;

                if (Vector3.Dot(inFace.GetPlane().normal, inNode.plane.normal) >= 0.0f)
                {
                    // same order as we face in the same order
                    front = inNode.front;
                    back  = inNode.back;

                    // we are for now outside (as we are looking outside)
                    info.planarSide = SIDE_Outside;
                }
                else
                {
                    // reverse order as we are facing in the opposite direction
                    front = inNode.back;
                    back  = inNode.front;

                    // we are now inside as we are looking to the inside
                    info.planarSide = SIDE_Inside;
                }

                // we are leaf node (coplanar face)
                if (front == null && back == null)
                {
                    // set leaf stuff
                    info.leafNode     = inNode;
                    info.leafLocation = BspNode.EBspLocation.BspLocation_Planar;

                    // process node
                    info.processingBack = true;

                    // process face
                    ProcessFace(inFace, InverseSide(info.planarSide), info);

                    // stop loop
                    inNode = null;
                }
                else if (front == null && back != null)
                {
                    // only back nodes
                    info.processingBack = true;

                    // process back
                    inNode = back;
                }
                else
                {
                    // tread like we were on front side (maybe we do have a back node)
                    info.processingBack = false;

                    // remember back node
                    info.backNode = back;

                    // process front
                    inNode = front;
                }

                break;
            }
        }
    }
示例#13
0
    // Split this Face with given Plane
    public bool Split(Plane inPlane, out CSGFace outFront, out CSGFace outBack)
    {
        outFront = new CSGFace();
        outBack  = new CSGFace();

        float[]      distance = new float[vertices.Length + 1];
        EPlaneSide[] side     = new EPlaneSide[vertices.Length + 1];


        for (int i = 0; i < vertices.Length; ++i)
        {
            distance[i] = inPlane.GetDistanceToPoint(vertices[i]);
            side[i]     = Side(inPlane, vertices[i]);
        }

        distance[vertices.Length] = distance[0];
        side[vertices.Length]     = side[0];

        for (int i = 0; i < vertices.Length; ++i)
        {
            // if we lie on plane, add them to both
            if (side[i] == EPlaneSide.Side_Planar)
            {
                outFront.AddVertex(vertices[i], uv[i]);
                outBack.AddVertex(vertices[i], uv[i]);
                // nothing todo with this vertex
                continue;
            }

            // if we are on the front, add it to front face
            if (side[i] == EPlaneSide.Side_Front)
            {
                outFront.AddVertex(vertices[i], uv[i]);
            }
            // if we are on the back, add it to the back side
            else if (side[i] == EPlaneSide.Side_Back)
            {
                outBack.AddVertex(vertices[i], uv[i]);
            }

            // check if the next vertex is planar or on the same side, then we do not split
            if (side[i + 1] == EPlaneSide.Side_Planar || side[i] == side[i + 1])
            {
                continue;
            }

            // create split point
            Vector3 nextVector = vertices[(i + 1) % vertices.Length];
            Vector2 nextUV = uv[(i + 1) % uv.Length];
            Vector3 newVector, newUV;

            // if we were on the front
            if (side[i] == EPlaneSide.Side_Front)
            {
                float t = distance[i] / (distance[i] - distance[i + 1]);

                newVector = vertices[i] + t * (nextVector - vertices[i]);
                newUV     = uv[i] + t * (nextUV - uv[i]);
            }
            else             // back side...
            {
                float t = distance[i + 1] / (distance[i + 1] - distance[i]);

                newVector = nextVector + t * (vertices[i] - nextVector);
                newUV     = nextUV + t * (uv[i] - nextUV);
            }

            // split points are added

            // add to front
            outFront.AddVertex(newVector, newUV);

            // add to back
            outBack.AddVertex(newVector, newUV);
        }

        // Debugging checks
        if (outFront.vertices.Length < 3 || outBack.vertices.Length < 3)
        {
            Debug.Log("Degenerate Faces");
        }


        // todo...
        outFront.material = material;

        //
        outBack.material = material;

        return(true);
    }
示例#14
0
    //
    bool FindSplitter(List <CSGFace> inFaces, out CSGFace outFace)
    {
        int increase  = 1;
        int bestValue = 9999999;

        // reset out face...
        outFace = null;

        // setup optimization...
        switch (bspOptm)
        {
        case BspOptm_Worse:
            increase = Mathf.Max(1, inFaces.Count / 24);
            break;

        case BspOptm_Average:
            increase = Mathf.Max(1, inFaces.Count / 12);
            break;

        case BspOptm_Best:
        default:
            increase = 1;
            break;
        }

        // find best splitter plane
        for (int i = 0; i < inFaces.Count; i += increase)
        {
            // statistics
            int numSplits = 0, numFront = 0, numBack = 0, numPlanar = 0;

            //
            CSGFace splitterFace = inFaces[i] as CSGFace;

            //
            Plane splitterPlane = splitterFace.GetPlane();

            // sort all faces to side where it lies...
            for (int j = 0; j < inFaces.Count; ++j)
            {
                CSGFace.EPlaneSide side = (inFaces[j] as CSGFace).Side(splitterPlane);

                switch (side)
                {
                case CSGFace.EPlaneSide.Side_Front:
                    numFront++;
                    break;

                case CSGFace.EPlaneSide.Side_Back:
                    numBack++;
                    break;

                case CSGFace.EPlaneSide.Side_Planar:
                    numPlanar++;
                    break;

                case CSGFace.EPlaneSide.Side_Split:
                    numSplits++;
                    break;

                default:
                    //ERROR
                    Debug.DebugBreak();
                    break;
                }
            }

            //
            int val = numSplits * 5 + Mathf.Abs(numFront - numBack) + numPlanar;

            if (val < bestValue)
            {
                bestValue = val;
                outFace   = splitterFace;
            }
        }

        // if we have a face found, return true
        return(outFace != null);
    }
示例#15
0
    /* Intersection
     *
     *
     * // Master Faces against Slave Tree
     * private void AdditiveMaster( Face inFace, EPolySide inSide, OperationInfo info )
     * {
     *      Debug.Log( inSide );
     *
     *      switch( inSide )
     *      {
     *      case EPolySide.PolySide_Outside:
     *      case EPolySide.PolySide_Planar_Front:
     *              // discard original node
     *              currentNode.flags |= BspNode.BspFlags_IsDestroyed;
     *              break;
     *      case EPolySide.PolySide_Inside:
     *      case EPolySide.PolySide_Planar_Back:
     *      case EPolySide.PolySide_CoPlanar_Back:
     *      case EPolySide.PolySide_CoPlanar_Front:
     *              // add cutted polygons
     *              if( (inFace.flags & Face.FaceFlags_WasCutted) != 0 )
     *                      BspGen.AddNode( currentNode, BspNode.EBspLocation.BspLocation_Planar, inFace, BspNode.BspFlags_IsNew );
     *              break;
     *
     *      }
     * }
     *
     * // Slave Polygons against Master Tree
     * private void AdditiveSlave( Face inFace, EPolySide inSide, OperationInfo info )
     * {
     *
     * //		Debug.Log( inSide );
     *
     *      switch( inSide )
     *      {
     *      case EPolySide.PolySide_Outside:
     *      case EPolySide.PolySide_CoPlanar_Front:
     *      case EPolySide.PolySide_Planar_Front:
     *              break;
     *      case EPolySide.PolySide_Inside:
     *      case EPolySide.PolySide_Planar_Back:
     *      case EPolySide.PolySide_CoPlanar_Back:
     *
     *              // add to deferred faces
     *              DeferredFace defFace;
     *              defFace.face = inFace;
     *              defFace.node = currentNode;
     *              deferredFaces.Add( defFace );
     *              break;
     *
     *      }
     * }
     */

    // Callback for Visitor
    public void AddPlanarFace(CSGFace inFace)
    {
        BspGen.AddNode(currentNode, BspNode.EBspLocation.BspLocation_Planar, inFace, BspNode.BspFlags_IsNew);
    }
示例#16
0
    public static BspNode AddNodeRecursive(BspNode inNode, CSGFace inFace, int inFlags)
    {
        while (inNode != null)
        {
            CSGFace.EPlaneSide planeSide = inFace.Side(inNode.plane);

            switch (planeSide)
            {
            case CSGFace.EPlaneSide.Side_Front:

                if (inNode.front == null)
                {
                    return(AddNode(inNode, BspNode.EBspLocation.BspLocation_Front, inFace, inFlags));
                }

                inNode = inNode.front;
                break;

            case CSGFace.EPlaneSide.Side_Back:

                if (inNode.back == null)
                {
                    return(AddNode(inNode, BspNode.EBspLocation.BspLocation_Back, inFace, inFlags));
                }

                inNode = inNode.back;
                break;

            case CSGFace.EPlaneSide.Side_Planar:
                return(AddNode(inNode, BspNode.EBspLocation.BspLocation_Planar, inFace, inFlags));

            case CSGFace.EPlaneSide.Side_Split:

                CSGFace frontFace, backFace;

                inFace.Split(inNode.plane, out frontFace, out backFace);

                if (inNode.front == null)
                {
                    AddNode(inNode, BspNode.EBspLocation.BspLocation_Front, frontFace, inFlags);
                }
                else
                {
                    AddNodeRecursive(inNode.front, frontFace, inFlags);
                }

                if (inNode.back == null)
                {
                    AddNode(inNode, BspNode.EBspLocation.BspLocation_Back, inFace, inFlags);
                }
                else
                {
                    AddNodeRecursive(inNode.back, backFace, inFlags);
                }

                inNode = null;
                break;
            }
        }

        // happens when face get splitted...
        return(null);
    }
示例#17
0
    //
    private void ProcessFace(CSGFace inFace, int inNodeSide, OperationInfo info)
    {
        EPolySide polySide;

        // never on a planar node, really easy
        if (info.wasPlanar == false)
        {
            // set polyside
            polySide = (inNodeSide == SIDE_Outside) ? EPolySide.PolySide_Outside : EPolySide.PolySide_Inside;

            //
            RouteOper(null, inFace, polySide, info);
        }
        else if (info.processingBack)
        {
            //
            if (inNodeSide == info.planarSide)
            {
                polySide = (inNodeSide == SIDE_Inside) ? EPolySide.PolySide_Planar_Inside : EPolySide.PolySide_Planar_Outside;
            }
            else
            {
                polySide = (info.planarSide == SIDE_Inside) ? EPolySide.PolySide_CoPlanar_Inside : EPolySide.PolySide_CoPlanar_Outside;
            }


            RouteOper(null, inFace, polySide, info);
        }
        else
        {
            //
            int backNodeSide = InverseSide(info.planarSide);

            //
            info.planarSide = inNodeSide;

            // back node is empty
            if (info.backNode == null)
            {
                // back tree is empty
                inNodeSide = backNodeSide;

                // back node is empty
                if (inNodeSide == info.planarSide)
                {
                    polySide = (inNodeSide == SIDE_Inside) ? EPolySide.PolySide_Planar_Inside : EPolySide.PolySide_Planar_Outside;
                }
                else
                {
                    polySide = (info.planarSide == SIDE_Inside) ? EPolySide.PolySide_CoPlanar_Inside : EPolySide.PolySide_CoPlanar_Outside;
                }

                RouteOper(null, inFace, polySide, info);
            }
            else
            {
                info.processingBack = true;

                // TODO: conversion
                inNodeSide = backNodeSide;

                //
                PerformNode(info.backNode, inFace, inNodeSide, info);
            }
        }
    }
示例#18
0
    //
    void Partition(BspNode inNode, List <CSGFace> inFaces)
    {
        List <CSGFace> frontFaces = new List <CSGFace>();
        List <CSGFace> backFaces  = new List <CSGFace>();
        CSGFace        nodeFace;

        // find best splitter plane for this
        bool ret = FindSplitter(inFaces, out nodeFace);

        // return has to be true!!!
        if (ret == false)
        {
            Debug.DebugBreak();
            Debug.Log("Error processing Mesh!");
            return;
        }

        // setup node
        inNode.front  = null;
        inNode.back   = null;
        inNode.planar = null;
        inNode.face   = nodeFace;
        inNode.plane  = nodeFace.GetPlane();


        // split remaining faces into lists
        for (int i = 0; i < inFaces.Count; ++i)
        {
            // get face
            CSGFace face = inFaces[i] as CSGFace;

            // do not process our self
            if (face == nodeFace)
            {
                continue;
            }


            CSGFace.EPlaneSide side = face.Side(inNode.plane);

            switch (side)
            {
            case CSGFace.EPlaneSide.Side_Front:
                frontFaces.Add(face);
                break;

            case CSGFace.EPlaneSide.Side_Back:
                backFaces.Add(face);
                break;

            case CSGFace.EPlaneSide.Side_Planar:
                // get last planar node
                BspNode lastPlanar = inNode;
                while (lastPlanar.planar != null)
                {
                    lastPlanar = lastPlanar.planar;
                }

                // create new planar node
                BspNode planar = lastPlanar.planar = new BspNode();

                // setup planar node
                planar.front  = null;
                planar.back   = null;
                planar.planar = null;
                planar.face   = face;
                planar.plane  = face.GetPlane();

                break;

            case CSGFace.EPlaneSide.Side_Split:
                // TODO...
                CSGFace front, back;
                // split face into two parts...
                ret = face.Split(inNode.plane, out front, out back);

                if (ret == false)
                {
                    Debug.DebugBreak();
                }

                // add to front and back
                frontFaces.Add(front);
                backFaces.Add(back);
                break;
            }
        }

        // optimizing a bit, clear in array list as we do not need it any more
        inFaces.Clear();

        // process front faces
        if (frontFaces.Count > 0)
        {
            inNode.front = new BspNode();
            // partition front faces
            Partition(inNode.front, frontFaces);
        }


        // process back faces
        if (backFaces.Count > 0)
        {
            inNode.back = new BspNode();
            // partition back faces
            Partition(inNode.back, backFaces);
        }
    }
示例#19
0
    public static void MergeCoplanars(BspNode inNode)
    {
        // proceed front nodes
        if (inNode.front != null)
        {
            MergeCoplanars(inNode.front);
        }

        // proceed back nodes
        if (inNode.back != null)
        {
            MergeCoplanars(inNode.back);
        }

        // first try to merge other co planar nodes
        if (inNode.planar != null)
        {
            MergeCoplanars(inNode.planar);
        }

        //
        bool tryToMerge = (inNode.flags & BspNode.BspFlags_IsDestroyed) == 0;

        while (tryToMerge)
        {
            // get planar node
            BspNode planarNode = inNode.planar;

            // assume we are done
            tryToMerge = false;

            // get through all planar nodes
            while (planarNode != null)
            {
                // if we are destroyed, proceed to next
                if ((planarNode.flags & BspNode.BspFlags_IsDestroyed) != 0)
                {
                    // proceed to next
                    planarNode = planarNode.planar;
                    continue;
                }


                CSGFace thisFace  = inNode.face;
                CSGFace otherFace = planarNode.face;

                // are we facing the same direction
                if (Vector3.Dot(thisFace.GetPlane().normal, otherFace.GetPlane().normal) > 0.995f)
                {
                    // result
                    CSGFace merged;

                    //
                    if (thisFace.Merge(otherFace, out merged))
                    {
                        // replace this face with merged
                        thisFace = merged;

                        // set other node as destroyed
                        planarNode.flags |= BspNode.BspFlags_IsDestroyed;

                        // retry to merge
                        tryToMerge = true;
                    }
                }

                // proceed to next
                planarNode = planarNode.planar;
            }
        }
    }
示例#20
0
    public bool Merge(CSGFace inOther, out CSGFace outFace)
    {
        outFace = null;


        // do not share same material
        if (material != inOther.material || vertices.Length < 1)
        {
            return(false);
        }

        Vector3 p1, p2;
        Vector3 p3, p4;
        int     i = 0, j = 0;

        // just to fix compiler error
        p1 = vertices[0];
        p2 = vertices[1 % vertices.Length];

        // check if we share an edge
        for (i = 0; i < vertices.Length; ++i)
        {
            // get edge
            p1 = vertices[i];
            p2 = vertices[(i + 1) % vertices.Length];


            // go through all edges of other face
            for (j = 0; j < inOther.vertices.Length; ++j)
            {
                // get other edge
                p3 = inOther.vertices[j];
                p4 = inOther.vertices[(j + 1) % inOther.vertices.Length];

                // check if we are sharing an edge
                if (p1.Equals(p4) && p2.Equals(p3))
                {
                    break;
                }
            }

            // found edge
            if (j < inOther.vertices.Length)
            {
                break;
            }
        }

        // no edge found
        if (i == vertices.Length)
        {
            return(false);
        }

        //  ...
        Vector3 back  = vertices[(i + vertices.Length - 1) % vertices.Length];
        Vector3 delta = p1 - back;

        Vector3 normal = Vector3.Cross(GetPlane().normal, delta);

        normal.Normalize();

        back  = inOther.vertices[(j + 2) % inOther.vertices.Length];
        delta = back - p1;

        float dot = Vector3.Dot(delta, normal);

        // not a convex polygon
        if (dot > GlobalSettings.Epsilonf)
        {
            return(false);
        }

        // if they are co linear
        bool keep1 = (dot < -GlobalSettings.Epsilonf);

        // ...
        back   = vertices[(i + 2) % vertices.Length];
        delta  = back - p2;
        normal = Vector3.Cross(GetPlane().normal, delta);
        normal.Normalize();

        back  = inOther.vertices[(j + inOther.vertices.Length - 1) % inOther.vertices.Length];
        delta = back - p2;
        dot   = Vector3.Dot(delta, normal);

        // not convex
        if (dot > GlobalSettings.Epsilonf)
        {
            return(false);
        }

        bool keep2 = (dot < -GlobalSettings.Epsilonf);

        bool keep = false;

        // create out face
        outFace = new CSGFace();

        outFace.flags    = flags;
        outFace.material = material;

        // copy vertices from this
        for (int k = (i + 1) % vertices.Length; k != i; k = (k + 1) % vertices.Length)
        {
            if (!keep && k == (i + 1) % vertices.Length && !keep2)
            {
                continue;
            }

            // copy vector
            outFace.AddVertex(vertices[k], uv[k]);
        }

        // copy vertices from other
        for (int k = (j + 1) % inOther.vertices.Length; k != j; k = (k + 1) % inOther.vertices.Length)
        {
            if (!keep && k == (j + 1) % inOther.vertices.Length && !keep1)
            {
                continue;
            }

            outFace.AddVertex(inOther.vertices[k], inOther.uv[k]);
        }

        return(true);
    }