unsafe float GetSpriteBB_RightX( int size, int tileX, int tileY, FastBitmap fastBmp ) { for( int x = size - 1; x >= 0; x-- ) { for( int y = 0; y < size; y++ ) { int* row = fastBmp.GetRowPtr( tileY * size + y ) + (tileX * size); if( (row[x] & alphaTest) != 0 ) return (float)(x + 1) / size; } } return 0; }
unsafe float GetSpriteBB_TopY( int size, int tileX, int tileY, FastBitmap fastBmp ) { for( int y = 0; y < size; y++ ) { int* row = fastBmp.GetRowPtr( tileY * size + y ) + (tileX * size); for( int x = 0; x < size; x++ ) { if( (row[x] & alphaTest) != 0 ) return 1 - (float)y / size; } } return 0; }
unsafe float GetSpriteBB_LeftX( int size, int tileX, int tileY, FastBitmap fastBmp ) { for( int x = 0; x < size; x++ ) { for( int y = 0; y < size; y++ ) { int* row = fastBmp.GetRowPtr( tileY * size + y ) + (tileX * size); if( (byte)(row[x] >> 24) != 0 ) return (float)x / size; } } return 1; }
unsafe float GetSpriteBB_BottomY( int size, int tileX, int tileY, FastBitmap fastBmp ) { for( int y = size - 1; y >= 0; y-- ) { int* row = fastBmp.GetRowPtr( tileY * size + y ) + (tileX * size); for( int x = 0; x < size; x++ ) { if( (row[x] & alphaTest) != 0 ) return 1 - (float)(y + 1) / size; } } return 1; }
internal void RecalculateBB( int block, FastBitmap fastBmp ) { int elemSize = fastBmp.Width / 16; int texId = GetTextureLoc( (byte)block, TileSide.Top ); float topY = GetSpriteBB_TopY( elemSize, texId & 0x0F, texId >> 4, fastBmp ); float bottomY = GetSpriteBB_BottomY( elemSize, texId & 0x0F, texId >> 4, fastBmp ); float leftX = GetSpriteBB_LeftX( elemSize, texId & 0x0F, texId >> 4, fastBmp ); float rightX = GetSpriteBB_RightX( elemSize, texId & 0x0F, texId >> 4, fastBmp ); MinBB[block] = Utils.RotateY( leftX - 0.5f, bottomY, 0, 45f * Utils.Deg2Rad ) + new Vector3( 0.5f, 0, 0.5f ); MaxBB[block] = Utils.RotateY( rightX - 0.5f, topY, 0, 45f * Utils.Deg2Rad ) + new Vector3( 0.5f, 0, 0.5f ); }
internal void RecalculateBB( int block, FastBitmap fastBmp ) { int elemSize = fastBmp.Width / 16; int texId = GetTextureLoc( (byte)block, Side.Top ); int texX = texId & 0x0F, texY = texId >> 4; float topY = GetSpriteBB_TopY( elemSize, texX, texY, fastBmp ); float bottomY = GetSpriteBB_BottomY( elemSize, texX, texY, fastBmp ); float leftX = GetSpriteBB_LeftX( elemSize, texX, texY, fastBmp ); float rightX = GetSpriteBB_RightX( elemSize, texX, texY, fastBmp ); MinBB[block] = Utils.RotateY( leftX - 0.5f, bottomY, 0, angle ) + centre; MaxBB[block] = Utils.RotateY( rightX - 0.5f, topY, 0, angle ) + centre; }
/// <summary> Reads a bitmap from the stream (converting it to 32 bits per pixel if necessary), /// and updates the native texture for it. </summary> public void UpdateTexture(ref int texId, byte[] data, bool setSkinType) { MemoryStream stream = new MemoryStream(data); Graphics.DeleteTexture(ref texId); using (Bitmap bmp = Platform.ReadBmp(stream)) { if (setSkinType) { DefaultPlayerSkinType = Utils.GetSkinType(bmp); } if (!FastBitmap.CheckFormat(bmp.PixelFormat)) { using (Bitmap bmp32 = Drawer2D.ConvertTo32Bpp(bmp)) texId = Graphics.CreateTexture(bmp32); } else { texId = Graphics.CreateTexture(bmp); } } }
protected void DrawBitmapTextImpl(FastBitmap dst, ref DrawTextArgs args, int x, int y) { bool underline = args.Font.Style == FontStyle.Underline; if (args.UseShadow) { int offset = ShadowOffset(args.Font.Size); DrawPart(dst, ref args, x + offset, y + offset, true); #if !LAUNCHER if (underline) { DrawUnderline(dst, x + offset, 0, ref args, true); } #endif } DrawPart(dst, ref args, x, y, false); #if !LAUNCHER if (underline) { DrawUnderline(dst, x, -2, ref args, false); } #endif }
protected void DrawBitmapTextImpl(FastBitmap dst, ref DrawTextArgs args, int x, int y) { bool ul = args.Font.Style == FontStyle.Underline; int offset = Utils.Floor(args.Font.Size) / 8; if (args.UseShadow) { DrawCore(dst, ref args, x + offset, y + offset, true); #if !LAUNCHER if (ul) { DrawUnderline(dst, ref args, x + offset, y + offset, true); } #endif } DrawCore(dst, ref args, x, y, false); #if !LAUNCHER if (ul) { DrawUnderline(dst, ref args, x, y, false); } #endif }
public void RecalculateSpriteBB( FastBitmap fastBmp ) { for( int i = 0; i < 256; i++ ) { if( IsSprite[i] ) RecalculateBB( i, fastBmp ); } }
void DrawRun(FastBitmap dst, int x, int y, int xMul, int runCount, byte *coords, int point, FastColour col) { if (runCount == 0) { return; } int srcY = (coords[0] >> 4) * boxSize; int textHeight = AdjTextSize(point), cellHeight = CellSize(textHeight); int padding = (cellHeight - textHeight) / 2; int startX = x; ushort *dstWidths = stackalloc ushort[runCount]; for (int i = 0; i < runCount; i++) { dstWidths[i] = (ushort)PtToPx(point, widths[coords[i]]); } for (int yy = 0; yy < textHeight; yy++) { int fontY = srcY + yy * boxSize / textHeight; int *fontRow = fontPixels.GetRowPtr(fontY); int dstY = y + (yy + padding); if (dstY >= dst.Height) { return; } int *dstRow = dst.GetRowPtr(dstY); int xOffset = xMul * ((textHeight - 1 - yy) / italicSize); for (int i = 0; i < runCount; i++) { int srcX = (coords[i] & 0x0F) * boxSize; int srcWidth = widths[coords[i]], dstWidth = dstWidths[i]; for (int xx = 0; xx < dstWidth; xx++) { int fontX = srcX + xx * srcWidth / dstWidth; int src = fontRow[fontX]; if ((byte)(src >> 24) == 0) { continue; } int dstX = x + xx + xOffset; if (dstX >= dst.Width) { break; } int pixel = src & ~0xFFFFFF; pixel |= ((src & 0xFF) * col.B / 255); pixel |= (((src >> 8) & 0xFF) * col.G / 255) << 8; pixel |= (((src >> 16) & 0xFF) * col.R / 255) << 16; dstRow[dstX] = pixel; } x += PtToPx(point, srcWidth + 1); } x = startX; } }
void DrawCore(FastBitmap dst, ref DrawTextArgs args, int x, int y, bool shadow) { PackedCol col = Cols['f']; if (shadow) { col = BlackTextShadows ? PackedCol.Black : PackedCol.Scale(col, 0.25f); } string text = args.Text; int point = Utils.Floor(args.Font.Size), count = 0; byte * coords = stackalloc byte[256]; PackedCol *cols = stackalloc PackedCol[256]; ushort * dstWidths = stackalloc ushort[256]; for (int i = 0; i < text.Length; i++) { char c = text[i]; if (c == '&' && ValidColCode(text, i + 1)) { col = GetCol(text[i + 1]); if (shadow) { col = BlackTextShadows ? PackedCol.Black : PackedCol.Scale(col, 0.25f); } i++; continue; // Skip over the colour code. } byte cur = Utils.UnicodeToCP437(c); coords[count] = cur; cols[count] = col; dstWidths[count] = (ushort)Width(point, cur); count++; } int dstHeight = point, startX = x; // adjust coords to make drawn text match GDI fonts int xPadding = Utils.CeilDiv(point, 8); int yPadding = (AdjHeight(dstHeight) - dstHeight) / 2; for (int yy = 0; yy < dstHeight; yy++) { int dstY = y + (yy + yPadding); if (dstY >= dst.Height) { return; } int fontY = 0 + yy * boxSize / dstHeight; int *dstRow = dst.GetRowPtr(dstY); for (int i = 0; i < count; i++) { int srcX = (coords[i] & 0x0F) * boxSize; int srcY = (coords[i] >> 4) * boxSize; int *fontRow = fontPixels.GetRowPtr(fontY + srcY); int srcWidth = widths[coords[i]], dstWidth = dstWidths[i]; col = cols[i]; for (int xx = 0; xx < dstWidth; xx++) { int fontX = srcX + xx * srcWidth / dstWidth; int src = fontRow[fontX]; if ((byte)(src >> 24) == 0) { continue; } int dstX = x + xx; if (dstX >= dst.Width) { break; } int pixel = src & ~0xFFFFFF; pixel |= ((src & 0xFF) * col.B / 255); pixel |= (((src >> 8) & 0xFF) * col.G / 255) << 8; pixel |= (((src >> 16) & 0xFF) * col.R / 255) << 16; dstRow[dstX] = pixel; } x += dstWidth + xPadding; } x = startX; } }
public static void CopyRow( int srcY, int dstY, FastBitmap src, FastBitmap dst, int width ) { int* srcRow = src.GetRowPtr( srcY ), dstRow = dst.GetRowPtr( dstY); for( int x = 0; x < width; x++ ) dstRow[x] = srcRow[x]; }
/// <summary> Updates the underlying atlas bitmap </summary> public void UpdateState() { using (FastBitmap fastBmp = new FastBitmap(AtlasBitmap, true, true)) BlockInfo.RecalculateSpriteBB(fastBmp); }
void HandleCpeDefineBlock() { byte block = reader.ReadUInt8(); BlockInfo info = game.BlockInfo; info.ResetBlockInfo( block ); info.Name[block] = reader.ReadAsciiString(); info.CollideType[block] = (BlockCollideType)reader.ReadUInt8(); if( info.CollideType[block] != BlockCollideType.Solid ) { info.IsTransparent[block] = true; info.IsOpaque[block] = false; } info.SpeedMultiplier[block] = (float)Math.Pow( 2, (reader.ReadUInt8() - 128) / 64f ); info.SetTop( reader.ReadUInt8(), (Block)block ); info.SetSide( reader.ReadUInt8(), (Block)block ); info.SetBottom( reader.ReadUInt8(), (Block)block ); info.BlocksLight[block] = reader.ReadUInt8() == 0; reader.ReadUInt8(); // walk sound, but we ignore this. info.FullBright[block] = reader.ReadUInt8() != 0; byte shape = reader.ReadUInt8(); if( shape == 2 ) { info.Height[block] = 0.5f; } else if( shape == 3 ) { // TODO: upside down slab not properly supported info.Height[block] = 0.5f; } else if( shape == 4 ) { info.IsSprite[block] = true; } if( info.IsOpaque[block] ) info.IsOpaque[block] = shape == 0; if( shape != 1 ) info.IsTransparent[block] = true; byte blockDraw = reader.ReadUInt8(); if( blockDraw == 1 ) { info.IsTransparent[block] = true; } else if( blockDraw == 2 ) { info.IsTransparent[block] = true; info.CullWithNeighbours[block] = false; } else if( blockDraw == 3 ) { info.IsTranslucent[block] = true; } if( info.IsOpaque[block] ) info.IsOpaque[block] = blockDraw == 0; byte fogDensity = reader.ReadUInt8(); info.FogDensity[block] = fogDensity == 0 ? 0 : (fogDensity + 1) / 128f; info.FogColour[block] = new FastColour( reader.ReadUInt8(), reader.ReadUInt8(), reader.ReadUInt8() ); info.SetupCullingCache(); // Update sprite BoundingBox if necessary if( info.IsSprite[block] ) { using( FastBitmap fastBmp = new FastBitmap( game.TerrainAtlas.AtlasBitmap, true ) ) { info.RecalculateBB( block, fastBmp ); } } }
protected void CheckAsyncResources() { DownloadedItem item; if (game.AsyncDownloader.TryGetItem("terrain", out item)) { if (item.Data != null) { Bitmap bmp = (Bitmap)item.Data; game.World.TextureUrl = item.Url; game.Events.RaiseTexturePackChanged(); if (!FastBitmap.CheckFormat(bmp.PixelFormat)) { Utils.LogDebug("Converting terrain atlas to 32bpp image"); game.Drawer2D.ConvertTo32Bpp(ref bmp); } if (!game.ChangeTerrainAtlas(bmp)) { bmp.Dispose(); return; } TextureCache.AddToCache(item.Url, bmp); TextureCache.AddETagToCache(item.Url, item.ETag, game.ETags); } else if (item.ResponseCode == HttpStatusCode.NotModified) { Bitmap bmp = TextureCache.GetBitmapFromCache(item.Url); if (bmp == null) // Should never happen, but handle anyways. { ExtractDefault(); } else if (item.Url != game.World.TextureUrl) { game.Events.RaiseTexturePackChanged(); if (!game.ChangeTerrainAtlas(bmp)) { bmp.Dispose(); return; } } if (bmp != null) { game.World.TextureUrl = item.Url; } } else { ExtractDefault(); } } if (game.AsyncDownloader.TryGetItem("texturePack", out item)) { if (item.Data != null) { game.World.TextureUrl = item.Url; TexturePackExtractor extractor = new TexturePackExtractor(); extractor.Extract((byte[])item.Data, game); TextureCache.AddToCache(item.Url, (byte[])item.Data); TextureCache.AddETagToCache(item.Url, item.ETag, game.ETags); } else if (item.ResponseCode == HttpStatusCode.NotModified) { byte[] data = TextureCache.GetDataFromCache(item.Url); if (data == null) // Should never happen, but handle anyways. { ExtractDefault(); } else if (item.Url != game.World.TextureUrl) { TexturePackExtractor extractor = new TexturePackExtractor(); extractor.Extract(data, game); } if (data != null) { game.World.TextureUrl = item.Url; } } else { ExtractDefault(); } } }
protected void CheckAsyncResources() { DownloadedItem item; if (game.AsyncDownloader.TryGetItem("terrain", out item)) { if (item.Data != null) { Bitmap bmp = (Bitmap)item.Data; if (!FastBitmap.CheckFormat(bmp.PixelFormat)) { Utils.LogDebug("Converting terrain atlas to 32bpp image"); game.Drawer2D.ConvertTo32Bpp(ref bmp); } game.ChangeTerrainAtlas(bmp); TextureCache.AddToCache(item.Url, bmp); game.Map.TextureUrl = item.Url; } else if (Is304Status(item.WebEx)) { Bitmap bmp = TextureCache.GetBitmapFromCache(item.Url); if (bmp == null) // Should never happen, but handle anyways. { ExtractDefault(); } else { game.ChangeTerrainAtlas(bmp); } game.Map.TextureUrl = item.Url; } else { ExtractDefault(); game.Map.TextureUrl = null; } } if (game.AsyncDownloader.TryGetItem("texturePack", out item)) { if (item.Data != null) { TexturePackExtractor extractor = new TexturePackExtractor(); extractor.Extract((byte[])item.Data, game); TextureCache.AddToCache(item.Url, (byte[])item.Data); game.Map.TextureUrl = item.Url; } else if (Is304Status(item.WebEx)) { byte[] data = TextureCache.GetDataFromCache(item.Url); if (data == null) // Should never happen, but handle anyways. { ExtractDefault(); } else { TexturePackExtractor extractor = new TexturePackExtractor(); extractor.Extract(data, game); } game.Map.TextureUrl = item.Url; } else { ExtractDefault(); game.Map.TextureUrl = null; } } }
public static void MovePortion(int srcX, int srcY, int dstX, int dstY, FastBitmap src, FastBitmap dst, int size) { for (int y = 0; y < size; y++) { int *srcRow = src.GetRowPtr(srcY + y); int *dstRow = dst.GetRowPtr(dstY + y); for (int x = 0; x < size; x++) { dstRow[dstX + x] = srcRow[srcX + x]; } } }
public void Reset(Game game) { // Reset properties for (int i = 0; i < IsTransparent.Length; i++) { IsTransparent[i] = false; } for (int i = 0; i < IsTranslucent.Length; i++) { IsTranslucent[i] = false; } for (int i = 0; i < IsOpaque.Length; i++) { IsOpaque[i] = false; } for (int i = 0; i < IsOpaqueY.Length; i++) { IsOpaqueY[i] = false; } for (int i = 0; i < IsSprite.Length; i++) { IsSprite[i] = false; } for (int i = 0; i < IsLiquid.Length; i++) { IsLiquid[i] = false; } for (int i = 0; i < BlocksLight.Length; i++) { BlocksLight[i] = false; } for (int i = 0; i < FullBright.Length; i++) { FullBright[i] = false; } for (int i = 0; i < Name.Length; i++) { Name[i] = "Invalid"; } for (int i = 0; i < FogColour.Length; i++) { FogColour[i] = default(FastColour); } for (int i = 0; i < FogDensity.Length; i++) { FogDensity[i] = 0; } for (int i = 0; i < Collide.Length; i++) { Collide[i] = CollideType.WalkThrough; } for (int i = 0; i < SpeedMultiplier.Length; i++) { SpeedMultiplier[i] = 0; } for (int i = 0; i < CullWithNeighbours.Length; i++) { CullWithNeighbours[i] = false; } for (int i = 0; i < LightOffset.Length; i++) { LightOffset[i] = 0; } for (int i = 0; i < DefinedCustomBlocks.Length; i++) { DefinedCustomBlocks[i] = 0; } // Reset textures texId = 0; for (int i = 0; i < textures.Length; i++) { textures[i] = 0; } // Reset culling for (int i = 0; i < hidden.Length; i++) { hidden[i] = 0; } for (int i = 0; i < CanStretch.Length; i++) { CanStretch[i] = false; } for (int i = 0; i < IsAir.Length; i++) { IsAir[i] = false; } // Reset bounds for (int i = 0; i < MinBB.Length; i++) { MinBB[i] = Vector3.Zero; } for (int i = 0; i < MaxBB.Length; i++) { MaxBB[i] = Vector3.One; } // Reset sounds for (int i = 0; i < DigSounds.Length; i++) { DigSounds[i] = SoundType.None; } for (int i = 0; i < StepSounds.Length; i++) { StepSounds[i] = SoundType.None; } Init(); // TODO: Make this part of TerrainAtlas2D maybe? using (FastBitmap fastBmp = new FastBitmap(game.TerrainAtlas.AtlasBitmap, true, true)) RecalculateSpriteBB(fastBmp); }