diff --git a/Launcher2/LauncherWindow.cs b/Launcher2/LauncherWindow.cs index e167a5f3d..0a6f0f6a1 100644 --- a/Launcher2/LauncherWindow.cs +++ b/Launcher2/LauncherWindow.cs @@ -27,7 +27,7 @@ namespace Launcher { /// Whether the client drawing area needs to be redrawn/presented to the screen. public bool Dirty, pendingRedraw; - /// The specific area/region of the window that needs to be redrawn. + /// The specific area/region of the window that needs to be redrawn. public Rectangle DirtyArea; public string Username; diff --git a/src/Animations.c b/src/Animations.c index 30d345653..19c64cd10 100644 --- a/src/Animations.c +++ b/src/Animations.c @@ -213,7 +213,7 @@ static void Animations_ReadDescription(struct Stream* stream, const String* path #define ANIMS_FAST_SIZE 64 static void Animations_Draw(struct AnimationData* data, TextureLoc texLoc, int size) { int dstX = Atlas1D_Index(texLoc), srcX; - int dstY = Atlas1D_RowId(texLoc) * Atlas2D_TileSize; + int dstY = Atlas1D_RowId(texLoc) * Atlas_TileSize; GfxResourceID tex; uint8_t buffer[Bitmap_DataSize(ANIMS_FAST_SIZE, ANIMS_FAST_SIZE)]; @@ -287,7 +287,7 @@ static void Animations_Validate(void) { tileX = Atlas2D_TileX(data.TexLoc); tileY = Atlas2D_TileY(data.TexLoc); - if (data.FrameSize > Atlas2D_TileSize || tileY >= Atlas2D_RowsCount) { + if (data.FrameSize > Atlas_TileSize || tileY >= Atlas_RowsCount) { Chat_Add2("&cAnimation frames for tile (%i, %i) are bigger than the size of a tile in terrain.png", &tileX, &tileY); } else if (maxX > anims_bmp.Width || maxY > anims_bmp.Height) { Chat_Add2("&cSome of the animation frames for tile (%i, %i) are at coordinates outside animations.png", &tileX, &tileY); @@ -308,11 +308,11 @@ static void Animations_Tick(struct ScheduledTask* task) { int i, size; if (anims_useLavaAnim) { - size = min(Atlas2D_TileSize, 64); + size = min(Atlas_TileSize, 64); Animations_Draw(NULL, 30, size); } if (anims_useWaterAnim) { - size = min(Atlas2D_TileSize, 64); + size = min(Atlas_TileSize, 64); Animations_Draw(NULL, 14, size); } diff --git a/src/Block.c b/src/Block.c index efebd538e..508045fad 100644 --- a/src/Block.c +++ b/src/Block.c @@ -433,8 +433,8 @@ static float Block_GetSpriteBB_MaxY(int size, int tileX, int tileY, Bitmap* bmp) } void Block_RecalculateBB(BlockID block) { - Bitmap* bmp = &Atlas2D_Bitmap; - int tileSize = Atlas2D_TileSize; + Bitmap* bmp = &Atlas_Bitmap; + int tileSize = Atlas_TileSize; TextureLoc texLoc = Block_GetTex(block, FACE_XMAX); int x = Atlas2D_TileX(texLoc), y = Atlas2D_TileY(texLoc); @@ -442,7 +442,7 @@ void Block_RecalculateBB(BlockID block) { float minX = 0, minY = 0, maxX = 1, maxY = 1; Vector3 minRaw, maxRaw; - if (y < Atlas2D_RowsCount) { + if (y < Atlas_RowsCount) { minX = Block_GetSpriteBB_MinX(tileSize, x, y, bmp); minY = Block_GetSpriteBB_MinY(tileSize, x, y, bmp); maxX = Block_GetSpriteBB_MaxX(tileSize, x, y, bmp); diff --git a/src/Chat.c b/src/Chat.c index 937cfb229..73006adf4 100644 --- a/src/Chat.c +++ b/src/Chat.c @@ -15,7 +15,13 @@ #include "EnvRenderer.h" #include "GameStructs.h" -struct ChatLine Chat_Status[3], Chat_BottomRight[3], Chat_ClientStatus[3], Chat_Announcement; +static char msgs[10][STRING_SIZE]; +String Chat_Status[3] = { String_FromArray(msgs[0]), String_FromArray(msgs[1]), String_FromArray(msgs[2]) }; +String Chat_BottomRight[3] = { String_FromArray(msgs[3]), String_FromArray(msgs[4]), String_FromArray(msgs[5]) }; +String Chat_ClientStatus[3] = { String_FromArray(msgs[6]), String_FromArray(msgs[7]), String_FromArray(msgs[8]) }; + +String Chat_Announcement = String_FromArray(msgs[9]); +TimeMS Chat_AnnouncementReceived; StringsBuffer Chat_Log, Chat_InputLog; /*########################################################################################################################* @@ -146,12 +152,6 @@ static void Chat_AppendLog(const String* text) { Chat_LogError2(res, "writing to", &Chat_LogPath); } -static void ChatLine_Make(struct ChatLine* line, const String* text) { - String dst = String_ClearedArray(line->Buffer); - String_AppendString(&dst, text); - line->Received = DateTime_CurrentUTC_MS(); -} - void Chat_LogError(ReturnCode result, const char* place) { Chat_Add4("&cError %h when %c", &result, place, NULL, NULL); } @@ -189,13 +189,14 @@ void Chat_AddOf(const String* text, MsgType type) { Chat_AppendLog(text); Chat_AppendLogTime(); } else if (type >= MSG_TYPE_STATUS_1 && type <= MSG_TYPE_STATUS_3) { - ChatLine_Make(&Chat_Status[type - MSG_TYPE_STATUS_1], text); + String_Copy(&Chat_Status[type - MSG_TYPE_STATUS_1], text); } else if (type >= MSG_TYPE_BOTTOMRIGHT_1 && type <= MSG_TYPE_BOTTOMRIGHT_3) { - ChatLine_Make(&Chat_BottomRight[type - MSG_TYPE_BOTTOMRIGHT_1], text); + String_Copy(&Chat_BottomRight[type - MSG_TYPE_BOTTOMRIGHT_1], text); } else if (type == MSG_TYPE_ANNOUNCEMENT) { - ChatLine_Make(&Chat_Announcement, text); + String_Copy(&Chat_Announcement, text); + Chat_AnnouncementReceived = DateTime_CurrentUTC_MS(); } else if (type >= MSG_TYPE_CLIENTSTATUS_1 && type <= MSG_TYPE_CLIENTSTATUS_3) { - ChatLine_Make(&Chat_ClientStatus[type - MSG_TYPE_CLIENTSTATUS_1], text); + String_Copy(&Chat_ClientStatus[type - MSG_TYPE_CLIENTSTATUS_1], text); } } diff --git a/src/Chat.h b/src/Chat.h index 26eda2384..fb6164e4c 100644 --- a/src/Chat.h +++ b/src/Chat.h @@ -23,9 +23,10 @@ typedef enum MsgType_ { MSG_TYPE_CLIENTSTATUS_3 = 258 /* Tab list matching names*/ } MsgType; -struct ChatLine { char Buffer[STRING_SIZE]; TimeMS Received; }; -extern struct ChatLine Chat_Status[3], Chat_BottomRight[3], Chat_ClientStatus[3], Chat_Announcement; +extern String Chat_Status[3], Chat_BottomRight[3], Chat_ClientStatus[3], Chat_Announcement; extern StringsBuffer Chat_Log, Chat_InputLog; + +extern TimeMS Chat_AnnouncementReceived; /* Gets the time the ith chat message was received at. */ TimeMS Chat_GetLogTime(int i); diff --git a/src/EnvRenderer.c b/src/EnvRenderer.c index 0a56b656a..b933c6a73 100644 --- a/src/EnvRenderer.c +++ b/src/EnvRenderer.c @@ -580,7 +580,7 @@ static void EnvRenderer_MakeBorderTex(GfxResourceID* texId, BlockID block) { if (Gfx_LostContext) return; Gfx_DeleteTexture(texId); - *texId = Atlas2D_LoadTile(loc); + *texId = Atlas_LoadTile(loc); } static Rect2D EnvRenderer_Rect(int x, int y, int width, int height) { diff --git a/src/Game.c b/src/Game.c index d7bc8450a..924a8a454 100644 --- a/src/Game.c +++ b/src/Game.c @@ -157,10 +157,8 @@ bool Game_ChangeTerrainAtlas(Bitmap* atlas) { } if (Gfx_LostContext) return false; - Atlas1D_Free(); - Atlas2D_Free(); - Atlas2D_UpdateState(atlas); - Atlas1D_UpdateState(); + Atlas_Free(); + Atlas_Update(atlas); Event_RaiseVoid(&TextureEvents_AtlasChanged); return true; @@ -709,8 +707,7 @@ static void Game_RenderFrame(double delta) { void Game_Free(void* obj) { struct IGameComponent* comp; - Atlas2D_Free(); - Atlas1D_Free(); + Atlas_Free(); Event_UnregisterVoid(&WorldEvents_NewMap, NULL, Game_OnNewMapCore); Event_UnregisterVoid(&WorldEvents_MapLoaded, NULL, Game_OnNewMapLoadedCore); diff --git a/src/Game.h b/src/Game.h index c4256755b..15c0a861f 100644 --- a/src/Game.h +++ b/src/Game.h @@ -86,7 +86,8 @@ void Game_Reset(void); /* (updating state means recalculating light, redrawing chunk block is in, etc) */ /* NOTE: This does NOT notify the server, use Game_ChangeBlock for that. */ CC_EXPORT void Game_UpdateBlock(int x, int y, int z, BlockID block); -/* Calls Game_UpdateBlock, then sends the block change to the server. */ +/* Calls Game_UpdateBlock, then informs server connection of the block change. */ +/* In multiplayer this is sent to the server, in singleplayer just activates physics. */ CC_EXPORT void Game_ChangeBlock(int x, int y, int z, BlockID block); bool Game_CanPick(BlockID block); bool Game_UpdateTexture(GfxResourceID* texId, struct Stream* src, const String* file, uint8_t* skinType); diff --git a/src/Lighting.h b/src/Lighting.h index a8fbf1752..e3b728c22 100644 --- a/src/Lighting.h +++ b/src/Lighting.h @@ -17,19 +17,19 @@ extern int16_t* Lighting_Heightmap; * CalcLight(x, maxY, z) */ void Lighting_LightHint(int startX, int startZ); -/* Called when a block is changed, to update the lighting information. -NOTE: Implementations ***MUST*** mark all chunks affected by this lighting changeas needing to be refreshed. */ +/* Called when a block is changed, to update the lighting information. */ +/* NOTE: Implementations ***MUST*** mark all chunks affected by this lighting changeas needing to be refreshed. */ void Lighting_OnBlockChanged(int x, int y, int z, BlockID oldBlock, BlockID newBlock); void Lighting_Refresh(void); -/* Returns whether the block at the given coordinates is fully in sunlight. -NOTE: Does ***NOT*** check that the coordinates are inside the map. */ +/* Returns whether the block at the given coordinates is fully in sunlight. */ +/* NOTE: Does ***NOT*** check that the coordinates are inside the map. */ bool Lighting_IsLit(int x, int y, int z); -/* Returns the light colour of the block at the given coordinates. -NOTE: Does ***NOT*** check that the coordinates are inside the map. */ +/* Returns the light colour of the block at the given coordinates. */ +/* NOTE: Does ***NOT*** check that the coordinates are inside the map. */ PackedCol Lighting_Col(int x, int y, int z); -/* Returns the light colour of the block at the given coordinates. -NOTE: Does ***NOT*** check that the coordinates are inside the map. */ +/* Returns the light colour of the block at the given coordinates. */ +/* NOTE: Does ***NOT*** check that the coordinates are inside the map. */ PackedCol Lighting_Col_XSide(int x, int y, int z); PackedCol Lighting_Col_Sprite_Fast(int x, int y, int z); diff --git a/src/MapRenderer.c b/src/MapRenderer.c index fc28726bb..87265a4a5 100644 --- a/src/MapRenderer.c +++ b/src/MapRenderer.c @@ -67,6 +67,16 @@ void ChunkInfo_Reset(struct ChunkInfo* chunk, int x, int y, int z) { chunk->TranslucentParts = NULL; } +CC_NOINLINE static int MapRenderer_UsedAtlases(void) { + TextureLoc maxLoc = 0; + int i; + + for (i = 0; i < Array_Elems(Block_Textures); i++) { + maxLoc = max(maxLoc, Block_Textures[i]); + } + return Atlas1D_Index(maxLoc) + 1; +} + /*########################################################################################################################* *-------------------------------------------------------Map rendering-----------------------------------------------------* @@ -386,7 +396,7 @@ void MapRenderer_Refresh(void) { MapRenderer_ResetChunks(); oldCount = MapRenderer_1DUsedCount; - MapRenderer_1DUsedCount = Atlas1D_UsedAtlasesCount(); + MapRenderer_1DUsedCount = MapRenderer_UsedAtlases(); /* Need to reallocate parts array in this case */ if (MapRenderer_1DUsedCount != oldCount) { MapRenderer_FreeParts(); @@ -693,14 +703,14 @@ static void MapRenderer_TerrainAtlasChanged(void* obj) { if (refreshRequired) MapRenderer_Refresh(); } - MapRenderer_1DUsedCount = Atlas1D_UsedAtlasesCount(); + MapRenderer_1DUsedCount = MapRenderer_UsedAtlases(); elementsPerBitmap = Atlas1D_TilesPerAtlas; MapRenderer_ResetPartFlags(); } static void MapRenderer_BlockDefinitionChanged(void* obj) { MapRenderer_Refresh(); - MapRenderer_1DUsedCount = Atlas1D_UsedAtlasesCount(); + MapRenderer_1DUsedCount = MapRenderer_UsedAtlases(); MapRenderer_ResetPartFlags(); } diff --git a/src/MapRenderer.h b/src/MapRenderer.h index 5064ab9c6..9cd9c0eb6 100644 --- a/src/MapRenderer.h +++ b/src/MapRenderer.h @@ -14,7 +14,7 @@ extern int MapRenderer_ChunksX, MapRenderer_ChunksY, MapRenderer_ChunksZ; #define MapRenderer_Pack(cx, cy, cz) (((cz) * MapRenderer_ChunksY + (cy)) * MapRenderer_ChunksX + (cx)) /* TODO: Swap Y and Z? Make sure to update ChunkUpdater's ResetChunkCache and ClearChunkCache methods! */ -/* Count of actual used 1D atlases. (i.e. 1DIndex(maxTextureLoc) + 1 */ +/* Max used 1D atlases. (i.e. Atlas1D_Index(maxTextureLoc) + 1) */ extern int MapRenderer_1DUsedCount; /* Number of chunks in the world, or ChunksX * ChunksY * ChunksZ */ extern int MapRenderer_ChunksCount; diff --git a/src/Menus.c b/src/Menus.c index 23f7203ac..0f5e68740 100644 --- a/src/Menus.c +++ b/src/Menus.c @@ -2963,7 +2963,7 @@ static void TexIdsOverlay_ContextRecreated(void* screen) { s->DynamicVb = Gfx_CreateDynamicVb(VERTEX_FORMAT_P3FT2FC4B, TEXID_OVERLAY_VERTICES_COUNT); TextAtlas_Make(&s->IdAtlas, &chars, &s->TextFont, &prefix); - s->XOffset = Gui_CalcPos(ANCHOR_CENTRE, 0, size * Atlas2D_RowsCount, Game_Width); + s->XOffset = Gui_CalcPos(ANCHOR_CENTRE, 0, size * Atlas_RowsCount, Game_Width); s->YOffset = Gui_CalcPos(ANCHOR_CENTRE, 0, size * ATLAS2D_TILES_PER_ROW, Game_Height); s->TileSize = size; @@ -3050,7 +3050,7 @@ static void TexIdsOverlay_Render(void* screen, double delta) { origXOffset = s->XOffset; s->BaseTexLoc = 0; - for (rows = Atlas2D_RowsCount; rows > 0; rows -= ATLAS2D_TILES_PER_ROW) { + for (rows = Atlas_RowsCount; rows > 0; rows -= ATLAS2D_TILES_PER_ROW) { TexIdsOverlay_RenderTerrain(s); TexIdsOverlay_RenderTextOverlay(s); diff --git a/src/Screens.c b/src/Screens.c index dab50deb5..8463d791b 100644 --- a/src/Screens.c +++ b/src/Screens.c @@ -782,26 +782,23 @@ static void ChatScreen_ConstructWidgets(struct ChatScreen* s) { } static void ChatScreen_SetInitialMessages(struct ChatScreen* s) { - String msg; int i; s->ChatIndex = Chat_Log.Count - Game_ChatLines; ChatScreen_ResetChat(s); -#define ChatScreen_Set(group, idx, src) msg = String_FromRawArray(src.Buffer); TextGroupWidget_SetText(group, idx, &msg); - ChatScreen_Set(&s->Status, 2, Chat_Status[0]); - ChatScreen_Set(&s->Status, 3, Chat_Status[1]); - ChatScreen_Set(&s->Status, 4, Chat_Status[2]); + TextGroupWidget_SetText(&s->Status, 2, &Chat_Status[0]); + TextGroupWidget_SetText(&s->Status, 3, &Chat_Status[1]); + TextGroupWidget_SetText(&s->Status, 4, &Chat_Status[2]); - ChatScreen_Set(&s->BottomRight, 2, Chat_BottomRight[0]); - ChatScreen_Set(&s->BottomRight, 1, Chat_BottomRight[1]); - ChatScreen_Set(&s->BottomRight, 0, Chat_BottomRight[2]); + TextGroupWidget_SetText(&s->BottomRight, 2, &Chat_BottomRight[0]); + TextGroupWidget_SetText(&s->BottomRight, 1, &Chat_BottomRight[1]); + TextGroupWidget_SetText(&s->BottomRight, 0, &Chat_BottomRight[2]); - msg = String_FromRawArray(Chat_Announcement.Buffer); - TextWidget_Set(&s->Announcement, &msg, &s->AnnouncementFont); + TextWidget_Set(&s->Announcement, &Chat_Announcement, &s->AnnouncementFont); for (i = 0; i < s->ClientStatus.LinesCount; i++) { - ChatScreen_Set(&s->ClientStatus, i, Chat_ClientStatus[i]); + TextGroupWidget_SetText(&s->ClientStatus, i, &Chat_ClientStatus[i]); } if (s->HandlesAllInput) { @@ -1167,7 +1164,7 @@ static void ChatScreen_Render(void* screen, double delta) { } } - if (s->Announcement.Texture.ID && now > Chat_Announcement.Received + (5 * 1000)) { + if (s->Announcement.Texture.ID && now > Chat_AnnouncementReceived + (5 * 1000)) { Elem_TryFree(&s->Announcement); } } diff --git a/src/TerrainAtlas.c b/src/TerrainAtlas.c index da15226ce..3f591de84 100644 --- a/src/TerrainAtlas.c +++ b/src/TerrainAtlas.c @@ -5,54 +5,13 @@ #include "Graphics.h" #include "Platform.h" -Bitmap Atlas2D_Bitmap; -int Atlas2D_TileSize, Atlas2D_RowsCount; +Bitmap Atlas_Bitmap; +int Atlas_TileSize, Atlas_RowsCount; int Atlas1D_Count, Atlas1D_TilesPerAtlas; int Atlas1D_Mask, Atlas1D_Shift; float Atlas1D_InvTileSize; GfxResourceID Atlas1D_TexIds[ATLAS1D_MAX_ATLASES]; -void Atlas2D_UpdateState(Bitmap* bmp) { - Atlas2D_Bitmap = *bmp; - Atlas2D_TileSize = bmp->Width / ATLAS2D_TILES_PER_ROW; - Atlas2D_RowsCount = bmp->Height / Atlas2D_TileSize; - Atlas2D_RowsCount = min(Atlas2D_RowsCount, ATLAS2D_MAX_ROWS_COUNT); - Block_RecalculateAllSpriteBB(); -} - -static GfxResourceID Atlas2D_LoadTextureElement_Raw(TextureLoc texLoc, Bitmap* element) { - int size = Atlas2D_TileSize; - int x = Atlas2D_TileX(texLoc), y = Atlas2D_TileY(texLoc); - if (y >= Atlas2D_RowsCount) return GFX_NULL; - - Bitmap_CopyBlock(x * size, y * size, 0, 0, &Atlas2D_Bitmap, element, size); - return Gfx_CreateTexture(element, false, Gfx_Mipmaps); -} - -GfxResourceID Atlas2D_LoadTile(TextureLoc texLoc) { - int tileSize = Atlas2D_TileSize; - Bitmap tile; - GfxResourceID texId; - uint8_t scan0[Bitmap_DataSize(64, 64)]; - - /* Try to allocate bitmap on stack if possible */ - if (tileSize > 64) { - Bitmap_Allocate(&tile, tileSize, tileSize); - texId = Atlas2D_LoadTextureElement_Raw(texLoc, &tile); - Mem_Free(tile.Scan0); - return texId; - } else { - Bitmap_Create(&tile, tileSize, tileSize, scan0); - return Atlas2D_LoadTextureElement_Raw(texLoc, &tile); - } -} - -void Atlas2D_Free(void) { - Mem_Free(Atlas2D_Bitmap.Scan0); - Atlas2D_Bitmap.Scan0 = NULL; -} - - TextureRec Atlas1D_TexRec(TextureLoc texLoc, int uCount, int* index) { TextureRec rec; int y = Atlas1D_RowId(texLoc); @@ -66,60 +25,88 @@ TextureRec Atlas1D_TexRec(TextureLoc texLoc, int uCount, int* index) { return rec; } -static void Atlas1D_Convert2DTo1D(int atlasesCount, int atlas1DHeight) { - int tileSize = Atlas2D_TileSize; +static void Atlas_Convert2DTo1D(void) { + int tileSize = Atlas_TileSize; + int tilesPerAtlas = Atlas1D_TilesPerAtlas; + int atlasesCount = Atlas1D_Count; Bitmap atlas1D; int atlasX, atlasY; int tile = 0, i, y; - Atlas1D_Count = atlasesCount; - Platform_Log2("Loaded new atlas: %i bmps, %i per bmp", &atlasesCount, &Atlas1D_TilesPerAtlas); - Bitmap_Allocate(&atlas1D, tileSize, atlas1DHeight); + Platform_Log2("Loaded new atlas: %i bmps, %i per bmp", &atlasesCount, &tilesPerAtlas); + Bitmap_Allocate(&atlas1D, tileSize, tilesPerAtlas * tileSize); for (i = 0; i < atlasesCount; i++) { - for (y = 0; y < Atlas1D_TilesPerAtlas; y++, tile++) { + for (y = 0; y < tilesPerAtlas; y++, tile++) { atlasX = Atlas2D_TileX(tile) * tileSize; atlasY = Atlas2D_TileY(tile) * tileSize; Bitmap_CopyBlock(atlasX, atlasY, 0, y * tileSize, - &Atlas2D_Bitmap, &atlas1D, tileSize); + &Atlas_Bitmap, &atlas1D, tileSize); } Atlas1D_TexIds[i] = Gfx_CreateTexture(&atlas1D, true, Gfx_Mipmaps); } Mem_Free(atlas1D.Scan0); } -void Atlas1D_UpdateState(void) { +static void Atlas_Update1D(void) { int maxAtlasHeight, maxTilesPerAtlas, maxTiles; - int atlasesCount, atlasHeight; maxAtlasHeight = min(4096, Gfx_MaxTexHeight); - maxTilesPerAtlas = maxAtlasHeight / Atlas2D_TileSize; - maxTiles = Atlas2D_RowsCount * ATLAS2D_TILES_PER_ROW; + maxTilesPerAtlas = maxAtlasHeight / Atlas_TileSize; + maxTiles = Atlas_RowsCount * ATLAS2D_TILES_PER_ROW; Atlas1D_TilesPerAtlas = min(maxTilesPerAtlas, maxTiles); - atlasesCount = Math_CeilDiv(maxTiles, Atlas1D_TilesPerAtlas); - atlasHeight = Atlas1D_TilesPerAtlas * Atlas2D_TileSize; + Atlas1D_Count = Math_CeilDiv(maxTiles, Atlas1D_TilesPerAtlas); Atlas1D_InvTileSize = 1.0f / Atlas1D_TilesPerAtlas; Atlas1D_Mask = Atlas1D_TilesPerAtlas - 1; Atlas1D_Shift = Math_Log2(Atlas1D_TilesPerAtlas); - - Atlas1D_Convert2DTo1D(atlasesCount, atlasHeight); } -int Atlas1D_UsedAtlasesCount(void) { - TextureLoc maxLoc = 0; - int i; +void Atlas_Update(Bitmap* bmp) { + Atlas_Bitmap = *bmp; + Atlas_TileSize = bmp->Width / ATLAS2D_TILES_PER_ROW; + Atlas_RowsCount = bmp->Height / Atlas_TileSize; + Atlas_RowsCount = min(Atlas_RowsCount, ATLAS2D_MAX_ROWS_COUNT); - for (i = 0; i < Array_Elems(Block_Textures); i++) { - maxLoc = max(maxLoc, Block_Textures[i]); + Block_RecalculateAllSpriteBB(); + Atlas_Update1D(); + Atlas_Convert2DTo1D(); +} + +static GfxResourceID Atlas_LoadTile_Raw(TextureLoc texLoc, Bitmap* element) { + int size = Atlas_TileSize; + int x = Atlas2D_TileX(texLoc), y = Atlas2D_TileY(texLoc); + if (y >= Atlas_RowsCount) return GFX_NULL; + + Bitmap_CopyBlock(x * size, y * size, 0, 0, &Atlas_Bitmap, element, size); + return Gfx_CreateTexture(element, false, Gfx_Mipmaps); +} + +GfxResourceID Atlas_LoadTile(TextureLoc texLoc) { + int tileSize = Atlas_TileSize; + Bitmap tile; + GfxResourceID texId; + uint8_t scan0[Bitmap_DataSize(64, 64)]; + + /* Try to allocate bitmap on stack if possible */ + if (tileSize > 64) { + Bitmap_Allocate(&tile, tileSize, tileSize); + texId = Atlas_LoadTile_Raw(texLoc, &tile); + Mem_Free(tile.Scan0); + return texId; + } else { + Bitmap_Create(&tile, tileSize, tileSize, scan0); + return Atlas_LoadTile_Raw(texLoc, &tile); } - return Atlas1D_Index(maxLoc) + 1; } -void Atlas1D_Free(void) { +void Atlas_Free(void) { int i; + Mem_Free(Atlas_Bitmap.Scan0); + Atlas_Bitmap.Scan0 = NULL; + for (i = 0; i < Atlas1D_Count; i++) { Gfx_DeleteTexture(&Atlas1D_TexIds[i]); } diff --git a/src/TerrainAtlas.h b/src/TerrainAtlas.h index ed7a4763f..23bb5cf55 100644 --- a/src/TerrainAtlas.h +++ b/src/TerrainAtlas.h @@ -5,21 +5,36 @@ Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 */ +/* Number of tiles in each row */ #define ATLAS2D_TILES_PER_ROW 16 #define ATLAS2D_MASK 15 #define ATLAS2D_SHIFT 4 +/* Maximum supported number of rows in the atlas. */ #ifdef EXTENDED_TEXTURES #define ATLAS2D_MAX_ROWS_COUNT 32 #else #define ATLAS2D_MAX_ROWS_COUNT 16 #endif +/* Maximum possible number of 1D terrain atlases. (worst case, each 1D atlas only has 1 tile) */ #define ATLAS1D_MAX_ATLASES (ATLAS2D_TILES_PER_ROW * ATLAS2D_MAX_ROWS_COUNT) -extern Bitmap Atlas2D_Bitmap; -extern int Atlas2D_TileSize, Atlas2D_RowsCount; -extern int Atlas1D_Count, Atlas1D_TilesPerAtlas; +/* Bitmap that contains the textures of all tiles. */ +/* Tiles are indexed left to right, top to bottom. */ +extern Bitmap Atlas_Bitmap; +/* Size of each tile in pixels. (default 16x16) */ +extern int Atlas_TileSize; +/* Number of rows in the atlas. (default 16, can be 32) */ +extern int Atlas_RowsCount; +/* Number of 1D atlases the atlas was split into. */ +extern int Atlas1D_Count; +/* Number of tiles in each 1D atlas. */ +extern int Atlas1D_TilesPerAtlas; +/* Converts a tile id into 1D atlas index, and index within that atlas. */ extern int Atlas1D_Mask, Atlas1D_Shift; +/* Texture V coord that equals the size of one tile. (i.e. 1/Atlas1D_TilesPerAtlas) */ +/* NOTE: The texture U coord that equals the size of one tile is 1. */ extern float Atlas1D_InvTileSize; +/* Textures for each 1D atlas. Only Atlas1D_Count of these are valid. */ extern GfxResourceID Atlas1D_TexIds[ATLAS1D_MAX_ATLASES]; #define Atlas2D_TileX(texLoc) ((texLoc) & ATLAS2D_MASK) /* texLoc % ATLAS2D_TILES_PER_ROW */ @@ -29,11 +44,15 @@ extern GfxResourceID Atlas1D_TexIds[ATLAS1D_MAX_ATLASES]; /* Returns the index of the 1D atlas within the array of 1D atlases that contains the given tile id */ #define Atlas1D_Index(texLoc) ((texLoc) >> Atlas1D_Shift) /* texLoc / Atlas1D_TilesPerAtlas */ -void Atlas2D_UpdateState(Bitmap* bmp); -GfxResourceID Atlas2D_LoadTile(TextureLoc texLoc); -void Atlas2D_Free(void); +/* Loads the given atlas and converts it into an array of 1D atlases. */ +/* NOTE: Use Game_ChangeTerrainAtlas to change atlas, because that raises TextureEvents_AtlasChanged */ +void Atlas_Update(Bitmap* bmp); +/* Loads the given tile into a new separate texture. */ +GfxResourceID Atlas_LoadTile(TextureLoc texLoc); +/* Frees the atlas and 1D atlas textures. */ +void Atlas_Free(void); +/* Returns the UV rectangle of the given tile id in the 1D atlases. */ +/* That is, returns U1/U2/V1/V2 coords that make up the tile in a 1D atlas. */ +/* index is set to the index of the 1D atlas that the tile is in. */ TextureRec Atlas1D_TexRec(TextureLoc texLoc, int uCount, int* index); -void Atlas1D_UpdateState(void); -int Atlas1D_UsedAtlasesCount(void); -void Atlas1D_Free(void); #endif