diff --git a/Blarg.GameFramework/Blarg.GameFramework.csproj b/Blarg.GameFramework/Blarg.GameFramework.csproj
index 25c04f2..0b3cfb8 100644
--- a/Blarg.GameFramework/Blarg.GameFramework.csproj
+++ b/Blarg.GameFramework/Blarg.GameFramework.csproj
@@ -204,6 +204,7 @@
+
@@ -230,6 +231,7 @@
+
diff --git a/Blarg.GameFramework/TileMap/Lighting/ITileMapLighter.cs b/Blarg.GameFramework/TileMap/Lighting/ITileMapLighter.cs
new file mode 100644
index 0000000..663c5e7
--- /dev/null
+++ b/Blarg.GameFramework/TileMap/Lighting/ITileMapLighter.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Blarg.GameFramework.TileMap.Lighting
+{
+ public interface ITileMapLighter
+ {
+ void Light(TileMap tileMap);
+ }
+}
+
diff --git a/Blarg.GameFramework/TileMap/TileChunk.cs b/Blarg.GameFramework/TileMap/TileChunk.cs
index 5a92e9e..3811c45 100644
--- a/Blarg.GameFramework/TileMap/TileChunk.cs
+++ b/Blarg.GameFramework/TileMap/TileChunk.cs
@@ -101,6 +101,7 @@ namespace Blarg.GameFramework.TileMap
_height = height;
_depth = depth;
_position = new Vector3(x, y, z);
+ _bounds = new BoundingBox();
_bounds.Min.Set(x, y, z);
_bounds.Max.Set(x + width, y + height, z + depth);
@@ -158,6 +159,10 @@ namespace Blarg.GameFramework.TileMap
public void Dispose()
{
+ if (Mesh != null)
+ Mesh.Dispose();
+ if (AlphaMesh != null)
+ AlphaMesh.Dispose();
}
}
}
diff --git a/Blarg.GameFramework/TileMap/TileMap.cs b/Blarg.GameFramework/TileMap/TileMap.cs
index cafea35..a30ab32 100644
--- a/Blarg.GameFramework/TileMap/TileMap.cs
+++ b/Blarg.GameFramework/TileMap/TileMap.cs
@@ -1,21 +1,272 @@
using System;
+using Blarg.GameFramework.TileMap.Lighting;
+using Blarg.GameFramework.TileMap.Meshes;
namespace Blarg.GameFramework.TileMap
{
- public class TileMap
+ public class TileMap : TileContainer, IDisposable
{
- public TileMap()
+ readonly Vector3 _position;
+ readonly BoundingBox _bounds;
+
+ public readonly TileChunk[] Chunks;
+ public readonly TileMeshCollection TileMeshes;
+ public readonly ChunkVertexGenerator VertexGenerator;
+ public readonly ITileMapLighter Lighter;
+ public byte AmbientLightValue;
+ public byte SkyLightValue;
+
+ public readonly int ChunkWidth;
+ public readonly int ChunkHeight;
+ public readonly int ChunkDepth;
+ public readonly int WidthInChunks;
+ public readonly int HeightInChunks;
+ public readonly int DepthInChunks;
+
+ public override int Width
{
+ get { return ChunkWidth * WidthInChunks; }
}
- public Tile Get(int x, int y, int z)
+ public override int Height
{
- return null;
+ get { return ChunkHeight * HeightInChunks; }
}
- public bool IsWithinBounds(int x, int y, int z)
+ public override int Depth
{
- return false;
+ get { return ChunkDepth * DepthInChunks; }
+ }
+
+ public override int MinX
+ {
+ get { return 0; }
+ }
+
+ public override int MinY
+ {
+ get { return 0; }
+ }
+
+ public override int MinZ
+ {
+ get { return 0; }
+ }
+
+ public override int MaxX
+ {
+ get { return Width - 1; }
+ }
+
+ public override int MaxY
+ {
+ get { return Height - 1; }
+ }
+
+ public override int MaxZ
+ {
+ get { return Depth - 1; }
+ }
+
+ public override Vector3 Position
+ {
+ get { return _position; }
+ }
+
+ public override BoundingBox Bounds
+ {
+ get { return _bounds; }
+ }
+
+ public TileMap(int chunkWidth, int chunkHeight, int chunkDepth,
+ int widthInChunks, int heightInChunks, int depthInChunks,
+ TileMeshCollection tileMeshes,
+ ChunkVertexGenerator vertexGenerator,
+ ITileMapLighter lighter
+ )
+ {
+ if (tileMeshes == null)
+ throw new ArgumentNullException("tileMeshes");
+ if (vertexGenerator == null)
+ throw new ArgumentNullException("vertexGenerator");
+
+ TileMeshes = tileMeshes;
+ VertexGenerator = vertexGenerator;
+ Lighter = lighter;
+ ChunkWidth = chunkWidth;
+ ChunkHeight = chunkHeight;
+ ChunkDepth = chunkDepth;
+ WidthInChunks = widthInChunks;
+ HeightInChunks = heightInChunks;
+ DepthInChunks = depthInChunks;
+
+ AmbientLightValue = 0;
+ SkyLightValue = Tile.LIGHT_VALUE_SKY;
+
+ int numChunks = widthInChunks * heightInChunks * depthInChunks;
+ Chunks = new TileChunk[numChunks];
+
+ for (int y = 0; y < heightInChunks; ++y)
+ {
+ for (int z = 0; z < depthInChunks; ++z)
+ {
+ for (int x = 0; x < widthInChunks; ++x)
+ {
+ TileChunk chunk = new TileChunk(
+ x * chunkWidth,
+ y * chunkHeight,
+ z * chunkDepth,
+ chunkWidth,
+ chunkHeight,
+ chunkDepth,
+ this
+ );
+
+ int index = GetChunkIndex(x, y, z);
+ Chunks[index] = chunk;
+ }
+ }
+ }
+
+ _position = Vector3.Zero;
+ _bounds = new BoundingBox();
+ _bounds.Min = Vector3.Zero;
+ _bounds.Max.Set(Width, Height, Depth);
+ }
+
+ public void updateVertices()
+ {
+ for (int i = 0; i < Chunks.Length; ++i)
+ UpdateChunkVertices(Chunks[i]);
+ }
+
+ private void UpdateChunkVertices(TileChunk chunk)
+ {
+ chunk.UpdateVertices(VertexGenerator);
+ }
+
+ public void UpdateLighting()
+ {
+ if (Lighter != null)
+ Lighter.Light(this);
+ }
+
+ public bool GetOverlappedChunks(BoundingBox box, Point3 min, Point3 max)
+ {
+ // make sure the given box actually intersects with the map in the first place
+ var bounds = _bounds;
+ if (!IntersectionTester.Test(ref bounds, ref box))
+ return false;
+
+ // convert to tile coords. this is in "tilemap space" which is how we want it
+ // HACK: ceil() calls and "-1"'s keep us from picking up too many/too few
+ // blocks. these were arrived at through observation
+ int minX = (int)box.Min.X;
+ int minY = (int)box.Min.Y;
+ int minZ = (int)box.Min.Z;
+ int maxX = (int)Math.Ceiling(box.Max.X);
+ int maxY = (int)Math.Ceiling(box.Max.Y - 1.0f);
+ int maxZ = (int)Math.Ceiling(box.Max.Z);
+
+ // now convert to chunk coords
+ int minChunkX = minX / ChunkWidth;
+ int minChunkY = minY / ChunkHeight;
+ int minChunkZ = minZ / ChunkDepth;
+ int maxChunkX = maxX / ChunkWidth;
+ int maxChunkY = maxY / ChunkHeight;
+ int maxChunkZ = maxZ / ChunkDepth;
+
+ // trim off the excess bounds so that we end up with a min-to-max area
+ // that is completely within the chunk bounds of the map
+ // HACK: "-1"'s keep us from picking up too many chunks. these were arrived
+ // at through observation
+ minChunkX = MathHelpers.Clamp(minChunkX, 0, WidthInChunks);
+ minChunkY = MathHelpers.Clamp(minChunkY, 0, (HeightInChunks - 1));
+ minChunkZ = MathHelpers.Clamp(minChunkZ, 0, DepthInChunks);
+ maxChunkX = MathHelpers.Clamp(maxChunkX, 0, WidthInChunks);
+ maxChunkY = MathHelpers.Clamp(maxChunkY, 0, (HeightInChunks - 1));
+ maxChunkZ = MathHelpers.Clamp(maxChunkZ, 0, DepthInChunks);
+
+ // return the leftover area
+ min.X = minChunkX;
+ min.Y = minChunkY;
+ min.Z = minChunkZ;
+ max.X = maxChunkX;
+ max.Y = maxChunkY;
+ max.Z = maxChunkZ;
+
+ return true;
+ }
+
+ public override Tile Get(int x, int y, int z)
+ {
+ var chunk = GetChunkContaining(x, y, z);
+ int chunkX = x - chunk.MinX;
+ int chunkY = y - chunk.MinY;
+ int chunkZ = z - chunk.MinZ;
+
+ return chunk.Get(chunkX, chunkY, chunkZ);
+ }
+
+ public override Tile GetSafe(int x, int y, int z)
+ {
+ if (!IsWithinBounds(x, y, z))
+ return null;
+ else
+ return Get(x, y, z);
+ }
+
+ public TileChunk GetChunk(int chunkX, int chunkY, int chunkZ)
+ {
+ int index = GetChunkIndex(chunkX, chunkY, chunkZ);
+ return Chunks[index];
+ }
+
+ public TileChunk GetChunkSafe(int chunkX, int chunkY, int chunkZ)
+ {
+ if ((chunkX >= WidthInChunks) ||
+ (chunkY >= HeightInChunks) ||
+ (chunkZ >= DepthInChunks)
+ )
+ return null;
+ else
+ return GetChunk(chunkX, chunkY, chunkZ);
+ }
+
+ public TileChunk GetChunkNextTo(TileChunk chunk, int chunkOffsetX, int chunkOffsetY, int chunkOffsetZ)
+ {
+ int checkX = chunk.MinX + chunkOffsetX;
+ int checkY = chunk.MinY + chunkOffsetY;
+ int checkZ = chunk.MinZ + chunkOffsetZ;
+
+ if ((checkX < 0 || checkX >= WidthInChunks) ||
+ (checkY < 0 || checkY >= HeightInChunks) ||
+ (checkZ < 0 || checkZ >= DepthInChunks)
+ )
+ return null;
+ else
+ return GetChunk(checkX, checkY, checkZ);
+ }
+
+ public TileChunk GetChunkContaining(int x, int y, int z) {
+ int index = GetChunkIndexAt(x, y, z);
+ return Chunks[index];
+ }
+
+ private int GetChunkIndexAt(int x, int y, int z)
+ {
+ return GetChunkIndex(x / ChunkWidth, y / ChunkHeight, z / ChunkDepth);
+ }
+
+ private int GetChunkIndex(int chunkX, int chunkY, int chunkZ)
+ {
+ return (chunkY * WidthInChunks * DepthInChunks) + (chunkZ * WidthInChunks) + chunkX;
+ }
+
+ public void Dispose()
+ {
+ for (int i = 0; i < Chunks.Length; ++i)
+ Chunks[i].Dispose();
}
}
}