diff --git a/conanfile.py b/conanfile.py index ae2e91f83..ded1b9a0e 100644 --- a/conanfile.py +++ b/conanfile.py @@ -17,7 +17,7 @@ class StormEngine(ConanFile): # dependencies used in deploy binaries # conan-center - requires = ["zlib/1.2.13", "spdlog/1.9.2", "fast_float/3.4.0", "mimalloc/2.0.3", "sentry-native/0.5.0", + requires = ["zlib/1.2.13", "spdlog/1.9.2", "fast_float/3.4.0", "mimalloc/2.0.3", "freeimage/3.18.0", "sentry-native/0.5.0", # storm.jfrog.io "directx/9.0@storm/prebuilt", "fmod/2.02.05@storm/prebuilt"] # aux dependencies (e.g. for tests) @@ -37,6 +37,15 @@ def requirements(self): self.requires("steamworks/1.5.1@storm/prebuilt") if self.options.conan_sdl: self.requires("sdl/2.0.18") + self.options["freeimage"].with_jpeg = "libjpeg-turbo" + self.options["freeimage"].with_png = True + self.options["freeimage"].with_tiff = False + self.options["freeimage"].with_jpeg2000 = False + self.options["freeimage"].with_openexr = False + self.options["freeimage"].with_eigen = False + self.options["freeimage"].with_webp = False + self.options["freeimage"].with_raw = False + self.options["freeimage"].with_jxr = False generators = "cmake_multi" diff --git a/src/libs/renderer/CMakeLists.txt b/src/libs/renderer/CMakeLists.txt index 682f7219c..f71ad7167 100644 --- a/src/libs/renderer/CMakeLists.txt +++ b/src/libs/renderer/CMakeLists.txt @@ -7,5 +7,5 @@ endif() STORM_SETUP( TARGET_NAME renderer TYPE storm_module - DEPENDENCIES core directx util ${SYSTEM_DEPS} + DEPENDENCIES core directx util freeimage ${SYSTEM_DEPS} ) diff --git a/src/libs/renderer/include/storm/renderer/image.hpp b/src/libs/renderer/include/storm/renderer/image.hpp new file mode 100644 index 000000000..0886899e3 --- /dev/null +++ b/src/libs/renderer/include/storm/renderer/image.hpp @@ -0,0 +1,16 @@ +#pragma once + +namespace storm::renderer +{ + +class Image { + public: + size_t width{}; + size_t height{}; + size_t pitch{}; + uint32_t type{}; + uint32_t bpp{}; + uint8_t *data{}; +}; + +} // namespace storm::renderer diff --git a/src/libs/renderer/include/storm/renderer/image_loader.hpp b/src/libs/renderer/include/storm/renderer/image_loader.hpp new file mode 100644 index 000000000..c009ad8a9 --- /dev/null +++ b/src/libs/renderer/include/storm/renderer/image_loader.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "image.hpp" + +#include + +namespace storm::renderer +{ + +class ImageLoader final +{ + public: + ImageLoader(); + ~ImageLoader(); + + std::unique_ptr LoadImageFromFile(const istring &path); + + static void CopyImageToBuffer(const Image& image, uint8_t *destination); + + private: + class Impl; + std::unique_ptr impl_; +}; + +} // namespace storm::renderer diff --git a/src/libs/renderer/src/s_device.cpp b/src/libs/renderer/src/s_device.cpp index 778312fa0..82241354d 100644 --- a/src/libs/renderer/src/s_device.cpp +++ b/src/libs/renderer/src/s_device.cpp @@ -1461,7 +1461,7 @@ bool DX9RENDER::TextureLoad(int32_t t) path_to_tex.replace_extension(); if (exists(path_to_tex)) { - return TextureLoadUsingD3DX(path_to_tex.string().c_str(), t); + return TextureLoadFromFile(path_to_tex.string().c_str(), t); } if (bTrace) { @@ -1768,32 +1768,49 @@ bool DX9RENDER::TextureLoad(int32_t t) return true; } -bool DX9RENDER::TextureLoadUsingD3DX(const char* path, int32_t t) +bool DX9RENDER::TextureLoadFromFile(const char* path, int32_t t) { -#ifdef _WIN32 // TextureLoadUsingD3DX - used only for loading raw Targa - // TODO: reimplement the whole thing in a tidy way - IDirect3DTexture9 *pTex; - if(CHECKD3DERR(D3DXCreateTextureFromFileA(d3d9, path, &pTex))) - { + auto image = imageLoader_.LoadImageFromFile(path); + + if (image) { + IDirect3DTexture9 *texture; + const auto d3d_format = image->bpp == 24 ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8; + if (CHECKD3DERR(d3d9->CreateTexture(image->width, image->height, 0, 0, d3d_format, D3DPOOL_MANAGED, &texture, + NULL))) { + delete Textures[t].name; + Textures[t].name = nullptr; + return false; + } + + IDirect3DSurface9 *surface = nullptr; + texture->GetSurfaceLevel(0, &surface); + D3DLOCKED_RECT rect; + if (CHECKD3DERR(surface->LockRect(&rect, nullptr, 0))) { + delete Textures[t].name; + Textures[t].name = nullptr; + return {}; + } + imageLoader_.CopyImageToBuffer(*image, static_cast(rect.pBits)); + surface->UnlockRect(); + surface->Release(); + + D3DSURFACE_DESC desc; + texture->GetLevelDesc(0, &desc); + + Textures[t].hash = 0; + Textures[t].ref = 1; + Textures[t].d3dtex = texture; + Textures[t].isCubeMap = false; + Textures[t].dwSize = desc.Height * desc.Width * 4; + Textures[t].loaded = true; + + return true; + } + else { delete Textures[t].name; Textures[t].name = nullptr; return false; } - - D3DSURFACE_DESC desc; - pTex->GetLevelDesc(0, &desc); - - Textures[t].hash = 0; - Textures[t].ref = 1; - Textures[t].d3dtex = pTex; - Textures[t].isCubeMap = false; - Textures[t].dwSize = desc.Height * desc.Width * 4; - Textures[t].loaded = true; - - return true; -#else - return false; -#endif } IDirect3DBaseTexture9 *DX9RENDER::GetBaseTexture(int32_t iTexture) diff --git a/src/libs/renderer/src/s_device.h b/src/libs/renderer/src/s_device.h index 177559dc5..119345df4 100644 --- a/src/libs/renderer/src/s_device.h +++ b/src/libs/renderer/src/s_device.h @@ -13,6 +13,7 @@ #include "d3d9types.h" #include "script_libriary.h" +#include "storm/renderer/image_loader.hpp" #include #include @@ -462,6 +463,8 @@ class DX9RENDER : public VDX9RENDER IDirect3D9 *d3d; HWND hwnd; + storm::renderer::ImageLoader imageLoader_; + CVECTOR Pos, Ang; float Fov; @@ -599,5 +602,5 @@ class DX9RENDER : public VDX9RENDER std::string screenshotExt; bool TextureLoad(int32_t texid); - bool TextureLoadUsingD3DX(const char *path, int32_t texid); + bool TextureLoadFromFile(const char *path, int32_t t); }; diff --git a/src/libs/renderer/src/storm/renderer/image_loader.cpp b/src/libs/renderer/src/storm/renderer/image_loader.cpp new file mode 100644 index 000000000..0a6cbfb67 --- /dev/null +++ b/src/libs/renderer/src/storm/renderer/image_loader.cpp @@ -0,0 +1,118 @@ +#include "storm/renderer/image_loader.hpp" + +#include + +namespace storm::renderer +{ + +namespace { + +class FreeImage final { + public: + FreeImage(); + ~FreeImage(); +}; + +FreeImage::FreeImage() +{ + FreeImage_Initialise(false); +} + +FreeImage::~FreeImage() +{ + FreeImage_DeInitialise(); +} + +} // namespace + +class ImageLoader::Impl +{ + public: + Impl(); + + std::shared_ptr freeImage_; + + static std::weak_ptr FreeImageInstance; + + static std::shared_ptr getGlobalFreeImageInstance(); + + friend ImageLoader; +}; + +std::weak_ptr ImageLoader::Impl::FreeImageInstance{}; + +ImageLoader::ImageLoader() + : impl_(std::make_unique()) +{ + +} + +ImageLoader::~ImageLoader() = default; + +std::unique_ptr ImageLoader::LoadImageFromFile(const istring &path) +{ + const auto image_type = FreeImage_GetFileType(path.c_str(), 0); + + if (image_type != FIF_UNKNOWN) + { + FIBITMAP *image = FreeImage_Load(image_type, path.c_str(), 0); + auto result = std::make_unique(); + result->width = FreeImage_GetWidth(image); + result->height = FreeImage_GetHeight(image); + result->pitch = FreeImage_GetPitch(image); + result->type = FreeImage_GetImageType(image); + result->bpp = FreeImage_GetBPP(image); + result->data = FreeImage_GetBits(image); + return result; + } + else { + return {}; + } +} + +void ImageLoader::CopyImageToBuffer(const Image& image, uint8_t *destination) +{ + if (image.bpp == 24) { + for(size_t y = image.height; y > 0; y--) { + BYTE *pixel = image.data + (y - 1) * image.pitch; + for(size_t x = 0; x < image.width; x++) {https://www.piratesahoy.net/threads/build-14-gamma-version-last-update-6th-april-2023.33573/ + destination[0] = pixel[FI_RGBA_BLUE]; + destination[1] = pixel[FI_RGBA_GREEN]; + destination[2] = pixel[FI_RGBA_RED]; + destination[3] = 255; + destination += 4; + pixel += 3; + } + } + } + else { + for(size_t y = image.height; y > 0; y--) { + BYTE *pixel = image.data + (y - 1) * image.pitch; + for(size_t x = 0; x < image.width; x++) { + destination[0] = pixel[FI_RGBA_BLUE]; + destination[1] = pixel[FI_RGBA_GREEN]; + destination[2] = pixel[FI_RGBA_RED]; + destination[3] = pixel[FI_RGBA_ALPHA]; + destination += 4; + pixel += 4; + } + } + } +} + +ImageLoader::Impl::Impl() +{ + freeImage_ = getGlobalFreeImageInstance(); +} + +std::shared_ptr ImageLoader::Impl::getGlobalFreeImageInstance() +{ + auto free_image = FreeImageInstance.lock(); + if (!free_image) { + free_image = std::make_shared(); + FreeImageInstance = free_image; + } + return free_image; +} + +} // namespace storm::renderer