ClassiCube/Map/ChunkMeshBuilderTex2Col4.cs

384 lines
15 KiB
C#

using System;
using ClassicalSharp.GraphicsAPI;
namespace ClassicalSharp {
public partial class ChunkMeshBuilder {
DrawInfo1D[] drawInfoBuffer;
TextureAtlas1D atlas;
int arraysCount = 0;
const int maxIndices = 65536;
void TerrainAtlasChanged( object sender, EventArgs e ) {
int newArraysCount = Window.TerrainAtlas1DTexIds.Length;
if( arraysCount > 0 && arraysCount != newArraysCount ) {
Array.Resize( ref drawInfoBuffer, newArraysCount );
for( int i = arraysCount; i < drawInfoBuffer.Length; i++ ) {
drawInfoBuffer[i] = new DrawInfo1D();
}
}
arraysCount = newArraysCount;
}
class DrawInfo1D {
public DrawInfo1DPart Solid = new DrawInfo1DPart();
public DrawInfo1DPart Translucent = new DrawInfo1DPart();
public DrawInfo1DPart Sprite = new DrawInfo1DPart();
}
class DrawInfo1DPart {
public VertexPos3fTex2fCol4b[] vertices1, vertices2, vertices;
public ushort[] indices1, indices2, indices;
public int vIndex, vCount;
public int iIndex, iCount;
public int vCount1, vCount2;
public int iCount1, iCount2;
public DrawInfo1DPart() {
vertices1 = new VertexPos3fTex2fCol4b[0];
indices1 = new ushort[0];
vertices2 = new VertexPos3fTex2fCol4b[0];
indices2 = new ushort[0];
}
public void ExpandToCapacity() {
vCount = ( iCount / 6 ) * 4;
vCount1 = Math.Min( vCount, maxIndices );
iCount1 = ( vCount1 / 4 ) * 6;
if( vCount1 > vertices1.Length ) {
vertices1 = new VertexPos3fTex2fCol4b[vCount1];
indices1 = new ushort[iCount1];
}
vCount2 = Math.Max( 0, vCount - maxIndices );
iCount2 = ( vCount2 / 4 ) * 6;
if( vCount2 > vertices2.Length ) {
vertices2 = new VertexPos3fTex2fCol4b[vCount2];
indices2 = new ushort[iCount2];
}
vertices = vertices1;
indices = indices1;
}
public void ResetState() {
vIndex = iIndex = 0;
vCount = iCount = 0;
vCount1 = vCount2 = 0;
iCount1 = iCount2 = 0;
}
}
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( startX, startY, startZ, face ) == IsLit( x, y, z, face ) );
}
bool IsLit( int x, int y, int z, int face ) {
switch( face ) {
case TileSide.Left:
return x <= 0 || IsLitAdj( x - 1, y, z );
case TileSide.Right:
return x >= maxX || IsLitAdj( x + 1, y, z );
case TileSide.Front:
return z <= 0 || IsLitAdj( x, y, z - 1 );
case TileSide.Back:
return z >= maxZ || IsLitAdj( x, y, z + 1 );
case TileSide.Bottom:
return y <= 0 || IsLit( x, y - 1, z );
case TileSide.Top:
return y >= maxY || IsLit( x, y + 1, z );
}
return true;
}
bool IsLit( int x, int y, int z ) {
return y > GetLightHeight( x, z );
}
bool IsLitAdj( int x, int y, int z ) {
return y > GetLightHeightAdj( x, z );
}
FastColour GetColour( int x, int y, int z, ref FastColour sunlight, ref FastColour shadow ) {
if( !map.IsValidPos( x, y, z ) ) return sunlight;
return y > GetLightHeight( x, z ) ? sunlight : shadow;
}
FastColour GetColourAdj( int x, int y, int z, ref FastColour sunlight, ref FastColour shadow ) {
if( !map.IsValidPos( x, y, z ) ) return sunlight;
return y > GetLightHeightAdj( x, z ) ? sunlight : shadow;
}
int GetLightHeight( int x, int z ) {
return map.GetLightHeight( x, z );
}
int GetLightHeightAdj( int x, int z ) {
int y = map.GetLightHeight( x, z );
return y == -1 ? -1 :
( BlockInfo.BlockHeight( map.GetBlock( x, y, z ) ) == 1 ? y : y - 1 );
}
ChunkDrawInfo GetChunkInfo( int x, int y, int z ) {
ChunkDrawInfo info = new ChunkDrawInfo( arraysCount );
for( int i = 0; i < arraysCount; i++ ) {
DrawInfo1D drawInfo = drawInfoBuffer[i];
SetPartInfo( drawInfo.Solid, i, info.SolidParts );
SetPartInfo( drawInfo.Translucent, i, info.TranslucentParts );
SetPartInfo( drawInfo.Sprite, i, info.SpriteParts );
}
return info;
}
void SetPartInfo( DrawInfo1DPart part, int i, ChunkPartInfo[] parts ) {
ChunkPartInfo info = default( ChunkPartInfo );
if( part.iCount1 > 0 ) {
info.VbId = Graphics.InitIndexedVb( part.vertices1, part.indices1, DrawMode.Triangles, part.vCount1, part.iCount1 );
info.IndicesCount = part.iCount1;
}
if( part.iCount2 > 0 ) {
info.VbId2 = Graphics.InitIndexedVb( part.vertices2, part.indices2, DrawMode.Triangles, part.vCount2, part.iCount2 );
info.IndicesCount2 = part.iCount2;
}
parts[i] = info;
}
bool isTranslucent;
float blockHeight;
float invVerElementSize;
void PreStretchTiles( int x1, int y1, int z1 ) {
invVerElementSize = Window.TerrainAtlas1D.invElementSize;
arraysCount = Window.TerrainAtlas1DTexIds.Length;
atlas = Window.TerrainAtlas1D;
if( drawInfoBuffer == null ) {
drawInfoBuffer = new DrawInfo1D[arraysCount];
for( int i = 0; i < drawInfoBuffer.Length; i++ ) {
drawInfoBuffer[i] = new DrawInfo1D();
}
} else {
for( int i = 0; i < drawInfoBuffer.Length; i++ ) {
DrawInfo1D info = drawInfoBuffer[i];
info.Solid.ResetState();
info.Sprite.ResetState();
info.Translucent.ResetState();
}
}
}
void PostStretchTiles( int x1, int y1, int z1 ) {
for( int i = 0; i < drawInfoBuffer.Length; i++ ) {
DrawInfo1D info = drawInfoBuffer[i];
info.Solid.ExpandToCapacity();
info.Sprite.ExpandToCapacity();
info.Translucent.ExpandToCapacity();
}
}
void AddSpriteVertices( byte tile, int count ) {
int i = atlas.Get1DIndex( BlockInfo.GetOptimTextureLoc( tile, TileSide.Left ) );
drawInfoBuffer[i].Sprite.iCount += 6 + 6 * count;
}
void AddVertices( byte tile, int count, int face ) {
int i = atlas.Get1DIndex( BlockInfo.GetOptimTextureLoc( tile, face ) );
if( BlockInfo.IsTranslucent( tile ) ) {
drawInfoBuffer[i].Translucent.iCount += 6;
} else {
drawInfoBuffer[i].Solid.iCount += 6;
}
}
void DrawTopFace( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Top );
int drawInfoIndex;
TextureRectangle rec = atlas.GetTexRec( texId, out drawInfoIndex );
rec.U2 = count;
FastColour col = GetColour( X, Y + 1, Z, ref map.Sunlight, ref map.Shadowlight );
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
isTranslucent = BlockInfo.IsTranslucent( tile );
}
DrawInfo1D info = drawInfoBuffer[drawInfoIndex];
DrawInfo1DPart part = isTranslucent ? info.Translucent : info.Solid;
AddIndices( part );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + count, Y + blockHeight, Z, rec.U2, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z, rec.U1, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z + 1, rec.U1, rec.V2, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + count, Y + blockHeight, Z + 1, rec.U2, rec.V2, col );
}
void DrawBottomFace( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Bottom );
int drawInfoIndex;
TextureRectangle rec = atlas.GetTexRec( texId, out drawInfoIndex );
rec.U2 = count;
FastColour col = GetColour( X, Y - 1, Z, ref map.SunlightYBottom, ref map.ShadowlightYBottom );
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
isTranslucent = BlockInfo.IsTranslucent( tile );
}
DrawInfo1D info = drawInfoBuffer[drawInfoIndex];
DrawInfo1DPart part = isTranslucent ? info.Translucent : info.Solid;
AddIndices( part );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + count, Y, Z + 1, rec.U2, rec.V2, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y, Z + 1, rec.U1, rec.V2, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y, Z, rec.U1, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + count, Y, Z, rec.U2, rec.V1, col );
}
void DrawBackFace( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Back );
int drawInfoIndex;
TextureRectangle rec = atlas.GetTexRec( texId, out drawInfoIndex );
rec.U2 = count;
FastColour col = GetColourAdj( X, Y, Z + 1, ref map.SunlightZSide, ref map.ShadowlightZSide );
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
isTranslucent = BlockInfo.IsTranslucent( tile );
}
if( blockHeight != 1 ) {
rec.V2 = rec.V1 + blockHeight * invVerElementSize;
}
DrawInfo1D info = drawInfoBuffer[drawInfoIndex];
DrawInfo1DPart part = isTranslucent ? info.Translucent : info.Solid;
AddIndices( part );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + count, Y + blockHeight, Z + 1, rec.U2, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z + 1, rec.U1, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y, Z + 1, rec.U1, rec.V2, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + count, Y, Z + 1, rec.U2, rec.V2, col );
}
void DrawFrontFace( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Front );
int drawInfoIndex;
TextureRectangle rec = atlas.GetTexRec( texId, out drawInfoIndex );
rec.U2 = count;
FastColour col = GetColourAdj( X, Y, Z - 1, ref map.SunlightZSide, ref map.ShadowlightZSide );
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
isTranslucent = BlockInfo.IsTranslucent( tile );
}
if( blockHeight != 1 ) {
rec.V2 = rec.V1 + blockHeight * invVerElementSize;
}
DrawInfo1D info = drawInfoBuffer[drawInfoIndex];
DrawInfo1DPart part = isTranslucent ? info.Translucent : info.Solid;
AddIndices( part );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + count, Y, Z, rec.U1, rec.V2, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y, Z, rec.U2, rec.V2, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z, rec.U2, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + count, Y + blockHeight, Z, rec.U1, rec.V1, col );
}
void DrawLeftFace( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Left );
int drawInfoIndex;
TextureRectangle rec = atlas.GetTexRec( texId, out drawInfoIndex );
rec.U2 = count;
FastColour col = GetColourAdj( X - 1, Y, Z, ref map.SunlightXSide, ref map.ShadowlightXSide );
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
isTranslucent = BlockInfo.IsTranslucent( tile );
}
if( blockHeight != 1 ) {
rec.V2 = rec.V1 + blockHeight * invVerElementSize;
}
DrawInfo1D info = drawInfoBuffer[drawInfoIndex];
DrawInfo1DPart part = isTranslucent ? info.Translucent : info.Solid;
AddIndices( part );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z + count, rec.U2, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z, rec.U1, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y, Z, rec.U1, rec.V2, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y, Z + count, rec.U2, rec.V2, col );
}
void DrawRightFace( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Right );
int drawInfoIndex;
TextureRectangle rec = atlas.GetTexRec( texId, out drawInfoIndex );
rec.U2 = count;
FastColour col = GetColourAdj( X + 1, Y, Z, ref map.SunlightXSide, ref map.ShadowlightXSide );
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
isTranslucent = BlockInfo.IsTranslucent( tile );
}
if( blockHeight != 1 ) {
rec.V2 = rec.V1 + blockHeight * invVerElementSize;
}
DrawInfo1D info = drawInfoBuffer[drawInfoIndex];
DrawInfo1DPart part = isTranslucent ? info.Translucent : info.Solid;
AddIndices( part );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + 1, Y + blockHeight, Z, rec.U2, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + 1, Y + blockHeight, Z + count, rec.U1, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + 1, Y, Z + count, rec.U1, rec.V2, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + 1, Y, Z, rec.U2, rec.V2, col );
}
void DrawSprite( int count ) {
int texId = BlockInfo.GetOptimTextureLoc( tile, TileSide.Right );
int drawInfoIndex;
TextureRectangle rec = atlas.GetTexRec( texId, out drawInfoIndex );
rec.U2 = count;
FastColour col = GetColour( X, Y + 1, Z, ref map.Sunlight, ref map.Shadowlight );
if( blockHeight == -1 ) {
blockHeight = BlockInfo.BlockHeight( tile );
}
DrawInfo1DPart part = drawInfoBuffer[drawInfoIndex].Sprite;
// Draw stretched Z axis
AddIndices( part );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y, Z + 0.5f, rec.U2, rec.V2, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X, Y + blockHeight, Z + 0.5f, rec.U2, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + count, Y + blockHeight, Z + 0.5f, rec.U1, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + count, Y, Z + 0.5f, rec.U1, rec.V2, col );
// Draw X axis
rec.U2 = 1;
int startX = X;
for( int i = 0; i < count; i++ ) {
AddIndices( part );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + 0.5f, Y, Z, rec.U1, rec.V2, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + 0.5f, Y + blockHeight, Z, rec.U1, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + 0.5f, Y + blockHeight, Z + 1, rec.U2, rec.V1, col );
part.vertices[part.vIndex++] = new VertexPos3fTex2fCol4b( X + 0.5f, Y, Z + 1, rec.U2, rec.V2, col );
X++;
}
X = startX;
}
void AddIndices( DrawInfo1DPart part ) {
int element = part.vIndex;
if( element == maxIndices ) {
part.indices = part.indices2;
part.vertices = part.vertices2;
part.iIndex = 0;
part.vIndex = 0;
element = 0;
}
part.indices[part.iIndex++] = (ushort)( element + 0 );
part.indices[part.iIndex++] = (ushort)( element + 1 );
part.indices[part.iIndex++] = (ushort)( element + 2 );
part.indices[part.iIndex++] = (ushort)( element + 2 );
part.indices[part.iIndex++] = (ushort)( element + 3 );
part.indices[part.iIndex++] = (ushort)( element + 0 );
}
}
}