Avoid using createImageFromData with preload data for texture
Todo: allow using single channel for font texture, saving 75% size
This commit is contained in:
parent
37a4d512ab
commit
6deb0e0f8a
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user