public static string CreateMtlFileForBsp(BspTag tag) { var sb = new StringBuilder(); var alreadyGenerated = new HashSet <uint>(); for (var i = 0; i < tag.RenderChunks.Length; i++) { var model = tag.RenderChunks[i].Model; foreach (var mesh in model.Meshes) { var matId = mesh.Shader.Id + 1; if (alreadyGenerated.Contains(matId)) { continue; } var color = GenerateRandomColor(); sb.AppendLine($"newmtl {matId}"); sb.AppendLine($"Kd {(color.R / 255f).ToString("0.000000")} {(color.G / 255f).ToString("0.000000")} {(color.B / 255f).ToString("0.000000")}"); sb.AppendLine($"Ka {(color.R / 255f).ToString("0.000000")} {(color.G / 255f).ToString("0.000000")} {(color.B / 255f).ToString("0.000000")}"); sb.AppendLine("Ks 1.000 1.000 1.000"); sb.AppendLine("Ns 10.000"); sb.AppendLine(""); alreadyGenerated.Add(matId); } } return(sb.ToString()); }
private static void ProcessRenderChunks(BspTag bsp, BspTagData tagData) { tagData.RenderModels = new BspTagData.RenderModel[bsp.RenderChunks.Length]; for (var c = 0; c < bsp.RenderChunks.Length; c++) { var chunk = bsp.RenderChunks[c]; if (chunk.Resources.Length < 9) { // TODO investigate when differing amount of resources // Skip if we don't have the right data setup var skipModel = new BspTagData.RenderModel(); skipModel.Meshes = new List <Mesh>(); tagData.RenderModels[c] = skipModel; continue; } var verts = ProcessVerticies(chunk); var partResource = chunk.Resources[0]; var partData = partResource.Data.Span; var partCount = partData.Length / 72; // Process face data var faceResource = chunk.Resources[2]; var faceData = faceResource.Data.Span; var meshes = new List <Mesh>(partCount); for (var i = 0; i < partCount; i++) { var start = i * 72; var matId = partData.ReadUInt16At(start + 4); var indexStart = partData.ReadUInt16At(start + 6); var indexCount = partData.ReadUInt16At(start + 8); var elementType = (MeshElementType)partData.ReadUInt16At(start + 2); var mesh = new Mesh(); mesh.Verticies = verts; mesh.Indicies = new int[indexCount]; mesh.MaterialIdentifier = bsp.ModelShaderReferences[matId].ShaderId; mesh.ElementType = elementType; for (var j = 0; j < indexCount; j++) { var byteStart = (indexStart + j) * 2; mesh.Indicies[j] = faceData.ReadUInt16At(byteStart); } meshes.Add(mesh); } var model = new BspTagData.RenderModel(); model.Meshes = meshes; tagData.RenderModels[c] = model; } }
public BspTagData ProcessCollisionGeometry(BspTag bsp, BspTagData tagData) { var block = bsp.CollisionInfos.First(); var faces = new List <int[]>(); for (var i = 0; i < block.Faces.Length; i++) { var face = block.Faces[i]; var faceVerts = new List <int>(8); var currentEdge = block.HalfEdges[face.FirstEdge]; while (true) { int fromVert; int toVert; int nextEdge; if (currentEdge.Face0 == i) { fromVert = currentEdge.Vertex0; toVert = currentEdge.Vertex1; nextEdge = currentEdge.NextEdge; } else { fromVert = currentEdge.Vertex1; toVert = currentEdge.Vertex0; nextEdge = currentEdge.PrevEdge; } if (faceVerts.Count == 0) { faceVerts.Add(fromVert); } if (faceVerts[0] == toVert) { break; } faceVerts.Add(toVert); currentEdge = block.HalfEdges[nextEdge]; } faces.Add(faceVerts.ToArray()); } //tagData.Faces = faces.ToArray(); //tagData.Verticies = block.Verticies // .Select(r => new Vector3(r.x, r.y, r.z)) // .Select(v => new Vertex() { Position = v }) // .ToArray(); return(tagData); }
public static string CreatObjFileForBsp(BspTag tag) { var sb = new StringBuilder(); var vertsWritten = 1; for (var i = 0; i < tag.RenderChunks.Length; i++) { var model = tag.RenderChunks[i].Model; sb.AppendLine($"o BspChunk.{i}"); var verts = model.Meshes.First().Verticies; foreach (var vert in verts) { sb.AppendLine($"v {vert.Position.X.ToString("0.000000")} {vert.Position.Y.ToString("0.000000")} {vert.Position.Z.ToString("0.000000")}"); } foreach (var vert in verts) { sb.AppendLine($"vt {vert.TexCoords.X.ToString("0.000000")} {vert.TexCoords.Y.ToString("0.000000")}"); } foreach (var vert in verts) { sb.AppendLine($"vn {vert.Normal.X.ToString("0.000000")} {vert.Normal.Y.ToString("0.000000")} {vert.Normal.Z.ToString("0.000000")}"); } foreach (var mesh in model.Meshes) { var matId = mesh.Shader.Id + 1; sb.AppendLine($"g BspChunk.{i}.{matId}"); sb.AppendLine($"usemtl {matId}"); for (var j = 0; j < mesh.Indices.Length; j += 3) { var indicies = (mesh.Indices[j], mesh.Indices[j + 1], mesh.Indices[j + 2]); sb.Append("f"); sb.Append($" {indicies.Item1 + vertsWritten}/{indicies.Item1 + vertsWritten}/{indicies.Item1 + vertsWritten}"); sb.Append($" {indicies.Item2 + vertsWritten}/{indicies.Item2 + vertsWritten}/{indicies.Item2 + vertsWritten}"); sb.Append($" {indicies.Item3 + vertsWritten}/{indicies.Item3 + vertsWritten}/{indicies.Item3 + vertsWritten}"); sb.AppendLine(""); } } sb.AppendLine(); vertsWritten += verts.Length; } return(sb.ToString()); }
public static string CreatePlanesObj(BspTag tag) { var sb = new StringBuilder(); var vertsAdded = 0; Console.WriteLine($"CollisionInfo lengths: {tag.CollisionInfos.Length}"); sb.AppendLine("o CollisionPlanes"); foreach (var col in tag.CollisionInfos) { foreach (var plane in col.Planes) { var centroid = plane.Normal * plane.Distance; // Use arbitrary vector to get tangent vector to normal var tempVec = Vector3.Normalize(new Vector3(plane.Normal.X + 1, plane.Normal.Y, plane.Normal.Z)); var tangent = Vector3.Normalize(Vector3.Cross(plane.Normal, tempVec)); var bitangent = Vector3.Cross(plane.Normal, tangent); var upperRight = centroid + tangent + bitangent; var lowerRight = centroid - tangent + bitangent; var upperLeft = centroid + tangent - bitangent; var lowerLeft = centroid - tangent - bitangent; sb.AppendLine($"v {upperRight.X.ToString("0.000000")} {upperRight.Y.ToString("0.000000")} {upperRight.Z.ToString("0.000000")}"); sb.AppendLine($"v {lowerRight.X.ToString("0.000000")} {lowerRight.Y.ToString("0.000000")} {lowerRight.Z.ToString("0.000000")}"); sb.AppendLine($"v {lowerLeft.X.ToString("0.000000")} {lowerLeft.Y.ToString("0.000000")} {lowerLeft.Z.ToString("0.000000")}"); sb.AppendLine($"v {upperLeft.X.ToString("0.000000")} {upperLeft.Y.ToString("0.000000")} {upperLeft.Z.ToString("0.000000")}"); sb.AppendLine($"f {++vertsAdded} {++vertsAdded} {++vertsAdded} {++vertsAdded}"); } } return(sb.ToString()); }
public Entity FromInstancedGeometry(BspTag bsp, BspTag.InstancedGeometryInstance instance) { return(SceneryFactory.FromInstancedGeometry(this.Map, bsp, instance)); }
public Entity FromBsp(BspTag bsp) { return(TerrainFactory.FromBspData(this.Map, bsp)); }
public BspTagData(BspTag tag) : base(tag) { }
public static Scenery FromInstancedGeometry(H2vMap map, BspTag bsp, BspTag.InstancedGeometryInstance instance) { var scenery = new Scenery(); scenery.FriendlyName = "Geom"; if (instance.Index >= bsp.InstancedGeometryDefinitions.Length) { return(scenery); } var def = bsp.InstancedGeometryDefinitions[instance.Index]; var transparentMeshes = new List <Mesh <BitmapTag> >(def.Model.Meshes.Length); var renderModelMeshes = new List <Mesh <BitmapTag> >(def.Model.Meshes.Length); foreach (var mesh in def.Model.Meshes) { var mat = map.CreateMaterial(mesh); var renderMesh = new Mesh <BitmapTag>() { Compressed = mesh.Compressed, ElementType = mesh.ElementType, Indicies = mesh.Indices, Note = mesh.Note, RawData = mesh.RawData, Verticies = mesh.Verticies, Material = mat }; if (mat.AlphaMap == null) { renderModelMeshes.Add(renderMesh); } else { transparentMeshes.Add(renderMesh); } } var comps = new List <Component>(); comps.Add(new RenderModelComponent(scenery, new Model <BitmapTag> { Note = $"[{bsp.Id}] {bsp.Name}//instanced//{instance.Index}", Meshes = renderModelMeshes.ToArray(), Flags = ModelFlags.Diffuse | ModelFlags.ReceivesShadows | ModelFlags.IsStatic })); foreach (var mesh in transparentMeshes) { comps.Add(new RenderModelComponent(scenery, new Model <BitmapTag> { Note = $"[{bsp.Id}] {bsp.Name}//instanced//{instance.Index}", Meshes = new[] { mesh }, Flags = ModelFlags.IsTransparent | ModelFlags.IsStatic })); } var xform = new TransformComponent(scenery, instance.Position, QuaternionExtensions.From3x3Mat(instance.RotationMatrix)) { Scale = new Vector3(instance.Scale), }; comps.Add(xform); if (def.Vertices.Length > 0) { var geom = PhysicsComponentFactory.CreateStaticGeometry(scenery, xform, def, bsp.Shaders); comps.Add(geom); comps.Add(new RenderModelComponent(scenery, new Model <BitmapTag> { Note = $"[{bsp.Id}] {bsp.Name}//instanced//{instance.Index}-collision", Meshes = MeshFactory.GetRenderModel(geom.Collider, new Vector4(0f, 1f, 1f, 1f)), Flags = ModelFlags.Wireframe | ModelFlags.IsStatic, RenderLayer = RenderLayers.Collision })); } xform.UpdateDerivedData(); scenery.SetComponents(comps); return(scenery); }
public static Terrain FromBspData(H2vMap map, BspTag tag) { var terrain = new Terrain(); terrain.FriendlyName = tag.Name; var meshes = new List <ModelMesh>(); foreach (var chunk in tag.RenderChunks) { meshes.AddRange(chunk.Model.Meshes); } var transparentMeshes = new List <Mesh <BitmapTag> >(meshes.Count); var renderModelMeshes = new List <Mesh <BitmapTag> >(meshes.Count); foreach (var mesh in meshes) { var mat = map.CreateMaterial(mesh); var renderMesh = new Mesh <BitmapTag>() { Compressed = mesh.Compressed, ElementType = mesh.ElementType, Indicies = mesh.Indices, Note = mesh.Note, RawData = mesh.RawData, Verticies = mesh.Verticies, Material = mat }; if (mat.AlphaMap == null) { renderModelMeshes.Add(renderMesh); } else { transparentMeshes.Add(renderMesh); } } var components = new List <Component>(); components.Add(new RenderModelComponent(terrain, new Model <BitmapTag> { Meshes = renderModelMeshes.ToArray(), Flags = ModelFlags.Diffuse | ModelFlags.ReceivesShadows | ModelFlags.IsStatic })); foreach (var mesh in transparentMeshes) { components.Add(new RenderModelComponent(terrain, new Model <BitmapTag> { Meshes = new[] { mesh }, Flags = ModelFlags.IsTransparent | ModelFlags.IsStatic })); } var collisionTerrain = PhysicsComponentFactory.CreateTerrain(terrain, tag.CollisionInfos, tag.Shaders); components.Add(collisionTerrain); components.Add(new RenderModelComponent(terrain, new Model <BitmapTag> { Meshes = MeshFactory.GetRenderModel(collisionTerrain.Collider), Flags = ModelFlags.Wireframe | ModelFlags.IsStatic, RenderLayer = RenderLayers.Collision })); components.Add(new TransformComponent(terrain, Vector3.Zero)); terrain.SetComponents(components); return(terrain); }
public static string CreateCollisionObj(BspTag tag) { var sb = new StringBuilder(); var vertsAdded = 0; Console.WriteLine($"CollisionInfo lengths: {tag.CollisionInfos.Length}"); sb.AppendLine("o CollisionMesh"); foreach (var col in tag.CollisionInfos) { var nextFaceSlot = 0; var faceTexLookup = new Dictionary <int, int>(); foreach (var face in col.Faces) { if (faceTexLookup.ContainsKey(face.ShaderIndex)) { continue; } faceTexLookup.Add(face.ShaderIndex, nextFaceSlot + 1); nextFaceSlot++; } for (var i = 0; i < nextFaceSlot; i++) { sb.AppendLine($"vt 0.5 {(i / (float)nextFaceSlot).ToString("0.000000")}"); } var faceIndex = 0; for (; faceIndex < col.Faces.Length; faceIndex++) { var face = col.Faces[faceIndex]; var verts = new List <ushort>(8); ushort edgeIndex = face.FirstEdge; do { var edge = col.HalfEdges[edgeIndex]; verts.Add(edge.Face0 == faceIndex ? edge.Vertex0 : edge.Vertex1); edgeIndex = edge.Face0 == faceIndex ? edge.NextEdge : edge.PrevEdge; } while (edgeIndex != face.FirstEdge); var faceTexCoord = faceTexLookup[face.ShaderIndex]; foreach (var index in verts) { var vert = col.Vertices[index]; sb.AppendLine($"v {vert.x.ToString("0.000000")} {vert.y.ToString("0.000000")} {vert.z.ToString("0.000000")}"); } sb.Append($"f"); foreach (var vert in verts) { sb.Append(" "); sb.Append($"{++vertsAdded}/{faceTexCoord}"); } sb.AppendLine(); } } return(sb.ToString()); }