mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-10-06 04:25:05 -04:00
207 lines
8.0 KiB
C#
207 lines
8.0 KiB
C#
using System;
|
|
using ClassicalSharp.GraphicsAPI;
|
|
using ClassicalSharp.Renderers;
|
|
using OpenTK;
|
|
|
|
namespace ClassicalSharp.Model {
|
|
|
|
public class BlockModel : IModel {
|
|
|
|
byte block = (byte)Block.Air;
|
|
float blockHeight;
|
|
TerrainAtlas1D atlas;
|
|
const float extent = 0.5f, adjust = 0.5f/16f;
|
|
bool bright;
|
|
Vector3 minBB, maxBB;
|
|
|
|
public BlockModel( Game game ) : base( game ) {
|
|
}
|
|
|
|
public override bool Bobbing {
|
|
get { return false; }
|
|
}
|
|
|
|
public override float NameYOffset {
|
|
get { return blockHeight + 0.075f; }
|
|
}
|
|
|
|
public override float GetEyeY( Player player ) {
|
|
byte block = Byte.Parse( player.ModelName );
|
|
return block == 0 ? 1 : game.BlockInfo.Height[block];
|
|
}
|
|
|
|
public override Vector3 CollisionSize {
|
|
get { return (maxBB - minBB) - new Vector3( adjust ); }
|
|
}
|
|
|
|
public override BoundingBox PickingBounds {
|
|
get { return new BoundingBox( -extent, 0f, -extent, extent, blockHeight, extent ); }
|
|
}
|
|
|
|
public void CalcState( byte block ) {
|
|
if( block == 0 ) {
|
|
blockHeight = 1;
|
|
bright = false;
|
|
minBB = Vector3.Zero;
|
|
maxBB = Vector3.One;
|
|
} else {
|
|
blockHeight = game.BlockInfo.Height[block];
|
|
bright = game.BlockInfo.FullBright[block];
|
|
minBB = game.BlockInfo.MinBB[block];
|
|
maxBB = game.BlockInfo.MaxBB[block];
|
|
}
|
|
}
|
|
|
|
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.
|
|
if( p is FakePlayer ) {
|
|
Vector3I eyePos = Vector3I.Floor( game.LocalPlayer.EyePosition );
|
|
FastColour baseCol = game.Map.IsLit( eyePos ) ? game.Map.Sunlight : game.Map.Shadowlight;
|
|
col = FastColour.Scale( baseCol, 0.8f );
|
|
block = ((FakePlayer)p).Block;
|
|
} else {
|
|
block = Byte.Parse( p.ModelName );
|
|
}
|
|
|
|
CalcState( block );
|
|
if( block == 0 )
|
|
return;
|
|
lastTexId = -1;
|
|
atlas = game.TerrainAtlas1D;
|
|
|
|
if( game.BlockInfo.IsSprite[block] ) {
|
|
SpriteXQuad( TileSide.Right, true );
|
|
SpriteZQuad( TileSide.Back, false );
|
|
|
|
SpriteXQuad( TileSide.Right, false );
|
|
SpriteZQuad( TileSide.Back, true );
|
|
} else {
|
|
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( extent, TileSide.Back, -extent, extent, false, 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 );
|
|
}
|
|
}
|
|
|
|
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 = bright ? FastColour.White : 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, 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 = bright ? FastColour.White : FastColour.Scale( this.col, shade );
|
|
|
|
if( blockHeight != 1 )
|
|
rec.V2 = rec.V1 + blockHeight * atlas.invElementSize * (15.99f/16f);
|
|
if( swapU ) rec.SwapU();
|
|
|
|
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, 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 = bright ? FastColour.White : FastColour.Scale( this.col, shade );
|
|
|
|
if( blockHeight != 1 )
|
|
rec.V2 = rec.V1 + blockHeight * atlas.invElementSize * (15.99f/16f);
|
|
if( swapU ) rec.SwapU();
|
|
|
|
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);
|
|
FastColour col = bright ? FastColour.White : this.col;
|
|
|
|
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);
|
|
FastColour col = bright ? FastColour.White : this.col;
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
} |