Ejemplo n.º 1
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.º 2
0
        private MetaInstructionBase GetHierarchy(int modelIndex)
        {
            //Form the hierachy by the following process:
            //Pick the submitted model, and take one of its children
            //Generate a sortnorm with the child in front, and the model, with that child removed on the back
            //Recurse across the child in front, which will sort its children, and the original model on the back, with that child gone.
            Submodel submodel = currentModel.Submodels[modelIndex];
            BSPModel data     = submodels[modelIndex];

            //Check if no children. If not, we're done.
            if (data.ChildrenList.Count == 0)
            {
                data.CompileInterpreterData(vertexOffset);
                vertexOffset += data.NumVertices;
                MetaModelInstruction instruction = new MetaModelInstruction()
                {
                    Model     = submodel,
                    DataModel = data
                };

                return(instruction);
            }
            else
            {
                //Get the child and remove it from the front
                //int child = data.ChildrenList[0];
                //data.ChildrenList.RemoveAt(0);

                //Prefer closer objects first, to try to make sorting more reliable in complex situations.
                int childIndex = 0;
                Fix bestLength = 32700.0;
                for (int i = 0; i < data.ChildrenList.Count; i++)
                {
                    Fix dist = (currentModel.Submodels[data.ChildrenList[i]].Point - submodel.Point).Mag();
                    if (dist < bestLength)
                    {
                        childIndex = i;
                    }
                }

                int child = data.ChildrenList[childIndex];
                data.ChildrenList.RemoveAt(childIndex);

                //Generate a sortnorm instruction
                MetaSortInstruction instruction = new MetaSortInstruction();
                instruction.Normal = currentModel.Submodels[child].Normal;
                instruction.Point  = currentModel.Submodels[child].Point;

                //Front is the newly created child
                //Need a subcall entering it. A submodel should only ever be entered in the front once.
                MetaSubModelInstruction submodelInstruction = new MetaSubModelInstruction();
                submodelInstruction.SubModel    = currentModel.Submodels[child];
                submodelInstruction.Instruction = GetHierarchy(child);
                instruction.FrontInstruction    = submodelInstruction;

                //Back is the current set, but with the original child no longer considered
                instruction.BackInstruction = GetHierarchy(modelIndex);

                return(instruction);
            }

            /*MetaInstructionBase rootInstruction = new MetaModelInstruction
             * {
             *  Model = rootModel
             * };
             *
             * var meshesToProcess = rootModel.Children.ToList();
             *
             * while (meshesToProcess.Any())
             * {
             *  var closestMesh = this.GetClosestModel(meshesToProcess, rootModel);
             *
             *  meshesToProcess.Remove(closestMesh);
             *
             *  MetaSortInstruction sorting = new MetaSortInstruction();
             *
             *  CalculatePositionAndNormal(rootModel, closestMesh, sorting);
             *
             *  sorting.BackInstruction = new MetaSubModelInstruction
             *  {
             *      SubModel = closestMesh,
             *      Instruction = GetHierarchy(closestMesh)
             *
             *  };
             *
             *  sorting.FrontInstruction = rootInstruction;
             *
             *  rootInstruction = sorting;
             * }*/
            throw new Exception("PolymodelBuilder::GetHierarchy: generated null instruction");
        }
Ejemplo n.º 3
0
 public FixVector(Fix x, Fix y, Fix z)
 {
     this.X = x; this.Y = y; this.Z = z;
 }
Ejemplo n.º 4
0
 public void WriteFix(Fix value)
 {
     this.WriteInt32(value.Value);
 }
Ejemplo n.º 5
0
 public LevelVertex(Fix x, Fix y, Fix z)
 {
     location = new FixVector(x, y, z);
 }