public override void Write(byte[] data, ref int offset) { int sortStatPosition = offset; PolymodelBuilder.SetShort(data, ref offset, 4); // SORTNORM opcode PolymodelBuilder.SetShort(data, ref offset, 0); // int n_points PolymodelBuilder.SetFixVector(data, ref offset, Normal); PolymodelBuilder.SetFixVector(data, ref offset, Point); int frontOffset = offset; PolymodelBuilder.SetShort(data, ref offset, 12345); // fix the back offset later int backOffset = offset; PolymodelBuilder.SetShort(data, ref offset, 12345); // fix the front offset later // End PolymodelBuilder.SetShort(data, ref offset, ModelOpCode.End); // END opcode // Front int frontOffsetValue = offset - sortStatPosition; FrontInstruction.Write(data, ref offset); // Back int backOffsetValue = offset - sortStatPosition; BackInstruction.Write(data, ref offset); // store current position int endPosition = offset; if (frontOffsetValue > short.MaxValue || backOffsetValue > short.MaxValue) { throw new ArgumentException("Model is too complex: 32KB displacement limit exceeded when compiling subobjects."); } offset = frontOffset; PolymodelBuilder.SetShort(data, ref offset, (short)frontOffsetValue); offset = backOffset; PolymodelBuilder.SetShort(data, ref offset, (short)backOffsetValue); // Return offset = endPosition; }
public void CompileInterpreterData(int vertexOffset) { if (mCompiled) { return; } mCompiled = true; //one MB of scratch space byte[] data = new byte[1024 * 1024]; int offset = 0; vertexDict = new Dictionary <FixVector, int>(); PolymodelBuilder.SetShort(data, ref offset, ModelOpCode.DefinePointStart); //Get all points //An ordered set would be great here... mVertexOffset = vertexOffset; GetVertexes(RootNode, data); PolymodelBuilder.SetShort(data, ref offset, (short)vertexDict.Count); //Number of points PolymodelBuilder.SetShort(data, ref offset, (short)vertexOffset); //Offset into the vertex list PolymodelBuilder.SetShort(data, ref offset, 0); //Padding NumVertices += vertexDict.Count; Console.WriteLine("Subobject generated {0} unique vertices", vertexDict.Count); foreach (var point in vertexDict.Keys) { PolymodelBuilder.SetFixVector(data, ref offset, point); } // Get faces GetFaces(RootNode, data, ref offset); InterpreterData = data.Take(offset).ToArray(); }
public override void Write(byte[] data, ref int offset) { int index = SubModel.ID; int offsetBase = offset; PolymodelBuilder.SetShort(data, ref offset, ModelOpCode.SubCall); short submodelNum = (short)(index); PolymodelBuilder.SetShort(data, ref offset, submodelNum); FixVector submodelOffset = SubModel.Offset; PolymodelBuilder.SetFixVector(data, ref offset, submodelOffset); //The address where we write the new offset value int offsetAddress = offset; short offsetValue = 0; PolymodelBuilder.SetShort(data, ref offset, offsetValue); offset += 2; //Subcall is immediately followed with the end op code PolymodelBuilder.SetShort(data, ref offset, ModelOpCode.End); // Calculate the new offset offsetValue = (short)(offset - offsetBase); Instruction.Write(data, ref offset); // Store offset var endOffset = offset; offset = offsetAddress; PolymodelBuilder.SetShort(data, ref offset, (short)offsetValue); offset = endOffset; }
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); } }