diff --git a/src/Entity.c b/src/Entity.c index 95beaa8bb..f25f88f05 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -326,7 +326,7 @@ static cc_result ApplySkin(struct Entity* e, struct Bitmap* bmp, struct Stream* if ((res = EnsurePow2Skin(e, bmp))) return res; e->SkinType = Utils_CalcSkinType(bmp); - if (bmp->width > Gfx.MaxTexWidth || bmp->height > Gfx.MaxTexHeight) { + if (!Gfx_CheckTextureSize(bmp->width, bmp->height)) { Chat_Add1("&cSkin %s is too large", skin); } else { if (e->Model->flags & MODEL_FLAG_CLEAR_HAT) diff --git a/src/Game.c b/src/Game.c index 1b54a854d..b0f45393a 100644 --- a/src/Game.c +++ b/src/Game.c @@ -231,6 +231,8 @@ cc_bool Game_UpdateTexture(GfxResourceID* texId, struct Stream* src, const cc_st cc_bool Game_ValidateBitmap(const cc_string* file, struct Bitmap* bmp) { int maxWidth = Gfx.MaxTexWidth, maxHeight = Gfx.MaxTexHeight; + float texSize, maxSize; + if (!bmp->scan0) { Chat_Add1("&cError loading %s from the texture pack.", file); return false; @@ -240,7 +242,17 @@ cc_bool Game_ValidateBitmap(const cc_string* file, struct Bitmap* bmp) { Chat_Add1("&cUnable to use %s from the texture pack.", file); Chat_Add4("&c Its size is (%i,%i), your GPU supports (%i,%i) at most.", - &bmp->width, &bmp->height, &maxWidth, &maxHeight); + &bmp->width, &bmp->height, &maxWidth, &maxHeight); + return false; + } + + if (Gfx.MaxTexSize && (bmp->width * bmp->height > Gfx.MaxTexSize)) { + Chat_Add1("&cUnable to use %s from the texture pack.", file); + texSize = (bmp->width * bmp->height) / (1024.0f * 1024.0f); + maxSize = Gfx.MaxTexSize / (1024.0f * 1024.0f); + + Chat_Add2("&c Its size is %f3 MB, your GPU supports %f3 MB at most.", + &texSize, &maxSize); return false; } diff --git a/src/Graphics.h b/src/Graphics.h index 9751785f1..922d6e83d 100644 --- a/src/Graphics.h +++ b/src/Graphics.h @@ -53,6 +53,9 @@ CC_VAR extern struct _GfxData { /* Whether graphics context has been created */ cc_bool Created; struct Matrix View, Projection; + /* Maximum size in pixels a texture can consist of */ + /* NOTE: Not all graphics backends specify a value for this */ + int MaxTexSize; } Gfx; extern GfxResourceID Gfx_defaultIb; @@ -69,10 +72,10 @@ extern const cc_string Gfx_LowPerfMessage; #define LOWPERF_EXIT_MESSAGE "&eExited reduced performance mode" -void Gfx_RecreateDynamicVb(GfxResourceID* vb, VertexFormat fmt, int maxVertices); -void Gfx_RecreateTexture(GfxResourceID* tex, struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps); +void Gfx_RecreateTexture(GfxResourceID* tex, struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps); void* Gfx_RecreateAndLockVb(GfxResourceID* vb, VertexFormat fmt, int count); +cc_bool Gfx_CheckTextureSize(int width, int height); /* Creates a new texture. (and also generates mipmaps if mipmaps) */ /* Supported flags: TEXTURE_FLAG_MANAGED, TEXTURE_FLAG_DYNAMIC */ /* NOTE: Only set mipmaps to true if Gfx_Mipmaps is also true, because whether textures @@ -87,6 +90,7 @@ void Gfx_UpdateTexture(GfxResourceID texId, int x, int y, struct Bitmap* part, i CC_API void Gfx_BindTexture(GfxResourceID texId); /* Deletes the given texture, then sets it to 0 */ CC_API void Gfx_DeleteTexture(GfxResourceID* texId); + /* NOTE: Completely useless now, and does nothing in all graphics backends */ /* (used to set whether texture colour is used when rendering vertices) */ CC_API void Gfx_SetTexturing(cc_bool enabled); diff --git a/src/Graphics_3DS.c b/src/Graphics_3DS.c index 51912a43d..b0b0ec45e 100644 --- a/src/Graphics_3DS.c +++ b/src/Graphics_3DS.c @@ -339,7 +339,7 @@ cc_result Gfx_TakeScreenshot(struct Stream* output) { void Gfx_GetApiInfo(cc_string* info) { String_Format1(info, "-- Using 3DS --\n", NULL); - String_Format2(info, "Max texture size: (%i, %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + PrintMaxTextureInfo(info); } void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) { diff --git a/src/Graphics_D3D11.c b/src/Graphics_D3D11.c index 56aed15a3..f3418cde5 100644 --- a/src/Graphics_D3D11.c +++ b/src/Graphics_D3D11.c @@ -1160,7 +1160,7 @@ void Gfx_GetApiInfo(cc_string* info) { String_Format1(info, "Adapter: %c\n", adapter); String_Format2(info, "Graphics memory: %f2 MB total (%f2 MB VRAM)\n", &tram_, &vram_); - String_Format2(info, "Max texture size: (%i x %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + PrintMaxTextureInfo(info); release_adapter: IDXGIAdapter_Release(dxgi_adapter); diff --git a/src/Graphics_D3D9.c b/src/Graphics_D3D9.c index e8a656f69..4c2b90d72 100644 --- a/src/Graphics_D3D9.c +++ b/src/Graphics_D3D9.c @@ -880,7 +880,7 @@ void Gfx_GetApiInfo(cc_string* info) { String_Format1(info, "Adapter: %c\n", adapter.Description); String_Format1(info, "Processing mode: %c\n", D3D9_StrFlags()); String_Format2(info, "Video memory: %f2 MB total, %f2 free\n", &totalMem, &curMem); - String_Format2(info, "Max texture size: (%i x %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + PrintMaxTextureInfo(info); String_Format1(info, "Depth buffer bits: %i", &depthBits); } diff --git a/src/Graphics_Dreamcast.c b/src/Graphics_Dreamcast.c index 77a8c563d..75ea9e64a 100644 --- a/src/Graphics_Dreamcast.c +++ b/src/Graphics_Dreamcast.c @@ -520,7 +520,7 @@ void Gfx_GetApiInfo(cc_string* info) { String_AppendConst(info, "GPU: PowerVR2 CLX2 100mHz\n"); String_AppendConst(info, "T&L: GLdc library (KallistiOS / Kazade)\n"); String_Format2(info, "Texture memory: %f2 MB used, %f2 MB free\n", &usedMemMB, &freeMemMB); - String_Format2(info, "Max texture size: (%i, %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + PrintMaxTextureInfo(info); } void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) { diff --git a/src/Graphics_GCWii.c b/src/Graphics_GCWii.c index 21568ca63..01049535b 100644 --- a/src/Graphics_GCWii.c +++ b/src/Graphics_GCWii.c @@ -240,8 +240,8 @@ cc_result Gfx_TakeScreenshot(struct Stream* output) { } void Gfx_GetApiInfo(cc_string* info) { - String_Format1(info, "-- Using GC/WII --", NULL); - String_Format2(info, "Max texture size: (%i, %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + String_AppendConst(info, "-- Using GC/Wii --\n"); + PrintMaxTextureInfo(info); } void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) { diff --git a/src/Graphics_N64.c b/src/Graphics_N64.c index 14ab3ce99..317352247 100644 --- a/src/Graphics_N64.c +++ b/src/Graphics_N64.c @@ -62,7 +62,7 @@ void Gfx_GetApiInfo(cc_string* info) { String_AppendConst(info, "-- Using Nintendo 64 --\n"); String_AppendConst(info, "GPU: Nintendo 64 RDP (LibDragon OpenGL)\n"); String_AppendConst(info, "T&L: Nintendo 64 RSP (LibDragon OpenGL)\n"); - String_Format2(info, "Max texture size: (%i, %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + PrintMaxTextureInfo(info); } void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) { @@ -121,8 +121,6 @@ typedef struct CCTexture { } CCTexture; static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps) { - if (bmp->width > 32 || bmp->height > 32) return NULL; - CCTexture* tex = Mem_Alloc(1, sizeof(CCTexture), "texture"); glGenTextures(1, &tex->textureID); diff --git a/src/Graphics_PS2.c b/src/Graphics_PS2.c index 1cfda7013..be7d95caf 100644 --- a/src/Graphics_PS2.c +++ b/src/Graphics_PS2.c @@ -617,9 +617,8 @@ void Gfx_OnWindowResize(void) { } void Gfx_GetApiInfo(cc_string* info) { - int pointerSize = sizeof(void*) * 8; - String_Format1(info, "-- Using PS2 (%i bit) --\n", &pointerSize); - String_Format2(info, "Max texture size: (%i x %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + String_AppendConst(info, "-- Using PS2 --\n"); + PrintMaxTextureInfo(info); } cc_bool Gfx_TryRestoreContext(void) { return true; } diff --git a/src/Graphics_PS3.c b/src/Graphics_PS3.c index 30a9ff88f..4adda6ae2 100644 --- a/src/Graphics_PS3.c +++ b/src/Graphics_PS3.c @@ -384,7 +384,7 @@ void Gfx_GetApiInfo(cc_string* info) { int pointerSize = sizeof(void*) * 8; String_Format1(info, "-- Using PS3 (%i bit) --\n", &pointerSize); - String_Format2(info, "Max texture size: (%i, %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + PrintMaxTextureInfo(info); } void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) { diff --git a/src/Graphics_PSP.c b/src/Graphics_PSP.c index 5e2b59701..770c40b95 100644 --- a/src/Graphics_PSP.c +++ b/src/Graphics_PSP.c @@ -239,8 +239,8 @@ cc_result Gfx_TakeScreenshot(struct Stream* output) { } void Gfx_GetApiInfo(cc_string* info) { - String_Format1(info, "-- Using PSP--\n", NULL); - String_Format2(info, "Max texture size: (%i, %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + String_AppendConst(info, "-- Using PSP--\n"); + PrintMaxTextureInfo(info); } void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) { diff --git a/src/Graphics_PSVita.c b/src/Graphics_PSVita.c index ef5d86df4..a0182ba52 100644 --- a/src/Graphics_PSVita.c +++ b/src/Graphics_PSVita.c @@ -750,10 +750,8 @@ cc_result Gfx_TakeScreenshot(struct Stream* output) { } void Gfx_GetApiInfo(cc_string* info) { - int pointerSize = sizeof(void*) * 8; - - String_Format1(info, "-- Using PS VITA (%i bit) --\n", &pointerSize); - String_Format2(info, "Max texture size: (%i, %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + String_AppendConst(info, "-- Using PS Vita --\n"); + PrintMaxTextureInfo(info); } void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) { diff --git a/src/Graphics_SoftGPU.c b/src/Graphics_SoftGPU.c index ea1507747..f43f5d03a 100644 --- a/src/Graphics_SoftGPU.c +++ b/src/Graphics_SoftGPU.c @@ -481,7 +481,7 @@ void Gfx_OnWindowResize(void) { void Gfx_GetApiInfo(cc_string* info) { int pointerSize = sizeof(void*) * 8; String_Format1(info, "-- Using software (%i bit) --\n", &pointerSize); - String_Format2(info, "Max texture size: (%i x %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + PrintMaxTextureInfo(info); } cc_bool Gfx_TryRestoreContext(void) { return true; } diff --git a/src/Graphics_Xbox.c b/src/Graphics_Xbox.c index dcf204c8a..048947459 100644 --- a/src/Graphics_Xbox.c +++ b/src/Graphics_Xbox.c @@ -345,7 +345,8 @@ cc_result Gfx_TakeScreenshot(struct Stream* output) { } void Gfx_GetApiInfo(cc_string* info) { - String_Format2(info, "Max texture size: (%i, %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + String_AppendConst(info, "-- Using XBox --\n"); + PrintMaxTextureInfo(info); } void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) { diff --git a/src/Graphics_Xbox360.c b/src/Graphics_Xbox360.c index 637bbdd15..9778c8cc2 100644 --- a/src/Graphics_Xbox360.c +++ b/src/Graphics_Xbox360.c @@ -357,10 +357,8 @@ void Gfx_EndFrame(void) { cc_bool Gfx_WarnIfNecessary(void) { return false; } void Gfx_GetApiInfo(cc_string* info) { - int pointerSize = sizeof(void*) * 8; - - String_Format1(info, "-- Using XBox 360 (%i bit) --\n", &pointerSize); - String_Format2(info, "Max texture size: (%i x %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + String_AppendConst(info, "-- Using XBox 360 --\n"); + PrintMaxTextureInfo(info); } void Gfx_OnWindowResize(void) { diff --git a/src/Gui.c b/src/Gui.c index 81eea8ee7..ce1055e7c 100644 --- a/src/Gui.c +++ b/src/Gui.c @@ -435,7 +435,8 @@ void Screen_Render2Widgets(void* screen, double delta) { void Screen_UpdateVb(void* screen) { struct Screen* s = (struct Screen*)screen; - Gfx_RecreateDynamicVb(&s->vb, VERTEX_FORMAT_TEXTURED, s->maxVertices); + Gfx_DeleteDynamicVb(&s->vb); + s->vb = Gfx_CreateDynamicVb(VERTEX_FORMAT_TEXTURED, s->maxVertices); } struct VertexTextured* Screen_LockVb(void* screen) { diff --git a/src/TexturePack.c b/src/TexturePack.c index f31329812..7f9efab1c 100644 --- a/src/TexturePack.c +++ b/src/TexturePack.c @@ -63,8 +63,16 @@ static void Atlas_Convert2DTo1D(void) { static void Atlas_Update1D(void) { int maxAtlasHeight, maxTilesPerAtlas, maxTiles; + int maxTexHeight = Gfx.MaxTexHeight; - maxAtlasHeight = min(4096, Gfx.MaxTexHeight); + /* E.g. a graphics backend may support textures up to 256 x 256 */ + /* dimension wise, but only have enough storage for 16 x 256 */ + if (Gfx.MaxTexSize) { + int maxCurHeight = Gfx.MaxTexSize / Atlas2D.TileSize; + maxTexHeight = min(maxTexHeight, maxCurHeight); + } + + maxAtlasHeight = min(4096, maxTexHeight); maxTilesPerAtlas = maxAtlasHeight / Atlas2D.TileSize; maxTiles = Atlas2D.RowsCount * ATLAS2D_TILES_PER_ROW; @@ -145,7 +153,7 @@ cc_bool Atlas_TryChange(struct Bitmap* atlas) { return false; } - if (tileSize > Gfx.MaxTexWidth) { + if (!Gfx_CheckTextureSize(tileSize, tileSize)) { Chat_AddRaw("&cUnable to use terrain.png from the texture pack."); Chat_Add4("&c Tile size is (%i,%i), your GPU supports (%i,%i) at most.", &tileSize, &tileSize, &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); diff --git a/src/_GLShared.h b/src/_GLShared.h index 9394f82d2..d40c9ecf2 100644 --- a/src/_GLShared.h +++ b/src/_GLShared.h @@ -285,7 +285,7 @@ void Gfx_GetApiInfo(cc_string* info) { String_Format1(info, "Renderer: %c\n", glGetString(GL_RENDERER)); String_Format1(info, "GL version: %c\n", glGetString(GL_VERSION)); AppendVRAMStats(info); - String_Format2(info, "Max texture size: (%i, %i)\n", &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + PrintMaxTextureInfo(info); String_Format1(info, "Depth buffer bits: %i\n", &depthBits); GLContext_GetApiInfo(info); } diff --git a/src/_GraphicsBase.h b/src/_GraphicsBase.h index d8d76be90..f08b55a23 100644 --- a/src/_GraphicsBase.h +++ b/src/_GraphicsBase.h @@ -51,11 +51,16 @@ static void MakeIndices(cc_uint16* indices, int count, void* obj) { } } +static void RecreateDynamicVb(GfxResourceID* vb, VertexFormat fmt, int maxVertices) { + Gfx_DeleteDynamicVb(vb); + *vb = Gfx_CreateDynamicVb(fmt, maxVertices); +} + static void InitDefaultResources(void) { Gfx_defaultIb = Gfx_CreateIb2(GFX_MAX_INDICES, MakeIndices, NULL); - Gfx_RecreateDynamicVb(&Gfx_quadVb, VERTEX_FORMAT_COLOURED, 4); - Gfx_RecreateDynamicVb(&Gfx_texVb, VERTEX_FORMAT_TEXTURED, 4); + RecreateDynamicVb(&Gfx_quadVb, VERTEX_FORMAT_COLOURED, 4); + RecreateDynamicVb(&Gfx_texVb, VERTEX_FORMAT_TEXTURED, 4); } static void FreeDefaultResources(void) { @@ -129,11 +134,6 @@ static void EndReducedPerformance(void) { } -void Gfx_RecreateDynamicVb(GfxResourceID* vb, VertexFormat fmt, int maxVertices) { - Gfx_DeleteDynamicVb(vb); - *vb = Gfx_CreateDynamicVb(fmt, maxVertices); -} - void Gfx_RecreateTexture(GfxResourceID* tex, struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps) { Gfx_DeleteTexture(tex); *tex = Gfx_CreateTexture(bmp, flags, mipmaps); @@ -252,6 +252,17 @@ static CC_INLINE float Reversed_CalcZNear(float fov, int depthbufferBits) { return 0.00390625f; } +static void PrintMaxTextureInfo(cc_string* info) { + if (Gfx.MaxTexSize) { + float maxSize = Gfx.MaxTexSize / (1024.0f * 1024.0f); + String_Format3(info, "Max texture size: (%i, %i), up to %f3 MB\n", + &Gfx.MaxTexWidth, &Gfx.MaxTexHeight, &maxSize); + } else { + String_Format2(info, "Max texture size: (%i, %i)\n", + &Gfx.MaxTexWidth, &Gfx.MaxTexHeight); + } +} + /*########################################################################################################################* *---------------------------------------------------------Textures--------------------------------------------------------* @@ -339,6 +350,15 @@ static CC_NOINLINE int CalcMipmapsLevels(int width, int height) { } } +cc_bool Gfx_CheckTextureSize(int width, int height) { + if (width > Gfx.MaxTexWidth) return false; + if (height > Gfx.MaxTexHeight) return false; + + if (Gfx.MaxTexSize && (width * height > Gfx.MaxTexSize)) + return false; + return true; +} + static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps); GfxResourceID Gfx_CreateTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipmaps) { @@ -346,6 +366,7 @@ GfxResourceID Gfx_CreateTexture(struct Bitmap* bmp, cc_uint8 flags, cc_bool mipm Logger_Abort("Textures must have power of two dimensions"); } if (Gfx.LostContext) return 0; + if (!Gfx_CheckTextureSize(bmp->width, bmp->height)) return 0; return Gfx_AllocTexture(bmp, flags, mipmaps); }