Fix some slab lighting bugs, support the ability to define animations with an animations.txt file, partially addresses #44.

This commit is contained in:
UnknownShadow200 2015-09-13 14:17:43 +10:00
parent d5f36adc8d
commit 8659760440
8 changed files with 136 additions and 41 deletions

View File

@ -51,9 +51,9 @@ namespace ClassicalSharp {
SetBlockHeight( Block.Snow, 2/16f );
MarkTranslucent( Block.StillWater ); MarkTranslucent( Block.Water );
MarkTranslucent( Block.Ice );
MarkTransparent( Block.Glass ); MarkTransparent( Block.Leaves );
MarkTransparent( Block.Slab ); MarkTransparent( Block.Snow );
MarkTransparent( Block.CobblestoneSlab );
MarkTransparent( Block.Glass, false ); MarkTransparent( Block.Leaves, false );
MarkTransparent( Block.Slab, true ); MarkTransparent( Block.Snow, true );
MarkTransparent( Block.CobblestoneSlab, true );
MarkSprite( Block.Rose ); MarkSprite( Block.Sapling );
MarkSprite( Block.Dandelion ); MarkSprite( Block.BrownMushroom );
MarkSprite( Block.RedMushroom ); MarkSprite( Block.Rope );
@ -83,9 +83,9 @@ namespace ClassicalSharp {
canDelete[(int)Block.StillLava] = false;
}
void MarkTransparent( Block id ) {
void MarkTransparent( Block id, bool blocks ) {
isTransparent[(int)id] = true;
blocksLight[(int)id] = false;
blocksLight[(int)id] = blocks;
isOpaque[(int)id] = false;
}

View File

@ -235,7 +235,7 @@ namespace ClassicalSharp {
int texId = info.GetTextureLoc( tile, TileSide.Bottom );
int i;
TextureRectangle rec = atlas.GetTexRec( texId, count, out i );
FastColour col = Y > 0 ? ( emitsLight || (Y - 1) > map.heightmap[( Z * width ) + X] ? map.SunlightYBottom : map.ShadowlightYBottom )
FastColour col = Y > 0 ? ( emitsLight || Y > map.heightmap[( Z * width ) + X] ? map.SunlightYBottom : map.ShadowlightYBottom )
: map.SunlightYBottom;
DrawInfo part = isTranslucent ? drawInfoTranslucent[i] : drawInfoNormal[i];
@ -249,7 +249,7 @@ namespace ClassicalSharp {
int texId = info.GetTextureLoc( tile, TileSide.Top );
int i;
TextureRectangle rec = atlas.GetTexRec( texId, count, out i );
FastColour col = Y < maxY ? ( emitsLight || (Y + 1) > map.heightmap[( Z * width ) + X] ? map.Sunlight : map.Shadowlight )
FastColour col = Y < maxY ? ( emitsLight || Y > map.heightmap[( Z * width ) + X] ? map.Sunlight : map.Shadowlight )
: map.Sunlight;
DrawInfo part = isTranslucent ? drawInfoTranslucent[i] : drawInfoNormal[i];

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using ClassicalSharp.GraphicsAPI;
namespace ClassicalSharp.TexturePack {
@ -22,8 +23,6 @@ namespace ClassicalSharp.TexturePack {
Dispose();
this.bmp = bmp;
fastBmp = new FastBitmap( bmp, true );
//DefineAnimation( 14, 0, 0, 0, 16, 32, 5 ); // water
//DefineAnimation( 14, 1, 0, 16, 16, 20, 5 ); // lava
}
public void Dispose() {
@ -41,12 +40,43 @@ namespace ClassicalSharp.TexturePack {
}
}
public void DefineAnimation( int tileX, int tileY, int animX, int animY, int animSize,
public void ReadAnimationsDescription( StreamReader reader ) {
string line;
while( ( line = reader.ReadLine() ) != null ) {
if( line.Length == 0 || line[0] == '#' ) continue;
string[] parts = line.Split( ' ' );
if( parts.Length < 7 ) {
Utils.LogWarning( "Not enough arguments for animation: " + line ); continue;
}
byte tileX, tileY;
if( !Byte.TryParse( parts[0], out tileX ) || !Byte.TryParse( parts[1], out tileY )
|| tileX >= 16 || tileY >= 16 ) {
Utils.LogWarning( "Invalid animation tile coordinates: " + line ); continue;
}
int frameX, frameY;
if( !Int32.TryParse( parts[2], out frameX ) || !Int32.TryParse( parts[3], out frameY )
|| frameX < 0 || frameY < 0 ) {
Utils.LogWarning( "Invalid animation coordinates: " + line ); continue;
}
int frameSize, statesCount, tickDelay;
if( !Int32.TryParse( parts[4], out frameSize ) || !Int32.TryParse( parts[5], out statesCount ) ||
!Int32.TryParse( parts[6], out tickDelay ) || frameSize < 0 || statesCount < 0 || tickDelay < 0 ) {
Utils.LogWarning( "Invalid animation: " + line ); continue;
}
DefineAnimation( tileX, tileY, frameX, frameY, frameSize, statesCount, tickDelay );
}
}
public void DefineAnimation( int tileX, int tileY, int frameX, int frameY, int frameSize,
int statesNum, int tickDelay ) {
AnimationData data = new AnimationData();
data.TileX = tileX; data.TileY = tileY;
data.AnimX = animX; data.AnimY = animY;
data.AnimSize = animSize; data.StatesCount = statesNum;
data.FrameX = frameX; data.FrameY = frameY;
data.FrameSize = frameSize; data.StatesCount = statesNum;
data.TickDelay = tickDelay;
animations.Add( data );
}
@ -54,7 +84,6 @@ namespace ClassicalSharp.TexturePack {
unsafe void ApplyAnimation( AnimationData data ) {
data.Tick--;
if( data.Tick >= 0 ) return;
Console.WriteLine( "tick" );
data.CurrentState++;
data.CurrentState %= data.StatesCount;
data.Tick = data.TickDelay;
@ -64,16 +93,16 @@ namespace ClassicalSharp.TexturePack {
int index = atlas.Get1DIndex( texId );
int rowNum = atlas.Get1DRowId( texId );
int size = data.AnimSize;
int size = data.FrameSize;
byte* temp = stackalloc byte[size * size * 4];
FastBitmap part = new FastBitmap( size, size, size * 4, (IntPtr)temp );
FastBitmap.MovePortion( data.AnimX + data.CurrentState * size, data.AnimY, 0, 0, fastBmp, part, size );
FastBitmap.MovePortion( data.FrameX + data.CurrentState * size, data.FrameY, 0, 0, fastBmp, part, size );
api.UpdateTexturePart( atlas.TexIds[index], 0, rowNum * game.TerrainAtlas.elementSize, part );
}
class AnimationData {
public int TileX, TileY;
public int AnimX, AnimY, AnimSize;
public int FrameX, FrameY, FrameSize;
public int CurrentState;
public int StatesCount;
public int Tick, TickDelay;

View File

@ -56,9 +56,6 @@ namespace ClassicalSharp.TexturePack {
UpdateTexture( ref cache.SheepFurTexId, stream, false ); break;
case "char.png":
UpdateTexture( ref cache.HumanoidTexId, stream, true ); break;
case "animations.png":
case "animation.png":
game.Animations.SetAtlas( new Bitmap( stream ) ); break;
case "clouds.png":
case "cloud.png":
UpdateTexture( ref game.CloudsTextureId, stream, false ); break;
@ -66,6 +63,14 @@ namespace ClassicalSharp.TexturePack {
UpdateTexture( ref game.RainTextureId, stream, false ); break;
case "snow.png":
UpdateTexture( ref game.SnowTextureId, stream, false ); break;
case "animations.png":
case "animation.png":
game.Animations.SetAtlas( new Bitmap( stream ) ); break;
case "animations.txt":
case "animation.txt":
StreamReader reader = new StreamReader( stream );
game.Animations.ReadAnimationsDescription( reader );
break;
}
}

View File

@ -85,6 +85,7 @@
</Compile>
<Compile Include="MainForm.GameState.cs" />
<Compile Include="MinecraftSession.cs" />
<Compile Include="Patcher\Animations.cs" />
<Compile Include="Patcher\ResourceFetcher.cs" />
<Compile Include="Patcher\ZipWriter.cs" />
<Compile Include="Program.cs" />

View File

@ -0,0 +1,50 @@
using System;
using System.Drawing;
using System.IO;
namespace Launcher {
public partial class ResourceFetcher {
const string animationsTxt = @"# This file defines the animations used in a texture pack for ClassicCube.
# Each line is in the format: <TileX> <TileY> <FrameX> <FrameY> <Frame size> <Frames count> <Tick delay>
# - TileX and TileY indicate the coordinates of the tile in terrain.png that
# will be replaced by the animation frames. These range from 0 to 15. (inclusive of 15)
# - FrameX and FrameY indicates the pixel coordinates of the first animation frame in animations.png.
# - Frame Size indicates the size in pixels of an animation frame.
# - Frames count indicates the number of used frames. The first frame is located at
# (FrameX, FrameY), the second one at (FrameX + FrameSize, FrameY) and so on.
# - Tick delay is the number of ticks a frame doesn't change. For instance, a value of 0
# means that the frame would be changed every tick, while a value of 2 would mean
# 'replace with frame 1, don't change frame, don't change frame, replace with frame 2'.
# still water
14 0 0 0 16 32 2
# still lava
14 1 0 16 16 39 2
# fire
6 2 0 32 16 32 0";
unsafe void PatchDefault( byte[] data, int y ) {
// Sadly files in modern are 24 rgb, so we can't use fastbitmap here
using( Bitmap bmp = new Bitmap( new MemoryStream( data ) ) ) {
for( int tile = 0; tile < bmp.Height; tile += 16 ) {
CopyTile( tile, tile, y, bmp );
}
}
}
unsafe void PatchCycle( byte[] data, int y ) {
using( Bitmap bmp = new Bitmap( new MemoryStream( data ) ) ) {
int dst = 0;
for( int tile = 0; tile < bmp.Height; tile += 16, dst += 16 ) {
CopyTile( tile, dst, y, bmp );
}
// Cycle back to first frame.
for( int tile = bmp.Height - 32; tile >= 0; tile -= 16, dst += 16 ) {
CopyTile( tile, dst, y, bmp );
}
}
}
}
}

View File

@ -9,7 +9,7 @@ using ClassicalSharp.TexturePack;
namespace Launcher {
public class ResourceFetcher {
public partial class ResourceFetcher {
const string classicJarUri = "http://s3.amazonaws.com/Minecraft.Download/versions/c0.30_01c/c0.30_01c.jar";
const string modernJarUri = "http://s3.amazonaws.com/Minecraft.Download/versions/1.6.2/1.6.2.jar";
@ -36,11 +36,12 @@ namespace Launcher {
reader.Extract( srcClassic );
// Grab animations and snow
animBitmap = new Bitmap( 512, 32, PixelFormat.Format32bppArgb );
animBitmap = new Bitmap( 1024, 64, PixelFormat.Format32bppArgb );
reader.ShouldProcessZipEntry = ShouldProcessZipEntry_Modern;
reader.ProcessZipEntry = ProcessZipEntry_Modern;
reader.Extract( srcModern );
writer.WriteNewImage( animBitmap, "animations.png" );
writer.WriteNewString( animationsTxt, "animations.txt" );
animBitmap.Dispose();
writer.WriteCentralDirectoryRecords();
}
@ -76,7 +77,8 @@ namespace Launcher {
( filename == "assets/minecraft/textures/environment/snow.png" ||
filename == "assets/minecraft/textures/blocks/water_still.png" ||
filename == "assets/minecraft/textures/blocks/lava_still.png" ||
filename == "assets/minecraft/textures/entity/chicken.png" );
filename == "assets/minecraft/textures/blocks/fire_layer_1.png" ||
filename == "assets/minecraft/textures/entity/chicken.png" );
}
void ProcessZipEntry_Modern( string filename, byte[] data, ZipEntry entry ) {
@ -90,10 +92,13 @@ namespace Launcher {
writer.WriteZipEntry( entry, data );
break;
case "assets/minecraft/textures/blocks/water_still.png":
PatchAnimation( data, 0 );
PatchDefault( data, 0 );
break;
case "assets/minecraft/textures/blocks/lava_still.png":
PatchAnimation( data, 16 );
PatchCycle( data, 16 );
break;
case "assets/minecraft/textures/blocks/fire_layer_1.png":
PatchDefault( data, 32 );
break;
}
}
@ -114,16 +119,11 @@ namespace Launcher {
}
}
unsafe void PatchAnimation( byte[] data, int y ) {
// Sadly files in modern are 24 rgb, so we can't use fastbitmap here
using( Bitmap bmp = new Bitmap( new MemoryStream( data ) ) ) {
for( int tile = 0; tile < bmp.Height; tile += 16 ) {
for( int yy = 0; yy < 16; yy++ ) {
for( int xx = 0; xx < 16; xx++ ) {
animBitmap.SetPixel( tile + xx, y + yy,
bmp.GetPixel( xx, tile + yy ) );
}
}
void CopyTile( int src, int dst, int y, Bitmap bmp ) {
for( int yy = 0; yy < 16; yy++ ) {
for( int xx = 0; xx < 16; xx++ ) {
animBitmap.SetPixel( dst + xx, y + yy,
bmp.GetPixel( xx, src + yy ) );
}
}
}

View File

@ -2,6 +2,7 @@
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using ClassicalSharp.TexturePack;
namespace Launcher {
@ -22,22 +23,31 @@ namespace Launcher {
entry.CompressedDataSize = (int)entry.UncompressedDataSize;
entry.LocalHeaderOffset = (int)stream.Position;
entries[entriesCount++] = entry;
WriteLocalFileHeader( entry, data, data.Length );
WriteLocalFileEntry( entry, data, data.Length );
}
public void WriteNewImage( Bitmap bmp, string filename ) {
MemoryStream data = new MemoryStream();
bmp.Save( data, ImageFormat.Png );
byte[] buffer = data.GetBuffer();
WriteNewEntry( filename, buffer, (int)data.Length );
}
public void WriteNewString( string text, string filename ) {
byte[] data = Encoding.ASCII.GetBytes( text );
WriteNewEntry( filename, data, data.Length );
}
public void WriteNewEntry( string filename, byte[] data, int dataLength ) {
ZipEntry entry = new ZipEntry();
entry.UncompressedDataSize = (int)data.Length;
entry.Crc32 = CRC32( buffer, entry.UncompressedDataSize );
entry.CompressedDataSize = entry.UncompressedDataSize;
entry.UncompressedDataSize = dataLength;
entry.Crc32 = CRC32( data, dataLength );
entry.CompressedDataSize = dataLength;
entry.LocalHeaderOffset = (int)stream.Position;
entry.Filename = filename;
entries[entriesCount++] = entry;
WriteLocalFileHeader( entry, buffer, entry.UncompressedDataSize );
WriteLocalFileEntry( entry, data, dataLength );
}
public void WriteCentralDirectoryRecords() {
@ -49,7 +59,7 @@ namespace Launcher {
WriteEndOfCentralDirectoryRecord( (ushort)entriesCount, dirSize, dirOffset );
}
void WriteLocalFileHeader( ZipEntry entry, byte[] data, int length ) {
void WriteLocalFileEntry( ZipEntry entry, byte[] data, int length ) {
writer.Write( 0x04034b50 ); // signature
writer.Write( (ushort)20 ); // version needed
writer.Write( (ushort)8 ); // bitflags