Make Textures a component too, move some texture specific out of Game.c and into TexturePack.c

This commit is contained in:
UnknownShadow200 2020-06-26 22:37:14 +10:00
parent 664428682c
commit dcc6a12946
4 changed files with 82 additions and 68 deletions

View File

@ -91,29 +91,6 @@ int ScheduledTask_Add(double interval, ScheduledTaskCallback callback) {
}
cc_bool Game_ChangeTerrainAtlas(Bitmap* atlas) {
static const String terrain = String_FromConst("terrain.png");
if (!Game_ValidateBitmap(&terrain, atlas)) return false;
if (atlas->Height < atlas->Width) {
Chat_AddRaw("&cUnable to use terrain.png from the texture pack.");
Chat_AddRaw("&c Its height is less than its width.");
return false;
}
if (atlas->Width < ATLAS2D_TILES_PER_ROW) {
Chat_AddRaw("&cUnable to use terrain.png from the texture pack.");
Chat_AddRaw("&c It must be 16 or more pixels wide.");
return false;
}
if (Gfx.LostContext) return false;
Atlas_Free();
Atlas_Update(atlas);
Event_RaiseVoid(&TextureEvents.AtlasChanged);
return true;
}
void Game_SetViewDistance(int distance) {
distance = min(distance, Game_MaxViewDistance);
if (distance == Game_ViewDistance) return;
@ -260,22 +237,6 @@ static void HandleOnNewMapLoaded(void* obj) {
}
}
static void HandleTextureChanged(void* obj, struct Stream* src, const String* name) {
Bitmap bmp;
cc_result res;
if (String_CaselessEqualsConst(name, "terrain.png")) {
res = Png_Decode(&bmp, src);
if (res) {
Logger_Warn2(res, "decoding", name);
Mem_Free(bmp.Scan0);
} else if (!Game_ChangeTerrainAtlas(&bmp)) {
Mem_Free(bmp.Scan0);
}
}
}
static void HandleLowVRAMDetected(void* obj) {
if (Game_UserViewDistance <= 16) Logger_Abort("Out of video memory!");
Game_UserViewDistance /= 2;
@ -372,16 +333,12 @@ static void Game_Load(void) {
Gfx_Init();
LoadOptions();
Event_RegisterVoid(&WorldEvents.NewMap, NULL, HandleOnNewMap);
Event_RegisterVoid(&WorldEvents.MapLoaded, NULL, HandleOnNewMapLoaded);
Event_RegisterEntry(&TextureEvents.FileChanged, NULL, HandleTextureChanged);
Event_RegisterVoid(&GfxEvents.LowVRAMDetected, NULL, HandleLowVRAMDetected);
Event_RegisterVoid(&WorldEvents.NewMap, NULL, HandleOnNewMap);
Event_RegisterVoid(&WorldEvents.MapLoaded, NULL, HandleOnNewMapLoaded);
Event_RegisterVoid(&GfxEvents.LowVRAMDetected, NULL, HandleLowVRAMDetected);
Event_RegisterVoid(&WindowEvents.Resized, NULL, Game_OnResize);
Event_RegisterVoid(&WindowEvents.Closing, NULL, Game_Free);
TextureCache_Init();
/* TODO: Survival vs Creative game mode */
Event_RegisterVoid(&WindowEvents.Resized, NULL, Game_OnResize);
Event_RegisterVoid(&WindowEvents.Closing, NULL, Game_Free);
InputHandler_Init();
Game_AddComponent(&Blocks_Component);
@ -398,6 +355,7 @@ static void Game_Load(void) {
Game_AddComponent(&Animations_Component);
Game_AddComponent(&Inventory_Component);
Game_AddComponent(&Textures_Component);
World_Reset();
Game_AddComponent(&Builder_Component);
@ -602,16 +560,16 @@ static void Game_RenderFrame(double delta) {
void Game_Free(void* obj) {
struct IGameComponent* comp;
Atlas_Free();
/* Most components will call OnContextLost in their Free functions */
/* Set to false so components will always free managed textures too */
Gfx.ManagedTextures = false;
Event_UnregisterVoid(&WorldEvents.NewMap, NULL, HandleOnNewMap);
Event_UnregisterVoid(&WorldEvents.MapLoaded, NULL, HandleOnNewMapLoaded);
Event_UnregisterEntry(&TextureEvents.FileChanged, NULL, HandleTextureChanged);
Event_UnregisterVoid(&GfxEvents.LowVRAMDetected, NULL, HandleLowVRAMDetected);
Event_UnregisterVoid(&WorldEvents.NewMap, NULL, HandleOnNewMap);
Event_UnregisterVoid(&WorldEvents.MapLoaded, NULL, HandleOnNewMapLoaded);
Event_UnregisterVoid(&GfxEvents.LowVRAMDetected, NULL, HandleLowVRAMDetected);
Event_UnregisterVoid(&WindowEvents.Resized, NULL, Game_OnResize);
Event_UnregisterVoid(&WindowEvents.Closing, NULL, Game_Free);
Event_UnregisterVoid(&WindowEvents.Resized, NULL, Game_OnResize);
Event_UnregisterVoid(&WindowEvents.Closing, NULL, Game_Free);
for (comp = comps_head; comp; comp = comp->next) {
if (comp->Free) comp->Free();

View File

@ -49,8 +49,6 @@ enum FpsLimitMethod {
};
extern const char* const FpsLimit_Names[FPS_LIMIT_COUNT];
/* Attempts to change the terrain atlas. (bitmap containing textures for all blocks) */
cc_bool Game_ChangeTerrainAtlas(Bitmap* atlas);
void Game_SetViewDistance(int distance);
void Game_UserSetViewDistance(int distance);
void Game_SetFov(int fov);

View File

@ -12,6 +12,7 @@
#include "ExtMath.h"
#include "Options.h"
#include "Logger.h"
#include "Chat.h" /* TODO avoid this include */
/*########################################################################################################################*
*------------------------------------------------------TerrainAtlas-------------------------------------------------------*
@ -71,7 +72,8 @@ static void Atlas_Update1D(void) {
Atlas1D.Shift = Math_Log2(Atlas1D.TilesPerAtlas);
}
void Atlas_Update(Bitmap* bmp) {
/* Loads the given atlas and converts it into an array of 1D atlases. */
static void Atlas_Update(Bitmap* bmp) {
Atlas2D.Bmp = *bmp;
Atlas2D.TileSize = bmp->Width / ATLAS2D_TILES_PER_ROW;
Atlas2D.RowsCount = bmp->Height / Atlas2D.TileSize;
@ -108,7 +110,8 @@ GfxResourceID Atlas2D_LoadTile(TextureLoc texLoc) {
}
}
void Atlas_Free(void) {
/* Frees the atlas and 1D atlas textures */
static void Atlas_Free(void) {
int i;
Mem_Free(Atlas2D.Bmp.Scan0);
Atlas2D.Bmp.Scan0 = NULL;
@ -118,13 +121,37 @@ void Atlas_Free(void) {
}
}
cc_bool Atlas_TryChange(Bitmap* atlas) {
static const String terrain = String_FromConst("terrain.png");
if (!Game_ValidateBitmap(&terrain, atlas)) return false;
if (atlas->Height < atlas->Width) {
Chat_AddRaw("&cUnable to use terrain.png from the texture pack.");
Chat_AddRaw("&c Its height is less than its width.");
return false;
}
if (atlas->Width < ATLAS2D_TILES_PER_ROW) {
Chat_AddRaw("&cUnable to use terrain.png from the texture pack.");
Chat_AddRaw("&c It must be 16 or more pixels wide.");
return false;
}
if (Gfx.LostContext) return false;
Atlas_Free();
Atlas_Update(atlas);
Event_RaiseVoid(&TextureEvents.AtlasChanged);
return true;
}
/*########################################################################################################################*
*------------------------------------------------------TextureCache-------------------------------------------------------*
*#########################################################################################################################*/
static struct EntryList acceptedList, deniedList, etagCache, lastModifiedCache;
void TextureCache_Init(void) {
/* Initialises cache state (loading various lists) */
static void TextureCache_Init(void) {
EntryList_Init(&acceptedList, "texturecache/acceptedurls.txt", ' ');
EntryList_Init(&deniedList, "texturecache/deniedurls.txt", ' ');
EntryList_Init(&etagCache, "texturecache/etags.txt", ' ');
@ -295,7 +322,7 @@ static cc_result TexturePack_ExtractPng(struct Stream* stream) {
if (!res) {
Event_RaiseVoid(&TextureEvents.PackChanged);
if (Game_ChangeTerrainAtlas(&bmp)) return 0;
if (Atlas_TryChange(&bmp)) return 0;
}
Mem_Free(bmp.Scan0);
@ -406,3 +433,37 @@ void TexturePack_DownloadAsync(const String* url, const String* id) {
}
Http_AsyncGetDataEx(url, true, id, &time, &etag, NULL);
}
/*########################################################################################################################*
*---------------------------------------------------Textures component----------------------------------------------------*
*#########################################################################################################################*/
static void OnFileChanged(void* obj, struct Stream* stream, const String* name) {
Bitmap bmp;
cc_result res;
if (!String_CaselessEqualsConst(name, "terrain.png")) return;
res = Png_Decode(&bmp, stream);
if (res) {
Logger_Warn2(res, "decoding", name);
Mem_Free(bmp.Scan0);
} else if (!Atlas_TryChange(&bmp)) {
Mem_Free(bmp.Scan0);
}
}
static void Textures_Init(void) {
Event_RegisterEntry(&TextureEvents.FileChanged, NULL, OnFileChanged);
TextureCache_Init();
}
static void Textures_Free(void) {
Event_UnregisterEntry(&TextureEvents.FileChanged, NULL, OnFileChanged);
Atlas_Free();
}
struct IGameComponent Textures_Component = {
Textures_Init, /* Init */
Textures_Free /* Free */
};

View File

@ -11,6 +11,8 @@
struct Stream;
struct HttpRequest;
struct IGameComponent;
extern struct IGameComponent Textures_Component;
/* Number of tiles in each row */
#define ATLAS2D_TILES_PER_ROW 16
@ -56,20 +58,15 @@ CC_VAR extern struct _Atlas1DData {
/* 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 */
/* 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 Atlas2D_LoadTile(TextureLoc texLoc);
/* Frees the atlas and 1D atlas textures. */
void Atlas_Free(void);
/* Attempts to change the terrain atlas. (bitmap containing textures for all blocks) */
cc_bool Atlas_TryChange(Bitmap* bmp);
/* 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);
/* Initialises cache state. (e.g. loading accepted/denied lists) */
void TextureCache_Init(void);
/* Whether the given URL is in list of accepted URLs. */
cc_bool TextureCache_HasAccepted(const String* url);
/* Whether the given URL is in list of denied URLs. */