add ChunkVertexGenerator
This commit is contained in:
parent
e1b5cb9c0c
commit
d20837e199
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using Blarg.GameFramework.Graphics;
|
||||
using Blarg.GameFramework.TileMap.Meshes;
|
||||
|
||||
namespace Blarg.GameFramework.TileMap
|
||||
{
|
||||
|
@ -8,8 +10,255 @@ namespace Blarg.GameFramework.TileMap
|
|||
{
|
||||
}
|
||||
|
||||
private VertexBuffer MakeVertexBuffer()
|
||||
{
|
||||
var buffer = new VertexBuffer(Framework.GraphicsDevice,
|
||||
VertexAttributeDeclarations.TextureColorNormalPosition3D,
|
||||
128,
|
||||
BufferObjectUsage.Static);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void Generate(TileChunk chunk)
|
||||
{
|
||||
VertexBuffer mesh = null;
|
||||
VertexBuffer alphaMesh = null;
|
||||
|
||||
for (int y = 0; y < chunk.Height; ++y)
|
||||
{
|
||||
for (int z = 0; z < chunk.Depth; ++z)
|
||||
{
|
||||
for (int x = 0; x < chunk.Width; ++x)
|
||||
{
|
||||
var tile = chunk.Get(x, y, z);
|
||||
if (tile.TileIndex == Tile.NO_TILE)
|
||||
continue;
|
||||
|
||||
var tileMesh = chunk.TileMap.TileMeshes.Get(tile);
|
||||
|
||||
// choose the right vertex buffer to add this tile's mesh
|
||||
// to and, if necessary, create the buffer
|
||||
VertexBuffer buffer;
|
||||
if (tileMesh.Alpha)
|
||||
{
|
||||
if (alphaMesh == null)
|
||||
alphaMesh = MakeVertexBuffer();
|
||||
buffer = alphaMesh;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mesh == null)
|
||||
mesh = MakeVertexBuffer();
|
||||
buffer = mesh;
|
||||
}
|
||||
|
||||
// "world/tilemap space" position that this tile is at
|
||||
Point3 position;
|
||||
position.X = x + (int)chunk.Position.X;
|
||||
position.Y = y + (int)chunk.Position.Y;
|
||||
position.Z = z + (int)chunk.Position.Z;
|
||||
|
||||
Matrix4x4 transform = Matrix4x4.Identity;
|
||||
Tile.GetTransformationFor(tile, ref transform);
|
||||
|
||||
// tile color
|
||||
Color color;
|
||||
if (tile.HasCustomColor)
|
||||
color = Color.FromInt(tile.Color);
|
||||
else
|
||||
color = tileMesh.Color;
|
||||
|
||||
if (tileMesh is CubeTileMesh)
|
||||
HandleCubeMesh(buffer, x, y, z, tile, chunk, (CubeTileMesh)tileMesh, position, transform, color);
|
||||
else
|
||||
HandleGenericMesh(buffer, x, y, z, tile, chunk, tileMesh, position, transform, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCubeMesh(VertexBuffer buffer,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
Tile tile,
|
||||
TileChunk chunk,
|
||||
CubeTileMesh mesh,
|
||||
Point3 tileMapPosition,
|
||||
Matrix4x4 transform,
|
||||
Color color)
|
||||
{
|
||||
// determine what's next to each cube face
|
||||
Tile left = chunk.GetWithinSelfOrNeighbourSafe(x - 1, y, z);
|
||||
Tile right = chunk.GetWithinSelfOrNeighbourSafe(x + 1, y, z);
|
||||
Tile forward = chunk.GetWithinSelfOrNeighbourSafe(x, y, z - 1);
|
||||
Tile backward = chunk.GetWithinSelfOrNeighbourSafe(x, y, z + 1);
|
||||
Tile down = chunk.GetWithinSelfOrNeighbourSafe(x, y - 1, z);
|
||||
Tile up = chunk.GetWithinSelfOrNeighbourSafe(x, y + 1, z);
|
||||
|
||||
// evaluate each face's visibility and add it's vertices if needed one at a time
|
||||
if ((left == null || left.TileIndex == Tile.NO_TILE || !chunk.TileMap.TileMeshes.Get(left).IsOpaque(TileMesh.SIDE_RIGHT)) && mesh.HasFace(TileMesh.SIDE_LEFT)) {
|
||||
// left face is visible
|
||||
AddMesh(buffer,
|
||||
tile,
|
||||
mesh,
|
||||
chunk,
|
||||
tileMapPosition,
|
||||
transform,
|
||||
color,
|
||||
mesh.LeftFaceVertexOffset,
|
||||
TileMesh.CUBE_VERTICES_PER_FACE);
|
||||
}
|
||||
if ((right == null || right.TileIndex == Tile.NO_TILE || !chunk.TileMap.TileMeshes.Get(right).IsOpaque(TileMesh.SIDE_LEFT)) && mesh.HasFace(TileMesh.SIDE_RIGHT)) {
|
||||
// right face is visible
|
||||
AddMesh(buffer,
|
||||
tile,
|
||||
mesh,
|
||||
chunk,
|
||||
tileMapPosition,
|
||||
transform,
|
||||
color,
|
||||
mesh.RightFaceVertexOffset,
|
||||
TileMesh.CUBE_VERTICES_PER_FACE);
|
||||
}
|
||||
if ((forward == null || forward.TileIndex == Tile.NO_TILE || !chunk.TileMap.TileMeshes.Get(forward).IsOpaque(TileMesh.SIDE_BACK)) && mesh.HasFace(TileMesh.SIDE_FRONT)) {
|
||||
// front face is visible
|
||||
AddMesh(buffer,
|
||||
tile,
|
||||
mesh,
|
||||
chunk,
|
||||
tileMapPosition,
|
||||
transform,
|
||||
color,
|
||||
mesh.FrontFaceVertexOffset,
|
||||
TileMesh.CUBE_VERTICES_PER_FACE);
|
||||
}
|
||||
if ((backward == null || backward.TileIndex == Tile.NO_TILE || !chunk.TileMap.TileMeshes.Get(backward).IsOpaque(TileMesh.SIDE_FRONT)) && mesh.HasFace(TileMesh.SIDE_BACK)) {
|
||||
// back face is visible
|
||||
AddMesh(buffer,
|
||||
tile,
|
||||
mesh,
|
||||
chunk,
|
||||
tileMapPosition,
|
||||
transform,
|
||||
color,
|
||||
mesh.BackFaceVertexOffset,
|
||||
TileMesh.CUBE_VERTICES_PER_FACE);
|
||||
}
|
||||
if ((down == null || down.TileIndex == Tile.NO_TILE || !chunk.TileMap.TileMeshes.Get(down).IsOpaque(TileMesh.SIDE_TOP)) && mesh.HasFace(TileMesh.SIDE_BOTTOM)) {
|
||||
// bottom face is visible
|
||||
AddMesh(buffer,
|
||||
tile,
|
||||
mesh,
|
||||
chunk,
|
||||
tileMapPosition,
|
||||
transform,
|
||||
color,
|
||||
mesh.BottomFaceVertexOffset,
|
||||
TileMesh.CUBE_VERTICES_PER_FACE);
|
||||
}
|
||||
if ((up == null || up.TileIndex == Tile.NO_TILE || !chunk.TileMap.TileMeshes.Get(up).IsOpaque(TileMesh.SIDE_BOTTOM)) && mesh.HasFace(TileMesh.SIDE_TOP)) {
|
||||
// top face is visible
|
||||
AddMesh(buffer,
|
||||
tile,
|
||||
mesh,
|
||||
chunk,
|
||||
tileMapPosition,
|
||||
transform,
|
||||
color,
|
||||
mesh.TopFaceVertexOffset,
|
||||
TileMesh.CUBE_VERTICES_PER_FACE);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleGenericMesh(VertexBuffer buffer,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
Tile tile,
|
||||
TileChunk chunk,
|
||||
TileMesh mesh,
|
||||
Point3 tileMapPosition,
|
||||
Matrix4x4 transform,
|
||||
Color color)
|
||||
{
|
||||
bool visible = false;
|
||||
|
||||
// visibility determination. we check for at least one
|
||||
// adjacent empty space / non-opaque tile
|
||||
Tile left = chunk.GetWithinSelfOrNeighbourSafe(x - 1, y, z);
|
||||
Tile right = chunk.GetWithinSelfOrNeighbourSafe(x + 1, y, z);
|
||||
Tile forward = chunk.GetWithinSelfOrNeighbourSafe(x, y, z - 1);
|
||||
Tile backward = chunk.GetWithinSelfOrNeighbourSafe(x, y, z + 1);
|
||||
Tile down = chunk.GetWithinSelfOrNeighbourSafe(x, y - 1, z);
|
||||
Tile up = chunk.GetWithinSelfOrNeighbourSafe(x, y + 1, z);
|
||||
|
||||
// null == empty space (off the edge of the entire map)
|
||||
if ((left == null || left.IsEmptySpace || !chunk.TileMap.TileMeshes.Get(left).IsOpaque(TileMesh.SIDE_RIGHT)) ||
|
||||
(right == null || right.IsEmptySpace || !chunk.TileMap.TileMeshes.Get(right).IsOpaque(TileMesh.SIDE_LEFT)) ||
|
||||
(forward == null || forward.IsEmptySpace || !chunk.TileMap.TileMeshes.Get(forward).IsOpaque(TileMesh.SIDE_BACK)) ||
|
||||
(backward == null || backward.IsEmptySpace || !chunk.TileMap.TileMeshes.Get(backward).IsOpaque(TileMesh.SIDE_FRONT)) ||
|
||||
(up == null || up.IsEmptySpace || !chunk.TileMap.TileMeshes.Get(up).IsOpaque(TileMesh.SIDE_BOTTOM)) ||
|
||||
(down == null || down.IsEmptySpace || !chunk.TileMap.TileMeshes.Get(down).IsOpaque(TileMesh.SIDE_TOP))
|
||||
)
|
||||
visible = true;
|
||||
|
||||
if (visible)
|
||||
AddMesh(buffer, tile, mesh, chunk, tileMapPosition, transform, color, 0, mesh.Vertices.NumElements);
|
||||
}
|
||||
|
||||
protected void AddMesh(VertexBuffer buffer,
|
||||
Tile tile,
|
||||
TileMesh sourceMesh,
|
||||
TileChunk chunk,
|
||||
Point3 position,
|
||||
Matrix4x4? transform,
|
||||
Color color,
|
||||
int firstVertex,
|
||||
int numVertices)
|
||||
{
|
||||
// adjust position by the tilemesh offset. TileMesh's are modeled using the
|
||||
// origin (0,0,0) as the center and are 1 unit wide/deep/tall. So, their
|
||||
// max extents are from -0.5,-0.5,-0.5 to 0.5,0.5,0.5. For rendering
|
||||
// purposes in a chunk, we want the extents to be 0,0,0 to 1,1,1. This
|
||||
// adjustment fixes that
|
||||
Vector3 offset = TileMesh.OFFSET;
|
||||
offset.X += (float)position.X;
|
||||
offset.Y += (float)position.Y;
|
||||
offset.Z += (float)position.Z;
|
||||
|
||||
var sourceVertices = sourceMesh.Vertices;
|
||||
sourceVertices.MoveTo(firstVertex);
|
||||
|
||||
// copy vertices
|
||||
for (int i = 0; i < numVertices; ++i) {
|
||||
Vector3 v = sourceVertices.GetCurrentPosition3D();
|
||||
Vector3 n = sourceVertices.GetCurrentNormal();
|
||||
|
||||
if (transform != null)
|
||||
{
|
||||
var transformMatrix = transform.Value;
|
||||
// need to transform the vertex + normal first before copying it
|
||||
v = Matrix4x4.Transform(transformMatrix, v);
|
||||
n = Matrix4x4.TransformNormal(transformMatrix, n);
|
||||
}
|
||||
|
||||
// translate vertex into "tilemap space"
|
||||
v += offset;
|
||||
|
||||
// copy to destination
|
||||
buffer.SetCurrentPosition3D(v);
|
||||
buffer.SetCurrentNormal(n);
|
||||
|
||||
// just directly copy the tex coord as-is
|
||||
buffer.SetCurrentTexCoord(sourceVertices.GetCurrentTexCoord());
|
||||
|
||||
// color is the same for the entire mesh
|
||||
buffer.SetCurrentColor(color);
|
||||
|
||||
sourceVertices.MoveNext();
|
||||
buffer.MoveNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,10 +14,11 @@ namespace Blarg.GameFramework.TileMap
|
|||
readonly int _depth;
|
||||
readonly Vector3 _position;
|
||||
readonly BoundingBox _bounds;
|
||||
readonly TileMap _tileMap;
|
||||
VertexBuffer _mesh;
|
||||
VertexBuffer _alphaMesh;
|
||||
|
||||
public readonly TileMap TileMap;
|
||||
|
||||
public Tile[] Data
|
||||
{
|
||||
get { return _data; }
|
||||
|
@ -93,7 +94,7 @@ namespace Blarg.GameFramework.TileMap
|
|||
if (tileMap == null)
|
||||
throw new ArgumentNullException("tileMap");
|
||||
|
||||
_tileMap = tileMap;
|
||||
TileMap = tileMap;
|
||||
_x = x;
|
||||
_y = y;
|
||||
_z = z;
|
||||
|
@ -119,12 +120,23 @@ namespace Blarg.GameFramework.TileMap
|
|||
generator.Generate(this);
|
||||
}
|
||||
|
||||
internal void SetMeshes(VertexBuffer mesh, VertexBuffer alphaMesh)
|
||||
{
|
||||
if (_mesh != null)
|
||||
_mesh.Dispose();
|
||||
_mesh = mesh;
|
||||
|
||||
if (_alphaMesh != null)
|
||||
_alphaMesh.Dispose();
|
||||
_alphaMesh = alphaMesh;
|
||||
}
|
||||
|
||||
public Tile GetWithinSelfOrNeighbour(int x, int y, int z)
|
||||
{
|
||||
int checkX = x + _x;
|
||||
int checkY = y + _y;
|
||||
int checkZ = z + _z;
|
||||
return _tileMap.Get(checkX, checkY, checkZ);
|
||||
return TileMap.Get(checkX, checkY, checkZ);
|
||||
}
|
||||
|
||||
public Tile GetWithinSelfOrNeighbourSafe(int x, int y, int z)
|
||||
|
@ -132,10 +144,10 @@ namespace Blarg.GameFramework.TileMap
|
|||
int checkX = x + _x;
|
||||
int checkY = y + _y;
|
||||
int checkZ = z + _z;
|
||||
if (!_tileMap.IsWithinBounds(checkX, checkY, checkZ))
|
||||
if (!TileMap.IsWithinBounds(checkX, checkY, checkZ))
|
||||
return null;
|
||||
else
|
||||
return _tileMap.Get(checkX, checkY, checkZ);
|
||||
return TileMap.Get(checkX, checkY, checkZ);
|
||||
}
|
||||
|
||||
public override Tile Get(int x, int y, int z)
|
||||
|
|
Reference in a new issue