#include "ge_gl_texture.hpp" #include "ge_gl_utils.hpp" #include "ge_main.hpp" #include "ge_texture.hpp" #include #include // TODO remove it after vulkan is done namespace irr { namespace video { extern bool useCoreContext; } } namespace GE { GEGLTexture::GEGLTexture(const std::string& path, std::function image_mani) : video::ITexture(path.c_str()), m_image_mani(image_mani), m_locked_data(NULL), m_texture_name(0), m_texture_size(0), m_driver_type(GE::getDriver()->getDriverType()), m_disable_reload(false), m_single_channel(false) { reload(); } // GEGLTexture // ---------------------------------------------------------------------------- GEGLTexture::GEGLTexture(video::IImage* img, const std::string& name) : video::ITexture(name.c_str()), m_image_mani(nullptr), m_locked_data(NULL), m_texture_name(0), m_texture_size(0), m_driver_type(GE::getDriver()->getDriverType()), m_disable_reload(true), m_single_channel(false) { if (!img) { LoadingFailed = true; return; } 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(const std::string& name, unsigned int size, bool single_channel) : video::ITexture(name.c_str()), m_image_mani(nullptr), m_locked_data(NULL), m_texture_name(0), m_texture_size(0), m_driver_type(GE::getDriver()->getDriverType()), m_disable_reload(true), m_single_channel(false) { glGenTextures(1, &m_texture_name); m_orig_size.Width = size; m_orig_size.Height = size; m_size = m_orig_size; bool texture_swizzle = false; if (m_driver_type == video::EDT_OGLES2) { int gl_major_version = 0; glGetIntegerv(GL_MAJOR_VERSION, &gl_major_version); if (gl_major_version >=3) texture_swizzle = true; else texture_swizzle = false; } else { texture_swizzle = irr::video::useCoreContext && GE::hasGLExtension("GL_ARB_texture_swizzle"); } if (single_channel && texture_swizzle) m_single_channel = true; std::vector data; data.resize(size * size * (m_single_channel ? 1 : 4), 0); upload(data.data()); } // GEGLTexture // ---------------------------------------------------------------------------- GEGLTexture::~GEGLTexture() { if (m_texture_name != 0) glDeleteTextures(1, &m_texture_name); } // ~GEGLTexture // ---------------------------------------------------------------------------- void GEGLTexture::reload() { if (m_disable_reload) return; const core::dimension2du & max_size = getDriver()->getDriverAttributes() .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); video::IImage* texture_image = getResizedImage(NamedPath.getPtr(), max_size, &m_orig_size); if (texture_image == NULL) { LoadingFailed = true; 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 (mode != video::ETLM_READ_ONLY) return NULL; if (m_driver_type == video::EDT_OGLES2 || !glGetTexImage) { const core::dimension2du & max_size = getDriver()->getDriverAttributes() .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); video::IImage* img = getResizedImage(NamedPath.getPtr(), max_size, NULL, &m_size); if (!img) return NULL; img->setDeleteMemory(false); m_locked_data = (uint8_t*)img->lock(); img->unlock(); img->drop(); return m_locked_data; } m_locked_data = 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, m_locked_data); glBindTexture(GL_TEXTURE_2D, tmp_texture); return m_locked_data; } // 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 //----------------------------------------------------------------------------- void GEGLTexture::updateTexture(void* data, video::ECOLOR_FORMAT format, u32 w, u32 h, u32 x, u32 y) { glBindTexture(GL_TEXTURE_2D, m_texture_name); if (m_single_channel) { if (format == video::ECF_R8) { glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RED, GL_UNSIGNED_BYTE, data); } } else { if (format == video::ECF_R8) { const unsigned int size = w * h; std::vector image_data(size * 4, 255); uint8_t* orig_data = (uint8_t*)data; for (unsigned int i = 0; i < size; i++) image_data[4 * i + 3] = orig_data[i]; glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image_data.data()); } else if (format == video::ECF_A8R8G8B8) { uint8_t* u8_data = (uint8_t*)data; for (unsigned int i = 0; i < w * h; i++) { uint8_t tmp_val = u8_data[i * 4]; u8_data[i * 4] = u8_data[i * 4 + 2]; u8_data[i * 4 + 2] = tmp_val; } glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, u8_data); } } if (hasMipMaps()) glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); } // updateTexture }