In case it's of use to anyone else, here is the draw2DImage I ended up using. It's heavily based on Lonesome Ducky's. Changes:
* Instead of a position and scaling, it takes a destination rect.
* Removed the rotation arguments and supporting code
* Removed the alpha argument. It was never used.
* Removed the color argument and supporting code.
* Saves and restores the world and texture matrices. Some other code (wild guess: the Quake 3 support) was leaving these in a weird state and causing problems.
* Disable checking the Z-Buffer.
* Silenced some warnings under g++ by explicitly casting to int to float.
* Uses an alpha channel on the texture instead of additive mixing.
Code: Select all
void draw2DImage(irr::video::IVideoDriver* driver, irr::video::ITexture* texture, irr::core::rect<irr::s32> sourceRect, irr::core::rect<irr::s32> destRect, irr::video::E_MATERIAL_FLAG filter = irr::video::EMF_BILINEAR_FILTER) {
const irr::video::SColor color = irr::video::SColor(255,255,255,255);
irr::video::SMaterial material;
// Store and clear the projection matrix
irr::core::matrix4 oldProjMat = driver->getTransform(irr::video::ETS_PROJECTION);
driver->setTransform(irr::video::ETS_PROJECTION,irr::core::matrix4());
// Store and clear the view matrix
irr::core::matrix4 oldViewMat = driver->getTransform(irr::video::ETS_VIEW);
driver->setTransform(irr::video::ETS_VIEW,irr::core::matrix4());
// Store and clear the world matrix
irr::core::matrix4 oldWorldMat = driver->getTransform(irr::video::ETS_WORLD);
driver->setTransform(irr::video::ETS_WORLD,irr::core::matrix4());
// Store and clear the texture matrices
irr::core::matrix4 oldTexture0Mat = driver->getTransform(irr::video::ETS_TEXTURE_0);
driver->setTransform(irr::video::ETS_TEXTURE_0,irr::core::matrix4());
irr::core::matrix4 oldTexture1Mat = driver->getTransform(irr::video::ETS_TEXTURE_1);
driver->setTransform(irr::video::ETS_TEXTURE_1,irr::core::matrix4());
irr::core::matrix4 oldTexture2Mat = driver->getTransform(irr::video::ETS_TEXTURE_2);
driver->setTransform(irr::video::ETS_TEXTURE_2,irr::core::matrix4());
irr::core::matrix4 oldTexture3Mat = driver->getTransform(irr::video::ETS_TEXTURE_3);
driver->setTransform(irr::video::ETS_TEXTURE_3,irr::core::matrix4());
// Find the positions of corners
irr::core::vector2df corner[4];
corner[0] = irr::core::vector2df(float(destRect.UpperLeftCorner.X), float(destRect.UpperLeftCorner.Y));
corner[1] = irr::core::vector2df(float(destRect.LowerRightCorner.X), float(destRect.UpperLeftCorner.Y));
corner[2] = irr::core::vector2df(float(destRect.UpperLeftCorner.X), float(destRect.LowerRightCorner.Y));
corner[3] = irr::core::vector2df(float(destRect.LowerRightCorner.X), float(destRect.LowerRightCorner.Y));
// Find the uv coordinates of the sourceRect
float subTexelX = 0.5f/float(texture->getSize().Width);
float subTexelY = 0.5f/float(texture->getSize().Height);
irr::core::vector2df uvCorner[4];
uvCorner[0] = irr::core::vector2df(float(sourceRect.UpperLeftCorner.X),float(sourceRect.UpperLeftCorner.Y));
uvCorner[1] = irr::core::vector2df(float(sourceRect.LowerRightCorner.X),float(sourceRect.UpperLeftCorner.Y));
uvCorner[2] = irr::core::vector2df(float(sourceRect.UpperLeftCorner.X),float(sourceRect.LowerRightCorner.Y));
uvCorner[3] = irr::core::vector2df(float(sourceRect.LowerRightCorner.X),float(sourceRect.LowerRightCorner.Y));
for (int x = 0; x < 4; x++) {
float uvX = uvCorner[x].X/(float)texture->getSize().Width;
float uvY = uvCorner[x].Y/(float)texture->getSize().Height;
uvCorner[x] = irr::core::vector2df(uvX,uvY);
}
uvCorner[0].X += subTexelX;
uvCorner[0].Y += subTexelY;
uvCorner[1].X -= subTexelX;
uvCorner[1].Y += subTexelY;
uvCorner[2].X += subTexelX;
uvCorner[2].Y -= subTexelY;
uvCorner[3].X -= subTexelX;
uvCorner[3].Y -= subTexelY;
// Vertices for the image
irr::video::S3DVertex vertices[4];
irr::u16 indices[6] = { 0, 1, 2, 3 ,2 ,1 };
// Convert pixels to world coordinates
float screenWidth = float(driver->getScreenSize().Width);
float screenHeight = float(driver->getScreenSize().Height);
for (int x = 0; x < 4; x++) {
float screenPosX = ((corner[x].X/screenWidth)-0.5f)*2.0f;
float screenPosY = ((corner[x].Y/screenHeight)-0.5f)*-2.0f;
vertices[x].Pos = irr::core::vector3df(screenPosX,screenPosY,1);
vertices[x].TCoords = uvCorner[x];
vertices[x].Color = color;
}
material.Lighting = false;
material.ZWriteEnable = false;
material.ZBuffer = irr::video::ECFN_ALWAYS;
material.TextureLayer[0].Texture = texture;
material.setFlag(irr::video::EMF_ANISOTROPIC_FILTER,false);
material.setFlag(irr::video::EMF_BILINEAR_FILTER,false);
material.setFlag(irr::video::EMF_TRILINEAR_FILTER,false);
material.setFlag(filter,true);
//material.MaterialType = irr::video::EMT_TRANSPARENT_ADD_COLOR;
material.MaterialType = irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL;
driver->setMaterial(material);
driver->drawIndexedTriangleList(&vertices[0],4,&indices[0],2);
// Restore projection and view matrices
driver->setTransform(irr::video::ETS_PROJECTION,oldProjMat);
driver->setTransform(irr::video::ETS_VIEW,oldViewMat);
driver->setTransform(irr::video::ETS_WORLD,oldWorldMat);
driver->setTransform(irr::video::ETS_TEXTURE_0,oldTexture0Mat);
driver->setTransform(irr::video::ETS_TEXTURE_1,oldTexture1Mat);
driver->setTransform(irr::video::ETS_TEXTURE_2,oldTexture2Mat);
driver->setTransform(irr::video::ETS_TEXTURE_3,oldTexture3Mat);
}