using System; using System.Collections.Generic; using Oni.Imaging; namespace Oni.Akira { internal class MaterialLibrary { private readonly MarkerMaterials markers = new MarkerMaterials(); private readonly Dictionary materials = new Dictionary(StringComparer.OrdinalIgnoreCase); private Material notFound; #region internal class MarkerMaterials internal class MarkerMaterials { private Material ghost; private Material stairs; private Material door; private Material danger; private Material barrier; private Material impassable; private Material blackness; private Material floor; public Material GetMarker(string name) { EnsureMaterials(); switch (name) { case "_marker_door": return door; case "_marker_ghost": return ghost; case "_marker_stairs": return stairs; case "_marker_danger": return danger; case "_marker_barrier": return barrier; case "_marker_impassable": return impassable; case "_marker_blackness": return blackness; case "_marker_floor": return floor; default: return null; } } public Material GetMarker(Polygon polygon) { EnsureMaterials(); var flags = polygon.Flags & ~(GunkFlags.ProjectionBit0 | GunkFlags.ProjectionBit1 | GunkFlags.Horizontal | GunkFlags.Vertical); var adjacencyFlags = GunkFlags.Ghost | GunkFlags.StairsUp | GunkFlags.StairsDown; if ((flags & (GunkFlags.DoorFrame | adjacencyFlags)) == GunkFlags.DoorFrame) return door; if ((flags & adjacencyFlags) != 0) return ghost; if ((flags & GunkFlags.Invisible) != 0) { flags &= ~GunkFlags.Invisible; if ((flags & GunkFlags.Danger) != 0) return danger; if ((flags & GunkFlags.Stairs) != 0) return stairs; if ((flags & (GunkFlags.NoObjectCollision | GunkFlags.NoCharacterCollision)) == GunkFlags.NoObjectCollision) return barrier; if ((flags & (GunkFlags.NoObjectCollision | GunkFlags.NoCharacterCollision | GunkFlags.NoCollision)) == 0) return impassable; // // What's the point of a invisible and no collision polygon?! // if ((flags & GunkFlags.NoCollision) != 0) return null; Console.Error.WriteLine("Unknown invisible material, fix tool: {0}", flags); } else { if ((flags & (GunkFlags.TwoSided | GunkFlags.NoCollision)) == (GunkFlags.TwoSided | GunkFlags.NoCollision) && polygon.Material != null && polygon.Material.Name == "BLACKNESS") { return blackness; } } return null; } private void EnsureMaterials() { if (ghost != null) return; CreateGhost(); CreateBarrier(); CreateDanger(); CreateDoor(); CreateStairs(); CreateImpassable(); CreateBlackness(); CreateFloor(); } private void CreateBarrier() { var surface = new Surface(128, 128); var fill = new Color(0, 240, 20, 180); var sign = new Color(240, 20, 0, 255); surface.Fill(0, 0, 128, 128, fill); surface.Fill(0, 0, 128, 1, sign); surface.Fill(0, 127, 128, 1, sign); surface.Fill(0, 1, 1, 126, sign); surface.Fill(127, 1, 1, 126, sign); surface.Fill(64, 1, 1, 126, sign); surface.Fill(1, 64, 126, 1, sign); barrier = new Material("_marker_barrier", true) { Flags = GunkFlags.NoObjectCollision | GunkFlags.Invisible, Image = surface }; } private void CreateImpassable() { var surface = new Surface(128, 128); var fill = new Color(240, 0, 20, 180); var sign = new Color(240, 20, 0, 255); surface.Fill(0, 0, 128, 128, fill); surface.Fill(0, 0, 128, 1, sign); surface.Fill(0, 127, 128, 1, sign); surface.Fill(0, 1, 1, 126, sign); surface.Fill(127, 1, 1, 126, sign); surface.Fill(64, 1, 1, 126, sign); surface.Fill(1, 64, 126, 1, sign); impassable = new Material("_marker_impassable", true) { Flags = GunkFlags.Invisible, Image = surface }; } private void CreateGhost() { var surface = new Surface(128, 128); var border = new Color(16, 48, 240, 240); var fill = new Color(208, 240, 240, 80); surface.Fill(0, 0, 128, 128, fill); surface.Fill(0, 0, 128, 1, border); surface.Fill(0, 127, 128, 1, border); surface.Fill(0, 1, 1, 126, border); surface.Fill(127, 1, 1, 126, border); surface.Fill(64, 1, 1, 126, border); surface.Fill(1, 64, 126, 1, border); ghost = new Material("_marker_ghost", true); ghost.Flags = GunkFlags.Ghost | GunkFlags.TwoSided | GunkFlags.Transparent | GunkFlags.NoCollision; ghost.Image = surface; } private void CreateDoor() { var surface = new Surface(128, 128); var fill = new Color(240, 240, 0, 208); var line = new Color(0, 0, 240); surface.Fill(0, 0, 128, 128, fill); surface.Fill(1, 1, 126, 1, line); surface.Fill(1, 1, 1, 126, line); surface.Fill(1, 126, 126, 1, line); surface.Fill(126, 1, 1, 126, line); door = new Material("_marker_door", true) { Flags = GunkFlags.DoorFrame | GunkFlags.TwoSided | GunkFlags.Transparent | GunkFlags.NoCollision, Image = surface }; } private void CreateDanger() { var surface = new Surface(128, 128); var fill = new Color(255, 10, 0, 208); var sign = new Color(255, 255, 255, 255); surface.Fill(0, 0, 128, 128, fill); surface.Fill(52, 16, 24, 64, sign); surface.Fill(52, 96, 24, 16, sign); danger = new Material("_marker_danger", true) { Flags = GunkFlags.Danger | GunkFlags.Invisible | GunkFlags.NoCollision | GunkFlags.NoOcclusion, Image = surface }; } private void CreateStairs() { var surface = new Surface(128, 128); var fill = new Color(40, 240, 0, 180); var step = new Color(40, 0, 240, 180); surface.Fill(0, 0, 128, 128, fill); for (int y = 0; y < surface.Height; y += 32) surface.Fill(0, y, surface.Width, 16, step); stairs = new Material("_marker_stairs", true) { Flags = GunkFlags.Stairs | GunkFlags.Invisible | GunkFlags.NoObjectCollision | GunkFlags.TwoSided, Image = surface }; } private void CreateBlackness() { var surface = new Surface(16, 16, SurfaceFormat.BGRX); surface.Fill(0, 0, 16, 16, Color.Black); blackness = new Material("_marker_blackness", true) { Flags = GunkFlags.TwoSided | GunkFlags.NoCollision, Image = surface }; } private void CreateFloor() { var surface = new Surface(256, 256); surface.Fill(0, 0, 16, 16, Color.White); for (int x = 0; x < 256; x += 4) { surface.Fill(x, 0, 1, 256, Color.Black); surface.Fill(0, x, 256, 1, Color.Black); } floor = new Material("_marker_floor", true) { Flags = GunkFlags.NoCollision, Image = surface }; } public Material Barrier { get { EnsureMaterials(); return barrier; } } public Material Ghost { get { EnsureMaterials(); return ghost; } } public Material Danger { get { EnsureMaterials(); return danger; } } public Material DoorFrame { get { EnsureMaterials(); return door; } } public Material Stairs { get { EnsureMaterials(); return stairs; } } public Material Floor { get { EnsureMaterials(); return floor; } } public Material Blackness { get { EnsureMaterials(); return blackness; } } } #endregion public MarkerMaterials Markers => markers; public Material NotFound { get { if (notFound == null) notFound = GetMaterial("notfoundtex"); return notFound; } } public IEnumerable All => materials.Values; public Material GetMaterial(string name) { Material material; if (!materials.TryGetValue(name, out material)) { material = markers.GetMarker(name); if (material == null) material = new Material(name); materials.Add(name, material); } if (name.StartsWith("lmap_", StringComparison.OrdinalIgnoreCase)) { material.Flags |= GunkFlags.NoCollision | GunkFlags.NoOcclusion | GunkFlags.SoundTransparent; } return material; } } }