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()
{
video::IImage* glyph = irr_driver->getVideoDriver()
->createImage(video::ECF_A8R8G8B8,
core::dimension2du(getGlyphPageSize(), getGlyphPageSize()));
glyph->fill(video::SColor(0, 255, 255, 255));
uint8_t* data = new uint8_t[getGlyphPageSize() * getGlyphPageSize() * 4]();
m_current_height = 0;
m_used_width = 0;
m_used_height = 0;
STKTexture* stkt = new STKTexture(glyph, typeid(*this).name() +
StringUtils::toString(m_spritebank->getTextureCount()));
STKTexture* stkt = new STKTexture(data, typeid(*this).name() +
StringUtils::toString(m_spritebank->getTextureCount()),
getGlyphPageSize());
m_spritebank->addTexture(stkt);
STKTexManager::getInstance()->addTexture(stkt);
} // createNewGlyphPage
@ -173,14 +171,7 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
// Convert to an anti-aliased bitmap
FT_Bitmap bits = slot->bitmap;
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);
core::dimension2du texture_size(bits.width + 1, bits.rows + 1);
if ((m_used_width + texture_size.Width > getGlyphPageSize() &&
m_used_height + m_current_height + texture_size.Height >
getGlyphPageSize()) ||
@ -190,46 +181,34 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
createNewGlyphPage();
}
video::IImage* glyph = NULL;
unsigned int* image_data = NULL;
std::vector<uint32_t> image_data;
image_data.resize(texture_size.Width * texture_size.Height,
video::SColor(0, 255, 255, 255).color);
switch (bits.pixel_mode)
{
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.
const float gray_count = static_cast<float>(bits.num_grays);
const unsigned int image_pitch =
glyph->getPitch() / sizeof(unsigned int);
image_data = (unsigned int*)glyph->lock();
unsigned char* glyph_data = bits.buffer;
for (unsigned int y = 0; y < (unsigned int)bits.rows; y++)
4 * texture_size.Width / sizeof(unsigned int);
uint8_t* glyph_data = bits.buffer;
for (int y = 0; y < bits.rows; y++)
{
unsigned char* row = glyph_data;
for (unsigned int x = 0; x < (unsigned)bits.width; x++)
uint8_t* row = glyph_data;
for (int x = 0; x < bits.width; x++)
{
image_data[y * image_pitch + x] |=
static_cast<unsigned int>(255.0f *
image_data.data()[y * image_pitch + x] |=
static_cast<uint32_t>(255.0f *
(static_cast<float>(*row++) / gray_count)) << 24;
}
glyph_data += bits.pitch;
}
glyph->unlock();
break;
}
default:
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...
// Determine the linebreak location
@ -250,7 +229,12 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
#endif
glTexSubImage2D(GL_TEXTURE_2D, 0, m_used_width, m_used_height,
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())
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
@ -281,10 +265,6 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
a.spriteno = f.rectNumber;
m_character_area_map[c] = a;
// Clean the temporary glyph
glyph->drop();
glyph = NULL;
// Store used area
m_used_width += texture_size.Width;
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())
return ret->second;
uint32_t color[4] = { c.color, c.color, c.color, c.color };
video::IImage* image = irr_driver->getVideoDriver()
->createImageFromData(video::ECF_A8R8G8B8,
core::dimension2d<u32>(2, 2), color);
STKTexture* texture = new STKTexture(image, name);
uint8_t* data = new uint8_t[2 * 2 * 4];
memcpy(data, &c.color, sizeof(video::SColor));
memcpy(data + 4, &c.color, sizeof(video::SColor));
memcpy(data + 8, &c.color, sizeof(video::SColor));
memcpy(data + 12, &c.color, sizeof(video::SColor));
STKTexture* texture = new STKTexture(data, name, 2);
addTexture(texture);
return texture;

View File

@ -49,12 +49,16 @@ STKTexture::STKTexture(const std::string& path, bool srgb, bool premul_alpha,
} // 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),
m_premul_alpha(false), m_mesh_texture(false), m_material(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
// ----------------------------------------------------------------------------
@ -71,7 +75,8 @@ 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
irr_driver->getDevice()->getLogger()->setLogLevel(ELL_NONE);
@ -119,7 +124,8 @@ void STKTexture::reload(bool no_upload, video::IImage* pre_loaded_tex)
#endif
video::IImage* orig_img = NULL;
if (pre_loaded_tex == NULL)
uint8_t* data = preload_data;
if (data == NULL)
{
orig_img =
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.",
NamedPath.getPtr());
orig_img->drop();
return;
}
}
else
orig_img = pre_loaded_tex;
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();
orig_img = resizeImage(orig_img, &m_orig_size, &m_size);
applyMask(orig_img);
data = (uint8_t*)orig_img->lock();
}
unsigned char* data = (unsigned char*)new_texture->lock();
const unsigned int w = m_size.Width;
const unsigned int h = m_size.Height;
unsigned int format = GL_BGRA;
@ -178,7 +172,7 @@ void STKTexture::reload(bool no_upload, video::IImage* pre_loaded_tex)
format = GL_RGBA;
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 + 2] = tmp_val;
}
@ -191,9 +185,9 @@ void STKTexture::reload(bool no_upload, video::IImage* pre_loaded_tex)
float alpha = data[4 * i + 3];
if (alpha > 0.0f)
alpha = pow(alpha / 255.f, 1.f / 2.2f);
data[i * 4] = (unsigned char)(data[i * 4] * alpha);
data[i * 4 + 1] = (unsigned char)(data[i * 4 + 1] * alpha);
data[i * 4 + 2] = (unsigned char)(data[i * 4 + 2] * alpha);
data[i * 4] = (uint8_t)(data[i * 4] * alpha);
data[i * 4 + 1] = (uint8_t)(data[i * 4 + 1] * 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,
GL_UNSIGNED_BYTE, data);
}
new_texture->unlock();
if (orig_img)
orig_img->unlock();
if (hasMipMaps())
glGenerateMipmap(GL_TEXTURE_2D);
}
m_texture_size = w * h * 4 /*BRGA*/;
if (no_upload)
m_texture_image = new_texture;
m_texture_image = orig_img;
else if (orig_img)
orig_img->drop();
else
new_texture->drop();
delete[] data;
if (!compressed_texture.empty())
saveCompressedTexture(compressed_texture);

View File

@ -62,7 +62,8 @@ public:
bool premul_alpha = false, bool set_material = 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();
// ------------------------------------------------------------------------
@ -112,7 +113,8 @@ public:
// ------------------------------------------------------------------------
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; }