Ejemplo n.º 1
0
        private void GetVertexes(BSPNode node, byte[] interpreterData)
        {
            if (node == null)
            {
                return;
            }

            if (node.faces != null)
            {
                foreach (var face in node.faces)
                {
                    foreach (var point in face.Points)
                    {
                        Fix x = point.Point.X;
                        Fix y = point.Point.Y;
                        Fix z = point.Point.Z;

                        //TODO this is a bit slow overall
                        var vec = new FixVector(x, y, z);

                        if (!vertexDict.ContainsKey(vec))
                        {
                            vertexDict.Add(vec, vertexDict.Count + mVertexOffset);
                        }
                    }
                }
            }

            GetVertexes(node.Front, interpreterData);
            GetVertexes(node.Back, interpreterData);
        }
Ejemplo n.º 2
0
        public void GetFaces(BSPNode node, byte[] data, ref int modelDataOffset)
        {
            if (node == null)
            {
                return;
            }

            if (node.Front == null && node.Back != null)
            {
                throw new Exception("ModelData::GetFaces: Front is null but back isn't.");
            }
            else if (node.Front != null && node.Back == null)
            {
                throw new Exception("ModelData::GetFaces: Back is null but front isn't.");
            }

            if (node.Front != null && node.Back != null)
            {
                if (node.Point.X == node.Point.Y && node.Point.Y == node.Point.Z && node.Point.Z == 0.0f)
                {
                    //TODO: figure out if this is actually an error condition.
                    throw new Exception("ModelData::GetFaces: splitter point is 0 but this probably isn't a problem. Probably.");
                }

                // Sort start
                int sortStatPosition = modelDataOffset;

                PolymodelBuilder.SetShort(data, ref modelDataOffset, 4); // SORTNORM opcode

                PolymodelBuilder.SetShort(data, ref modelDataOffset, 0); // int n_points

                FixVector normal = new FixVector(node.Normal.X, node.Normal.Y, node.Normal.Z);
                FixVector point  = new FixVector(node.Point.X, node.Point.Y, node.Point.Z);

                PolymodelBuilder.SetFixVector(data, ref modelDataOffset, normal);
                PolymodelBuilder.SetFixVector(data, ref modelDataOffset, point);

                int backOffset = modelDataOffset;
                PolymodelBuilder.SetShort(data, ref modelDataOffset, (short)backOffset); // fix the back offset later

                int frontOffset = modelDataOffset;
                PolymodelBuilder.SetShort(data, ref modelDataOffset, (short)frontOffset); // fix the front offset later

                // Terminator opcode
                PolymodelBuilder.SetShort(data, ref modelDataOffset, ModelOpCode.End);

                // Process front and store offset
                int frontOffsetValue = modelDataOffset - sortStatPosition;
                GetFaces(node.Front, data, ref modelDataOffset);

                // Process back and store offset
                int backOffsetValue = modelDataOffset - sortStatPosition;
                GetFaces(node.Back, data, ref modelDataOffset);


                // Store the end position
                int endPosition = modelDataOffset;

                if (frontOffsetValue > short.MaxValue || backOffsetValue > short.MaxValue || modelDataOffset < 0)
                {
                    throw new ArgumentException("Model is too complex: 32KB displacement limit exceeded.");
                }

                // Correct the back offset
                modelDataOffset = backOffset;
                PolymodelBuilder.SetShort(data, ref modelDataOffset, (short)frontOffsetValue); // fix the back offset later

                // Correct the front offset
                modelDataOffset = frontOffset;
                PolymodelBuilder.SetShort(data, ref modelDataOffset, (short)backOffsetValue); // fix the back offset later


                // Restore the offset to the end position
                modelDataOffset = endPosition;

                if (node.faces != null && node.faces.Any())
                {
                    throw new Exception("Missing faces!");
                }
            }
            else if (node.faces != null)
            {
                int       facesStatPosition = modelDataOffset;
                BSPVertex vert;
                short     vertexNum;
                foreach (var face in node.faces)
                {
                    if (face.TextureID == -1)
                    {
                        // Flat poly opcode
                        PolymodelBuilder.SetShort(data, ref modelDataOffset, ModelOpCode.FlatPoly);

                        short pointc = (short)face.Points.Count();
                        PolymodelBuilder.SetShort(data, ref modelDataOffset, pointc);

                        Fix x = face.Point.X;
                        Fix y = face.Point.Y;
                        Fix z = face.Point.Z;

                        var facePoint = new FixVector(x, y, z);

                        PolymodelBuilder.SetFixVector(data, ref modelDataOffset, facePoint);

                        x = face.Normal.X;
                        y = face.Normal.Y;
                        z = face.Normal.Z;

                        var normal = new FixVector(x, y, z);

                        PolymodelBuilder.SetFixVector(data, ref modelDataOffset, normal);
                        PolymodelBuilder.SetShort(data, ref modelDataOffset, (short)face.Color);
                        for (short i = 0; i < pointc; i++)
                        {
                            vert = face.Points[i];
                            FixVector vec = new FixVector(vert.Point.X, vert.Point.Y, vert.Point.Z);
                            vertexNum = (short)vertexDict[vec];
                            PolymodelBuilder.SetShort(data, ref modelDataOffset, vertexNum);
                        }

                        if (pointc % 2 == 0)
                        {
                            PolymodelBuilder.SetShort(data, ref modelDataOffset, 0);
                        }
                    }
                    else
                    {
                        // tmapped poly opcode
                        PolymodelBuilder.SetShort(data, ref modelDataOffset, ModelOpCode.TexturedPoly);

                        short pointc = (short)face.Points.Count();
                        PolymodelBuilder.SetShort(data, ref modelDataOffset, pointc);

                        Fix x = face.Point.X;
                        Fix y = face.Point.Y;
                        Fix z = face.Point.Z;

                        var facePoint = new FixVector(x, y, z);

                        PolymodelBuilder.SetFixVector(data, ref modelDataOffset, facePoint);

                        x = face.Normal.X;
                        y = face.Normal.Y;
                        z = face.Normal.Z;

                        var normal = new FixVector(x, y, z);

                        PolymodelBuilder.SetFixVector(data, ref modelDataOffset, normal);

                        PolymodelBuilder.SetShort(data, ref modelDataOffset, (short)face.TextureID);

                        for (short i = 0; i < pointc; i++)
                        {
                            vert = face.Points[i];
                            FixVector vec = new FixVector(vert.Point.X, vert.Point.Y, vert.Point.Z);
                            vertexNum = (short)vertexDict[vec];
                            PolymodelBuilder.SetShort(data, ref modelDataOffset, vertexNum);
                        }

                        if (pointc % 2 == 0)
                        {
                            PolymodelBuilder.SetShort(data, ref modelDataOffset, 0);
                        }

                        for (short i = 0; i < pointc; i++)
                        {
                            x = face.Points[i].UVs.X;
                            y = face.Points[i].UVs.Y;
                            z = face.Points[i].UVs.Z;

                            var uv = new FixVector(x, y, z);

                            PolymodelBuilder.SetFixVector(data, ref modelDataOffset, uv);
                        }
                    }
                }

                PolymodelBuilder.SetShort(data, ref modelDataOffset, ModelOpCode.End);
            }
        }
Ejemplo n.º 3
0
        public void BuildTree(BSPNode node, List <BSPFace> faces)
        {
#if DEBUG_SPLITTER_DIAGONISTICS
            if (recursionLevel == 0)
            {
                Console.WriteLine("----------------------------------------------");
                Console.WriteLine("STARTING");
                Console.WriteLine("----------------------------------------------");
            }
            recursionLevel++;
#endif
            List <BSPFace> frontList = new List <BSPFace>();
            List <BSPFace> backList  = new List <BSPFace>();

            node.Splitter = FindSplitter(faces, ref node.Point, ref node.Normal);

            if (node.Splitter == null) //If a splitter wasn't found, this set of faces is convex
            {
                node.faces = faces;
                node.type  = BSPNodeType.Leaf;
            }
            else //A splitter is known, so do any needed splits and recurse
            {
                foreach (BSPFace face in faces)
                {
                    if (face != node.Splitter) //splitter is classified and added later.
                    {
                        ClassifyFace(face, node.Splitter.Point, node.Splitter.Normal);
                        //else
                        //    //[ISB] Fix bug with splitters ending up on both sides. Doom puts them in front implicity
                        //    face.Classification = BSPClassification.Front;

                        switch (face.Classification)
                        {
                        case BSPClassification.Front:
                            frontList.Add(face);
                            break;

                        case BSPClassification.Back:
                            backList.Add(face);
                            break;

                        case BSPClassification.Spanning:
                            BSPFace frontFace = new BSPFace();
                            BSPFace backFace  = new BSPFace();
                            if (face.TextureID == -1)     // colored face
                            {
                                frontFace.Color = backFace.Color = face.Color;
                            }

                            SplitPolygon(face, node.Splitter.Point, node.Splitter.Normal, ref frontFace, ref backFace);


                            frontList.Add(frontFace);
                            backList.Add(backFace);
                            break;

                        default:
                            throw new Exception("BSPTree::BuildTree: Face has invalid classification.");
                        }
                    }
                }

                //Where does the splitter go?
                //Try it in both the front and back. Whichever one generates the highest score fails.
                int            frontScore = 0;
                int            backScore  = 0;
                int            tempScore;
                List <BSPFace> faceTemp;

                if (frontList.Count > 0)
                {
                    faceTemp = new List <BSPFace>(frontList);
                    faceTemp.Add(node.Splitter);
                    foreach (BSPFace face in faceTemp)
                    {
                        tempScore = EvalulateSplitter(faceTemp, face);
                        if (tempScore != int.MaxValue && tempScore > frontScore)
                        {
                            frontScore = tempScore;
                        }
                    }
                }
                else
                {
                    frontScore = int.MaxValue;
                }

                if (backList.Count > 0)
                {
                    faceTemp = new List <BSPFace>(backList);
                    faceTemp.Add(node.Splitter);
                    foreach (BSPFace face in faceTemp)
                    {
                        tempScore = EvalulateSplitter(faceTemp, face);
                        if (tempScore != int.MaxValue && tempScore > backScore)
                        {
                            backScore = tempScore;
                        }
                    }
                }
                else
                {
                    backScore = int.MaxValue;
                }

                if (frontScore > backScore)
                {
                    frontList.Add(node.Splitter);
                }
                else
                {
                    backList.Add(node.Splitter);
                }

#if DEBUG_SPLITTER_DIAGONISTICS
                if (recursionLevel <= 2)
                {
                    Console.WriteLine("Frontlist:{0} Backlist:{1}, fs<bs:{2}", frontList.Count, backList.Count, frontScore < backScore);
                }
#endif

                if (frontList.Count > 0)
                {
                    BSPNode newNode = new BSPNode();
                    newNode.type = BSPNodeType.Node;

#if DEBUG_SPLITTER_DIAGONISTICS
                    if (recursionLevel <= 1)
                    {
                        Console.WriteLine("Doing front.");
                    }
#endif
                    BuildTree(newNode, frontList);
                    node.Front = newNode;
                }

                if (backList.Count > 0)
                {
                    BSPNode newNode = new BSPNode();
                    newNode.type = BSPNodeType.Node;
#if DEBUG_SPLITTER_DIAGONISTICS
                    if (recursionLevel <= 1)
                    {
                        Console.WriteLine("Doing back.");
                    }
#endif
                    BuildTree(newNode, backList);
                    node.Back = newNode;
                }
            }
#if DEBUG_SPLITTER_DIAGONISTICS
            recursionLevel--;
#endif
        }