Applied and fixed MiniBjorn's support for pre-mul textures by setting adjust-image=premultiply or

adjust-image=divide in material.xml
But big question: can't we just modify the textures externally and use them, 
instead of doing this at runtime?


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@7712 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk
2011-02-16 06:07:38 +00:00
parent 858091d26f
commit 745bea6285
4 changed files with 79 additions and 45 deletions

View File

@@ -763,69 +763,77 @@ void IrrDriver::removeCameraSceneNode(scene::ICameraSceneNode *camera)
// ----------------------------------------------------------------------------
/** Loads a texture from a file and returns the texture object.
* \param filename File name of the texture to load.
* \param is_premul If the alpha values needd to be multiplied for
* all pixels.
* \param is_prediv If the alpha value needs to be divided into
* each pixel.
*/
video::ITexture *IrrDriver::getTexture(const std::string &filename)
video::ITexture *IrrDriver::getTexture(const std::string &filename,
bool is_premul,
bool is_prediv)
{
#undef PREMULPNGS
#ifndef PREMULPNGS
video::ITexture* out = m_scene_manager->getVideoDriver()->getTexture(filename.c_str());
#else
video::IImage* img = m_scene_manager->getVideoDriver()->createImageFromFile(filename.c_str());
// PNGs are non premul, but some are used for premul tasks, so convert
// http://home.comcast.net/~tom_forsyth/blog.wiki.html#[[Premultiplied%20alpha]]
if(StringUtils::hasSuffix(filename.c_str(), ".png")) // FIXME check param, not name
video::ITexture* out;
if(!is_premul && !is_prediv)
out = m_scene_manager->getVideoDriver()->getTexture(filename.c_str());
else
{
if ((img->getColorFormat() == irr::video::ECF_A8R8G8B8) && img->lock())
// FIXME: can't we just do this externally, and just use the
// modified textures??
video::IImage* img =
m_scene_manager->getVideoDriver()->createImageFromFile(filename.c_str());
// PNGs are non premul, but some are used for premul tasks, so convert
// http://home.comcast.net/~tom_forsyth/blog.wiki.html#[[Premultiplied%20alpha]]
// FIXME check param, not name
if(is_premul &&
StringUtils::hasSuffix(filename.c_str(), ".png") &&
(img->getColorFormat() == irr::video::ECF_A8R8G8B8) &&
img->lock())
{
core::dimension2d<u32> dim = img->getDimension();
for(uint x = 0; x < dim.Width; x++)
for(unsigned int x = 0; x < dim.Width; x++)
{
for(uint y = 0; y < dim.Height; y++)
for(unsigned int y = 0; y < dim.Height; y++)
{
video::SColor col = img->getPixel(x, y);
uint alpha = col.getAlpha();
uint red = alpha * col.getRed() / 255;
uint blue = alpha * col.getBlue() / 255;
uint green = alpha * col.getGreen() / 255;
unsigned int alpha = col.getAlpha();
unsigned int red = alpha * col.getRed() / 255;
unsigned int blue = alpha * col.getBlue() / 255;
unsigned int green = alpha * col.getGreen() / 255;
col.set(alpha, red, green, blue);
img->setPixel(x, y, col, false);
}
}
} // for y
} // for x
img->unlock();
}
}
/*
// Other formats can be premul, but the tasks can be non premul
// So divide to get the separate RGBA (only possible if alpha!=0)
else if() // FIXME, use param "DE-PREMUL requested" to match above
{
if ((img->getColorFormat() == irr::video::ECF_A8R8G8B8) && img->lock())
} // if png and ColorFOrmat and lock
// Other formats can be premul, but the tasks can be non premul
// So divide to get the separate RGBA (only possible if alpha!=0)
else if(is_prediv &&
(img->getColorFormat() == irr::video::ECF_A8R8G8B8) &&
img->lock())
{
core::dimension2d<u32> dim = img->getDimension();
for(uint x = 0; x < dim.Width; x++)
for(unsigned int x = 0; x < dim.Width; x++)
{
for(uint y = 0; y < dim.Height; y++)
for(unsigned int y = 0; y < dim.Height; y++)
{
video::SColor col = img->getPixel(x, y);
uint alpha = col.getAlpha();
unsigned int alpha = col.getAlpha();
// Avoid divide by zero
if (alpha) {
uint red = 255 * col.getRed() / alpha ;
uint blue = 255 * col.getBlue() / alpha;
uint green = 255 * col.getGreen() / alpha;
unsigned int red = 255 * col.getRed() / alpha ;
unsigned int blue = 255 * col.getBlue() / alpha;
unsigned int green = 255 * col.getGreen() / alpha;
col.set(alpha, red, green, blue);
img->setPixel(x, y, col, false);
}
}
}
} // for y
} // for x
img->unlock();
}
}
*/
video::ITexture* out = m_scene_manager->getVideoDriver()->addTexture(filename.c_str(),
img, NULL);
#endif
} // if premul && color format && lock
out = m_scene_manager->getVideoDriver()->addTexture(filename.c_str(),
img, NULL);
} // if is_premul or is_prediv
#ifndef NDEBUG
if (out == NULL)
{

View File

@@ -112,7 +112,9 @@ public:
bool OnEvent(const irr::SEvent &event);
void setAmbientLight(const video::SColor &light);
video::ITexture *getTexture(const std::string &filename);
video::ITexture *getTexture(const std::string &filename,
bool is_premul=false,
bool is_prediv=false);
scene::IMesh *createQuadMesh(const video::SMaterial *material=NULL,
bool create_one_quad=false);
scene::IMesh *createTexturedQuadMesh(const video::SMaterial *material, const double w, const double h);

View File

@@ -56,6 +56,17 @@ Material::Material(const XMLNode *node, int index)
node->get("clampV", &b); if (b) m_clamp_tex |= VCLAMP;
node->get("transparency", &m_alpha_testing );
node->get("lightmap", &m_lightmap );
std::string s;
node->get("adjust-image", &s );
if(s=="premultiply")
m_adjust_image = ADJ_PREMUL;
else if (s=="divide")
m_adjust_image = ADJ_DIV;
else if (s=="" || s=="none")
m_adjust_image = ADJ_NONE;
else
printf("Incorrect adjust-image specification: '%s' - ignored.\n",
s.c_str());
node->get("alpha", &m_alpha_blending );
node->get("light", &m_lighting );
node->get("sphere", &m_sphere_map );
@@ -77,7 +88,8 @@ Material::Material(const XMLNode *node, int index)
node->get("anisotropic", &m_anisotropic );
node->get("backface-culling", &m_backface_culling );
node->get("disable-z-write", &m_disable_z_write );
std::string s("");
s="";
node->get("graphical-effect", &s );
if(s=="water")
m_graphical_effect = GE_WATER;
@@ -162,6 +174,7 @@ void Material::init(unsigned int index)
m_clamp_tex = 0;
m_alpha_testing = false;
m_lightmap = false;
m_adjust_image = ADJ_NONE;
m_alpha_blending = false;
m_lighting = true;
m_anisotropic = false;
@@ -201,7 +214,8 @@ void Material::install(bool is_full_path)
const std::string &full_path = is_full_path
? m_texname
: file_manager->getTextureFile(m_texname);
m_texture = irr_driver->getTexture(full_path);
m_texture = irr_driver->getTexture(full_path,
isPreMul(), isPreDiv());
// now set the name to the basename, so that all tests work as expected
m_texname = StringUtils::getBasename(m_texname);

View File

@@ -96,7 +96,11 @@ private:
/** Set to true to disable writing to the Z buffer. Usually to be used with alpha blending */
bool m_disable_z_write;
/** Some textures need to be pre-multiplied, some divided to give
* the intended effect. */
enum {ADJ_NONE, ADJ_PREMUL, ADJ_DIV}
m_adjust_image;
/** True if lightmapping is enabled for this material. */
bool m_lightmap;
float m_friction;
@@ -158,6 +162,12 @@ public:
bool isTransparent () const { return m_alpha_testing || m_alpha_blending || m_add; }
// ------------------------------------------------------------------------
/** Returns true if this materials need pre-multiply of alpha. */
bool isPreMul() const {return m_adjust_image==ADJ_PREMUL; }
// ------------------------------------------------------------------------
/** Returns true if this materials need pre-division of alpha. */
bool isPreDiv() const {return m_adjust_image==ADJ_DIV; }
// ------------------------------------------------------------------------
/** Returns the fraction of maximum speed on this material. */
float getMaxSpeedFraction() const { return m_max_speed_fraction; }