From 30c4384d6697a345c69afb4a48576ac7f10a6c55 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 24 Nov 2015 09:17:16 +1100 Subject: [PATCH] Refactor block models - they rotate and use shading, also orient sprite block models correctly. Add slight bobbing up/down of in-game entities. --- ClassicalSharp/ClassicalSharp.csproj | 1 + ClassicalSharp/Entities/AnimatedEntity.cs | 3 + ClassicalSharp/Model/BlockModel.cs | 186 +++++++++++++++------- ClassicalSharp/Model/ChickenModel.cs | 4 + ClassicalSharp/Model/CreeperModel.cs | 4 + ClassicalSharp/Model/IModel.cs | 13 +- ClassicalSharp/Model/PigModel.cs | 4 + ClassicalSharp/Model/PlayerModel.cs | 4 + ClassicalSharp/Model/SheepModel.cs | 4 + ClassicalSharp/Model/SkeletonModel.cs | 4 + ClassicalSharp/Model/SpiderModel.cs | 4 + ClassicalSharp/Model/ZombieModel.cs | 4 + ClassicalSharp/Utils/FastColour.cs | 7 +- 13 files changed, 176 insertions(+), 66 deletions(-) diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index f1e080bb7..e36cb4222 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -35,6 +35,7 @@ DEBUG;TRACE; Project obj\ + wwwf df 127.0.0.1 25564 ..\output\release\ diff --git a/ClassicalSharp/Entities/AnimatedEntity.cs b/ClassicalSharp/Entities/AnimatedEntity.cs index f7a0ba413..ee8195d6b 100644 --- a/ClassicalSharp/Entities/AnimatedEntity.cs +++ b/ClassicalSharp/Entities/AnimatedEntity.cs @@ -10,6 +10,7 @@ namespace ClassicalSharp { } public float leftLegXRot, leftArmXRot, leftArmZRot; public float rightLegXRot, rightArmXRot, rightArmZRot; + public float bobYOffset; protected float walkTimeO, walkTimeN, swingO, swingN; /// Calculates the next animation state based on old and new position. @@ -49,6 +50,8 @@ namespace ClassicalSharp { leftLegXRot = -rightLegXRot; rightArmZRot = idleZRot; leftArmZRot = -idleZRot; + + bobYOffset = -(float)(Math.Abs( Math.Cos( walkTime ) ) * swing * (2/16f)); } } } \ No newline at end of file diff --git a/ClassicalSharp/Model/BlockModel.cs b/ClassicalSharp/Model/BlockModel.cs index b738c3c46..db5a29cb8 100644 --- a/ClassicalSharp/Model/BlockModel.cs +++ b/ClassicalSharp/Model/BlockModel.cs @@ -8,9 +8,17 @@ namespace ClassicalSharp.Model { public class BlockModel : IModel { byte block = (byte)Block.Air; + float blockHeight; + TerrainAtlas1D atlas; + const float adjust = 0.1f, extent = 0.5f; + public BlockModel( Game game ) : base( game ) { } + public override bool Bobbing { + get { return false; } + } + public override float NameYOffset { get { return blockHeight + 0.075f; } } @@ -20,15 +28,15 @@ namespace ClassicalSharp.Model { return block == 0 ? 1 : game.BlockInfo.Height[block]; } - const float adjust = 0.1f; public override Vector3 CollisionSize { get { return new Vector3( 1 - adjust, blockHeight - adjust, 1 - adjust ); } } public override BoundingBox PickingBounds { - get { return new BoundingBox( -scale, 0f, -scale, scale, blockHeight, scale ); } + get { return new BoundingBox( -extent, 0f, -extent, extent, blockHeight, extent ); } } + int lastTexId = -1; protected override void DrawPlayerModel( Player p ) { // TODO: using 'is' is ugly, but means we can avoid creating // a string every single time held block changes. @@ -38,87 +46,145 @@ namespace ClassicalSharp.Model { col = FastColour.Scale( baseCol, 0.8f ); block = ((FakePlayer)p).Block; } else { - block = Byte.Parse( p.ModelName ); + block = Byte.Parse( p.ModelName ); } if( block == 0 ) { blockHeight = 1; return; } - - graphics.BindTexture( game.TerrainAtlas.TexId ); + lastTexId = -1; blockHeight = game.BlockInfo.Height[block]; - atlas = game.TerrainAtlas; - BlockInfo = game.BlockInfo; + atlas = game.TerrainAtlas1D; - if( BlockInfo.IsSprite[block] ) { - float offset = TerrainAtlas2D.invElementSize / 2; - XQuad( 0f, TileSide.Right, -scale, 0, 0, -offset, false ); - ZQuad( 0f, TileSide.Back, 0, scale, offset, 0, false ); + if( game.BlockInfo.IsSprite[block] ) { + SpriteXQuad( TileSide.Right, true ); + SpriteZQuad( TileSide.Back, false ); - XQuad( 0f, TileSide.Right, 0, scale, offset, 0, false ); - ZQuad( 0f, TileSide.Back, -scale, 0, 0, -offset, false ); + SpriteXQuad( TileSide.Right, false ); + SpriteZQuad( TileSide.Back, true ); } else { - YQuad( 0f, TileSide.Bottom ); - XQuad( scale, TileSide.Left, -scale, scale, 0, 0, true ); - ZQuad( -scale, TileSide.Front, -scale, scale, 0, 0, true ); + YQuad( 0f, TileSide.Bottom, FastColour.ShadeYBottom ); + XQuad( extent, TileSide.Left, -extent, extent, true, FastColour.ShadeX ); + ZQuad( -extent, TileSide.Front, -extent, extent, true, FastColour.ShadeZ ); - ZQuad( scale, TileSide.Back, -scale, scale, 0, 0, true ); - YQuad( blockHeight, TileSide.Top ); - XQuad( -scale, TileSide.Right, -scale, scale, 0, 0, true ); + ZQuad( extent, TileSide.Back, -extent, extent, true, FastColour.ShadeZ ); + YQuad( blockHeight, TileSide.Top, 1.0f ); + XQuad( -extent, TileSide.Right, -extent, extent, true, FastColour.ShadeX ); + } + + if( index > 0 ) { + graphics.BindTexture( lastTexId ); + TransformVertices(); + graphics.UpdateDynamicIndexedVb( DrawMode.Triangles, cache.vb, cache.vertices, index, index * 6 / 4 ); } - graphics.UpdateDynamicIndexedVb( DrawMode.Triangles, cache.vb, cache.vertices, index, index * 6 / 4 ); - } - float blockHeight; - TerrainAtlas2D atlas; - BlockInfo BlockInfo; - float scale = 0.5f; - - public override void Dispose() { } - void YQuad( float y, int side ) { - int texId = BlockInfo.GetTextureLoc( block, side ); - TextureRec rec = atlas.GetAdjTexRec( texId ); - - cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y + y, pos.Z - scale, rec.U1, rec.V1, col ); - cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y + y, pos.Z - scale, rec.U2, rec.V1, col ); - cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + scale, pos.Y + y, pos.Z + scale, rec.U2, rec.V2, col ); - cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X - scale, pos.Y + y, pos.Z + scale, rec.U1, rec.V2, col ); + void YQuad( float y, int side, float shade ) { + int texId = game.BlockInfo.GetTextureLoc( block, side ), texIndex = 0; + TextureRec rec = atlas.GetTexRec( texId, 1, out texIndex ); + FlushIfNotSame( texIndex ); + FastColour col = FastColour.Scale( this.col, shade ); + + cache.vertices[index++] = new VertexPos3fTex2fCol4b( -extent, y, -extent, rec.U1, rec.V1, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( extent, y, -extent, rec.U2, rec.V1, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( extent, y, extent, rec.U2, rec.V2, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( -extent, y, extent, rec.U1, rec.V2, col ); } - void ZQuad( float z, int side, float x1, float x2, - float u1Offset, float u2Offset, bool swapU ) { - int texId = BlockInfo.GetTextureLoc( block, side ); - TextureRec rec = atlas.GetAdjTexRec( texId ); + void ZQuad( float z, int side, float x1, float x2, bool swapU, float shade ) { + int texId = game.BlockInfo.GetTextureLoc( block, side ), texIndex = 0; + TextureRec rec = atlas.GetTexRec( texId, 1, out texIndex ); + FlushIfNotSame( texIndex ); + FastColour col = FastColour.Scale( this.col, shade ); + if( blockHeight != 1 ) - rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize * (15.99f/16f); - - // need to break into two quads when drawing a sprite model in hand. + rec.V2 = rec.V1 + blockHeight * atlas.invElementSize * (15.99f/16f); if( swapU ) rec.SwapU(); - rec.U1 += u1Offset; - rec.U2 += u2Offset; - cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x1, pos.Y + 0f, pos.Z + z, rec.U1, rec.V2, col ); - cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x1, pos.Y + blockHeight, pos.Z + z, rec.U1, rec.V1, col ); - cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x2, pos.Y + blockHeight, pos.Z + z, rec.U2, rec.V1, col ); - cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x2, pos.Y + 0f, pos.Z + z, rec.U2, rec.V2, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( x1, 0f, z, rec.U1, rec.V2, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( x1, blockHeight, z, rec.U1, rec.V1, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( x2, blockHeight, z, rec.U2, rec.V1, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( x2, 0f, z, rec.U2, rec.V2, col ); } - void XQuad( float x, int side, float z1, float z2, - float u1Offset, float u2Offset, bool swapU ) { - int texId = BlockInfo.GetTextureLoc( block, side ); - TextureRec rec = atlas.GetAdjTexRec( texId ); + void XQuad( float x, int side, float z1, float z2, bool swapU, float shade ) { + int texId = game.BlockInfo.GetTextureLoc( block, side ), texIndex = 0; + TextureRec rec = atlas.GetTexRec( texId, 1, out texIndex ); + FlushIfNotSame( texIndex ); + FastColour col = FastColour.Scale( this.col, shade ); + if( blockHeight != 1 ) - rec.V2 = rec.V1 + blockHeight * TerrainAtlas2D.invElementSize * (15.99f/16f); - + rec.V2 = rec.V1 + blockHeight * atlas.invElementSize * (15.99f/16f); if( swapU ) rec.SwapU(); - rec.U1 += u1Offset; - rec.U2 += u2Offset; - cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y + 0f, pos.Z + z1, rec.U1, rec.V2, col ); - cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y + blockHeight, pos.Z + z1, rec.U1, rec.V1, col ); - cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y + blockHeight, pos.Z + z2, rec.U2, rec.V1, col ); - cache.vertices[index++] = new VertexPos3fTex2fCol4b( pos.X + x, pos.Y + 0f, pos.Z + z2, rec.U2, rec.V2, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( x, 0f, z1, rec.U1, rec.V2, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( x, blockHeight, z1, rec.U1, rec.V1, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( x, blockHeight, z2, rec.U2, rec.V1, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( x, 0f, z2, rec.U2, rec.V2, col ); + } + + void SpriteZQuad( int side, bool firstPart ) { + int texId = game.BlockInfo.GetTextureLoc( block, side ), texIndex = 0; + TextureRec rec = atlas.GetTexRec( texId, 1, out texIndex ); + FlushIfNotSame( texIndex ); + if( blockHeight != 1 ) + rec.V2 = rec.V1 + blockHeight * atlas.invElementSize * (15.99f/16f); + + float p1, p2; + if( firstPart ) { // Need to break into two quads for when drawing a sprite model in hand. + rec.U1 = 0.5f; p1 = -5.5f/16; p2 = 0.0f/16; + } else { + rec.U2 = 0.5f; p1 = 0.0f/16; p2 = 5.5f/16; + } + cache.vertices[index++] = new VertexPos3fTex2fCol4b( p1, 0f, p1, rec.U2, rec.V2, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( p1, blockHeight, p1, rec.U2, rec.V1, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( p2, blockHeight, p2, rec.U1, rec.V1, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( p2, 0f, p2, rec.U1, rec.V2, col ); + } + + void SpriteXQuad( int side, bool firstPart ) { // dis is broken + int texId = game.BlockInfo.GetTextureLoc( block, side ), texIndex = 0; + TextureRec rec = atlas.GetTexRec( texId, 1, out texIndex ); + FlushIfNotSame( texIndex ); + if( blockHeight != 1 ) + rec.V2 = rec.V1 + blockHeight * atlas.invElementSize * (15.99f/16f); + + float x1, x2, z1, z2; + if( firstPart ) { + rec.U1 = 0; rec.U2 = 0.5f; x1 = -5.5f/16; + x2 = 0.0f/16; z1 = 5.5f/16; z2 = 0.0f/16; + } else { + rec.U1 = 0.5f; rec.U2 = 1f; x1 = 0.0f/16; + x2 = 5.5f/16; z1 = 0.0f/16; z2 = -5.5f/16; + } + + cache.vertices[index++] = new VertexPos3fTex2fCol4b( x1, 0f, z1, rec.U1, rec.V2, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( x1, blockHeight, z1, rec.U1, rec.V1, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( x2, blockHeight, z2, rec.U2, rec.V1, col ); + cache.vertices[index++] = new VertexPos3fTex2fCol4b( x2, 0f, z2, rec.U2, rec.V2, col ); + } + + void FlushIfNotSame( int texIndex ) { + int texId = game.TerrainAtlas1D.TexIds[texIndex]; + if( texId == lastTexId ) return; + + if( lastTexId != -1 ) { + graphics.BindTexture( lastTexId ); + TransformVertices(); + graphics.UpdateDynamicIndexedVb( DrawMode.Triangles, cache.vb, + cache.vertices, index, index * 6 / 4 ); + } + lastTexId = texId; + index = 0; + } + + void TransformVertices() { + for( int i = 0; i < index; i++ ) { + VertexPos3fTex2fCol4b vertex = cache.vertices[i]; + Vector3 newPos = Utils.RotateY( vertex.X, vertex.Y, vertex.Z, cosA, sinA ) + pos; + vertex.X = newPos.X; vertex.Y = newPos.Y; vertex.Z = newPos.Z; + cache.vertices[i] = vertex; + } } } } \ No newline at end of file diff --git a/ClassicalSharp/Model/ChickenModel.cs b/ClassicalSharp/Model/ChickenModel.cs index cabf52a2b..62dd12552 100644 --- a/ClassicalSharp/Model/ChickenModel.cs +++ b/ClassicalSharp/Model/ChickenModel.cs @@ -32,6 +32,10 @@ namespace ClassicalSharp.Model { return new ModelPart( index - 2 * 4, 2 * 4 ); } + public override bool Bobbing { + get { return true; } + } + public override float NameYOffset { get { return 1.0125f; } } diff --git a/ClassicalSharp/Model/CreeperModel.cs b/ClassicalSharp/Model/CreeperModel.cs index c05323e5c..5c7bc5e6d 100644 --- a/ClassicalSharp/Model/CreeperModel.cs +++ b/ClassicalSharp/Model/CreeperModel.cs @@ -23,6 +23,10 @@ namespace ClassicalSharp.Model { .SetTexOrigin( 0, 16 ) ); } + public override bool Bobbing { + get { return false; } + } + public override float NameYOffset { get { return 1.7f; } } diff --git a/ClassicalSharp/Model/IModel.cs b/ClassicalSharp/Model/IModel.cs index 4f75a2f36..21c8d51a7 100644 --- a/ClassicalSharp/Model/IModel.cs +++ b/ClassicalSharp/Model/IModel.cs @@ -22,6 +22,11 @@ namespace ClassicalSharp.Model { cache = game.ModelCache; } + /// Whether the entity should be slightly bobbed up and down when rendering. + /// e.g. for players when their legs are at the peak of their swing, + /// the whole model will be moved slightly down. + public abstract bool Bobbing { get; } + /// Vertical offset from the model's feet/base that the name texture should be drawn at. public abstract float NameYOffset { get; } @@ -43,6 +48,8 @@ namespace ClassicalSharp.Model { public void RenderModel( Player p ) { index = 0; pos = p.Position; + if( Bobbing ) + pos.Y += p.bobYOffset; cosA = (float)Math.Cos( p.YawRadians ); sinA = (float)Math.Sin( p.YawRadians ); Map map = game.Map; @@ -225,11 +232,11 @@ namespace ClassicalSharp.Model { if( count != boxVertices ) return FastColour.Scale( col, 0.7f ); if( i >= 4 && i < 8 ) - return FastColour.Scale( col, 0.5f ); // y bottom + return FastColour.Scale( col, FastColour.ShadeYBottom ); if( i >= 8 && i < 16 ) - return FastColour.Scale( col, 0.8f ); // z sides + return FastColour.Scale( col, FastColour.ShadeZ ); if( i >= 16 && i < 24 ) - return FastColour.Scale( col, 0.6f ); // x sides + return FastColour.Scale( col, FastColour.ShadeX ); return col; } diff --git a/ClassicalSharp/Model/PigModel.cs b/ClassicalSharp/Model/PigModel.cs index cbddb5a78..7b44ed024 100644 --- a/ClassicalSharp/Model/PigModel.cs +++ b/ClassicalSharp/Model/PigModel.cs @@ -22,6 +22,10 @@ namespace ClassicalSharp.Model { .SetTexOrigin( 0, 16 ) ); } + public override bool Bobbing { + get { return true; } + } + public override float NameYOffset { get { return 1.075f; } } diff --git a/ClassicalSharp/Model/PlayerModel.cs b/ClassicalSharp/Model/PlayerModel.cs index e92af8e25..146e93f0f 100644 --- a/ClassicalSharp/Model/PlayerModel.cs +++ b/ClassicalSharp/Model/PlayerModel.cs @@ -39,6 +39,10 @@ namespace ClassicalSharp.Model { .SetTexOrigin( 40, 16 ) ); SetSlim.Hat = Set.Hat; } + + public override bool Bobbing { + get { return true; } + } public override float NameYOffset { get { return 2.1375f; } diff --git a/ClassicalSharp/Model/SheepModel.cs b/ClassicalSharp/Model/SheepModel.cs index 729a52fe4..a0cc58618 100644 --- a/ClassicalSharp/Model/SheepModel.cs +++ b/ClassicalSharp/Model/SheepModel.cs @@ -44,6 +44,10 @@ namespace ClassicalSharp.Model { FurRightLegBack = BuildBox( legDesc.SetModelBounds( 0.5f, 5.5f, 4.5f, 5.5f, 12.5f, 9.5f ) ); } + public override bool Bobbing { + get { return true; } + } + public override float NameYOffset { get { return Fur ? 1.48125f: 1.075f; } } diff --git a/ClassicalSharp/Model/SkeletonModel.cs b/ClassicalSharp/Model/SkeletonModel.cs index 6c600b62e..8c7cdb344 100644 --- a/ClassicalSharp/Model/SkeletonModel.cs +++ b/ClassicalSharp/Model/SkeletonModel.cs @@ -22,6 +22,10 @@ namespace ClassicalSharp.Model { .SetTexOrigin( 40, 16 ) ); } + public override bool Bobbing { + get { return true; } + } + public override float NameYOffset { get { return 2.075f; } } diff --git a/ClassicalSharp/Model/SpiderModel.cs b/ClassicalSharp/Model/SpiderModel.cs index 258a0aed0..c12e4519e 100644 --- a/ClassicalSharp/Model/SpiderModel.cs +++ b/ClassicalSharp/Model/SpiderModel.cs @@ -20,6 +20,10 @@ namespace ClassicalSharp.Model { .SetTexOrigin( 18, 0 ) ); } + public override bool Bobbing { + get { return false; } + } + public override float NameYOffset { get { return 1.0125f; } } diff --git a/ClassicalSharp/Model/ZombieModel.cs b/ClassicalSharp/Model/ZombieModel.cs index f5268149e..553cc87b5 100644 --- a/ClassicalSharp/Model/ZombieModel.cs +++ b/ClassicalSharp/Model/ZombieModel.cs @@ -21,6 +21,10 @@ namespace ClassicalSharp.Model { RightArm = BuildBox( MakeBoxBounds( 4, 12, -2, 8, 24, 2 ) .SetTexOrigin( 40, 16 ) ); } + + public override bool Bobbing { + get { return true; } + } public override float NameYOffset { get { return 2.075f; } diff --git a/ClassicalSharp/Utils/FastColour.cs b/ClassicalSharp/Utils/FastColour.cs index 3a4c2ea60..df60938ab 100644 --- a/ClassicalSharp/Utils/FastColour.cs +++ b/ClassicalSharp/Utils/FastColour.cs @@ -76,11 +76,12 @@ namespace ClassicalSharp { 191 * ((hex >> 0) & 1) + 64 * (hex >> 3) ); } + public const float ShadeX = 0.6f, ShadeZ = 0.8f, ShadeYBottom = 0.5f; public static void GetShaded( FastColour normal, ref FastColour xSide, ref FastColour zSide, ref FastColour yBottom ) { - xSide = FastColour.Scale( normal, 0.6f ); - zSide = FastColour.Scale( normal, 0.8f ); - yBottom = FastColour.Scale( normal, 0.5f ); + xSide = FastColour.Scale( normal, ShadeX ); + zSide = FastColour.Scale( normal, ShadeZ ); + yBottom = FastColour.Scale( normal, ShadeYBottom ); } public Color ToColor() {