1515 *
1616 */
1717
18+ #include < cstddef>
19+
1820// Note this include is placed in the src file because
1921// otherwise ogre produces compile errors
2022#ifdef _MSC_VER
3133#include < OgreMaterialManager.h>
3234#include < OgrePixelFormatGpuUtils.h>
3335#include < OgreTechnique.h>
36+ #include < OgreTextureBox.h>
37+ #include < OgreTextureFilters.h>
3438#include < OgreTextureGpuManager.h>
3539#include < Vao/OgreVaoManager.h>
3640#ifdef _MSC_VER
@@ -130,6 +134,23 @@ class gz::rendering::Ogre2MaterialPrivate
130134 return " invalid" ;
131135 }
132136 }
137+
138+ // / \brief Prepare for normal mapping by converting to two-component
139+ // / normalized signed 8-bit format
140+ // / \param[in] _texture Normal map texture
141+ // / \param[in/out] _image Normal map image data
142+ public: void PrepareForNormalMapping (Ogre::TextureGpu *_texture,
143+ Ogre::Image2 &_image);
144+
145+ // / \brief Allocate mimaps for the texture. This should be done when the
146+ // / texture's residency status is still OnStorage.
147+ // / \param[in] _texture Input texture to allocate mimaps
148+ public: void AllocateMipmaps (Ogre::TextureGpu *_texture);
149+
150+ // / \brief Generate mimaps for the texture. This should be done when the
151+ // / texture's residency status is Resident.
152+ // / \param[in] _texture Input texture to generate mimpas
153+ public: void GenerateMipmaps (Ogre::TextureGpu *_texture);
133154};
134155
135156using namespace gz ;
@@ -1220,6 +1241,8 @@ void Ogre2Material::SetTextureMapDataImpl(const std::string& _name,
12201241 root->getRenderSystem ()->getTextureGpuManager ();
12211242
12221243 // create the gpu texture
1244+ Ogre::uint32 filters = Ogre::TextureFilter::TypeGenerateDefaultMipmaps;
1245+ filters |= this ->ogreDatablock ->suggestFiltersForType (_type);
12231246 Ogre::uint32 textureFlags = 0 ;
12241247 textureFlags |= Ogre::TextureFlags::AutomaticBatching;
12251248 Ogre::TextureGpu *texture = textureMgr->createOrRetrieveTexture (
@@ -1228,7 +1251,7 @@ void Ogre2Material::SetTextureMapDataImpl(const std::string& _name,
12281251 textureFlags | Ogre::TextureFlags::ManualTexture,
12291252 Ogre::TextureTypes::Type2D,
12301253 Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME,
1231- 0u );
1254+ filters );
12321255
12331256 // Has to be loaded
12341257 if (texture->getWidth () == 0 )
@@ -1241,13 +1264,31 @@ void Ogre2Material::SetTextureMapDataImpl(const std::string& _name,
12411264 texture->setTextureType (Ogre::TextureTypes::Type2D);
12421265 texture->setNumMipmaps (1u );
12431266 texture->setResolution (_img->Width (), _img->Height ());
1244- texture->scheduleTransitionTo (Ogre::GpuResidency::Resident);
1245- texture->waitForData ();
12461267
1247- // upload raw color image data to gpu texture
12481268 Ogre::Image2 img;
12491269 img.loadDynamicImage (&data[0 ], false , texture);
1270+
1271+ // Replicates the steps that ogre does when it loads a texture map from
1272+ // file. For normal maps, it is first converted to a two component signed
1273+ // 8 bit format. Albedo and normal maps will have mipmaps generated.
1274+ // \todo(iche033) See if there is a way to reuse these functions
1275+ // from ogre-next without copying the code here.
1276+
1277+ // Normal maps - convert to two component signed 8 bit format:
1278+ // Ogre::PFG_RG8_SNORM format
1279+ if (_type == Ogre::PBSM_NORMAL)
1280+ this ->dataPtr ->PrepareForNormalMapping (texture, img);
1281+
1282+ if (_type == Ogre::PBSM_DIFFUSE || _type == Ogre::PBSM_NORMAL)
1283+ this ->dataPtr ->AllocateMipmaps (texture);
1284+
1285+ // Upload raw color image data to gpu texture
1286+ texture->scheduleTransitionTo (Ogre::GpuResidency::Resident);
1287+ texture->waitForData ();
12501288 img.uploadTo (texture, 0 , 0 );
1289+
1290+ if (_type == Ogre::PBSM_DIFFUSE || _type == Ogre::PBSM_NORMAL)
1291+ this ->dataPtr ->GenerateMipmaps (texture);
12511292 }
12521293
12531294 // Now assign it to the material
@@ -1563,3 +1604,89 @@ ShaderParamsPtr Ogre2Material::FragmentShaderParams()
15631604{
15641605 return this ->dataPtr ->fragmentShaderParams ;
15651606}
1607+
1608+ // ////////////////////////////////////////////////
1609+ void Ogre2MaterialPrivate::PrepareForNormalMapping (Ogre::TextureGpu *_texture,
1610+ Ogre::Image2 &_image)
1611+ {
1612+ // code adpated from PrepareForNormalMapping::_executeStreaming function in
1613+ // OgreMain/src/OgreTextureFilters.cpp (v2-3)
1614+ const Ogre::uint8 numMipmaps = _image.getNumMipmaps ();
1615+ const Ogre::PixelFormatGpu dstFormat = Ogre::PFG_RG8_SNORM;
1616+ const Ogre::uint32 rowAlignment = 4u ;
1617+ const size_t dstSizeBytes = Ogre::PixelFormatGpuUtils::calculateSizeBytes (
1618+ _image.getWidth (),
1619+ _image.getHeight (),
1620+ _image.getDepth (),
1621+ _image.getNumSlices (),
1622+ dstFormat, numMipmaps,
1623+ rowAlignment );
1624+ void *imgData = OGRE_MALLOC_SIMD ( dstSizeBytes, Ogre::MEMCATEGORY_RESOURCE);
1625+ for (Ogre::uint8 mip = 0 ; mip < numMipmaps; ++mip)
1626+ {
1627+ Ogre::TextureBox srcBox = _image.getData ( mip );
1628+ const Ogre::uint32 width = srcBox.width ;
1629+ const Ogre::uint32 height = srcBox.height ;
1630+
1631+ Ogre::TextureBox dstBox = srcBox;
1632+ dstBox.bytesPerPixel =
1633+ Ogre::PixelFormatGpuUtils::getBytesPerPixel (dstFormat);
1634+ dstBox.bytesPerRow =
1635+ Ogre::PixelFormatGpuUtils::getSizeBytes (
1636+ width, 1u , 1u , 1u , dstFormat, 4u );
1637+ dstBox.bytesPerImage =
1638+ Ogre::PixelFormatGpuUtils::getSizeBytes (width, height, 1u , 1u ,
1639+ dstFormat, 4u );
1640+ dstBox.data = Ogre::PixelFormatGpuUtils::advancePointerToMip (
1641+ imgData, width, height, srcBox.depth , srcBox.numSlices , mip, dstFormat);
1642+
1643+ Ogre::PixelFormatGpuUtils::convertForNormalMapping (
1644+ srcBox, _image.getPixelFormat (),
1645+ dstBox, dstFormat);
1646+ }
1647+ _image.loadDynamicImage (imgData, _image.getWidth (), _image.getHeight (),
1648+ _image.getDepthOrSlices (), _image.getTextureType (), dstFormat, false ,
1649+ numMipmaps);
1650+ _texture->setPixelFormat (dstFormat);
1651+ }
1652+
1653+ // ////////////////////////////////////////////////
1654+ void Ogre2MaterialPrivate::AllocateMipmaps (Ogre::TextureGpu *_texture)
1655+ {
1656+ // code adpated from GenerateHwMipmaps::_executeStreaming function in
1657+ // OgreMain/src/OgreTextureFilters.cpp (v2-3)
1658+ Ogre::uint8 maxMipmaps = Ogre::PixelFormatGpuUtils::getMaxMipmapCount (
1659+ _texture->getWidth (),
1660+ _texture->getHeight (),
1661+ _texture->getDepth () );
1662+ _texture->setNumMipmaps (maxMipmaps);
1663+ }
1664+
1665+ // ////////////////////////////////////////////////
1666+ void Ogre2MaterialPrivate::GenerateMipmaps (Ogre::TextureGpu *_texture)
1667+ {
1668+ // code adpated from GenerateHwMipmaps::_executeSerial function in
1669+ // OgreMain/src/OgreTextureFilters.cpp (v2-3)
1670+ Ogre::TextureGpuManager *textureManager = _texture->getTextureManager ();
1671+ Ogre::TextureGpu *tempTexture = textureManager->createTexture (
1672+ " ___tempMipmapTexture" ,
1673+ Ogre::GpuPageOutStrategy::Discard,
1674+ Ogre::TextureFlags::RenderToTexture |
1675+ Ogre::TextureFlags::AllowAutomipmaps |
1676+ Ogre::TextureFlags::DiscardableContent,
1677+ _texture->getTextureType ());
1678+ tempTexture->copyParametersFrom (_texture);
1679+ tempTexture->unsafeScheduleTransitionTo (Ogre::GpuResidency::Resident);
1680+ Ogre::TextureBox box = _texture->getEmptyBox (0 );
1681+ _texture->copyTo (tempTexture, box, 0 , box, 0 );
1682+ tempTexture->_autogenerateMipmaps ();
1683+
1684+ Ogre::uint8 mipmaps = _texture->getNumMipmaps ();
1685+ for (size_t i = 1u ; i < mipmaps; ++i)
1686+ {
1687+ box = _texture->getEmptyBox ( i );
1688+ tempTexture->copyTo (_texture, box, i, box, i);
1689+ }
1690+ textureManager->destroyTexture (tempTexture);
1691+ tempTexture = 0 ;
1692+ }
0 commit comments