private void CalculateTwoSidedLowerUV(SectorPlane floor, SectorPlane ceiling, ref Vector2 start, ref Vector2 end) { float lineLength = wall.Line.Segment.Length(); int height = ceiling.Height - floor.Height; Vector2 invDimension = texture.InverseDimension; Vector2 spanUV = new Vector2(lineLength, height) * invDimension; Vector2 offsetUV = wall.Side.Offset.Float() * invDimension; // If it's upper, draw from the top of the ceiling down. if (wall.Line.Unpegged.HasUpper()) { // Remember that this draws from the very top, so we need to // know the sector height that will act as the top. Drawing the // other pieces float maxHeight = wall.Side.Sector.Ceiling.Height; // We need to find the V coordinates from the top to do these // correctly. float topV = (maxHeight - ceiling.Height) * invDimension.y; float bottomV = (maxHeight - floor.Height) * invDimension.y; start = new Vector2(offsetUV.x, topV + offsetUV.y); end = new Vector2(offsetUV.x + spanUV.x, bottomV + offsetUV.y); } else { start = offsetUV; end = offsetUV + spanUV; } }
private static (Vector3[] vertices, Vector2[] uvCoords) CalculateVertices(SectorPlane plane, List <Seg2F> edges, Texture texture) { int vertexCount = edges.Count; Vector3[] vertices = new Vector3[vertexCount]; Vector2[] uvCoords = new Vector2[vertexCount]; for (int i = 0; i < vertexCount; i++) { Vector2 vertex = edges[i].Start.UnityFloat(); vertices[i] = new Vector3(vertex.x, plane.Height, vertex.y).MapUnit(); uvCoords[i] = vertex * texture.InverseDimension; } // If it's a ceiling, we have to reverse the triangle fan to make // the facing side visible. if (plane.IsCeiling) { Array.Reverse(vertices, 0, vertices.Length); Array.Reverse(uvCoords, 0, uvCoords.Length); } return(vertices, uvCoords); }
private void UpdateEnabledStatus(SectorPlane floor, SectorPlane ceiling) { if (wall.IsTwoSidedNoMiddle) { Disable(); isDisabled = true; return; } // We do it this way just in case enabling/disabling ends up being // a non-cheap operation. if (floor.Height <= ceiling.Height) { if (isDisabled) { Enable(); isDisabled = false; } } else { if (!isDisabled) { Disable(); isDisabled = true; } } }
private static Color[] CalculateColors(SectorPlane sectorPlane, int vertexCount) { float lightLevel = sectorPlane.LightLevelNormalized; Color color = new Color(lightLevel, lightLevel, lightLevel, 1.0f); return(Arrays.Create(vertexCount, color)); }
public SubsectorMeshComponents(SubsectorPlane plane, SectorPlane sectorPlane, List <Seg2F> edges, GameObject gameObject) { subsectorPlane = plane; texture = TextureManager.Texture(plane.SectorPlane.TextureName, ResourceNamespace.Flats); Mesh = CreateMesh(sectorPlane, edges, texture); Filter = CreateFilter(gameObject); Renderer = CreateRenderer(gameObject); Collider = CreateCollider(gameObject, edges); }
private void CalculateTwoSidedMiddleUV(SectorPlane floor, SectorPlane ceiling, Vector3[] vertices, ref Vector2 start, ref Vector2 end) { // TODO: Should probably turn this into a data structure to avoid these cryptic references. float height = vertices[2].y - vertices[0].y; float lineLength = wall.Line.Segment.Length(); Vector2 invDimension = texture.InverseDimension; Vector2 spanUV = new Vector2(lineLength, height) * invDimension; Vector2 offsetUV = wall.Side.Offset.Float() * invDimension; // TODO: Draw it to the proper clipped spot. start = new Vector2(offsetUV.x, 0); end = new Vector2(offsetUV.x + spanUV.x, 1); }
public SubsectorPlane(int index, SectorPlane sectorPlane, List <Seg2F> edges) { Debug.Assert(edges.Count >= 3, $"Two or less lines is not a polygon (subsector plane {index})"); string facingText = sectorPlane.IsCeiling ? "Ceiling" : "Floor"; Index = index; SectorPlane = sectorPlane; Edges = edges.ToList(); gameObject = new GameObject($"Subsector {index} (Sector {sectorPlane.Sector.Index} Plane {sectorPlane.Index} {facingText})"); MeshComponents = new SubsectorMeshComponents(this, sectorPlane, edges, gameObject); collisionInfo = CollisionInfo.CreateOn(gameObject, this); sectorPlane.SubsectorPlanes.Add(this); }
private static Mesh CreateMesh(SectorPlane sectorPlane, List <Seg2F> edges, Texture texture) { (Vector3[] vertices, Vector2[] uvCoords) = CalculateVertices(sectorPlane, edges, texture); int[] indices = CalculateIndices(vertices.Length); Vector3[] normals = CalculateNormals(sectorPlane, vertices.Length); Color[] colors = CalculateColors(sectorPlane, vertices.Length); return(new Mesh { vertices = vertices, triangles = indices, normals = normals, uv = uvCoords, colors = colors }); }
private Vector3[] CalculateVertices(SectorPlane floor, SectorPlane ceiling) { float top = ceiling.Height; float bottom = floor.Height; Vec2F start = wall.Line.Segment.Start; Vec2F end = wall.Line.Segment.End; if (wall.OnBackSide) { (start, end) = (end, start); } if (wall.Section == WallSection.Middle && wall.Line.TwoSided) { float imageHeight = texture.Height; float texTop = top; float texBottom = bottom; // Draws from the top down, unless it's lower unpegged. if (wall.Line.Unpegged.HasLower()) { texTop = texBottom + imageHeight; } else { texBottom = texTop - imageHeight; } texTop += wall.Side.Offset.Y; texBottom += wall.Side.Offset.Y; // Now we clip it to the gap that exists. top = Math.Min(top, texTop); bottom = Math.Max(bottom, texBottom); } return(new[] { new Vector3(start.X, bottom, start.Y).MapUnit(), new Vector3(end.X, bottom, end.Y).MapUnit(), new Vector3(start.X, top, start.Y).MapUnit(), new Vector3(end.X, top, end.Y).MapUnit(), }); }
private void CalculateTwoSidedUpperUV(SectorPlane floor, SectorPlane ceiling, ref Vector2 start, ref Vector2 end) { float lineLength = wall.Line.Segment.Length(); int height = ceiling.Height - floor.Height; Vector2 invDimension = texture.InverseDimension; Vector2 spanUV = new Vector2(lineLength, height) * invDimension; Vector2 offsetUV = wall.Side.Offset.Float() * invDimension; // If it's upper, draw it from the top down. if (wall.Line.Unpegged.HasUpper()) { start = offsetUV; end = offsetUV + spanUV; } else { end = new Vector2(spanUV.x + offsetUV.x, 1.0f - offsetUV.y); start = new Vector2(offsetUV.x, end.y - spanUV.y); } }
private Vector2[] CalculateUVCoordinates(SectorPlane floor, SectorPlane ceiling, Vector3[] vertices) { Vector2 start = new Vector2(0, 0); Vector2 end = new Vector2(1, 1); // An important note for all of the following functions: // Remember that the texture was uploaded such that the // 0.0 -> 1.0 coordinates look like: // // (0.0, 0.0) (1.0, 0.0) // S--------o // | Top | S = start // | | E = end // | | // | | // | Bottom | // o--------E // (0.0, 1.0) (1.0, 1.0) // // This means when we are drawing from the bottom up, we want to // start out at the bottom UV and subtract the X/Y span and offsets // to go upwards. Likewise if we are drawing from the top down, we // want to start at the top two coordinates and add the span and // offset to go down. // In short, the coordinate system looks exactly like the image // origin system. switch (wall.Section) { case WallSection.Lower: CalculateTwoSidedLowerUV(floor, ceiling, ref start, ref end); break; case WallSection.Middle: if (wall.Line.OneSided) { CalculateOneSidedMiddleUV(floor, ceiling, ref start, ref end); } else { CalculateTwoSidedMiddleUV(floor, ceiling, vertices, ref start, ref end); } break; case WallSection.Upper: CalculateTwoSidedUpperUV(floor, ceiling, ref start, ref end); break; default: throw new Exception($"Unexpected wall section for UV calculations: {wall.Section}"); } // This follows easily from the comment/ASCII-art above, along with // the vertex locations from the class documentation. return(new[] { new Vector2(start.x, end.y), new Vector2(end.x, end.y), new Vector2(start.x, start.y), new Vector2(end.x, start.y) }); }
private static Vector3[] CalculateNormals(SectorPlane sectorPlane, int vertexCount) { Vector3 normal = sectorPlane.IsCeiling ? Vector3.down : Vector3.up; return(Arrays.Create(vertexCount, normal)); }