diff --git a/lib/graphics_engine/CMakeLists.txt b/lib/graphics_engine/CMakeLists.txt index a00226949..eb75bb569 100644 --- a/lib/graphics_engine/CMakeLists.txt +++ b/lib/graphics_engine/CMakeLists.txt @@ -5,4 +5,5 @@ add_library(graphics_engine STATIC src/vulkan.c src/ge_main.cpp src/ge_texture.cpp + src/ge_gl_texture.cpp ) diff --git a/lib/graphics_engine/include/ge_texture.hpp b/lib/graphics_engine/include/ge_texture.hpp index 668ff0e6a..9556c4e4e 100644 --- a/lib/graphics_engine/include/ge_texture.hpp +++ b/lib/graphics_engine/include/ge_texture.hpp @@ -1,6 +1,7 @@ #ifndef HEADER_GE_TEXTURE_HPP #define HEADER_GE_TEXTURE_HPP +#include #include #include #include @@ -8,9 +9,12 @@ namespace GE { irr::video::ITexture* createFontTexture(const std::string& name); -irr::video::ITexture* createTexture(irr::video::IImage* img); -irr::video::IImage* getResizedImage(const std::string& path); -irr::video::ITexture* createTexture(const std::string& path); +irr::video::ITexture* createTexture(irr::video::IImage* img, + const std::string& name); +irr::video::IImage* getResizedImage(const std::string& path, + irr::core::dimension2d* orig_size = NULL); +irr::video::ITexture* createTexture(const std::string& path, + std::function image_mani = nullptr); }; // GE #endif diff --git a/lib/graphics_engine/src/ge_gl_texture.cpp b/lib/graphics_engine/src/ge_gl_texture.cpp new file mode 100644 index 000000000..6af2522d7 --- /dev/null +++ b/lib/graphics_engine/src/ge_gl_texture.cpp @@ -0,0 +1,131 @@ +#include "ge_gl_texture.hpp" +#include "ge_main.hpp" +#include "ge_texture.hpp" + +namespace GE +{ +GEGLTexture::GEGLTexture(const std::string& path, + std::function image_mani) + : video::ITexture(path.c_str()), m_image_mani(image_mani), + m_single_channel(false), m_texture_name(0), m_texture_size(0), + m_driver_type(GE::getDriver()->getDriverType()), + m_disable_reload(false) +{ + reload(); +} // GEGLTexture + +// ---------------------------------------------------------------------------- +GEGLTexture::GEGLTexture(video::IImage* img, const std::string& name) + : video::ITexture(name.c_str()), m_image_mani(nullptr), + m_single_channel(false), m_texture_name(0), m_texture_size(0), + m_driver_type(GE::getDriver()->getDriverType()), + m_disable_reload(true) +{ + glGenTextures(1, &m_texture_name); + m_size = m_orig_size = img->getDimension(); + uint8_t* data = (uint8_t*)img->lock(); + upload(data); + img->unlock(); + img->drop(); +} // GEGLTexture + +// ---------------------------------------------------------------------------- +GEGLTexture::~GEGLTexture() +{ + if (m_texture_name != 0) + glDeleteTextures(1, &m_texture_name); +} // ~GEGLTexture + +// ---------------------------------------------------------------------------- +void GEGLTexture::reload() +{ + if (m_disable_reload) + return; + video::IImage* texture_image = getResizedImage(NamedPath.getPtr(), + &m_orig_size); + if (texture_image == NULL) + return; + m_size = texture_image->getDimension(); + if (m_image_mani) + m_image_mani(texture_image); + if (m_texture_name == 0) + glGenTextures(1, &m_texture_name); + uint8_t* data = (uint8_t*)texture_image->lock(); + upload(data); + texture_image->unlock(); + texture_image->drop(); +} // reload + +// ---------------------------------------------------------------------------- +void GEGLTexture::upload(uint8_t* data) +{ + const unsigned int w = m_size.Width; + const unsigned int h = m_size.Height; + unsigned int format = m_single_channel ? GL_RED : GL_BGRA; + unsigned int internal_format = m_single_channel ? GL_R8 : GL_RGBA8; + + if (m_driver_type == video::EDT_OGLES2) + { + formatConversion(data, &format, w, h); + int gl_major_version = 0; + glGetIntegerv(GL_MAJOR_VERSION, &gl_major_version); + // GLES 2.0 specs doesn't allow GL_RGBA8 internal format + if (gl_major_version < 3) + internal_format = GL_RGBA; + } + + glBindTexture(GL_TEXTURE_2D, m_texture_name); + if (m_single_channel) + { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED); + } + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, w, h, 0, format, + GL_UNSIGNED_BYTE, data); + if (hasMipMaps()) + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + m_texture_size = w * h * (m_single_channel ? 1 : 4); +} // upload + +// ---------------------------------------------------------------------------- +void* GEGLTexture::lock(video::E_TEXTURE_LOCK_MODE mode, u32 mipmap_level) +{ + if (m_driver_type == video::EDT_OGLES2 || !glGetTexImage) + { + video::IImage* img = getResizedImage(NamedPath.getPtr()); + img->setDeleteMemory(false); + void* data = img->lock(); + img->drop(); + return data; + } + uint8_t* pixels = new uint8_t[m_size.Width * m_size.Height * 4](); + GLint tmp_texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &tmp_texture); + glBindTexture(GL_TEXTURE_2D, m_texture_name); + glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels); + glBindTexture(GL_TEXTURE_2D, tmp_texture); + return pixels; +} // lock + +//----------------------------------------------------------------------------- +void GEGLTexture::formatConversion(uint8_t* data, unsigned int* format, + unsigned int w, unsigned int h) const +{ + if (!m_single_channel) + { + if (format) + *format = GL_RGBA; + for (unsigned int i = 0; i < w * h; i++) + { + uint8_t tmp_val = data[i * 4]; + data[i * 4] = data[i * 4 + 2]; + data[i * 4 + 2] = tmp_val; + } + } +} // formatConversion + +} diff --git a/lib/graphics_engine/src/ge_gl_texture.hpp b/lib/graphics_engine/src/ge_gl_texture.hpp new file mode 100644 index 000000000..34f6181c0 --- /dev/null +++ b/lib/graphics_engine/src/ge_gl_texture.hpp @@ -0,0 +1,78 @@ +#ifndef HEADER_GE_GL_TEXTURE_HPP +#define HEADER_GE_GL_TEXTURE_HPP + +#include "glad/gl.h" + +#include +#include +#include + +using namespace irr; + +namespace GE +{ +class GEGLTexture : public video::ITexture +{ +private: + core::dimension2d m_size, m_orig_size; + + std::function m_image_mani; + + bool m_single_channel; + + GLuint m_texture_name; + + unsigned int m_texture_size; + + const video::E_DRIVER_TYPE m_driver_type; + + const bool m_disable_reload; + + // ------------------------------------------------------------------------ + void upload(uint8_t* data); + // ------------------------------------------------------------------------ + void formatConversion(uint8_t* data, unsigned int* format, unsigned int w, + unsigned int h) const; + +public: + // ------------------------------------------------------------------------ + GEGLTexture(const std::string& path, + std::function image_mani = nullptr); + // ------------------------------------------------------------------------ + GEGLTexture(video::IImage* img, const std::string& name); + // ------------------------------------------------------------------------ + virtual ~GEGLTexture(); + // ------------------------------------------------------------------------ + virtual void* lock(video::E_TEXTURE_LOCK_MODE mode = + video::ETLM_READ_WRITE, u32 mipmap_level = 0); + // ------------------------------------------------------------------------ + virtual void unlock() {} + // ------------------------------------------------------------------------ + virtual const core::dimension2d& getOriginalSize() const + { return m_orig_size; } + // ------------------------------------------------------------------------ + virtual const core::dimension2d& getSize() const { return m_size; } + // ------------------------------------------------------------------------ + virtual video::E_DRIVER_TYPE getDriverType() const + { return m_driver_type; } + // ------------------------------------------------------------------------ + virtual video::ECOLOR_FORMAT getColorFormat() const + { return video::ECF_A8R8G8B8; } + // ------------------------------------------------------------------------ + virtual u32 getPitch() const { return 0; } + // ------------------------------------------------------------------------ + virtual bool hasMipMaps() const { return glGenerateMipmap != NULL; } + // ------------------------------------------------------------------------ + virtual void regenerateMipMapLevels(void* mipmap_data = NULL) {} + // ------------------------------------------------------------------------ + virtual u64 getTextureHandler() const { return m_texture_name; } + // ------------------------------------------------------------------------ + virtual unsigned int getTextureSize() const { return m_texture_size; } + // ------------------------------------------------------------------------ + virtual void reload(); + +}; // GEGLTexture + +} + +#endif diff --git a/lib/graphics_engine/src/ge_texture.cpp b/lib/graphics_engine/src/ge_texture.cpp index 4d787c299..3ba285548 100644 --- a/lib/graphics_engine/src/ge_texture.cpp +++ b/lib/graphics_engine/src/ge_texture.cpp @@ -1,4 +1,5 @@ #include "ge_main.hpp" +#include "ge_gl_texture.hpp" #include "ge_texture.hpp" #include @@ -7,11 +8,14 @@ namespace GE { using namespace irr; -video::IImage* getResizedImage(const std::string& path) +video::IImage* getResizedImage(const std::string& path, + core::dimension2d* orig_size) { video::IImage* image = getDriver()->createImageFromFile(path.c_str()); if (image == NULL) return NULL; + if (orig_size) + *orig_size = image->getDimension(); core::dimension2du img_size = image->getDimension(); bool has_npot = !getGEConfig()->m_disable_npot_texture && @@ -40,6 +44,34 @@ video::IImage* getResizedImage(const std::string& path) } return image; -} +} // getResizedImage + +// ---------------------------------------------------------------------------- +irr::video::ITexture* createTexture(const std::string& path, + std::function image_mani) +{ + switch (GE::getDriver()->getDriverType()) + { + case video::EDT_OPENGL: + case video::EDT_OGLES2: + return new GEGLTexture(path, image_mani); + default: + return NULL; + } +} // createTexture + +// ---------------------------------------------------------------------------- +irr::video::ITexture* createTexture(video::IImage* img, + const std::string& name) +{ + switch (GE::getDriver()->getDriverType()) + { + case video::EDT_OPENGL: + case video::EDT_OGLES2: + return new GEGLTexture(img, name); + default: + return NULL; + } +} // createTexture } diff --git a/lib/irrlicht/include/ITexture.h b/lib/irrlicht/include/ITexture.h index 9935c7ebd..00f41a4c4 100644 --- a/lib/irrlicht/include/ITexture.h +++ b/lib/irrlicht/include/ITexture.h @@ -201,6 +201,7 @@ public: virtual void updateTexture(void* data, ECOLOR_FORMAT format, u32 w, u32 h, u32 x, u32 y) {} + virtual void reload() {} protected: //! Helper function, helps to get the desired texture creation format from the flags. diff --git a/src/graphics/post_processing.cpp b/src/graphics/post_processing.cpp index 74d1e72cd..468b7bb9b 100644 --- a/src/graphics/post_processing.cpp +++ b/src/graphics/post_processing.cpp @@ -29,7 +29,6 @@ #include "graphics/glwrap.hpp" #include "graphics/rtts.hpp" #include "graphics/shared_gpu_objects.hpp" -#include "graphics/stk_texture.hpp" #include "graphics/stk_tex_manager.hpp" #include "graphics/texture_shader.hpp" #include "graphics/weather.hpp" @@ -48,6 +47,7 @@ #include "utils/cpp2011.hpp" #include +#include using namespace video; using namespace scene; @@ -749,7 +749,7 @@ PostProcessing::PostProcessing() createMemoryReadFile((void *) AreaMap33, sizeof(AreaMap33), "AreaMap33", false); video::IImage* img = irr_driver->getVideoDriver()->createImageFromFile(areamap); - m_areamap = new STKTexture(img, "AreaMap33"); + m_areamap = GE::createTexture(img, "AreaMap33"); if (m_areamap->getTextureHandler() == 0) { Log::fatal("postprocessing", "Failed to load the areamap"); diff --git a/src/graphics/post_processing.hpp b/src/graphics/post_processing.hpp index b6c1c88ab..fa2fc4cbd 100644 --- a/src/graphics/post_processing.hpp +++ b/src/graphics/post_processing.hpp @@ -26,11 +26,10 @@ class FrameBuffer; class RTT; -class STKTexture; namespace irr { - namespace video { class IVideoDriver; } + namespace video { class IVideoDriver; class ITexture; } namespace scene { class ICameraSceneNode; } } @@ -47,7 +46,7 @@ private: * have a stronger effect. */ std::vector m_boost_time; - STKTexture* m_areamap; + video::ITexture* m_areamap; public: PostProcessing(); diff --git a/src/graphics/stk_tex_manager.cpp b/src/graphics/stk_tex_manager.cpp index 95c2f5b19..4c1338328 100644 --- a/src/graphics/stk_tex_manager.cpp +++ b/src/graphics/stk_tex_manager.cpp @@ -28,6 +28,9 @@ #include "utils/log.hpp" #include +#ifndef SERVER_ONLY +#include +#endif // ---------------------------------------------------------------------------- STKTexManager::~STKTexManager() @@ -96,7 +99,7 @@ video::ITexture* STKTexManager::getTexture(const std::string& path) else { new_texture = - new STKTexture(full_path.empty() ? path : full_path, NULL); + GE::createTexture(full_path.empty() ? path : full_path); } if (new_texture->getTextureHandler() == 0) { diff --git a/src/graphics/stk_tex_manager.hpp b/src/graphics/stk_tex_manager.hpp index dd917eea1..172f36b3b 100644 --- a/src/graphics/stk_tex_manager.hpp +++ b/src/graphics/stk_tex_manager.hpp @@ -84,6 +84,16 @@ public: // ------------------------------------------------------------------------ int dumpTextureUsage(); // ------------------------------------------------------------------------ + void reloadAllTextures() + { + for (auto p : m_all_textures) + { + if (p.second == NULL) + continue; + p.second->reload(); + } + } + // ------------------------------------------------------------------------ /** Returns the currently defined texture error message, which is used * by event_handler.cpp to print additional info about irrlicht * internal errors or warnings. If no error message is currently diff --git a/src/guiengine/widgets/icon_button_widget.cpp b/src/guiengine/widgets/icon_button_widget.cpp index 0f9954998..684ec659a 100644 --- a/src/guiengine/widgets/icon_button_widget.cpp +++ b/src/guiengine/widgets/icon_button_widget.cpp @@ -19,7 +19,6 @@ #include "graphics/central_settings.hpp" #include "graphics/irr_driver.hpp" #include "graphics/stk_tex_manager.hpp" -#include "graphics/stk_texture.hpp" #include "guiengine/engine.hpp" #include "guiengine/scalable_font.hpp" #include "io/file_manager.hpp" @@ -32,6 +31,9 @@ #include #include #include +#ifndef SERVER_ONLY +#include +#endif using namespace GUIEngine; using namespace irr::video; @@ -365,13 +367,8 @@ const video::ITexture* IconButtonWidget::getTexture() // ----------------------------------------------------------------------------- video::ITexture* IconButtonWidget::getDeactivatedTexture(video::ITexture* texture) { -#if !defined(SERVER_ONLY) && !defined(USE_GLES2) - STKTexture* stk_tex = static_cast(texture); - // Compressed texture can't be turned into greyscale - if (stk_tex->isMeshTexture() && CVS->isTextureCompressionEnabled()) - return stk_tex; - - std::string name = stk_tex->getName().getPtr(); +#ifndef SERVER_ONLY + std::string name = texture->getName().getPtr(); name += "_disabled"; STKTexManager* stkm = STKTexManager::getInstance(); if (!stkm->hasTexture(name)) @@ -381,8 +378,8 @@ video::ITexture* IconButtonWidget::getDeactivatedTexture(video::ITexture* textur video::IVideoDriver* driver = irr_driver->getVideoDriver(); video::IImage* image = driver->createImageFromData - (video::ECF_A8R8G8B8, stk_tex->getSize(), stk_tex->lock(), - stk_tex->getTextureImage() == NULL/*ownForeignMemory*/); + (video::ECF_A8R8G8B8, texture->getSize(), texture->lock(), + true/*ownForeignMemory*/); texture->unlock(); //Turn the image into grayscale @@ -396,12 +393,12 @@ video::ITexture* IconButtonWidget::getDeactivatedTexture(video::ITexture* textur image->setPixel(x, y, c); } } - return stkm->addTexture(new STKTexture(image, name)); + return stkm->addTexture(GE::createTexture(image, name)); } return stkm->getTexture(name); #else return texture; -#endif // !SERVER_ONLY +#endif } // -----------------------------------------------------------------------------