Avoid using createImageFromData with preload data for texture

Todo: allow using single channel for font texture, saving 75% size
This commit is contained in:
Benau 2017-01-07 14:45:47 +08:00
parent 37a4d512ab
commit 6deb0e0f8a
4 changed files with 55 additions and 75 deletions

View File

@ -131,15 +131,13 @@ void FontWithFace::loadGlyphInfo(wchar_t c)
*/ */
void FontWithFace::createNewGlyphPage() void FontWithFace::createNewGlyphPage()
{ {
video::IImage* glyph = irr_driver->getVideoDriver() uint8_t* data = new uint8_t[getGlyphPageSize() * getGlyphPageSize() * 4]();
->createImage(video::ECF_A8R8G8B8,
core::dimension2du(getGlyphPageSize(), getGlyphPageSize()));
glyph->fill(video::SColor(0, 255, 255, 255));
m_current_height = 0; m_current_height = 0;
m_used_width = 0; m_used_width = 0;
m_used_height = 0; m_used_height = 0;
STKTexture* stkt = new STKTexture(glyph, typeid(*this).name() + STKTexture* stkt = new STKTexture(data, typeid(*this).name() +
StringUtils::toString(m_spritebank->getTextureCount())); StringUtils::toString(m_spritebank->getTextureCount()),
getGlyphPageSize());
m_spritebank->addTexture(stkt); m_spritebank->addTexture(stkt);
STKTexManager::getInstance()->addTexture(stkt); STKTexManager::getInstance()->addTexture(stkt);
} // createNewGlyphPage } // createNewGlyphPage
@ -173,14 +171,7 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
// Convert to an anti-aliased bitmap // Convert to an anti-aliased bitmap
FT_Bitmap bits = slot->bitmap; FT_Bitmap bits = slot->bitmap;
core::dimension2du texture_size(bits.width + 1, bits.rows + 1);
core::dimension2du d(bits.width + 1, bits.rows + 1);
core::dimension2du texture_size;
texture_size = d.getOptimalSize(!(irr_driver->getVideoDriver()
->queryFeature(video::EVDF_TEXTURE_NPOT)), !(irr_driver
->getVideoDriver()->queryFeature(video::EVDF_TEXTURE_NSQUARE)),
true, 0);
if ((m_used_width + texture_size.Width > getGlyphPageSize() && if ((m_used_width + texture_size.Width > getGlyphPageSize() &&
m_used_height + m_current_height + texture_size.Height > m_used_height + m_current_height + texture_size.Height >
getGlyphPageSize()) || getGlyphPageSize()) ||
@ -190,46 +181,34 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
createNewGlyphPage(); createNewGlyphPage();
} }
video::IImage* glyph = NULL; std::vector<uint32_t> image_data;
unsigned int* image_data = NULL; image_data.resize(texture_size.Width * texture_size.Height,
video::SColor(0, 255, 255, 255).color);
switch (bits.pixel_mode) switch (bits.pixel_mode)
{ {
case FT_PIXEL_MODE_GRAY: case FT_PIXEL_MODE_GRAY:
{ {
// Create our blank image.
glyph = irr_driver->getVideoDriver()
->createImage(video::ECF_A8R8G8B8, texture_size);
glyph->fill(video::SColor(0, 255, 255, 255));
// Load the grayscale data in. // Load the grayscale data in.
const float gray_count = static_cast<float>(bits.num_grays); const float gray_count = static_cast<float>(bits.num_grays);
const unsigned int image_pitch = const unsigned int image_pitch =
glyph->getPitch() / sizeof(unsigned int); 4 * texture_size.Width / sizeof(unsigned int);
image_data = (unsigned int*)glyph->lock(); uint8_t* glyph_data = bits.buffer;
unsigned char* glyph_data = bits.buffer; for (int y = 0; y < bits.rows; y++)
for (unsigned int y = 0; y < (unsigned int)bits.rows; y++)
{ {
unsigned char* row = glyph_data; uint8_t* row = glyph_data;
for (unsigned int x = 0; x < (unsigned)bits.width; x++) for (int x = 0; x < bits.width; x++)
{ {
image_data[y * image_pitch + x] |= image_data.data()[y * image_pitch + x] |=
static_cast<unsigned int>(255.0f * static_cast<uint32_t>(255.0f *
(static_cast<float>(*row++) / gray_count)) << 24; (static_cast<float>(*row++) / gray_count)) << 24;
} }
glyph_data += bits.pitch; glyph_data += bits.pitch;
} }
glyph->unlock();
break; break;
} }
default: default:
assert(false); assert(false);
} }
if (glyph == NULL)
{
Log::warn("FontWithFace", "Failed to load a glyph");
return;
}
// Done creating a single glyph, now copy to the glyph page... // Done creating a single glyph, now copy to the glyph page...
// Determine the linebreak location // Determine the linebreak location
@ -250,7 +229,12 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
#endif #endif
glTexSubImage2D(GL_TEXTURE_2D, 0, m_used_width, m_used_height, glTexSubImage2D(GL_TEXTURE_2D, 0, m_used_width, m_used_height,
texture_size.Width, texture_size.Height, format, GL_UNSIGNED_BYTE, texture_size.Width, texture_size.Height, format, GL_UNSIGNED_BYTE,
image_data); image_data.data());
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//static GLint swizzle_mask[] = { GL_ONE, GL_ONE, GL_ONE, GL_RED };
//glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_mask);
//glTexSubImage2D(GL_TEXTURE_2D, 0, m_used_width, m_used_height, bits.width, bits.rows, GL_RED, GL_UNSIGNED_BYTE, bits.buffer);
//glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
if (tex->hasMipMaps()) if (tex->hasMipMaps())
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
@ -281,10 +265,6 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
a.spriteno = f.rectNumber; a.spriteno = f.rectNumber;
m_character_area_map[c] = a; m_character_area_map[c] = a;
// Clean the temporary glyph
glyph->drop();
glyph = NULL;
// Store used area // Store used area
m_used_width += texture_size.Width; m_used_width += texture_size.Width;
if (m_current_height < texture_size.Height) if (m_current_height < texture_size.Height)

View File

@ -162,11 +162,12 @@ video::ITexture* STKTexManager::getUnicolorTexture(const irr::video::SColor &c)
if (ret != m_all_textures.end()) if (ret != m_all_textures.end())
return ret->second; return ret->second;
uint32_t color[4] = { c.color, c.color, c.color, c.color }; uint8_t* data = new uint8_t[2 * 2 * 4];
video::IImage* image = irr_driver->getVideoDriver() memcpy(data, &c.color, sizeof(video::SColor));
->createImageFromData(video::ECF_A8R8G8B8, memcpy(data + 4, &c.color, sizeof(video::SColor));
core::dimension2d<u32>(2, 2), color); memcpy(data + 8, &c.color, sizeof(video::SColor));
STKTexture* texture = new STKTexture(image, name); memcpy(data + 12, &c.color, sizeof(video::SColor));
STKTexture* texture = new STKTexture(data, name, 2);
addTexture(texture); addTexture(texture);
return texture; return texture;

View File

@ -49,12 +49,16 @@ STKTexture::STKTexture(const std::string& path, bool srgb, bool premul_alpha,
} // STKTexture } // STKTexture
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
STKTexture::STKTexture(video::IImage* image, const std::string& name) STKTexture::STKTexture(uint8_t* data, const std::string& name, size_t size,
bool single_channel)
: video::ITexture(name.c_str()), m_texture_handle(0), m_srgb(false), : video::ITexture(name.c_str()), m_texture_handle(0), m_srgb(false),
m_premul_alpha(false), m_mesh_texture(false), m_material(NULL), m_premul_alpha(false), m_mesh_texture(false), m_material(NULL),
m_texture_name(0), m_texture_size(0), m_texture_image(NULL) m_texture_name(0), m_texture_size(0), m_texture_image(NULL)
{ {
reload(false/*no_upload*/, image/*pre_loaded_tex*/); m_size.Width = size;
m_size.Height = size;
m_orig_size = m_size;
reload(false/*no_upload*/, data, single_channel);
} // STKTexture } // STKTexture
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -71,7 +75,8 @@ STKTexture::~STKTexture()
} // ~STKTexture } // ~STKTexture
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void STKTexture::reload(bool no_upload, video::IImage* pre_loaded_tex) void STKTexture::reload(bool no_upload, uint8_t* preload_data,
bool single_channel)
{ {
#ifndef SERVER_ONLY #ifndef SERVER_ONLY
irr_driver->getDevice()->getLogger()->setLogLevel(ELL_NONE); irr_driver->getDevice()->getLogger()->setLogLevel(ELL_NONE);
@ -119,7 +124,8 @@ void STKTexture::reload(bool no_upload, video::IImage* pre_loaded_tex)
#endif #endif
video::IImage* orig_img = NULL; video::IImage* orig_img = NULL;
if (pre_loaded_tex == NULL) uint8_t* data = preload_data;
if (data == NULL)
{ {
orig_img = orig_img =
irr_driver->getVideoDriver()->createImageFromFile(NamedPath); irr_driver->getVideoDriver()->createImageFromFile(NamedPath);
@ -134,26 +140,14 @@ void STKTexture::reload(bool no_upload, video::IImage* pre_loaded_tex)
{ {
Log::warn("STKTexture", "image %s has 0 size.", Log::warn("STKTexture", "image %s has 0 size.",
NamedPath.getPtr()); NamedPath.getPtr());
orig_img->drop();
return; return;
} }
} orig_img = resizeImage(orig_img, &m_orig_size, &m_size);
else applyMask(orig_img);
orig_img = pre_loaded_tex; data = (uint8_t*)orig_img->lock();
video::IImage* new_texture = NULL;
if (pre_loaded_tex == NULL)
{
new_texture = resizeImage(orig_img, &m_orig_size, &m_size);
applyMask(new_texture);
}
else
{
new_texture = pre_loaded_tex;
m_orig_size = pre_loaded_tex->getDimension();
m_size = pre_loaded_tex->getDimension();
} }
unsigned char* data = (unsigned char*)new_texture->lock();
const unsigned int w = m_size.Width; const unsigned int w = m_size.Width;
const unsigned int h = m_size.Height; const unsigned int h = m_size.Height;
unsigned int format = GL_BGRA; unsigned int format = GL_BGRA;
@ -178,7 +172,7 @@ void STKTexture::reload(bool no_upload, video::IImage* pre_loaded_tex)
format = GL_RGBA; format = GL_RGBA;
for (unsigned int i = 0; i < w * h; i++) for (unsigned int i = 0; i < w * h; i++)
{ {
char tmp_val = data[i * 4]; uint8_t tmp_val = data[i * 4];
data[i * 4] = data[i * 4 + 2]; data[i * 4] = data[i * 4 + 2];
data[i * 4 + 2] = tmp_val; data[i * 4 + 2] = tmp_val;
} }
@ -191,9 +185,9 @@ void STKTexture::reload(bool no_upload, video::IImage* pre_loaded_tex)
float alpha = data[4 * i + 3]; float alpha = data[4 * i + 3];
if (alpha > 0.0f) if (alpha > 0.0f)
alpha = pow(alpha / 255.f, 1.f / 2.2f); alpha = pow(alpha / 255.f, 1.f / 2.2f);
data[i * 4] = (unsigned char)(data[i * 4] * alpha); data[i * 4] = (uint8_t)(data[i * 4] * alpha);
data[i * 4 + 1] = (unsigned char)(data[i * 4 + 1] * alpha); data[i * 4 + 1] = (uint8_t)(data[i * 4 + 1] * alpha);
data[i * 4 + 2] = (unsigned char)(data[i * 4 + 2] * alpha); data[i * 4 + 2] = (uint8_t)(data[i * 4 + 2] * alpha);
} }
} }
@ -214,16 +208,19 @@ void STKTexture::reload(bool no_upload, video::IImage* pre_loaded_tex)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format,
GL_UNSIGNED_BYTE, data); GL_UNSIGNED_BYTE, data);
} }
new_texture->unlock(); if (orig_img)
orig_img->unlock();
if (hasMipMaps()) if (hasMipMaps())
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
} }
m_texture_size = w * h * 4 /*BRGA*/; m_texture_size = w * h * 4 /*BRGA*/;
if (no_upload) if (no_upload)
m_texture_image = new_texture; m_texture_image = orig_img;
else if (orig_img)
orig_img->drop();
else else
new_texture->drop(); delete[] data;
if (!compressed_texture.empty()) if (!compressed_texture.empty())
saveCompressedTexture(compressed_texture); saveCompressedTexture(compressed_texture);

View File

@ -62,7 +62,8 @@ public:
bool premul_alpha = false, bool set_material = false, bool premul_alpha = false, bool set_material = false,
bool mesh_tex = false, bool no_upload = false); bool mesh_tex = false, bool no_upload = false);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
STKTexture(video::IImage* image, const std::string& name); STKTexture(uint8_t* data, const std::string& name, size_t size,
bool single_channel = false);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual ~STKTexture(); virtual ~STKTexture();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -112,7 +113,8 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
unsigned int getTextureSize() const { return m_texture_size; } unsigned int getTextureSize() const { return m_texture_size; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void reload(bool no_upload = false, video::IImage* pre_loaded_tex = NULL); void reload(bool no_upload = false, uint8_t* preload_data = NULL,
bool single_channel = false);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
video::IImage* getTextureImage() { return m_texture_image; } video::IImage* getTextureImage() { return m_texture_image; }