diff --git a/ClassicalSharp/Blocks/BlockInfo.BoundingBox.cs b/ClassicalSharp/Blocks/BlockInfo.BoundsBox.cs similarity index 82% rename from ClassicalSharp/Blocks/BlockInfo.BoundingBox.cs rename to ClassicalSharp/Blocks/BlockInfo.BoundsBox.cs index e75919962..df2eea218 100644 --- a/ClassicalSharp/Blocks/BlockInfo.BoundingBox.cs +++ b/ClassicalSharp/Blocks/BlockInfo.BoundsBox.cs @@ -11,7 +11,7 @@ namespace ClassicalSharp { public Vector3[] MaxBB = new Vector3[BlocksCount]; void InitBoundingBoxes() { - for( int i = 0; i < 256; i++ ) { + for( int i = 0; i < BlocksCount; i++ ) { if( IsSprite[i] ) { MinBB[i] = new Vector3( 2.50f/16f, 0, 2.50f/16f ); MaxBB[i] = new Vector3( 13.5f/16f, 1, 13.5f/16f ); @@ -22,8 +22,20 @@ namespace ClassicalSharp { } } + internal void InitLightOffsets() { + for( int tile = 0; tile < BlocksCount; tile++ ) { + int flags = 0xFF; + Vector3 min = MinBB[tile], max = MaxBB[tile]; + if( min.X != 0 ) flags &= ~(1 << TileSide.Left); + if( max.X != 1 ) flags &= ~(1 << TileSide.Right); + if( min.Z != 0 ) flags &= ~(1 << TileSide.Front); + if( max.Z != 1 ) flags &= ~(1 << TileSide.Back); + LightOffset[tile] = (byte)flags; + } + } + public void RecalculateSpriteBB( FastBitmap fastBmp ) { - for( int i = 0; i < 256; i++ ) { + for( int i = 0; i < BlocksCount; i++ ) { if( IsSprite[i] ) RecalculateBB( i, fastBmp ); } } diff --git a/ClassicalSharp/Blocks/BlockInfo.cs b/ClassicalSharp/Blocks/BlockInfo.cs index 98e672360..7509d67f0 100644 --- a/ClassicalSharp/Blocks/BlockInfo.cs +++ b/ClassicalSharp/Blocks/BlockInfo.cs @@ -46,6 +46,8 @@ namespace ClassicalSharp { public bool[] CullWithNeighbours = new bool[BlocksCount]; + public byte[] LightOffset = new byte[BlocksCount]; + public const byte MaxDefinedCpeBlock = (byte)Block.StoneBrick; public const int CpeBlocksCount = MaxDefinedCpeBlock + 1; public const byte MaxDefinedBlock = byte.MaxValue; @@ -97,9 +99,10 @@ namespace ClassicalSharp { IsOpaqueY[(byte)Block.Slab] = true; IsOpaqueY[(byte)Block.CobblestoneSlab] = true; IsOpaqueY[(byte)Block.Snow] = true; - + InitBoundingBoxes(); InitSounds(); + InitLightOffsets(); SetupCullingCache(); } diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index ef93b1e0a..8d4ba54c2 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -140,7 +140,7 @@ - + diff --git a/ClassicalSharp/Map/ChunkMeshBuilder.cs b/ClassicalSharp/Map/ChunkMeshBuilder.cs index 38da282fa..0808df556 100644 --- a/ClassicalSharp/Map/ChunkMeshBuilder.cs +++ b/ClassicalSharp/Map/ChunkMeshBuilder.cs @@ -144,6 +144,7 @@ namespace ClassicalSharp { fullBright = info.FullBright[tile]; isTranslucent = info.IsTranslucent[tile]; + lightFlags = info.LightOffset[tile]; if( leftCount != 0 ) DrawLeftFace( leftCount ); @@ -274,7 +275,9 @@ namespace ClassicalSharp { chunkIndex++; countIndex += TileSide.Sides; int max = chunkSize - xx; - while( count < max && x < width && CanStretch( tile, chunkIndex, x, y, z, face ) ) { + bool stretchTile = info.CanStretch[tile * TileSide.Sides + face]; + + while( count < max && x < width && stretchTile && CanStretch( tile, chunkIndex, x, y, z, face ) ) { counts[countIndex] = 0; count++; x++; @@ -290,7 +293,9 @@ namespace ClassicalSharp { chunkIndex += extChunkSize; countIndex += chunkSize * TileSide.Sides; int max = chunkSize - zz; - while( count < max && z < length && CanStretch( tile, chunkIndex, x, y, z, face ) ) { + bool stretchTile = info.CanStretch[tile * TileSide.Sides + face]; + + while( count < max && z < length && stretchTile && CanStretch( tile, chunkIndex, x, y, z, face ) ) { counts[countIndex] = 0; count++; z++; diff --git a/ClassicalSharp/Map/ChunkMeshBuilderTex2Col4.cs b/ClassicalSharp/Map/ChunkMeshBuilderTex2Col4.cs index c3ad14cef..15811773f 100644 --- a/ClassicalSharp/Map/ChunkMeshBuilderTex2Col4.cs +++ b/ClassicalSharp/Map/ChunkMeshBuilderTex2Col4.cs @@ -10,6 +10,7 @@ namespace ClassicalSharp { TerrainAtlas1D atlas; int arraysCount = 0; bool fullBright; + int lightFlags; void TerrainAtlasChanged( object sender, EventArgs e ) { int newArraysCount = game.TerrainAtlas1D.TexIds.Length; @@ -64,30 +65,25 @@ namespace ClassicalSharp { bool CanStretch( byte initialTile, int chunkIndex, int x, int y, int z, int face ) { byte tile = chunk[chunkIndex]; - return tile == initialTile && info.CanStretch[tile * TileSide.Sides + face] && - !info.IsFaceHidden( tile, GetNeighbour( chunkIndex, face ), face ) && - ( IsLit( X, Y, Z, face ) == IsLit( x, y, z, face ) ); + return tile == initialTile && !info.IsFaceHidden( tile, GetNeighbour( chunkIndex, face ), face ) + && (fullBright || IsLit( X, Y, Z, face, initialTile ) == IsLit( x, y, z, face, tile ) ); } - bool IsLit( int x, int y, int z, int face ) { + bool IsLit( int x, int y, int z, int face, byte type ) { + int offset = (info.LightOffset[type] >> face) & 1; switch( face ) { case TileSide.Left: - return fullBright || x <= 0 || y > map.heightmap[(z * width) + (x - 1)]; - + return x < offset || y > map.heightmap[(z * width) + (x - offset)]; case TileSide.Right: - return fullBright || x >= maxX || y > map.heightmap[(z * width) + (x + 1)]; - + return x > (maxX - offset) || y > map.heightmap[(z * width) + (x + offset)]; case TileSide.Front: - return fullBright || z <= 0 || y > map.heightmap[((z - 1) * width) + x]; - + return z < offset || y > map.heightmap[((z - offset) * width) + x]; case TileSide.Back: - return fullBright || z >= maxZ || y > map.heightmap[((z + 1) * width) + x]; - + return z > (maxZ - offset) || y > map.heightmap[((z + offset) * width) + x]; case TileSide.Bottom: - return fullBright || y <= 0 || (y - 1) > map.heightmap[(z * width) + x]; - + return y <= 0 || (y - 1) > map.heightmap[(z * width) + x]; case TileSide.Top: - return fullBright || y >= maxY || y > map.heightmap[(z * width) + x]; + return y >= maxY || y > map.heightmap[(z * width) + x]; } return true; } @@ -169,13 +165,14 @@ namespace ClassicalSharp { int texId = info.textures[tile * TileSide.Sides + TileSide.Left]; int i = texId / elementsPerAtlas1D; float vOrigin = (texId % elementsPerAtlas1D) * invVerElementSize; + int offset = (lightFlags >> TileSide.Left) & 1; float u1 = minBB.Z, u2 = (maxBB.Z + (count - 1)) * 15.99f/16f; float v1 = vOrigin + minBB.Y * invVerElementSize; float v2 = vOrigin + maxBB.Y * invVerElementSize * 15.99f/16f; DrawInfo part = isTranslucent ? drawInfoTranslucent[i] : drawInfoNormal[i]; FastColour col = fullBright ? FastColour.White : - X > 0 ? (Y > map.heightmap[(Z * width) + (X - 1)] ? map.SunlightXSide : map.ShadowlightXSide) : map.SunlightXSide; + X >= offset ? (Y > map.heightmap[(Z * width) + (X - offset)] ? map.SunlightXSide : map.ShadowlightXSide) : map.SunlightXSide; part.vertices[part.vIndex.left++] = new VertexPos3fTex2fCol4b( x1, y2, z2 + (count - 1), u2, v1, col ); part.vertices[part.vIndex.left++] = new VertexPos3fTex2fCol4b( x1, y2, z1, u1, v1, col ); @@ -187,49 +184,33 @@ namespace ClassicalSharp { int texId = info.textures[tile * TileSide.Sides + TileSide.Right]; int i = texId / elementsPerAtlas1D; float vOrigin = (texId % elementsPerAtlas1D) * invVerElementSize; + int offset = (lightFlags >> TileSide.Right) & 1; float u1 = minBB.Z, u2 = (maxBB.Z + (count - 1)) * 15.99f/16f; float v1 = vOrigin + minBB.Y * invVerElementSize; float v2 = vOrigin + maxBB.Y * invVerElementSize * 15.99f/16f; DrawInfo part = isTranslucent ? drawInfoTranslucent[i] : drawInfoNormal[i]; FastColour col = fullBright ? FastColour.White : - X < maxX ? (Y > map.heightmap[(Z * width) + (X + 1)] ? map.SunlightXSide : map.ShadowlightXSide) : map.SunlightXSide; + X <= (maxX - offset) ? (Y > map.heightmap[(Z * width) + (X + offset)] ? map.SunlightXSide : map.ShadowlightXSide) : map.SunlightXSide; part.vertices[part.vIndex.right++] = new VertexPos3fTex2fCol4b( x2, y2, z1, u2, v1, col ); part.vertices[part.vIndex.right++] = new VertexPos3fTex2fCol4b( x2, y2, z2 + (count - 1), u1, v1, col ); part.vertices[part.vIndex.right++] = new VertexPos3fTex2fCol4b( x2, y1, z2 + (count - 1), u1, v2, col ); part.vertices[part.vIndex.right++] = new VertexPos3fTex2fCol4b( x2, y1, z1, u2, v2, col ); } - - void DrawBackFace( int count ) { - int texId = info.textures[tile * TileSide.Sides + TileSide.Back]; - int i = texId / elementsPerAtlas1D; - float vOrigin = (texId % elementsPerAtlas1D) * invVerElementSize; - - float u1 = minBB.X, u2 = (maxBB.X + (count - 1)) * 15.99f/16f; - float v1 = vOrigin + minBB.Y * invVerElementSize; - float v2 = vOrigin + maxBB.Y * invVerElementSize * 15.99f/16f; - DrawInfo part = isTranslucent ? drawInfoTranslucent[i] : drawInfoNormal[i]; - FastColour col = fullBright ? FastColour.White : - Z < maxZ ? (Y > map.heightmap[((Z + 1) * width) + X] ? map.SunlightZSide : map.ShadowlightZSide) : map.SunlightZSide; - - part.vertices[part.vIndex.back++] = new VertexPos3fTex2fCol4b( x2 + (count - 1), y2, z2, u2, v1, col ); - part.vertices[part.vIndex.back++] = new VertexPos3fTex2fCol4b( x1, y2, z2, u1, v1, col ); - part.vertices[part.vIndex.back++] = new VertexPos3fTex2fCol4b( x1, y1, z2, u1, v2, col ); - part.vertices[part.vIndex.back++] = new VertexPos3fTex2fCol4b( x2 + (count - 1), y1, z2, u2, v2, col ); - } void DrawFrontFace( int count ) { int texId = info.textures[tile * TileSide.Sides + TileSide.Front]; int i = texId / elementsPerAtlas1D; float vOrigin = (texId % elementsPerAtlas1D) * invVerElementSize; + int offset = (lightFlags >> TileSide.Front) & 1; float u1 = minBB.X, u2 = (maxBB.X + (count - 1)) * 15.99f/16f; float v1 = vOrigin + minBB.Y * invVerElementSize; float v2 = vOrigin + maxBB.Y * invVerElementSize * 15.99f/16f; DrawInfo part = isTranslucent ? drawInfoTranslucent[i] : drawInfoNormal[i]; FastColour col = fullBright ? FastColour.White : - Z > 0 ? (Y > map.heightmap[((Z - 1) * width) + X] ? map.SunlightZSide : map.ShadowlightZSide) : map.SunlightZSide; + Z >= offset ? (Y > map.heightmap[((Z - offset) * width) + X] ? map.SunlightZSide : map.ShadowlightZSide) : map.SunlightZSide; part.vertices[part.vIndex.front++] = new VertexPos3fTex2fCol4b( x2 + (count - 1), y1, z1, u1, v2, col ); part.vertices[part.vIndex.front++] = new VertexPos3fTex2fCol4b( x1, y1, z1, u2, v2, col ); @@ -237,6 +218,25 @@ namespace ClassicalSharp { part.vertices[part.vIndex.front++] = new VertexPos3fTex2fCol4b( x2 + (count - 1), y2, z1, u1, v1, col ); } + void DrawBackFace( int count ) { + int texId = info.textures[tile * TileSide.Sides + TileSide.Back]; + int i = texId / elementsPerAtlas1D; + float vOrigin = (texId % elementsPerAtlas1D) * invVerElementSize; + int offset = (lightFlags >> TileSide.Back) & 1; + + float u1 = minBB.X, u2 = (maxBB.X + (count - 1)) * 15.99f/16f; + float v1 = vOrigin + minBB.Y * invVerElementSize; + float v2 = vOrigin + maxBB.Y * invVerElementSize * 15.99f/16f; + DrawInfo part = isTranslucent ? drawInfoTranslucent[i] : drawInfoNormal[i]; + FastColour col = fullBright ? FastColour.White : + Z <= (maxZ - offset) ? (Y > map.heightmap[((Z + offset) * width) + X] ? map.SunlightZSide : map.ShadowlightZSide) : map.SunlightZSide; + + part.vertices[part.vIndex.back++] = new VertexPos3fTex2fCol4b( x2 + (count - 1), y2, z2, u2, v1, col ); + part.vertices[part.vIndex.back++] = new VertexPos3fTex2fCol4b( x1, y2, z2, u1, v1, col ); + part.vertices[part.vIndex.back++] = new VertexPos3fTex2fCol4b( x1, y1, z2, u1, v2, col ); + part.vertices[part.vIndex.back++] = new VertexPos3fTex2fCol4b( x2 + (count - 1), y1, z2, u2, v2, col ); + } + void DrawBottomFace( int count ) { int texId = info.textures[tile * TileSide.Sides + TileSide.Bottom]; int i = texId / elementsPerAtlas1D;