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); } }
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"); }
public FixVector(Fix x, Fix y, Fix z) { this.X = x; this.Y = y; this.Z = z; }
public void WriteFix(Fix value) { this.WriteInt32(value.Value); }
public LevelVertex(Fix x, Fix y, Fix z) { location = new FixVector(x, y, z); }