private static void SerializeFace(ValveBspFile bsp, int index, VertexArray verts) { const SurfFlags ignoreFlags = SurfFlags.NODRAW | SurfFlags.LIGHT; const SurfFlags skyFlags = SurfFlags.SKY2D | SurfFlags.SKY; var face = bsp.FacesHdr[index]; var texInfo = bsp.TextureInfos[face.TexInfo]; var plane = bsp.Planes[face.PlaneNum]; if ((texInfo.Flags & ignoreFlags) != 0 || texInfo.TexData < 0) { return; } var isSky = (texInfo.Flags & skyFlags) != 0; if (face.DispInfo != -1) { SerializeDisplacement(bsp, index, ref face, ref plane, verts); return; } var texData = bsp.TextureData[texInfo.TexData]; var texScale = new Vector2(1f / texData.Width, 1f / texData.Height); verts.BeginPrimitive(); for (int i = face.FirstEdge, iEnd = face.FirstEdge + face.NumEdges; i < iEnd; ++i) { var vert = bsp.GetVertexFromSurfEdgeId(i); var uv = GetUv(vert, texInfo.TextureUAxis, texInfo.TextureVAxis) * texScale; var uv2 = GetLightmapUv(bsp, vert, index, ref face, ref texInfo); verts.AddVertex(vert, texCoord: uv, lightmapCoord: uv2); } var numPrimitives = face.NumPrimitives & 0x7fff; var texStringIndex = isSky ? -1 : texData.NameStringTableId; if (numPrimitives == 0) { verts.CommitPrimitive(PrimitiveType.TriangleFan, texStringIndex); return; } if (_sIndicesBuffer == null) { _sIndicesBuffer = new List <int>(); } for (int i = face.FirstPrimitive, iEnd = face.FirstPrimitive + numPrimitives; i < iEnd; ++i) { var primitive = bsp.Primitives[i]; for (int j = primitive.FirstIndex, jEnd = primitive.FirstIndex + primitive.IndexCount; j < jEnd; ++j) { _sIndicesBuffer.Add(bsp.PrimitiveIndices[j]); } verts.CommitPrimitive(primitive.Type, texStringIndex, _sIndicesBuffer); _sIndicesBuffer.Clear(); } }
private void WriteFace(ValveBspFile bsp, int faceIndex, GeometryPage page, List <Face> outFaces) { const SurfFlags ignoreFlags = SurfFlags.NODRAW | SurfFlags.LIGHT | SurfFlags.SKY | SurfFlags.SKY2D; var faceInfo = bsp.Faces[faceIndex]; var texInfo = bsp.TextureInfos[faceInfo.TexInfo]; if ((texInfo.Flags & ignoreFlags) != 0 || texInfo.TexData < 0) { return; } var texData = bsp.TextureData[texInfo.TexData]; var matPath = bsp.GetTextureString(texData.NameStringTableId); var meshData = GetOrCreateMeshData(bsp, page, matPath); if (Skip) { return; } MeshElement elem; Face face; var leafFaceIndex = outFaces.FindIndex(x => x.Material == meshData.MaterialIndex); if (leafFaceIndex != -1) { face = outFaces[leafFaceIndex]; elem = meshData.Elements[face.Element]; } else { elem = new MeshElement { Mode = PrimitiveType.Triangles, Material = 0, IndexOffset = meshData.Indices.Count }; face = new Face { Material = meshData.MaterialIndex, Element = meshData.Elements.Count }; outFaces.Add(face); meshData.Elements.Add(elem); } var texScale = new Vector2(1f / Math.Max(texData.Width, 1), 1f / Math.Max(texData.Height, 1)); Vector2 lmMin, lmSize; bsp.LightmapLayout.GetUvs(faceIndex, out lmMin, out lmSize); if (faceInfo.DispInfo != -1) { var disp = bsp.DisplacementManager[faceInfo.DispInfo]; SourceUtils.Vector3 c0, c1, c2, c3; disp.GetCorners(out c0, out c1, out c2, out c3); var uv00 = GetUv(c0, texInfo.TextureUAxis, texInfo.TextureVAxis) * texScale; var uv10 = GetUv(c3, texInfo.TextureUAxis, texInfo.TextureVAxis) * texScale; var uv01 = GetUv(c1, texInfo.TextureUAxis, texInfo.TextureVAxis) * texScale; var uv11 = GetUv(c2, texInfo.TextureUAxis, texInfo.TextureVAxis) * texScale; var subDivMul = 1f / disp.Subdivisions; for (var y = 0; y < disp.Subdivisions; ++y) { meshData.BeginPrimitive(); var v0 = (y + 0) * subDivMul; var v1 = (y + 1) * subDivMul; for (var x = 0; x < disp.Size; ++x) { var u = x * subDivMul; meshData.VertexAttribute(VertexAttribute.Position, disp.GetPosition(x, y + 0)); meshData.VertexAttribute(VertexAttribute.Normal, disp.GetNormal(x, y + 0)); meshData.VertexAttribute(VertexAttribute.Uv, (uv00 * (1f - u) + uv10 * u) * (1f - v0) + (uv01 * (1f - u) + uv11 * u) * v0); meshData.VertexAttribute(VertexAttribute.Uv2, new Vector2(u, v0) * lmSize + lmMin); meshData.VertexAttribute(VertexAttribute.Alpha, disp.GetAlpha(x, y + 0)); meshData.CommitVertex(); meshData.VertexAttribute(VertexAttribute.Position, disp.GetPosition(x, y + 1)); meshData.VertexAttribute(VertexAttribute.Normal, disp.GetNormal(x, y + 1)); meshData.VertexAttribute(VertexAttribute.Uv, (uv00 * (1f - u) + uv10 * u) * (1f - v1) + (uv01 * (1f - u) + uv11 * u) * v1); meshData.VertexAttribute(VertexAttribute.Uv2, new Vector2(u, v1) * lmSize + lmMin); meshData.VertexAttribute(VertexAttribute.Alpha, disp.GetAlpha(x, y + 1)); meshData.CommitVertex(); } meshData.CommitPrimitive(PrimitiveType.TriangleStrip); } } else { meshData.BeginPrimitive(); var plane = bsp.Planes[faceInfo.PlaneNum]; for (int k = faceInfo.FirstEdge, kEnd = faceInfo.FirstEdge + faceInfo.NumEdges; k < kEnd; ++k) { var vert = bsp.GetVertexFromSurfEdgeId(k); var uv = GetUv(vert, texInfo.TextureUAxis, texInfo.TextureVAxis); var uv2 = GetUv(vert, texInfo.LightmapUAxis, texInfo.LightmapVAxis); uv2.X -= faceInfo.LightMapOffsetX; uv2.Y -= faceInfo.LightMapOffsetY; uv2.X /= Math.Max(faceInfo.LightMapSizeX, 1); uv2.Y /= Math.Max(faceInfo.LightMapSizeY, 1); uv2 *= lmSize; uv2 += lmMin; meshData.VertexAttribute(VertexAttribute.Position, vert); meshData.VertexAttribute(VertexAttribute.Normal, plane.Normal); meshData.VertexAttribute(VertexAttribute.Uv, uv * texScale); meshData.VertexAttribute(VertexAttribute.Uv2, uv2); meshData.CommitVertex(); } var numPrimitives = faceInfo.NumPrimitives & 0x7fff; if (numPrimitives == 0) { meshData.CommitPrimitive(PrimitiveType.TriangleFan); } else { if (_sIndexBuffer == null) { _sIndexBuffer = new List <int>(); } else { _sIndexBuffer.Clear(); } var indices = _sIndexBuffer; for (int k = faceInfo.FirstPrimitive, kEnd = faceInfo.FirstPrimitive + numPrimitives; k < kEnd; ++k) { var primitive = bsp.Primitives[k]; for (int l = primitive.FirstIndex, lEnd = primitive.FirstIndex + primitive.IndexCount; l < lEnd; ++l) { indices.Add(bsp.PrimitiveIndices[l]); } PrimitiveType mode; switch (primitive.Type) { case ValveBsp.PrimitiveType.TriangleStrip: mode = PrimitiveType.TriangleStrip; break; case ValveBsp.PrimitiveType.TriangleFan: mode = PrimitiveType.TriangleFan; break; case ValveBsp.PrimitiveType.TriangleList: mode = PrimitiveType.Triangles; break; default: throw new NotImplementedException(); } meshData.CommitPrimitive(mode, indices); indices.Clear(); } } } elem.IndexCount = meshData.Indices.Count - elem.IndexOffset; }
private MeshGroup GenerateMesh(MeshBuilder meshGen, IEnumerable <int> faceIndices) { var mesh = new Mesh(); var primitiveIndices = new List <int>(); const SurfFlags ignoreFlags = SurfFlags.NODRAW | SurfFlags.SKIP | SurfFlags.SKY | SurfFlags.SKY2D | SurfFlags.HINT | SurfFlags.TRIGGER; var corners = new Vector3[4]; var lightmap = GetLightmap(); using (Profiler.Begin("GenerateMesh")) { foreach (var faceIndex in faceIndices) { var face = FacesHdr[faceIndex]; var plane = Planes[face.PlaneNum]; var tex = TexInfos[face.TexInfo]; if ((tex.Flags & ignoreFlags) != 0 || tex.TexData < 0) { continue; } var texData = TexData[tex.TexData]; var uvScale = new Vector2(1f / texData.Width, 1f / texData.Height); var matName = GetTexdataString(texData.NameStringTableId) + ".vmt"; var mat = World.Resources.LoadVmt(matName).GetMaterial(World.Resources); mat.SetTexture("_LightMap", lightmap); Rect lightmapRect; if (!_lightmapRects.TryGetValue(faceIndex, out lightmapRect)) { lightmapRect = new Rect(0f, 0f, 1f, 1f); } if (face.DispInfo != -1) { Debug.Assert(face.NumEdges == 4); var disp = DispInfos[face.DispInfo]; var size = 1 << disp.Power; var firstCorner = 0; var firstCornerDist2 = float.MaxValue; for (var surfId = face.FirstEdge; surfId < face.FirstEdge + face.NumEdges; ++surfId) { var surfEdge = SurfEdges[surfId]; var edgeIndex = Math.Abs(surfEdge); var edge = Edges[edgeIndex]; var vert = Vertices[surfEdge >= 0 ? edge.A : edge.B]; corners[surfId - face.FirstEdge] = vert; var dist2 = ((Vector3)disp.StartPosition - vert).sqrMagnitude; if (dist2 < firstCornerDist2) { firstCorner = surfId - face.FirstEdge; firstCornerDist2 = dist2; } } for (var x = 0; x < size; ++x) { for (var y = 0; y < size; ++y) { var a = GetDisplacementVertex(disp.DispVertStart, x, y, size, corners, firstCorner); var b = GetDisplacementVertex(disp.DispVertStart, x, y + 1, size, corners, firstCorner); var c = GetDisplacementVertex(disp.DispVertStart, x + 1, y + 1, size, corners, firstCorner); var d = GetDisplacementVertex(disp.DispVertStart, x + 1, y, size, corners, firstCorner); meshGen.StartFace(mat); meshGen.AddVertex(a * SourceToUnityUnits, plane.Normal, Vector2.zero, GetLightmapUv(x, y, size, face, lightmapRect)); meshGen.AddVertex(b * SourceToUnityUnits, plane.Normal, Vector2.zero, GetLightmapUv(x, y + 1, size, face, lightmapRect)); meshGen.AddVertex(c * SourceToUnityUnits, plane.Normal, Vector2.zero, GetLightmapUv(x + 1, y + 1, size, face, lightmapRect)); meshGen.AddVertex(d * SourceToUnityUnits, plane.Normal, Vector2.zero, GetLightmapUv(x + 1, y, size, face, lightmapRect)); meshGen.AddPrimitive(PrimitiveType.TriangleStrip); meshGen.EndFace(); } } continue; } meshGen.StartFace(mat); for (var surfId = face.FirstEdge; surfId < face.FirstEdge + face.NumEdges; ++surfId) { var surfEdge = SurfEdges[surfId]; var edgeIndex = Math.Abs(surfEdge); var edge = Edges[edgeIndex]; var vert = Vertices[surfEdge >= 0 ? edge.A : edge.B]; var textureUv = Vector2.Scale(GetUv(vert, tex.TextureUAxis, tex.TextureVAxis), uvScale); var lightmapUv = GetLightmapUv(vert, face, tex, lightmapRect); meshGen.AddVertex((Vector3)vert * SourceToUnityUnits, plane.Normal, textureUv, lightmapUv); } if (face.NumPrimitives == 0 || face.NumPrimitives >= 0x8000) { meshGen.AddPrimitive(PrimitiveType.TriangleStrip); meshGen.EndFace(); continue; } for (var primId = face.FirstPrimitive; primId < face.FirstPrimitive + face.NumPrimitives; ++primId) { var primitive = Primitives[primId]; for (var indexId = primitive.FirstIndex; indexId < primitive.FirstIndex + primitive.IndexCount; ++indexId) { primitiveIndices.Add(PrimitiveIndices[indexId]); } meshGen.AddPrimitive(primitive.Type, primitiveIndices); primitiveIndices.Clear(); } meshGen.EndFace(); } } meshGen.CopyToMesh(mesh); return(new MeshGroup(mesh, meshGen.GetMaterials())); }