private static double GetSidedefValue(Sidedef target, VisualGeometryType targetparttype, string key, double defaultvalue) { switch (targetparttype) { case VisualGeometryType.WALL_UPPER: return(Math.Round(UniFields.GetFloat(target.Fields, key + "_top", defaultvalue), 3)); case VisualGeometryType.WALL_MIDDLE: return(Math.Round(UniFields.GetFloat(target.Fields, key + "_mid", defaultvalue), 3)); case VisualGeometryType.WALL_LOWER: return(Math.Round(UniFields.GetFloat(target.Fields, key + "_bottom", defaultvalue), 3)); } return(0); }
private static List <WorldVertex[]> OptimizeGeometry(WorldVertex[] verts, VisualGeometryType geotype, bool skiprectoptimization) { List <WorldVertex[]> groups = new List <WorldVertex[]>(); // Only do optimizations for walls right now. Doing them blindly for floors/ceilings will cause problems with concave sectors with 4 corners if (!skiprectoptimization && verts.Length == 6 && (geotype != VisualGeometryType.CEILING && geotype != VisualGeometryType.FLOOR)) //rectangular surface { verts = new[] { verts[5], verts[2], verts[1], verts[0] }; groups.Add(verts); } else { for (int i = 0; i < verts.Length; i += 3) { groups.Add(new[] { verts[i + 2], verts[i + 1], verts[i] }); } } return(groups); }
private void AddProcessedSides(Sidedef s1, VisualGeometryType type1, Sidedef s2, VisualGeometryType type2) { // Add them both ways if (!donesides[type1].ContainsKey(s1.Index)) { donesides[type1].Add(s1.Index, new Dictionary <VisualGeometryType, Dictionary <int, bool> >()); donesides[type1][s1.Index].Add(VisualGeometryType.WALL_UPPER, new Dictionary <int, bool>()); donesides[type1][s1.Index].Add(VisualGeometryType.WALL_MIDDLE, new Dictionary <int, bool>()); donesides[type1][s1.Index].Add(VisualGeometryType.WALL_LOWER, new Dictionary <int, bool>()); } donesides[type1][s1.Index][type2].Add(s2.Index, false); if (!donesides[type2].ContainsKey(s2.Index)) { donesides[type2].Add(s2.Index, new Dictionary <VisualGeometryType, Dictionary <int, bool> >()); donesides[type2][s2.Index].Add(VisualGeometryType.WALL_UPPER, new Dictionary <int, bool>()); donesides[type2][s2.Index].Add(VisualGeometryType.WALL_MIDDLE, new Dictionary <int, bool>()); donesides[type2][s2.Index].Add(VisualGeometryType.WALL_LOWER, new Dictionary <int, bool>()); } donesides[type2][s2.Index][type1].Add(s1.Index, false); }
public static Rectangle GetSidedefPartSize(Sidedef side, VisualGeometryType type) { Rectangle rect = new Rectangle(0, 0, Math.Max(1, (int)Math.Round(side.Line.Length)), 0); switch (type) { case VisualGeometryType.WALL_LOWER: if (side.LowRequired()) { rect.Y = -side.Other.Sector.FloorHeight; rect.Height = side.GetLowHeight(); } break; case VisualGeometryType.WALL_UPPER: if (side.HighRequired()) { rect.Y = -side.Sector.CeilHeight; rect.Height = side.GetHighHeight(); } break; case VisualGeometryType.WALL_MIDDLE: if (side.MiddleRequired()) { rect.Y = -side.Sector.CeilHeight; } else if (side.Other.Sector != null) // Double-sided { rect.Y = -Math.Min(side.Sector.CeilHeight, side.Other.Sector.CeilHeight); } rect.Height = side.GetMiddleHeight(); break; default: throw new NotImplementedException("GetSidedefPartSize: got unsupported geometry type: \"" + type + "\""); } return(rect); }
/// <summary> /// This creates visual geometry that is bound to a sidedef. This geometry is only visible when the sidedef is visible. It is automatically back-face culled during rendering and automatically XY intersection tested as well as back-face culled during object picking. /// </summary> protected VisualGeometry(VisualSector vs, Sidedef sd) { this.sector = vs; this.sidedef = sd; this.geometrytype = VisualGeometryType.UNKNOWN; //mxd }
/// <summary> /// This creates sector-global visual geometry. This geometry is always visible when any of the sector is visible. /// </summary> protected VisualGeometry(VisualSector vs) { this.sector = vs; this.geometrytype = VisualGeometryType.UNKNOWN; //mxd }
private static int GetExpectedOffsetY(Sidedef source, Sidedef target, string texturename, int textureheight, double texturescaley, double linescaley, Rectangle partsize, out VisualGeometryType matchingparttype) { if (target.MiddleTexture == texturename && partsize.IntersectsWith(BuilderModesTools.GetSidedefPartSize(target, VisualGeometryType.WALL_MIDDLE))) { matchingparttype = VisualGeometryType.WALL_MIDDLE; int partheight = (int)Math.Round(((target.Sector.CeilHeight - source.Sector.CeilHeight) / texturescaley) * linescaley); return(((int)Tools.GetSidedefMiddleOffsetY(target, target.OffsetY + GetSidedefValue(target, matchingparttype, "offsety", 0f), linescaley, false) + partheight) % textureheight); } // Only check upper and lower textures if the sidedef as an other side. See https://github.com/jewalky/UltimateDoomBuilder/issues/533 if (target.Other != null && target.HighTexture == texturename && partsize.IntersectsWith(BuilderModesTools.GetSidedefPartSize(target, VisualGeometryType.WALL_UPPER))) { matchingparttype = VisualGeometryType.WALL_UPPER; int partheight = (int)Math.Round(((target.Sector.CeilHeight - source.Sector.CeilHeight) / texturescaley) * linescaley); return(((int)Tools.GetSidedefTopOffsetY(target, target.OffsetY + GetSidedefValue(target, matchingparttype, "offsety", 0f), linescaley, false) + partheight) % textureheight); } if (target.Other != null && target.LowTexture == texturename && partsize.IntersectsWith(BuilderModesTools.GetSidedefPartSize(target, VisualGeometryType.WALL_LOWER))) { matchingparttype = VisualGeometryType.WALL_LOWER; int partheight = (int)Math.Round(((target.Sector.CeilHeight - source.Sector.CeilHeight) / texturescaley) * linescaley); return(((int)Tools.GetSidedefBottomOffsetY(target, target.OffsetY + GetSidedefValue(target, matchingparttype, "offsety", 0f), linescaley, false) + partheight) % textureheight); } matchingparttype = VisualGeometryType.UNKNOWN; return(int.MinValue); }
private void CheckAlignment(Sidedef sidedef, int offsetx, int offsety, double linescalex, double linescaley, VisualGeometryType parttype, string texturename) { ImageData texture = General.Map.Data.GetTextureImage(texturename); if (!texture.IsImageLoaded) { return; } Rectangle partsize = BuilderModesTools.GetSidedefPartSize(sidedef, parttype); double scalex = ((General.Map.Config.ScaledTextureOffsets && !texture.WorldPanning) ? texture.Scale.x : 1.0f); double scaley = ((General.Map.Config.ScaledTextureOffsets && !texture.WorldPanning) ? texture.Scale.y : 1.0f); // Move offsets to proper range offsetx %= texture.Width; if (offsetx < 0) { offsetx += texture.Width; } offsety %= texture.Height; if (offsety < 0) { offsety += texture.Height; } // Check if current line is aligned to other sides ICollection <Linedef> lines = (sidedef.IsFront ? sidedef.Line.Start.Linedefs : sidedef.Line.End.Linedefs); Vertex v = sidedef.IsFront ? sidedef.Line.Start : sidedef.Line.End; foreach (Linedef line in lines) { if (line.Index == sidedef.Line.Index) { continue; } Sidedef target = null; if (line.Front != null && line.End == v) { target = line.Front; } else if (line.Back != null && line.Start == v) { target = line.Back; } // No target? if (target == null) { continue; } // Get expected texture offsets VisualGeometryType targetparttype; int alignedY = GetExpectedOffsetY(sidedef, target, texturename, texture.Height, scaley, linescaley, partsize, out targetparttype); if (targetparttype == VisualGeometryType.UNKNOWN) { continue; } // Already added? if (donesides[parttype].ContainsKey(sidedef.Index) && donesides[parttype][sidedef.Index][targetparttype].ContainsKey(target.Index)) { continue; } // Not aligned if scaley is not equal double targetscaley = GetSidedefValue(target, targetparttype, "scaley", 1.0); if (targetscaley != linescaley) { SubmitResult(new ResultTexturesMisaligned(sidedef, target, texturename)); } double targetscalex = GetSidedefValue(target, targetparttype, "scalex", 1.0); alignedY %= texture.Height; if (alignedY < 0) { alignedY += texture.Height; } int alignedX = (target.OffsetX + (int)GetSidedefValue(target, targetparttype, "offsetx", 0f) + (int)Math.Round(target.Line.Length / scalex * targetscalex)) % texture.Width; if (alignedX < 0) { alignedX += texture.Width; } // Submit result if target offsets don't match expected ones if (offsetx != alignedX || offsety != alignedY) { SubmitResult(new ResultTexturesMisaligned(sidedef, target, texturename)); } // Add to collection AddProcessedSides(sidedef, parttype, target, targetparttype); } // Check if other sides are aligned to current side lines = (sidedef.IsFront ? sidedef.Line.End.Linedefs : sidedef.Line.Start.Linedefs); v = (sidedef.IsFront ? sidedef.Line.End : sidedef.Line.Start); foreach (Linedef line in lines) { if (line.Index == sidedef.Line.Index) { continue; } Sidedef target = null; if (line.Front != null && line.Start == v) { target = line.Front; } else if (line.Back != null && line.End == v) { target = line.Back; } // No target or laready processed? if (target == null) { continue; } // Get expected texture offsets VisualGeometryType targetparttype; int alignedY = GetExpectedOffsetY(sidedef, target, texturename, texture.Height, scaley, linescaley, partsize, out targetparttype); if (targetparttype == VisualGeometryType.UNKNOWN) { continue; } // Already added? if (donesides[parttype].ContainsKey(sidedef.Index) && donesides[parttype][sidedef.Index][targetparttype].ContainsKey(target.Index)) { continue; } // Not aligned if scaley is not equal double targetscaley = GetSidedefValue(target, targetparttype, "scaley", 1.0); if (targetscaley != linescaley) { SubmitResult(new ResultTexturesMisaligned(sidedef, target, texturename)); } alignedY %= texture.Height; if (alignedY < 0) { alignedY += texture.Height; } int alignedX = (target.OffsetX + (int)GetSidedefValue(target, targetparttype, "offsetx", 0.0) - (int)Math.Round(sidedef.Line.Length / scalex * linescalex)) % texture.Width; if (alignedX < 0) { alignedX += texture.Width; } // Submit result if target offsets don't match expected ones if (offsetx != alignedX || offsety != alignedY) { SubmitResult(new ResultTexturesMisaligned(sidedef, target, texturename)); } // Add to collection AddProcessedSides(sidedef, parttype, target, targetparttype); } }
private static int GetExpectedOffsetY(Sidedef source, Sidedef target, string texturename, int textureheight, double texturescaley, double linescaley, Rectangle partsize, out VisualGeometryType matchingparttype) { if (target.MiddleTexture == texturename && partsize.IntersectsWith(BuilderModesTools.GetSidedefPartSize(target, VisualGeometryType.WALL_MIDDLE))) { matchingparttype = VisualGeometryType.WALL_MIDDLE; int partheight = (int)Math.Round(((target.Sector.CeilHeight - source.Sector.CeilHeight) / texturescaley) * linescaley); return(((int)Tools.GetSidedefMiddleOffsetY(target, target.OffsetY + GetSidedefValue(target, matchingparttype, "offsety", 0f), linescaley, false) + partheight) % textureheight); } if (target.HighTexture == texturename && partsize.IntersectsWith(BuilderModesTools.GetSidedefPartSize(target, VisualGeometryType.WALL_UPPER))) { matchingparttype = VisualGeometryType.WALL_UPPER; int partheight = (int)Math.Round(((target.Sector.CeilHeight - source.Sector.CeilHeight) / texturescaley) * linescaley); return(((int)Tools.GetSidedefTopOffsetY(target, target.OffsetY + GetSidedefValue(target, matchingparttype, "offsety", 0f), linescaley, false) + partheight) % textureheight); } if (target.LowTexture == texturename && partsize.IntersectsWith(BuilderModesTools.GetSidedefPartSize(target, VisualGeometryType.WALL_LOWER))) { matchingparttype = VisualGeometryType.WALL_LOWER; int partheight = (int)Math.Round(((target.Sector.CeilHeight - source.Sector.CeilHeight) / texturescaley) * linescaley); return(((int)Tools.GetSidedefBottomOffsetY(target, target.OffsetY + GetSidedefValue(target, matchingparttype, "offsety", 0f), linescaley, false) + partheight) % textureheight); } matchingparttype = VisualGeometryType.UNKNOWN; return(int.MinValue); }
private static List <WorldVertex[]> OptimizeGeometry(WorldVertex[] verts, VisualGeometryType geotype) { return(OptimizeGeometry(verts, geotype, false)); }