internal Displacement(ValveBspFile bsp, DispInfo dispInfo) { _bspFile = bsp; _dispInfo = dispInfo; _corners = new Vector3[8]; _min = IntVector2.Zero; _max = new IntVector2(Subdivisions, Subdivisions); var face = bsp.FacesHdr[_dispInfo.MapFace]; var firstCornerDist2 = float.MaxValue; Normal = bsp.Planes[face.PlaneNum].Normal; for (var i = 0; i < 4; ++i) { var vert = bsp.GetVertexFromSurfEdgeId(face.FirstEdge + i); _corners[i] = vert; var dist2 = (_dispInfo.StartPosition - vert).LengthSquared; if (dist2 < firstCornerDist2) { _firstCorner = i; firstCornerDist2 = dist2; } } }
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 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(); } }