public List <BSPModel> Extract()
        {
            modelDatas = new List <BSPModel>();

            for (int i = 0; i < model.NumSubmodels; i++)
            {
                var currentModel = new BSPModel(i);
                modelDatas.Add(currentModel);

                //Make sure IDs are correct
                model.Submodels[i].ID = i;
            }

            Execute(model.InterpreterData, 0, model, model.Submodels[0], modelDatas[0]);

            for (int i = 0; i < modelDatas.Count; i++)
            {
                //bash all pointers to 0 because they'll be set later.
                model.Submodels[modelDatas[i].SubmodelNum].Pointer = 0;

                //Build list of all children for eash BSP model. This list will be used to build trees across submodels.
                if (model.Submodels[modelDatas[i].SubmodelNum].Parent != 255)
                {
                    modelDatas[model.Submodels[modelDatas[i].SubmodelNum].Parent].ChildrenList.Add(i);
                }
            }

            return(modelDatas);
        }
Example #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");
        }
        private void Execute(byte[] data, int offset, Polymodel mainModel, Submodel model, BSPModel currentModel)
        {
            short instruction = GetShort(data, ref offset);

            while (true)
            {
                switch (instruction)
                {
                case ModelOpCode.End:
                    return;

                case ModelOpCode.Points:
                {
                    short pointc = GetShort(data, ref offset);
                    for (int i = 0; i < pointc; i++)
                    {
                        interpPoints[i] = GetFixVector(data, ref offset);
                    }
                }
                break;

                case ModelOpCode.FlatPoly:     //FLATPOLY
                {
                    short     pointc = GetShort(data, ref offset);
                    FixVector point  = GetFixVector(data, ref offset);
                    FixVector normal = GetFixVector(data, ref offset);
                    short     color  = GetShort(data, ref offset);

                    short[] points = new short[pointc];         //TODO: seems wasteful to do all these allocations?
                    for (int i = 0; i < pointc; i++)
                    {
                        points[i] = GetShort(data, ref offset);
                    }
                    if (pointc % 2 == 0)
                    {
                        GetShort(data, ref offset);
                    }

                    if (pointc >= 3)
                    {
                        var triangle = new BSPFace();

                        triangle.Normal    = new Vector3(normal.X, normal.Y, normal.Z);
                        triangle.Point     = new Vector3(point.X, point.Y, point.Z);
                        triangle.Color     = color;
                        triangle.TextureID = -1;

                        currentModel.Polygons.Add(triangle);

                        for (int i = 0; i < pointc; i++)
                        {
                            var vxA = interpPoints[points[i]].X;
                            var vyA = interpPoints[points[i]].Y;
                            var vzA = interpPoints[points[i]].Z;

                            triangle.Points.Add(new BSPVertex {
                                    Point = new Vector3(vxA, vyA, vzA), UVs = new Vector3(0.0f, 0.0f, 0.0f)
                                });
                        }
                    }
                }
                break;

                case ModelOpCode.TexturedPoly:     //TMAPPOLY
                {
                    short     pointc  = GetShort(data, ref offset);
                    FixVector point   = GetFixVector(data, ref offset);
                    FixVector normal  = GetFixVector(data, ref offset);
                    short     texture = GetShort(data, ref offset);

                    short[]     points = new short[pointc];     //TODO: seems wasteful to do all these allocations?
                    FixVector[] uvls   = new FixVector[pointc];
                    for (int i = 0; i < pointc; i++)
                    {
                        points[i] = GetShort(data, ref offset);
                    }
                    if (pointc % 2 == 0)
                    {
                        GetShort(data, ref offset);
                    }

                    for (int i = 0; i < pointc; i++)
                    {
                        uvls[i] = GetFixVector(data, ref offset);
                    }

                    if (pointc >= 3)
                    {
                        var triangle = new BSPFace();

                        triangle.Normal    = new Vector3(normal.X, normal.Y, normal.Z);
                        triangle.Point     = new Vector3(point.X, point.Y, point.Z);
                        triangle.TextureID = texture;
                        currentModel.Polygons.Add(triangle);

                        for (int i = 0; i < pointc; i++)
                        {
                            var vxA = interpPoints[points[i]].X;
                            var vyA = interpPoints[points[i]].Y;
                            var vzA = interpPoints[points[i]].Z;

                            var uvxA = uvls[i].X;
                            var uvyA = uvls[i].Y;

                            triangle.Points.Add(new BSPVertex {
                                    Point = new Vector3(vxA, vyA, vzA), UVs = new Vector3(uvxA, uvyA, 0.0f)
                                });
                        }
                    }
                }
                break;

                case ModelOpCode.SortNormal:     //SORTNORM
                {
                    IsPartitioned = true;
                    int       baseOffset  = offset - 2;
                    int       n_points    = GetShort(data, ref offset);
                    FixVector norm        = GetFixVector(data, ref offset);
                    FixVector point       = GetFixVector(data, ref offset);
                    short     backOffset  = GetShort(data, ref offset);
                    short     frontOffset = GetShort(data, ref offset);

                    Execute(data, baseOffset + frontOffset, mainModel, model, currentModel);
                    Execute(data, baseOffset + backOffset, mainModel, model, currentModel);
                }
                break;

                case ModelOpCode.Rod:     //RODBM
                {
                    offset += 34;
                }
                break;

                case ModelOpCode.SubCall:     //SUBCALL
                {
                    int       baseOffset     = offset - 2;
                    short     submodelNum    = GetShort(data, ref offset);
                    FixVector submodelOffset = GetFixVector(data, ref offset);
                    short     modelOffset    = GetShort(data, ref offset);
                    offset += 2;

                    Submodel newModel = mainModel.Submodels[submodelNum];

                    currentModel.modelOffset = submodelOffset;

                    Execute(data, baseOffset + modelOffset, mainModel, newModel, modelDatas[submodelNum]);
                }
                break;

                case ModelOpCode.DefinePointStart:     //DEFPSTART
                {
                    short pointc     = GetShort(data, ref offset);
                    short firstPoint = GetShort(data, ref offset);
                    offset += 2;

                    for (int i = 0; i < pointc; i++)
                    {
                        interpPoints[i + firstPoint] = GetFixVector(data, ref offset);
                    }
                }
                break;

                case ModelOpCode.Glow:
                    offset += 2;
                    break;

                default:
                    throw new Exception(string.Format("Unknown interpreter instruction {0} at offset {1}\n", instruction, offset));
                }
                instruction = GetShort(data, ref offset);
            }
        }