From 951b3f2fc833377675176a0b91329d6838db1e4b Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Thu, 28 Sep 2023 21:45:49 +0200 Subject: [PATCH 01/10] Use SDL_Image instead of devIL does not crash --- CMakeLists.txt | 8 +- TheForceEngine/TFE_Asset/imageAsset.cpp | 297 +++++++++++------------- TheForceEngine/TFE_Asset/imageAsset.h | 6 +- TheForceEngine/TFE_Game/saveSystem.cpp | 12 +- 4 files changed, 154 insertions(+), 169 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ff5a7beb5..4f61ca80d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,10 +47,9 @@ set_target_properties(tfe PROPERTIES OUTPUT_NAME "theforceengine") if(LINUX) find_package(PkgConfig REQUIRED) find_package(Threads REQUIRED) - pkg_check_modules(SDL2 REQUIRED sdl2) + find_package(SDL2 2.24 REQUIRED) + pkg_check_modules(SDL2_IMAGE REQUIRED SDL2_image) pkg_check_modules(GLEW REQUIRED glew) - pkg_check_modules(IL REQUIRED IL) - pkg_check_modules(ILU REQUIRED ILU) set(OpenGL_GL_PREFERENCE GLVND) find_package(OpenGL REQUIRED) target_include_directories(tfe PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) @@ -59,8 +58,7 @@ if(LINUX) ${OPENGL_LIBRARIES} ${GLEW_LIBRARIES} ${SDL2_LIBRARIES} - ${IL_LIBRARIES} - ${ILU_LIBRARIES} + ${SDL2_IMAGE_LIBRARIES} ) if(NOT DISABLE_SYSMIDI) diff --git a/TheForceEngine/TFE_Asset/imageAsset.cpp b/TheForceEngine/TFE_Asset/imageAsset.cpp index 86a61348d..488bab18f 100644 --- a/TheForceEngine/TFE_Asset/imageAsset.cpp +++ b/TheForceEngine/TFE_Asset/imageAsset.cpp @@ -8,10 +8,8 @@ #include #include #include - -#define IL_USE_PRAGMA_LIBS -#include -#include +#include +#include namespace TFE_Image { @@ -19,50 +17,72 @@ namespace TFE_Image static ImageMap s_images; static std::vector s_buffer; + static SDL_Surface* convertToRGBA(SDL_Surface* src) + { + SDL_PixelFormat rgba32 = { + .format = SDL_PIXELFORMAT_RGBA32, + .palette = NULL, + .BitsPerPixel = 32, + .BytesPerPixel = 4, + .Rmask = 0x000000FF, + .Gmask = 0x0000FF00, + .Bmask = 0x00FF0000, + .Amask = 0xFF000000, + .Rloss = 0, + .Gloss = 0, + .Bloss = 0, + .Aloss = 0, + .Rshift = 0, + .Gshift = 8, + .Bshift = 16, + .Ashift = 24 + }; + + SDL_Surface* n = SDL_ConvertSurface(src, &rgba32, 0); + SDL_FreeSurface(src); + return n; + } + void init() { + int ret; + int flags = IMG_INIT_PNG | IMG_INIT_JPG; + TFE_System::logWrite(LOG_MSG, "Startup", "TFE_Image::init"); - - // Initialize IL - ilInit(); - iluInit(); - - // We want all images to be loaded in a consistent manner - ilEnable(IL_ORIGIN_SET); - ilOriginFunc(IL_ORIGIN_UPPER_LEFT); + ret = IMG_Init(flags); + if ((ret & flags) != flags) + { + TFE_System::logWrite(LOG_ERROR, "ImageAsset", "SDL_image init failed!"); + } } void shutdown() { freeAll(); - ilShutDown(); + IMG_Quit(); } Image* loadFromMemory(const u8* buffer, size_t size) { - Image* image = new Image; - - // Now let's switch over to using devIL... - ILuint handle; - - // In the next section, we load one image - ilGenImages(1, &handle); - ilBindImage(handle); - if (ilLoadL(IL_JPG, buffer, (ILuint)size) == IL_FALSE) - { + SDL_RWops* memops = SDL_RWFromConstMem(buffer, size); + if (!memops) + return nullptr; + + SDL_Surface* sdlimg = IMG_Load_RW(memops, 1); + if (!sdlimg) + return nullptr; + if (sdlimg->format->BitsPerPixel != 32) + sdlimg = convertToRGBA(sdlimg); + if (!sdlimg) return nullptr; - } - - // Let’s spy on it a little bit - image->width = (u32)ilGetInteger(IL_IMAGE_WIDTH); // getting image width - image->height = (u32)ilGetInteger(IL_IMAGE_HEIGHT); // and height - - image->data = new u32[image->width * image->height]; - // get the image data - ilCopyPixels(0, 0, 0, image->width, image->height, 1, IL_RGBA, IL_UNSIGNED_BYTE, image->data); - // Finally, clean the mess! - ilDeleteImages(1, &handle); + Image* image = new Image; + + image->sdl = sdlimg; + image->width = (u32)sdlimg->w; + image->height = (u32)sdlimg->h; + image->data = (u32*)sdlimg->pixels; + SDL_LockSurface(sdlimg); // required to manipulate the pixel buffer return image; } @@ -75,31 +95,26 @@ namespace TFE_Image return iImage->second; } + SDL_Surface* sdlimg = IMG_Load(imagePath); + if (!sdlimg) + return nullptr; + if (sdlimg->format->BitsPerPixel != 32) + sdlimg = convertToRGBA(sdlimg); + if (!sdlimg) + return nullptr; + Image* image = new Image; - - // Now let's switch over to using devIL... - ILuint handle; - - // In the next section, we load one image - ilGenImages(1, &handle); - ilBindImage(handle); - if (ilLoadImage(imagePath) == IL_FALSE) + if (!image) { - // TODO: handle error. - // ILenum error = ilGetError(); + SDL_FreeSurface(sdlimg); return nullptr; } - // Let’s spy on it a little bit - image->width = (u32)ilGetInteger(IL_IMAGE_WIDTH); // getting image width - image->height = (u32)ilGetInteger(IL_IMAGE_HEIGHT); // and height - - image->data = new u32[image->width * image->height]; - // get the image data - ilCopyPixels(0, 0, 0, image->width, image->height, 1, IL_RGBA, IL_UNSIGNED_BYTE, image->data); - - // Finally, clean the mess! - ilDeleteImages(1, &handle); + image->sdl = sdlimg; + image->width = (u32)sdlimg->w; + image->height = (u32)sdlimg->h; + image->data = (u32*)sdlimg->pixels; + SDL_LockSurface(sdlimg); // required to manipulate the pixel buffer s_images[imagePath] = image; return image; @@ -108,8 +123,11 @@ namespace TFE_Image void free(Image* image) { if (!image) { return; } - delete[] image->data; + SDL_UnlockSurface(image->sdl); + SDL_FreeSurface(image->sdl); + image->sdl = nullptr; + ImageMap::iterator iImage = s_images.begin(); for (; iImage != s_images.end(); ++iImage) { @@ -130,7 +148,8 @@ namespace TFE_Image Image* image = iImage->second; if (image) { - delete[] image->data; + SDL_UnlockSurface(image->sdl); + SDL_FreeSurface(image->sdl); } delete image; } @@ -139,126 +158,88 @@ namespace TFE_Image void writeImage(const char* path, u32 width, u32 height, u32* pixelData) { - ILuint handle; - ilGenImages(1, &handle); - ilBindImage(handle); - - ilTexImage(width, height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, (void*)pixelData); - ilSetData((void*)pixelData); - ilEnable(IL_FILE_OVERWRITE); - ilSaveImage(path); - - ilBindImage(0); - ilDeleteImage(handle); + SDL_Surface* surf = SDL_CreateRGBSurfaceFrom(pixelData, width, height, + 32, width * sizeof(u32), + 0xFF, 0xFF00, 0xFF0000, 0xFF000000); + if (!surf) + return; + int ret = IMG_SavePNG(surf, path); + if (ret != 0) + { + fprintf(stderr, "writeImage(%s) failed '%s'\n", path, SDL_GetError()); + } } ////////////////////////////////////////////////////// - // Wacky file overrides to get Devil to read and write - // images to/from memory. + // Wacky file override to get SDL-Image to write + // images to memory. ////////////////////////////////////////////////////// - static MemoryStream s_memStream; - - ILHANDLE ILAPIENTRY iOpen(const char *FileName) - { - return (ILHANDLE)1; - } - - void ILAPIENTRY iClose(ILHANDLE Handle) + static size_t SDLCALL _sdl_wop_mem(struct SDL_RWops * context, const void *ptr, + size_t size, size_t num) { - } - - ILboolean ILAPIENTRY iEof(ILHANDLE Handle) - { - return s_memStream.getLoc() >= s_memStream.getSize(); - } - - ILint ILAPIENTRY iGetc(ILHANDLE Handle) - { - u8 c; - s_memStream.read(&c); - return ILint(c); - } - - ILint ILAPIENTRY iPutc(ILubyte Char, ILHANDLE Handle) - { - u8 c = u8(Char); - s_memStream.write(&c); - return 1; - } - - ILint ILAPIENTRY iRead(void *Buffer, ILuint Size, ILuint Number, ILHANDLE Handle) - { - s_memStream.readBuffer(Buffer, Size, Number); - return Number; - } - - ILint ILAPIENTRY iWrite(const void *Buffer, ILuint Size, ILuint Number, ILHANDLE Handle) - { - s_memStream.writeBuffer(Buffer, Size, Number); - return Number; - } - - ILint ILAPIENTRY iSeek(ILHANDLE Handle, ILint Offset, ILint Mode) - { - Stream::Origin c_origin[] = + size_t bytes = num * size; + ptrdiff_t space = context->hidden.mem.stop - context->hidden.mem.here; + if (space >= bytes) { - Stream::ORIGIN_START, - Stream::ORIGIN_CURRENT, - Stream::ORIGIN_END, - }; - return s_memStream.seek(Offset, c_origin[Mode]) ? 0 : -1; + memcpy(context->hidden.mem.here, ptr, bytes); + context->hidden.mem.here += bytes; + return bytes; + } + else + { + fprintf(stderr, "AIEEE: _sdl_wop_mem %p %x %x | %llu %llu\n", ptr, size, num, space, bytes); + } + + return 0; } - ILint ILAPIENTRY iTell(ILHANDLE Handle) - { - return (ILint)s_memStream.getLoc(); - } - ////////////////////////////////////////////////////// // Code to write and read images from memory. ////////////////////////////////////////////////////// - size_t writeImageToMemory(u8*& output, u32 width, u32 height, const u32* pixelData) - { - s_memStream.open(Stream::MODE_WRITE); - ilSetWrite(iOpen, iClose, iPutc, iSeek, iTell, iWrite); - - writeImage("image.png", width, height, (u32*)pixelData); - - ilResetWrite(); - s_memStream.close(); - - output = (u8*)s_memStream.data(); - return s_memStream.getSize(); + size_t writeImageToMemory(u8* output, u32 width, u32 height, const u32* pixelData) + { + SDL_Surface* surf = SDL_CreateRGBSurfaceFrom((void *)pixelData, width, height, 32, width * sizeof(u32), + 0xFF, 0xFF00, 0xFF0000, 0xFF000000); + if (!surf) + return 0; + SDL_RWops* memops = SDL_RWFromMem(output, width * height * sizeof(u32)); + if (!memops) + { + SDL_FreeSurface(surf); + return 0; + } + memops->write = _sdl_wop_mem; + int ret = IMG_SavePNG_RW(surf, memops, 0); + SDL_FreeSurface(surf); + size_t written = 0; + if (ret == 0) + { + written = memops->hidden.mem.here - memops->hidden.mem.base; + } + SDL_FreeRW(memops); + return written; } void readImageFromMemory(Image* output, size_t size, const u32* pixelData) { - s_memStream.load(size, pixelData); - s_memStream.open(Stream::MODE_READ); - ilSetRead(iOpen, iClose, iEof, iGetc, iRead, iSeek, iTell); - - // Now let's switch over to using devIL... - ILuint handle; + SDL_RWops* memops = SDL_RWFromConstMem(pixelData, size); + if (!memops) + return; + + SDL_Surface* sdlimg = IMG_Load_RW(memops, 1); + if (!sdlimg) + return; - // In the next section, we load one image - ilGenImages(1, &handle); - ilBindImage(handle); - if (ilLoadImage("image.png") == IL_FALSE) + if (output->sdl) { - ILenum error = ilGetError(); - return; + SDL_UnlockSurface(output->sdl); + SDL_FreeSurface(output->sdl); } - // Let’s spy on it a little bit - output->width = (u32)ilGetInteger(IL_IMAGE_WIDTH); // getting image width - output->height = (u32)ilGetInteger(IL_IMAGE_HEIGHT); // and height - // get the image data - ilCopyPixels(0, 0, 0, output->width, output->height, 1, IL_RGBA, IL_UNSIGNED_BYTE, output->data); - - // Finally, clean the mess! - ilDeleteImages(1, &handle); - - ilResetRead(); - s_memStream.close(); + output->sdl = sdlimg; + output->width = (u32)sdlimg->w; + output->height = (u32)sdlimg->h; + output->data = (u32*)sdlimg->pixels; + SDL_LockSurface(sdlimg); // required to manipulate the pixel buffer } } diff --git a/TheForceEngine/TFE_Asset/imageAsset.h b/TheForceEngine/TFE_Asset/imageAsset.h index 8bdc2c0ee..9e6f61abe 100644 --- a/TheForceEngine/TFE_Asset/imageAsset.h +++ b/TheForceEngine/TFE_Asset/imageAsset.h @@ -1,13 +1,13 @@ #pragma once ////////////////////////////////////////////////////////////////////// // The Force Engine Image Loading -// TODO: Replace DeviL with libPNG? or STB_IMAGE? -// Can use std_image.h and std_image_write.h for reading and writing. ////////////////////////////////////////////////////////////////////// #include +#include struct Image { + SDL_Surface* sdl = nullptr; u32 width = 0u; u32 height = 0u; u32* data = nullptr; @@ -25,6 +25,6 @@ namespace TFE_Image void writeImage(const char* path, u32 width, u32 height, u32* pixelData); - size_t writeImageToMemory(u8*& output, u32 width, u32 height, const u32* pixelData); + size_t writeImageToMemory(u8* output, u32 width, u32 height, const u32* pixelData); void readImageFromMemory(Image* output, size_t size, const u32* pixelData); } diff --git a/TheForceEngine/TFE_Game/saveSystem.cpp b/TheForceEngine/TFE_Game/saveSystem.cpp index e9a65d943..dbe3f91de 100644 --- a/TheForceEngine/TFE_Game/saveSystem.cpp +++ b/TheForceEngine/TFE_Game/saveSystem.cpp @@ -91,7 +91,8 @@ namespace TFE_SaveSystem } // Save to memory. - u8* png; + u8* png = (u8*)malloc(newSize); + // FIXME: check memory! u32 pngSize = (u32)TFE_Image::writeImageToMemory(png, newWidth, newHeight, s_imageBuffer[1]); // Master version. @@ -129,6 +130,7 @@ namespace TFE_SaveSystem // Image. stream->write(&pngSize); stream->writeBuffer(png, pngSize); + free(png); } void loadHeader(Stream* stream, SaveHeader* header, const char* fileName) @@ -177,9 +179,13 @@ namespace TFE_SaveSystem stream->readBuffer(s_imageBuffer[0], pngSize); Image image = { 0 }; - image.data = header->imageData; TFE_Image::readImageFromMemory(&image, pngSize, s_imageBuffer[0]); - assert(image.width == SAVE_IMAGE_WIDTH && image.height == SAVE_IMAGE_HEIGHT); + if (image.width == SAVE_IMAGE_WIDTH && image.height == SAVE_IMAGE_HEIGHT) + { + const u32 sz = SAVE_IMAGE_WIDTH * SAVE_IMAGE_HEIGHT * sizeof(u32); + memcpy(header->imageData, image.data, sz); + TFE_Image::free(&image); + } } void populateSaveDirectory(std::vector& dir) From b88f09ce4ccbbdf69892783a2a09fce6d01177b3 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Fri, 29 Sep 2023 08:33:41 +0200 Subject: [PATCH 02/10] Let SDL_image do the scaling of the save screenshot --- TheForceEngine/TFE_Asset/imageAsset.cpp | 46 +++++++++++++++++------- TheForceEngine/TFE_Asset/imageAsset.h | 2 +- TheForceEngine/TFE_Game/saveSystem.cpp | 48 +++---------------------- 3 files changed, 39 insertions(+), 57 deletions(-) diff --git a/TheForceEngine/TFE_Asset/imageAsset.cpp b/TheForceEngine/TFE_Asset/imageAsset.cpp index 488bab18f..980eef898 100644 --- a/TheForceEngine/TFE_Asset/imageAsset.cpp +++ b/TheForceEngine/TFE_Asset/imageAsset.cpp @@ -177,41 +177,63 @@ namespace TFE_Image static size_t SDLCALL _sdl_wop_mem(struct SDL_RWops * context, const void *ptr, size_t size, size_t num) { - size_t bytes = num * size; - ptrdiff_t space = context->hidden.mem.stop - context->hidden.mem.here; + const size_t bytes = num * size; + const ptrdiff_t space = context->hidden.mem.stop - context->hidden.mem.here; if (space >= bytes) { memcpy(context->hidden.mem.here, ptr, bytes); context->hidden.mem.here += bytes; return bytes; } - else - { - fprintf(stderr, "AIEEE: _sdl_wop_mem %p %x %x | %llu %llu\n", ptr, size, num, space, bytes); - } - return 0; } ////////////////////////////////////////////////////// // Code to write and read images from memory. ////////////////////////////////////////////////////// - size_t writeImageToMemory(u8* output, u32 width, u32 height, const u32* pixelData) + size_t writeImageToMemory(u8* output, u32 srcw, u32 srch, u32 dstw, + u32 dsth, const u32* pixelData) { - SDL_Surface* surf = SDL_CreateRGBSurfaceFrom((void *)pixelData, width, height, 32, width * sizeof(u32), + size_t written; + int ret; + + SDL_Surface* surf = SDL_CreateRGBSurfaceFrom((void *)pixelData, srcw, srch, 32, srcw * sizeof(u32), 0xFF, 0xFF00, 0xFF0000, 0xFF000000); if (!surf) return 0; - SDL_RWops* memops = SDL_RWFromMem(output, width * height * sizeof(u32)); + if ((srcw != dstw) || (srch != dsth)) + { + const SDL_Rect rs = { .x = 0, .y = 0, .w = srcw, .h = srch }; + const SDL_Rect rd = { .x = 0, .y = 0, .w = dstw, .h = dsth }; + SDL_Surface* scaled = SDL_CreateRGBSurface(0, dstw, dsth, 32, + 0xFF, 0xFF00, 0xFF0000, 0xFF000000); + if (!scaled) + { + SDL_FreeSurface(surf); + return 0; + } + ret = SDL_SoftStretchLinear(surf, &rs, scaled, &rd); + if (ret != 0) + { + SDL_FreeSurface(surf); + SDL_FreeSurface(scaled); + return 0; + } + SDL_FreeSurface(surf); + surf = scaled; + srcw = dstw; + srch = dsth; + } + + SDL_RWops* memops = SDL_RWFromMem(output, srcw * srch * sizeof(u32)); if (!memops) { SDL_FreeSurface(surf); return 0; } memops->write = _sdl_wop_mem; - int ret = IMG_SavePNG_RW(surf, memops, 0); + ret = IMG_SavePNG_RW(surf, memops, 0); SDL_FreeSurface(surf); - size_t written = 0; if (ret == 0) { written = memops->hidden.mem.here - memops->hidden.mem.base; diff --git a/TheForceEngine/TFE_Asset/imageAsset.h b/TheForceEngine/TFE_Asset/imageAsset.h index 9e6f61abe..6f64298da 100644 --- a/TheForceEngine/TFE_Asset/imageAsset.h +++ b/TheForceEngine/TFE_Asset/imageAsset.h @@ -25,6 +25,6 @@ namespace TFE_Image void writeImage(const char* path, u32 width, u32 height, u32* pixelData); - size_t writeImageToMemory(u8* output, u32 width, u32 height, const u32* pixelData); + size_t writeImageToMemory(u8* output, u32 srcw, u32 srch, u32 dstw, u32 dsth, const u32* pixelData); void readImageFromMemory(Image* output, size_t size, const u32* pixelData); } diff --git a/TheForceEngine/TFE_Game/saveSystem.cpp b/TheForceEngine/TFE_Game/saveSystem.cpp index dbe3f91de..1f785303f 100644 --- a/TheForceEngine/TFE_Game/saveSystem.cpp +++ b/TheForceEngine/TFE_Game/saveSystem.cpp @@ -48,52 +48,12 @@ namespace TFE_SaveSystem s_imageBufferSize[0] = size; } TFE_RenderBackend::captureScreenToMemory(s_imageBuffer[0]); - - // Scale and crop the image to fit inside 426 x 240 (widescreen). - s64 scale = SAVE_IMAGE_HEIGHT * 65536 / displayInfo.height; - s64 invScale = displayInfo.height * 65536 / SAVE_IMAGE_HEIGHT; - s32 scaledWidth = s32((displayInfo.width * scale) >> 16ll); - s32 newWidth = SAVE_IMAGE_WIDTH, newHeight = SAVE_IMAGE_HEIGHT; - - s32 dstOffset = 0; - s64 srcOffset = 0; - if (scaledWidth < newWidth) - { - dstOffset = (newWidth - scaledWidth) / 2; - } - else if (scaledWidth > newWidth) - { - srcOffset = (scaledWidth - newWidth) / 2; - srcOffset = srcOffset * invScale; - } - - size_t newSize = newWidth * newHeight * 4; - if (newSize > s_imageBufferSize[1]) - { - s_imageBuffer[1] = (u32*)realloc(s_imageBuffer[1], newSize); - s_imageBufferSize[1] = newSize; - } - - const u32 *src; - u32* dst = s_imageBuffer[1]; - memset(dst, 0, newWidth * newHeight * 4); - - s64 u = srcOffset, v = 0; - s64 du = invScale, dv = invScale; - for (s32 y = 0; y < newHeight; y++, v += dv, dst += newWidth) - { - u = srcOffset; - src = &s_imageBuffer[0][(v >> 16ll) * displayInfo.width]; - for (s32 x = dstOffset; x < newWidth - dstOffset; x++, u += du) - { - dst[x] = src[u >> 16ll]; - } - } - // Save to memory. - u8* png = (u8*)malloc(newSize); + u8* png = (u8*)malloc(SAVE_IMAGE_WIDTH * SAVE_IMAGE_HEIGHT * 4); // FIXME: check memory! - u32 pngSize = (u32)TFE_Image::writeImageToMemory(png, newWidth, newHeight, s_imageBuffer[1]); + u32 pngSize = (u32)TFE_Image::writeImageToMemory(png, displayInfo.width, displayInfo.height, + SAVE_IMAGE_WIDTH, SAVE_IMAGE_HEIGHT, + s_imageBuffer[0]); // Master version. u32 version = SVER_CUR; From 9817b642c86938c3ae031d9cd739fe0218e07fc5 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Fri, 29 Sep 2023 09:59:59 +0200 Subject: [PATCH 03/10] Fix screenshot image orientation OpenGL's origin is the lower left corner, while the rest of the world places it in the upper left. Need to flip the captured framebuffer vertically for a savegame screenshot. --- TheForceEngine/TFE_Asset/imageAsset.cpp | 4 ++-- TheForceEngine/TFE_Game/saveSystem.cpp | 1 - .../Win32OpenGL/screenCapture.cpp | 24 +++++++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/TheForceEngine/TFE_Asset/imageAsset.cpp b/TheForceEngine/TFE_Asset/imageAsset.cpp index 980eef898..476c45430 100644 --- a/TheForceEngine/TFE_Asset/imageAsset.cpp +++ b/TheForceEngine/TFE_Asset/imageAsset.cpp @@ -203,8 +203,8 @@ namespace TFE_Image return 0; if ((srcw != dstw) || (srch != dsth)) { - const SDL_Rect rs = { .x = 0, .y = 0, .w = srcw, .h = srch }; - const SDL_Rect rd = { .x = 0, .y = 0, .w = dstw, .h = dsth }; + const SDL_Rect rs = { 0, 0, srcw, srch }; + const SDL_Rect rd = { 0, 0, dstw, dsth }; SDL_Surface* scaled = SDL_CreateRGBSurface(0, dstw, dsth, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000); if (!scaled) diff --git a/TheForceEngine/TFE_Game/saveSystem.cpp b/TheForceEngine/TFE_Game/saveSystem.cpp index 1f785303f..3a5013588 100644 --- a/TheForceEngine/TFE_Game/saveSystem.cpp +++ b/TheForceEngine/TFE_Game/saveSystem.cpp @@ -54,7 +54,6 @@ namespace TFE_SaveSystem u32 pngSize = (u32)TFE_Image::writeImageToMemory(png, displayInfo.width, displayInfo.height, SAVE_IMAGE_WIDTH, SAVE_IMAGE_HEIGHT, s_imageBuffer[0]); - // Master version. u32 version = SVER_CUR; stream->write(&version); diff --git a/TheForceEngine/TFE_RenderBackend/Win32OpenGL/screenCapture.cpp b/TheForceEngine/TFE_RenderBackend/Win32OpenGL/screenCapture.cpp index dfffdf7f6..f737c1f83 100644 --- a/TheForceEngine/TFE_RenderBackend/Win32OpenGL/screenCapture.cpp +++ b/TheForceEngine/TFE_RenderBackend/Win32OpenGL/screenCapture.cpp @@ -94,10 +94,34 @@ bool ScreenCapture::changeBufferCount(u32 newBufferCount, bool forceRealloc/* = return m_bufferCount; } +static void flipVert32bpp(void* mem, u32 w, u32 h) +{ + u32 stride = w * 4; + const u32 size = stride * h; + // increase copysize to at least a certain size for perf reasons. + while (stride < 16384) + stride *= 2; + char* upper = (char *)mem; + char* lower = (char *)mem + size - stride; + char* tmpb = (char *)malloc(stride); + while (tmpb && (upper < lower)) { + memcpy(tmpb, upper, stride); + memcpy(upper, lower, stride); + memcpy(lower, tmpb, stride); + upper += stride; + lower -= stride; + } + free(tmpb); +} + void ScreenCapture::captureFrontBufferToMemory(u32* mem) { glReadBuffer(GL_FRONT); glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, mem); + + // Need to flip image upside-down. OpenGL has (0|0) at lower left + // corner, while the rest of the world places it in the upper left. + flipVert32bpp(mem, m_width, m_height); } void ScreenCapture::update(bool flush) From ea082ef9c2d27077c211413f6d8ee0df4d282834 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Fri, 29 Sep 2023 10:31:21 +0200 Subject: [PATCH 04/10] SDL_Image: replace "struct Image" with SDL_Surface Didn't check the editor code though.. --- TheForceEngine/TFE_Asset/imageAsset.cpp | 65 ++++---------------- TheForceEngine/TFE_Asset/imageAsset.h | 16 ++--- TheForceEngine/TFE_Asset/textureAsset.cpp | 23 +++---- TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp | 8 +-- TheForceEngine/TFE_FrontEndUI/modLoader.cpp | 19 +++--- TheForceEngine/TFE_Game/reticle.cpp | 4 +- TheForceEngine/TFE_Game/saveSystem.cpp | 8 +-- TheForceEngine/TFE_Ui/markdown.cpp | 4 +- 8 files changed, 50 insertions(+), 97 deletions(-) diff --git a/TheForceEngine/TFE_Asset/imageAsset.cpp b/TheForceEngine/TFE_Asset/imageAsset.cpp index 476c45430..d7e085fe0 100644 --- a/TheForceEngine/TFE_Asset/imageAsset.cpp +++ b/TheForceEngine/TFE_Asset/imageAsset.cpp @@ -13,7 +13,7 @@ namespace TFE_Image { - typedef std::map ImageMap; + typedef std::map ImageMap; static ImageMap s_images; static std::vector s_buffer; @@ -62,7 +62,7 @@ namespace TFE_Image IMG_Quit(); } - Image* loadFromMemory(const u8* buffer, size_t size) + SDL_Surface* loadFromMemory(const u8* buffer, size_t size) { SDL_RWops* memops = SDL_RWFromConstMem(buffer, size); if (!memops) @@ -76,18 +76,10 @@ namespace TFE_Image if (!sdlimg) return nullptr; - Image* image = new Image; - - image->sdl = sdlimg; - image->width = (u32)sdlimg->w; - image->height = (u32)sdlimg->h; - image->data = (u32*)sdlimg->pixels; - SDL_LockSurface(sdlimg); // required to manipulate the pixel buffer - - return image; + return sdlimg; } - Image* get(const char* imagePath) + SDL_Surface* get(const char* imagePath) { ImageMap::iterator iImage = s_images.find(imagePath); if (iImage != s_images.end()) @@ -103,37 +95,20 @@ namespace TFE_Image if (!sdlimg) return nullptr; - Image* image = new Image; - if (!image) - { - SDL_FreeSurface(sdlimg); - return nullptr; - } - - image->sdl = sdlimg; - image->width = (u32)sdlimg->w; - image->height = (u32)sdlimg->h; - image->data = (u32*)sdlimg->pixels; - SDL_LockSurface(sdlimg); // required to manipulate the pixel buffer - - s_images[imagePath] = image; - return image; + s_images[imagePath] = sdlimg; + return sdlimg; } - void free(Image* image) + void free(SDL_Surface* image) { if (!image) { return; } - SDL_UnlockSurface(image->sdl); - SDL_FreeSurface(image->sdl); - image->sdl = nullptr; - + SDL_FreeSurface(image); ImageMap::iterator iImage = s_images.begin(); for (; iImage != s_images.end(); ++iImage) { if (iImage->second == image) { - delete iImage->second; s_images.erase(iImage); break; } @@ -145,13 +120,11 @@ namespace TFE_Image ImageMap::iterator iImage = s_images.begin(); for (; iImage != s_images.end(); ++iImage) { - Image* image = iImage->second; + SDL_Surface* image = iImage->second; if (image) { - SDL_UnlockSurface(image->sdl); - SDL_FreeSurface(image->sdl); + SDL_FreeSurface(image); } - delete image; } s_images.clear(); } @@ -242,26 +215,14 @@ namespace TFE_Image return written; } - void readImageFromMemory(Image* output, size_t size, const u32* pixelData) + void readImageFromMemory(SDL_Surface** output, size_t size, const u32* pixelData) { SDL_RWops* memops = SDL_RWFromConstMem(pixelData, size); if (!memops) return; SDL_Surface* sdlimg = IMG_Load_RW(memops, 1); - if (!sdlimg) - return; - - if (output->sdl) - { - SDL_UnlockSurface(output->sdl); - SDL_FreeSurface(output->sdl); - } - - output->sdl = sdlimg; - output->width = (u32)sdlimg->w; - output->height = (u32)sdlimg->h; - output->data = (u32*)sdlimg->pixels; - SDL_LockSurface(sdlimg); // required to manipulate the pixel buffer + if (output) + *output = sdlimg; } } diff --git a/TheForceEngine/TFE_Asset/imageAsset.h b/TheForceEngine/TFE_Asset/imageAsset.h index 6f64298da..56bf60419 100644 --- a/TheForceEngine/TFE_Asset/imageAsset.h +++ b/TheForceEngine/TFE_Asset/imageAsset.h @@ -5,26 +5,18 @@ #include #include -struct Image -{ - SDL_Surface* sdl = nullptr; - u32 width = 0u; - u32 height = 0u; - u32* data = nullptr; -}; - namespace TFE_Image { void init(); void shutdown(); - Image* get(const char* imagePath); - Image* loadFromMemory(const u8* buffer, size_t size); - void free(Image* image); + SDL_Surface* get(const char* imagePath); + SDL_Surface* loadFromMemory(const u8* buffer, size_t size); + void free(SDL_Surface* image); void freeAll(); void writeImage(const char* path, u32 width, u32 height, u32* pixelData); size_t writeImageToMemory(u8* output, u32 srcw, u32 srch, u32 dstw, u32 dsth, const u32* pixelData); - void readImageFromMemory(Image* output, size_t size, const u32* pixelData); + void readImageFromMemory(SDL_Surface** output, size_t size, const u32* pixelData); } diff --git a/TheForceEngine/TFE_Asset/textureAsset.cpp b/TheForceEngine/TFE_Asset/textureAsset.cpp index d7f900e86..3bd48a8bf 100644 --- a/TheForceEngine/TFE_Asset/textureAsset.cpp +++ b/TheForceEngine/TFE_Asset/textureAsset.cpp @@ -572,7 +572,7 @@ namespace TFE_Texture return index; } - Texture* convertImageToTexture_8bit(const char* name, const Image* image, const char* paletteName) + Texture* convertImageToTexture_8bit(const char* name, const SDL_Surface* image, const char* paletteName) { TextureMap::iterator iTex = s_textures.find(name); if (iTex != s_textures.end()) @@ -591,7 +591,7 @@ namespace TFE_Texture strcpy(texture->name, name); // Allocate memory. - texture->memory = new u8[sizeof(TextureFrame) + image->width * image->height]; + texture->memory = new u8[sizeof(TextureFrame) + image->w * image->h]; texture->frames = (TextureFrame*)texture->memory; texture->frameCount = 1; texture->frameRate = 0; // arbitrary. @@ -599,23 +599,24 @@ namespace TFE_Texture texture->frames[0].image = texture->memory + sizeof(TextureFrame); u8* imageOut = texture->frames[0].image; - texture->frames[0].width = image->width; - texture->frames[0].height = image->height; + texture->frames[0].width = image->w; + texture->frames[0].height = image->h; texture->frames[0].logSizeY = 0; texture->frames[0].offsetX = 0; texture->frames[0].offsetY = 0; texture->frames[0].opacity = TEX_OPACITY_TRANS; - texture->frames[0].uvWidth = image->width; - texture->frames[0].uvHeight = image->height; + texture->frames[0].uvWidth = image->w; + texture->frames[0].uvHeight = image->h; // For now look for the closest "manhattan" match. - s32 pixelCount = image->width * image->height; + s32 pixelCount = image->w * image->h; for (s32 i = 0; i < pixelCount; i++) { - u8 srcR = image->data[i] & 0xffu; - u8 srcG = (image->data[i] >> 8u) & 0xff; - u8 srcB = (image->data[i] >> 16u) & 0xff; - u8 srcA = (image->data[i] >> 24u) & 0xff; + u32 pixel = ((u32*)(image->pixels))[i]; + u8 srcR = pixel & 0xffu; + u8 srcG = (pixel >> 8u) & 0xff; + u8 srcB = (pixel >> 16u) & 0xff; + u8 srcA = (pixel >> 24u) & 0xff; if (srcA < 128u) { diff --git a/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp b/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp index 7264a29a8..0c3457795 100644 --- a/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp +++ b/TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp @@ -275,13 +275,13 @@ namespace TFE_FrontEndUI memset(imagePath, 0, TFE_MAX_PATH); TFE_Paths::appendPath(TFE_PathType::PATH_PROGRAM, localPath, imagePath, TFE_MAX_PATH); } - Image* image = TFE_Image::get(imagePath); + SDL_Surface* image = TFE_Image::get(imagePath); if (image) { - TextureGpu* gpuImage = TFE_RenderBackend::createTexture(image->width, image->height, image->data, MAG_FILTER_LINEAR); + TextureGpu* gpuImage = TFE_RenderBackend::createTexture(image->w, image->h, (u32*)image->pixels, MAG_FILTER_LINEAR); uiImage->image = TFE_RenderBackend::getGpuPtr(gpuImage); - uiImage->width = image->width; - uiImage->height = image->height; + uiImage->width = image->w; + uiImage->height = image->h; return true; } return false; diff --git a/TheForceEngine/TFE_FrontEndUI/modLoader.cpp b/TheForceEngine/TFE_FrontEndUI/modLoader.cpp index f3b6e4bf5..c6d3fc927 100644 --- a/TheForceEngine/TFE_FrontEndUI/modLoader.cpp +++ b/TheForceEngine/TFE_FrontEndUI/modLoader.cpp @@ -1014,16 +1014,15 @@ namespace TFE_FrontEndUI zipArchive.readFile(s_imageBuffer.data(), imageSize); zipArchive.closeFile(); - Image* image = TFE_Image::loadFromMemory((u8*)s_imageBuffer.data(), imageSize); + SDL_Surface* image = TFE_Image::loadFromMemory((u8*)s_imageBuffer.data(), imageSize); if (image) { - TextureGpu* gpuImage = TFE_RenderBackend::createTexture(image->width, image->height, image->data, MAG_FILTER_LINEAR); + TextureGpu* gpuImage = TFE_RenderBackend::createTexture(image->w, image->h, (u32*)image->pixels, MAG_FILTER_LINEAR); poster->texture = gpuImage; - poster->width = image->width; - poster->height = image->height; + poster->width = image->w; + poster->height = image->h; - delete[] image->data; - delete image; + TFE_Image::free(image); } } zipArchive.close(); @@ -1033,13 +1032,13 @@ namespace TFE_FrontEndUI char imagePath[TFE_MAX_PATH]; sprintf(imagePath, "%s%s", baseDir, imageFileName); - Image* image = TFE_Image::get(imagePath); + SDL_Surface* image = TFE_Image::get(imagePath); if (image) { - TextureGpu* gpuImage = TFE_RenderBackend::createTexture(image->width, image->height, image->data, MAG_FILTER_LINEAR); + TextureGpu* gpuImage = TFE_RenderBackend::createTexture(image->w, image->h, (u32*)image->pixels, MAG_FILTER_LINEAR); poster->texture = gpuImage; - poster->width = image->width; - poster->height = image->height; + poster->width = image->w; + poster->height = image->h; } } } diff --git a/TheForceEngine/TFE_Game/reticle.cpp b/TheForceEngine/TFE_Game/reticle.cpp index 61a3a0716..697b2065d 100644 --- a/TheForceEngine/TFE_Game/reticle.cpp +++ b/TheForceEngine/TFE_Game/reticle.cpp @@ -36,14 +36,14 @@ bool reticle_init() TFE_Paths::appendPath(TFE_PathType::PATH_PROGRAM, "UI_Images/ReticleAtlas.png", imagePath, TFE_MAX_PATH); } - Image* image = TFE_Image::get(imagePath); + SDL_Surface* image = TFE_Image::get(imagePath); if (!image) { TFE_System::logWrite(LOG_ERROR, "Reticle", "Cannot load reticle atlas: '%s'.", imagePath); return false; } - s_reticleImage.texture = TFE_RenderBackend::createTexture(image->width, image->height, image->data); + s_reticleImage.texture = TFE_RenderBackend::createTexture(image->w, image->h, (u32*)image->pixels); s_reticleImage.overlayX = 0; s_reticleImage.overlayY = 0; s_reticleImage.overlayWidth = 32; diff --git a/TheForceEngine/TFE_Game/saveSystem.cpp b/TheForceEngine/TFE_Game/saveSystem.cpp index 3a5013588..b7393518e 100644 --- a/TheForceEngine/TFE_Game/saveSystem.cpp +++ b/TheForceEngine/TFE_Game/saveSystem.cpp @@ -137,13 +137,13 @@ namespace TFE_SaveSystem } stream->readBuffer(s_imageBuffer[0], pngSize); - Image image = { 0 }; + SDL_Surface* image; TFE_Image::readImageFromMemory(&image, pngSize, s_imageBuffer[0]); - if (image.width == SAVE_IMAGE_WIDTH && image.height == SAVE_IMAGE_HEIGHT) + if (image) { const u32 sz = SAVE_IMAGE_WIDTH * SAVE_IMAGE_HEIGHT * sizeof(u32); - memcpy(header->imageData, image.data, sz); - TFE_Image::free(&image); + memcpy(header->imageData, image->pixels, sz); + TFE_Image::free(image); } } diff --git a/TheForceEngine/TFE_Ui/markdown.cpp b/TheForceEngine/TFE_Ui/markdown.cpp index d87265203..9d8527c08 100644 --- a/TheForceEngine/TFE_Ui/markdown.cpp +++ b/TheForceEngine/TFE_Ui/markdown.cpp @@ -95,10 +95,10 @@ namespace TFE_Markdown return iTexture->second; } - const Image* image = TFE_Image::get(path); + const SDL_Surface* image = TFE_Image::get(path); if (!image) { return nullptr; } - TextureGpu* texture = TFE_RenderBackend::createTexture(image->width, image->height, image->data); + TextureGpu* texture = TFE_RenderBackend::createTexture(image->w, image->h, (u32*)image->pixels); if (texture) { s_textures[path] = texture; } return texture; } From 16a0475039d7a2bb0a7e6e25091ba533aa8b60ea Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Fri, 29 Sep 2023 10:38:14 +0200 Subject: [PATCH 05/10] README.md: Linux: mention updated requirements drop devIL, add SDL2-image --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0b7e13b0f..7984bb267 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,8 @@ Runtime data like Savegames, Configuration, Mods, ... are by default stored at _ This can be overridden by defining the "__TFE_DATA_HOME__" environment variable. ### Required Libraries -* [SDL2](TheForceEngine/TFE_FrontEndUI/frontEndUi.cpp) 2.24 or higher -* [devIL](https://openil.sourceforge.net) +* [SDL2](http://libsdl.org) Version 2.24 +* [SDL2-image](https://github.com/libsdl-org/SDL_image) Version 2.6.3 * [GLEW](http://glew.sourceforge.net/) 2.2.0 * OpenGL 3.3 capable driver (latest [mesa](https://www.mesa3d.org) or nvidia proprietary driver recommended) * [RtMidi](https://www.music.mcgill.ca/~gary/rtmidi/) 5.0.0 or higher for external MIDI Synthesizer support From d2a209e3c11bcb9c1ef72b04d8c2b6d72161e8d9 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Fri, 29 Sep 2023 10:47:30 +0200 Subject: [PATCH 06/10] SDL-image: fix up editor not build-tested though. --- TheForceEngine/TFE_Editor/levelEditor.cpp | 4 ++-- TheForceEngine/TFE_Editor/levelEditorData.cpp | 24 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/TheForceEngine/TFE_Editor/levelEditor.cpp b/TheForceEngine/TFE_Editor/levelEditor.cpp index f1763082c..ae08b1e1e 100644 --- a/TheForceEngine/TFE_Editor/levelEditor.cpp +++ b/TheForceEngine/TFE_Editor/levelEditor.cpp @@ -317,10 +317,10 @@ namespace LevelEditor { char imagePath[TFE_MAX_PATH]; TFE_Paths::appendPath(TFE_PathType::PATH_PROGRAM, localPath, imagePath, TFE_MAX_PATH); - Image* image = TFE_Image::get(imagePath); + SDL_Surface* image = TFE_Image::get(imagePath); if (image) { - TextureGpu* editCtrlHandle = TFE_RenderBackend::createTexture(image->width, image->height, image->data); + TextureGpu* editCtrlHandle = TFE_RenderBackend::createTexture(image->w, image->h, (u32*)image->pixels); return TFE_RenderBackend::getGpuPtr(editCtrlHandle); } return nullptr; diff --git a/TheForceEngine/TFE_Editor/levelEditorData.cpp b/TheForceEngine/TFE_Editor/levelEditorData.cpp index 953577768..c20d06f39 100644 --- a/TheForceEngine/TFE_Editor/levelEditorData.cpp +++ b/TheForceEngine/TFE_Editor/levelEditorData.cpp @@ -127,16 +127,16 @@ namespace LevelEditorData if (tex) { return tex; } TFE_Paths::appendPath(TFE_PathType::PATH_PROGRAM, "UI_Images/SpiritObject.png", imagePath, TFE_MAX_PATH); - Image* image = TFE_Image::get(imagePath); + SDL_Surface* image = TFE_Image::get(imagePath); if (image) { s_objIcons.push_back({}); tex = &s_objIcons.back(); tex->scale = { 1.0f, 1.0f }; - tex->texture = TFE_RenderBackend::createTexture(image->width, image->height, image->data); - tex->width = image->width; - tex->height = image->height; + tex->texture = TFE_RenderBackend::createTexture(image->w, image->h, (u32*)image->pixels); + tex->width = image->w; + tex->height = image->h; strcpy(tex->name, "SpiritObject.png"); s_editorLevel.textureMap[tex->name] = tex; @@ -149,16 +149,16 @@ namespace LevelEditorData if (tex) { return tex; } TFE_Paths::appendPath(TFE_PathType::PATH_PROGRAM, "UI_Images/SafeObject.png", imagePath, TFE_MAX_PATH); - Image* image = TFE_Image::get(imagePath); + SDL_Surface* image = TFE_Image::get(imagePath); if (image) { s_objIcons.push_back({}); tex = &s_objIcons.back(); tex->scale = { 1.0f, 1.0f }; - tex->texture = TFE_RenderBackend::createTexture(image->width, image->height, image->data); - tex->width = image->width; - tex->height = image->height; + tex->texture = TFE_RenderBackend::createTexture(image->w, image->h, (u32*)image->pixels); + tex->width = image->w; + tex->height = image->h; strcpy(tex->name, "SafeObject.png"); s_editorLevel.textureMap[tex->name] = tex; @@ -221,16 +221,16 @@ namespace LevelEditorData if (tex) { return tex; } TFE_Paths::appendPath(TFE_PathType::PATH_PROGRAM, "UI_Images/SoundObject.png", imagePath, TFE_MAX_PATH); - Image* image = TFE_Image::get(imagePath); + SDL_Surface* image = TFE_Image::get(imagePath); if (image) { s_objIcons.push_back({}); tex = &s_objIcons.back(); tex->scale = { 1.0f, 1.0f }; - tex->texture = TFE_RenderBackend::createTexture(image->width, image->height, image->data); - tex->width = image->width; - tex->height = image->height; + tex->texture = TFE_RenderBackend::createTexture(image->w, image->h, (u32*)image->pixels); + tex->width = image->w; + tex->height = image->h; strcpy(tex->name, "SoundObject.png"); s_editorLevel.textureMap[tex->name] = tex; From 757c7e16a8246400f3b706c5958ffc0397888897 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Fri, 29 Sep 2023 20:09:34 +0200 Subject: [PATCH 07/10] Fix braino in vertical flip --- .../TFE_RenderBackend/Win32OpenGL/screenCapture.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/TheForceEngine/TFE_RenderBackend/Win32OpenGL/screenCapture.cpp b/TheForceEngine/TFE_RenderBackend/Win32OpenGL/screenCapture.cpp index f737c1f83..4981cad20 100644 --- a/TheForceEngine/TFE_RenderBackend/Win32OpenGL/screenCapture.cpp +++ b/TheForceEngine/TFE_RenderBackend/Win32OpenGL/screenCapture.cpp @@ -96,11 +96,8 @@ bool ScreenCapture::changeBufferCount(u32 newBufferCount, bool forceRealloc/* = static void flipVert32bpp(void* mem, u32 w, u32 h) { - u32 stride = w * 4; + const u32 stride = w * 4; const u32 size = stride * h; - // increase copysize to at least a certain size for perf reasons. - while (stride < 16384) - stride *= 2; char* upper = (char *)mem; char* lower = (char *)mem + size - stride; char* tmpb = (char *)malloc(stride); From 59a73ecb933592178f9f42c593f8cf6f968bfc44 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Fri, 29 Sep 2023 20:46:07 +0200 Subject: [PATCH 08/10] fix whitespace issue --- TheForceEngine/TFE_Asset/imageAsset.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TheForceEngine/TFE_Asset/imageAsset.cpp b/TheForceEngine/TFE_Asset/imageAsset.cpp index d7e085fe0..c52f9f007 100644 --- a/TheForceEngine/TFE_Asset/imageAsset.cpp +++ b/TheForceEngine/TFE_Asset/imageAsset.cpp @@ -67,7 +67,7 @@ namespace TFE_Image SDL_RWops* memops = SDL_RWFromConstMem(buffer, size); if (!memops) return nullptr; - + SDL_Surface* sdlimg = IMG_Load_RW(memops, 1); if (!sdlimg) return nullptr; From 4935ce287b0f9af5a7b3f6b6abdfd9220dd54996 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Fri, 29 Sep 2023 20:52:58 +0200 Subject: [PATCH 09/10] Even more tydings --- TheForceEngine/TFE_Asset/imageAsset.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/TheForceEngine/TFE_Asset/imageAsset.cpp b/TheForceEngine/TFE_Asset/imageAsset.cpp index c52f9f007..ba7165d13 100644 --- a/TheForceEngine/TFE_Asset/imageAsset.cpp +++ b/TheForceEngine/TFE_Asset/imageAsset.cpp @@ -37,7 +37,7 @@ namespace TFE_Image .Bshift = 16, .Ashift = 24 }; - + SDL_Surface* n = SDL_ConvertSurface(src, &rgba32, 0); SDL_FreeSurface(src); return n; @@ -139,15 +139,15 @@ namespace TFE_Image int ret = IMG_SavePNG(surf, path); if (ret != 0) { - fprintf(stderr, "writeImage(%s) failed '%s'\n", path, SDL_GetError()); + TFE_System::logWrite(LOG_ERROR, "writeImage", "Saving PNG '%s' failed with '%s'", path, SDL_GetError()); } } ////////////////////////////////////////////////////// // Wacky file override to get SDL-Image to write - // images to memory. + // images to memory. SDL_RWmemOps by default do not support writing. ////////////////////////////////////////////////////// - static size_t SDLCALL _sdl_wop_mem(struct SDL_RWops * context, const void *ptr, + static size_t SDLCALL _sdl_wop_mem(struct SDL_RWops* context, const void *ptr, size_t size, size_t num) { const size_t bytes = num * size; @@ -176,14 +176,14 @@ namespace TFE_Image return 0; if ((srcw != dstw) || (srch != dsth)) { - const SDL_Rect rs = { 0, 0, srcw, srch }; - const SDL_Rect rd = { 0, 0, dstw, dsth }; + const SDL_Rect rs = { 0, 0, (int)srcw, (int)srch }; + const SDL_Rect rd = { 0, 0, (int)dstw, (int)dsth }; SDL_Surface* scaled = SDL_CreateRGBSurface(0, dstw, dsth, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000); if (!scaled) { - SDL_FreeSurface(surf); - return 0; + SDL_FreeSurface(surf); + return 0; } ret = SDL_SoftStretchLinear(surf, &rs, scaled, &rd); if (ret != 0) @@ -220,7 +220,7 @@ namespace TFE_Image SDL_RWops* memops = SDL_RWFromConstMem(pixelData, size); if (!memops) return; - + SDL_Surface* sdlimg = IMG_Load_RW(memops, 1); if (output) *output = sdlimg; From 268edddba1bd56a2ed193214e0b9ca0e621bd1e9 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Fri, 29 Sep 2023 20:56:10 +0200 Subject: [PATCH 10/10] saveGame: write zero sized PNG if pixmem alloc fails --- TheForceEngine/TFE_Game/saveSystem.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/TheForceEngine/TFE_Game/saveSystem.cpp b/TheForceEngine/TFE_Game/saveSystem.cpp index b7393518e..138d5158d 100644 --- a/TheForceEngine/TFE_Game/saveSystem.cpp +++ b/TheForceEngine/TFE_Game/saveSystem.cpp @@ -50,10 +50,16 @@ namespace TFE_SaveSystem TFE_RenderBackend::captureScreenToMemory(s_imageBuffer[0]); // Save to memory. u8* png = (u8*)malloc(SAVE_IMAGE_WIDTH * SAVE_IMAGE_HEIGHT * 4); - // FIXME: check memory! - u32 pngSize = (u32)TFE_Image::writeImageToMemory(png, displayInfo.width, displayInfo.height, + if (png) + { + u32 pngSize = (u32)TFE_Image::writeImageToMemory(png, displayInfo.width, displayInfo.height, SAVE_IMAGE_WIDTH, SAVE_IMAGE_HEIGHT, s_imageBuffer[0]); + } else { + pngSize = 0; + png = s_imageBuffer[0]; + } + // Master version. u32 version = SVER_CUR; stream->write(&version);