mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-16 19:15:14 -04:00
Optimise chunk mesh building functions even further.
This commit is contained in:
parent
d6e541bc91
commit
3b3a155243
@ -6,7 +6,7 @@ namespace ClassicalSharp {
|
|||||||
/// <summary> Stores various properties about the blocks in Minecraft Classic. </summary>
|
/// <summary> Stores various properties about the blocks in Minecraft Classic. </summary>
|
||||||
public partial class BlockInfo {
|
public partial class BlockInfo {
|
||||||
|
|
||||||
bool[] hidden = new bool[BlocksCount * BlocksCount * TileSide.Sides];
|
public bool[] hidden = new bool[BlocksCount * BlocksCount * TileSide.Sides];
|
||||||
|
|
||||||
public bool[] CanStretch = new bool[BlocksCount * TileSide.Sides];
|
public bool[] CanStretch = new bool[BlocksCount * TileSide.Sides];
|
||||||
|
|
||||||
|
@ -97,9 +97,6 @@ namespace ClassicalSharp.Commands {
|
|||||||
game.Chat.Add( "map width: " + game.Map.Width );
|
game.Chat.Add( "map width: " + game.Map.Width );
|
||||||
game.Chat.Add( "map height: " + game.Map.Height );
|
game.Chat.Add( "map height: " + game.Map.Height );
|
||||||
game.Chat.Add( "map length: " + game.Map.Length );
|
game.Chat.Add( "map length: " + game.Map.Length );
|
||||||
} else if( Utils.CaselessEquals( property, "spam" ) ) {
|
|
||||||
for( int i = 0; i < 1000; i++ )
|
|
||||||
game.Chat.Add( "spamsdfdfd sdfd dsfdfdf &e" + i );
|
|
||||||
} else {
|
} else {
|
||||||
game.Chat.Add( "&e/client info: Unrecognised property: \"&f" + property + "&e\"." );
|
game.Chat.Add( "&e/client info: Unrecognised property: \"&f" + property + "&e\"." );
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
/// <summary> Class responsible for converting a 16x16x16 into an optimised mesh of vertices. </summary>
|
/// <summary> Class responsible for converting a 16x16x16 into an optimised mesh of vertices. </summary>
|
||||||
/// <remarks> This class is heavily optimised and as such may suffer from slightly unreadable code. </remarks>
|
/// <remarks> This class is heavily optimised and as such may suffer from slightly unreadable code. </remarks>
|
||||||
public partial class ChunkMeshBuilder {
|
public unsafe partial class ChunkMeshBuilder {
|
||||||
|
|
||||||
int X, Y, Z;
|
int X, Y, Z;
|
||||||
float x1, y1, z1, x2, y2, z2;
|
float x1, y1, z1, x2, y2, z2;
|
||||||
@ -29,12 +29,15 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
internal int width, length, height, clipLevel;
|
internal int width, length, height, clipLevel;
|
||||||
int maxX, maxY, maxZ;
|
int maxX, maxY, maxZ;
|
||||||
byte[] counts = new byte[chunkSize3 * TileSide.Sides];
|
byte* chunk, counts;
|
||||||
byte[] chunk = new byte[extChunkSize3];
|
|
||||||
|
|
||||||
bool BuildChunk( int x1, int y1, int z1 ) {
|
bool BuildChunk( int x1, int y1, int z1 ) {
|
||||||
PreStretchTiles( x1, y1, z1 );
|
PreStretchTiles( x1, y1, z1 );
|
||||||
|
byte* chunkPtr = stackalloc byte[extChunkSize3]; chunk = chunkPtr;
|
||||||
|
byte* countsPtr = stackalloc byte[chunkSize3 * TileSide.Sides]; counts = countsPtr;
|
||||||
|
MemUtils.memset( (IntPtr)chunkPtr, 0, 0, extChunkSize3 );
|
||||||
if( ReadChunkData( x1, y1, z1 ) ) return false;
|
if( ReadChunkData( x1, y1, z1 ) ) return false;
|
||||||
|
MemUtils.memset( (IntPtr)countsPtr, 1, 0, chunkSize3 * TileSide.Sides );
|
||||||
|
|
||||||
Stretch( x1, y1, z1 );
|
Stretch( x1, y1, z1 );
|
||||||
PostStretchTiles( x1, y1, z1 );
|
PostStretchTiles( x1, y1, z1 );
|
||||||
@ -48,8 +51,10 @@ namespace ClassicalSharp {
|
|||||||
int chunkIndex = (yy + 1) * extChunkSize2 + (zz + 1) * extChunkSize + (0 + 1);
|
int chunkIndex = (yy + 1) * extChunkSize2 + (zz + 1) * extChunkSize + (0 + 1);
|
||||||
for( int x = x1, xx = 0; x < xMax; x++, xx++ ) {
|
for( int x = x1, xx = 0; x < xMax; x++, xx++ ) {
|
||||||
tile = chunk[chunkIndex];
|
tile = chunk[chunkIndex];
|
||||||
if( !info.IsAir[tile] )
|
if( !info.IsAir[tile] ) {
|
||||||
RenderTile( chunkIndex, xx, yy, zz, x, y, z );
|
int index = ((yy << 8) | (zz << 4) | xx) * TileSide.Sides;
|
||||||
|
RenderTile( chunkIndex, index, x, y, z );
|
||||||
|
}
|
||||||
chunkIndex++;
|
chunkIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,10 +62,9 @@ namespace ClassicalSharp {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe bool ReadChunkData( int x1, int y1, int z1 ) {
|
bool ReadChunkData( int x1, int y1, int z1 ) {
|
||||||
bool allAir = true, allSolid = true;
|
bool allAir = true, allSolid = true;
|
||||||
fixed( byte* chunkPtr = chunk, mapPtr = map.mapData ) {
|
fixed( byte* mapPtr = map.mapData ) {
|
||||||
MemUtils.memset( (IntPtr)chunkPtr, 0, 0, extChunkSize3 );
|
|
||||||
|
|
||||||
for( int yy = -1; yy < 17; yy++ ) {
|
for( int yy = -1; yy < 17; yy++ ) {
|
||||||
int y = yy + y1;
|
int y = yy + y1;
|
||||||
@ -87,7 +91,7 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
if( allAir && block != 0 ) allAir = false;
|
if( allAir && block != 0 ) allAir = false;
|
||||||
if( allSolid && !info.IsOpaque[block] ) allSolid = false;
|
if( allSolid && !info.IsOpaque[block] ) allSolid = false;
|
||||||
chunkPtr[chunkIndex] = block;
|
chunk[chunkIndex] = block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,8 +107,7 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
public void GetDrawInfo( int x, int y, int z, ref ChunkPartInfo[] normalParts,
|
public void GetDrawInfo( int x, int y, int z, ref ChunkPartInfo[] normalParts,
|
||||||
ref ChunkPartInfo[] translucentParts, ref byte occlusionFlags ) {
|
ref ChunkPartInfo[] translucentParts, ref byte occlusionFlags ) {
|
||||||
if( !BuildChunk( x, y, z ) )
|
if( !BuildChunk( x, y, z ) ) return;
|
||||||
return;
|
|
||||||
|
|
||||||
for( int i = 0; i < arraysCount; i++ ) {
|
for( int i = 0; i < arraysCount; i++ ) {
|
||||||
SetPartInfo( drawInfoNormal[i], i, ref normalParts );
|
SetPartInfo( drawInfoNormal[i], i, ref normalParts );
|
||||||
@ -115,9 +118,8 @@ namespace ClassicalSharp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vector3 minBB, maxBB;
|
Vector3 minBB, maxBB;
|
||||||
public void RenderTile( int chunkIndex, int xx, int yy, int zz, int x, int y, int z ) {
|
public void RenderTile( int chunkIndex, int index, int x, int y, int z ) {
|
||||||
X = x; Y = y; Z = z;
|
X = x; Y = y; Z = z;
|
||||||
int index = ((yy << 8) | (zz << 4) | xx) * TileSide.Sides;
|
|
||||||
|
|
||||||
if( info.IsSprite[tile] ) {
|
if( info.IsSprite[tile] ) {
|
||||||
fullBright = info.FullBright[tile];
|
fullBright = info.FullBright[tile];
|
||||||
@ -143,24 +145,15 @@ namespace ClassicalSharp {
|
|||||||
isTranslucent = info.IsTranslucent[tile];
|
isTranslucent = info.IsTranslucent[tile];
|
||||||
lightFlags = info.LightOffset[tile];
|
lightFlags = info.LightOffset[tile];
|
||||||
|
|
||||||
if( leftCount != 0 )
|
if( leftCount != 0 ) DrawLeftFace( leftCount );
|
||||||
DrawLeftFace( leftCount );
|
if( rightCount != 0 ) DrawRightFace( rightCount );
|
||||||
if( rightCount != 0 )
|
if( frontCount != 0 ) DrawFrontFace( frontCount );
|
||||||
DrawRightFace( rightCount );
|
if( backCount != 0 ) DrawBackFace( backCount );
|
||||||
if( frontCount != 0 )
|
if( bottomCount != 0 ) DrawBottomFace( bottomCount );
|
||||||
DrawFrontFace( frontCount );
|
if( topCount != 0 ) DrawTopFace( topCount );
|
||||||
if( backCount != 0 )
|
|
||||||
DrawBackFace( backCount );
|
|
||||||
if( bottomCount != 0 )
|
|
||||||
DrawBottomFace( bottomCount );
|
|
||||||
if( topCount != 0 )
|
|
||||||
DrawTopFace( topCount );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void Stretch( int x1, int y1, int z1 ) {
|
void Stretch( int x1, int y1, int z1 ) {
|
||||||
fixed( byte* ptr = counts )
|
|
||||||
MemUtils.memset( (IntPtr)ptr, 1, 0, chunkSize3 * TileSide.Sides );
|
|
||||||
|
|
||||||
int xMax = Math.Min( width, x1 + chunkSize );
|
int xMax = Math.Min( width, x1 + chunkSize );
|
||||||
int yMax = Math.Min( height, y1 + chunkSize );
|
int yMax = Math.Min( height, y1 + chunkSize );
|
||||||
int zMax = Math.Min( length, z1 + chunkSize );
|
int zMax = Math.Min( length, z1 + chunkSize );
|
||||||
@ -175,6 +168,7 @@ namespace ClassicalSharp {
|
|||||||
map.SunlightZSide = map.ShadowlightZSide = col;
|
map.SunlightZSide = map.ShadowlightZSide = col;
|
||||||
map.SunlightYBottom = map.ShadowlightYBottom = col;
|
map.SunlightYBottom = map.ShadowlightYBottom = col;
|
||||||
#endif
|
#endif
|
||||||
|
bool[] hidden = game.BlockInfo.hidden;
|
||||||
|
|
||||||
for( int y = y1, yy = 0; y < yMax; y++, yy++ ) {
|
for( int y = y1, yy = 0; y < yMax; y++, yy++ ) {
|
||||||
for( int z = z1, zz = 0; z < zMax; z++, zz++ ) {
|
for( int z = z1, zz = 0; z < zMax; z++, zz++ ) {
|
||||||
@ -198,71 +192,67 @@ namespace ClassicalSharp {
|
|||||||
} else {
|
} else {
|
||||||
X = x; Y = y; Z = z;
|
X = x; Y = y; Z = z;
|
||||||
fullBright = info.FullBright[tile];
|
fullBright = info.FullBright[tile];
|
||||||
TestAndStretchZ( zz, countIndex, tile, chunkIndex, x, 0, TileSide.Left, -1 );
|
int tileAdj = tile * BlockInfo.BlocksCount;
|
||||||
TestAndStretchZ( zz, countIndex, tile, chunkIndex, x, maxX, TileSide.Right, 1 );
|
// All of these function calls are inlined as they can be called tens of millions to hundreds of millions of times.
|
||||||
TestAndStretchX( xx, countIndex, tile, chunkIndex, z, 0, TileSide.Front, -extChunkSize );
|
|
||||||
TestAndStretchX( xx, countIndex, tile, chunkIndex, z, maxZ, TileSide.Back, extChunkSize );
|
|
||||||
|
|
||||||
if( y > 0 )
|
int index = countIndex + TileSide.Left;
|
||||||
TestAndStretchX( xx, countIndex, tile, chunkIndex, y, 0, TileSide.Bottom, -extChunkSize2 );
|
if( counts[index] == 0 || (x == 0 && Y < clipLevel) ||
|
||||||
else
|
(x != 0 && hidden[(tileAdj + chunk[chunkIndex - 1]) * TileSide.Sides + TileSide.Left]) ) {
|
||||||
counts[countIndex + TileSide.Bottom] = 0;
|
|
||||||
TestAndStretchX( xx, countIndex, tile, chunkIndex, y, maxY + 2, TileSide.Top, extChunkSize2 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestAndStretchX( int xx, int index, byte tile, int chunkIndex, int value, int test, int tileSide, int offset ) {
|
|
||||||
index += tileSide;
|
|
||||||
if( counts[index] != 0 ) {
|
|
||||||
if( (value == test && Y < clipLevel) ||
|
|
||||||
(value != test && info.IsFaceHidden( tile, chunk[chunkIndex + offset], tileSide )) ) {
|
|
||||||
counts[index] = 0;
|
counts[index] = 0;
|
||||||
} else {
|
} else {
|
||||||
int count = StretchX( xx, index, X, Y, Z, chunkIndex, tile, tileSide );
|
int count = StretchZ( zz, index, X, Y, Z, chunkIndex, tile, TileSide.Left );
|
||||||
AddVertices( tile, count, tileSide );
|
AddVertices( tile, count, TileSide.Left ); counts[index] = (byte)count;
|
||||||
counts[index] = (byte)count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestAndStretchZ( int zz, int index, byte tile, int chunkIndex, int value, int test, int tileSide, int offset ) {
|
index = countIndex + TileSide.Right;
|
||||||
index += tileSide;
|
if( counts[index] == 0 || (x == maxX && Y < clipLevel) ||
|
||||||
if( counts[index] != 0 ) {
|
(x != maxX && hidden[(tileAdj + chunk[chunkIndex + 1]) * TileSide.Sides + TileSide.Right]) ) {
|
||||||
if( (value == test && Y < clipLevel) ||
|
|
||||||
(value != test && info.IsFaceHidden( tile, chunk[chunkIndex + offset], tileSide )) ) {
|
|
||||||
counts[index] = 0;
|
counts[index] = 0;
|
||||||
} else {
|
} else {
|
||||||
int count = StretchZ( zz, index, X, Y, Z, chunkIndex, tile, tileSide );
|
int count = StretchZ( zz, index, X, Y, Z, chunkIndex, tile, TileSide.Right );
|
||||||
AddVertices( tile, count, tileSide );
|
AddVertices( tile, count, TileSide.Right ); counts[index] = (byte)count;
|
||||||
counts[index] = (byte)count;
|
}
|
||||||
|
|
||||||
|
index = countIndex + TileSide.Front;
|
||||||
|
if( counts[index] == 0 || (z == 0 && Y < clipLevel) ||
|
||||||
|
(z != 0 && hidden[(tileAdj + chunk[chunkIndex - 18]) * TileSide.Sides + TileSide.Front]) ) {
|
||||||
|
counts[index] = 0;
|
||||||
|
} else {
|
||||||
|
int count = StretchX( xx, index, X, Y, Z, chunkIndex, tile, TileSide.Front );
|
||||||
|
AddVertices( tile, count, TileSide.Front ); counts[index] = (byte)count;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = countIndex + TileSide.Back;
|
||||||
|
if( counts[index] == 0 || (z == maxZ && Y < clipLevel) ||
|
||||||
|
(z != maxZ && hidden[(tileAdj + chunk[chunkIndex + 18]) * TileSide.Sides + TileSide.Back]) ) {
|
||||||
|
counts[index] = 0;
|
||||||
|
} else {
|
||||||
|
int count = StretchX( xx, index, X, Y, Z, chunkIndex, tile, TileSide.Back );
|
||||||
|
AddVertices( tile, count, TileSide.Back ); counts[index] = (byte)count;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = countIndex + TileSide.Bottom;
|
||||||
|
if( counts[index] == 0 || y == 0 ||
|
||||||
|
hidden[(tileAdj + chunk[chunkIndex - 324]) * TileSide.Sides + TileSide.Bottom] ) {
|
||||||
|
counts[index] = 0;
|
||||||
|
} else {
|
||||||
|
int count = StretchX( xx, index, X, Y, Z, chunkIndex, tile, TileSide.Bottom );
|
||||||
|
AddVertices( tile, count, TileSide.Bottom ); counts[index] = (byte)count;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = countIndex + TileSide.Top;
|
||||||
|
if( counts[index] == 0 ||
|
||||||
|
hidden[(tileAdj + chunk[chunkIndex + 324]) * TileSide.Sides + TileSide.Top] ) {
|
||||||
|
counts[index] = 0;
|
||||||
|
} else {
|
||||||
|
int count = StretchX( xx, index, X, Y, Z, chunkIndex, tile, TileSide.Top );
|
||||||
|
AddVertices( tile, count, TileSide.Top ); counts[index] = (byte)count;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byte GetNeighbour( int chunkIndex, int face ) {
|
|
||||||
switch( face ) {
|
|
||||||
case TileSide.Left:
|
|
||||||
return chunk[chunkIndex - 1]; // x - 1
|
|
||||||
|
|
||||||
case TileSide.Right:
|
|
||||||
return chunk[chunkIndex + 1]; // x + 1
|
|
||||||
|
|
||||||
case TileSide.Front:
|
|
||||||
return chunk[chunkIndex - 18]; // z - 1
|
|
||||||
|
|
||||||
case TileSide.Back:
|
|
||||||
return chunk[chunkIndex + 18]; // z + 1
|
|
||||||
|
|
||||||
case TileSide.Bottom:
|
|
||||||
return chunk[chunkIndex - 324]; // y - 1
|
|
||||||
|
|
||||||
case TileSide.Top:
|
|
||||||
return chunk[chunkIndex + 324]; // y + 1
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int StretchX( int xx, int countIndex, int x, int y, int z, int chunkIndex, byte tile, int face ) {
|
int StretchX( int xx, int countIndex, int x, int y, int z, int chunkIndex, byte tile, int face ) {
|
||||||
|
@ -4,7 +4,7 @@ using ClassicalSharp.GraphicsAPI;
|
|||||||
|
|
||||||
namespace ClassicalSharp {
|
namespace ClassicalSharp {
|
||||||
|
|
||||||
public partial class ChunkMeshBuilder {
|
public unsafe partial class ChunkMeshBuilder {
|
||||||
|
|
||||||
DrawInfo[] drawInfoNormal, drawInfoTranslucent;
|
DrawInfo[] drawInfoNormal, drawInfoTranslucent;
|
||||||
TerrainAtlas1D atlas;
|
TerrainAtlas1D atlas;
|
||||||
@ -63,9 +63,10 @@ namespace ClassicalSharp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int[] offsets = { -1, 1, -extChunkSize, extChunkSize, -extChunkSize2, extChunkSize2 };
|
||||||
bool CanStretch( byte initialTile, int chunkIndex, int x, int y, int z, int face ) {
|
bool CanStretch( byte initialTile, int chunkIndex, int x, int y, int z, int face ) {
|
||||||
byte tile = chunk[chunkIndex];
|
byte tile = chunk[chunkIndex];
|
||||||
return tile == initialTile && !info.IsFaceHidden( tile, GetNeighbour( chunkIndex, face ), face )
|
return tile == initialTile && !info.IsFaceHidden( tile, chunk[chunkIndex + offsets[face]], face )
|
||||||
&& (fullBright || IsLit( X, Y, Z, face, initialTile ) == IsLit( x, y, z, face, tile ) );
|
&& (fullBright || IsLit( X, Y, Z, face, initialTile ) == IsLit( x, y, z, face, tile ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user