ClassiCube/ClassicalSharp/Map/ChunkMeshBuilderTex2Col4.cs

316 lines
13 KiB
C#

using System;
using System.Runtime.InteropServices;
using ClassicalSharp.GraphicsAPI;
namespace ClassicalSharp {
public partial class ChunkMeshBuilder {
DrawInfo[] drawInfoNormal, drawInfoTranslucent;
TerrainAtlas1D atlas;
int arraysCount = 0;
void TerrainAtlasChanged( object sender, EventArgs e ) {
int newArraysCount = Window.TerrainAtlas1D.TexIds.Length;
if( arraysCount > 0 && arraysCount != newArraysCount ) {
Array.Resize( ref drawInfoNormal, newArraysCount );
Array.Resize( ref drawInfoTranslucent, newArraysCount );
for( int i = arraysCount; i < drawInfoNormal.Length; i++ ) {
drawInfoNormal[i] = new DrawInfo();
drawInfoTranslucent[i] = new DrawInfo();
}
}
arraysCount = newArraysCount;
}
public void Dispose() {
Window.TerrainAtlasChanged -= TerrainAtlasChanged;
}
[StructLayout( LayoutKind.Sequential )]
struct DrawInfoFaceData {
public int left, right, front, back, bottom, top;
}
class DrawInfo {
public VertexPos3fTex2fCol4b[] vertices;
public int vCount, iCount;
public DrawInfoFaceData vIndex;
public DrawInfoFaceData Count;
public int spriteIndex, spriteCount;
public void ExpandToCapacity() {
vCount = ( iCount / 6 ) * 4;
if( vertices == null || vCount > vertices.Length ) {
vertices = new VertexPos3fTex2fCol4b[vCount];
}
vIndex.left = spriteCount / 6 * 4;
vIndex.right = vIndex.left + Count.left / 6 * 4;
vIndex.front = vIndex.right + Count.right / 6 * 4;
vIndex.back = vIndex.front + Count.front / 6 * 4;
vIndex.bottom = vIndex.back + Count.back / 6 * 4;
vIndex.top = vIndex.bottom + Count.bottom / 6 * 4;
}
public void ResetState() {
vCount = iCount = 0;
spriteIndex = spriteCount = 0;
vIndex = new DrawInfoFaceData();
Count = new DrawInfoFaceData();
}
}
bool CanStretch( byte initialTile, int chunkIndex, int x, int y, int z, int face ) {
byte tile = chunk[chunkIndex];
return tile == initialTile && !BlockInfo.IsFaceHidden( tile, GetNeighbour( chunkIndex, face ), face ) &&
( IsLit( X, Y, Z, face ) == IsLit( x, y, z, face ) );
}
bool IsLit( int x, int y, int z, int face ) {
switch( face ) {
case TileSide.Left:
return x <= 0 || y > map.heightmap[( z * width ) + (x - 1)];
case TileSide.Right:
return x >= maxX || y > map.heightmap[( z * width ) + (x + 1)];
case TileSide.Front:
return z <= 0 || y > map.heightmap[( (z - 1) * width ) + x];
case TileSide.Back:
return z >= maxZ || y > map.heightmap[( (z + 1) * width ) + x];
case TileSide.Bottom:
return y <= 0 || (y - 1) > map.heightmap[( z * width ) + x];
case TileSide.Top:
return y >= maxY || (y + 1) > map.heightmap[( z * width ) + x];
}
return true;
}
void SetPartInfo( DrawInfo part, int i, ref ChunkPartInfo[] parts ) {
if( part.iCount == 0 ) return;
ChunkPartInfo info;
info.VbId = Graphics.CreateVb( part.vertices, VertexFormat.Pos3fTex2fCol4b, part.vCount );
info.IndicesCount = part.iCount;
info.leftCount = (ushort)part.Count.left; info.rightCount = (ushort)part.Count.right;
info.frontCount = (ushort)part.Count.front; info.backCount = (ushort)part.Count.back;
info.bottomCount = (ushort)part.Count.bottom; info.topCount = (ushort)part.Count.top;
info.spriteCount = (ushort)part.spriteCount;
info.leftIndex = info.spriteCount;
info.rightIndex = info.leftIndex + info.leftCount;
info.frontIndex = info.rightIndex + info.rightCount;
info.backIndex = info.frontIndex + info.frontCount;
info.bottomIndex = info.backIndex + info.backCount;
info.topIndex = info.bottomIndex + info.bottomCount;
// Lazy initalize part arrays so we can save time in MapRenderer for chunks that only contain 1 or 2 part types.
if( parts == null )
parts = new ChunkPartInfo[arraysCount];
parts[i] = info;
}
bool isTranslucent;
float blockHeight;
float invVerElementSize;
void PreStretchTiles( int x1, int y1, int z1 ) {
invVerElementSize = Window.TerrainAtlas1D.invElementSize;
arraysCount = Window.TerrainAtlas1D.TexIds.Length;
atlas = Window.TerrainAtlas1D;
if( drawInfoNormal == null ) {
drawInfoNormal = new DrawInfo[arraysCount];
drawInfoTranslucent = new DrawInfo[arraysCount];
for( int i = 0; i < drawInfoNormal.Length; i++ ) {
drawInfoNormal[i] = new DrawInfo();
drawInfoTranslucent[i] = new DrawInfo();
}
} else {
for( int i = 0; i < drawInfoNormal.Length; i++ ) {
drawInfoNormal[i].ResetState();
drawInfoTranslucent[i].ResetState();
}
}
}
void PostStretchTiles( int x1, int y1, int z1 ) {
for( int i = 0; i < drawInfoNormal.Length; i++ ) {
drawInfoNormal[i].ExpandToCapacity();
drawInfoTranslucent[i].ExpandToCapacity();
}
}
void AddSpriteVertices( byte tile, int count ) {
int i = atlas.Get1DIndex( BlockInfo.GetOptimTextureLoc( tile, TileSide.Left ) );
DrawInfo part = drawInfoNormal[i];
part.spriteCount += 6 + 6 * count;
part.iCount += 6 + 6 * count;
}
unsafe void AddVertices( byte tile, int count, int face ) {
int i = atlas.Get1DIndex( BlockInfo.GetOptimTextureLoc( tile, face ) );
DrawInfo part = BlockInfo.IsTranslucent( tile ) ? drawInfoTranslucent[i] : drawInfoNormal[i];
part.iCount += 6;
DrawInfoFaceData counts = part.Count;
*( &counts.left + face ) += 6;
part.Count = counts;
}
void DrawLeftFace( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Left );
int i;
TextureRectangle rec = atlas.GetTexRec( texId, count, out i );
FastColour col = X > 0 ? ( Y > map.heightmap[( Z * width ) + (X - 1)] ? map.SunlightXSide : map.ShadowlightXSide )
: map.SunlightXSide;
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
isTranslucent = BlockInfo.IsTranslucent( tile );
}
if( blockHeight != 1 ) {
rec.V2 = rec.V1 + blockHeight * invVerElementSize;
}
DrawInfo part = isTranslucent ? drawInfoTranslucent[i] : drawInfoNormal[i];
part.vertices[part.vIndex.left++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z + count, rec.U2, rec.V1, col );
part.vertices[part.vIndex.left++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z, rec.U1, rec.V1, col );
part.vertices[part.vIndex.left++] = new VertexPos3fTex2fCol4b( X, Y, Z, rec.U1, rec.V2, col );
part.vertices[part.vIndex.left++] = new VertexPos3fTex2fCol4b( X, Y, Z + count, rec.U2, rec.V2, col );
}
void DrawRightFace( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Right );
int i;
TextureRectangle rec = atlas.GetTexRec( texId, count, out i );
FastColour col = X < maxX ? ( Y > map.heightmap[( Z * width ) + (X + 1)] ? map.SunlightXSide : map.ShadowlightXSide )
: map.SunlightXSide;
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
isTranslucent = BlockInfo.IsTranslucent( tile );
}
if( blockHeight != 1 ) {
rec.V2 = rec.V1 + blockHeight * invVerElementSize;
}
DrawInfo part = isTranslucent ? drawInfoTranslucent[i] : drawInfoNormal[i];
part.vertices[part.vIndex.right++] = new VertexPos3fTex2fCol4b( X + 1, Y + blockHeight, Z, rec.U2, rec.V1, col );
part.vertices[part.vIndex.right++] = new VertexPos3fTex2fCol4b( X + 1, Y + blockHeight, Z + count, rec.U1, rec.V1, col );
part.vertices[part.vIndex.right++] = new VertexPos3fTex2fCol4b( X + 1, Y, Z + count, rec.U1, rec.V2, col );
part.vertices[part.vIndex.right++] = new VertexPos3fTex2fCol4b( X + 1, Y, Z, rec.U2, rec.V2, col );
}
void DrawBackFace( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Back );
int i;
TextureRectangle rec = atlas.GetTexRec( texId, count, out i );
FastColour col = Z < maxZ ? ( Y > map.heightmap[( (Z + 1) * width ) + X] ? map.SunlightZSide : map.ShadowlightZSide )
: map.SunlightZSide;
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
isTranslucent = BlockInfo.IsTranslucent( tile );
}
if( blockHeight != 1 ) {
rec.V2 = rec.V1 + blockHeight * invVerElementSize;
}
DrawInfo part = isTranslucent ? drawInfoTranslucent[i] : drawInfoNormal[i];
part.vertices[part.vIndex.back++] = new VertexPos3fTex2fCol4b( X + count, Y + blockHeight, Z + 1, rec.U2, rec.V1, col );
part.vertices[part.vIndex.back++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z + 1, rec.U1, rec.V1, col );
part.vertices[part.vIndex.back++] = new VertexPos3fTex2fCol4b( X, Y, Z + 1, rec.U1, rec.V2, col );
part.vertices[part.vIndex.back++] = new VertexPos3fTex2fCol4b( X + count, Y, Z + 1, rec.U2, rec.V2, col );
}
void DrawFrontFace( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Front );
int i;
TextureRectangle rec = atlas.GetTexRec( texId, count, out i );
FastColour col = Z > 0 ? ( Y > map.heightmap[( (Z - 1) * width ) + X] ? map.SunlightZSide : map.ShadowlightZSide )
: map.SunlightZSide;
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
isTranslucent = BlockInfo.IsTranslucent( tile );
}
if( blockHeight != 1 ) {
rec.V2 = rec.V1 + blockHeight * invVerElementSize;
}
DrawInfo part = isTranslucent ? drawInfoTranslucent[i] : drawInfoNormal[i];
part.vertices[part.vIndex.front++] = new VertexPos3fTex2fCol4b( X + count, Y, Z, rec.U1, rec.V2, col );
part.vertices[part.vIndex.front++] = new VertexPos3fTex2fCol4b( X, Y, Z, rec.U2, rec.V2, col );
part.vertices[part.vIndex.front++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z, rec.U2, rec.V1, col );
part.vertices[part.vIndex.front++] = new VertexPos3fTex2fCol4b( X + count, Y + blockHeight, Z, rec.U1, rec.V1, col );
}
void DrawBottomFace( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Bottom );
int i;
TextureRectangle rec = atlas.GetTexRec( texId, count, out i );
FastColour col = Y > 0 ? ( (Y - 1) > map.heightmap[( Z * width ) + X] ? map.SunlightYBottom : map.ShadowlightYBottom )
: map.SunlightYBottom;
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
isTranslucent = BlockInfo.IsTranslucent( tile );
}
DrawInfo part = isTranslucent ? drawInfoTranslucent[i] : drawInfoNormal[i];
part.vertices[part.vIndex.bottom++] = new VertexPos3fTex2fCol4b( X + count, Y, Z + 1, rec.U2, rec.V2, col );
part.vertices[part.vIndex.bottom++] = new VertexPos3fTex2fCol4b( X, Y, Z + 1, rec.U1, rec.V2, col );
part.vertices[part.vIndex.bottom++] = new VertexPos3fTex2fCol4b( X, Y, Z, rec.U1, rec.V1, col );
part.vertices[part.vIndex.bottom++] = new VertexPos3fTex2fCol4b( X + count, Y, Z, rec.U2, rec.V1, col );
}
void DrawTopFace( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Top );
int i;
TextureRectangle rec = atlas.GetTexRec( texId, count, out i );
FastColour col = Y < maxY ? ( (Y + 1) > map.heightmap[( Z * width ) + X] ? map.Sunlight : map.Shadowlight )
: map.Sunlight;
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
isTranslucent = BlockInfo.IsTranslucent( tile );
}
DrawInfo part = isTranslucent ? drawInfoTranslucent[i] : drawInfoNormal[i];
part.vertices[part.vIndex.top++] = new VertexPos3fTex2fCol4b( X + count, Y + blockHeight, Z, rec.U2, rec.V1, col );
part.vertices[part.vIndex.top++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z, rec.U1, rec.V1, col );
part.vertices[part.vIndex.top++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z + 1, rec.U1, rec.V2, col );
part.vertices[part.vIndex.top++] = new VertexPos3fTex2fCol4b( X + count, Y + blockHeight, Z + 1, rec.U2, rec.V2, col );
}
void DrawSprite( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Right );
int i;
TextureRectangle rec = atlas.GetTexRec( texId, count, out i );
FastColour col = Y < maxY ? ( (Y + 1) > map.heightmap[( Z * width ) + X] ? map.Sunlight : map.Shadowlight )
: map.Sunlight;
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
}
DrawInfo part = drawInfoNormal[i];
// Draw stretched Z axis
part.vertices[part.spriteIndex++] = new VertexPos3fTex2fCol4b( X, Y, Z + 0.5f, rec.U2, rec.V2, col );
part.vertices[part.spriteIndex++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z + 0.5f, rec.U2, rec.V1, col );
part.vertices[part.spriteIndex++] = new VertexPos3fTex2fCol4b( X + count, Y + blockHeight, Z + 0.5f, rec.U1, rec.V1, col );
part.vertices[part.spriteIndex++] = new VertexPos3fTex2fCol4b( X + count, Y, Z + 0.5f, rec.U1, rec.V2, col );
// Draw X axis
rec.U2 = 1;
int startX = X;
for( int j = 0; j < count; j++ ) {
part.vertices[part.spriteIndex++] = new VertexPos3fTex2fCol4b( X + 0.5f, Y, Z, rec.U1, rec.V2, col );
part.vertices[part.spriteIndex++] = new VertexPos3fTex2fCol4b( X + 0.5f, Y + blockHeight, Z, rec.U1, rec.V1, col );
part.vertices[part.spriteIndex++] = new VertexPos3fTex2fCol4b( X + 0.5f, Y + blockHeight, Z + 1, rec.U2, rec.V1, col );
part.vertices[part.spriteIndex++] = new VertexPos3fTex2fCol4b( X + 0.5f, Y, Z + 1, rec.U2, rec.V2, col );
X++;
}
X = startX;
}
}
}