mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-14 08:04:40 +00:00
Update GFXTextureManager and GBitmap
GBitmap Changes: Added all other formats to gbitmap that we support gbitmap now supports cubemaps added converters for all these other formats added stb_image_resize for extrudemips so we can extrude mipmaps for all other formats GFXTextureManager Can now directly make cubemaps and texture arrays based on the GFXTextureProfile API implementations for all functions that cubemaps and arrays needed
This commit is contained in:
parent
975fc924cc
commit
3aef90a6bc
66 changed files with 4235 additions and 2590 deletions
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
namespace IBLUtilities
|
namespace IBLUtilities
|
||||||
{
|
{
|
||||||
void GenerateIrradianceMap(GFXTextureTargetRef renderTarget, GFXCubemapHandle cubemap, GFXCubemapHandle &cubemapOut)
|
void GenerateIrradianceMap(GFXTextureTargetRef renderTarget, GFXTexHandle cubemap, GFXTexHandle &cubemapOut)
|
||||||
{
|
{
|
||||||
GFXTransformSaver saver;
|
GFXTransformSaver saver;
|
||||||
|
|
||||||
|
|
@ -65,11 +65,11 @@ namespace IBLUtilities
|
||||||
GFX->setShaderConstBuffer(irrConsts);
|
GFX->setShaderConstBuffer(irrConsts);
|
||||||
GFX->setStateBlock(irrStateBlock);
|
GFX->setStateBlock(irrStateBlock);
|
||||||
GFX->setVertexBuffer(NULL);
|
GFX->setVertexBuffer(NULL);
|
||||||
GFX->setCubeTexture(0, cubemap);
|
GFX->setTexture(0, cubemap);
|
||||||
|
|
||||||
for (U32 i = 0; i < 6; i++)
|
for (U32 i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
renderTarget->attachTexture(GFXTextureTarget::Color0, cubemapOut, i);
|
renderTarget->attachTexture(GFXTextureTarget::Color0, cubemapOut, 0,0, i);
|
||||||
irrConsts->setSafe(irrFaceSC, (S32)i);
|
irrConsts->setSafe(irrFaceSC, (S32)i);
|
||||||
GFX->setActiveRenderTarget(renderTarget);
|
GFX->setActiveRenderTarget(renderTarget);
|
||||||
GFX->clear(GFXClearTarget, LinearColorF::BLACK, 1.0f, 0);
|
GFX->clear(GFXClearTarget, LinearColorF::BLACK, 1.0f, 0);
|
||||||
|
|
@ -80,7 +80,7 @@ namespace IBLUtilities
|
||||||
GFX->popActiveRenderTarget();
|
GFX->popActiveRenderTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateAndSaveIrradianceMap(String outputPath, S32 resolution, GFXCubemapHandle cubemap, GFXCubemapHandle &cubemapOut)
|
void GenerateAndSaveIrradianceMap(String outputPath, S32 resolution, GFXTexHandle cubemap, GFXTexHandle &cubemapOut)
|
||||||
{
|
{
|
||||||
if (outputPath.isEmpty())
|
if (outputPath.isEmpty())
|
||||||
{
|
{
|
||||||
|
|
@ -101,7 +101,7 @@ namespace IBLUtilities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveCubeMap(String outputPath, GFXCubemapHandle &cubemap)
|
void SaveCubeMap(String outputPath, GFXTexHandle &cubemap)
|
||||||
{
|
{
|
||||||
if (outputPath.isEmpty())
|
if (outputPath.isEmpty())
|
||||||
{
|
{
|
||||||
|
|
@ -118,7 +118,7 @@ namespace IBLUtilities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneratePrefilterMap(GFXTextureTargetRef renderTarget, GFXCubemapHandle cubemap, U32 mipLevels, GFXCubemapHandle &cubemapOut)
|
void GeneratePrefilterMap(GFXTextureTargetRef renderTarget, GFXTexHandle cubemap, U32 mipLevels, GFXTexHandle &cubemapOut)
|
||||||
{
|
{
|
||||||
GFXTransformSaver saver;
|
GFXTransformSaver saver;
|
||||||
|
|
||||||
|
|
@ -153,9 +153,9 @@ namespace IBLUtilities
|
||||||
GFX->pushActiveRenderTarget();
|
GFX->pushActiveRenderTarget();
|
||||||
GFX->setShader(prefilterShader);
|
GFX->setShader(prefilterShader);
|
||||||
GFX->setShaderConstBuffer(prefilterConsts);
|
GFX->setShaderConstBuffer(prefilterConsts);
|
||||||
GFX->setCubeTexture(0, cubemap);
|
GFX->setTexture(0, cubemap);
|
||||||
|
|
||||||
U32 prefilterSize = cubemapOut->getSize();
|
U32 prefilterSize = cubemapOut->getWidth();
|
||||||
|
|
||||||
U32 resolutionSize = prefilterSize;
|
U32 resolutionSize = prefilterSize;
|
||||||
|
|
||||||
|
|
@ -171,7 +171,7 @@ namespace IBLUtilities
|
||||||
prefilterConsts->setSafe(prefilterRoughnessSC, roughness);
|
prefilterConsts->setSafe(prefilterRoughnessSC, roughness);
|
||||||
prefilterConsts->setSafe(prefilterMipSizeSC, mipSize);
|
prefilterConsts->setSafe(prefilterMipSizeSC, mipSize);
|
||||||
U32 size = prefilterSize * mPow(0.5f, mip);
|
U32 size = prefilterSize * mPow(0.5f, mip);
|
||||||
renderTarget->attachTexture(GFXTextureTarget::Color0, cubemapOut, face);
|
renderTarget->attachTexture(GFXTextureTarget::Color0, cubemapOut, 0,0 ,face);
|
||||||
GFX->setActiveRenderTarget(renderTarget, false);//we set the viewport ourselves
|
GFX->setActiveRenderTarget(renderTarget, false);//we set the viewport ourselves
|
||||||
GFX->setViewport(RectI(0, 0, size, size));
|
GFX->setViewport(RectI(0, 0, size, size));
|
||||||
GFX->clear(GFXClearTarget, LinearColorF::BLACK, 1.0f, 0);
|
GFX->clear(GFXClearTarget, LinearColorF::BLACK, 1.0f, 0);
|
||||||
|
|
@ -183,7 +183,7 @@ namespace IBLUtilities
|
||||||
GFX->popActiveRenderTarget();
|
GFX->popActiveRenderTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateAndSavePrefilterMap(String outputPath, S32 resolution, GFXCubemapHandle cubemap, U32 mipLevels, GFXCubemapHandle &cubemapOut)
|
void GenerateAndSavePrefilterMap(String outputPath, S32 resolution, GFXTexHandle cubemap, U32 mipLevels, GFXTexHandle &cubemapOut)
|
||||||
{
|
{
|
||||||
if (outputPath.isEmpty())
|
if (outputPath.isEmpty())
|
||||||
{
|
{
|
||||||
|
|
@ -504,7 +504,7 @@ namespace IBLUtilities
|
||||||
//SH Calculations
|
//SH Calculations
|
||||||
// From http://sunandblackcat.com/tipFullView.php?l=eng&topicid=32&topic=Spherical-Harmonics-From-Cube-Texture
|
// From http://sunandblackcat.com/tipFullView.php?l=eng&topicid=32&topic=Spherical-Harmonics-From-Cube-Texture
|
||||||
// With shader decode logic from https://github.com/nicknikolov/cubemap-sh
|
// With shader decode logic from https://github.com/nicknikolov/cubemap-sh
|
||||||
void calculateSHTerms(GFXCubemapHandle cubemap, LinearColorF SHTerms[9], F32 SHConstants[5])
|
void calculateSHTerms(GFXTexHandle cubemap, LinearColorF SHTerms[9], F32 SHConstants[5])
|
||||||
{
|
{
|
||||||
if (!cubemap)
|
if (!cubemap)
|
||||||
return;
|
return;
|
||||||
|
|
@ -525,7 +525,7 @@ namespace IBLUtilities
|
||||||
VectorF(0.0f, 0.0f, -1.0f),
|
VectorF(0.0f, 0.0f, -1.0f),
|
||||||
};
|
};
|
||||||
|
|
||||||
U32 cubemapResolution = cubemap->getSize();
|
U32 cubemapResolution = cubemap->getWidth();
|
||||||
|
|
||||||
GBitmap* cubeFaceBitmaps[6];
|
GBitmap* cubeFaceBitmaps[6];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,13 @@
|
||||||
|
|
||||||
namespace IBLUtilities
|
namespace IBLUtilities
|
||||||
{
|
{
|
||||||
void GenerateIrradianceMap(GFXTextureTargetRef renderTarget, GFXCubemapHandle cubemap, GFXCubemapHandle &cubemapOut);
|
void GenerateIrradianceMap(GFXTextureTargetRef renderTarget, GFXTexHandle cubemap, GFXTexHandle& cubemapOut);
|
||||||
void GenerateAndSaveIrradianceMap(String outputPath, S32 resolution, GFXCubemapHandle cubemap, GFXCubemapHandle &cubemapOut);
|
void GenerateAndSaveIrradianceMap(String outputPath, S32 resolution, GFXTexHandle cubemap, GFXTexHandle& cubemapOut);
|
||||||
|
|
||||||
void GeneratePrefilterMap(GFXTextureTargetRef renderTarget, GFXCubemapHandle cubemap, U32 mipLevels, GFXCubemapHandle &cubemapOut);
|
void GeneratePrefilterMap(GFXTextureTargetRef renderTarget, GFXTexHandle cubemap, U32 mipLevels, GFXTexHandle &cubemapOut);
|
||||||
void GenerateAndSavePrefilterMap(String outputPath, S32 resolution, GFXCubemapHandle cubemap, U32 mipLevels, GFXCubemapHandle &cubemapOut);
|
void GenerateAndSavePrefilterMap(String outputPath, S32 resolution, GFXTexHandle cubemap, U32 mipLevels, GFXTexHandle &cubemapOut);
|
||||||
|
|
||||||
void SaveCubeMap(String outputPath, GFXCubemapHandle &cubemap);
|
void SaveCubeMap(String outputPath, GFXTexHandle &cubemap);
|
||||||
|
|
||||||
void bakeReflection(String outputPath, S32 resolution);
|
void bakeReflection(String outputPath, S32 resolution);
|
||||||
|
|
||||||
|
|
@ -60,7 +60,7 @@ namespace IBLUtilities
|
||||||
//SH Calculations
|
//SH Calculations
|
||||||
// From http://sunandblackcat.com/tipFullView.php?l=eng&topicid=32&topic=Spherical-Harmonics-From-Cube-Texture
|
// From http://sunandblackcat.com/tipFullView.php?l=eng&topicid=32&topic=Spherical-Harmonics-From-Cube-Texture
|
||||||
// With shader decode logic from https://github.com/nicknikolov/cubemap-sh
|
// With shader decode logic from https://github.com/nicknikolov/cubemap-sh
|
||||||
void calculateSHTerms(GFXCubemapHandle cubemap, LinearColorF SHTerms[9], F32 SHConstants[5]);
|
void calculateSHTerms(GFXTexHandle cubemap, LinearColorF SHTerms[9], F32 SHConstants[5]);
|
||||||
|
|
||||||
F32 texelSolidAngle(F32 aU, F32 aV, U32 width, U32 height);
|
F32 texelSolidAngle(F32 aU, F32 aV, U32 width, U32 height);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,13 @@ ImplementEnumType(ReflectionModeEnum,
|
||||||
//{ ReflectionProbe::DynamicCubemap, "Dynamic Cubemap", "Uses a cubemap baked from the probe's current position, updated at a set rate" },
|
//{ ReflectionProbe::DynamicCubemap, "Dynamic Cubemap", "Uses a cubemap baked from the probe's current position, updated at a set rate" },
|
||||||
EndImplementEnumType;
|
EndImplementEnumType;
|
||||||
|
|
||||||
|
void ReflectionProbe::ProbeInfo::clear()
|
||||||
|
{
|
||||||
|
mPrefilterCubemap.free();
|
||||||
|
mIrradianceCubemap.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Object setup and teardown
|
// Object setup and teardown
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
@ -146,11 +153,18 @@ ReflectionProbe::~ReflectionProbe()
|
||||||
if (mReflectionModeType == StaticCubemap && mStaticCubemap)
|
if (mReflectionModeType == StaticCubemap && mStaticCubemap)
|
||||||
mStaticCubemap->deleteObject();
|
mStaticCubemap->deleteObject();
|
||||||
|
|
||||||
if (mIrridianceMap)
|
mProbeInfo.clear();
|
||||||
mIrridianceMap->deleteObject();
|
|
||||||
|
if (mIrridianceMap) {
|
||||||
|
if (mIrridianceMap->isProperlyAdded() && !mIrridianceMap->isRemoved())
|
||||||
|
mIrridianceMap->deleteObject();
|
||||||
|
}
|
||||||
|
|
||||||
if (mPrefilterMap)
|
if (mPrefilterMap)
|
||||||
mPrefilterMap->deleteObject();
|
{
|
||||||
|
if (mPrefilterMap->isProperlyAdded() && !mPrefilterMap->isRemoved())
|
||||||
|
mPrefilterMap->deleteObject();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
@ -603,7 +617,7 @@ void ReflectionProbe::processBakedCubemap()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
String irrPath = getIrradianceMapPath();
|
String irrPath = getIrradianceMapPath();
|
||||||
if (Platform::isFile(irrPath))
|
if ((mIrridianceMap == nullptr || mIrridianceMap->mCubemap.isNull()) && Platform::isFile(irrPath))
|
||||||
{
|
{
|
||||||
mIrridianceMap->setCubemapFile(FileName(irrPath));
|
mIrridianceMap->setCubemapFile(FileName(irrPath));
|
||||||
mIrridianceMap->updateFaces();
|
mIrridianceMap->updateFaces();
|
||||||
|
|
@ -616,7 +630,7 @@ void ReflectionProbe::processBakedCubemap()
|
||||||
}
|
}
|
||||||
|
|
||||||
String prefilPath = getPrefilterMapPath();
|
String prefilPath = getPrefilterMapPath();
|
||||||
if (Platform::isFile(prefilPath))
|
if ((mPrefilterMap == nullptr || mPrefilterMap->mCubemap.isNull()) && Platform::isFile(prefilPath))
|
||||||
{
|
{
|
||||||
mPrefilterMap->setCubemapFile(FileName(prefilPath));
|
mPrefilterMap->setCubemapFile(FileName(prefilPath));
|
||||||
mPrefilterMap->updateFaces();
|
mPrefilterMap->updateFaces();
|
||||||
|
|
@ -631,7 +645,7 @@ void ReflectionProbe::processBakedCubemap()
|
||||||
mProbeInfo.mPrefilterCubemap = mPrefilterMap->mCubemap;
|
mProbeInfo.mPrefilterCubemap = mPrefilterMap->mCubemap;
|
||||||
mProbeInfo.mIrradianceCubemap = mIrridianceMap->mCubemap;
|
mProbeInfo.mIrradianceCubemap = mIrridianceMap->mCubemap;
|
||||||
|
|
||||||
if (mEnabled && mProbeInfo.mPrefilterCubemap->isInitialized() && mProbeInfo.mIrradianceCubemap->isInitialized())
|
if (mEnabled && !mProbeInfo.mPrefilterCubemap.isNull() && !mProbeInfo.mIrradianceCubemap.isNull())
|
||||||
{
|
{
|
||||||
//mProbeInfo.mIsEnabled = true;
|
//mProbeInfo.mIsEnabled = true;
|
||||||
|
|
||||||
|
|
@ -698,7 +712,7 @@ void ReflectionProbe::processStaticCubemap()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mStaticCubemap->mCubemap == nullptr)
|
if (mStaticCubemap->mCubemap.isNull())
|
||||||
{
|
{
|
||||||
mStaticCubemap->createMap();
|
mStaticCubemap->createMap();
|
||||||
mStaticCubemap->updateFaces();
|
mStaticCubemap->updateFaces();
|
||||||
|
|
@ -706,13 +720,13 @@ void ReflectionProbe::processStaticCubemap()
|
||||||
|
|
||||||
if (mUseHDRCaptures)
|
if (mUseHDRCaptures)
|
||||||
{
|
{
|
||||||
mIrridianceMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR16G16B16A16F);
|
mIrridianceMap->mCubemap.set(mPrefilterSize, mPrefilterSize, GFXFormatR16G16B16A16F, &GFXCubemapRenderTargetProfile, "ReflectionProbe::mIrridianceMap_HDR");
|
||||||
mPrefilterMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR16G16B16A16F);
|
mPrefilterMap->mCubemap.set(mPrefilterSize, mPrefilterSize, GFXFormatR16G16B16A16F, &GFXCubemapRenderTargetProfile, "ReflectionProbe::mPrefilterMap_HDR");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mIrridianceMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR8G8B8A8);
|
mIrridianceMap->mCubemap.set(mPrefilterSize, mPrefilterSize, GFXFormatR8G8B8A8, &GFXCubemapRenderTargetProfile, "ReflectionProbe::mIrridianceMap");
|
||||||
mPrefilterMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR8G8B8A8);
|
mPrefilterMap->mCubemap.set(mPrefilterSize, mPrefilterSize, GFXFormatR8G8B8A8, &GFXCubemapRenderTargetProfile, "ReflectionProbe::mPrefilterMap");
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false);
|
GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false);
|
||||||
|
|
@ -730,7 +744,7 @@ void ReflectionProbe::processStaticCubemap()
|
||||||
mProbeInfo.mIrradianceCubemap = mIrridianceMap->mCubemap;
|
mProbeInfo.mIrradianceCubemap = mIrridianceMap->mCubemap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mEnabled && mProbeInfo.mPrefilterCubemap->isInitialized() && mProbeInfo.mIrradianceCubemap->isInitialized())
|
if (mEnabled && mProbeInfo.mPrefilterCubemap.isValid() && mProbeInfo.mIrradianceCubemap.isValid())
|
||||||
{
|
{
|
||||||
mProbeInfo.mIsEnabled = true;
|
mProbeInfo.mIsEnabled = true;
|
||||||
|
|
||||||
|
|
@ -1009,7 +1023,7 @@ void ReflectionProbe::setPreviewMatParameters(SceneRenderState* renderState, Bas
|
||||||
GFX->setTexture(0, deferredTexObject);
|
GFX->setTexture(0, deferredTexObject);
|
||||||
|
|
||||||
//Set the cubemap
|
//Set the cubemap
|
||||||
GFX->setCubeTexture(1, mPrefilterMap->mCubemap);
|
GFX->setTexture(1, mPrefilterMap->mCubemap);
|
||||||
|
|
||||||
//Set the invViewMat
|
//Set the invViewMat
|
||||||
MatrixSet &matrixSet = renderState->getRenderPass()->getMatrixSet();
|
MatrixSet &matrixSet = renderState->getRenderPass()->getMatrixSet();
|
||||||
|
|
@ -1036,3 +1050,4 @@ DefineEngineMethod(ReflectionProbe, Bake, void, (), ,
|
||||||
clientProbe->bake();
|
clientProbe->bake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,8 +94,8 @@ public:
|
||||||
|
|
||||||
F32 mScore;
|
F32 mScore;
|
||||||
|
|
||||||
GFXCubemapHandle mPrefilterCubemap;
|
GFXTexHandle mPrefilterCubemap;
|
||||||
GFXCubemapHandle mIrradianceCubemap;
|
GFXTexHandle mIrradianceCubemap;
|
||||||
|
|
||||||
/// The priority of this light used for
|
/// The priority of this light used for
|
||||||
/// light and shadow scoring.
|
/// light and shadow scoring.
|
||||||
|
|
@ -233,7 +233,7 @@ protected:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
StringTableEntry mCubemapName;
|
StringTableEntry mCubemapName;
|
||||||
CubemapData *mStaticCubemap;
|
CubemapData *mStaticCubemap;
|
||||||
GFXCubemapHandle mDynamicCubemap;
|
GFXTexHandle mDynamicCubemap;
|
||||||
|
|
||||||
//String cubeDescName;
|
//String cubeDescName;
|
||||||
//U32 cubeDescId;
|
//U32 cubeDescId;
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,21 @@ bool AssetManager::onAdd()
|
||||||
|
|
||||||
void AssetManager::onRemove()
|
void AssetManager::onRemove()
|
||||||
{
|
{
|
||||||
|
// Remove all private assets explicitly before purge.
|
||||||
|
Vector<AssetDefinition*> assetDefinitions;
|
||||||
|
|
||||||
|
// at this point all module assets should have been unloaded.
|
||||||
|
for (typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr)
|
||||||
|
{
|
||||||
|
assetDefinitions.push_back(assetItr->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Vector<AssetDefinition*>::iterator assetItr = assetDefinitions.begin(); assetItr != assetDefinitions.end(); ++assetItr)
|
||||||
|
{
|
||||||
|
AssetDefinition* pAssetDefinition = *assetItr;
|
||||||
|
unloadAsset(pAssetDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
// Do we have an asset tags manifest?
|
// Do we have an asset tags manifest?
|
||||||
if ( !mAssetTagsManifest.isNull() )
|
if ( !mAssetTagsManifest.isNull() )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1090,7 +1090,7 @@ void ScatterSky::_render( ObjectRenderInst *ri, SceneRenderState *state, BaseMat
|
||||||
if ( !mNightCubemap->mCubemap )
|
if ( !mNightCubemap->mCubemap )
|
||||||
mNightCubemap->createMap();
|
mNightCubemap->createMap();
|
||||||
|
|
||||||
GFX->setCubeTexture( 0, mNightCubemap->mCubemap );
|
GFX->setTexture( 0, mNightCubemap->mCubemap );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -776,9 +776,9 @@ void WaterObject::setCustomTextures( S32 matIdx, U32 pass, const WaterMatParams
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ( matIdx == WaterMat || matIdx == BasicWaterMat ) && mCubemap )
|
if ( ( matIdx == WaterMat || matIdx == BasicWaterMat ) && mCubemap )
|
||||||
GFX->setCubeTexture( paramHandles.mCubemapSamplerSC->getSamplerRegister(pass), mCubemap->mCubemap );
|
GFX->setTexture( paramHandles.mCubemapSamplerSC->getSamplerRegister(pass), mCubemap->mCubemap );
|
||||||
else if(paramHandles.mCubemapSamplerSC->getSamplerRegister(pass) != -1 )
|
else if(paramHandles.mCubemapSamplerSC->getSamplerRegister(pass) != -1 )
|
||||||
GFX->setCubeTexture( paramHandles.mCubemapSamplerSC->getSamplerRegister(pass), NULL );
|
GFX->setTexture( paramHandles.mCubemapSamplerSC->getSamplerRegister(pass), NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterObject::drawUnderwaterFilter( SceneRenderState *state )
|
void WaterObject::drawUnderwaterFilter( SceneRenderState *state )
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ GFXD3D11TextureTarget::GFXD3D11TextureTarget(bool genMips)
|
||||||
mResolveTargets[i] = NULL;
|
mResolveTargets[i] = NULL;
|
||||||
mTargetViews[i] = NULL;
|
mTargetViews[i] = NULL;
|
||||||
mTargetSRViews[i] = NULL;
|
mTargetSRViews[i] = NULL;
|
||||||
|
mTargetArrayIdx[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mGenMips = genMips;
|
mGenMips = genMips;
|
||||||
|
|
@ -57,9 +58,9 @@ GFXD3D11TextureTarget::~GFXD3D11TextureTarget()
|
||||||
zombify();
|
zombify();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *tex, U32 mipLevel/*=0*/, U32 zOffset /*= 0*/ )
|
void GFXD3D11TextureTarget::attachTexture(RenderSlot slot, GFXTextureObject* tex, U32 mipLevel /*= 0*/, U32 zOffset /*= 0*/, U32 faceIndex /*= 0*/)
|
||||||
{
|
{
|
||||||
GFXDEBUGEVENT_SCOPE( GFXPCD3D11TextureTarget_attachTexture, ColorI::RED );
|
GFXDEBUGEVENT_SCOPE(GFXPCD3D11TextureTarget_attachTexture, ColorI::RED);
|
||||||
|
|
||||||
AssertFatal(slot < MaxRenderSlotId, "GFXD3D11TextureTarget::attachTexture - out of range slot.");
|
AssertFatal(slot < MaxRenderSlotId, "GFXD3D11TextureTarget::attachTexture - out of range slot.");
|
||||||
|
|
||||||
|
|
@ -76,17 +77,17 @@ void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *te
|
||||||
SAFE_RELEASE(mTargetViews[slot]);
|
SAFE_RELEASE(mTargetViews[slot]);
|
||||||
SAFE_RELEASE(mTargets[slot]);
|
SAFE_RELEASE(mTargets[slot]);
|
||||||
SAFE_RELEASE(mTargetSRViews[slot]);
|
SAFE_RELEASE(mTargetSRViews[slot]);
|
||||||
|
|
||||||
mResolveTargets[slot] = NULL;
|
mResolveTargets[slot] = NULL;
|
||||||
|
mTargetArrayIdx[slot] = 0;
|
||||||
|
|
||||||
if(slot == Color0)
|
if (slot == Color0)
|
||||||
{
|
{
|
||||||
mTargetSize = Point2I::Zero;
|
mTargetSize = Point2I::Zero;
|
||||||
mTargetFormat = GFXFormatR8G8B8A8;
|
mTargetFormat = GFXFormatR8G8B8A8;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are we clearing?
|
// Are we clearing?
|
||||||
if(!tex)
|
if (!tex)
|
||||||
{
|
{
|
||||||
// Yup - just exit, it'll stay NULL.
|
// Yup - just exit, it'll stay NULL.
|
||||||
return;
|
return;
|
||||||
|
|
@ -96,7 +97,7 @@ void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *te
|
||||||
mTargetSRViews[slot] = NULL;
|
mTargetSRViews[slot] = NULL;
|
||||||
|
|
||||||
// Take care of default targets
|
// Take care of default targets
|
||||||
if( tex == GFXTextureTarget::sDefaultDepthStencil )
|
if (tex == GFXTextureTarget::sDefaultDepthStencil)
|
||||||
{
|
{
|
||||||
mTargets[slot] = D3D11->mDeviceDepthStencil;
|
mTargets[slot] = D3D11->mDeviceDepthStencil;
|
||||||
mTargetViews[slot] = D3D11->mDeviceDepthStencilView;
|
mTargetViews[slot] = D3D11->mDeviceDepthStencilView;
|
||||||
|
|
@ -108,81 +109,100 @@ void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *te
|
||||||
// Cast the texture object to D3D...
|
// Cast the texture object to D3D...
|
||||||
AssertFatal(dynamic_cast<GFXD3D11TextureObject*>(tex), "GFXD3D11TextureTarget::attachTexture - invalid texture object.");
|
AssertFatal(dynamic_cast<GFXD3D11TextureObject*>(tex), "GFXD3D11TextureTarget::attachTexture - invalid texture object.");
|
||||||
|
|
||||||
GFXD3D11TextureObject *d3dto = dynamic_cast<GFXD3D11TextureObject*>(tex);
|
GFXD3D11TextureObject* d3dto = dynamic_cast<GFXD3D11TextureObject*>(tex);
|
||||||
|
bool isCube = d3dto->isCubeMap();
|
||||||
|
|
||||||
// Grab the surface level.
|
// Grab the surface level.
|
||||||
if( slot == DepthStencil )
|
if (slot == DepthStencil)
|
||||||
{
|
{
|
||||||
mTargets[slot] = d3dto->getSurface();
|
mTargets[slot] = d3dto->getSurface();
|
||||||
if ( mTargets[slot] )
|
if (mTargets[slot])
|
||||||
mTargets[slot]->AddRef();
|
mTargets[slot]->AddRef();
|
||||||
|
|
||||||
mTargetViews[slot] = d3dto->getDSView();
|
mTargetViews[slot] = d3dto->getDSView();
|
||||||
if( mTargetViews[slot])
|
if (mTargetViews[slot])
|
||||||
mTargetViews[slot]->AddRef();
|
mTargetViews[slot]->AddRef();
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// getSurface will almost always return NULL. It will only return non-NULL
|
if (!isCube)
|
||||||
// if the surface that it needs to render to is different than the mip level
|
|
||||||
// in the actual texture. This will happen with MSAA.
|
|
||||||
if( d3dto->getSurface() == NULL )
|
|
||||||
{
|
{
|
||||||
|
if (d3dto->getSurface() == NULL)
|
||||||
mTargets[slot] = d3dto->get2DTex();
|
|
||||||
mTargets[slot]->AddRef();
|
|
||||||
mTargetViews[slot] = d3dto->getRTView();
|
|
||||||
mTargetViews[slot]->AddRef();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mTargets[slot] = d3dto->getSurface();
|
|
||||||
mTargets[slot]->AddRef();
|
|
||||||
mTargetViews[slot]->AddRef();
|
|
||||||
mResolveTargets[slot] = d3dto;
|
|
||||||
|
|
||||||
if ( tex && slot == Color0 )
|
|
||||||
{
|
{
|
||||||
mTargetSize.set( tex->getSize().x, tex->getSize().y );
|
mTargets[slot] = d3dto->get2DTex();
|
||||||
mTargetFormat = tex->getFormat();
|
mTargets[slot]->AddRef();
|
||||||
|
mTargetViews[slot] = d3dto->getRTView();
|
||||||
|
mTargetViews[slot]->AddRef();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mTargets[slot] = d3dto->getSurface();
|
||||||
|
mTargets[slot]->AddRef();
|
||||||
|
mTargetViews[slot] = d3dto->getRTView();
|
||||||
|
mTargetViews[slot]->AddRef();
|
||||||
|
mResolveTargets[slot] = d3dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Cubemap render target face
|
||||||
|
mGenMips = false;
|
||||||
|
AssertFatal(faceIndex < 6, "Invalid cubemap face index!");
|
||||||
|
ID3D11RenderTargetView* faceRTV = d3dto->getCubeFaceRTView(faceIndex);
|
||||||
|
AssertFatal(faceRTV, "Cubemap face RTV is null!");
|
||||||
|
|
||||||
|
mTargetArrayIdx[slot] = faceIndex;
|
||||||
|
|
||||||
|
if (d3dto->getSurface() == NULL)
|
||||||
|
{
|
||||||
|
mTargets[slot] = d3dto->get2DTex();
|
||||||
|
mTargets[slot]->AddRef();
|
||||||
|
mTargetViews[slot] = faceRTV;
|
||||||
|
mTargetViews[slot]->AddRef();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mTargets[slot] = d3dto->getSurface();
|
||||||
|
mTargets[slot]->AddRef();
|
||||||
|
mTargetViews[slot] = faceRTV;
|
||||||
|
mTargetViews[slot]->AddRef();
|
||||||
|
mResolveTargets[slot] = d3dto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For mip generation
|
||||||
if (mGenMips)
|
if (mGenMips)
|
||||||
{
|
{
|
||||||
mTargetSRViews[slot] = d3dto->getSRView();
|
mTargetSRViews[slot] = d3dto->getSRView();
|
||||||
mTargetSRViews[slot]->AddRef();
|
if (mTargetSRViews[slot])
|
||||||
|
mTargetSRViews[slot]->AddRef();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update surface size
|
// Update color target info
|
||||||
if(slot == Color0)
|
if (slot == Color0)
|
||||||
{
|
{
|
||||||
ID3D11Texture2D *surface = mTargets[Color0];
|
ID3D11Texture2D* surface = mTargets[Color0];
|
||||||
if ( surface )
|
if (surface)
|
||||||
{
|
{
|
||||||
D3D11_TEXTURE2D_DESC sd;
|
D3D11_TEXTURE2D_DESC sd;
|
||||||
surface->GetDesc(&sd);
|
surface->GetDesc(&sd);
|
||||||
mTargetSize = Point2I(sd.Width, sd.Height);
|
mTargetSize = Point2I(sd.Width, sd.Height);
|
||||||
|
|
||||||
S32 format = sd.Format;
|
S32 format = sd.Format;
|
||||||
|
|
||||||
if (format == DXGI_FORMAT_R8G8B8A8_TYPELESS || format == DXGI_FORMAT_B8G8R8A8_TYPELESS)
|
if (format == DXGI_FORMAT_R8G8B8A8_TYPELESS || format == DXGI_FORMAT_B8G8R8A8_TYPELESS)
|
||||||
{
|
|
||||||
mTargetFormat = GFXFormatR8G8B8A8;
|
mTargetFormat = GFXFormatR8G8B8A8;
|
||||||
return;
|
else
|
||||||
|
{
|
||||||
|
GFXREVERSE_LOOKUP(GFXD3D11TextureFormat, GFXFormat, format);
|
||||||
|
mTargetFormat = (GFXFormat)format;
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXREVERSE_LOOKUP( GFXD3D11TextureFormat, GFXFormat, format );
|
|
||||||
mTargetFormat = (GFXFormat)format;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel/*=0*/ )
|
void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel/*=0*/ )
|
||||||
{
|
{
|
||||||
GFXDEBUGEVENT_SCOPE( GFXPCD3D11TextureTarget_attachTexture_Cubemap, ColorI::RED );
|
GFXDEBUGEVENT_SCOPE( GFXPCD3D11TextureTarget_attachTexture_Cubemap, ColorI::RED );
|
||||||
|
|
@ -316,7 +336,9 @@ void GFXD3D11TextureTarget::resolveTo( GFXTextureObject *tex )
|
||||||
|
|
||||||
D3D11_TEXTURE2D_DESC desc;
|
D3D11_TEXTURE2D_DESC desc;
|
||||||
mTargets[Color0]->GetDesc(&desc);
|
mTargets[Color0]->GetDesc(&desc);
|
||||||
D3D11DEVICECONTEXT->CopySubresourceRegion(((GFXD3D11TextureObject*)(tex))->get2DTex(), 0, 0, 0, 0, mTargets[Color0], 0, NULL);
|
UINT mipLevels = desc.MipLevels ? desc.MipLevels : 1;
|
||||||
|
UINT subResource = D3D11CalcSubresource(0, mTargetArrayIdx[Color0], mipLevels);
|
||||||
|
D3D11DEVICECONTEXT->CopySubresourceRegion(((GFXD3D11TextureObject*)(tex))->get2DTex(), 0, 0, 0, 0, mTargets[Color0], subResource, NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,8 @@ class GFXD3D11TextureTarget : public GFXTextureTarget
|
||||||
|
|
||||||
GFXFormat mTargetFormat;
|
GFXFormat mTargetFormat;
|
||||||
|
|
||||||
|
U32 mTargetArrayIdx[MaxRenderSlotId];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GFXD3D11TextureTarget(bool genMips);
|
GFXD3D11TextureTarget(bool genMips);
|
||||||
|
|
@ -57,7 +59,7 @@ public:
|
||||||
// Public interface.
|
// Public interface.
|
||||||
const Point2I getSize() override { return mTargetSize; }
|
const Point2I getSize() override { return mTargetSize; }
|
||||||
GFXFormat getFormat() override { return mTargetFormat; }
|
GFXFormat getFormat() override { return mTargetFormat; }
|
||||||
void attachTexture(RenderSlot slot, GFXTextureObject *tex, U32 mipLevel=0, U32 zOffset = 0) override;
|
void attachTexture(RenderSlot slot, GFXTextureObject* tex, U32 mipLevel = 0, U32 zOffset = 0, U32 faceIndex = 0) override;
|
||||||
void attachTexture(RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel=0) override;
|
void attachTexture(RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel=0) override;
|
||||||
void resolve() override;
|
void resolve() override;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,8 @@ void GFXD3D11TextureManager::_innerCreateTexture( GFXD3D11TextureObject *retTex,
|
||||||
GFXTextureProfile *profile,
|
GFXTextureProfile *profile,
|
||||||
U32 numMipLevels,
|
U32 numMipLevels,
|
||||||
bool forceMips,
|
bool forceMips,
|
||||||
S32 antialiasLevel)
|
S32 antialiasLevel,
|
||||||
|
U32 arraySize)
|
||||||
{
|
{
|
||||||
U32 usage = 0;
|
U32 usage = 0;
|
||||||
U32 bindFlags = 0;
|
U32 bindFlags = 0;
|
||||||
|
|
@ -67,6 +68,9 @@ void GFXD3D11TextureManager::_innerCreateTexture( GFXD3D11TextureObject *retTex,
|
||||||
retTex->isManaged = false;
|
retTex->isManaged = false;
|
||||||
DXGI_FORMAT d3dTextureFormat = GFXD3D11TextureFormat[format];
|
DXGI_FORMAT d3dTextureFormat = GFXD3D11TextureFormat[format];
|
||||||
|
|
||||||
|
if (retTex->isCubeMap())
|
||||||
|
miscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
|
||||||
|
|
||||||
if( retTex->mProfile->isDynamic() )
|
if( retTex->mProfile->isDynamic() )
|
||||||
{
|
{
|
||||||
usage = D3D11_USAGE_DYNAMIC;
|
usage = D3D11_USAGE_DYNAMIC;
|
||||||
|
|
@ -199,7 +203,7 @@ void GFXD3D11TextureManager::_innerCreateTexture( GFXD3D11TextureObject *retTex,
|
||||||
D3D11_TEXTURE2D_DESC desc;
|
D3D11_TEXTURE2D_DESC desc;
|
||||||
|
|
||||||
ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
|
ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
|
||||||
desc.ArraySize = 1;
|
desc.ArraySize = arraySize * (retTex->isCubeMap() ? 6 : 1);
|
||||||
desc.BindFlags = bindFlags;
|
desc.BindFlags = bindFlags;
|
||||||
desc.CPUAccessFlags = cpuFlags;
|
desc.CPUAccessFlags = cpuFlags;
|
||||||
desc.Format = d3dTextureFormat;
|
desc.Format = d3dTextureFormat;
|
||||||
|
|
@ -219,6 +223,7 @@ void GFXD3D11TextureManager::_innerCreateTexture( GFXD3D11TextureObject *retTex,
|
||||||
|
|
||||||
retTex->get2DTex()->GetDesc(&desc);
|
retTex->get2DTex()->GetDesc(&desc);
|
||||||
retTex->mMipLevels = desc.MipLevels;
|
retTex->mMipLevels = desc.MipLevels;
|
||||||
|
retTex->mArraySize = arraySize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// start creating the resource views...
|
// start creating the resource views...
|
||||||
|
|
@ -267,6 +272,7 @@ GFXTextureObject *GFXD3D11TextureManager::_createTextureObject( U32 height,
|
||||||
U32 numMipLevels,
|
U32 numMipLevels,
|
||||||
bool forceMips,
|
bool forceMips,
|
||||||
S32 antialiasLevel,
|
S32 antialiasLevel,
|
||||||
|
U32 arraySize,
|
||||||
GFXTextureObject *inTex )
|
GFXTextureObject *inTex )
|
||||||
{
|
{
|
||||||
GFXD3D11TextureObject *retTex;
|
GFXD3D11TextureObject *retTex;
|
||||||
|
|
@ -278,11 +284,11 @@ GFXTextureObject *GFXD3D11TextureManager::_createTextureObject( U32 height,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
retTex = new GFXD3D11TextureObject(GFX, profile);
|
retTex = new GFXD3D11TextureObject(GFX, profile, arraySize);
|
||||||
retTex->registerResourceWithDevice(GFX);
|
retTex->registerResourceWithDevice(GFX);
|
||||||
}
|
}
|
||||||
|
|
||||||
_innerCreateTexture(retTex, height, width, depth, format, profile, numMipLevels, forceMips, antialiasLevel);
|
_innerCreateTexture(retTex, height, width, depth, format, profile, numMipLevels, forceMips, antialiasLevel, arraySize);
|
||||||
|
|
||||||
return retTex;
|
return retTex;
|
||||||
}
|
}
|
||||||
|
|
@ -295,7 +301,9 @@ bool GFXD3D11TextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *p
|
||||||
|
|
||||||
// Check with profiler to see if we can do automatic mipmap generation.
|
// Check with profiler to see if we can do automatic mipmap generation.
|
||||||
const bool supportsAutoMips = GFX->getCardProfiler()->queryProfile("autoMipMapLevel", true);
|
const bool supportsAutoMips = GFX->getCardProfiler()->queryProfile("autoMipMapLevel", true);
|
||||||
|
|
||||||
|
const bool isCube = texture->isCubeMap() && pDL->getNumFaces() > 1;
|
||||||
|
const U32 numFaces = isCube ? 6 : 1;
|
||||||
// Helper bool
|
// Helper bool
|
||||||
const bool isCompressedTexFmt = ImageUtil::isCompressedFormat(aTexture->mFormat);
|
const bool isCompressedTexFmt = ImageUtil::isCompressedFormat(aTexture->mFormat);
|
||||||
|
|
||||||
|
|
@ -312,98 +320,101 @@ bool GFXD3D11TextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *p
|
||||||
|
|
||||||
bool isDynamic = texture->mProfile->isDynamic();
|
bool isDynamic = texture->mProfile->isDynamic();
|
||||||
// Fill the texture...
|
// Fill the texture...
|
||||||
for( U32 i = 0; i < maxDownloadMip; i++ )
|
for (U32 face = 0; face < numFaces; ++face)
|
||||||
{
|
{
|
||||||
U32 subResource = D3D11CalcSubresource(i, 0, aTexture->mMipLevels);
|
for (U32 i = 0; i < maxDownloadMip; i++)
|
||||||
|
{
|
||||||
|
U32 subResource = D3D11CalcSubresource(i, face, aTexture->mMipLevels);
|
||||||
|
|
||||||
if(!isDynamic)
|
if (!isDynamic)
|
||||||
{
|
{
|
||||||
U8* copyBuffer = NULL;
|
U8* copyBuffer = NULL;
|
||||||
|
|
||||||
switch(texture->mFormat)
|
switch (texture->mFormat)
|
||||||
{
|
{
|
||||||
case GFXFormatR8G8B8:
|
case GFXFormatR8G8B8:
|
||||||
case GFXFormatR8G8B8_SRGB:
|
case GFXFormatR8G8B8_SRGB:
|
||||||
{
|
{
|
||||||
PROFILE_SCOPE(Swizzle24_Upload);
|
PROFILE_SCOPE(Swizzle24_Upload);
|
||||||
|
|
||||||
U8* Bits = new U8[pDL->getWidth(i) * pDL->getHeight(i) * 4];
|
U8* Bits = new U8[pDL->getWidth(i) * pDL->getHeight(i) * 4];
|
||||||
dMemcpy(Bits, pDL->getBits(i), pDL->getWidth(i) * pDL->getHeight(i) * 3);
|
dMemcpy(Bits, pDL->getBits(i, face), pDL->getWidth(i) * pDL->getHeight(i) * 3);
|
||||||
bitmapConvertRGB_to_RGBX(&Bits, pDL->getWidth(i) * pDL->getHeight(i));
|
bitmapConvertRGB_to_RGBX(&Bits, pDL->getWidth(i) * pDL->getHeight(i));
|
||||||
copyBuffer = new U8[pDL->getWidth(i) * pDL->getHeight(i) * 4];
|
copyBuffer = new U8[pDL->getWidth(i) * pDL->getHeight(i) * 4];
|
||||||
|
|
||||||
dev->getDeviceSwizzle32()->ToBuffer(copyBuffer, Bits, pDL->getWidth(i) * pDL->getHeight(i) * 4);
|
dev->getDeviceSwizzle32()->ToBuffer(copyBuffer, Bits, pDL->getWidth(i) * pDL->getHeight(i) * 4);
|
||||||
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subResource, NULL, copyBuffer, pDL->getWidth() * 4, pDL->getHeight() *4);
|
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subResource, NULL, copyBuffer, pDL->getWidth() * 4, pDL->getHeight() * 4);
|
||||||
SAFE_DELETE_ARRAY(Bits);
|
SAFE_DELETE_ARRAY(Bits);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case GFXFormatR8G8B8A8:
|
|
||||||
case GFXFormatR8G8B8X8:
|
|
||||||
case GFXFormatR8G8B8A8_SRGB:
|
|
||||||
{
|
|
||||||
PROFILE_SCOPE(Swizzle32_Upload);
|
|
||||||
copyBuffer = new U8[pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel()];
|
|
||||||
dev->getDeviceSwizzle32()->ToBuffer(copyBuffer, pDL->getBits(i), pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel());
|
|
||||||
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subResource, NULL, copyBuffer, pDL->getWidth() * pDL->getBytesPerPixel(), pDL->getHeight() *pDL->getBytesPerPixel());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
// Just copy the bits in no swizzle or padding
|
|
||||||
PROFILE_SCOPE(SwizzleNull_Upload);
|
|
||||||
AssertFatal( pDL->getFormat() == texture->mFormat, "Format mismatch");
|
|
||||||
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subResource, NULL, pDL->getBits(i), pDL->getWidth() *pDL->getBytesPerPixel(), pDL->getHeight() *pDL->getBytesPerPixel());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SAFE_DELETE_ARRAY(copyBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
D3D11_MAPPED_SUBRESOURCE mapping;
|
|
||||||
HRESULT res = dev->getDeviceContext()->Map(texture->get2DTex(), subResource, D3D11_MAP_WRITE, 0, &mapping);
|
|
||||||
|
|
||||||
AssertFatal(res, "tex2d map call failure");
|
|
||||||
|
|
||||||
switch( texture->mFormat )
|
|
||||||
{
|
|
||||||
case GFXFormatR8G8B8:
|
|
||||||
case GFXFormatR8G8B8_SRGB:
|
|
||||||
{
|
|
||||||
PROFILE_SCOPE(Swizzle24_Upload);
|
|
||||||
|
|
||||||
U8* Bits = new U8[pDL->getWidth(i) * pDL->getHeight(i) * 4];
|
|
||||||
dMemcpy(Bits, pDL->getBits(i), pDL->getWidth(i) * pDL->getHeight(i) * 3);
|
|
||||||
bitmapConvertRGB_to_RGBX(&Bits, pDL->getWidth(i) * pDL->getHeight(i));
|
|
||||||
|
|
||||||
dev->getDeviceSwizzle32()->ToBuffer(mapping.pData, Bits, pDL->getWidth(i) * pDL->getHeight(i) * 4);
|
|
||||||
SAFE_DELETE_ARRAY(Bits);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GFXFormatR8G8B8A8:
|
case GFXFormatR8G8B8A8:
|
||||||
case GFXFormatR8G8B8X8:
|
case GFXFormatR8G8B8X8:
|
||||||
case GFXFormatR8G8B8A8_SRGB:
|
case GFXFormatR8G8B8A8_SRGB:
|
||||||
{
|
{
|
||||||
PROFILE_SCOPE(Swizzle32_Upload);
|
PROFILE_SCOPE(Swizzle32_Upload);
|
||||||
dev->getDeviceSwizzle32()->ToBuffer(mapping.pData, pDL->getBits(i), pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel());
|
copyBuffer = new U8[pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel()];
|
||||||
|
dev->getDeviceSwizzle32()->ToBuffer(copyBuffer, pDL->getBits(i, face), pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel());
|
||||||
|
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subResource, NULL, copyBuffer, pDL->getWidth() * pDL->getBytesPerPixel(), pDL->getHeight() * pDL->getBytesPerPixel());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Just copy the bits in no swizzle or padding
|
// Just copy the bits in no swizzle or padding
|
||||||
PROFILE_SCOPE(SwizzleNull_Upload);
|
PROFILE_SCOPE(SwizzleNull_Upload);
|
||||||
AssertFatal( pDL->getFormat() == texture->mFormat, "Format mismatch");
|
AssertFatal(pDL->getFormat() == texture->mFormat, "Format mismatch");
|
||||||
dMemcpy(mapping.pData, pDL->getBits(i), pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel());
|
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subResource, NULL, pDL->getBits(i, face), pDL->getWidth() * pDL->getBytesPerPixel(), pDL->getHeight() * pDL->getBytesPerPixel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->getDeviceContext()->Unmap(texture->get2DTex(), subResource);
|
SAFE_DELETE_ARRAY(copyBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
D3D11_MAPPED_SUBRESOURCE mapping;
|
||||||
|
HRESULT res = dev->getDeviceContext()->Map(texture->get2DTex(), subResource, D3D11_MAP_WRITE, 0, &mapping);
|
||||||
|
|
||||||
|
AssertFatal(res, "tex2d map call failure");
|
||||||
|
|
||||||
|
switch (texture->mFormat)
|
||||||
|
{
|
||||||
|
case GFXFormatR8G8B8:
|
||||||
|
case GFXFormatR8G8B8_SRGB:
|
||||||
|
{
|
||||||
|
PROFILE_SCOPE(Swizzle24_Upload);
|
||||||
|
|
||||||
|
U8* Bits = new U8[pDL->getWidth(i) * pDL->getHeight(i) * 4];
|
||||||
|
dMemcpy(Bits, pDL->getBits(i, face), pDL->getWidth(i) * pDL->getHeight(i) * 3);
|
||||||
|
bitmapConvertRGB_to_RGBX(&Bits, pDL->getWidth(i) * pDL->getHeight(i));
|
||||||
|
|
||||||
|
dev->getDeviceSwizzle32()->ToBuffer(mapping.pData, Bits, pDL->getWidth(i) * pDL->getHeight(i) * 4);
|
||||||
|
SAFE_DELETE_ARRAY(Bits);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GFXFormatR8G8B8A8:
|
||||||
|
case GFXFormatR8G8B8X8:
|
||||||
|
case GFXFormatR8G8B8A8_SRGB:
|
||||||
|
{
|
||||||
|
PROFILE_SCOPE(Swizzle32_Upload);
|
||||||
|
dev->getDeviceSwizzle32()->ToBuffer(mapping.pData, pDL->getBits(i, face), pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Just copy the bits in no swizzle or padding
|
||||||
|
PROFILE_SCOPE(SwizzleNull_Upload);
|
||||||
|
AssertFatal(pDL->getFormat() == texture->mFormat, "Format mismatch");
|
||||||
|
dMemcpy(mapping.pData, pDL->getBits(i, face), pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->getDeviceContext()->Unmap(texture->get2DTex(), subResource);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D11_TEXTURE2D_DESC desc;
|
D3D11_TEXTURE2D_DESC desc;
|
||||||
|
|
@ -487,7 +498,7 @@ bool GFXD3D11TextureManager::_refreshTexture(GFXTextureObject *texture)
|
||||||
if(texture->mProfile->isRenderTarget() || texture->mProfile->isDynamic() || texture->mProfile->isZTarget())
|
if(texture->mProfile->isRenderTarget() || texture->mProfile->isDynamic() || texture->mProfile->isZTarget())
|
||||||
{
|
{
|
||||||
realTex->release();
|
realTex->release();
|
||||||
_innerCreateTexture(realTex, texture->getHeight(), texture->getWidth(), texture->getDepth(), texture->mFormat, texture->mProfile, texture->mMipLevels, false, texture->mAntialiasLevel);
|
_innerCreateTexture(realTex, texture->getHeight(), texture->getWidth(), texture->getDepth(), texture->mFormat, texture->mProfile, texture->mMipLevels, false, texture->mAntialiasLevel, texture->mArraySize);
|
||||||
usedStrategies++;
|
usedStrategies++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -519,14 +530,31 @@ bool GFXD3D11TextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *d
|
||||||
GFXD3D11TextureObject *texture = static_cast<GFXD3D11TextureObject*>(aTexture);
|
GFXD3D11TextureObject *texture = static_cast<GFXD3D11TextureObject*>(aTexture);
|
||||||
GFXD3D11Device* dev = static_cast<GFXD3D11Device *>(GFX);
|
GFXD3D11Device* dev = static_cast<GFXD3D11Device *>(GFX);
|
||||||
// Fill the texture...
|
// Fill the texture...
|
||||||
for( U32 i = 0; i < aTexture->mMipLevels; i++ )
|
const bool isCube = texture->isCubeMap() && dds->isCubemap();
|
||||||
|
const U32 numFaces = isCube ? 6 : 1;
|
||||||
|
|
||||||
|
// Loop over faces and mips
|
||||||
|
for (U32 face = 0; face < numFaces; ++face)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPE(GFXD3DTexMan_loadSurface);
|
for (U32 mip = 0; mip < aTexture->mMipLevels; ++mip)
|
||||||
|
{
|
||||||
|
PROFILE_SCOPE(GFXD3DTexMan_loadSurface);
|
||||||
|
|
||||||
AssertFatal( dds->mSurfaces.size() > 0, "Assumption failed. DDSFile has no surfaces." );
|
// DDSFile must have data for each face
|
||||||
|
AssertFatal(dds->mSurfaces.size() > face, "DDSFile missing cubemap face data.");
|
||||||
|
AssertFatal(dds->mSurfaces[face]->mMips.size() > mip, "DDSFile missing mip level.");
|
||||||
|
|
||||||
U32 subresource = D3D11CalcSubresource(i, 0, aTexture->mMipLevels);
|
const U32 subresource = D3D11CalcSubresource(mip, face, aTexture->mMipLevels);
|
||||||
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subresource, 0, dds->mSurfaces[0]->mMips[i], dds->getSurfacePitch(i), 0);
|
|
||||||
|
dev->getDeviceContext()->UpdateSubresource(
|
||||||
|
texture->get2DTex(), // resource
|
||||||
|
subresource, // subresource index
|
||||||
|
nullptr, // box (nullptr for full subresource)
|
||||||
|
dds->mSurfaces[face]->mMips[mip], // source data pointer
|
||||||
|
dds->getSurfacePitch(mip), // row pitch
|
||||||
|
0 // depth pitch
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D11_TEXTURE2D_DESC desc;
|
D3D11_TEXTURE2D_DESC desc;
|
||||||
|
|
@ -541,14 +569,14 @@ bool GFXD3D11TextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *d
|
||||||
void GFXD3D11TextureManager::createResourceView(U32 height, U32 width, U32 depth, DXGI_FORMAT format, U32 numMipLevels,U32 usageFlags, GFXTextureObject *inTex)
|
void GFXD3D11TextureManager::createResourceView(U32 height, U32 width, U32 depth, DXGI_FORMAT format, U32 numMipLevels,U32 usageFlags, GFXTextureObject *inTex)
|
||||||
{
|
{
|
||||||
GFXD3D11TextureObject *tex = static_cast<GFXD3D11TextureObject*>(inTex);
|
GFXD3D11TextureObject *tex = static_cast<GFXD3D11TextureObject*>(inTex);
|
||||||
ID3D11Resource* resource = NULL;
|
ID3D11Resource* resource;
|
||||||
|
|
||||||
if(tex->get2DTex())
|
if (tex->get2DTex())
|
||||||
resource = tex->get2DTex();
|
resource = tex->get2DTex();
|
||||||
else if(tex->getSurface())
|
else if (tex->getSurface())
|
||||||
resource = tex->getSurface();
|
resource = tex->getSurface();
|
||||||
else
|
else
|
||||||
resource = tex->get3DTex();
|
resource = tex->get3DTex();
|
||||||
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
//TODO: add MSAA support later.
|
//TODO: add MSAA support later.
|
||||||
|
|
@ -567,11 +595,40 @@ void GFXD3D11TextureManager::createResourceView(U32 height, U32 width, U32 depth
|
||||||
desc.Texture3D.MipLevels = -1;
|
desc.Texture3D.MipLevels = -1;
|
||||||
desc.Texture3D.MostDetailedMip = 0;
|
desc.Texture3D.MostDetailedMip = 0;
|
||||||
}
|
}
|
||||||
else
|
else if (tex->isCubeMap())
|
||||||
|
{
|
||||||
|
if (tex->getArraySize() == 1)
|
||||||
|
{
|
||||||
|
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
|
||||||
|
desc.TextureCube.MipLevels = -1;
|
||||||
|
desc.TextureCube.MostDetailedMip = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
|
||||||
|
desc.TextureCubeArray.MostDetailedMip = 0;
|
||||||
|
desc.TextureCubeArray.MipLevels = -1;
|
||||||
|
desc.TextureCubeArray.First2DArrayFace = 0;
|
||||||
|
desc.TextureCubeArray.NumCubes = tex->getArraySize();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
if (tex->getArraySize() == 1)
|
||||||
desc.Texture2D.MipLevels = -1;
|
{
|
||||||
desc.Texture2D.MostDetailedMip = 0;
|
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||||
|
desc.Texture2D.MipLevels = -1;
|
||||||
|
desc.Texture2D.MostDetailedMip = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
|
||||||
|
desc.Texture2DArray.MipLevels = -1;
|
||||||
|
desc.Texture2DArray.MostDetailedMip = 0;
|
||||||
|
desc.Texture2DArray.FirstArraySlice = 0;
|
||||||
|
desc.Texture2DArray.ArraySize = tex->getArraySize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = D3D11DEVICE->CreateShaderResourceView(resource,&desc, tex->getSRViewPtr());
|
hr = D3D11DEVICE->CreateShaderResourceView(resource,&desc, tex->getSRViewPtr());
|
||||||
|
|
@ -580,12 +637,29 @@ void GFXD3D11TextureManager::createResourceView(U32 height, U32 width, U32 depth
|
||||||
|
|
||||||
if(usageFlags & D3D11_BIND_RENDER_TARGET)
|
if(usageFlags & D3D11_BIND_RENDER_TARGET)
|
||||||
{
|
{
|
||||||
D3D11_RENDER_TARGET_VIEW_DESC desc;
|
if (tex->isCubeMap())
|
||||||
desc.Format = format;
|
{
|
||||||
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
for (U32 face = 0; face < 6; face++)
|
||||||
desc.Texture2D.MipSlice = 0;
|
{
|
||||||
hr = D3D11DEVICE->CreateRenderTargetView(resource, &desc, tex->getRTViewPtr());
|
D3D11_RENDER_TARGET_VIEW_DESC desc;
|
||||||
AssertFatal(SUCCEEDED(hr), "CreateRenderTargetView:: failed to create view!");
|
desc.Format = format;
|
||||||
|
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||||
|
desc.Texture2DArray.ArraySize = 1;
|
||||||
|
desc.Texture2DArray.FirstArraySlice = face;
|
||||||
|
desc.Texture2DArray.MipSlice = 0;
|
||||||
|
hr = D3D11DEVICE->CreateRenderTargetView(resource, &desc, tex->getCubeFaceRTViewPtr(face));
|
||||||
|
AssertFatal(SUCCEEDED(hr), "CreateRenderTargetView:: failed to create view!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
D3D11_RENDER_TARGET_VIEW_DESC desc;
|
||||||
|
desc.Format = format;
|
||||||
|
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||||
|
desc.Texture2D.MipSlice = 0;
|
||||||
|
hr = D3D11DEVICE->CreateRenderTargetView(resource, &desc, tex->getRTViewPtr());
|
||||||
|
AssertFatal(SUCCEEDED(hr), "CreateRenderTargetView:: failed to create view!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(usageFlags & D3D11_BIND_DEPTH_STENCIL)
|
if(usageFlags & D3D11_BIND_DEPTH_STENCIL)
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ protected:
|
||||||
U32 numMipLevels,
|
U32 numMipLevels,
|
||||||
bool forceMips = false,
|
bool forceMips = false,
|
||||||
S32 antialiasLevel = 0,
|
S32 antialiasLevel = 0,
|
||||||
|
U32 arraySize = 1,
|
||||||
GFXTextureObject *inTex = NULL ) override;
|
GFXTextureObject *inTex = NULL ) override;
|
||||||
|
|
||||||
bool _loadTexture(GFXTextureObject *texture, DDSFile *dds) override;
|
bool _loadTexture(GFXTextureObject *texture, DDSFile *dds) override;
|
||||||
|
|
@ -56,7 +57,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
U32 mCurTexSet[GFX_TEXTURE_STAGE_COUNT];
|
U32 mCurTexSet[GFX_TEXTURE_STAGE_COUNT];
|
||||||
|
|
||||||
void _innerCreateTexture(GFXD3D11TextureObject *obj, U32 height, U32 width, U32 depth, GFXFormat format, GFXTextureProfile *profile, U32 numMipLevels, bool forceMips = false, S32 antialiasLevel = 0);
|
void _innerCreateTexture(GFXD3D11TextureObject *obj, U32 height, U32 width, U32 depth, GFXFormat format, GFXTextureProfile *profile, U32 numMipLevels, bool forceMips = false, S32 antialiasLevel = 0, U32 arraySize = 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -33,26 +33,16 @@ U32 GFXD3D11TextureObject::mTexCount = 0;
|
||||||
// GFXFormatR8G8B8 has now the same behaviour as GFXFormatR8G8B8X8.
|
// GFXFormatR8G8B8 has now the same behaviour as GFXFormatR8G8B8X8.
|
||||||
// This is because 24 bit format are now deprecated by microsoft, for data alignment reason there's no changes beetween 24 and 32 bit formats.
|
// This is because 24 bit format are now deprecated by microsoft, for data alignment reason there's no changes beetween 24 and 32 bit formats.
|
||||||
// DirectX 10-11 both have 24 bit format no longer.
|
// DirectX 10-11 both have 24 bit format no longer.
|
||||||
|
GFXD3D11TextureObject::GFXD3D11TextureObject( GFXDevice * d, GFXTextureProfile *profile, const U32 arraySize) : GFXTextureObject( d, profile )
|
||||||
|
|
||||||
GFXD3D11TextureObject::GFXD3D11TextureObject( GFXDevice * d, GFXTextureProfile *profile) : GFXTextureObject( d, profile )
|
|
||||||
{
|
{
|
||||||
#ifdef D3D11_DEBUG_SPEW
|
#ifdef D3D11_DEBUG_SPEW
|
||||||
mTexCount++;
|
mTexCount++;
|
||||||
Con::printf("+ texMake %d %x", mTexCount, this);
|
Con::printf("+ texMake %d %x", mTexCount, this);
|
||||||
#endif
|
#endif
|
||||||
|
isManaged = false;
|
||||||
mD3DTexture = NULL;
|
|
||||||
mLocked = false;
|
|
||||||
|
|
||||||
mD3DSurface = NULL;
|
|
||||||
dMemset(&mLockRect, 0, sizeof(mLockRect));
|
dMemset(&mLockRect, 0, sizeof(mLockRect));
|
||||||
dMemset(&mLockBox, 0, sizeof(mLockBox));
|
dMemset(&mLockBox, 0, sizeof(mLockBox));
|
||||||
mLockedSubresource = 0;
|
mArraySize = arraySize;
|
||||||
mDSView = NULL;
|
|
||||||
mRTView = NULL;
|
|
||||||
mSRView = NULL;
|
|
||||||
isManaged = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXD3D11TextureObject::~GFXD3D11TextureObject()
|
GFXD3D11TextureObject::~GFXD3D11TextureObject()
|
||||||
|
|
@ -64,53 +54,76 @@ GFXD3D11TextureObject::~GFXD3D11TextureObject()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXLockedRect *GFXD3D11TextureObject::lock(U32 mipLevel /*= 0*/, RectI *inRect /*= NULL*/)
|
ID3D11Texture2D* GFXD3D11TextureObject::get2DTex() const
|
||||||
{
|
{
|
||||||
AssertFatal( !mLocked, "GFXD3D11TextureObject::lock - The texture is already locked!" );
|
ComPtr<ID3D11Texture2D> tex2D;
|
||||||
|
if (mD3DTexture) mD3DTexture.As(&tex2D);
|
||||||
|
return tex2D.Get();
|
||||||
|
}
|
||||||
|
|
||||||
if( !mStagingTex ||
|
ID3D11Texture3D* GFXD3D11TextureObject::get3DTex() const
|
||||||
|
{
|
||||||
|
ComPtr<ID3D11Texture3D> tex3D;
|
||||||
|
if (mD3DTexture) mD3DTexture.As(&tex3D);
|
||||||
|
return tex3D.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D11Texture2D** GFXD3D11TextureObject::get2DTexPtr()
|
||||||
|
{
|
||||||
|
return reinterpret_cast<ID3D11Texture2D**>(mD3DTexture.GetAddressOf());
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D11Texture3D** GFXD3D11TextureObject::get3DTexPtr()
|
||||||
|
{
|
||||||
|
return reinterpret_cast<ID3D11Texture3D**>(mD3DTexture.GetAddressOf());
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D11RenderTargetView** GFXD3D11TextureObject::getCubeFaceRTViewPtr(U32 face)
|
||||||
|
{
|
||||||
|
AssertFatal(isCubeMap(), "Not a cubemap texture!");
|
||||||
|
AssertFatal(face < 6, "Invalid cubemap face index!");
|
||||||
|
return mCubeRTV[face].GetAddressOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
GFXLockedRect* GFXD3D11TextureObject::lock(U32 mipLevel /*= 0*/, RectI* inRect /*= NULL*/, U32 faceIndex /*= 0*/)
|
||||||
|
{
|
||||||
|
AssertFatal(!mLocked, "GFXD3D11TextureObject::lock - Texture is already locked!");
|
||||||
|
AssertFatal(faceIndex < 6 || !isCubeMap(), "Invalid cubemap face index!");
|
||||||
|
|
||||||
|
// Ensure staging texture exists and matches size
|
||||||
|
if (!mStagingTex.isValid() ||
|
||||||
mStagingTex->getWidth() != getWidth() ||
|
mStagingTex->getWidth() != getWidth() ||
|
||||||
mStagingTex->getHeight() != getHeight() ||
|
mStagingTex->getHeight() != getHeight() ||
|
||||||
mStagingTex->getDepth() != getDepth())
|
mStagingTex->getDepth() != getDepth())
|
||||||
{
|
{
|
||||||
if (getDepth() != 0)
|
mStagingTex.set(getWidth(), getHeight(), mFormat, &GFXSystemMemTextureProfile,
|
||||||
{
|
avar("%s() - stagingTex", __FUNCTION__));
|
||||||
mStagingTex.set(getWidth(), getHeight(), getDepth(), mFormat, &GFXSystemMemTextureProfile, avar("%s() - mLockTex (line %d)", __FUNCTION__, __LINE__, 0));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mStagingTex.set(getWidth(), getHeight(), mFormat, &GFXSystemMemTextureProfile, avar("%s() - mLockTex (line %d)", __FUNCTION__, __LINE__));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ID3D11DeviceContext* pContext = D3D11DEVICECONTEXT;
|
|
||||||
D3D11_MAPPED_SUBRESOURCE mapInfo;
|
D3D11_MAPPED_SUBRESOURCE mapInfo;
|
||||||
U32 offset = 0;
|
|
||||||
mLockedSubresource = D3D11CalcSubresource(mipLevel, 0, getMipLevels());
|
|
||||||
GFXD3D11TextureObject* pD3DStagingTex = (GFXD3D11TextureObject*)&(*mStagingTex);
|
|
||||||
|
|
||||||
//map staging texture
|
mLockedSubresource = D3D11CalcSubresource(mipLevel, faceIndex, getMipLevels());
|
||||||
HRESULT hr = pContext->Map(pD3DStagingTex->getResource(), mLockedSubresource, D3D11_MAP_WRITE, 0, &mapInfo);
|
GFXD3D11TextureObject* staging = (GFXD3D11TextureObject*)&(*mStagingTex);
|
||||||
|
|
||||||
|
HRESULT hr = D3D11DEVICECONTEXT->Map(staging->getResource(), mLockedSubresource, D3D11_MAP_WRITE, 0, &mapInfo);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
AssertFatal(false, "GFXD3D11TextureObject:lock - failed to map render target resource!");
|
AssertFatal(false, "GFXD3D11TextureObject:lock - failed to map render target resource!");
|
||||||
|
|
||||||
|
|
||||||
const bool is3D = mStagingTex->getDepth() != 0;
|
const bool is3D = mStagingTex->getDepth() != 0;
|
||||||
const U32 width = mTextureSize.x >> mipLevel;
|
const U32 width = mTextureSize.x >> mipLevel;
|
||||||
const U32 height = mTextureSize.y >> mipLevel;
|
const U32 height = mTextureSize.y >> mipLevel;
|
||||||
const U32 depth = is3D ? mTextureSize.z >> mipLevel : 1;
|
const U32 depth = is3D ? mTextureSize.z >> mipLevel : 1;
|
||||||
|
U32 offset = 0;
|
||||||
|
|
||||||
//calculate locked box region and offset
|
|
||||||
if (inRect)
|
if (inRect)
|
||||||
{
|
{
|
||||||
if ((inRect->point.x + inRect->extent.x > width) || (inRect->point.y + inRect->extent.y > height))
|
AssertFatal(inRect->point.x + inRect->extent.x <= width, "GFXD3D11TextureObject::lock - Invalid lock rect width!");
|
||||||
AssertFatal(false, "GFXD3D11TextureObject::lock - Rectangle too big!");
|
AssertFatal(inRect->point.y + inRect->extent.y <= height, "GFXD3D11TextureObject::lock - Invalid lock rect height!");
|
||||||
|
|
||||||
mLockBox.top = inRect->point.y;
|
mLockBox.top = inRect->point.y;
|
||||||
mLockBox.left = inRect->point.x;
|
mLockBox.left = inRect->point.x;
|
||||||
mLockBox.bottom = inRect->point.y + inRect->extent.y;
|
|
||||||
mLockBox.right = inRect->point.x + inRect->extent.x;
|
mLockBox.right = inRect->point.x + inRect->extent.x;
|
||||||
|
mLockBox.bottom = inRect->point.y + inRect->extent.y;
|
||||||
mLockBox.back = depth;
|
mLockBox.back = depth;
|
||||||
mLockBox.front = 0;
|
mLockBox.front = 0;
|
||||||
|
|
||||||
|
|
@ -121,49 +134,57 @@ GFXLockedRect *GFXD3D11TextureObject::lock(U32 mipLevel /*= 0*/, RectI *inRect /
|
||||||
{
|
{
|
||||||
mLockBox.top = 0;
|
mLockBox.top = 0;
|
||||||
mLockBox.left = 0;
|
mLockBox.left = 0;
|
||||||
mLockBox.bottom = height;
|
|
||||||
mLockBox.right = width;
|
mLockBox.right = width;
|
||||||
|
mLockBox.bottom = height;
|
||||||
mLockBox.back = depth;
|
mLockBox.back = depth;
|
||||||
mLockBox.front = 0;
|
mLockBox.front = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mLocked = true;
|
mLocked = true;
|
||||||
mLockRect.pBits = static_cast<U8*>(mapInfo.pData) + offset;
|
mLockRect.pBits = static_cast<U8*>(mapInfo.pData) + offset;
|
||||||
mLockRect.Pitch = mapInfo.RowPitch;
|
mLockRect.Pitch = mapInfo.RowPitch;
|
||||||
|
|
||||||
return (GFXLockedRect*)&mLockRect;
|
return reinterpret_cast<GFXLockedRect*>(&mLockRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXD3D11TextureObject::unlock(U32 mipLevel)
|
void GFXD3D11TextureObject::unlock(U32 mipLevel /*= 0*/, U32 faceIndex /*= 0*/)
|
||||||
{
|
{
|
||||||
AssertFatal( mLocked, "GFXD3D11TextureObject::unlock - Attempting to unlock a surface that has not been locked" );
|
AssertFatal(mLocked, "GFXD3D11TextureObject::unlock - Texture is not locked!");
|
||||||
|
AssertFatal(faceIndex < 6 || !isCubeMap(), "Invalid cubemap face index!");
|
||||||
|
|
||||||
//profile in the unlock function because all the heavy lifting is done here
|
PROFILE_START(GFXD3D11TextureObject_unlock);
|
||||||
PROFILE_START(GFXD3D11TextureObject_lockRT);
|
|
||||||
|
|
||||||
ID3D11DeviceContext* pContext = D3D11DEVICECONTEXT;
|
GFXD3D11TextureObject* staging = (GFXD3D11TextureObject*)&(*mStagingTex);
|
||||||
GFXD3D11TextureObject* pD3DStagingTex = (GFXD3D11TextureObject*)&(*mStagingTex);
|
|
||||||
ID3D11Resource* pStagingResource = pD3DStagingTex->getResource();
|
|
||||||
const bool is3D = mStagingTex->getDepth() != 0;
|
|
||||||
|
|
||||||
//unmap staging texture
|
D3D11DEVICECONTEXT->Unmap(staging->getResource(), mLockedSubresource);
|
||||||
pContext->Unmap(pStagingResource, mLockedSubresource);
|
|
||||||
//copy lock box region from the staging texture to our regular texture
|
|
||||||
pContext->CopySubresourceRegion(mD3DTexture, mLockedSubresource, mLockBox.left, mLockBox.top, is3D ? mLockBox.back : 0, pStagingResource, mLockedSubresource, &mLockBox);
|
|
||||||
|
|
||||||
PROFILE_END();
|
// Copy from staging back to GPU texture
|
||||||
|
D3D11DEVICECONTEXT->CopySubresourceRegion(
|
||||||
|
mD3DTexture.Get(),
|
||||||
|
mLockedSubresource,
|
||||||
|
0, 0, 0,
|
||||||
|
staging->getResource(),
|
||||||
|
mLockedSubresource,
|
||||||
|
&mLockBox
|
||||||
|
);
|
||||||
|
|
||||||
mLockedSubresource = 0;
|
mLockedSubresource = 0;
|
||||||
mLocked = false;
|
mLocked = false;
|
||||||
|
|
||||||
|
PROFILE_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXD3D11TextureObject::release()
|
void GFXD3D11TextureObject::release()
|
||||||
{
|
{
|
||||||
SAFE_RELEASE(mSRView);
|
mSRView.Reset();
|
||||||
SAFE_RELEASE(mRTView);
|
mRTView.Reset();
|
||||||
SAFE_RELEASE(mDSView);
|
mDSView.Reset();
|
||||||
SAFE_RELEASE(mD3DTexture);
|
mD3DTexture.Reset();
|
||||||
SAFE_RELEASE(mD3DSurface);
|
mD3DSurface.Reset();
|
||||||
|
|
||||||
|
for (auto& faceRTV : mCubeRTV)
|
||||||
|
faceRTV.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXD3D11TextureObject::zombify()
|
void GFXD3D11TextureObject::zombify()
|
||||||
|
|
@ -189,149 +210,206 @@ bool GFXD3D11TextureObject::copyToBmp(GBitmap* bmp)
|
||||||
if (!bmp)
|
if (!bmp)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// check format limitations
|
AssertFatal(mFormat == GFXFormatR16G16B16A16F || mFormat == GFXFormatR8G8B8A8 ||
|
||||||
// at the moment we only support RGBA for the source (other 4 byte formats should
|
mFormat == GFXFormatR8G8B8A8_LINEAR_FORCE || mFormat == GFXFormatR8G8B8A8_SRGB ||
|
||||||
// be easy to add though)
|
mFormat == GFXFormatR8G8B8,
|
||||||
AssertFatal(mFormat == GFXFormatR16G16B16A16F || mFormat == GFXFormatR8G8B8A8 || mFormat == GFXFormatR8G8B8A8_LINEAR_FORCE || mFormat == GFXFormatR8G8B8A8_SRGB || mFormat == GFXFormatR8G8B8, "copyToBmp: invalid format");
|
"GFXD3D11TextureObject::copyToBmp - Unsupported source format.");
|
||||||
if (mFormat != GFXFormatR16G16B16A16F && mFormat != GFXFormatR8G8B8A8 && mFormat != GFXFormatR8G8B8A8_LINEAR_FORCE && mFormat != GFXFormatR8G8B8A8_SRGB && mFormat != GFXFormatR8G8B8)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
PROFILE_START(GFXD3D11TextureObject_copyToBmp);
|
PROFILE_START(GFXD3D11TextureObject_copyToBmp);
|
||||||
|
|
||||||
AssertFatal(bmp->getWidth() == getWidth(), avar("GFXGLTextureObject::copyToBmp - Width mismatch: %i vs %i", bmp->getWidth(), getWidth()));
|
AssertFatal(bmp->getWidth() == getWidth(), "Width mismatch between texture and bitmap.");
|
||||||
AssertFatal(bmp->getHeight() == getHeight(), avar("GFXGLTextureObject::copyToBmp - Height mismatch: %i vs %i", bmp->getHeight(), getHeight()));
|
AssertFatal(bmp->getHeight() == getHeight(), "Height mismatch between texture and bitmap.");
|
||||||
const U32 mipLevels = getMipLevels();
|
|
||||||
|
|
||||||
|
const U32 mipLevels = getMipLevels();
|
||||||
bmp->setHasTransparency(mHasTransparency);
|
bmp->setHasTransparency(mHasTransparency);
|
||||||
|
|
||||||
// set some constants
|
// Figure out bytes per pixel
|
||||||
U32 sourceBytesPerPixel = 4;
|
const bool isFP16 = (bmp->getFormat() == GFXFormatR16G16B16A16F);
|
||||||
U32 destBytesPerPixel = 0;
|
const U32 destBpp = (bmp->getFormat() == GFXFormatR8G8B8 ? 3 :
|
||||||
|
bmp->getFormat() == GFXFormatR16G16B16A16F ? 8 : 4);
|
||||||
|
const U32 srcBpp = (mFormat == GFXFormatR16G16B16A16F ? 8 : 4);
|
||||||
|
|
||||||
const GFXFormat fmt = bmp->getFormat();
|
// --- Create staging texture ---
|
||||||
bool fp16 = false;//is rgba16f format?
|
D3D11_TEXTURE2D_DESC desc = {};
|
||||||
if (fmt == GFXFormatR16G16B16A16F)
|
reinterpret_cast<ID3D11Texture2D*>(mD3DTexture.Get())->GetDesc(&desc);
|
||||||
{
|
|
||||||
destBytesPerPixel = 8;
|
|
||||||
sourceBytesPerPixel = 8;
|
|
||||||
fp16 = true;
|
|
||||||
}
|
|
||||||
else if (fmt == GFXFormatR8G8B8A8 || fmt == GFXFormatR8G8B8A8_LINEAR_FORCE || fmt == GFXFormatR8G8B8A8_SRGB)
|
|
||||||
destBytesPerPixel = 4;
|
|
||||||
else if(bmp->getFormat() == GFXFormatR8G8B8)
|
|
||||||
destBytesPerPixel = 3;
|
|
||||||
else
|
|
||||||
// unsupported
|
|
||||||
AssertFatal(false, "GFXD3D11TextureObject::copyToBmp - unsupported bitmap format");
|
|
||||||
|
|
||||||
//create temp staging texture
|
|
||||||
D3D11_TEXTURE2D_DESC desc;
|
|
||||||
static_cast<ID3D11Texture2D*>(mD3DTexture)->GetDesc(&desc);
|
|
||||||
desc.BindFlags = 0;
|
desc.BindFlags = 0;
|
||||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||||
desc.Usage = D3D11_USAGE_STAGING;
|
desc.Usage = D3D11_USAGE_STAGING;
|
||||||
desc.MiscFlags = 0;
|
desc.MiscFlags = 0;
|
||||||
|
|
||||||
ID3D11Texture2D* pStagingTexture = NULL;
|
ComPtr<ID3D11Texture2D> stagingTex;
|
||||||
HRESULT hr = D3D11DEVICE->CreateTexture2D(&desc, NULL, &pStagingTexture);
|
HRESULT hr = D3D11DEVICE->CreateTexture2D(&desc, nullptr, stagingTex.GetAddressOf());
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to create staging texture");
|
Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to create staging texture (0x%X)", hr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//copy the classes texture to the staging texture
|
// --- Copy texture (handle cubemap or 2D) ---
|
||||||
D3D11DEVICECONTEXT->CopyResource(pStagingTexture, mD3DTexture);
|
const U32 faceCount = isCubeMap() && bmp->getNumFaces() == 6 ? 6 : 1;
|
||||||
|
|
||||||
for (U32 mip = 0; mip < mipLevels; mip++)
|
for (U32 face = 0; face < faceCount; ++face)
|
||||||
{
|
{
|
||||||
const U32 width = bmp->getWidth(mip);
|
for (U32 mip = 0; mip < mipLevels; ++mip)
|
||||||
const U32 height = bmp->getHeight(mip);
|
|
||||||
//map the staging resource
|
|
||||||
D3D11_MAPPED_SUBRESOURCE mappedRes;
|
|
||||||
const U32 subResource = D3D11CalcSubresource(mip, 0, mipLevels);
|
|
||||||
hr = D3D11DEVICECONTEXT->Map(pStagingTexture, subResource, D3D11_MAP_READ, 0, &mappedRes);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
{
|
||||||
//cleanup
|
const U32 srcSubRes = D3D11CalcSubresource(mip, face, mipLevels);
|
||||||
SAFE_RELEASE(pStagingTexture);
|
// Always map mip-level 0..mipLevels-1 on *slice 0* of the staging texture
|
||||||
Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to map staging texture");
|
const U32 dstSubRes = D3D11CalcSubresource(mip, face, mipLevels);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set pointers
|
D3D11DEVICECONTEXT->CopySubresourceRegion(
|
||||||
const U8* srcPtr = (U8*)mappedRes.pData;
|
stagingTex.Get(), dstSubRes, 0, 0, 0,
|
||||||
U8* destPtr = bmp->getWritableBits(mip);
|
mD3DTexture.Get(), srcSubRes, nullptr);
|
||||||
|
|
||||||
// we will want to skip over any D3D cache data in the source texture
|
D3D11_MAPPED_SUBRESOURCE mapped = {};
|
||||||
const S32 sourceCacheSize = mappedRes.RowPitch - width * sourceBytesPerPixel;
|
hr = D3D11DEVICECONTEXT->Map(stagingTex.Get(), dstSubRes, D3D11_MAP_READ, 0, &mapped);
|
||||||
AssertFatal(sourceCacheSize >= 0, "GFXD3D11TextureObject::copyToBmp - cache size is less than zero?");
|
if (FAILED(hr))
|
||||||
|
|
||||||
// copy data into bitmap
|
|
||||||
for (U32 row = 0; row < height; ++row)
|
|
||||||
{
|
|
||||||
for (U32 col = 0; col < width; ++col)
|
|
||||||
{
|
{
|
||||||
//we can just copy data straight in with RGBA16F format
|
Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to map staging texture (0x%X)", hr);
|
||||||
if (fp16)
|
return false;
|
||||||
{
|
|
||||||
dMemcpy(destPtr, srcPtr, sizeof(U16) * 4);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
destPtr[0] = srcPtr[2]; // red
|
|
||||||
destPtr[1] = srcPtr[1]; // green
|
|
||||||
destPtr[2] = srcPtr[0]; // blue
|
|
||||||
if (destBytesPerPixel == 4)
|
|
||||||
destPtr[3] = srcPtr[3]; // alpha
|
|
||||||
}
|
|
||||||
|
|
||||||
// go to next pixel in src
|
|
||||||
srcPtr += sourceBytesPerPixel;
|
|
||||||
|
|
||||||
// go to next pixel in dest
|
|
||||||
destPtr += destBytesPerPixel;
|
|
||||||
}
|
}
|
||||||
// skip past the cache data for this row (if any)
|
|
||||||
srcPtr += sourceCacheSize;
|
const U8* src = static_cast<const U8*>(mapped.pData);
|
||||||
|
U8* dst = bmp->getWritableBits(mip, face);
|
||||||
|
|
||||||
|
const U32 width = bmp->getWidth(mip);
|
||||||
|
const U32 height = bmp->getHeight(mip);
|
||||||
|
|
||||||
|
for (U32 y = 0; y < height; ++y)
|
||||||
|
{
|
||||||
|
const U8* srcRow = src;
|
||||||
|
U8* dstRow = dst;
|
||||||
|
|
||||||
|
for (U32 x = 0; x < width; ++x)
|
||||||
|
{
|
||||||
|
if (isFP16)
|
||||||
|
{
|
||||||
|
dMemcpy(dstRow, srcRow, sizeof(U16) * 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Convert BGRA → RGB(A)
|
||||||
|
dstRow[0] = srcRow[2];
|
||||||
|
dstRow[1] = srcRow[1];
|
||||||
|
dstRow[2] = srcRow[0];
|
||||||
|
if (destBpp == 4)
|
||||||
|
dstRow[3] = srcRow[3];
|
||||||
|
}
|
||||||
|
srcRow += srcBpp;
|
||||||
|
dstRow += destBpp;
|
||||||
|
}
|
||||||
|
|
||||||
|
src += mapped.RowPitch;
|
||||||
|
dst += width * destBpp;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D11DEVICECONTEXT->Unmap(stagingTex.Get(), dstSubRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// assert if we stomped or underran memory
|
|
||||||
AssertFatal(U32(destPtr - bmp->getWritableBits(mip)) == width * height * destBytesPerPixel, "GFXD3D11TextureObject::copyToBmp - memory error");
|
|
||||||
AssertFatal(U32(srcPtr - (U8*)mappedRes.pData) == height * mappedRes.RowPitch, "GFXD3D11TextureObject::copyToBmp - memory error");
|
|
||||||
|
|
||||||
D3D11DEVICECONTEXT->Unmap(pStagingTexture, subResource);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SAFE_RELEASE(pStagingTexture);
|
|
||||||
PROFILE_END();
|
PROFILE_END();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ID3D11ShaderResourceView* GFXD3D11TextureObject::getSRView()
|
void GFXD3D11TextureObject::generateMipMaps()
|
||||||
{
|
{
|
||||||
return mSRView;
|
//Generate mips
|
||||||
}
|
D3D11DEVICECONTEXT->GenerateMips(mSRView.Get());
|
||||||
ID3D11RenderTargetView* GFXD3D11TextureObject::getRTView()
|
//get mip level count
|
||||||
{
|
D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
|
||||||
return mRTView;
|
mSRView->GetDesc(&viewDesc);
|
||||||
}
|
mMipLevels = viewDesc.TextureCube.MipLevels;
|
||||||
ID3D11DepthStencilView* GFXD3D11TextureObject::getDSView()
|
|
||||||
{
|
|
||||||
return mDSView;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ID3D11ShaderResourceView** GFXD3D11TextureObject::getSRViewPtr()
|
void GFXD3D11TextureObject::updateTextureSlot(const GFXTexHandle& texHandle, const U32 slot, const S32 faceIdx /*=-1*/)
|
||||||
{
|
{
|
||||||
return &mSRView;
|
AssertFatal(slot < getArraySize(), "updateTextureSlot - destination slot out of bounds");
|
||||||
}
|
AssertFatal(mFormat == texHandle->getFormat(), "updateTextureSlot - format mismatch");
|
||||||
ID3D11RenderTargetView** GFXD3D11TextureObject::getRTViewPtr()
|
AssertFatal(getMipLevels() == texHandle->getMipLevels(), "updateTextureSlot - mip level mismatch");
|
||||||
{
|
|
||||||
return &mRTView;
|
GFXD3D11TextureObject* srcTex = static_cast<GFXD3D11TextureObject*>(texHandle.getPointer());
|
||||||
|
|
||||||
|
ID3D11Resource* dstRes = get2DTex();
|
||||||
|
ID3D11Resource* srcRes = srcTex->get2DTex();
|
||||||
|
|
||||||
|
const UINT mipLevels = getMipLevels();
|
||||||
|
|
||||||
|
const bool dstIsCube = isCubeMap();
|
||||||
|
const bool srcIsCube = srcTex->isCubeMap();
|
||||||
|
|
||||||
|
const UINT dstArraySize = getArraySize();
|
||||||
|
const UINT srcArraySize = srcTex->getArraySize();
|
||||||
|
|
||||||
|
// Determine number of faces to copy
|
||||||
|
const UINT faceCount = srcIsCube ? 6 : 1;
|
||||||
|
const UINT startFace = (faceIdx >= 0) ? faceIdx : 0;
|
||||||
|
const UINT endFace = (faceIdx >= 0) ? faceIdx + 1 : faceCount;
|
||||||
|
|
||||||
|
for (UINT face = startFace; face < endFace; ++face)
|
||||||
|
{
|
||||||
|
// Compute source slice
|
||||||
|
const UINT srcSlice = srcIsCube
|
||||||
|
? (srcArraySize > 1 ? face + slot * 6 : face) // only add slot*6 if it's a cubemap array
|
||||||
|
: (srcArraySize > 1 ? face + slot : 0); // otherwise, single 2D texture or 2D array
|
||||||
|
|
||||||
|
const UINT dstSlice = dstIsCube
|
||||||
|
? (dstArraySize > 1 ? face + slot * 6 : face) // only add slot*6 if it's a cubemap array
|
||||||
|
: (dstArraySize > 1 ? face + slot : 0); // otherwise, single 2D texture or 2D array
|
||||||
|
|
||||||
|
for (UINT mip = 0; mip < mipLevels; ++mip)
|
||||||
|
{
|
||||||
|
const UINT srcSubresource = D3D11CalcSubresource(mip, srcSlice, mipLevels);
|
||||||
|
const UINT dstSubresource = D3D11CalcSubresource(mip, dstSlice, mipLevels);
|
||||||
|
|
||||||
|
D3D11DEVICECONTEXT->CopySubresourceRegion(dstRes, dstSubresource, 0, 0, 0, srcRes, srcSubresource, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ID3D11DepthStencilView** GFXD3D11TextureObject::getDSViewPtr()
|
void GFXD3D11TextureObject::copyTo(GFXTextureObject* dstTex)
|
||||||
{
|
{
|
||||||
return &mDSView;
|
AssertFatal(dstTex, "GFXD3D11TextureObject::copyTo - destination is null");
|
||||||
|
|
||||||
|
GFXD3D11TextureObject* pDstTex = static_cast<GFXD3D11TextureObject*>(dstTex);
|
||||||
|
|
||||||
|
ID3D11Texture2D* srcTex = (ID3D11Texture2D*)mD3DTexture.Get();
|
||||||
|
ID3D11Texture2D* dstTex2D = pDstTex->get2DTex();
|
||||||
|
|
||||||
|
D3D11_TEXTURE2D_DESC srcDesc, dstDesc;
|
||||||
|
srcTex->GetDesc(&srcDesc);
|
||||||
|
dstTex2D->GetDesc(&dstDesc);
|
||||||
|
|
||||||
|
// Sanity check – sizes and formats must match for a full copy.
|
||||||
|
AssertFatal(srcDesc.Width == dstDesc.Width && srcDesc.Height == dstDesc.Height,
|
||||||
|
"GFXD3D11TextureObject::copyTo - Mismatched texture dimensions");
|
||||||
|
AssertFatal(srcDesc.Format == dstDesc.Format,
|
||||||
|
"GFXD3D11TextureObject::copyTo - Mismatched formats");
|
||||||
|
|
||||||
|
UINT srcMipLevels = srcDesc.MipLevels ? srcDesc.MipLevels : 1;
|
||||||
|
UINT dstMipLevels = dstDesc.MipLevels ? dstDesc.MipLevels : 1;
|
||||||
|
UINT mipLevels = getMin(srcMipLevels, dstMipLevels);
|
||||||
|
|
||||||
|
UINT srcArraySize = srcDesc.ArraySize;
|
||||||
|
UINT dstArraySize = dstDesc.ArraySize;
|
||||||
|
UINT arraySize = getMin(srcArraySize, dstArraySize);
|
||||||
|
|
||||||
|
// Handle cube maps and cube map arrays
|
||||||
|
bool isCubeSrc = (srcDesc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) != 0;
|
||||||
|
|
||||||
|
// In cubemaps, ArraySize is always 6 * numCubes
|
||||||
|
if (isCubeSrc) arraySize = srcArraySize; // 6 or 6*nCubes
|
||||||
|
|
||||||
|
for (UINT arraySlice = 0; arraySlice < arraySize; ++arraySlice)
|
||||||
|
{
|
||||||
|
for (UINT mip = 0; mip < mipLevels; ++mip)
|
||||||
|
{
|
||||||
|
UINT srcSubresource = D3D11CalcSubresource(mip, arraySlice, srcMipLevels);
|
||||||
|
UINT dstSubresource = D3D11CalcSubresource(mip, arraySlice, dstMipLevels);
|
||||||
|
|
||||||
|
D3D11DEVICECONTEXT->CopySubresourceRegion(
|
||||||
|
dstTex2D, dstSubresource,
|
||||||
|
0, 0, 0,
|
||||||
|
srcTex, srcSubresource,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,55 +27,77 @@
|
||||||
#include "gfx/gfxTextureHandle.h"
|
#include "gfx/gfxTextureHandle.h"
|
||||||
#include "gfx/gfxTextureManager.h"
|
#include "gfx/gfxTextureManager.h"
|
||||||
|
|
||||||
|
#include <wrl/client.h>
|
||||||
|
using Microsoft::WRL::ComPtr;
|
||||||
|
|
||||||
class GFXD3D11TextureObject : public GFXTextureObject
|
class GFXD3D11TextureObject : public GFXTextureObject
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
static U32 mTexCount;
|
static U32 mTexCount;
|
||||||
|
|
||||||
GFXTexHandle mStagingTex;
|
GFXTexHandle mStagingTex;
|
||||||
DXGI_MAPPED_RECT mLockRect;
|
DXGI_MAPPED_RECT mLockRect;
|
||||||
D3D11_BOX mLockBox;
|
D3D11_BOX mLockBox;
|
||||||
bool mLocked;
|
bool mLocked = false;
|
||||||
|
|
||||||
U32 mLockedSubresource;
|
U32 mLockedSubresource = 0;
|
||||||
ID3D11Resource *mD3DTexture;
|
|
||||||
|
|
||||||
// used for z buffers...
|
// Main GPU texture resource (2D / 3D / Cubemap)
|
||||||
ID3D11Texture2D *mD3DSurface;
|
ComPtr<ID3D11Resource> mD3DTexture;
|
||||||
|
|
||||||
ID3D11ShaderResourceView* mSRView; // for shader resource input
|
// Used for Z-targets
|
||||||
ID3D11RenderTargetView* mRTView; // for render targets
|
ComPtr<ID3D11Texture2D> mD3DSurface;
|
||||||
ID3D11DepthStencilView* mDSView; //render target view for depth stencil
|
|
||||||
|
|
||||||
|
// Views
|
||||||
|
ComPtr<ID3D11ShaderResourceView> mSRView; // Shader resource
|
||||||
|
ComPtr<ID3D11RenderTargetView> mRTView; // Render target
|
||||||
|
ComPtr<ID3D11DepthStencilView> mDSView; // Depth stencil
|
||||||
|
|
||||||
|
// Cubemap face render target views (optional)
|
||||||
|
ComPtr<ID3D11RenderTargetView> mCubeRTV[6];
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GFXD3D11TextureObject( GFXDevice * d, GFXTextureProfile *profile);
|
GFXD3D11TextureObject( GFXDevice * d, GFXTextureProfile *profile, const U32 arraySize = 1);
|
||||||
~GFXD3D11TextureObject();
|
~GFXD3D11TextureObject();
|
||||||
|
|
||||||
ID3D11Resource* getResource(){ return mD3DTexture; }
|
// Accessors
|
||||||
ID3D11Texture2D* get2DTex(){ return (ID3D11Texture2D*) mD3DTexture; }
|
ID3D11Resource* getResource() const { return mD3DTexture.Get(); }
|
||||||
ID3D11Texture2D** get2DTexPtr(){ return (ID3D11Texture2D**) &mD3DTexture; }
|
ID3D11Texture2D* get2DTex() const;
|
||||||
ID3D11Texture3D* get3DTex(){ return (ID3D11Texture3D*) mD3DTexture; }
|
ID3D11Texture3D* get3DTex() const;
|
||||||
ID3D11Texture3D** get3DTexPtr(){ return (ID3D11Texture3D**) &mD3DTexture; }
|
ID3D11Texture2D** get2DTexPtr();
|
||||||
|
ID3D11Texture3D** get3DTexPtr();
|
||||||
ID3D11ShaderResourceView* getSRView();
|
|
||||||
ID3D11RenderTargetView* getRTView();
|
|
||||||
ID3D11DepthStencilView* getDSView();
|
|
||||||
|
|
||||||
ID3D11ShaderResourceView** getSRViewPtr();
|
ID3D11ShaderResourceView* getSRView() const { return mSRView.Get(); }
|
||||||
ID3D11RenderTargetView** getRTViewPtr();
|
ID3D11RenderTargetView* getRTView() const { return mRTView.Get(); }
|
||||||
ID3D11DepthStencilView** getDSViewPtr();
|
ID3D11DepthStencilView* getDSView() const { return mDSView.Get(); }
|
||||||
|
|
||||||
|
ID3D11ShaderResourceView** getSRViewPtr() { return mSRView.GetAddressOf(); }
|
||||||
|
ID3D11RenderTargetView** getRTViewPtr() { return mRTView.GetAddressOf(); }
|
||||||
|
ID3D11DepthStencilView** getDSViewPtr() { return mDSView.GetAddressOf(); }
|
||||||
|
|
||||||
|
// Cubemap face RTV access (for render-to-cubemap)
|
||||||
|
ID3D11RenderTargetView* getCubeFaceRTView(U32 face) const
|
||||||
|
{
|
||||||
|
AssertFatal(isCubeMap(), "Not a cubemap texture!");
|
||||||
|
AssertFatal(face < 6, "Invalid cubemap face index!");
|
||||||
|
return mCubeRTV[face].Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3D11RenderTargetView** getCubeFaceRTViewPtr(U32 face);
|
||||||
|
|
||||||
void release();
|
void release();
|
||||||
|
|
||||||
bool isManaged; //setting to true tells this texture not to be released from being zombify
|
bool isManaged; //setting to true tells this texture not to be released from being zombify
|
||||||
|
|
||||||
GFXLockedRect * lock(U32 mipLevel = 0, RectI *inRect = NULL) override;
|
GFXLockedRect* lock(U32 mipLevel = 0, RectI* inRect = NULL, U32 faceIndex = 0) override;
|
||||||
void unlock(U32 mipLevel = 0 ) override;
|
void unlock(U32 mipLevel = 0, U32 faceIndex = 0) override;
|
||||||
|
|
||||||
bool copyToBmp(GBitmap* bmp) override;
|
bool copyToBmp(GBitmap* bmp) override;
|
||||||
ID3D11Texture2D* getSurface() {return mD3DSurface;}
|
void generateMipMaps() override;
|
||||||
ID3D11Texture2D** getSurfacePtr() {return &mD3DSurface;}
|
void updateTextureSlot(const GFXTexHandle& texHandle, const U32 slot, const S32 face = -1) override;
|
||||||
|
void copyTo(GFXTextureObject* dstTex) override;
|
||||||
|
ID3D11Texture2D* getSurface() {return mD3DSurface.Get();}
|
||||||
|
ID3D11Texture2D** getSurfacePtr() {return mD3DSurface.GetAddressOf();}
|
||||||
|
|
||||||
// GFXResource
|
// GFXResource
|
||||||
void zombify() override;
|
void zombify() override;
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,12 @@ public:
|
||||||
void pureVirtualCrash() override {}
|
void pureVirtualCrash() override {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GFXLockedRect * lock( U32 mipLevel = 0, RectI *inRect = NULL ) override { return NULL; };
|
GFXLockedRect * lock( U32 mipLevel = 0, RectI *inRect = NULL, U32 faceIndex = 0)override { return NULL; };
|
||||||
void unlock( U32 mipLevel = 0) override {};
|
void unlock( U32 mipLevel = 0, U32 faceIndex = 0)override {};
|
||||||
bool copyToBmp(GBitmap *) override { return false; };
|
bool copyToBmp(GBitmap *) override { return false; };
|
||||||
|
void updateTextureSlot(const GFXTexHandle& texHandle, const U32 slot, const S32 face = -1) override {};
|
||||||
|
void copyTo(GFXTextureObject* dstTex) override {};
|
||||||
|
void generateMipMaps() override {};
|
||||||
void zombify() override {}
|
void zombify() override {}
|
||||||
void resurrect() override {}
|
void resurrect() override {}
|
||||||
};
|
};
|
||||||
|
|
@ -94,8 +96,8 @@ public:
|
||||||
GFXTextureObject* createTexture(DDSFile* dds, GFXTextureProfile* profile, bool deleteDDS) override { return nullptr; }
|
GFXTextureObject* createTexture(DDSFile* dds, GFXTextureProfile* profile, bool deleteDDS) override { return nullptr; }
|
||||||
GFXTextureObject* createTexture(const Torque::Path& path, GFXTextureProfile* profile) override { return nullptr; }
|
GFXTextureObject* createTexture(const Torque::Path& path, GFXTextureProfile* profile) override { return nullptr; }
|
||||||
GFXTextureObject* createTexture(U32 width, U32 height, void* pixels, GFXFormat format, GFXTextureProfile* profile) override { return nullptr; }
|
GFXTextureObject* createTexture(U32 width, U32 height, void* pixels, GFXFormat format, GFXTextureProfile* profile) override { return nullptr; }
|
||||||
GFXTextureObject* createTexture(U32 width, U32 height, U32 depth, GFXFormat format, GFXTextureProfile* profile, U32 numMipLevels = 1) override { return nullptr; }
|
GFXTextureObject* createTexture(U32 width, U32 height, U32 depth, GFXFormat format, GFXTextureProfile* profile, U32 numMipLevels = 1, U32 arraySize = 1) override { return nullptr; }
|
||||||
GFXTextureObject* createTexture(U32 width, U32 height, GFXFormat format, GFXTextureProfile* profile, U32 numMipLevels, S32 antialiasLevel) override { return nullptr; }
|
GFXTextureObject* createTexture(U32 width, U32 height, GFXFormat format, GFXTextureProfile* profile, U32 numMipLevels, S32 antialiasLevel, U32 arraySize = 1) override { return nullptr; }
|
||||||
GFXTextureObject* createCompositeTexture(GBitmap* bmp[4], U32 inputKey[4], const String& resourceName, GFXTextureProfile* profile, bool deleteBmp) override { return nullptr; }
|
GFXTextureObject* createCompositeTexture(GBitmap* bmp[4], U32 inputKey[4], const String& resourceName, GFXTextureProfile* profile, bool deleteBmp) override { return nullptr; }
|
||||||
protected:
|
protected:
|
||||||
GFXTextureObject *_createTextureObject( U32 height,
|
GFXTextureObject *_createTextureObject( U32 height,
|
||||||
|
|
@ -105,7 +107,8 @@ protected:
|
||||||
GFXTextureProfile *profile,
|
GFXTextureProfile *profile,
|
||||||
U32 numMipLevels,
|
U32 numMipLevels,
|
||||||
bool forceMips = false,
|
bool forceMips = false,
|
||||||
S32 antialiasLevel = 0,
|
S32 antialiasLevel = 0,
|
||||||
|
U32 arraySize = 1,
|
||||||
GFXTextureObject *inTex = NULL ) override
|
GFXTextureObject *inTex = NULL ) override
|
||||||
{
|
{
|
||||||
GFXNullTextureObject *retTex;
|
GFXNullTextureObject *retTex;
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,11 @@
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
|
|
||||||
|
#ifndef STB_IMAGE_RESIZE2_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_RESIZE2_IMPLEMENTATION
|
||||||
|
#define STBIR_PROFILE
|
||||||
|
#include "gfx/bitmap/loaders/stb/stb_image_resize2.h"
|
||||||
|
#endif // !STB_IMAGE_RESIZE2_IMPLEMENTATION
|
||||||
|
|
||||||
void bitmapExtrude5551_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth)
|
void bitmapExtrude5551_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth)
|
||||||
{
|
{
|
||||||
|
|
@ -67,7 +72,7 @@ void bitmapExtrude5551_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWi
|
||||||
{
|
{
|
||||||
U32 a = src[0];
|
U32 a = src[0];
|
||||||
U32 c = src[stride];
|
U32 c = src[stride];
|
||||||
#if defined(TORQUE_OS_MAC)
|
#if defined(TORQUE_BIG_ENDIAN)
|
||||||
dst[y] = ((( (a >> 10) + (c >> 10)) >> 1) << 10) |
|
dst[y] = ((( (a >> 10) + (c >> 10)) >> 1) << 10) |
|
||||||
((( ((a >> 5) & 0x1F) + ((c >> 5) & 0x1f)) >> 1) << 5) |
|
((( ((a >> 5) & 0x1F) + ((c >> 5) & 0x1f)) >> 1) << 5) |
|
||||||
((( ((a >> 0) & 0x1F) + ((c >> 0) & 0x1f)) >> 1) << 0);
|
((( ((a >> 0) & 0x1F) + ((c >> 0) & 0x1f)) >> 1) << 0);
|
||||||
|
|
@ -81,151 +86,434 @@ void bitmapExtrude5551_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
void bitmapExtrudeRGB_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth)
|
|
||||||
|
template <typename T>
|
||||||
|
void bitmapExtrudeGeneric(
|
||||||
|
const T* src, T* dst,
|
||||||
|
U32 srcWidth, U32 srcHeight,
|
||||||
|
U32 channels, U32 bpp)
|
||||||
{
|
{
|
||||||
const U8 *src = (const U8 *) srcMip;
|
U32 srcRowStride = srcHeight != 1 ? (srcWidth * bpp) / sizeof(T) : 0;
|
||||||
U8 *dst = (U8 *) mip;
|
U32 dstWidth = srcWidth > 1 ? srcWidth / 2 : 1;
|
||||||
U32 stride = srcHeight != 1 ? (srcWidth) * 3 : 0;
|
U32 dstHeight = srcHeight > 1 ? srcHeight / 2 : 1;
|
||||||
|
U32 dstRowStride = dstHeight != 1 ? (dstWidth * bpp) / sizeof(T) : 0;
|
||||||
|
|
||||||
U32 width = srcWidth >> 1;
|
for (U32 y = 0; y < dstHeight; ++y)
|
||||||
U32 height = srcHeight >> 1;
|
|
||||||
if (width == 0) width = 1;
|
|
||||||
if (height == 0) height = 1;
|
|
||||||
|
|
||||||
if (srcWidth != 1)
|
|
||||||
{
|
{
|
||||||
for(U32 y = 0; y < height; y++)
|
for (U32 x = 0; x < dstWidth; ++x)
|
||||||
{
|
{
|
||||||
for(U32 x = 0; x < width; x++)
|
for (U32 c = 0; c < channels; ++c)
|
||||||
{
|
{
|
||||||
*dst++ = (U32(*src) + U32(src[3]) + U32(src[stride]) + U32(src[stride+3]) + 2) >> 2;
|
U32 x0 = x * 2;
|
||||||
src++;
|
U32 y0 = y * 2;
|
||||||
*dst++ = (U32(*src) + U32(src[3]) + U32(src[stride]) + U32(src[stride+3]) + 2) >> 2;
|
U32 x1 = (x0 + 1 < srcWidth) ? x0 + 1 : x0;
|
||||||
src++;
|
U32 y1 = (y0 + 1 < srcHeight) ? y0 + 1 : y0;
|
||||||
*dst++ = (U32(*src) + U32(src[3]) + U32(src[stride]) + U32(src[stride+3]) + 2) >> 2;
|
|
||||||
src += 4;
|
|
||||||
}
|
|
||||||
src += stride; // skip
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(U32 y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
|
|
||||||
src++;
|
|
||||||
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
|
|
||||||
src++;
|
|
||||||
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
|
|
||||||
src += 4;
|
|
||||||
|
|
||||||
src += stride; // skip
|
if constexpr (std::is_floating_point_v<T>)
|
||||||
|
{
|
||||||
|
T sum = 0;
|
||||||
|
sum += src[y0 * srcRowStride + x0 * channels + c];
|
||||||
|
sum += src[y0 * srcRowStride + x1 * channels + c];
|
||||||
|
sum += src[y1 * srcRowStride + x0 * channels + c];
|
||||||
|
sum += src[y1 * srcRowStride + x1 * channels + c];
|
||||||
|
|
||||||
|
dst[y * dstRowStride + x * channels + c] = sum * 0.25f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
U32 sum = 0;
|
||||||
|
sum += src[y0 * srcRowStride + x0 * channels + c];
|
||||||
|
sum += src[y0 * srcRowStride + x1 * channels + c];
|
||||||
|
sum += src[y1 * srcRowStride + x0 * channels + c];
|
||||||
|
sum += src[y1 * srcRowStride + x1 * channels + c];
|
||||||
|
dst[y * dstRowStride + x * channels + c] = T((sum + 2) >> 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
// 8-bit RGBA
|
||||||
void bitmapExtrudeRGBA_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth)
|
auto bitmapExtrudeU8_RGBA = [](const void* src, void* dst, U32 h, U32 w, U32 bpp) {
|
||||||
|
bitmapExtrudeGeneric((const U8*)src, (U8*)dst, w, h, 4, bpp);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 16-bit RGBA (U16 / F32 stored as U16)
|
||||||
|
auto bitmapExtrudeU16_RGBA = [](const void* src, void* dst, U32 h, U32 w, U32 bpp) {
|
||||||
|
bitmapExtrudeGeneric((const U16*)src, (U16*)dst, w, h, 4, bpp);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 32-bit float RGBA
|
||||||
|
auto bitmapExtrudeF32_RGBA = [](const void* src, void* dst, U32 h, U32 w, U32 bpp) {
|
||||||
|
bitmapExtrudeGeneric((const F32*)src, (F32*)dst, w, h, 4, bpp);
|
||||||
|
};
|
||||||
|
|
||||||
|
// RGB U8
|
||||||
|
auto bitmapExtrudeU8_RGB = [](const void* src, void* dst, U32 h, U32 w, U32 bpp) {
|
||||||
|
bitmapExtrudeGeneric((const U8*)src, (U8*)dst, w, h, 3, bpp);
|
||||||
|
};
|
||||||
|
|
||||||
|
void (*bitmapExtrude5551)(const void* srcMip, void* mip, U32 height, U32 width) = bitmapExtrude5551_c;
|
||||||
|
void (*bitmapExtrudeRGB)(const void* srcMip, void* mip, U32 srcHeight, U32 srcWidth, U32 bpp) = bitmapExtrudeU8_RGB;
|
||||||
|
void (*bitmapExtrudeRGBA)(const void* srcMip, void* mip, U32 srcHeight, U32 srcWidth, U32 bpp) = bitmapExtrudeU8_RGBA;
|
||||||
|
void (*bitmapExtrude16BitRGBA)(const void* srcMip, void* mip, U32 srcHeight, U32 srcWidth, U32 bpp) = bitmapExtrudeU16_RGBA;
|
||||||
|
void (*bitmapExtrudeFPRGBA)(const void* srcMip, void* mip, U32 srcHeight, U32 srcWidth, U32 bpp) = bitmapExtrudeU16_RGBA;
|
||||||
|
void (*bitmapExtrudeF32RGBA)(const void* srcMip, void* mip, U32 srcHeight, U32 srcWidth, U32 bpp) = bitmapExtrudeF32_RGBA;
|
||||||
|
|
||||||
|
struct StbResizeDesc
|
||||||
{
|
{
|
||||||
const U8 *src = (const U8 *) srcMip;
|
stbir_datatype datatype;
|
||||||
U8 *dst = (U8 *) mip;
|
stbir_pixel_layout layout;
|
||||||
U32 stride = srcHeight != 1 ? (srcWidth) * 4 : 0;
|
U32 bytesPerPixel;
|
||||||
|
};
|
||||||
|
|
||||||
U32 width = srcWidth >> 1;
|
inline bool getStbResizeDesc(GFXFormat fmt, StbResizeDesc& out)
|
||||||
U32 height = srcHeight >> 1;
|
{
|
||||||
if (width == 0) width = 1;
|
switch (fmt)
|
||||||
if (height == 0) height = 1;
|
|
||||||
|
|
||||||
if (srcWidth != 1)
|
|
||||||
{
|
{
|
||||||
for(U32 y = 0; y < height; y++)
|
// ---- 1 channel ----
|
||||||
|
case GFXFormatA8:
|
||||||
|
case GFXFormatL8:
|
||||||
|
out = { STBIR_TYPE_UINT8, STBIR_1CHANNEL, 1 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GFXFormatL16:
|
||||||
|
out = { STBIR_TYPE_UINT16, STBIR_1CHANNEL, 2 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GFXFormatR16F:
|
||||||
|
out = { STBIR_TYPE_HALF_FLOAT, STBIR_1CHANNEL, 2 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GFXFormatR32F:
|
||||||
|
out = { STBIR_TYPE_FLOAT, STBIR_1CHANNEL, 4 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// ---- 2 channel ----
|
||||||
|
case GFXFormatA8L8:
|
||||||
|
out = { STBIR_TYPE_UINT8, STBIR_2CHANNEL, 2 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GFXFormatR16G16:
|
||||||
|
out = { STBIR_TYPE_UINT16, STBIR_2CHANNEL, 4 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GFXFormatR16G16F:
|
||||||
|
out = { STBIR_TYPE_HALF_FLOAT, STBIR_2CHANNEL, 4 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// ---- RGB ----
|
||||||
|
case GFXFormatR8G8B8:
|
||||||
|
out = { STBIR_TYPE_UINT8, STBIR_RGB, 3 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GFXFormatR8G8B8_SRGB:
|
||||||
|
out = { STBIR_TYPE_UINT8_SRGB, STBIR_RGB, 3 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// ---- RGBA / RGBX ----
|
||||||
|
case GFXFormatR8G8B8A8:
|
||||||
|
case GFXFormatR8G8B8X8:
|
||||||
|
out = { STBIR_TYPE_UINT8, STBIR_RGBA, 4 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GFXFormatR8G8B8A8_SRGB:
|
||||||
|
out = { STBIR_TYPE_UINT8_SRGB_ALPHA, STBIR_RGBA, 4 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GFXFormatB8G8R8A8:
|
||||||
|
out = { STBIR_TYPE_UINT8, STBIR_BGRA, 4 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// ---- 16-bit RGBA ----
|
||||||
|
case GFXFormatR16G16B16A16:
|
||||||
|
out = { STBIR_TYPE_UINT16, STBIR_RGBA, 8 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GFXFormatR16G16B16A16F:
|
||||||
|
out = { STBIR_TYPE_HALF_FLOAT, STBIR_RGBA, 8 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// ---- 32-bit RGBA ----
|
||||||
|
case GFXFormatR32G32B32A32F:
|
||||||
|
out = { STBIR_TYPE_FLOAT, STBIR_RGBA, 16 };
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitmapStbResizeToOutput(const void* src, U32 srcHeight, U32 srcWidth, void* out, U32 outHeight, U32 outWidth, U32 bpp, GFXFormat format)
|
||||||
|
{
|
||||||
|
StbResizeDesc desc;
|
||||||
|
if (!getStbResizeDesc(format, desc))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int srcStride = srcWidth * bpp;
|
||||||
|
const int dstStride = outWidth * bpp;
|
||||||
|
|
||||||
|
stbir_resize(
|
||||||
|
src,
|
||||||
|
srcWidth,
|
||||||
|
srcHeight,
|
||||||
|
srcStride,
|
||||||
|
out,
|
||||||
|
outWidth,
|
||||||
|
outHeight,
|
||||||
|
dstStride,
|
||||||
|
desc.layout,
|
||||||
|
desc.datatype,
|
||||||
|
STBIR_EDGE_CLAMP,
|
||||||
|
STBIR_FILTER_MITCHELL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void(*bitmapResizeToOutput)(const void* src, U32 srcHeight, U32 srcWidth, void* out, U32 outHeight, U32 outWidth, U32 bpp, GFXFormat format) = bitmapStbResizeToOutput;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// Format description
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// Channel semantics
|
||||||
|
enum ChannelSemantic : U8
|
||||||
|
{
|
||||||
|
CH_NONE,
|
||||||
|
CH_L,
|
||||||
|
CH_A,
|
||||||
|
CH_R,
|
||||||
|
CH_G,
|
||||||
|
CH_B
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// Bitmap format descriptor
|
||||||
|
struct GBitmapFormatDesc
|
||||||
|
{
|
||||||
|
U8 channels;
|
||||||
|
ChannelSemantic semantic[4]; // per-channel meaning
|
||||||
|
stbir_datatype datatype;
|
||||||
|
bool srgb;
|
||||||
|
bool premultiplied;
|
||||||
|
bool isFloat;
|
||||||
|
U8 bytesPerChannel;
|
||||||
|
|
||||||
|
bool is8() const { return !isFloat && bytesPerChannel == 1; }
|
||||||
|
bool is16() const { return !isFloat && bytesPerChannel == 2; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// Table mapping GFXFormat -> descriptor
|
||||||
|
GBitmapFormatDesc getFormatDesc(GFXFormat fmt)
|
||||||
|
{
|
||||||
|
switch (fmt)
|
||||||
|
{
|
||||||
|
// 8-bit formats
|
||||||
|
case GFXFormatA8:
|
||||||
|
return { 1, {CH_A, CH_NONE, CH_NONE, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 };
|
||||||
|
case GFXFormatL8:
|
||||||
|
return { 1, {CH_L, CH_NONE, CH_NONE, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 };
|
||||||
|
case GFXFormatA4L4:
|
||||||
|
return { 2, {CH_L, CH_A, CH_NONE, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 };
|
||||||
|
|
||||||
|
// 16-bit formats
|
||||||
|
case GFXFormatR5G6B5:
|
||||||
|
return { 3, {CH_R, CH_G, CH_B, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 };
|
||||||
|
case GFXFormatR5G5B5A1:
|
||||||
|
return { 4, {CH_R, CH_G, CH_B, CH_A}, STBIR_TYPE_UINT8, false, false, false, 1 };
|
||||||
|
case GFXFormatR5G5B5X1:
|
||||||
|
return { 4, {CH_R, CH_G, CH_B, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 };
|
||||||
|
case GFXFormatA8L8:
|
||||||
|
return { 2, {CH_L, CH_A, CH_NONE, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 };
|
||||||
|
case GFXFormatL16:
|
||||||
|
return { 1, {CH_L, CH_NONE, CH_NONE, CH_NONE}, STBIR_TYPE_UINT16, false, false, false, 2 };
|
||||||
|
case GFXFormatR16F:
|
||||||
|
return { 1, {CH_R, CH_NONE, CH_NONE, CH_NONE}, STBIR_TYPE_HALF_FLOAT, false, false, true, 2 };
|
||||||
|
case GFXFormatD16:
|
||||||
|
return { 1, {CH_L, CH_NONE, CH_NONE, CH_NONE}, STBIR_TYPE_UINT16, false, false, false, 2 };
|
||||||
|
|
||||||
|
// 24-bit formats
|
||||||
|
case GFXFormatR8G8B8:
|
||||||
|
return { 3, {CH_R, CH_G, CH_B, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 };
|
||||||
|
case GFXFormatR8G8B8_SRGB:
|
||||||
|
return { 3, {CH_R, CH_G, CH_B, CH_NONE}, STBIR_TYPE_UINT8_SRGB, true, false, false, 1 };
|
||||||
|
|
||||||
|
// 32-bit formats
|
||||||
|
case GFXFormatR8G8B8A8:
|
||||||
|
case GFXFormatR8G8B8X8:
|
||||||
|
return { 4, {CH_R, CH_G, CH_B, CH_A}, STBIR_TYPE_UINT8, false, false, false, 1 };
|
||||||
|
case GFXFormatB8G8R8A8:
|
||||||
|
return { 4, {CH_B, CH_G, CH_R, CH_A}, STBIR_TYPE_UINT8, false, false, false, 1 };
|
||||||
|
case GFXFormatR8G8B8A8_SRGB:
|
||||||
|
return { 4, {CH_R, CH_G, CH_B, CH_A}, STBIR_TYPE_UINT8_SRGB_ALPHA, true, false, false, 1 };
|
||||||
|
case GFXFormatR16G16:
|
||||||
|
return { 2, {CH_R, CH_G, CH_NONE, CH_NONE}, STBIR_TYPE_UINT16, false, false, false, 2 };
|
||||||
|
case GFXFormatR16G16F:
|
||||||
|
return { 2, {CH_R, CH_G, CH_NONE, CH_NONE}, STBIR_TYPE_HALF_FLOAT, false, false, true, 2 };
|
||||||
|
|
||||||
|
// 64-bit formats
|
||||||
|
case GFXFormatR16G16B16A16:
|
||||||
|
return { 4, {CH_R, CH_G, CH_B, CH_A}, STBIR_TYPE_UINT16, false, false, false, 2 };
|
||||||
|
case GFXFormatR16G16B16A16F:
|
||||||
|
return { 4, {CH_R, CH_G, CH_B, CH_A}, STBIR_TYPE_HALF_FLOAT, false, false, true, 2 };
|
||||||
|
|
||||||
|
// 128-bit formats
|
||||||
|
case GFXFormatR32G32B32A32F:
|
||||||
|
return { 4, {CH_R, CH_G, CH_B, CH_A}, STBIR_TYPE_FLOAT, false, false, true, 4 };
|
||||||
|
|
||||||
|
default: // fallback
|
||||||
|
return { 1, {CH_L, CH_NONE, CH_NONE, CH_NONE}, STBIR_TYPE_UINT8, false, false, false, 1 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// Conversion plan
|
||||||
|
struct ConversionPlan
|
||||||
|
{
|
||||||
|
bool bitDepthChange;
|
||||||
|
bool channelRepack;
|
||||||
|
bool colorspaceChange;
|
||||||
|
};
|
||||||
|
|
||||||
|
ConversionPlan decideConversion(const GBitmapFormatDesc& src, const GBitmapFormatDesc& dst)
|
||||||
|
{
|
||||||
|
ConversionPlan plan = {};
|
||||||
|
plan.bitDepthChange = src.bytesPerChannel != dst.bytesPerChannel || src.isFloat != dst.isFloat;
|
||||||
|
plan.channelRepack = src.channels != dst.channels || dMemcmp(src.semantic, dst.semantic, sizeof(src.semantic)) != 0;
|
||||||
|
plan.colorspaceChange = src.srgb != dst.srgb;
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// Linear representation
|
||||||
|
struct LinearPixel
|
||||||
|
{
|
||||||
|
float r = 0.f, g = 0.f, b = 0.f, a = 1.f;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline float srgbToLinear(float c)
|
||||||
|
{
|
||||||
|
return (c <= 0.04045f) ? c / 12.92f : powf((c + 0.055f) / 1.055f, 2.4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float linearToSrgb(float c)
|
||||||
|
{
|
||||||
|
return (c <= 0.0031308f) ? c * 12.92f : 1.055f * powf(c, 1.f / 2.4f) - 0.055f;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// Load a pixel from src format into LinearPixel
|
||||||
|
static inline LinearPixel loadPixel(const void* src, const GBitmapFormatDesc& fmt, U32 index)
|
||||||
|
{
|
||||||
|
LinearPixel p;
|
||||||
|
const U8* base = (const U8*)src + index * fmt.channels * fmt.bytesPerChannel;
|
||||||
|
|
||||||
|
for (U32 c = 0; c < fmt.channels; ++c)
|
||||||
|
{
|
||||||
|
float v = 0.f;
|
||||||
|
if (fmt.is8())
|
||||||
|
v = float(base[c]) / 255.f;
|
||||||
|
else if (fmt.is16())
|
||||||
|
v = float(convert16To8(*(const U16*)(base + c * 2))) / 255.f;
|
||||||
|
else if (fmt.isFloat)
|
||||||
{
|
{
|
||||||
for(U32 x = 0; x < width; x++)
|
if (fmt.bytesPerChannel == 2) // half float
|
||||||
{
|
v = convertHalfToFloat(*(const U16*)(base + c * 2));
|
||||||
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride+4]) + 2) >> 2;
|
else // full float
|
||||||
src++;
|
v = *(const float*)(base + c * 4);
|
||||||
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride+4]) + 2) >> 2;
|
}
|
||||||
src++;
|
|
||||||
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride+4]) + 2) >> 2;
|
if (fmt.srgb && fmt.semantic[c] != CH_A)
|
||||||
src++;
|
v = srgbToLinear(v);
|
||||||
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride+4]) + 2) >> 2;
|
|
||||||
src += 5;
|
switch (fmt.semantic[c])
|
||||||
}
|
{
|
||||||
src += stride; // skip
|
case CH_R: p.r = v; break;
|
||||||
|
case CH_G: p.g = v; break;
|
||||||
|
case CH_B: p.b = v; break;
|
||||||
|
case CH_A: p.a = v; break;
|
||||||
|
case CH_L: p.r = p.g = p.b = v; break;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
return p;
|
||||||
{
|
}
|
||||||
for(U32 y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
|
|
||||||
src++;
|
|
||||||
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
|
|
||||||
src++;
|
|
||||||
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
|
|
||||||
src++;
|
|
||||||
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
|
|
||||||
src += 5;
|
|
||||||
|
|
||||||
src += stride; // skip
|
//--------------------------------------------------------------------------------
|
||||||
|
// Store a LinearPixel into dst format
|
||||||
|
static inline void storePixel(void* dst, const GBitmapFormatDesc& fmt, U32 index, const LinearPixel& p)
|
||||||
|
{
|
||||||
|
U8* base = (U8*)dst + index * fmt.channels * fmt.bytesPerChannel;
|
||||||
|
for (U32 c = 0; c < fmt.channels; ++c)
|
||||||
|
{
|
||||||
|
float v = 0.f;
|
||||||
|
switch (fmt.semantic[c])
|
||||||
|
{
|
||||||
|
case CH_R: v = p.r; break;
|
||||||
|
case CH_G: v = p.g; break;
|
||||||
|
case CH_B: v = p.b; break;
|
||||||
|
case CH_A: v = p.a; break;
|
||||||
|
case CH_L: v = (p.r + p.g + p.b) / 3.f; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fmt.srgb && fmt.semantic[c] != CH_A)
|
||||||
|
v = linearToSrgb(v);
|
||||||
|
|
||||||
|
if (fmt.is8())
|
||||||
|
base[c] = uint8_t(mClamp(v * 255.f, 0.f, 255.f));
|
||||||
|
else if (fmt.is16())
|
||||||
|
*(U16*)(base + c * 2) = convert8To16(uint8_t(mClamp(v * 255.f, 0.f, 255.f)));
|
||||||
|
else if (fmt.isFloat)
|
||||||
|
{
|
||||||
|
if (fmt.bytesPerChannel == 2) // half float
|
||||||
|
*(U16*)(base + c * 2) = convertFloatToHalf(v);
|
||||||
|
else
|
||||||
|
*(float*)(base + c * 4) = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bitmapExtrudeFPRGBA_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth)
|
//--------------------------------------------------------------------------------
|
||||||
|
// Main generalized converter
|
||||||
|
bool bitmapConvertFormat(U8** srcBuffer, U32 pixels, const GBitmapFormatDesc& srcFmt, const GBitmapFormatDesc& dstFmt)
|
||||||
{
|
{
|
||||||
const U16 *src = (const U16 *)srcMip;
|
ConversionPlan plan = decideConversion(srcFmt, dstFmt);
|
||||||
U16 *dst = (U16 *)mip;
|
if (!plan.bitDepthChange && !plan.channelRepack && !plan.colorspaceChange)
|
||||||
U32 stride = srcHeight != 1 ? (srcWidth) * 8 : 0;
|
return true; // nothing to do
|
||||||
|
|
||||||
U32 width = srcWidth >> 1;
|
void* dstBuffer = *srcBuffer;
|
||||||
U32 height = srcHeight >> 1;
|
|
||||||
if (width == 0) width = 1;
|
|
||||||
if (height == 0) height = 1;
|
|
||||||
|
|
||||||
if (srcWidth != 1)
|
if (plan.bitDepthChange || plan.channelRepack)
|
||||||
|
dstBuffer = new U8[pixels * dstFmt.channels * dstFmt.bytesPerChannel];
|
||||||
|
|
||||||
|
for (U32 i = 0; i < pixels; ++i)
|
||||||
{
|
{
|
||||||
for (U32 y = 0; y < height; y++)
|
LinearPixel p = loadPixel(*srcBuffer, srcFmt, i);
|
||||||
{
|
storePixel(dstBuffer, dstFmt, i, p);
|
||||||
for (U32 x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride + 4]) + 2) >> 2;
|
|
||||||
src++;
|
|
||||||
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride + 4]) + 2) >> 2;
|
|
||||||
src++;
|
|
||||||
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride + 4]) + 2) >> 2;
|
|
||||||
src++;
|
|
||||||
*dst++ = (U32(*src) + U32(src[4]) + U32(src[stride]) + U32(src[stride + 4]) + 2) >> 2;
|
|
||||||
src += 5;
|
|
||||||
}
|
|
||||||
src += stride; // skip
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
for (U32 y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
|
|
||||||
src++;
|
|
||||||
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
|
|
||||||
src++;
|
|
||||||
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
|
|
||||||
src++;
|
|
||||||
*dst++ = (U32(*src) + U32(src[stride]) + 1) >> 1;
|
|
||||||
src += 5;
|
|
||||||
|
|
||||||
src += stride; // skip
|
if (dstBuffer != *srcBuffer)
|
||||||
}
|
{
|
||||||
|
delete[](U8*)* srcBuffer;
|
||||||
|
*srcBuffer = (U8*)dstBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void (*bitmapExtrude5551)(const void *srcMip, void *mip, U32 height, U32 width) = bitmapExtrude5551_c;
|
//--------------------------------------------------------------------------------
|
||||||
void (*bitmapExtrudeRGB)(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth) = bitmapExtrudeRGB_c;
|
// Entry point for GBitmap::setFormat
|
||||||
void (*bitmapExtrudeRGBA)(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth) = bitmapExtrudeRGBA_c;
|
bool bitmapALLConvertToOutput(U8** src, U32 pixels, GFXFormat srcFormat, GFXFormat dstFormat)
|
||||||
void (*bitmapExtrudeFPRGBA)(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth) = bitmapExtrudeFPRGBA_c;
|
{
|
||||||
|
const GBitmapFormatDesc& srcFmt = getFormatDesc(srcFormat);
|
||||||
|
const GBitmapFormatDesc& dstFmt = getFormatDesc(dstFormat);
|
||||||
|
return bitmapConvertFormat(src, pixels, srcFmt, dstFmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool(*bitmapConvertToOutput)(U8** src, U32 pixels, GFXFormat srcFormat, GFXFormat dstFormat) = bitmapALLConvertToOutput;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -238,7 +526,7 @@ void bitmapConvertRGB_to_1555_c(U8 *src, U32 pixels)
|
||||||
U32 g = src[1] >> 3;
|
U32 g = src[1] >> 3;
|
||||||
U32 b = src[2] >> 3;
|
U32 b = src[2] >> 3;
|
||||||
|
|
||||||
#if defined(TORQUE_OS_MAC)
|
#if defined(TORQUE_BIG_ENDIAN)
|
||||||
*dst++ = 0x8000 | (b << 10) | (g << 5) | (r << 0);
|
*dst++ = 0x8000 | (b << 10) | (g << 5) | (r << 0);
|
||||||
#else
|
#else
|
||||||
*dst++ = b | (g << 5) | (r << 10) | 0x8000;
|
*dst++ = b | (g << 5) | (r << 10) | 0x8000;
|
||||||
|
|
@ -260,7 +548,7 @@ void bitmapConvertRGB_to_5551_c(U8 *src, U32 pixels)
|
||||||
U32 g = src[1] >> 3;
|
U32 g = src[1] >> 3;
|
||||||
U32 b = src[2] >> 3;
|
U32 b = src[2] >> 3;
|
||||||
|
|
||||||
#if defined(TORQUE_OS_MAC)
|
#if defined(TORQUE_BIG_ENDIAN)
|
||||||
*dst++ = (1 << 15) | (b << 10) | (g << 5) | (r << 0);
|
*dst++ = (1 << 15) | (b << 10) | (g << 5) | (r << 0);
|
||||||
#else
|
#else
|
||||||
*dst++ = (b << 1) | (g << 6) | (r << 11) | 1;
|
*dst++ = (b << 1) | (g << 6) | (r << 11) | 1;
|
||||||
|
|
|
||||||
|
|
@ -22,21 +22,148 @@
|
||||||
|
|
||||||
#ifndef _BITMAPUTILS_H_
|
#ifndef _BITMAPUTILS_H_
|
||||||
#define _BITMAPUTILS_H_
|
#define _BITMAPUTILS_H_
|
||||||
|
#ifndef _PLATFORM_H_
|
||||||
|
#include "platform/platform.h"
|
||||||
|
#endif
|
||||||
#ifndef _TORQUE_TYPES_H_
|
#ifndef _TORQUE_TYPES_H_
|
||||||
#include "platform/types.h"
|
#include "platform/types.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef _GFXENUMS_H_
|
||||||
|
#include "gfx/gfxEnums.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _MMATHFN_H_
|
||||||
|
#include "math/mMathFn.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
extern void (*bitmapExtrude5551)(const void *srcMip, void *mip, U32 height, U32 width);
|
extern void (*bitmapExtrude5551)(const void *srcMip, void *mip, U32 height, U32 width);
|
||||||
extern void (*bitmapExtrudeRGB)(const void *srcMip, void *mip, U32 height, U32 width);
|
extern void (*bitmapExtrudeRGB)(const void *srcMip, void *mip, U32 height, U32 width, U32 bpp);
|
||||||
extern void (*bitmapExtrudeRGBA)(const void *srcMip, void *mip, U32 height, U32 width);
|
extern void (*bitmapExtrudeRGBA)(const void *srcMip, void *mip, U32 height, U32 width, U32 bpp);
|
||||||
extern void(*bitmapExtrudeFPRGBA)(const void *srcMip, void *mip, U32 height, U32 width);
|
extern void (*bitmapExtrude16BitRGBA)(const void *srcMip, void *mip, U32 height, U32 width, U32 bpp);
|
||||||
|
extern void(*bitmapExtrudeFPRGBA)(const void *srcMip, void *mip, U32 height, U32 width, U32 bpp);
|
||||||
|
extern void(*bitmapExtrudeF32RGBA)(const void *srcMip, void *mip, U32 height, U32 width, U32 bpp);
|
||||||
|
|
||||||
|
extern void(*bitmapResizeToOutput)(const void* src, U32 srcHeight, U32 srcWidth, void* out, U32 outHeight, U32 outWidth, U32 bpp, GFXFormat format);
|
||||||
|
extern bool(*bitmapConvertToOutput)(U8** src, U32 pixels, GFXFormat srcFormat, GFXFormat dstFormat);
|
||||||
|
|
||||||
extern void (*bitmapConvertRGB_to_5551)(U8 *src, U32 pixels);
|
extern void (*bitmapConvertRGB_to_5551)(U8 *src, U32 pixels);
|
||||||
extern void (*bitmapConvertRGB_to_1555)(U8 *src, U32 pixels);
|
extern void (*bitmapConvertRGB_to_1555)(U8 *src, U32 pixels);
|
||||||
extern void (*bitmapConvertRGB_to_RGBX)( U8 **src, U32 pixels );
|
extern void (*bitmapConvertRGB_to_RGBX)( U8 **src, U32 pixels );
|
||||||
extern void (*bitmapConvertRGBX_to_RGB)( U8 **src, U32 pixels );
|
extern void (*bitmapConvertRGBX_to_RGB)( U8 **src, U32 pixels );
|
||||||
extern void (*bitmapConvertA8_to_RGBA)( U8 **src, U32 pixels );
|
extern void (*bitmapConvertA8_to_RGBA)( U8 **src, U32 pixels );
|
||||||
|
|
||||||
void bitmapExtrudeRGB_c(const void *srcMip, void *mip, U32 height, U32 width);
|
//-----------------------------------------------------------------------------
|
||||||
|
// Half <-> Float Conversion Utilities
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
inline F32 convertHalfToFloat(U16 h)
|
||||||
|
{
|
||||||
|
U32 sign = (h >> 15) & 0x00000001;
|
||||||
|
U32 exp = (h >> 10) & 0x0000001F;
|
||||||
|
U32 mant = h & 0x000003FF;
|
||||||
|
|
||||||
|
U32 outSign = sign << 31;
|
||||||
|
U32 outExp, outMant;
|
||||||
|
|
||||||
|
if (exp == 0)
|
||||||
|
{
|
||||||
|
if (mant == 0)
|
||||||
|
{
|
||||||
|
// Zero
|
||||||
|
outExp = 0;
|
||||||
|
outMant = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Subnormal number -> normalize
|
||||||
|
exp = 1;
|
||||||
|
while ((mant & 0x00000400) == 0)
|
||||||
|
{
|
||||||
|
mant <<= 1;
|
||||||
|
exp -= 1;
|
||||||
|
}
|
||||||
|
mant &= 0x000003FF;
|
||||||
|
outExp = (exp + (127 - 15)) << 23;
|
||||||
|
outMant = mant << 13;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (exp == 31)
|
||||||
|
{
|
||||||
|
// Inf or NaN
|
||||||
|
outExp = 0xFF << 23;
|
||||||
|
outMant = mant ? (mant << 13) : 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Normalized
|
||||||
|
outExp = (exp + (127 - 15)) << 23;
|
||||||
|
outMant = mant << 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 out = outSign | outExp | outMant;
|
||||||
|
F32 result;
|
||||||
|
dMemcpy(&result, &out, sizeof(F32));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline U16 convertFloatToHalf(F32 f)
|
||||||
|
{
|
||||||
|
U32 bits;
|
||||||
|
dMemcpy(&bits, &f, sizeof(U32));
|
||||||
|
|
||||||
|
U32 sign = (bits >> 16) & 0x00008000;
|
||||||
|
U32 exp = ((bits >> 23) & 0x000000FF) - (127 - 15);
|
||||||
|
U32 mant = bits & 0x007FFFFF;
|
||||||
|
|
||||||
|
if (exp <= 0)
|
||||||
|
{
|
||||||
|
if (exp < -10)
|
||||||
|
return (U16)sign; // Too small => 0
|
||||||
|
mant = (mant | 0x00800000) >> (1 - exp);
|
||||||
|
return (U16)(sign | (mant >> 13));
|
||||||
|
}
|
||||||
|
else if (exp == 0xFF - (127 - 15))
|
||||||
|
{
|
||||||
|
if (mant == 0)
|
||||||
|
{
|
||||||
|
// Inf
|
||||||
|
return (U16)(sign | 0x7C00);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// NaN
|
||||||
|
mant >>= 13;
|
||||||
|
return (U16)(sign | 0x7C00 | mant | (mant == 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (exp > 30)
|
||||||
|
{
|
||||||
|
// Overflow => Inf
|
||||||
|
return (U16)(sign | 0x7C00);
|
||||||
|
}
|
||||||
|
return (U16)(sign | (exp << 10) | (mant >> 13));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a single 16-bit value (0..65535) to 8-bit (0..255)
|
||||||
|
inline U8 convert16To8(U16 v16)
|
||||||
|
{
|
||||||
|
// Take the top 8 bits as approximation
|
||||||
|
return U8(v16 >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a single 8-bit value (0..255) to 16-bit (0..65535)
|
||||||
|
inline U16 convert8To16(U8 v8)
|
||||||
|
{
|
||||||
|
// Replicate into high and low byte: 0->0, 255->0xFFFF
|
||||||
|
return (U16(v8) << 8) | v8;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline U8 floatTo8(F32 v)
|
||||||
|
{
|
||||||
|
return U8(mClamp(v * 255.f, 0.f, 255.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif //_BITMAPUTILS_H_
|
#endif //_BITMAPUTILS_H_
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,7 @@
|
||||||
|
|
||||||
namespace CubemapSaver
|
namespace CubemapSaver
|
||||||
{
|
{
|
||||||
const U32 CubeFaces = 6;
|
bool save(GFXTexHandle cubemap, const Torque::Path &path, GFXFormat compressionFormat)
|
||||||
|
|
||||||
bool save(GFXCubemapHandle cubemap, const Torque::Path &path, GFXFormat compressionFormat)
|
|
||||||
{
|
{
|
||||||
if (!cubemap.isValid())
|
if (!cubemap.isValid())
|
||||||
{
|
{
|
||||||
|
|
@ -44,43 +42,24 @@ namespace CubemapSaver
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GFXCubemap *pCubemap = cubemap.getPointer();
|
|
||||||
const U32 faceSize = pCubemap->getSize();
|
|
||||||
const U32 mipLevels = pCubemap->getMipMapLevels();
|
|
||||||
|
|
||||||
GFXFormat targetFmt = pCubemap->getFormat();
|
|
||||||
//setup render targets
|
|
||||||
GFXTexHandle pTextures[CubeFaces];
|
|
||||||
|
|
||||||
for (U32 face = 0; face < CubeFaces; face++)
|
|
||||||
{
|
|
||||||
pTextures[face].set(faceSize, faceSize, targetFmt,
|
|
||||||
&GFXTexturePersistentProfile, avar("%s() - (line %d)", __FUNCTION__, __LINE__),
|
|
||||||
mipLevels, GFXTextureManager::AA_MATCH_BACKBUFFER);
|
|
||||||
|
|
||||||
// yep t3d has funky z up, need to change the face order
|
|
||||||
GFX->copyResource(pTextures[face], pCubemap, GFXCubemap::zUpFaceIndex(face) );
|
|
||||||
}
|
|
||||||
|
|
||||||
GBitmap *pBitmaps[CubeFaces];
|
|
||||||
bool error = false;
|
bool error = false;
|
||||||
const bool compressedFormat = ImageUtil::isCompressedFormat(compressionFormat);
|
const bool compressedFormat = ImageUtil::isCompressedFormat(compressionFormat);
|
||||||
|
const U32 faceSize = cubemap->getWidth();
|
||||||
|
const U32 mipLevels = cubemap->getMipLevels();
|
||||||
|
GFXFormat targetFmt = cubemap->getFormat();
|
||||||
const bool hasMips = mipLevels > 1 ? true : false;
|
const bool hasMips = mipLevels > 1 ? true : false;
|
||||||
for (U32 i = 0; i < CubeFaces; i++)
|
|
||||||
|
GBitmap* temp = new GBitmap(faceSize, faceSize, hasMips, targetFmt, 6);
|
||||||
|
bool result = cubemap.copyToBmp(temp);
|
||||||
|
if (!result)
|
||||||
{
|
{
|
||||||
pBitmaps[i] = new GBitmap(faceSize, faceSize, hasMips, targetFmt);
|
Con::errorf("CubemapSaver: cubemap failed to copy");
|
||||||
bool result = pTextures[i].copyToBmp(pBitmaps[i]);
|
error = true;
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
Con::errorf("CubemapSaver: cubemap number %u failed to copy", i);
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!error)
|
if (!error)
|
||||||
{
|
{
|
||||||
DDSFile *pDds = DDSFile::createDDSCubemapFileFromGBitmaps(pBitmaps);
|
DDSFile *pDds = DDSFile::createDDSFileFromGBitmap(temp);
|
||||||
if (pDds)
|
if (pDds)
|
||||||
{
|
{
|
||||||
// compressed and floating point don't need swizzling
|
// compressed and floating point don't need swizzling
|
||||||
|
|
@ -103,14 +82,12 @@ namespace CubemapSaver
|
||||||
}
|
}
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
for (U32 i = 0; i < CubeFaces; i++)
|
SAFE_DELETE(temp);
|
||||||
SAFE_DELETE(pBitmaps[i]);
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getBitmaps(GFXCubemapHandle cubemap, GFXFormat compressionFormat, GBitmap* faceBitmaps[6])
|
bool getBitmaps(GFXTexHandle cubemap, GFXFormat compressionFormat, GBitmap* faceBitmaps[6])
|
||||||
{
|
{
|
||||||
if (!cubemap.isValid())
|
if (!cubemap.isValid())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,9 @@
|
||||||
namespace CubemapSaver
|
namespace CubemapSaver
|
||||||
{
|
{
|
||||||
// save cubemap handle to a dds cubemap with optional compression
|
// save cubemap handle to a dds cubemap with optional compression
|
||||||
bool save(GFXCubemapHandle cubemap, const Torque::Path &path, GFXFormat compressionFormat = GFXFormatR8G8B8A8);
|
bool save(GFXTexHandle cubemap, const Torque::Path &path, GFXFormat compressionFormat = GFXFormatR8G8B8A8);
|
||||||
|
|
||||||
bool getBitmaps(GFXCubemapHandle cubemap, GFXFormat compressionFormat, GBitmap* faceBitmaps[6]);
|
bool getBitmaps(GFXTexHandle cubemap, GFXFormat compressionFormat, GBitmap* faceBitmaps[6]);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -652,6 +652,12 @@ Resource<DDSFile> DDSFile::load( const Torque::Path &path, U32 dropMipCount )
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool DDSFile::isCompressedFormat(GFXFormat fmt)
|
||||||
|
{
|
||||||
|
return (fmt >= GFXFormatBC1 && fmt <= GFXFormatBC5) ||
|
||||||
|
(fmt >= GFXFormatBC1_SRGB && fmt <= GFXFormatBC3_SRGB);
|
||||||
|
}
|
||||||
|
|
||||||
DDSFile *DDSFile::createDDSFileFromGBitmap( const GBitmap *gbmp )
|
DDSFile *DDSFile::createDDSFileFromGBitmap( const GBitmap *gbmp )
|
||||||
{
|
{
|
||||||
if( gbmp == NULL )
|
if( gbmp == NULL )
|
||||||
|
|
@ -666,6 +672,11 @@ DDSFile *DDSFile::createDDSFileFromGBitmap( const GBitmap *gbmp )
|
||||||
ret->mDepth = 0;
|
ret->mDepth = 0;
|
||||||
ret->mFormat = gbmp->getFormat();
|
ret->mFormat = gbmp->getFormat();
|
||||||
ret->mFlags.set(RGBData);
|
ret->mFlags.set(RGBData);
|
||||||
|
if (gbmp->getNumFaces() == 6)
|
||||||
|
{
|
||||||
|
ret->mFlags.set(RGBData | CubeMapFlag | CubeMap_PosX_Flag | CubeMap_NegX_Flag | CubeMap_PosY_Flag |
|
||||||
|
CubeMap_NegY_Flag | CubeMap_PosZ_Flag | CubeMap_NegZ_Flag);
|
||||||
|
}
|
||||||
ret->mBytesPerPixel = gbmp->getBytesPerPixel();
|
ret->mBytesPerPixel = gbmp->getBytesPerPixel();
|
||||||
ret->mMipMapCount = gbmp->getNumMipLevels();
|
ret->mMipMapCount = gbmp->getNumMipLevels();
|
||||||
ret->mHasTransparency = gbmp->getHasTransparency();
|
ret->mHasTransparency = gbmp->getHasTransparency();
|
||||||
|
|
@ -685,36 +696,39 @@ DDSFile *DDSFile::createDDSFileFromGBitmap( const GBitmap *gbmp )
|
||||||
if( ret->mMipMapCount > 1 )
|
if( ret->mMipMapCount > 1 )
|
||||||
ret->mFlags.set(MipMapsFlag);
|
ret->mFlags.set(MipMapsFlag);
|
||||||
|
|
||||||
// One surface per GBitmap
|
for (U32 face = 0; face < gbmp->getNumFaces(); face++)
|
||||||
ret->mSurfaces.push_back( new SurfaceData() );
|
|
||||||
|
|
||||||
// Load the mips
|
|
||||||
for( S32 i = 0; i < ret->mMipMapCount; i++ )
|
|
||||||
{
|
{
|
||||||
const U32 mipSz = ret->getSurfaceSize(i);
|
// One surface per GBitmap
|
||||||
ret->mSurfaces.last()->mMips.push_back( new U8[mipSz] );
|
ret->mSurfaces.push_back(new SurfaceData());
|
||||||
|
|
||||||
U8 *mipMem = ret->mSurfaces.last()->mMips.last();
|
// Load the mips
|
||||||
|
for (S32 i = 0; i < ret->mMipMapCount; i++)
|
||||||
// If this is a straight copy, just do it, otherwise (ugh)
|
|
||||||
if( ret->mFormat == gbmp->getFormat() )
|
|
||||||
dMemcpy( mipMem, gbmp->getBits(i), mipSz );
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Assumption:
|
const U32 mipSz = ret->getSurfaceSize(i);
|
||||||
AssertFatal( gbmp->getBytesPerPixel() + 1 == ret->mBytesPerPixel, "Assumption failed, not 24->32 bit straight convert." );
|
ret->mSurfaces.last()->mMips.push_back(new U8[mipSz]);
|
||||||
|
|
||||||
for( S32 pxl = 0; pxl < gbmp->getWidth(i) * gbmp->getHeight(i); pxl++ )
|
U8* mipMem = ret->mSurfaces.last()->mMips.last();
|
||||||
|
|
||||||
|
// If this is a straight copy, just do it, otherwise (ugh)
|
||||||
|
if (ret->mFormat == gbmp->getFormat())
|
||||||
|
dMemcpy(mipMem, gbmp->getBits(i, face), mipSz);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
U8 *dst = &mipMem[pxl * ret->mBytesPerPixel];
|
// Assumption:
|
||||||
const U8 *src = &gbmp->getBits(i)[pxl * gbmp->getBytesPerPixel()];
|
AssertFatal(gbmp->getBytesPerPixel() + 1 == ret->mBytesPerPixel, "Assumption failed, not 24->32 bit straight convert.");
|
||||||
dMemcpy( dst, src, gbmp->getBytesPerPixel() * sizeof(U8) );
|
|
||||||
dst[ret->mBytesPerPixel - 1] = 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uncomment to debug-dump each mip level
|
for (S32 pxl = 0; pxl < gbmp->getWidth(i) * gbmp->getHeight(i); pxl++)
|
||||||
//ret->mSurfaces.last()->dumpImage( ret, i, avar( "%d_Gbmp_xmip%d", ret, i ) );
|
{
|
||||||
|
U8* dst = &mipMem[pxl * ret->mBytesPerPixel];
|
||||||
|
const U8* src = &gbmp->getBits(i, face)[pxl * gbmp->getBytesPerPixel()];
|
||||||
|
dMemcpy(dst, src, gbmp->getBytesPerPixel() * sizeof(U8));
|
||||||
|
dst[ret->mBytesPerPixel - 1] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uncomment to debug-dump each mip level
|
||||||
|
//ret->mSurfaces.last()->dumpImage( ret, i, avar( "%d_Gbmp_xmip%d", ret, i ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -777,22 +791,50 @@ DDSFile *DDSFile::createDDSCubemapFileFromGBitmaps(GBitmap **gbmps)
|
||||||
|
|
||||||
bool DDSFile::decompressToGBitmap(GBitmap *dest)
|
bool DDSFile::decompressToGBitmap(GBitmap *dest)
|
||||||
{
|
{
|
||||||
|
const bool isCube = isCubemap();
|
||||||
|
const U32 numFaces = isCube ? 6 : 1;
|
||||||
// TBD: do we support other formats?
|
// TBD: do we support other formats?
|
||||||
if (mFormat != GFXFormatBC1 && mFormat != GFXFormatBC2 && mFormat != GFXFormatBC3)
|
if (!isCompressedFormat(mFormat))
|
||||||
return false;
|
{
|
||||||
|
dest->allocateBitmapWithMips(getWidth(), getHeight(), getMipLevels(), mFormat, numFaces);
|
||||||
|
U32 numMips = getMipLevels();
|
||||||
|
|
||||||
dest->allocateBitmapWithMips(getWidth(), getHeight(), getMipLevels(), GFXFormatR8G8B8A8);
|
for (U32 face = 0; face < numFaces; face++)
|
||||||
|
{
|
||||||
|
for (U32 i = 0; i < numMips; i++)
|
||||||
|
{
|
||||||
|
U8* addr = dest->getAddress(0, 0, i, face);
|
||||||
|
|
||||||
|
const U8* mipBuffer = mSurfaces[face]->mMips[i];
|
||||||
|
const U32 mipWidth = getWidth(i);
|
||||||
|
const U32 mipHeight = getHeight(i);
|
||||||
|
|
||||||
|
const U32 bpp = dest->getBytesPerPixel();
|
||||||
|
const U32 rowBytes = mipWidth * bpp;
|
||||||
|
|
||||||
|
for (U32 y = 0; y < mipHeight; ++y)
|
||||||
|
{
|
||||||
|
dMemcpy(addr + y * rowBytes, mipBuffer + y * rowBytes, rowBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest->allocateBitmapWithMips(getWidth(), getHeight(), getMipLevels(), GFXFormatR8G8B8A8, numFaces);
|
||||||
|
|
||||||
// Decompress and copy mips...
|
// Decompress and copy mips...
|
||||||
|
|
||||||
U32 numMips = getMipLevels();
|
U32 numMips = getMipLevels();
|
||||||
|
for (U32 face = 0; face < numFaces; face++)
|
||||||
for (U32 i = 0; i < numMips; i++)
|
|
||||||
{
|
{
|
||||||
U8 *addr = dest->getAddress(0, 0, i);
|
for (U32 i = 0; i < numMips; i++)
|
||||||
const U8 *mipBuffer = mSurfaces[0]->mMips[i];
|
{
|
||||||
ImageUtil::decompress(mipBuffer, addr, getWidth(i), getHeight(i), mFormat);
|
U8* addr = dest->getAddress(0, 0, i, face);
|
||||||
|
const U8* mipBuffer = mSurfaces[face]->mMips[i];
|
||||||
|
ImageUtil::decompress(mipBuffer, addr, getWidth(i), getHeight(i), mFormat);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,8 @@ struct DDSFile
|
||||||
mSurfaces.clear();
|
mSurfaces.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isCompressedFormat(GFXFormat fmt);
|
||||||
|
|
||||||
static DDSFile *createDDSFileFromGBitmap( const GBitmap *gbmp );
|
static DDSFile *createDDSFileFromGBitmap( const GBitmap *gbmp );
|
||||||
//Create a single cubemap texture from 6 GBitmap
|
//Create a single cubemap texture from 6 GBitmap
|
||||||
static DDSFile *createDDSCubemapFileFromGBitmaps(GBitmap **gbmps);
|
static DDSFile *createDDSCubemapFileFromGBitmaps(GBitmap **gbmps);
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -135,13 +135,15 @@ public:
|
||||||
GBitmap(const U32 in_width,
|
GBitmap(const U32 in_width,
|
||||||
const U32 in_height,
|
const U32 in_height,
|
||||||
const bool in_extrudeMipLevels = false,
|
const bool in_extrudeMipLevels = false,
|
||||||
const GFXFormat in_format = GFXFormatR8G8B8 );
|
const GFXFormat in_format = GFXFormatR8G8B8,
|
||||||
|
const U32 in_numFaces = 1);
|
||||||
|
|
||||||
// This builds a GBitmap with the R8G8B8A8 format using the passed in
|
// This builds a GBitmap with the R8G8B8A8 format using the passed in
|
||||||
// data (assumes that there is width * height * 4 U8's in data)
|
// data (assumes that there is width * height * 4 U8's in data)
|
||||||
GBitmap(const U32 in_width,
|
GBitmap(const U32 in_width,
|
||||||
const U32 in_height,
|
const U32 in_height,
|
||||||
const U8* data );
|
const U8* data,
|
||||||
|
const U32 in_numFaces = 1);
|
||||||
|
|
||||||
virtual ~GBitmap();
|
virtual ~GBitmap();
|
||||||
|
|
||||||
|
|
@ -163,12 +165,14 @@ public:
|
||||||
void allocateBitmap(const U32 in_width,
|
void allocateBitmap(const U32 in_width,
|
||||||
const U32 in_height,
|
const U32 in_height,
|
||||||
const bool in_extrudeMipLevels = false,
|
const bool in_extrudeMipLevels = false,
|
||||||
const GFXFormat in_format = GFXFormatR8G8B8 );
|
const GFXFormat in_format = GFXFormatR8G8B8,
|
||||||
|
const U32 in_numFaces = 1);
|
||||||
|
|
||||||
void allocateBitmapWithMips(const U32 in_width,
|
void allocateBitmapWithMips(const U32 in_width,
|
||||||
const U32 in_height,
|
const U32 in_height,
|
||||||
const U32 in_numMips,
|
const U32 in_numMips,
|
||||||
const GFXFormat in_format = GFXFormatR8G8B8);
|
const GFXFormat in_format = GFXFormatR8G8B8,
|
||||||
|
const U32 in_numFaces = 1);
|
||||||
|
|
||||||
void extrudeMipLevels(bool clearBorders = false);
|
void extrudeMipLevels(bool clearBorders = false);
|
||||||
void chopTopMips(U32 mipsToChop);
|
void chopTopMips(U32 mipsToChop);
|
||||||
|
|
@ -191,16 +195,18 @@ public:
|
||||||
|
|
||||||
U32 getWidth(const U32 in_mipLevel = 0) const;
|
U32 getWidth(const U32 in_mipLevel = 0) const;
|
||||||
U32 getHeight(const U32 in_mipLevel = 0) const;
|
U32 getHeight(const U32 in_mipLevel = 0) const;
|
||||||
|
U32 _getFaceOffset(const U32 face = 0) const;
|
||||||
U32 getDepth(const U32 in_mipLevel = 0) const;
|
U32 getDepth(const U32 in_mipLevel = 0) const;
|
||||||
|
|
||||||
U8* getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel = 0);
|
U8* getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel = 0, const U32 face = 0);
|
||||||
const U8* getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel = 0) const;
|
const U8* getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel = 0, const U32 face = 0) const;
|
||||||
|
|
||||||
const U8* getBits(const U32 in_mipLevel = 0) const;
|
const U8* getBits(const U32 in_mipLevel = 0, const U32 face = 0) const;
|
||||||
U8* getWritableBits(const U32 in_mipLevel = 0);
|
U8* getWritableBits(const U32 in_mipLevel = 0, const U32 face = 0);
|
||||||
|
|
||||||
U32 getByteSize() const { return mByteSize; }
|
U32 getByteSize() const { return mByteSize; }
|
||||||
U32 getBytesPerPixel() const { return mBytesPerPixel; }
|
U32 getBytesPerPixel() const { return mBytesPerPixel; }
|
||||||
|
U32 getFormatBytesPerPixel(GFXFormat fmt);
|
||||||
|
|
||||||
U32 getSurfaceSize(const U32 mipLevel) const;
|
U32 getSurfaceSize(const U32 mipLevel) const;
|
||||||
|
|
||||||
|
|
@ -220,6 +226,7 @@ public:
|
||||||
bool getColor(const U32 x, const U32 y, ColorI& rColor) const;
|
bool getColor(const U32 x, const U32 y, ColorI& rColor) const;
|
||||||
bool setColor(const U32 x, const U32 y, const ColorI& rColor);
|
bool setColor(const U32 x, const U32 y, const ColorI& rColor);
|
||||||
U8 getChanelValueAt(U32 x, U32 y, U32 chan);
|
U8 getChanelValueAt(U32 x, U32 y, U32 chan);
|
||||||
|
U32 getNumFaces() const { return mNumFaces; }
|
||||||
|
|
||||||
/// This method will combine bitmapA and bitmapB using the operation specified
|
/// This method will combine bitmapA and bitmapB using the operation specified
|
||||||
/// by combineOp. The result will be stored in the bitmap that this method is
|
/// by combineOp. The result will be stored in the bitmap that this method is
|
||||||
|
|
@ -275,7 +282,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GFXFormat mInternalFormat;
|
GFXFormat mInternalFormat;
|
||||||
|
U32 mNumFaces; // default 1, set to 6 for cubemap
|
||||||
U8* mBits; // Master bytes
|
U8* mBits; // Master bytes
|
||||||
U32 mByteSize;
|
U32 mByteSize;
|
||||||
U32 mWidth;
|
U32 mWidth;
|
||||||
|
|
@ -284,6 +291,7 @@ private:
|
||||||
|
|
||||||
U32 mNumMipLevels;
|
U32 mNumMipLevels;
|
||||||
U32 mMipLevelOffsets[c_maxMipLevels];
|
U32 mMipLevelOffsets[c_maxMipLevels];
|
||||||
|
U32 mFaceOffsets[6]; // Maximum 6 for cubemaps; could also dynamically allocate if needed
|
||||||
|
|
||||||
bool mHasTransparency;
|
bool mHasTransparency;
|
||||||
|
|
||||||
|
|
@ -316,32 +324,39 @@ inline U32 GBitmap::getHeight(const U32 in_mipLevel) const
|
||||||
return (retVal != 0) ? retVal : 1;
|
return (retVal != 0) ? retVal : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const U8* GBitmap::getBits(const U32 in_mipLevel) const
|
inline U32 GBitmap::_getFaceOffset(const U32 face) const
|
||||||
|
{
|
||||||
|
AssertFatal(face < mNumFaces, "GBitmap::_getFaceOffset: invalid face index");
|
||||||
|
|
||||||
|
return mFaceOffsets[face];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const U8* GBitmap::getBits(const U32 in_mipLevel, const U32 face) const
|
||||||
{
|
{
|
||||||
AssertFatal(in_mipLevel < mNumMipLevels,
|
AssertFatal(in_mipLevel < mNumMipLevels,
|
||||||
avar("GBitmap::getBits: mip level out of range: (%d, %d)",
|
avar("GBitmap::getBits: mip level out of range: (%d, %d)",
|
||||||
in_mipLevel, mNumMipLevels));
|
in_mipLevel, mNumMipLevels));
|
||||||
|
|
||||||
return &mBits[mMipLevelOffsets[in_mipLevel]];
|
return &mBits[_getFaceOffset(face) + mMipLevelOffsets[in_mipLevel]];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline U8* GBitmap::getWritableBits(const U32 in_mipLevel)
|
inline U8* GBitmap::getWritableBits(const U32 in_mipLevel, const U32 face)
|
||||||
{
|
{
|
||||||
AssertFatal(in_mipLevel < mNumMipLevels,
|
AssertFatal(in_mipLevel < mNumMipLevels,
|
||||||
avar("GBitmap::getWritableBits: mip level out of range: (%d, %d)",
|
avar("GBitmap::getWritableBits: mip level out of range: (%d, %d)",
|
||||||
in_mipLevel, mNumMipLevels));
|
in_mipLevel, mNumMipLevels));
|
||||||
|
|
||||||
return &mBits[mMipLevelOffsets[in_mipLevel]];
|
return &mBits[_getFaceOffset(face) + mMipLevelOffsets[in_mipLevel]];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline U8* GBitmap::getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel)
|
inline U8* GBitmap::getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel, const U32 face)
|
||||||
{
|
{
|
||||||
return (getWritableBits(mipLevel) + (U64)(((in_y * getWidth(mipLevel)) + in_x) * mBytesPerPixel));
|
return (getWritableBits(mipLevel, face) + (U64)(((in_y * getWidth(mipLevel)) + in_x) * mBytesPerPixel));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const U8* GBitmap::getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel) const
|
inline const U8* GBitmap::getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel, const U32 face) const
|
||||||
{
|
{
|
||||||
return (getBits(mipLevel) + ((in_y * getWidth(mipLevel)) + in_x) * mBytesPerPixel);
|
return (getBits(mipLevel, face) + ((in_y * getWidth(mipLevel)) + in_x) * mBytesPerPixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, dsize_t mapLength>
|
template<class T, dsize_t mapLength>
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "core/stream/memStream.h"
|
#include "core/stream/memStream.h"
|
||||||
#include "core/strings/stringFunctions.h"
|
#include "core/strings/stringFunctions.h"
|
||||||
#include "gfx/bitmap/gBitmap.h"
|
#include "gfx/bitmap/gBitmap.h"
|
||||||
|
#include "gfx/bitmap/bitmapUtils.h"
|
||||||
#include "gfx/bitmap/imageUtils.h"
|
#include "gfx/bitmap/imageUtils.h"
|
||||||
#include "gfx/bitmap/loaders/ies/ies_loader.h"
|
#include "gfx/bitmap/loaders/ies/ies_loader.h"
|
||||||
#include "platform/profiler.h"
|
#include "platform/profiler.h"
|
||||||
|
|
@ -41,12 +42,12 @@
|
||||||
#ifndef STB_IMAGE_IMPLEMENTATION
|
#ifndef STB_IMAGE_IMPLEMENTATION
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#define STB_IMAGE_STATIC
|
#define STB_IMAGE_STATIC
|
||||||
#include "stb_image.h"
|
#include "gfx/bitmap/loaders/stb/stb_image.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
#define STB_IMAGE_WRITE_STATIC
|
#define STB_IMAGE_WRITE_STATIC
|
||||||
#include "stb_image_write.h"
|
#include "gfx/bitmap/loaders/stb/stb_image_write.h"
|
||||||
|
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|
||||||
|
|
@ -56,6 +57,38 @@ static bool sReadStreamSTB(Stream& stream, GBitmap* bitmap, U32 len);
|
||||||
static bool sWriteSTB(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel);
|
static bool sWriteSTB(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel);
|
||||||
static bool sWriteStreamSTB(const String& bmType, Stream& stream, GBitmap* bitmap, U32 compressionLevel);
|
static bool sWriteStreamSTB(const String& bmType, Stream& stream, GBitmap* bitmap, U32 compressionLevel);
|
||||||
|
|
||||||
|
static GFXFormat determineFormat(bool isHDR, bool is16Bit, int numChannels)
|
||||||
|
{
|
||||||
|
if (isHDR)
|
||||||
|
{
|
||||||
|
// we force hdr to 4 channels.
|
||||||
|
return GFXFormatR32G32B32A32F;
|
||||||
|
}
|
||||||
|
else if (is16Bit)
|
||||||
|
{
|
||||||
|
switch (numChannels)
|
||||||
|
{
|
||||||
|
case 1: return GFXFormatL16;
|
||||||
|
case 2: return GFXFormatA8L8; // No native L16A16, but could add one later
|
||||||
|
case 3: return GFXFormatR16G16B16A16;
|
||||||
|
case 4: return GFXFormatR16G16B16A16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // 8-bit
|
||||||
|
{
|
||||||
|
switch (numChannels)
|
||||||
|
{
|
||||||
|
case 1: return GFXFormatA8;
|
||||||
|
case 2: return GFXFormatA8L8;
|
||||||
|
case 3: return GFXFormatR8G8B8;
|
||||||
|
case 4: return GFXFormatR8G8B8A8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback
|
||||||
|
return GFXFormatR8G8B8A8;
|
||||||
|
}
|
||||||
|
|
||||||
// stbi_write callback / rextimmy.
|
// stbi_write callback / rextimmy.
|
||||||
static void stbiWriteFunc(void* context, void* data, int size)
|
static void stbiWriteFunc(void* context, void* data, int size)
|
||||||
{
|
{
|
||||||
|
|
@ -210,119 +243,55 @@ bool sReadSTB(const Torque::Path& path, GBitmap* bitmap)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stbi_info(path.getFullPath().c_str(), &x, &y, &channels))
|
const char* filePath = path.getFullPath().c_str();
|
||||||
{
|
|
||||||
const char* stbErr = stbi_failure_reason();
|
|
||||||
|
|
||||||
if (!stbErr)
|
// Detect format
|
||||||
stbErr = "Unknown Error!";
|
bool isHDR = stbi_is_hdr(filePath);
|
||||||
|
bool is16Bit = stbi_is_16_bit(filePath);
|
||||||
|
|
||||||
Con::errorf("STB get file info: %s", stbErr);
|
void* data = nullptr;
|
||||||
|
|
||||||
|
if (isHDR) {
|
||||||
|
data = stbi_loadf(filePath, &x, &y, &n, 4);
|
||||||
}
|
}
|
||||||
|
else if (is16Bit)
|
||||||
|
data = stbi_load_16(filePath, &x, &y, &n, 0);
|
||||||
|
else
|
||||||
|
data = stbi_load(filePath, &x, &y, &n, 0);
|
||||||
|
|
||||||
// do this to map 2 channels to 4, 2 channel not supported by gbitmap yet..
|
if (!data)
|
||||||
if (channels == 2)
|
|
||||||
channels = 4;
|
|
||||||
if (!ext.equal("png"))
|
|
||||||
{
|
{
|
||||||
if (stbi_is_16_bit(path.getFullPath().c_str()))
|
|
||||||
{
|
|
||||||
U16* data = stbi_load_16(path.getFullPath().c_str(), &x, &y, &n, channels);
|
|
||||||
|
|
||||||
// if succesful deal make the bitmap, else try other loaders.
|
|
||||||
if (data)
|
|
||||||
{
|
|
||||||
GFXFormat format;
|
|
||||||
if (n == 1)
|
|
||||||
format = GFXFormatL16;
|
|
||||||
else
|
|
||||||
format = GFXFormatR16G16B16A16; // not sure if this is correct.
|
|
||||||
|
|
||||||
bitmap->deleteImage();
|
|
||||||
|
|
||||||
// actually allocate the bitmap space...
|
|
||||||
bitmap->allocateBitmap(x, y,
|
|
||||||
false, // don't extrude miplevels...
|
|
||||||
format); // use determined format...
|
|
||||||
|
|
||||||
U16* pBase = (U16*)bitmap->getBits();
|
|
||||||
|
|
||||||
U32 rowBytes = bitmap->getByteSize();
|
|
||||||
|
|
||||||
dMemcpy(pBase, data, rowBytes);
|
|
||||||
|
|
||||||
stbi_image_free(data);
|
|
||||||
|
|
||||||
PROFILE_END();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ext.equal("hdr"))
|
|
||||||
{
|
|
||||||
// force load to 4 channel.
|
|
||||||
float* data = stbi_loadf(path.getFullPath().c_str(), &x, &y, &n, 0);
|
|
||||||
|
|
||||||
unsigned char* dataChar = stbi__hdr_to_ldr(data, x, y, n);
|
|
||||||
bitmap->deleteImage();
|
|
||||||
// actually allocate the bitmap space...
|
|
||||||
bitmap->allocateBitmap(x, y,
|
|
||||||
false,
|
|
||||||
GFXFormatR8G8B8);
|
|
||||||
|
|
||||||
U8* pBase = (U8*)bitmap->getBits();
|
|
||||||
|
|
||||||
U32 rowBytes = x * y * n;
|
|
||||||
|
|
||||||
dMemcpy(pBase, dataChar, rowBytes);
|
|
||||||
|
|
||||||
//stbi_image_free(data);
|
|
||||||
stbi_image_free(dataChar);
|
|
||||||
|
|
||||||
PROFILE_END();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char* data = stbi_load(path.getFullPath().c_str(), &x, &y, &n, channels);
|
|
||||||
|
|
||||||
bitmap->deleteImage();
|
|
||||||
|
|
||||||
GFXFormat format;
|
|
||||||
|
|
||||||
switch (channels) {
|
|
||||||
case 1:
|
|
||||||
format = GFXFormatA8;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
format = GFXFormatA8L8;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
format = GFXFormatR8G8B8;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
format = GFXFormatR8G8B8A8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PROFILE_END();
|
PROFILE_END();
|
||||||
|
Con::errorf("sReadSTB() - Failed to load %s: %s", filePath, stbi_failure_reason());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// actually allocate the bitmap space...
|
// Determine internal GFX format
|
||||||
bitmap->allocateBitmap(x, y,
|
GFXFormat format = determineFormat(isHDR, is16Bit, n);
|
||||||
false, // don't extrude miplevels...
|
|
||||||
format); // use determined format...
|
|
||||||
|
|
||||||
U8* pBase = (U8*)bitmap->getBits();
|
// Allocate bitmap
|
||||||
|
bitmap->deleteImage();
|
||||||
|
bitmap->allocateBitmap(x, y, false, format);
|
||||||
|
|
||||||
U32 rowBytes = bitmap->getByteSize();
|
//if (isHDR)
|
||||||
|
//{
|
||||||
dMemcpy(pBase, data, rowBytes);
|
// U16* pBase = (U16*)bitmap->getBits();
|
||||||
|
// const size_t totalPixels = (size_t)x * (size_t)y;
|
||||||
|
// for (size_t i = 0; i < totalPixels * 4; ++i)
|
||||||
|
// {
|
||||||
|
// pBase[i] = convertFloatToHalf(reinterpret_cast<F32*>(data)[i]); // convert F32 -> U16
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
U8* dst = (U8*)bitmap->getBits();
|
||||||
|
U32 byteSize = bitmap->getByteSize();
|
||||||
|
dMemcpy(dst, data, byteSize);
|
||||||
|
//}
|
||||||
|
|
||||||
stbi_image_free(data);
|
stbi_image_free(data);
|
||||||
// Check this bitmap for transparency
|
|
||||||
if (channels == 4)
|
bitmap->checkForTransparency();
|
||||||
bitmap->checkForTransparency();
|
|
||||||
|
|
||||||
PROFILE_END();
|
PROFILE_END();
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -331,45 +300,36 @@ bool sReadSTB(const Torque::Path& path, GBitmap* bitmap)
|
||||||
bool sReadStreamSTB(Stream& stream, GBitmap* bitmap, U32 len)
|
bool sReadStreamSTB(Stream& stream, GBitmap* bitmap, U32 len)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPE(sReadStreamSTB);
|
PROFILE_SCOPE(sReadStreamSTB);
|
||||||
// only used for font at the moment.
|
|
||||||
|
|
||||||
U8* data = new U8[len];
|
Vector<U8> data(len);
|
||||||
stream.read(len, data);
|
stream.read(len, data.address());
|
||||||
|
|
||||||
S32 width, height, comp = 0;
|
int x, y, n;
|
||||||
|
bool isHDR = stbi_is_hdr_from_memory(data.address(), len);
|
||||||
|
bool is16Bit = stbi_is_16_bit_from_memory(data.address(), len);
|
||||||
|
|
||||||
unsigned char* pixelData = stbi_load_from_memory((const U8*)data, (int)len, &width, &height, &comp, 0);
|
void* pixels = nullptr;
|
||||||
|
if (isHDR)
|
||||||
|
pixels = stbi_loadf_from_memory(data.address(), len, &x, &y, &n, 0);
|
||||||
|
else if (is16Bit)
|
||||||
|
pixels = stbi_load_16_from_memory(data.address(), len, &x, &y, &n, 0);
|
||||||
|
else
|
||||||
|
pixels = stbi_load_from_memory(data.address(), len, &x, &y, &n, 0);
|
||||||
|
|
||||||
if (!pixelData)
|
if (!pixels)
|
||||||
{
|
{
|
||||||
const char* stbErr = stbi_failure_reason();
|
Con::errorf("sReadStreamSTB() - STB load failed: %s", stbi_failure_reason());
|
||||||
|
|
||||||
if (!stbErr)
|
|
||||||
stbErr = "Unknown Error!";
|
|
||||||
|
|
||||||
Con::errorf("sReadStreamSTB Error: %s", stbErr);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GFXFormat format = determineFormat(isHDR, is16Bit, n);
|
||||||
bitmap->deleteImage();
|
bitmap->deleteImage();
|
||||||
|
bitmap->allocateBitmap(x, y, false, format);
|
||||||
|
dMemcpy(bitmap->getWritableBits(0), pixels, bitmap->getByteSize());
|
||||||
|
|
||||||
//work out what format we need to use - todo floating point?
|
stbi_image_free(pixels);
|
||||||
GFXFormat fmt = GFXFormat_FIRST;
|
|
||||||
switch (comp)
|
|
||||||
{
|
|
||||||
case 1: fmt = GFXFormatA8; break;
|
|
||||||
case 2: fmt = GFXFormatA8L8; break; //todo check this
|
|
||||||
case 3: fmt = GFXFormatR8G8B8; break;
|
|
||||||
case 4: fmt = GFXFormatR8G8B8A8; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bitmap->allocateBitmap(width, height, false, fmt);
|
bitmap->checkForTransparency();
|
||||||
|
|
||||||
U8* pBase = bitmap->getWritableBits(0);
|
|
||||||
U32 rowBytes = bitmap->getByteSize();
|
|
||||||
dMemcpy(pBase, pixelData, rowBytes);
|
|
||||||
|
|
||||||
dFree(data);
|
|
||||||
dFree(pixelData);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -401,47 +361,34 @@ bool sWriteSTB(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel)
|
||||||
GFXFormat format = bitmap->getFormat();
|
GFXFormat format = bitmap->getFormat();
|
||||||
String ext = path.getExtension();
|
String ext = path.getExtension();
|
||||||
|
|
||||||
|
|
||||||
// we always have at least 1
|
|
||||||
U32 comp = 1;
|
|
||||||
|
|
||||||
if (format == GFXFormatR8G8B8)
|
|
||||||
{
|
|
||||||
comp = 3;
|
|
||||||
}
|
|
||||||
else if (format == GFXFormatR8G8B8A8 || format == GFXFormatR8G8B8X8 || format == GFXFormatR8G8B8A8_LINEAR_FORCE)
|
|
||||||
{
|
|
||||||
comp = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ext.equal("png"))
|
if (ext.equal("png"))
|
||||||
{
|
{
|
||||||
stbi_write_png_compression_level = compressionLevel;
|
stbi_write_png_compression_level = compressionLevel;
|
||||||
if (stbi_write_png(path.getFullPath().c_str(), width, height, comp, bitmap->getWritableBits(), 0))
|
if (stbi_write_png(path.getFullPath().c_str(), width, height, bytes, bitmap->getWritableBits(), 0))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ext.equal("tga"))
|
if (ext.equal("tga"))
|
||||||
{
|
{
|
||||||
if (stbi_write_tga(path.getFullPath().c_str(), width, height, comp, bitmap->getWritableBits()))
|
if (stbi_write_tga(path.getFullPath().c_str(), width, height, bytes, bitmap->getWritableBits()))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ext.equal("bmp"))
|
if (ext.equal("bmp"))
|
||||||
{
|
{
|
||||||
if (stbi_write_bmp(path.getFullPath().c_str(), width, height, comp, bitmap->getWritableBits()))
|
if (stbi_write_bmp(path.getFullPath().c_str(), width, height, bytes, bitmap->getWritableBits()))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ext.equal("jpg") || ext.equal("jpeg"))
|
if (ext.equal("jpg") || ext.equal("jpeg"))
|
||||||
{
|
{
|
||||||
if (stbi_write_jpg(path.getFullPath().c_str(), width, height, comp, bitmap->getWritableBits(), compressionLevel))
|
if (stbi_write_jpg(path.getFullPath().c_str(), width, height, bytes, bitmap->getWritableBits(), compressionLevel))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ext.equal("hdr"))
|
if (ext.equal("hdr"))
|
||||||
{
|
{
|
||||||
if (stbi_write_hdr(path.getFullPath().c_str(), width, height, comp, (const F32*)bitmap->getWritableBits()))
|
if (stbi_write_hdr(path.getFullPath().c_str(), width, height, bytes, (const F32*)bitmap->getWritableBits()))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
|
/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb
|
||||||
no warranty implied; use at your own risk
|
no warranty implied; use at your own risk
|
||||||
|
|
||||||
Do this:
|
Do this:
|
||||||
|
|
@ -48,6 +48,8 @@ LICENSE
|
||||||
|
|
||||||
RECENT REVISION HISTORY:
|
RECENT REVISION HISTORY:
|
||||||
|
|
||||||
|
2.30 (2024-05-31) avoid erroneous gcc warning
|
||||||
|
2.29 (2023-05-xx) optimizations
|
||||||
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
|
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
|
||||||
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
|
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
|
||||||
2.26 (2020-07-13) many minor fixes
|
2.26 (2020-07-13) many minor fixes
|
||||||
|
|
@ -1072,8 +1074,8 @@ static int stbi__addints_valid(int a, int b)
|
||||||
return a <= INT_MAX - b;
|
return a <= INT_MAX - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns 1 if the product of two signed shorts is valid, 0 on overflow.
|
// returns 1 if the product of two ints fits in a signed short, 0 on overflow.
|
||||||
static int stbi__mul2shorts_valid(short a, short b)
|
static int stbi__mul2shorts_valid(int a, int b)
|
||||||
{
|
{
|
||||||
if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow
|
if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow
|
||||||
if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid
|
if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid
|
||||||
|
|
@ -3384,13 +3386,13 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
|
static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
|
||||||
{
|
{
|
||||||
// some JPEGs have junk at end, skip over it but if we find what looks
|
// some JPEGs have junk at end, skip over it but if we find what looks
|
||||||
// like a valid marker, resume there
|
// like a valid marker, resume there
|
||||||
while (!stbi__at_eof(j->s)) {
|
while (!stbi__at_eof(j->s)) {
|
||||||
int x = stbi__get8(j->s);
|
stbi_uc x = stbi__get8(j->s);
|
||||||
while (x == 255) { // might be a marker
|
while (x == 0xff) { // might be a marker
|
||||||
if (stbi__at_eof(j->s)) return STBI__MARKER_none;
|
if (stbi__at_eof(j->s)) return STBI__MARKER_none;
|
||||||
x = stbi__get8(j->s);
|
x = stbi__get8(j->s);
|
||||||
if (x != 0x00 && x != 0xff) {
|
if (x != 0x00 && x != 0xff) {
|
||||||
|
|
@ -4176,6 +4178,7 @@ typedef struct
|
||||||
{
|
{
|
||||||
stbi_uc *zbuffer, *zbuffer_end;
|
stbi_uc *zbuffer, *zbuffer_end;
|
||||||
int num_bits;
|
int num_bits;
|
||||||
|
int hit_zeof_once;
|
||||||
stbi__uint32 code_buffer;
|
stbi__uint32 code_buffer;
|
||||||
|
|
||||||
char *zout;
|
char *zout;
|
||||||
|
|
@ -4242,9 +4245,20 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
|
||||||
int b,s;
|
int b,s;
|
||||||
if (a->num_bits < 16) {
|
if (a->num_bits < 16) {
|
||||||
if (stbi__zeof(a)) {
|
if (stbi__zeof(a)) {
|
||||||
return -1; /* report error for unexpected end of data. */
|
if (!a->hit_zeof_once) {
|
||||||
|
// This is the first time we hit eof, insert 16 extra padding btis
|
||||||
|
// to allow us to keep going; if we actually consume any of them
|
||||||
|
// though, that is invalid data. This is caught later.
|
||||||
|
a->hit_zeof_once = 1;
|
||||||
|
a->num_bits += 16; // add 16 implicit zero bits
|
||||||
|
} else {
|
||||||
|
// We already inserted our extra 16 padding bits and are again
|
||||||
|
// out, this stream is actually prematurely terminated.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stbi__fill_bits(a);
|
||||||
}
|
}
|
||||||
stbi__fill_bits(a);
|
|
||||||
}
|
}
|
||||||
b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
|
b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
|
||||||
if (b) {
|
if (b) {
|
||||||
|
|
@ -4309,6 +4323,13 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
|
||||||
int len,dist;
|
int len,dist;
|
||||||
if (z == 256) {
|
if (z == 256) {
|
||||||
a->zout = zout;
|
a->zout = zout;
|
||||||
|
if (a->hit_zeof_once && a->num_bits < 16) {
|
||||||
|
// The first time we hit zeof, we inserted 16 extra zero bits into our bit
|
||||||
|
// buffer so the decoder can just do its speculative decoding. But if we
|
||||||
|
// actually consumed any of those bits (which is the case when num_bits < 16),
|
||||||
|
// the stream actually read past the end so it is malformed.
|
||||||
|
return stbi__err("unexpected end","Corrupt PNG");
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data
|
if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data
|
||||||
|
|
@ -4320,7 +4341,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
|
||||||
dist = stbi__zdist_base[z];
|
dist = stbi__zdist_base[z];
|
||||||
if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
|
if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
|
||||||
if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
|
if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
|
||||||
if (zout + len > a->zout_end) {
|
if (len > a->zout_end - zout) {
|
||||||
if (!stbi__zexpand(a, zout, len)) return 0;
|
if (!stbi__zexpand(a, zout, len)) return 0;
|
||||||
zout = a->zout;
|
zout = a->zout;
|
||||||
}
|
}
|
||||||
|
|
@ -4464,6 +4485,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
|
||||||
if (!stbi__parse_zlib_header(a)) return 0;
|
if (!stbi__parse_zlib_header(a)) return 0;
|
||||||
a->num_bits = 0;
|
a->num_bits = 0;
|
||||||
a->code_buffer = 0;
|
a->code_buffer = 0;
|
||||||
|
a->hit_zeof_once = 0;
|
||||||
do {
|
do {
|
||||||
final = stbi__zreceive(a,1);
|
final = stbi__zreceive(a,1);
|
||||||
type = stbi__zreceive(a,2);
|
type = stbi__zreceive(a,2);
|
||||||
|
|
@ -4619,9 +4641,8 @@ enum {
|
||||||
STBI__F_up=2,
|
STBI__F_up=2,
|
||||||
STBI__F_avg=3,
|
STBI__F_avg=3,
|
||||||
STBI__F_paeth=4,
|
STBI__F_paeth=4,
|
||||||
// synthetic filters used for first scanline to avoid needing a dummy row of 0s
|
// synthetic filter used for first scanline to avoid needing a dummy row of 0s
|
||||||
STBI__F_avg_first,
|
STBI__F_avg_first
|
||||||
STBI__F_paeth_first
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static stbi_uc first_row_filter[5] =
|
static stbi_uc first_row_filter[5] =
|
||||||
|
|
@ -4630,29 +4651,56 @@ static stbi_uc first_row_filter[5] =
|
||||||
STBI__F_sub,
|
STBI__F_sub,
|
||||||
STBI__F_none,
|
STBI__F_none,
|
||||||
STBI__F_avg_first,
|
STBI__F_avg_first,
|
||||||
STBI__F_paeth_first
|
STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub
|
||||||
};
|
};
|
||||||
|
|
||||||
static int stbi__paeth(int a, int b, int c)
|
static int stbi__paeth(int a, int b, int c)
|
||||||
{
|
{
|
||||||
int p = a + b - c;
|
// This formulation looks very different from the reference in the PNG spec, but is
|
||||||
int pa = abs(p-a);
|
// actually equivalent and has favorable data dependencies and admits straightforward
|
||||||
int pb = abs(p-b);
|
// generation of branch-free code, which helps performance significantly.
|
||||||
int pc = abs(p-c);
|
int thresh = c*3 - (a + b);
|
||||||
if (pa <= pb && pa <= pc) return a;
|
int lo = a < b ? a : b;
|
||||||
if (pb <= pc) return b;
|
int hi = a < b ? b : a;
|
||||||
return c;
|
int t0 = (hi <= thresh) ? lo : c;
|
||||||
|
int t1 = (thresh <= lo) ? hi : t0;
|
||||||
|
return t1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
|
static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
|
||||||
|
|
||||||
|
// adds an extra all-255 alpha channel
|
||||||
|
// dest == src is legal
|
||||||
|
// img_n must be 1 or 3
|
||||||
|
static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
// must process data backwards since we allow dest==src
|
||||||
|
if (img_n == 1) {
|
||||||
|
for (i=x-1; i >= 0; --i) {
|
||||||
|
dest[i*2+1] = 255;
|
||||||
|
dest[i*2+0] = src[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
STBI_ASSERT(img_n == 3);
|
||||||
|
for (i=x-1; i >= 0; --i) {
|
||||||
|
dest[i*4+3] = 255;
|
||||||
|
dest[i*4+2] = src[i*3+2];
|
||||||
|
dest[i*4+1] = src[i*3+1];
|
||||||
|
dest[i*4+0] = src[i*3+0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// create the png data from post-deflated data
|
// create the png data from post-deflated data
|
||||||
static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
|
static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
|
||||||
{
|
{
|
||||||
int bytes = (depth == 16? 2 : 1);
|
int bytes = (depth == 16 ? 2 : 1);
|
||||||
stbi__context *s = a->s;
|
stbi__context *s = a->s;
|
||||||
stbi__uint32 i,j,stride = x*out_n*bytes;
|
stbi__uint32 i,j,stride = x*out_n*bytes;
|
||||||
stbi__uint32 img_len, img_width_bytes;
|
stbi__uint32 img_len, img_width_bytes;
|
||||||
|
stbi_uc *filter_buf;
|
||||||
|
int all_ok = 1;
|
||||||
int k;
|
int k;
|
||||||
int img_n = s->img_n; // copy it into a local for later
|
int img_n = s->img_n; // copy it into a local for later
|
||||||
|
|
||||||
|
|
@ -4664,8 +4712,11 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
|
||||||
a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
|
a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
|
||||||
if (!a->out) return stbi__err("outofmem", "Out of memory");
|
if (!a->out) return stbi__err("outofmem", "Out of memory");
|
||||||
|
|
||||||
|
// note: error exits here don't need to clean up a->out individually,
|
||||||
|
// stbi__do_png always does on error.
|
||||||
if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
|
if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
|
||||||
img_width_bytes = (((img_n * x * depth) + 7) >> 3);
|
img_width_bytes = (((img_n * x * depth) + 7) >> 3);
|
||||||
|
if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG");
|
||||||
img_len = (img_width_bytes + 1) * y;
|
img_len = (img_width_bytes + 1) * y;
|
||||||
|
|
||||||
// we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
|
// we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
|
||||||
|
|
@ -4673,189 +4724,137 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
|
||||||
// so just check for raw_len < img_len always.
|
// so just check for raw_len < img_len always.
|
||||||
if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
|
if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
|
||||||
|
|
||||||
|
// Allocate two scan lines worth of filter workspace buffer.
|
||||||
|
filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0);
|
||||||
|
if (!filter_buf) return stbi__err("outofmem", "Out of memory");
|
||||||
|
|
||||||
|
// Filtering for low-bit-depth images
|
||||||
|
if (depth < 8) {
|
||||||
|
filter_bytes = 1;
|
||||||
|
width = img_width_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
for (j=0; j < y; ++j) {
|
for (j=0; j < y; ++j) {
|
||||||
stbi_uc *cur = a->out + stride*j;
|
// cur/prior filter buffers alternate
|
||||||
stbi_uc *prior;
|
stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes;
|
||||||
|
stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes;
|
||||||
|
stbi_uc *dest = a->out + stride*j;
|
||||||
|
int nk = width * filter_bytes;
|
||||||
int filter = *raw++;
|
int filter = *raw++;
|
||||||
|
|
||||||
if (filter > 4)
|
// check filter type
|
||||||
return stbi__err("invalid filter","Corrupt PNG");
|
if (filter > 4) {
|
||||||
|
all_ok = stbi__err("invalid filter","Corrupt PNG");
|
||||||
if (depth < 8) {
|
break;
|
||||||
if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG");
|
|
||||||
cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
|
|
||||||
filter_bytes = 1;
|
|
||||||
width = img_width_bytes;
|
|
||||||
}
|
}
|
||||||
prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above
|
|
||||||
|
|
||||||
// if first row, use special filter that doesn't sample previous row
|
// if first row, use special filter that doesn't sample previous row
|
||||||
if (j == 0) filter = first_row_filter[filter];
|
if (j == 0) filter = first_row_filter[filter];
|
||||||
|
|
||||||
// handle first byte explicitly
|
// perform actual filtering
|
||||||
for (k=0; k < filter_bytes; ++k) {
|
switch (filter) {
|
||||||
switch (filter) {
|
case STBI__F_none:
|
||||||
case STBI__F_none : cur[k] = raw[k]; break;
|
memcpy(cur, raw, nk);
|
||||||
case STBI__F_sub : cur[k] = raw[k]; break;
|
break;
|
||||||
case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
|
case STBI__F_sub:
|
||||||
case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
|
memcpy(cur, raw, filter_bytes);
|
||||||
case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
|
for (k = filter_bytes; k < nk; ++k)
|
||||||
case STBI__F_avg_first : cur[k] = raw[k]; break;
|
cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]);
|
||||||
case STBI__F_paeth_first: cur[k] = raw[k]; break;
|
break;
|
||||||
}
|
case STBI__F_up:
|
||||||
|
for (k = 0; k < nk; ++k)
|
||||||
|
cur[k] = STBI__BYTECAST(raw[k] + prior[k]);
|
||||||
|
break;
|
||||||
|
case STBI__F_avg:
|
||||||
|
for (k = 0; k < filter_bytes; ++k)
|
||||||
|
cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1));
|
||||||
|
for (k = filter_bytes; k < nk; ++k)
|
||||||
|
cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1));
|
||||||
|
break;
|
||||||
|
case STBI__F_paeth:
|
||||||
|
for (k = 0; k < filter_bytes; ++k)
|
||||||
|
cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0)
|
||||||
|
for (k = filter_bytes; k < nk; ++k)
|
||||||
|
cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes]));
|
||||||
|
break;
|
||||||
|
case STBI__F_avg_first:
|
||||||
|
memcpy(cur, raw, filter_bytes);
|
||||||
|
for (k = filter_bytes; k < nk; ++k)
|
||||||
|
cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (depth == 8) {
|
raw += nk;
|
||||||
if (img_n != out_n)
|
|
||||||
cur[img_n] = 255; // first pixel
|
|
||||||
raw += img_n;
|
|
||||||
cur += out_n;
|
|
||||||
prior += out_n;
|
|
||||||
} else if (depth == 16) {
|
|
||||||
if (img_n != out_n) {
|
|
||||||
cur[filter_bytes] = 255; // first pixel top byte
|
|
||||||
cur[filter_bytes+1] = 255; // first pixel bottom byte
|
|
||||||
}
|
|
||||||
raw += filter_bytes;
|
|
||||||
cur += output_bytes;
|
|
||||||
prior += output_bytes;
|
|
||||||
} else {
|
|
||||||
raw += 1;
|
|
||||||
cur += 1;
|
|
||||||
prior += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is a little gross, so that we don't switch per-pixel or per-component
|
// expand decoded bits in cur to dest, also adding an extra alpha channel if desired
|
||||||
if (depth < 8 || img_n == out_n) {
|
if (depth < 8) {
|
||||||
int nk = (width - 1)*filter_bytes;
|
|
||||||
#define STBI__CASE(f) \
|
|
||||||
case f: \
|
|
||||||
for (k=0; k < nk; ++k)
|
|
||||||
switch (filter) {
|
|
||||||
// "none" filter turns into a memcpy here; make that explicit.
|
|
||||||
case STBI__F_none: memcpy(cur, raw, nk); break;
|
|
||||||
STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
|
|
||||||
STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
|
|
||||||
STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
|
|
||||||
STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
|
|
||||||
STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
|
|
||||||
STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
|
|
||||||
}
|
|
||||||
#undef STBI__CASE
|
|
||||||
raw += nk;
|
|
||||||
} else {
|
|
||||||
STBI_ASSERT(img_n+1 == out_n);
|
|
||||||
#define STBI__CASE(f) \
|
|
||||||
case f: \
|
|
||||||
for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \
|
|
||||||
for (k=0; k < filter_bytes; ++k)
|
|
||||||
switch (filter) {
|
|
||||||
STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break;
|
|
||||||
STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
|
|
||||||
STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
|
|
||||||
STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
|
|
||||||
STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
|
|
||||||
STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
|
|
||||||
STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
|
|
||||||
}
|
|
||||||
#undef STBI__CASE
|
|
||||||
|
|
||||||
// the loop above sets the high byte of the pixels' alpha, but for
|
|
||||||
// 16 bit png files we also need the low byte set. we'll do that here.
|
|
||||||
if (depth == 16) {
|
|
||||||
cur = a->out + stride*j; // start at the beginning of the row again
|
|
||||||
for (i=0; i < x; ++i,cur+=output_bytes) {
|
|
||||||
cur[filter_bytes+1] = 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we make a separate pass to expand bits to pixels; for performance,
|
|
||||||
// this could run two scanlines behind the above code, so it won't
|
|
||||||
// intefere with filtering but will still be in the cache.
|
|
||||||
if (depth < 8) {
|
|
||||||
for (j=0; j < y; ++j) {
|
|
||||||
stbi_uc *cur = a->out + stride*j;
|
|
||||||
stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes;
|
|
||||||
// unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
|
|
||||||
// png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
|
|
||||||
stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
|
stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
|
||||||
|
stbi_uc *in = cur;
|
||||||
|
stbi_uc *out = dest;
|
||||||
|
stbi_uc inb = 0;
|
||||||
|
stbi__uint32 nsmp = x*img_n;
|
||||||
|
|
||||||
// note that the final byte might overshoot and write more data than desired.
|
// expand bits to bytes first
|
||||||
// we can allocate enough data that this never writes out of memory, but it
|
|
||||||
// could also overwrite the next scanline. can it overwrite non-empty data
|
|
||||||
// on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
|
|
||||||
// so we need to explicitly clamp the final ones
|
|
||||||
|
|
||||||
if (depth == 4) {
|
if (depth == 4) {
|
||||||
for (k=x*img_n; k >= 2; k-=2, ++in) {
|
for (i=0; i < nsmp; ++i) {
|
||||||
*cur++ = scale * ((*in >> 4) );
|
if ((i & 1) == 0) inb = *in++;
|
||||||
*cur++ = scale * ((*in ) & 0x0f);
|
*out++ = scale * (inb >> 4);
|
||||||
|
inb <<= 4;
|
||||||
}
|
}
|
||||||
if (k > 0) *cur++ = scale * ((*in >> 4) );
|
|
||||||
} else if (depth == 2) {
|
} else if (depth == 2) {
|
||||||
for (k=x*img_n; k >= 4; k-=4, ++in) {
|
for (i=0; i < nsmp; ++i) {
|
||||||
*cur++ = scale * ((*in >> 6) );
|
if ((i & 3) == 0) inb = *in++;
|
||||||
*cur++ = scale * ((*in >> 4) & 0x03);
|
*out++ = scale * (inb >> 6);
|
||||||
*cur++ = scale * ((*in >> 2) & 0x03);
|
inb <<= 2;
|
||||||
*cur++ = scale * ((*in ) & 0x03);
|
|
||||||
}
|
}
|
||||||
if (k > 0) *cur++ = scale * ((*in >> 6) );
|
} else {
|
||||||
if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
|
STBI_ASSERT(depth == 1);
|
||||||
if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
|
for (i=0; i < nsmp; ++i) {
|
||||||
} else if (depth == 1) {
|
if ((i & 7) == 0) inb = *in++;
|
||||||
for (k=x*img_n; k >= 8; k-=8, ++in) {
|
*out++ = scale * (inb >> 7);
|
||||||
*cur++ = scale * ((*in >> 7) );
|
inb <<= 1;
|
||||||
*cur++ = scale * ((*in >> 6) & 0x01);
|
|
||||||
*cur++ = scale * ((*in >> 5) & 0x01);
|
|
||||||
*cur++ = scale * ((*in >> 4) & 0x01);
|
|
||||||
*cur++ = scale * ((*in >> 3) & 0x01);
|
|
||||||
*cur++ = scale * ((*in >> 2) & 0x01);
|
|
||||||
*cur++ = scale * ((*in >> 1) & 0x01);
|
|
||||||
*cur++ = scale * ((*in ) & 0x01);
|
|
||||||
}
|
}
|
||||||
if (k > 0) *cur++ = scale * ((*in >> 7) );
|
|
||||||
if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);
|
|
||||||
if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);
|
|
||||||
if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);
|
|
||||||
if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);
|
|
||||||
if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);
|
|
||||||
if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);
|
|
||||||
}
|
}
|
||||||
if (img_n != out_n) {
|
|
||||||
int q;
|
// insert alpha=255 values if desired
|
||||||
// insert alpha = 255
|
if (img_n != out_n)
|
||||||
cur = a->out + stride*j;
|
stbi__create_png_alpha_expand8(dest, dest, x, img_n);
|
||||||
|
} else if (depth == 8) {
|
||||||
|
if (img_n == out_n)
|
||||||
|
memcpy(dest, cur, x*img_n);
|
||||||
|
else
|
||||||
|
stbi__create_png_alpha_expand8(dest, cur, x, img_n);
|
||||||
|
} else if (depth == 16) {
|
||||||
|
// convert the image data from big-endian to platform-native
|
||||||
|
stbi__uint16 *dest16 = (stbi__uint16*)dest;
|
||||||
|
stbi__uint32 nsmp = x*img_n;
|
||||||
|
|
||||||
|
if (img_n == out_n) {
|
||||||
|
for (i = 0; i < nsmp; ++i, ++dest16, cur += 2)
|
||||||
|
*dest16 = (cur[0] << 8) | cur[1];
|
||||||
|
} else {
|
||||||
|
STBI_ASSERT(img_n+1 == out_n);
|
||||||
if (img_n == 1) {
|
if (img_n == 1) {
|
||||||
for (q=x-1; q >= 0; --q) {
|
for (i = 0; i < x; ++i, dest16 += 2, cur += 2) {
|
||||||
cur[q*2+1] = 255;
|
dest16[0] = (cur[0] << 8) | cur[1];
|
||||||
cur[q*2+0] = cur[q];
|
dest16[1] = 0xffff;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
STBI_ASSERT(img_n == 3);
|
STBI_ASSERT(img_n == 3);
|
||||||
for (q=x-1; q >= 0; --q) {
|
for (i = 0; i < x; ++i, dest16 += 4, cur += 6) {
|
||||||
cur[q*4+3] = 255;
|
dest16[0] = (cur[0] << 8) | cur[1];
|
||||||
cur[q*4+2] = cur[q*3+2];
|
dest16[1] = (cur[2] << 8) | cur[3];
|
||||||
cur[q*4+1] = cur[q*3+1];
|
dest16[2] = (cur[4] << 8) | cur[5];
|
||||||
cur[q*4+0] = cur[q*3+0];
|
dest16[3] = 0xffff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (depth == 16) {
|
|
||||||
// force the image data from big-endian to platform-native.
|
|
||||||
// this is done in a separate pass due to the decoding relying
|
|
||||||
// on the data being untouched, but could probably be done
|
|
||||||
// per-line during decode if care is taken.
|
|
||||||
stbi_uc *cur = a->out;
|
|
||||||
stbi__uint16 *cur16 = (stbi__uint16*)cur;
|
|
||||||
|
|
||||||
for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {
|
|
||||||
*cur16 = (cur[0] << 8) | cur[1];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STBI_FREE(filter_buf);
|
||||||
|
if (!all_ok) return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5161,9 +5160,11 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
|
||||||
// non-paletted with tRNS = constant alpha. if header-scanning, we can stop now.
|
// non-paletted with tRNS = constant alpha. if header-scanning, we can stop now.
|
||||||
if (scan == STBI__SCAN_header) { ++s->img_n; return 1; }
|
if (scan == STBI__SCAN_header) { ++s->img_n; return 1; }
|
||||||
if (z->depth == 16) {
|
if (z->depth == 16) {
|
||||||
for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
|
for (k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning
|
||||||
|
tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
|
||||||
} else {
|
} else {
|
||||||
for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
|
for (k = 0; k < s->img_n && k < 3; ++k)
|
||||||
|
tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -7984,4 +7985,4 @@ AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -180,3 +180,37 @@ ImplementEnumType( GFXBlendOp,
|
||||||
{ GFXBlendOpMax, "GFXBlendOpMax" }
|
{ GFXBlendOpMax, "GFXBlendOpMax" }
|
||||||
|
|
||||||
EndImplementEnumType;
|
EndImplementEnumType;
|
||||||
|
|
||||||
|
ImplementEnumType(GFXShaderConstType,
|
||||||
|
"The shader const types.\n"
|
||||||
|
"@ingroup GFX")
|
||||||
|
|
||||||
|
{ GFXSCT_Uknown, "GFXSCT_Uknown" },
|
||||||
|
{ GFXSCT_ConstBuffer, "GFXSCT_ConstBuffer" },
|
||||||
|
{ GFXSCT_Float, "GFXSCT_Float" },
|
||||||
|
{ GFXSCT_Float2, "GFXSCT_Float2" },
|
||||||
|
{ GFXSCT_Float3, "GFXSCT_Float3" },
|
||||||
|
{ GFXSCT_Float4, "GFXSCT_Float4" },
|
||||||
|
{ GFXSCT_Float2x2, "GFXSCT_Float2x2" },
|
||||||
|
{ GFXSCT_Float3x3, "GFXSCT_Float3x3" },
|
||||||
|
{ GFXSCT_Float3x4, "GFXSCT_Float3x4" },
|
||||||
|
{ GFXSCT_Float4x3, "GFXSCT_Float4x3" },
|
||||||
|
{ GFXSCT_Float4x4, "GFXSCT_Float4x4" },
|
||||||
|
{ GFXSCT_Int, "GFXSCT_Int" },
|
||||||
|
{ GFXSCT_Int2, "GFXSCT_Int2" },
|
||||||
|
{ GFXSCT_Int3, "GFXSCT_Int3" },
|
||||||
|
{ GFXSCT_Int4, "GFXSCT_Int4" },
|
||||||
|
{ GFXSCT_UInt, "GFXSCT_UInt" },
|
||||||
|
{ GFXSCT_UInt2, "GFXSCT_UInt2" },
|
||||||
|
{ GFXSCT_UInt3, "GFXSCT_UInt3" },
|
||||||
|
{ GFXSCT_UInt4, "GFXSCT_UInt4" },
|
||||||
|
{ GFXSCT_Bool, "GFXSCT_Bool" },
|
||||||
|
{ GFXSCT_Bool2, "GFXSCT_Bool2" },
|
||||||
|
{ GFXSCT_Bool3, "GFXSCT_Bool3" },
|
||||||
|
{ GFXSCT_Bool4, "GFXSCT_Bool4" },
|
||||||
|
{ GFXSCT_Sampler, "GFXSCT_Sampler" },
|
||||||
|
{ GFXSCT_SamplerCube, "GFXSCT_SamplerCube" },
|
||||||
|
{ GFXSCT_SamplerCubeArray, "GFXSCT_SamplerCubeArray" },
|
||||||
|
{ GFXSCT_SamplerTextureArray, "GFXSCT_SamplerTextureArray" }
|
||||||
|
|
||||||
|
EndImplementEnumType;
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ DefineEnumType( GFXTextureFilterType );
|
||||||
DefineEnumType( GFXCullMode );
|
DefineEnumType( GFXCullMode );
|
||||||
DefineEnumType( GFXStencilOp );
|
DefineEnumType( GFXStencilOp );
|
||||||
DefineEnumType( GFXBlendOp );
|
DefineEnumType( GFXBlendOp );
|
||||||
|
DefineEnumType(GFXShaderConstType);
|
||||||
DefineEnumType( GFXAdapterType );
|
DefineEnumType( GFXAdapterType );
|
||||||
|
|
||||||
DECLARE_STRUCT( GFXVideoMode );
|
DECLARE_STRUCT( GFXVideoMode );
|
||||||
|
|
@ -57,5 +58,6 @@ DefineConsoleType( TypeGFXTextureFilterType, GFXTextureFilterType );
|
||||||
DefineConsoleType( TypeGFXCullMode, GFXCullMode );
|
DefineConsoleType( TypeGFXCullMode, GFXCullMode );
|
||||||
DefineConsoleType( TypeGFXStencilOp, GFXStencilOp );
|
DefineConsoleType( TypeGFXStencilOp, GFXStencilOp );
|
||||||
DefineConsoleType( TypeGFXBlendOp, GFXBlendOp );
|
DefineConsoleType( TypeGFXBlendOp, GFXBlendOp );
|
||||||
|
DefineConsoleType( TypeGFXShaderConstType, GFXShaderConstType);
|
||||||
|
|
||||||
#endif // !_GFXAPI_H_
|
#endif // !_GFXAPI_H_
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,12 @@ GFXShader::GFXShader()
|
||||||
|
|
||||||
GFXShader::~GFXShader()
|
GFXShader::~GFXShader()
|
||||||
{
|
{
|
||||||
Torque::FS::RemoveChangeNotification( mVertexFile, this, &GFXShader::_onFileChanged );
|
if (!mVertexFile.isEmpty())
|
||||||
Torque::FS::RemoveChangeNotification( mPixelFile, this, &GFXShader::_onFileChanged );
|
Torque::FS::RemoveChangeNotification( mVertexFile, this, &GFXShader::_onFileChanged );
|
||||||
|
if (!mPixelFile.isEmpty())
|
||||||
|
Torque::FS::RemoveChangeNotification( mPixelFile, this, &GFXShader::_onFileChanged );
|
||||||
|
if (!mGeometryFile.isEmpty())
|
||||||
|
Torque::FS::RemoveChangeNotification(mGeometryFile, this, &GFXShader::_onFileChanged);
|
||||||
|
|
||||||
SAFE_DELETE(mInstancingFormat);
|
SAFE_DELETE(mInstancingFormat);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,9 @@ enum GFXShaderStage
|
||||||
GEOMETRY_SHADER = BIT(2),
|
GEOMETRY_SHADER = BIT(2),
|
||||||
DOMAIN_SHADER = BIT(3),
|
DOMAIN_SHADER = BIT(3),
|
||||||
HULL_SHADER = BIT(4),
|
HULL_SHADER = BIT(4),
|
||||||
COMPUTE_SHADER = BIT(5)
|
COMPUTE_SHADER = BIT(5),
|
||||||
|
ALL_STAGES = VERTEX_SHADER | PIXEL_SHADER | GEOMETRY_SHADER |
|
||||||
|
DOMAIN_SHADER | HULL_SHADER | COMPUTE_SHADER
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Instances of this struct are returned GFXShaderConstBuffer
|
/// Instances of this struct are returned GFXShaderConstBuffer
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ public:
|
||||||
/// @param mipLevel What level of this texture are we rendering to?
|
/// @param mipLevel What level of this texture are we rendering to?
|
||||||
/// @param zOffset If this is a depth texture, what z level are we
|
/// @param zOffset If this is a depth texture, what z level are we
|
||||||
/// rendering to?
|
/// rendering to?
|
||||||
virtual void attachTexture(RenderSlot slot, GFXTextureObject *tex, U32 mipLevel=0, U32 zOffset = 0) = 0;
|
virtual void attachTexture(RenderSlot slot, GFXTextureObject *tex, U32 mipLevel=0, U32 zOffset = 0, U32 faceIndex = 0) = 0;
|
||||||
|
|
||||||
/// Support binding to cubemaps.
|
/// Support binding to cubemaps.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -137,19 +137,19 @@ bool GFXTexHandle::set( DDSFile *dds, GFXTextureProfile *profile, bool deleteDDS
|
||||||
return isValid();
|
return isValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXTexHandle::GFXTexHandle( U32 width, U32 height, GFXFormat format, GFXTextureProfile *profile, const String &desc, U32 numMipLevels, S32 antialiasLevel)
|
GFXTexHandle::GFXTexHandle( U32 width, U32 height, GFXFormat format, GFXTextureProfile *profile, const String &desc, U32 numMipLevels, S32 antialiasLevel, U32 arraySize)
|
||||||
{
|
{
|
||||||
set( width, height, format, profile, desc, numMipLevels, antialiasLevel );
|
set( width, height, format, profile, desc, numMipLevels, antialiasLevel, arraySize );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GFXTexHandle::set( U32 width, U32 height, GFXFormat format, GFXTextureProfile *profile, const String &desc, U32 numMipLevels, S32 antialiasLevel)
|
bool GFXTexHandle::set( U32 width, U32 height, GFXFormat format, GFXTextureProfile *profile, const String &desc, U32 numMipLevels, S32 antialiasLevel, U32 arraySize)
|
||||||
{
|
{
|
||||||
// Clear the existing texture first, so that
|
// Clear the existing texture first, so that
|
||||||
// its memory is free for the new allocation.
|
// its memory is free for the new allocation.
|
||||||
free();
|
free();
|
||||||
|
|
||||||
// Create and set the new texture.
|
// Create and set the new texture.
|
||||||
StrongObjectRef::set( TEXMGR->createTexture( width, height, format, profile, numMipLevels, antialiasLevel ) );
|
StrongObjectRef::set( TEXMGR->createTexture( width, height, format, profile, numMipLevels, antialiasLevel, arraySize) );
|
||||||
|
|
||||||
#ifdef TORQUE_DEBUG
|
#ifdef TORQUE_DEBUG
|
||||||
if ( getPointer() )
|
if ( getPointer() )
|
||||||
|
|
@ -159,14 +159,14 @@ bool GFXTexHandle::set( U32 width, U32 height, GFXFormat format, GFXTextureProfi
|
||||||
return isValid();
|
return isValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GFXTexHandle::set(U32 width, U32 height, U32 depth, GFXFormat format, GFXTextureProfile* profile, const String& desc, U32 numMipLevels)
|
bool GFXTexHandle::set(U32 width, U32 height, U32 depth, GFXFormat format, GFXTextureProfile* profile, const String& desc, U32 numMipLevels, U32 arraySize)
|
||||||
{
|
{
|
||||||
// Clear the existing texture first, so that
|
// Clear the existing texture first, so that
|
||||||
// its memory is free for the new allocation.
|
// its memory is free for the new allocation.
|
||||||
free();
|
free();
|
||||||
|
|
||||||
// Create and set the new texture.
|
// Create and set the new texture.
|
||||||
StrongObjectRef::set(TEXMGR->createTexture(width, height, depth, format, profile, numMipLevels));
|
StrongObjectRef::set(TEXMGR->createTexture(width, height, depth, format, profile, numMipLevels, arraySize));
|
||||||
|
|
||||||
#ifdef TORQUE_DEBUG
|
#ifdef TORQUE_DEBUG
|
||||||
if ( getPointer() )
|
if ( getPointer() )
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,9 @@ public:
|
||||||
bool set( DDSFile *bmp, GFXTextureProfile *profile, bool deleteDDS, const String &desc );
|
bool set( DDSFile *bmp, GFXTextureProfile *profile, bool deleteDDS, const String &desc );
|
||||||
|
|
||||||
// Sized bitmap
|
// Sized bitmap
|
||||||
GFXTexHandle( U32 width, U32 height, GFXFormat format, GFXTextureProfile *profile, const String &desc, U32 numMipLevels = 1, S32 antialiasLevel = 0);
|
GFXTexHandle( U32 width, U32 height, GFXFormat format, GFXTextureProfile *profile, const String &desc, U32 numMipLevels = 1, S32 antialiasLevel = 0, U32 arraySize = 1);
|
||||||
bool set( U32 width, U32 height, GFXFormat format, GFXTextureProfile *profile, const String &desc, U32 numMipLevels = 1, S32 antialiasLevel = 0);
|
bool set( U32 width, U32 height, GFXFormat format, GFXTextureProfile *profile, const String &desc, U32 numMipLevels = 1, S32 antialiasLevel = 0, U32 arraySize = 1);
|
||||||
bool set( U32 width, U32 height, U32 depth, GFXFormat format, GFXTextureProfile* profile, const String& desc, U32 numMipLevels = 1);
|
bool set( U32 width, U32 height, U32 depth, GFXFormat format, GFXTextureProfile* profile, const String& desc, U32 numMipLevels = 1, U32 arraySize = 1);
|
||||||
|
|
||||||
/// Returns the width and height as a point.
|
/// Returns the width and height as a point.
|
||||||
Point2I getWidthHeight() const { return getPointer() ? Point2I( getPointer()->getWidth(), getPointer()->getHeight() ) : Point2I::Zero; }
|
Point2I getWidthHeight() const { return getPointer() ? Point2I( getPointer()->getWidth(), getPointer()->getHeight() ) : Point2I::Zero; }
|
||||||
|
|
@ -68,6 +68,7 @@ public:
|
||||||
U32 getWidth() const { return getPointer() ? getPointer()->getWidth() : 0; }
|
U32 getWidth() const { return getPointer() ? getPointer()->getWidth() : 0; }
|
||||||
U32 getHeight() const { return getPointer() ? getPointer()->getHeight() : 0; }
|
U32 getHeight() const { return getPointer() ? getPointer()->getHeight() : 0; }
|
||||||
U32 getDepth() const { return getPointer() ? getPointer()->getDepth() : 0; }
|
U32 getDepth() const { return getPointer() ? getPointer()->getDepth() : 0; }
|
||||||
|
U32 getArraySize() const { return getPointer() ? getPointer()->getArraySize() : 0; }
|
||||||
GFXFormat getFormat() const { return getPointer() ? getPointer()->getFormat() : GFXFormat_COUNT; }
|
GFXFormat getFormat() const { return getPointer() ? getPointer()->getFormat() : GFXFormat_COUNT; }
|
||||||
|
|
||||||
/// Reloads the texture.
|
/// Reloads the texture.
|
||||||
|
|
|
||||||
|
|
@ -361,7 +361,7 @@ GFXTextureObject *GFXTextureManager::_createTexture( GBitmap *bmp,
|
||||||
if ( inObj->getWidth() != realWidth ||
|
if ( inObj->getWidth() != realWidth ||
|
||||||
inObj->getHeight() != realHeight ||
|
inObj->getHeight() != realHeight ||
|
||||||
inObj->getFormat() != realFmt )
|
inObj->getFormat() != realFmt )
|
||||||
ret = _createTextureObject( realHeight, realWidth, 0, realFmt, profile, numMips, false, 0, inObj );
|
ret = _createTextureObject( realHeight, realWidth, 0, realFmt, profile, numMips, false, 0, 1, inObj );
|
||||||
else
|
else
|
||||||
ret = inObj;
|
ret = inObj;
|
||||||
}
|
}
|
||||||
|
|
@ -569,7 +569,7 @@ GFXTextureObject *GFXTextureManager::_createTexture( DDSFile *dds,
|
||||||
inObj->getMipLevels() != numMips )
|
inObj->getMipLevels() != numMips )
|
||||||
ret = _createTextureObject( dds->getHeight(), dds->getWidth(), 0,
|
ret = _createTextureObject( dds->getHeight(), dds->getWidth(), 0,
|
||||||
fmt, profile, numMips,
|
fmt, profile, numMips,
|
||||||
true, 0, inObj );
|
true, 0, 1, inObj );
|
||||||
else
|
else
|
||||||
ret = inObj;
|
ret = inObj;
|
||||||
}
|
}
|
||||||
|
|
@ -744,7 +744,7 @@ GFXTextureObject *GFXTextureManager::createTexture( U32 width, U32 height, void
|
||||||
return createTexture( bmp, String::EmptyString, profile, true );
|
return createTexture( bmp, String::EmptyString, profile, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXTextureObject *GFXTextureManager::createTexture( U32 width, U32 height, GFXFormat format, GFXTextureProfile *profile, U32 numMipLevels, S32 antialiasLevel )
|
GFXTextureObject *GFXTextureManager::createTexture( U32 width, U32 height, GFXFormat format, GFXTextureProfile *profile, U32 numMipLevels, S32 antialiasLevel, U32 arraySize)
|
||||||
{
|
{
|
||||||
// Deal with sizing issues...
|
// Deal with sizing issues...
|
||||||
U32 localWidth = width;
|
U32 localWidth = width;
|
||||||
|
|
@ -783,7 +783,7 @@ GFXTextureObject *GFXTextureManager::createTexture( U32 width, U32 height, GFXFo
|
||||||
// Create the texture if we didn't get one from the pool.
|
// Create the texture if we didn't get one from the pool.
|
||||||
if ( !outTex )
|
if ( !outTex )
|
||||||
{
|
{
|
||||||
outTex = _createTextureObject( localHeight, localWidth, 0, format, profile, numMips, false, antialiasLevel );
|
outTex = _createTextureObject( localHeight, localWidth, 0, format, profile, numMips, false, antialiasLevel, arraySize );
|
||||||
|
|
||||||
// Make sure we add it to the pool.
|
// Make sure we add it to the pool.
|
||||||
if ( outTex && profile->isPooled() )
|
if ( outTex && profile->isPooled() )
|
||||||
|
|
@ -814,12 +814,13 @@ GFXTextureObject *GFXTextureManager::createTexture( U32 width,
|
||||||
U32 depth,
|
U32 depth,
|
||||||
GFXFormat format,
|
GFXFormat format,
|
||||||
GFXTextureProfile *profile,
|
GFXTextureProfile *profile,
|
||||||
U32 numMipLevels)
|
U32 numMipLevels,
|
||||||
|
U32 arraySize)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPE( GFXTextureManager_CreateTexture_3D );
|
PROFILE_SCOPE( GFXTextureManager_CreateTexture_3D );
|
||||||
|
|
||||||
// Create texture...
|
// Create texture...
|
||||||
GFXTextureObject *ret = _createTextureObject( height, width, depth, format, profile, numMipLevels );
|
GFXTextureObject *ret = _createTextureObject( height, width, depth, format, profile, numMipLevels, arraySize );
|
||||||
|
|
||||||
if(!ret)
|
if(!ret)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -120,14 +120,16 @@ public:
|
||||||
U32 depth,
|
U32 depth,
|
||||||
GFXFormat format,
|
GFXFormat format,
|
||||||
GFXTextureProfile *profile,
|
GFXTextureProfile *profile,
|
||||||
U32 numMipLevels = 1);
|
U32 numMipLevels = 1,
|
||||||
|
U32 arraySize = 1);
|
||||||
|
|
||||||
virtual GFXTextureObject *createTexture( U32 width,
|
virtual GFXTextureObject *createTexture( U32 width,
|
||||||
U32 height,
|
U32 height,
|
||||||
GFXFormat format,
|
GFXFormat format,
|
||||||
GFXTextureProfile *profile,
|
GFXTextureProfile *profile,
|
||||||
U32 numMipLevels,
|
U32 numMipLevels,
|
||||||
S32 antialiasLevel);
|
S32 antialiasLevel,
|
||||||
|
U32 arraySize = 1);
|
||||||
|
|
||||||
Torque::Path validatePath(const Torque::Path &path);
|
Torque::Path validatePath(const Torque::Path &path);
|
||||||
GBitmap *loadUncompressedTexture(const Torque::Path& path, GFXTextureProfile* profile, U32 width, U32 height, bool genMips = false);
|
GBitmap *loadUncompressedTexture(const Torque::Path& path, GFXTextureProfile* profile, U32 width, U32 height, bool genMips = false);
|
||||||
|
|
@ -319,7 +321,8 @@ protected:
|
||||||
GFXTextureProfile *profile,
|
GFXTextureProfile *profile,
|
||||||
U32 numMipLevels,
|
U32 numMipLevels,
|
||||||
bool forceMips = false,
|
bool forceMips = false,
|
||||||
S32 antialiasLevel = 0,
|
S32 antialiasLevel = 0,
|
||||||
|
U32 arraySize = 1,
|
||||||
GFXTextureObject *inTex = NULL ) = 0;
|
GFXTextureObject *inTex = NULL ) = 0;
|
||||||
|
|
||||||
/// Load a texture from a proper DDSFile instance.
|
/// Load a texture from a proper DDSFile instance.
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,8 @@ GFXTextureObject::GFXTextureObject(GFXDevice *aDevice, GFXTextureProfile *aProfi
|
||||||
|
|
||||||
mHasTransparency = false;
|
mHasTransparency = false;
|
||||||
|
|
||||||
|
mArraySize = 1;
|
||||||
|
|
||||||
#if defined(TORQUE_DEBUG)
|
#if defined(TORQUE_DEBUG)
|
||||||
// Active object tracking.
|
// Active object tracking.
|
||||||
smActiveTOCount++;
|
smActiveTOCount++;
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ class GFXTextureProfile;
|
||||||
class GBitmap;
|
class GBitmap;
|
||||||
struct DDSFile;
|
struct DDSFile;
|
||||||
class RectI;
|
class RectI;
|
||||||
|
class GFXTexHandle;
|
||||||
|
|
||||||
/// Contains information on a locked region of a texture.
|
/// Contains information on a locked region of a texture.
|
||||||
///
|
///
|
||||||
|
|
@ -92,6 +93,8 @@ public:
|
||||||
|
|
||||||
bool mDead;
|
bool mDead;
|
||||||
|
|
||||||
|
U32 mArraySize;
|
||||||
|
|
||||||
/// The device this texture belongs to.
|
/// The device this texture belongs to.
|
||||||
GFXDevice *mDevice;
|
GFXDevice *mDevice;
|
||||||
|
|
||||||
|
|
@ -150,10 +153,13 @@ public:
|
||||||
U32 getBitmapHeight() const { return mBitmapSize.y; }
|
U32 getBitmapHeight() const { return mBitmapSize.y; }
|
||||||
U32 getBitmapDepth() const { return mBitmapSize.z; }
|
U32 getBitmapDepth() const { return mBitmapSize.z; }
|
||||||
GFXFormat getFormat() const { return mFormat; }
|
GFXFormat getFormat() const { return mFormat; }
|
||||||
|
U32 getArraySize() const { return mArraySize; }
|
||||||
|
|
||||||
/// Returns true if this texture is a render target.
|
/// Returns true if this texture is a render target.
|
||||||
bool isRenderTarget() const { return mProfile->isRenderTarget(); }
|
bool isRenderTarget() const { return mProfile->isRenderTarget(); }
|
||||||
|
|
||||||
|
bool isCubeMap() const { return mProfile->isCubeMap(); }
|
||||||
|
|
||||||
/// Returns the file path to the texture if
|
/// Returns the file path to the texture if
|
||||||
/// it was loaded from disk.
|
/// it was loaded from disk.
|
||||||
const String& getPath() const { return mPath; }
|
const String& getPath() const { return mPath; }
|
||||||
|
|
@ -167,11 +173,11 @@ public:
|
||||||
|
|
||||||
/// Acquire a lock on part of the texture. The GFXLockedRect returned
|
/// Acquire a lock on part of the texture. The GFXLockedRect returned
|
||||||
/// is managed by the GFXTextureObject and does not need to be freed.
|
/// is managed by the GFXTextureObject and does not need to be freed.
|
||||||
virtual GFXLockedRect * lock( U32 mipLevel = 0, RectI *inRect = NULL ) = 0;
|
virtual GFXLockedRect * lock( U32 mipLevel = 0, RectI *inRect = NULL, U32 faceIndex = 0) = 0;
|
||||||
|
|
||||||
/// Releases a lock previously acquired. Note that the mipLevel parameter
|
/// Releases a lock previously acquired. Note that the mipLevel parameter
|
||||||
/// must match the corresponding lock!
|
/// must match the corresponding lock!
|
||||||
virtual void unlock( U32 mipLevel = 0) = 0;
|
virtual void unlock( U32 mipLevel = 0, U32 faceIndex = 0) = 0;
|
||||||
|
|
||||||
// copy the texture data into the specified bitmap.
|
// copy the texture data into the specified bitmap.
|
||||||
// - this texture object must be a render target. the function will assert if this is not the case.
|
// - this texture object must be a render target. the function will assert if this is not the case.
|
||||||
|
|
@ -182,6 +188,10 @@ public:
|
||||||
// - this process is not fast.
|
// - this process is not fast.
|
||||||
virtual bool copyToBmp(GBitmap* bmp) = 0;
|
virtual bool copyToBmp(GBitmap* bmp) = 0;
|
||||||
|
|
||||||
|
virtual void updateTextureSlot(const GFXTexHandle& texHandle, const U32 slot, const S32 face = -1) = 0;
|
||||||
|
virtual void copyTo(GFXTextureObject* dstTex) = 0;
|
||||||
|
virtual void generateMipMaps() = 0;
|
||||||
|
|
||||||
#ifdef TORQUE_DEBUG
|
#ifdef TORQUE_DEBUG
|
||||||
|
|
||||||
// It is important for any derived objects to define this method
|
// It is important for any derived objects to define this method
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,21 @@ GFX_ImplementTextureProfile(GFXDynamicTextureSRGBProfile,
|
||||||
GFXTextureProfile::DiffuseMap,
|
GFXTextureProfile::DiffuseMap,
|
||||||
GFXTextureProfile::Dynamic | GFXTextureProfile::SRGB,
|
GFXTextureProfile::Dynamic | GFXTextureProfile::SRGB,
|
||||||
GFXTextureProfile::NONE);
|
GFXTextureProfile::NONE);
|
||||||
|
GFX_ImplementTextureProfile(GFXDynamicCubemapTextureProfile,
|
||||||
|
GFXTextureProfile::DiffuseMap,
|
||||||
|
GFXTextureProfile::Dynamic | GFXTextureProfile::CubeMap,
|
||||||
|
GFXTextureProfile::NONE);
|
||||||
|
GFX_ImplementTextureProfile(GFXCubemapRenderTargetProfile,
|
||||||
|
GFXTextureProfile::DiffuseMap,
|
||||||
|
GFXTextureProfile::PreserveSize | GFXTextureProfile::RenderTarget | GFXTextureProfile::CubeMap,
|
||||||
|
GFXTextureProfile::NONE);
|
||||||
|
GFX_ImplementTextureProfile(GFXCubemapStaticTextureProfile, GFXTextureProfile::DiffuseMap,
|
||||||
|
GFXTextureProfile::Static | GFXTextureProfile::CubeMap,
|
||||||
|
GFXTextureProfile::NONE);
|
||||||
|
GFX_ImplementTextureProfile(GFXCubemapTexturePersistentProfile,
|
||||||
|
GFXTextureProfile::DiffuseMap,
|
||||||
|
GFXTextureProfile::PreserveSize | GFXTextureProfile::Static | GFXTextureProfile::KeepBitmap | GFXTextureProfile::CubeMap,
|
||||||
|
GFXTextureProfile::NONE);
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ public:
|
||||||
KeepBitmap = BIT(7), ///< Always keep a copy of this texture's bitmap. (Potentially in addition to the API managed copy?)
|
KeepBitmap = BIT(7), ///< Always keep a copy of this texture's bitmap. (Potentially in addition to the API managed copy?)
|
||||||
ZTarget = BIT(8), ///< This texture will be used as a Z target.
|
ZTarget = BIT(8), ///< This texture will be used as a Z target.
|
||||||
SRGB = BIT(9), ///< sRGB texture
|
SRGB = BIT(9), ///< sRGB texture
|
||||||
|
CubeMap = BIT(10), ///< Cubemap texture
|
||||||
/// Track and pool textures of this type for reuse.
|
/// Track and pool textures of this type for reuse.
|
||||||
///
|
///
|
||||||
/// You should use this profile flag sparingly. Odd
|
/// You should use this profile flag sparingly. Odd
|
||||||
|
|
@ -96,16 +96,15 @@ public:
|
||||||
/// the pool to contain unused textures which will remain
|
/// the pool to contain unused textures which will remain
|
||||||
/// in memory until a flush occurs.
|
/// in memory until a flush occurs.
|
||||||
///
|
///
|
||||||
Pooled = BIT(10),
|
Pooled = BIT(11),
|
||||||
|
|
||||||
/// A hint that the device is not allowed to discard the content
|
/// A hint that the device is not allowed to discard the content
|
||||||
/// of a target texture after presentation or deactivated.
|
/// of a target texture after presentation or deactivated.
|
||||||
///
|
///
|
||||||
/// This is mainly a depth buffer optimization.
|
/// This is mainly a depth buffer optimization.
|
||||||
NoDiscard = BIT(11),
|
NoDiscard = BIT(12),
|
||||||
|
|
||||||
|
NoModify = BIT(12)
|
||||||
NoModify = BIT(11)
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -173,6 +172,7 @@ public:
|
||||||
inline bool isPooled() const { return testFlag(Pooled); }
|
inline bool isPooled() const { return testFlag(Pooled); }
|
||||||
inline bool canDiscard() const { return !testFlag(NoDiscard); }
|
inline bool canDiscard() const { return !testFlag(NoDiscard); }
|
||||||
inline bool isSRGB() const { return testFlag(SRGB); }
|
inline bool isSRGB() const { return testFlag(SRGB); }
|
||||||
|
inline bool isCubeMap() const { return testFlag(CubeMap); }
|
||||||
//compare profile flags for equality
|
//compare profile flags for equality
|
||||||
inline bool compareFlags(const GFXTextureProfile& in_Cmp) const{ return (mProfile == in_Cmp.mProfile); }
|
inline bool compareFlags(const GFXTextureProfile& in_Cmp) const{ return (mProfile == in_Cmp.mProfile); }
|
||||||
private:
|
private:
|
||||||
|
|
@ -209,7 +209,7 @@ private:
|
||||||
#define GFX_DeclareTextureProfile(name) extern GFXTextureProfile name
|
#define GFX_DeclareTextureProfile(name) extern GFXTextureProfile name
|
||||||
#define GFX_ImplementTextureProfile(name, type, flags, compression) GFXTextureProfile name(#name, type, flags, compression)
|
#define GFX_ImplementTextureProfile(name, type, flags, compression) GFXTextureProfile name(#name, type, flags, compression)
|
||||||
|
|
||||||
// Default Texture profiles
|
// Default 2D Texture profiles
|
||||||
// Texture we can render to.
|
// Texture we can render to.
|
||||||
GFX_DeclareTextureProfile(GFXRenderTargetProfile);
|
GFX_DeclareTextureProfile(GFXRenderTargetProfile);
|
||||||
GFX_DeclareTextureProfile(GFXRenderTargetSRGBProfile);
|
GFX_DeclareTextureProfile(GFXRenderTargetSRGBProfile);
|
||||||
|
|
@ -231,4 +231,14 @@ GFX_DeclareTextureProfile(GFXZTargetProfile);
|
||||||
GFX_DeclareTextureProfile(GFXDynamicTextureProfile);
|
GFX_DeclareTextureProfile(GFXDynamicTextureProfile);
|
||||||
GFX_DeclareTextureProfile(GFXDynamicTextureSRGBProfile);
|
GFX_DeclareTextureProfile(GFXDynamicTextureSRGBProfile);
|
||||||
|
|
||||||
|
// Default Cubemap Texture profiles
|
||||||
|
// Dynamic Texure
|
||||||
|
GFX_DeclareTextureProfile(GFXDynamicCubemapTextureProfile);
|
||||||
|
// Texture we can render to.
|
||||||
|
GFX_DeclareTextureProfile(GFXCubemapRenderTargetProfile);
|
||||||
|
// Standard static diffuse textures
|
||||||
|
GFX_DeclareTextureProfile(GFXCubemapStaticTextureProfile);
|
||||||
|
// Standard static diffuse textures that are persistent in memory
|
||||||
|
GFX_DeclareTextureProfile(GFXCubemapTexturePersistentProfile);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ GFXTextureObject *GFXGLTextureManager::_createTextureObject( U32 height,
|
||||||
U32 numMipLevels,
|
U32 numMipLevels,
|
||||||
bool forceMips,
|
bool forceMips,
|
||||||
S32 antialiasLevel,
|
S32 antialiasLevel,
|
||||||
|
U32 arraySize,
|
||||||
GFXTextureObject *inTex )
|
GFXTextureObject *inTex )
|
||||||
{
|
{
|
||||||
AssertFatal(format >= 0 && format < GFXFormat_COUNT, "GFXGLTextureManager::_createTexture - invalid format!");
|
AssertFatal(format >= 0 && format < GFXFormat_COUNT, "GFXGLTextureManager::_createTexture - invalid format!");
|
||||||
|
|
@ -73,7 +74,7 @@ GFXTextureObject *GFXGLTextureManager::_createTextureObject( U32 height,
|
||||||
retTex->registerResourceWithDevice( GFX );
|
retTex->registerResourceWithDevice( GFX );
|
||||||
}
|
}
|
||||||
|
|
||||||
innerCreateTexture(retTex, height, width, depth, format, profile, numMipLevels, forceMips);
|
innerCreateTexture(retTex, height, width, depth, format, profile, numMipLevels, forceMips, arraySize);
|
||||||
|
|
||||||
return retTex;
|
return retTex;
|
||||||
}
|
}
|
||||||
|
|
@ -89,19 +90,40 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
|
||||||
GFXFormat format,
|
GFXFormat format,
|
||||||
GFXTextureProfile *profile,
|
GFXTextureProfile *profile,
|
||||||
U32 numMipLevels,
|
U32 numMipLevels,
|
||||||
bool forceMips)
|
bool forceMips,
|
||||||
|
U32 arraySize)
|
||||||
{
|
{
|
||||||
// No 24 bit formats. They trigger various oddities because hardware (and Apple's drivers apparently...) don't natively support them.
|
// No 24 bit formats. They trigger various oddities because hardware (and Apple's drivers apparently...) don't natively support them.
|
||||||
if (format == GFXFormatR8G8B8)
|
if (format == GFXFormatR8G8B8)
|
||||||
format = GFXFormatR8G8B8A8;
|
format = GFXFormatR8G8B8A8;
|
||||||
else if (format == GFXFormatR8G8B8_SRGB)
|
else if (format == GFXFormatR8G8B8_SRGB)
|
||||||
format = GFXFormatR8G8B8A8_SRGB;
|
format = GFXFormatR8G8B8A8_SRGB;
|
||||||
|
|
||||||
|
retTex->mProfile = profile;
|
||||||
retTex->mFormat = format;
|
retTex->mFormat = format;
|
||||||
retTex->mIsZombie = false;
|
retTex->mIsZombie = false;
|
||||||
retTex->mIsNPoT2 = false;
|
retTex->mIsNPoT2 = false;
|
||||||
|
|
||||||
GLenum binding = ( (height == 1 || width == 1) && ( height != width ) ) ? GL_TEXTURE_1D : ( (depth == 0) ? GL_TEXTURE_2D : GL_TEXTURE_3D );
|
const bool isCube = profile->isCubeMap();
|
||||||
|
GLenum binding;
|
||||||
|
|
||||||
|
if (isCube)
|
||||||
|
{
|
||||||
|
binding = (arraySize > 1) ? GL_TEXTURE_CUBE_MAP_ARRAY : GL_TEXTURE_CUBE_MAP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const bool is3D = (depth > 1);
|
||||||
|
const bool is1D = (height == 1 && width > 1);
|
||||||
|
|
||||||
|
if (is3D)
|
||||||
|
binding = GL_TEXTURE_3D;
|
||||||
|
else if (is1D)
|
||||||
|
binding = (arraySize > 1) ? GL_TEXTURE_1D_ARRAY : GL_TEXTURE_1D;
|
||||||
|
else
|
||||||
|
binding = (arraySize > 1) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
|
||||||
|
}
|
||||||
|
|
||||||
if((profile->testFlag(GFXTextureProfile::RenderTarget) || profile->testFlag(GFXTextureProfile::ZTarget)) && (!isPow2(width) || !isPow2(height)) && !depth)
|
if((profile->testFlag(GFXTextureProfile::RenderTarget) || profile->testFlag(GFXTextureProfile::ZTarget)) && (!isPow2(width) || !isPow2(height)) && !depth)
|
||||||
retTex->mIsNPoT2 = true;
|
retTex->mIsNPoT2 = true;
|
||||||
retTex->mBinding = binding;
|
retTex->mBinding = binding;
|
||||||
|
|
@ -155,55 +177,155 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
|
||||||
retTex->mMipLevels = getMaxMipmaps(width, height, 1);
|
retTex->mMipLevels = getMaxMipmaps(width, height, 1);
|
||||||
|
|
||||||
glTexParameteri(binding, GL_TEXTURE_MAX_LEVEL, retTex->mMipLevels-1 );
|
glTexParameteri(binding, GL_TEXTURE_MAX_LEVEL, retTex->mMipLevels-1 );
|
||||||
|
|
||||||
if( GFXGL->mCapabilities.textureStorage )
|
bool hasTexStorage = false;
|
||||||
|
// not supported when creating these.
|
||||||
|
if (arraySize > 1 || isCube || profile->isDynamic())
|
||||||
|
hasTexStorage = false;
|
||||||
|
|
||||||
|
const bool isCompressed = ImageUtil::isCompressedFormat(format);
|
||||||
|
|
||||||
|
// --- Allocation by binding ---
|
||||||
|
if (binding == GL_TEXTURE_CUBE_MAP)
|
||||||
{
|
{
|
||||||
if(binding == GL_TEXTURE_2D)
|
// Single cubemap: prefer glTexStorage2D if available, else per-face texImage2D
|
||||||
glTexStorage2D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height );
|
if (hasTexStorage)
|
||||||
else if(binding == GL_TEXTURE_1D)
|
{
|
||||||
glTexStorage1D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], getMax(width, height) );
|
// Some drivers accept texStorage2D with GL_TEXTURE_CUBE_MAP
|
||||||
else
|
glTexStorage2D(GL_TEXTURE_CUBE_MAP, retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height);
|
||||||
glTexStorage3D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height, depth );
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Explicitly allocate each face/level
|
||||||
|
for (U32 face = 0; face < 6; ++face)
|
||||||
|
{
|
||||||
|
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
|
||||||
|
{
|
||||||
|
U32 mipW = getMax(1u, width >> mip);
|
||||||
|
U32 mipH = getMax(1u, height >> mip);
|
||||||
|
|
||||||
|
if (isCompressed)
|
||||||
|
{
|
||||||
|
U32 size = getCompressedSurfaceSize(format, width, height, mip);
|
||||||
|
glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, GFXGLTextureInternalFormat[format], mipW, mipH, 0, size, nullptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mip, GFXGLTextureInternalFormat[format], mipW, mipH, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (binding == GL_TEXTURE_CUBE_MAP_ARRAY)
|
||||||
{
|
{
|
||||||
//If it wasn't for problems on amd drivers this next part could be really simplified and we wouldn't need to go through manually creating our
|
// cube-map array: layers = arraySize * 6
|
||||||
//mipmap pyramid and instead just use glGenerateMipmap
|
U32 layers = getMax(1u, arraySize) * 6u;
|
||||||
if(ImageUtil::isCompressedFormat(format))
|
if (hasTexStorage)
|
||||||
{
|
{
|
||||||
AssertFatal(binding == GL_TEXTURE_2D,
|
glTexStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height, layers);
|
||||||
"GFXGLTextureManager::innerCreateTexture - Only compressed 2D textures are supported");
|
}
|
||||||
|
else
|
||||||
U32 tempWidth = width;
|
{
|
||||||
U32 tempHeight = height;
|
// fallback to glTexImage3D with NULL data
|
||||||
U32 size = getCompressedSurfaceSize(format,height,width);
|
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
|
||||||
//Fill compressed images with 0's
|
{
|
||||||
U8 *pTemp = (U8*)dMalloc(sizeof(U8)*size);
|
U32 mipW = getMax(1u, width >> mip);
|
||||||
dMemset(pTemp,0,size);
|
U32 mipH = getMax(1u, height >> mip);
|
||||||
|
glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, GFXGLTextureInternalFormat[format], mipW, mipH, layers, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
|
||||||
for(U32 i=0;i< retTex->mMipLevels;i++)
|
}
|
||||||
{
|
}
|
||||||
tempWidth = getMax( U32(1), width >> i );
|
|
||||||
tempHeight = getMax( U32(1), height >> i );
|
|
||||||
size = getCompressedSurfaceSize(format,width,height,i);
|
|
||||||
glCompressedTexImage2D(binding,i,GFXGLTextureInternalFormat[format],tempWidth,tempHeight,0,size,pTemp);
|
|
||||||
}
|
|
||||||
|
|
||||||
dFree(pTemp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(binding == GL_TEXTURE_2D)
|
|
||||||
glTexImage2D(binding, 0, GFXGLTextureInternalFormat[format], width, height, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
|
|
||||||
else if(binding == GL_TEXTURE_1D)
|
|
||||||
glTexImage1D(binding, 0, GFXGLTextureInternalFormat[format], (width > 1 ? width : height), 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
|
|
||||||
else
|
|
||||||
glTexImage3D(GL_TEXTURE_3D, 0, GFXGLTextureInternalFormat[format], width, height, depth, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
|
|
||||||
|
|
||||||
if(retTex->mMipLevels > 1)
|
|
||||||
glGenerateMipmap(binding);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (binding == GL_TEXTURE_2D_ARRAY)
|
||||||
|
{
|
||||||
|
// 2D texture array: depth = arraySize (layers)
|
||||||
|
U32 layers = getMax(1u, arraySize);
|
||||||
|
if (hasTexStorage)
|
||||||
|
{
|
||||||
|
glTexStorage3D(GL_TEXTURE_2D_ARRAY, retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height, layers);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
|
||||||
|
{
|
||||||
|
U32 mipW = getMax(1u, width >> mip);
|
||||||
|
U32 mipH = getMax(1u, height >> mip);
|
||||||
|
glTexImage3D(GL_TEXTURE_2D_ARRAY, mip, GFXGLTextureInternalFormat[format], mipW, mipH, layers, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (binding == GL_TEXTURE_1D_ARRAY)
|
||||||
|
{
|
||||||
|
// 1D array stored as GL_TEXTURE_1D_ARRAY. glTexStorage2D can be used for 1D arrays with height=layers on many drivers.
|
||||||
|
U32 layers = getMax(1u, arraySize);
|
||||||
|
if (hasTexStorage)
|
||||||
|
{
|
||||||
|
// glTexStorage2D works for GL_TEXTURE_1D_ARRAY (width, layers)
|
||||||
|
glTexStorage2D(GL_TEXTURE_1D_ARRAY, retTex->mMipLevels, GFXGLTextureInternalFormat[format], getMax(width, height), layers);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// fallback: allocate as 2D where the "height" dimension is layers via glTexImage2D? Not ideal.
|
||||||
|
// Safer: use glTexImage2D with target GL_TEXTURE_1D_ARRAY is invalid; instead use glTexImage3D with depth=layers
|
||||||
|
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
|
||||||
|
{
|
||||||
|
U32 mipW = getMax(1u, getMax(width, height) >> mip);
|
||||||
|
glTexImage3D(GL_TEXTURE_1D_ARRAY, mip, GFXGLTextureInternalFormat[format], mipW, layers, 1, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (binding == GL_TEXTURE_1D)
|
||||||
|
{
|
||||||
|
if (hasTexStorage)
|
||||||
|
glTexStorage1D(GL_TEXTURE_1D, retTex->mMipLevels, GFXGLTextureInternalFormat[format], getMax(width, height));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
|
||||||
|
{
|
||||||
|
U32 mipW = getMax(1u, getMax(width, height) >> mip);
|
||||||
|
glTexImage1D(GL_TEXTURE_1D, mip, GFXGLTextureInternalFormat[format], mipW, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (binding == GL_TEXTURE_3D)
|
||||||
|
{
|
||||||
|
if (hasTexStorage)
|
||||||
|
glTexStorage3D(GL_TEXTURE_3D, retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height, depth);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
|
||||||
|
{
|
||||||
|
U32 mipW = getMax(1u, width >> mip);
|
||||||
|
U32 mipH = getMax(1u, height >> mip);
|
||||||
|
U32 mipD = getMax(1u, depth >> mip);
|
||||||
|
glTexImage3D(GL_TEXTURE_3D, mip, GFXGLTextureInternalFormat[format], mipW, mipH, mipD, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // GL_TEXTURE_2D (default)
|
||||||
|
{
|
||||||
|
if (hasTexStorage)
|
||||||
|
glTexStorage2D(GL_TEXTURE_2D, retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
|
||||||
|
{
|
||||||
|
U32 mipW = getMax(1u, width >> mip);
|
||||||
|
U32 mipH = getMax(1u, height >> mip);
|
||||||
|
|
||||||
|
if (isCompressed)
|
||||||
|
{
|
||||||
|
U32 size = getCompressedSurfaceSize(format, width, height, mip);
|
||||||
|
glCompressedTexImage2D(GL_TEXTURE_2D, mip, GFXGLTextureInternalFormat[format], mipW, mipH, 0, size, nullptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, mip, GFXGLTextureInternalFormat[format], mipW, mipH, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Complete the texture
|
// Complete the texture
|
||||||
// Complete the texture - this does get changed later but we need to complete the texture anyway
|
// Complete the texture - this does get changed later but we need to complete the texture anyway
|
||||||
|
|
@ -221,14 +343,20 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
|
||||||
if(GFXGLTextureSwizzle[format])
|
if(GFXGLTextureSwizzle[format])
|
||||||
glTexParameteriv(binding, GL_TEXTURE_SWIZZLE_RGBA, GFXGLTextureSwizzle[format]);
|
glTexParameteriv(binding, GL_TEXTURE_SWIZZLE_RGBA, GFXGLTextureSwizzle[format]);
|
||||||
|
|
||||||
// Get the size from GL (you never know...)
|
GLint texHeight = 0, texWidth = 0, texDepth = 0;
|
||||||
GLint texHeight, texWidth, texDepth = 0;
|
|
||||||
|
GLenum queryTarget = binding;
|
||||||
glGetTexLevelParameteriv(binding, 0, GL_TEXTURE_WIDTH, &texWidth);
|
if (binding == GL_TEXTURE_CUBE_MAP)
|
||||||
glGetTexLevelParameteriv(binding, 0, GL_TEXTURE_HEIGHT, &texHeight);
|
{
|
||||||
if(binding == GL_TEXTURE_3D)
|
// Query a specific face, e.g. +X
|
||||||
glGetTexLevelParameteriv(binding, 0, GL_TEXTURE_DEPTH, &texDepth);
|
queryTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
glGetTexLevelParameteriv(queryTarget, 0, GL_TEXTURE_WIDTH, &texWidth);
|
||||||
|
glGetTexLevelParameteriv(queryTarget, 0, GL_TEXTURE_HEIGHT, &texHeight);
|
||||||
|
if (binding == GL_TEXTURE_3D)
|
||||||
|
glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &texDepth);
|
||||||
|
|
||||||
retTex->mTextureSize.set(texWidth, texHeight, texDepth);
|
retTex->mTextureSize.set(texWidth, texHeight, texDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -236,7 +364,7 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
|
||||||
// loadTexture - GBitmap
|
// loadTexture - GBitmap
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
static void _textureUpload(const S32 width, const S32 height,const S32 bytesPerPixel,const GFXGLTextureObject* texture, const GFXFormat fmt, const U8* data,const S32 mip=0, Swizzle<U8, 4> *pSwizzle = NULL)
|
static void _textureUpload(const S32 width, const S32 height,const S32 bytesPerPixel,const GFXGLTextureObject* texture, const GFXFormat fmt, const U8* data,const S32 mip=0, const U32 face = 0, Swizzle<U8, 4> *pSwizzle = NULL)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->getBuffer());
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->getBuffer());
|
||||||
U32 bufSize = width * height * bytesPerPixel;
|
U32 bufSize = width * height * bytesPerPixel;
|
||||||
|
|
@ -256,7 +384,9 @@ static void _textureUpload(const S32 width, const S32 height,const S32 bytesPerP
|
||||||
glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, bufSize, data);
|
glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, bufSize, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texture->getBinding() == GL_TEXTURE_2D)
|
if(texture->getBinding() == GL_TEXTURE_CUBE_MAP)
|
||||||
|
glTexSubImage2D(GFXGLFaceType[face], mip, 0, 0, width, height, GFXGLTextureFormat[fmt], GFXGLTextureType[fmt], NULL);
|
||||||
|
else if (texture->getBinding() == GL_TEXTURE_2D)
|
||||||
glTexSubImage2D(texture->getBinding(), mip, 0, 0, width, height, GFXGLTextureFormat[fmt], GFXGLTextureType[fmt], NULL);
|
glTexSubImage2D(texture->getBinding(), mip, 0, 0, width, height, GFXGLTextureFormat[fmt], GFXGLTextureType[fmt], NULL);
|
||||||
else
|
else
|
||||||
glTexSubImage1D(texture->getBinding(), mip, 0, (width > 1 ? width : height), GFXGLTextureFormat[fmt], GFXGLTextureType[fmt], NULL);
|
glTexSubImage1D(texture->getBinding(), mip, 0, (width > 1 ? width : height), GFXGLTextureFormat[fmt], GFXGLTextureType[fmt], NULL);
|
||||||
|
|
@ -266,76 +396,125 @@ static void _textureUpload(const S32 width, const S32 height,const S32 bytesPerP
|
||||||
|
|
||||||
bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *pDL)
|
bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *pDL)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPE(GFXGLTextureManager_loadTexture);
|
PROFILE_SCOPE(GFXGLTextureManager_loadTextureGBitmap);
|
||||||
GFXGLTextureObject *texture = static_cast<GFXGLTextureObject*>(aTexture);
|
GFXGLTextureObject *texture = static_cast<GFXGLTextureObject*>(aTexture);
|
||||||
|
|
||||||
AssertFatal(texture->getBinding() == GL_TEXTURE_1D || texture->getBinding() == GL_TEXTURE_2D,
|
const GLenum target = texture->getBinding();
|
||||||
"GFXGLTextureManager::_loadTexture(GBitmap) - This method can only be used with 1D/2D textures");
|
|
||||||
|
AssertFatal(target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP,
|
||||||
|
"GFXGLTextureManager::_loadTexture(GBitmap) - This method can only be used with 1D/2D and CubeMap textures");
|
||||||
|
|
||||||
if(texture->getBinding() == GL_TEXTURE_3D)
|
if(texture->getBinding() == GL_TEXTURE_3D)
|
||||||
return false;
|
return false;
|
||||||
|
//
|
||||||
// No 24bit formats.
|
//// No 24bit formats.
|
||||||
if(pDL->getFormat() == GFXFormatR8G8B8)
|
//if(pDL->getFormat() == GFXFormatR8G8B8)
|
||||||
pDL->setFormat(GFXFormatR8G8B8A8);
|
// pDL->setFormat(GFXFormatR8G8B8A8);
|
||||||
else if (pDL->getFormat() == GFXFormatR8G8B8_SRGB)
|
//else if (pDL->getFormat() == GFXFormatR8G8B8_SRGB)
|
||||||
pDL->setFormat(GFXFormatR8G8B8A8_SRGB);
|
// pDL->setFormat(GFXFormatR8G8B8A8_SRGB);
|
||||||
|
|
||||||
// Bind to edit
|
// Bind to edit
|
||||||
PRESERVE_TEXTURE(texture->getBinding());
|
PRESERVE_TEXTURE(texture->getBinding());
|
||||||
glBindTexture(texture->getBinding(), texture->getHandle());
|
glBindTexture(texture->getBinding(), texture->getHandle());
|
||||||
|
|
||||||
_textureUpload(pDL->getWidth(),pDL->getHeight(),pDL->getBytesPerPixel(),texture,pDL->getFormat(), pDL->getBits(), 0);
|
const U32 mipLevels = texture->getMipLevels();
|
||||||
|
const bool isCubemap = (target == GL_TEXTURE_CUBE_MAP) && pDL->getNumFaces() > 1;
|
||||||
|
U32 faceCount = isCubemap ? 6 : 1;
|
||||||
|
|
||||||
if(!ImageUtil::isCompressedFormat(pDL->getFormat()))
|
for (U32 mip = 0; mip < mipLevels; mip++)
|
||||||
glGenerateMipmap(texture->getBinding());
|
{
|
||||||
|
const GLsizei width = getMax(1u, pDL->getWidth(mip));
|
||||||
|
const GLsizei height = getMax(1u, pDL->getHeight(mip));
|
||||||
|
for (U32 face = 0; face < faceCount; ++face)
|
||||||
|
{
|
||||||
|
_textureUpload(width, height, pDL->getBytesPerPixel(), texture, pDL->getFormat(), pDL->getBits(mip,face), mip, face);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ImageUtil::isCompressedFormat(pDL->getFormat()))
|
||||||
|
glGenerateMipmap(texture->getBinding());
|
||||||
|
|
||||||
|
glBindTexture(target, 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds)
|
bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds)
|
||||||
{
|
{
|
||||||
|
PROFILE_SCOPE(GFXGLTextureManager_loadTextureDDS);
|
||||||
GFXGLTextureObject* texture = static_cast<GFXGLTextureObject*>(aTexture);
|
GFXGLTextureObject* texture = static_cast<GFXGLTextureObject*>(aTexture);
|
||||||
|
|
||||||
AssertFatal(texture->getBinding() == GL_TEXTURE_2D,
|
const GLenum target = texture->getBinding();
|
||||||
"GFXGLTextureManager::_loadTexture(DDSFile) - This method can only be used with 2D textures");
|
|
||||||
|
const bool isCube = texture->getBinding() == GL_TEXTURE_CUBE_MAP && dds->isCubemap();
|
||||||
if(texture->getBinding() != GL_TEXTURE_2D)
|
const bool isCompressed = ImageUtil::isCompressedFormat(texture->mFormat);
|
||||||
return false;
|
|
||||||
|
AssertFatal(target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP,
|
||||||
PRESERVE_TEXTURE(texture->getBinding());
|
"GFXGLTextureManager::_loadTexture(DDS) - This method can only be used with 1D/2D and CubeMap textures");
|
||||||
glBindTexture(texture->getBinding(), texture->getHandle());
|
|
||||||
U32 numMips = dds->mSurfaces[0]->mMips.size();
|
if (texture->getBinding() == GL_TEXTURE_3D)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
PRESERVE_TEXTURE(target);
|
||||||
|
glBindTexture(target, texture->getHandle());
|
||||||
|
|
||||||
|
const U32 numFaces = isCube ? 6 : 1;
|
||||||
|
const U32 numMips = dds->mSurfaces[0]->mMips.size();
|
||||||
const GFXFormat fmt = texture->mFormat;
|
const GFXFormat fmt = texture->mFormat;
|
||||||
|
|
||||||
for(U32 i = 0; i < numMips; i++)
|
for (U32 face = 0; face < numFaces; ++face)
|
||||||
{
|
{
|
||||||
PROFILE_SCOPE(GFXGLTexMan_loadSurface);
|
// Skip empty surfaces
|
||||||
|
if (!dds->mSurfaces[face])
|
||||||
|
continue;
|
||||||
|
|
||||||
if(ImageUtil::isCompressedFormat(texture->mFormat))
|
for (U32 mip = 0; mip < numMips; ++mip)
|
||||||
{
|
{
|
||||||
if((!isPow2(dds->getWidth()) || !isPow2(dds->getHeight())) && GFX->getCardProfiler()->queryProfile("GL::Workaround::noCompressedNPoTTextures"))
|
const U32 mipWidth = getMax(1u, dds->getWidth(mip));
|
||||||
|
const U32 mipHeight = getMax(1u, dds->getHeight(mip));
|
||||||
|
|
||||||
|
GLenum uploadTarget = target;
|
||||||
|
if (isCube)
|
||||||
|
uploadTarget = GFXGLFaceType[face];
|
||||||
|
|
||||||
|
if (isCompressed)
|
||||||
{
|
{
|
||||||
U8* uncompressedTex = new U8[dds->getWidth(i) * dds->getHeight(i) * 4];
|
// Handle NPOT workaround
|
||||||
ImageUtil::decompress(dds->mSurfaces[0]->mMips[i],uncompressedTex, dds->getWidth(i), dds->getHeight(i), fmt);
|
if ((!isPow2(mipWidth) || !isPow2(mipHeight)) && GFX->getCardProfiler()->queryProfile("GL::Workaround::noCompressedNPoTTextures"))
|
||||||
glTexSubImage2D(texture->getBinding(), i, 0, 0, dds->getWidth(i), dds->getHeight(i), GL_RGBA, GL_UNSIGNED_BYTE, uncompressedTex);
|
{
|
||||||
delete[] uncompressedTex;
|
U8* uncompressedTex = new U8[mipWidth * mipHeight * 4];
|
||||||
|
ImageUtil::decompress(dds->mSurfaces[face]->mMips[mip], uncompressedTex, mipWidth, mipHeight, fmt);
|
||||||
|
glTexSubImage2D(uploadTarget,
|
||||||
|
mip, 0, 0, mipWidth, mipHeight, GL_RGBA, GL_UNSIGNED_BYTE, uncompressedTex
|
||||||
|
);
|
||||||
|
delete[] uncompressedTex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glCompressedTexImage2D(uploadTarget,
|
||||||
|
mip, GFXGLTextureInternalFormat[fmt], mipWidth, mipHeight, 0,
|
||||||
|
dds->getSurfaceSize(mip), dds->mSurfaces[face]->mMips[mip]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
glCompressedTexSubImage2D(texture->getBinding(), i, 0, 0, dds->getWidth(i), dds->getHeight(i), GFXGLTextureInternalFormat[fmt], dds->getSurfaceSize(dds->getHeight(), dds->getWidth(), i), dds->mSurfaces[0]->mMips[i]);
|
{
|
||||||
}
|
Swizzle<U8, 4>* pSwizzle = nullptr;
|
||||||
else
|
if (fmt == GFXFormatR8G8B8A8 || fmt == GFXFormatR8G8B8X8 || fmt == GFXFormatR8G8B8A8_SRGB ||
|
||||||
{
|
fmt == GFXFormatR8G8B8A8_LINEAR_FORCE || fmt == GFXFormatB8G8R8A8)
|
||||||
Swizzle<U8, 4> *pSwizzle = NULL;
|
pSwizzle = &Swizzles::bgra;
|
||||||
if (fmt == GFXFormatR8G8B8A8 || fmt == GFXFormatR8G8B8X8 || fmt == GFXFormatR8G8B8A8_SRGB || fmt == GFXFormatR8G8B8A8_LINEAR_FORCE || fmt == GFXFormatB8G8R8A8)
|
|
||||||
pSwizzle = &Swizzles::bgra;
|
_textureUpload(
|
||||||
|
mipWidth, mipHeight, dds->mBytesPerPixel, texture, fmt,
|
||||||
|
dds->mSurfaces[face]->mMips[mip], mip, face, pSwizzle);
|
||||||
|
}
|
||||||
|
|
||||||
_textureUpload(dds->getWidth(i), dds->getHeight(i),dds->mBytesPerPixel, texture, fmt, dds->mSurfaces[0]->mMips[i],i, pSwizzle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(numMips !=1 && !ImageUtil::isCompressedFormat(texture->mFormat))
|
if (numMips != 1 && !isCompressed)
|
||||||
glGenerateMipmap(texture->getBinding());
|
glGenerateMipmap(texture->getBinding());
|
||||||
|
|
||||||
|
glBindTexture(target, 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ protected:
|
||||||
U32 numMipLevels,
|
U32 numMipLevels,
|
||||||
bool forceMips = false,
|
bool forceMips = false,
|
||||||
S32 antialiasLevel = 0,
|
S32 antialiasLevel = 0,
|
||||||
|
U32 arraySize = 1,
|
||||||
GFXTextureObject *inTex = NULL ) override;
|
GFXTextureObject *inTex = NULL ) override;
|
||||||
bool _loadTexture(GFXTextureObject *texture, DDSFile *dds) override;
|
bool _loadTexture(GFXTextureObject *texture, DDSFile *dds) override;
|
||||||
bool _loadTexture(GFXTextureObject *texture, GBitmap *bmp) override;
|
bool _loadTexture(GFXTextureObject *texture, GBitmap *bmp) override;
|
||||||
|
|
@ -56,7 +57,7 @@ private:
|
||||||
friend class GFXGLTextureObject;
|
friend class GFXGLTextureObject;
|
||||||
|
|
||||||
/// Creates internal GL texture
|
/// Creates internal GL texture
|
||||||
void innerCreateTexture(GFXGLTextureObject *obj, U32 height, U32 width, U32 depth, GFXFormat format, GFXTextureProfile *profile, U32 numMipLevels, bool forceMips = false);
|
void innerCreateTexture(GFXGLTextureObject *obj, U32 height, U32 width, U32 depth, GFXFormat format, GFXTextureProfile *profile, U32 numMipLevels, bool forceMips = false, U32 arraySize = 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ GFXGLTextureObject::~GFXGLTextureObject()
|
||||||
kill();
|
kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
GFXLockedRect* GFXGLTextureObject::lock(U32 mipLevel, RectI *inRect)
|
GFXLockedRect* GFXGLTextureObject::lock(U32 mipLevel /*= 0*/, RectI* inRect /*= NULL*/, U32 faceIndex /*= 0*/)
|
||||||
{
|
{
|
||||||
//AssertFatal(mBinding != GL_TEXTURE_3D, "GFXGLTextureObject::lock - We don't support locking 3D textures yet");
|
//AssertFatal(mBinding != GL_TEXTURE_3D, "GFXGLTextureObject::lock - We don't support locking 3D textures yet");
|
||||||
U32 width = mTextureSize.x >> mipLevel;
|
U32 width = mTextureSize.x >> mipLevel;
|
||||||
|
|
@ -100,7 +100,7 @@ GFXLockedRect* GFXGLTextureObject::lock(U32 mipLevel, RectI *inRect)
|
||||||
return &mLockedRect;
|
return &mLockedRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXGLTextureObject::unlock(U32 mipLevel)
|
void GFXGLTextureObject::unlock(U32 mipLevel /*= 0*/, U32 faceIndex /*= 0*/)
|
||||||
{
|
{
|
||||||
if(!mLockedRect.bits)
|
if(!mLockedRect.bits)
|
||||||
return;
|
return;
|
||||||
|
|
@ -175,38 +175,231 @@ bool GFXGLTextureObject::copyToBmp(GBitmap * bmp)
|
||||||
|
|
||||||
FrameAllocatorMarker mem;
|
FrameAllocatorMarker mem;
|
||||||
|
|
||||||
|
const bool isCubemap = (mBinding == GL_TEXTURE_CUBE_MAP);
|
||||||
|
const U32 numFaces = isCubemap ? 6 : 1;
|
||||||
|
|
||||||
U32 mipLevels = getMipLevels();
|
for (U32 mip = 0; mip < getMipLevels(); mip++)
|
||||||
for (U32 mip = 0; mip < mipLevels; mip++)
|
|
||||||
{
|
{
|
||||||
U32 srcPixelCount = bmp->getSurfaceSize(mip)/ srcBytesPerPixel;
|
U32 width = getWidth() >> mip;
|
||||||
|
U32 height = getHeight() >> mip;
|
||||||
|
if (width == 0) width = 1;
|
||||||
|
if (height == 0) height = 1;
|
||||||
|
|
||||||
U8* dest = bmp->getWritableBits(mip);
|
// Check if multisampled
|
||||||
U8* orig = (U8*)mem.alloc(srcPixelCount * srcBytesPerPixel);
|
GLint samples = 0;
|
||||||
|
GLenum target = mBinding;
|
||||||
|
if (mBinding == GL_TEXTURE_CUBE_MAP)
|
||||||
|
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
|
||||||
|
|
||||||
glGetTexImage(mBinding, mip, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], orig);
|
glGetTexLevelParameteriv(target, mip, GL_TEXTURE_SAMPLES, &samples);
|
||||||
if (mFormat == GFXFormatR16G16B16A16F)
|
if (samples > 0)
|
||||||
{
|
{
|
||||||
dMemcpy(dest, orig, srcPixelCount * srcBytesPerPixel);
|
Con::warnf("GFXGLTextureObject::copyToBmp - Texture is multisampled (%d samples) at mip %d; resolve first.", samples, mip);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < srcPixelCount; ++i)
|
|
||||||
{
|
|
||||||
dest[0] = orig[0];
|
|
||||||
dest[1] = orig[1];
|
|
||||||
dest[2] = orig[2];
|
|
||||||
if (dstBytesPerPixel == 4)
|
|
||||||
dest[3] = orig[3];
|
|
||||||
|
|
||||||
orig += srcBytesPerPixel;
|
for (U32 face = 0; face < numFaces; face++)
|
||||||
dest += dstBytesPerPixel;
|
{
|
||||||
|
GLenum faceTarget = isCubemap ? GFXGLFaceType[face] : mBinding;
|
||||||
|
|
||||||
|
U32 pixelCount = width * height;
|
||||||
|
U8* srcPixels = (U8*)mem.alloc(pixelCount * srcBytesPerPixel);
|
||||||
|
U8* dest = bmp->getWritableBits(mip, face);
|
||||||
|
|
||||||
|
if (!dest)
|
||||||
|
{
|
||||||
|
Con::errorf("GFXGLTextureObject::copyToBmp - No destination bits for mip=%u face=%u", mip, face);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read texture data
|
||||||
|
glGetTexImage(faceTarget, mip, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], srcPixels);
|
||||||
|
|
||||||
|
if (mFormat == GFXFormatR16G16B16A16F)
|
||||||
|
{
|
||||||
|
dMemcpy(dest, srcPixels, pixelCount * srcBytesPerPixel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Simple 8-bit per channel copy (RGBA)
|
||||||
|
U8* src = srcPixels;
|
||||||
|
for (U32 i = 0; i < pixelCount; ++i)
|
||||||
|
{
|
||||||
|
dest[0] = src[0];
|
||||||
|
dest[1] = src[1];
|
||||||
|
dest[2] = src[2];
|
||||||
|
if (dstBytesPerPixel == 4)
|
||||||
|
dest[3] = src[3];
|
||||||
|
|
||||||
|
src += srcBytesPerPixel;
|
||||||
|
dest += dstBytesPerPixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // face
|
||||||
|
} // mip
|
||||||
|
|
||||||
|
glBindTexture(mBinding, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GFXGLTextureObject::updateTextureSlot(const GFXTexHandle& texHandle, const U32 slot, const S32 face)
|
||||||
|
{
|
||||||
|
if (!texHandle.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
GFXGLTextureObject* srcTex = static_cast<GFXGLTextureObject*>(texHandle.getPointer());
|
||||||
|
if (!srcTex || srcTex->getHandle() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const GLenum dstTarget = mBinding; // destination binding (this)
|
||||||
|
const GLenum srcTarget = srcTex->getBinding(); // source binding
|
||||||
|
const bool srcIsCube = (srcTarget == GL_TEXTURE_CUBE_MAP || srcTarget == GL_TEXTURE_CUBE_MAP_ARRAY);
|
||||||
|
|
||||||
|
// Determine list of faces to copy from source
|
||||||
|
U32 firstFace = 0;
|
||||||
|
U32 faceCount = 1;
|
||||||
|
if (face >= 0)
|
||||||
|
{
|
||||||
|
firstFace = (U32)face;
|
||||||
|
faceCount = 1;
|
||||||
|
}
|
||||||
|
else if (srcIsCube)
|
||||||
|
{
|
||||||
|
firstFace = 0;
|
||||||
|
faceCount = 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
firstFace = 0;
|
||||||
|
faceCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure textures are valid
|
||||||
|
if (!glIsTexture(mHandle) || !glIsTexture(srcTex->getHandle()))
|
||||||
|
{
|
||||||
|
Con::errorf("updateTextureSlot: invalid GL texture handle src=%u dst=%u", srcTex->getHandle(), mHandle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If copyImage supported, prefer that. We'll copy face-by-face (one-layer depth = 1)
|
||||||
|
if (GFXGL->mCapabilities.copyImage)
|
||||||
|
{
|
||||||
|
for (U32 mip = 0; mip < getMipLevels(); ++mip)
|
||||||
|
{
|
||||||
|
const GLsizei mipW = getMax(1u, srcTex->getWidth() >> mip);
|
||||||
|
const GLsizei mipH = getMax(1u, srcTex->getHeight() >> mip);
|
||||||
|
|
||||||
|
for (U32 f = firstFace; f < firstFace + faceCount; ++f)
|
||||||
|
{
|
||||||
|
// Compute source z offset (for cube arrays it's layer index; for cubemap it's face index)
|
||||||
|
GLint srcZ = 0;
|
||||||
|
if (srcTarget == GL_TEXTURE_CUBE_MAP_ARRAY)
|
||||||
|
{
|
||||||
|
srcZ = f;
|
||||||
|
}
|
||||||
|
else if (srcTarget == GL_TEXTURE_CUBE_MAP)
|
||||||
|
{
|
||||||
|
srcZ = f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
srcZ = 0; // 2D source
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute destination layer (z offset) depending on destination type
|
||||||
|
GLint dstZ = 0;
|
||||||
|
if (dstTarget == GL_TEXTURE_CUBE_MAP_ARRAY)
|
||||||
|
{
|
||||||
|
// each slot is a whole cubemap => slot * 6 + faceIndex
|
||||||
|
dstZ = (GLint)(slot * 6 + f);
|
||||||
|
}
|
||||||
|
else if (dstTarget == GL_TEXTURE_2D_ARRAY)
|
||||||
|
{
|
||||||
|
dstZ = (GLint)slot; // each slot is a single layer
|
||||||
|
}
|
||||||
|
else if (dstTarget == GL_TEXTURE_CUBE_MAP)
|
||||||
|
{
|
||||||
|
dstZ = (GLint)f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dstZ = 0; // 2D texture target
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy single layer/face at this mip
|
||||||
|
glCopyImageSubData(
|
||||||
|
srcTex->getHandle(), srcTarget, mip, 0, 0, srcZ,
|
||||||
|
mHandle, dstTarget, mip, 0, 0, dstZ,
|
||||||
|
mipW, mipH, 1
|
||||||
|
);
|
||||||
|
|
||||||
|
GLenum err = glGetError();
|
||||||
|
if (err != GL_NO_ERROR)
|
||||||
|
Con::errorf("glCopyImageSubData failed with 0x%X (mip=%u face=%u)", err, mip, f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
glBindTexture(mBinding, 0);
|
|
||||||
|
|
||||||
return true;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: CPU-side copy using glGetTexImage + glTexSubImage
|
||||||
|
for (U32 mip = 0; mip < getMipLevels() && mip < srcTex->getMipLevels(); ++mip)
|
||||||
|
{
|
||||||
|
const GLsizei mipW = getMax(1u, srcTex->getWidth() >> mip);
|
||||||
|
const GLsizei mipH = getMax(1u, srcTex->getHeight() >> mip);
|
||||||
|
const U32 pixelSize = GFXFormat_getByteSize(mFormat); // assuming same fmt for src/dst
|
||||||
|
const U32 dataSize = mipW * mipH * pixelSize;
|
||||||
|
|
||||||
|
FrameAllocatorMarker mem;
|
||||||
|
U8* buffer = (U8*)mem.alloc(dataSize);
|
||||||
|
|
||||||
|
glBindTexture(srcTarget, srcTex->getHandle());
|
||||||
|
glBindTexture(dstTarget, mHandle);
|
||||||
|
|
||||||
|
for (U32 f = firstFace; f < firstFace + faceCount; ++f)
|
||||||
|
{
|
||||||
|
GLenum srcFaceTarget = srcTarget;
|
||||||
|
if (srcTarget == GL_TEXTURE_CUBE_MAP)
|
||||||
|
srcFaceTarget = GFXGLFaceType[f];
|
||||||
|
|
||||||
|
// read pixels from source
|
||||||
|
glGetTexImage(srcFaceTarget, mip, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], buffer);
|
||||||
|
|
||||||
|
GLint dstLayer = 0;
|
||||||
|
if (dstTarget == GL_TEXTURE_CUBE_MAP_ARRAY)
|
||||||
|
dstLayer = (GLint)(slot * 6 + f);
|
||||||
|
else if (dstTarget == GL_TEXTURE_2D_ARRAY)
|
||||||
|
dstLayer = (GLint)slot;
|
||||||
|
else if (dstTarget == GL_TEXTURE_CUBE_MAP)
|
||||||
|
dstLayer = (GLint)f;
|
||||||
|
else
|
||||||
|
dstLayer = 0;
|
||||||
|
|
||||||
|
if (dstTarget == GL_TEXTURE_CUBE_MAP)
|
||||||
|
{
|
||||||
|
GLenum dstFaceTarget = GFXGLFaceType[f];
|
||||||
|
glTexSubImage2D(dstFaceTarget, mip, 0, 0, mipW, mipH,
|
||||||
|
GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], buffer);
|
||||||
|
}
|
||||||
|
else if (dstTarget == GL_TEXTURE_2D)
|
||||||
|
{
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, mip, 0, 0, mipW, mipH,
|
||||||
|
GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], buffer);
|
||||||
|
}
|
||||||
|
else if (dstTarget == GL_TEXTURE_2D_ARRAY || dstTarget == GL_TEXTURE_CUBE_MAP_ARRAY)
|
||||||
|
{
|
||||||
|
glTexSubImage3D(dstTarget, mip, 0, 0, dstLayer, mipW, mipH, 1,
|
||||||
|
GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(dstTarget, 0);
|
||||||
|
glBindTexture(srcTarget, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GFXGLTextureObject::copyTo(GFXTextureObject* dstTex)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXGLTextureObject::initSamplerState(const GFXSamplerStateDesc &ssd)
|
void GFXGLTextureObject::initSamplerState(const GFXSamplerStateDesc &ssd)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,9 @@
|
||||||
#include "gfx/gfxTextureObject.h"
|
#include "gfx/gfxTextureObject.h"
|
||||||
#include "gfx/gl/tGL/tGL.h"
|
#include "gfx/gl/tGL/tGL.h"
|
||||||
#include "gfx/gfxStateBlock.h"
|
#include "gfx/gfxStateBlock.h"
|
||||||
|
#ifndef _MRECT_H_
|
||||||
|
#include "math/mRect.h"
|
||||||
|
#endif
|
||||||
class GFXGLDevice;
|
class GFXGLDevice;
|
||||||
|
|
||||||
class GFXGLTextureObject : public GFXTextureObject
|
class GFXGLTextureObject : public GFXTextureObject
|
||||||
|
|
@ -64,11 +66,13 @@ public:
|
||||||
|
|
||||||
/// Get/set data from texture (for dynamic textures and render targets)
|
/// Get/set data from texture (for dynamic textures and render targets)
|
||||||
/// @attention DO NOT READ FROM THE RETURNED RECT! It is not guaranteed to work and may incur significant performance penalties.
|
/// @attention DO NOT READ FROM THE RETURNED RECT! It is not guaranteed to work and may incur significant performance penalties.
|
||||||
GFXLockedRect* lock(U32 mipLevel = 0, RectI *inRect = NULL) override;
|
GFXLockedRect* lock(U32 mipLevel = 0, RectI *inRect = NULL, U32 faceIndex = 0) override;
|
||||||
void unlock(U32 mipLevel = 0 ) override;
|
void unlock(U32 mipLevel = 0, U32 faceIndex = 0) override;
|
||||||
|
|
||||||
bool copyToBmp(GBitmap *) override; ///< Not implemented
|
bool copyToBmp(GBitmap *) override; ///< Not implemented
|
||||||
|
void updateTextureSlot(const GFXTexHandle& texHandle, const U32 slot, const S32 face = -1) override;
|
||||||
|
void copyTo(GFXTextureObject* dstTex) override;
|
||||||
|
void generateMipMaps() override {};
|
||||||
bool mIsNPoT2;
|
bool mIsNPoT2;
|
||||||
|
|
||||||
// GFXResource interface
|
// GFXResource interface
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,9 @@ public:
|
||||||
mipLevel(_mipLevel), zOffset(_zOffset)
|
mipLevel(_mipLevel), zOffset(_zOffset)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~_GFXGLTargetDesc() {}
|
virtual ~_GFXGLTargetDesc() {}
|
||||||
|
|
||||||
virtual U32 getHandle() = 0;
|
virtual U32 getHandle() = 0;
|
||||||
virtual U32 getWidth() = 0;
|
virtual U32 getWidth() = 0;
|
||||||
virtual U32 getHeight() = 0;
|
virtual U32 getHeight() = 0;
|
||||||
|
|
@ -49,10 +49,10 @@ public:
|
||||||
virtual GLenum getBinding() = 0;
|
virtual GLenum getBinding() = 0;
|
||||||
virtual GFXFormat getFormat() = 0;
|
virtual GFXFormat getFormat() = 0;
|
||||||
virtual bool isCompatible(const GFXGLTextureObject* tex) = 0;
|
virtual bool isCompatible(const GFXGLTextureObject* tex) = 0;
|
||||||
|
|
||||||
U32 getMipLevel() { return mipLevel; }
|
U32 getMipLevel() { return mipLevel; }
|
||||||
U32 getZOffset() { return zOffset; }
|
U32 getZOffset() { return zOffset; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
U32 mipLevel;
|
U32 mipLevel;
|
||||||
U32 zOffset;
|
U32 zOffset;
|
||||||
|
|
@ -62,19 +62,21 @@ private:
|
||||||
class _GFXGLTextureTargetDesc : public _GFXGLTargetDesc
|
class _GFXGLTextureTargetDesc : public _GFXGLTargetDesc
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
_GFXGLTextureTargetDesc(GFXGLTextureObject* tex, U32 _mipLevel, U32 _zOffset)
|
|
||||||
: _GFXGLTargetDesc(_mipLevel, _zOffset), mTex(tex)
|
_GFXGLTextureTargetDesc(GFXGLTextureObject* tex, U32 _mipLevel, U32 _zOffset, U32 _face = 0, bool isCube = false)
|
||||||
|
: _GFXGLTargetDesc(_mipLevel, _zOffset), mTex(tex), mFace(_face), mIsCube(isCube)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~_GFXGLTextureTargetDesc() {}
|
virtual ~_GFXGLTextureTargetDesc() {}
|
||||||
|
|
||||||
U32 getHandle() override { return mTex->getHandle(); }
|
U32 getHandle() override { return mTex->getHandle(); }
|
||||||
U32 getWidth() override { return mTex->getWidth(); }
|
U32 getWidth() override { return mTex->getWidth(); }
|
||||||
U32 getHeight() override { return mTex->getHeight(); }
|
U32 getHeight() override { return mTex->getHeight(); }
|
||||||
U32 getDepth() override { return mTex->getDepth(); }
|
U32 getDepth() override { return mTex->getDepth(); }
|
||||||
|
U32 getFace() { return mFace; }
|
||||||
bool hasMips() override { return mTex->mMipLevels != 1; }
|
bool hasMips() override { return mTex->mMipLevels != 1; }
|
||||||
GLenum getBinding() override { return mTex->getBinding(); }
|
GLenum getBinding() override { return mIsCube ? GFXGLFaceType[mFace] : mTex->getBinding(); }
|
||||||
GFXFormat getFormat() override { return mTex->getFormat(); }
|
GFXFormat getFormat() override { return mTex->getFormat(); }
|
||||||
bool isCompatible(const GFXGLTextureObject* tex) override
|
bool isCompatible(const GFXGLTextureObject* tex) override
|
||||||
{
|
{
|
||||||
|
|
@ -82,40 +84,12 @@ public:
|
||||||
&& mTex->getWidth() == tex->getWidth()
|
&& mTex->getWidth() == tex->getWidth()
|
||||||
&& mTex->getHeight() == tex->getHeight();
|
&& mTex->getHeight() == tex->getHeight();
|
||||||
}
|
}
|
||||||
GFXGLTextureObject* getTextureObject() const {return mTex; }
|
GFXGLTextureObject* getTextureObject() const { return mTex; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StrongRefPtr<GFXGLTextureObject> mTex;
|
StrongRefPtr<GFXGLTextureObject> mTex;
|
||||||
};
|
|
||||||
|
|
||||||
/// Internal struct used to track Cubemap texture information for FBO attachment
|
|
||||||
class _GFXGLCubemapTargetDesc : public _GFXGLTargetDesc
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
_GFXGLCubemapTargetDesc(GFXGLCubemap* tex, U32 _face, U32 _mipLevel, U32 _zOffset)
|
|
||||||
: _GFXGLTargetDesc(_mipLevel, _zOffset), mTex(tex), mFace(_face)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~_GFXGLCubemapTargetDesc() {}
|
|
||||||
|
|
||||||
U32 getHandle() override { return mTex->getHandle(); }
|
|
||||||
U32 getWidth() override { return mTex->getWidth(); }
|
|
||||||
U32 getHeight() override { return mTex->getHeight(); }
|
|
||||||
U32 getDepth() override { return 0; }
|
|
||||||
bool hasMips() override { return mTex->getMipMapLevels() != 1; }
|
|
||||||
GLenum getBinding() override { return GFXGLCubemap::getEnumForFaceNumber(mFace); }
|
|
||||||
GFXFormat getFormat() override { return mTex->getFormat(); }
|
|
||||||
bool isCompatible(const GFXGLTextureObject* tex) override
|
|
||||||
{
|
|
||||||
return mTex->getFormat() == tex->getFormat()
|
|
||||||
&& mTex->getWidth() == tex->getWidth()
|
|
||||||
&& mTex->getHeight() == tex->getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
StrongRefPtr<GFXGLCubemap> mTex;
|
|
||||||
U32 mFace;
|
U32 mFace;
|
||||||
|
bool mIsCube;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal implementations
|
// Internal implementations
|
||||||
|
|
@ -123,9 +97,9 @@ class _GFXGLTextureTargetImpl // TODO OPENGL remove and implement on GFXGLTextur
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GFXGLTextureTarget* mTarget;
|
GFXGLTextureTarget* mTarget;
|
||||||
|
|
||||||
virtual ~_GFXGLTextureTargetImpl() {}
|
virtual ~_GFXGLTextureTargetImpl() {}
|
||||||
|
|
||||||
virtual void applyState() = 0;
|
virtual void applyState() = 0;
|
||||||
virtual void makeActive() = 0;
|
virtual void makeActive() = 0;
|
||||||
virtual void finish() = 0;
|
virtual void finish() = 0;
|
||||||
|
|
@ -137,10 +111,10 @@ class _GFXGLTextureTargetFBOImpl : public _GFXGLTextureTargetImpl
|
||||||
public:
|
public:
|
||||||
GLuint mFramebuffer;
|
GLuint mFramebuffer;
|
||||||
bool mGenMips;
|
bool mGenMips;
|
||||||
|
|
||||||
_GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target);
|
_GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target);
|
||||||
virtual ~_GFXGLTextureTargetFBOImpl();
|
virtual ~_GFXGLTextureTargetFBOImpl();
|
||||||
|
|
||||||
void applyState() override;
|
void applyState() override;
|
||||||
void makeActive() override;
|
void makeActive() override;
|
||||||
void finish() override;
|
void finish() override;
|
||||||
|
|
@ -159,42 +133,42 @@ _GFXGLTextureTargetFBOImpl::~_GFXGLTextureTargetFBOImpl()
|
||||||
}
|
}
|
||||||
|
|
||||||
void _GFXGLTextureTargetFBOImpl::applyState()
|
void _GFXGLTextureTargetFBOImpl::applyState()
|
||||||
{
|
{
|
||||||
// REMINDER: When we implement MRT support, check against GFXGLDevice::getNumRenderTargets()
|
// REMINDER: When we implement MRT support, check against GFXGLDevice::getNumRenderTargets()
|
||||||
|
|
||||||
PRESERVE_FRAMEBUFFER();
|
PRESERVE_FRAMEBUFFER();
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
|
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
|
||||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||||
bool drawbufs[16];
|
bool drawbufs[16];
|
||||||
int bufsize = 0;
|
int bufsize = 0;
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
drawbufs[i] = false;
|
drawbufs[i] = false;
|
||||||
bool hasColor = false;
|
bool hasColor = false;
|
||||||
for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
|
for (int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
|
||||||
{
|
{
|
||||||
_GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ));
|
_GFXGLTargetDesc* color = mTarget->getTargetDesc(static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0 + i));
|
||||||
if(color)
|
if (color)
|
||||||
{
|
{
|
||||||
hasColor = true;
|
hasColor = true;
|
||||||
const GLenum binding = color->getBinding();
|
const GLenum binding = color->getBinding();
|
||||||
if( binding == GL_TEXTURE_2D || (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) )
|
if (binding == GL_TEXTURE_2D || (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
|
||||||
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ) );
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding(), color->getHandle(), color->getMipLevel());
|
||||||
else if( binding == GL_TEXTURE_1D )
|
else if (binding == GL_TEXTURE_1D)
|
||||||
glFramebufferTexture1D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ) );
|
glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding(), color->getHandle(), color->getMipLevel());
|
||||||
else if( binding == GL_TEXTURE_3D )
|
else if (binding == GL_TEXTURE_3D)
|
||||||
glFramebufferTexture3D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ), color->getZOffset( ) );
|
glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding(), color->getHandle(), color->getMipLevel(), color->getZOffset());
|
||||||
else
|
else
|
||||||
Con::errorf("_GFXGLTextureTargetFBOImpl::applyState - Bad binding");
|
Con::errorf("_GFXGLTextureTargetFBOImpl::applyState - Bad binding");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Clears the texture (note that the binding is irrelevent)
|
// Clears the texture (note that the binding is irrelevent)
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_TEXTURE_2D, 0, 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_GFXGLTargetDesc* depthStecil = mTarget->getTargetDesc(GFXTextureTarget::DepthStencil);
|
_GFXGLTargetDesc* depthStecil = mTarget->getTargetDesc(GFXTextureTarget::DepthStencil);
|
||||||
if(depthStecil)
|
if (depthStecil)
|
||||||
{
|
{
|
||||||
// Certain drivers have issues with depth only FBOs. That and the next two asserts assume we have a color target.
|
// Certain drivers have issues with depth only FBOs. That and the next two asserts assume we have a color target.
|
||||||
AssertFatal(hasColor, "GFXGLTextureTarget::applyState() - Cannot set DepthStencil target without Color0 target!");
|
AssertFatal(hasColor, "GFXGLTextureTarget::applyState() - Cannot set DepthStencil target without Color0 target!");
|
||||||
|
|
@ -206,40 +180,40 @@ void _GFXGLTextureTargetFBOImpl::applyState()
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum *buf = new GLenum[bufsize];
|
GLenum* buf = new GLenum[bufsize];
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i = 0; i < bufsize; i++)
|
for (int i = 0; i < bufsize; i++)
|
||||||
{
|
{
|
||||||
if (drawbufs[i])
|
if (drawbufs[i])
|
||||||
{
|
{
|
||||||
buf[count] = GL_COLOR_ATTACHMENT0 + i;
|
buf[count] = GL_COLOR_ATTACHMENT0 + i;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glDrawBuffers(bufsize, buf);
|
glDrawBuffers(bufsize, buf);
|
||||||
|
|
||||||
delete[] buf;
|
delete[] buf;
|
||||||
CHECK_FRAMEBUFFER_STATUS();
|
CHECK_FRAMEBUFFER_STATUS();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _GFXGLTextureTargetFBOImpl::makeActive()
|
void _GFXGLTextureTargetFBOImpl::makeActive()
|
||||||
{
|
{
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
|
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
|
||||||
GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, mFramebuffer);
|
GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, mFramebuffer);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
GLenum draws[16];
|
GLenum draws[16];
|
||||||
for( i = 0; i < GFXGL->getNumRenderTargets(); ++i)
|
for (i = 0; i < GFXGL->getNumRenderTargets(); ++i)
|
||||||
{
|
{
|
||||||
_GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ));
|
_GFXGLTargetDesc* color = mTarget->getTargetDesc(static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0 + i));
|
||||||
if(color)
|
if (color)
|
||||||
draws[i] = GL_COLOR_ATTACHMENT0 + i;
|
draws[i] = GL_COLOR_ATTACHMENT0 + i;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
glDrawBuffers( i, draws );
|
glDrawBuffers(i, draws);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _GFXGLTextureTargetFBOImpl::finish()
|
void _GFXGLTextureTargetFBOImpl::finish()
|
||||||
|
|
@ -250,20 +224,20 @@ void _GFXGLTextureTargetFBOImpl::finish()
|
||||||
if (!mGenMips)
|
if (!mGenMips)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
|
for (int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
|
||||||
{
|
{
|
||||||
_GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ) );
|
_GFXGLTargetDesc* color = mTarget->getTargetDesc(static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0 + i));
|
||||||
if(!color || !(color->hasMips()))
|
if (!color || !(color->hasMips()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Generate mips if necessary
|
// Generate mips if necessary
|
||||||
// Assumes a 2D texture.
|
// Assumes a 2D texture.
|
||||||
GLenum binding = color->getBinding();
|
GLenum binding = color->getBinding();
|
||||||
binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;
|
binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;
|
||||||
|
|
||||||
PRESERVE_TEXTURE( binding );
|
PRESERVE_TEXTURE(binding);
|
||||||
glBindTexture( binding, color->getHandle() );
|
glBindTexture(binding, color->getHandle());
|
||||||
glGenerateMipmap( binding );
|
glGenerateMipmap(binding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,13 +245,13 @@ void _GFXGLTextureTargetFBOImpl::finish()
|
||||||
GFXGLTextureTarget::GFXGLTextureTarget(bool genMips) : mCopyFboSrc(0), mCopyFboDst(0)
|
GFXGLTextureTarget::GFXGLTextureTarget(bool genMips) : mCopyFboSrc(0), mCopyFboDst(0)
|
||||||
{
|
{
|
||||||
mGenMips = genMips;
|
mGenMips = genMips;
|
||||||
for(U32 i=0; i<MaxRenderSlotId; i++)
|
for (U32 i = 0; i < MaxRenderSlotId; i++)
|
||||||
mTargets[i] = NULL;
|
mTargets[i] = NULL;
|
||||||
|
|
||||||
GFXTextureManager::addEventDelegate( this, &GFXGLTextureTarget::_onTextureEvent );
|
GFXTextureManager::addEventDelegate(this, &GFXGLTextureTarget::_onTextureEvent);
|
||||||
|
|
||||||
_impl = new _GFXGLTextureTargetFBOImpl(this);
|
_impl = new _GFXGLTextureTargetFBOImpl(this);
|
||||||
|
|
||||||
glGenFramebuffers(1, &mCopyFboSrc);
|
glGenFramebuffers(1, &mCopyFboSrc);
|
||||||
glGenFramebuffers(1, &mCopyFboDst);
|
glGenFramebuffers(1, &mCopyFboDst);
|
||||||
}
|
}
|
||||||
|
|
@ -292,7 +266,7 @@ GFXGLTextureTarget::~GFXGLTextureTarget()
|
||||||
|
|
||||||
const Point2I GFXGLTextureTarget::getSize()
|
const Point2I GFXGLTextureTarget::getSize()
|
||||||
{
|
{
|
||||||
if(mTargets[Color0].isValid())
|
if (mTargets[Color0].isValid())
|
||||||
return Point2I(mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight());
|
return Point2I(mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight());
|
||||||
|
|
||||||
return Point2I(0, 0);
|
return Point2I(0, 0);
|
||||||
|
|
@ -300,61 +274,50 @@ const Point2I GFXGLTextureTarget::getSize()
|
||||||
|
|
||||||
GFXFormat GFXGLTextureTarget::getFormat()
|
GFXFormat GFXGLTextureTarget::getFormat()
|
||||||
{
|
{
|
||||||
if(mTargets[Color0].isValid())
|
if (mTargets[Color0].isValid())
|
||||||
return mTargets[Color0]->getFormat();
|
return mTargets[Color0]->getFormat();
|
||||||
|
|
||||||
return GFXFormatR8G8B8A8;
|
return GFXFormatR8G8B8A8;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXGLTextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *tex, U32 mipLevel/*=0*/, U32 zOffset /*= 0*/ )
|
void GFXGLTextureTarget::attachTexture(RenderSlot slot, GFXTextureObject* tex, U32 mipLevel/*=0*/, U32 zOffset /*= 0*/, U32 face /*= 0*/)
|
||||||
{
|
{
|
||||||
if( tex == GFXTextureTarget::sDefaultDepthStencil )
|
if (tex == GFXTextureTarget::sDefaultDepthStencil)
|
||||||
tex = GFXGL->getDefaultDepthTex();
|
tex = GFXGL->getDefaultDepthTex();
|
||||||
|
|
||||||
|
// are we readding the same thing, face and all?
|
||||||
_GFXGLTextureTargetDesc* mTex = static_cast<_GFXGLTextureTargetDesc*>(mTargets[slot].ptr());
|
_GFXGLTextureTargetDesc* mTex = static_cast<_GFXGLTextureTargetDesc*>(mTargets[slot].ptr());
|
||||||
if( (!tex && !mTex) || (mTex && mTex->getTextureObject() == tex) )
|
if ((!tex && !mTex) || (mTex && mTex->getTextureObject() == tex && mTex->getFace() == face))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Triggers an update when we next render
|
// Triggers an update when we next render
|
||||||
invalidateState();
|
invalidateState();
|
||||||
|
|
||||||
// We stash the texture and info into an internal struct.
|
// We stash the texture and info into an internal struct.
|
||||||
GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(tex);
|
GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(tex);
|
||||||
if(tex && tex != GFXTextureTarget::sDefaultDepthStencil)
|
if (tex && tex != GFXTextureTarget::sDefaultDepthStencil)
|
||||||
mTargets[slot] = new _GFXGLTextureTargetDesc(glTexture, mipLevel, zOffset);
|
{
|
||||||
|
mTargets[slot] = new _GFXGLTextureTargetDesc(glTexture, mipLevel, zOffset, face, glTexture->isCubeMap());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
mTargets[slot] = NULL;
|
mTargets[slot] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXGLTextureTarget::attachTexture( RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel/*=0*/ )
|
void GFXGLTextureTarget::attachTexture(RenderSlot slot, GFXCubemap* tex, U32 face, U32 mipLevel/*=0*/)
|
||||||
{
|
{
|
||||||
// No depth cubemaps, sorry
|
|
||||||
AssertFatal(slot != DepthStencil, "GFXGLTextureTarget::attachTexture (cube) - Cube depth textures not supported!");
|
|
||||||
if(slot == DepthStencil)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Triggers an update when we next render
|
|
||||||
invalidateState();
|
|
||||||
|
|
||||||
// We stash the texture and info into an internal struct.
|
|
||||||
GFXGLCubemap* glTexture = static_cast<GFXGLCubemap*>(tex);
|
|
||||||
if(tex)
|
|
||||||
mTargets[slot] = new _GFXGLCubemapTargetDesc(glTexture, face, mipLevel, 0);
|
|
||||||
else
|
|
||||||
mTargets[slot] = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXGLTextureTarget::clearAttachments()
|
void GFXGLTextureTarget::clearAttachments()
|
||||||
{
|
{
|
||||||
deactivate();
|
deactivate();
|
||||||
for(S32 i=1; i<MaxRenderSlotId; i++)
|
for (S32 i = 1; i < MaxRenderSlotId; i++)
|
||||||
attachTexture((RenderSlot)i, NULL);
|
attachTexture((RenderSlot)i, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXGLTextureTarget::zombify()
|
void GFXGLTextureTarget::zombify()
|
||||||
{
|
{
|
||||||
invalidateState();
|
invalidateState();
|
||||||
|
|
||||||
// Will be recreated in applyState
|
// Will be recreated in applyState
|
||||||
_impl = NULL;
|
_impl = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -376,15 +339,15 @@ void GFXGLTextureTarget::deactivate()
|
||||||
|
|
||||||
void GFXGLTextureTarget::applyState()
|
void GFXGLTextureTarget::applyState()
|
||||||
{
|
{
|
||||||
if(!isPendingState())
|
if (!isPendingState())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// So we don't do this over and over again
|
// So we don't do this over and over again
|
||||||
stateApplied();
|
stateApplied();
|
||||||
|
|
||||||
if(_impl.isNull())
|
if (_impl.isNull())
|
||||||
_impl = new _GFXGLTextureTargetFBOImpl(this);
|
_impl = new _GFXGLTextureTargetFBOImpl(this);
|
||||||
|
|
||||||
_impl->applyState();
|
_impl->applyState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -394,7 +357,7 @@ _GFXGLTargetDesc* GFXGLTextureTarget::getTargetDesc(RenderSlot slot) const
|
||||||
return mTargets[slot].ptr();
|
return mTargets[slot].ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GFXGLTextureTarget::_onTextureEvent( GFXTexCallbackCode code )
|
void GFXGLTextureTarget::_onTextureEvent(GFXTexCallbackCode code)
|
||||||
{
|
{
|
||||||
invalidateState();
|
invalidateState();
|
||||||
}
|
}
|
||||||
|
|
@ -403,7 +366,7 @@ const String GFXGLTextureTarget::describeSelf() const
|
||||||
{
|
{
|
||||||
String ret = String::ToString(" Color0 Attachment: %i", mTargets[Color0].isValid() ? mTargets[Color0]->getHandle() : 0);
|
String ret = String::ToString(" Color0 Attachment: %i", mTargets[Color0].isValid() ? mTargets[Color0]->getHandle() : 0);
|
||||||
ret += String::ToString(" Depth Attachment: %i", mTargets[DepthStencil].isValid() ? mTargets[DepthStencil]->getHandle() : 0);
|
ret += String::ToString(" Depth Attachment: %i", mTargets[DepthStencil].isValid() ? mTargets[DepthStencil]->getHandle() : 0);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,27 +379,27 @@ void GFXGLTextureTarget::resolveTo(GFXTextureObject* obj)
|
||||||
AssertFatal(dynamic_cast<GFXGLTextureObject*>(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject");
|
AssertFatal(dynamic_cast<GFXGLTextureObject*>(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject");
|
||||||
GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(obj);
|
GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(obj);
|
||||||
|
|
||||||
if( GFXGL->mCapabilities.copyImage && mTargets[Color0]->isCompatible(glTexture) )
|
if (GFXGL->mCapabilities.copyImage && mTargets[Color0]->isCompatible(glTexture))
|
||||||
{
|
{
|
||||||
GLenum binding = mTargets[Color0]->getBinding();
|
GLenum binding = mTargets[Color0]->getBinding();
|
||||||
binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;
|
binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;
|
||||||
U32 srcStartDepth = binding == GL_TEXTURE_CUBE_MAP ? mTargets[Color0]->getBinding() - GL_TEXTURE_CUBE_MAP_POSITIVE_X : 0;
|
U32 srcStartDepth = binding == GL_TEXTURE_CUBE_MAP ? mTargets[Color0]->getBinding() - GL_TEXTURE_CUBE_MAP_POSITIVE_X : 0;
|
||||||
glCopyImageSubData(
|
glCopyImageSubData(
|
||||||
mTargets[Color0]->getHandle(), binding, 0, 0, 0, srcStartDepth,
|
mTargets[Color0]->getHandle(), binding, 0, 0, 0, srcStartDepth,
|
||||||
glTexture->getHandle(), glTexture->getBinding(), 0, 0, 0, 0,
|
glTexture->getHandle(), glTexture->getBinding(), 0, 0, 0, 0,
|
||||||
mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(), 1);
|
mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(), 1);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRESERVE_FRAMEBUFFER();
|
PRESERVE_FRAMEBUFFER();
|
||||||
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mCopyFboDst);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mCopyFboDst);
|
||||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, glTexture->getBinding(), glTexture->getHandle(), 0);
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, glTexture->getBinding(), glTexture->getHandle(), 0);
|
||||||
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, mCopyFboSrc);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, mCopyFboSrc);
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTargets[Color0]->getBinding(), mTargets[Color0]->getHandle(), 0);
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTargets[Color0]->getBinding(), mTargets[Color0]->getHandle(), 0);
|
||||||
|
|
||||||
glBlitFramebuffer(0, 0, mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(),
|
glBlitFramebuffer(0, 0, mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(),
|
||||||
0, 0, glTexture->getWidth(), glTexture->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
0, 0, glTexture->getWidth(), glTexture->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,35 +50,35 @@ public:
|
||||||
|
|
||||||
const Point2I getSize() override;
|
const Point2I getSize() override;
|
||||||
GFXFormat getFormat() override;
|
GFXFormat getFormat() override;
|
||||||
void attachTexture(RenderSlot slot, GFXTextureObject *tex, U32 mipLevel=0, U32 zOffset = 0) override;
|
void attachTexture(RenderSlot slot, GFXTextureObject* tex, U32 mipLevel = 0, U32 zOffset = 0, U32 face = 0) override;
|
||||||
void attachTexture(RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel=0) override;
|
void attachTexture(RenderSlot slot, GFXCubemap* tex, U32 face, U32 mipLevel = 0) override;
|
||||||
virtual void clearAttachments();
|
virtual void clearAttachments();
|
||||||
|
|
||||||
/// Functions to query internal state
|
/// Functions to query internal state
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
/// Returns the internal structure for the given slot. This should only be called by our internal implementations.
|
/// Returns the internal structure for the given slot. This should only be called by our internal implementations.
|
||||||
_GFXGLTargetDesc* getTargetDesc(RenderSlot slot) const;
|
_GFXGLTargetDesc* getTargetDesc(RenderSlot slot) const;
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
void deactivate() override;
|
void deactivate() override;
|
||||||
void zombify() override;
|
void zombify() override;
|
||||||
void resurrect() override;
|
void resurrect() override;
|
||||||
const String describeSelf() const override;
|
const String describeSelf() const override;
|
||||||
|
|
||||||
void resolve() override;
|
void resolve() override;
|
||||||
|
|
||||||
void resolveTo(GFXTextureObject* obj) override;
|
void resolveTo(GFXTextureObject* obj) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
friend class GFXGLDevice;
|
friend class GFXGLDevice;
|
||||||
|
|
||||||
/// The callback used to get texture events.
|
/// The callback used to get texture events.
|
||||||
/// @see GFXTextureManager::addEventDelegate
|
/// @see GFXTextureManager::addEventDelegate
|
||||||
void _onTextureEvent( GFXTexCallbackCode code );
|
void _onTextureEvent(GFXTexCallbackCode code);
|
||||||
|
|
||||||
/// Pointer to our internal implementation
|
/// Pointer to our internal implementation
|
||||||
AutoPtr<_GFXGLTextureTargetImpl> _impl;
|
AutoPtr<_GFXGLTextureTargetImpl> _impl;
|
||||||
|
|
||||||
|
|
@ -87,10 +87,10 @@ protected:
|
||||||
|
|
||||||
/// These redirect to our internal implementation
|
/// These redirect to our internal implementation
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
void applyState();
|
void applyState();
|
||||||
void makeActive();
|
void makeActive();
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
//copy FBO
|
//copy FBO
|
||||||
|
|
|
||||||
|
|
@ -103,8 +103,6 @@ void GFXGLDevice::enumerateAdapters( Vector<GFXAdapter*> &adapterList )
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_ClearError();
|
SDL_ClearError();
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1);
|
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1);
|
||||||
|
|
||||||
|
|
@ -140,6 +138,10 @@ void GFXGLDevice::enumerateAdapters( Vector<GFXAdapter*> &adapterList )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set our sdl attribute to use this version.
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
|
||||||
|
|
||||||
//check for required extensions
|
//check for required extensions
|
||||||
if (!gglHasExtension(ARB_texture_cube_map_array))
|
if (!gglHasExtension(ARB_texture_cube_map_array))
|
||||||
{
|
{
|
||||||
|
|
@ -168,7 +170,24 @@ void GFXGLDevice::enumerateAdapters( Vector<GFXAdapter*> &adapterList )
|
||||||
dStrcpy(toAdd->mName, "OpenGL", GFXAdapter::MaxAdapterNameLen);
|
dStrcpy(toAdd->mName, "OpenGL", GFXAdapter::MaxAdapterNameLen);
|
||||||
|
|
||||||
toAdd->mType = OpenGL;
|
toAdd->mType = OpenGL;
|
||||||
toAdd->mShaderModel = 0.f;
|
F32 shaderModel = 3.3f;
|
||||||
|
if (major == 4)
|
||||||
|
{
|
||||||
|
if (minor == 0)
|
||||||
|
shaderModel = 4.00f; // GLSL 4.00
|
||||||
|
else if (minor == 1)
|
||||||
|
shaderModel = 4.10f; // GLSL 4.10
|
||||||
|
else if (minor == 2)
|
||||||
|
shaderModel = 4.20f; // GLSL 4.20
|
||||||
|
else if (minor == 3)
|
||||||
|
shaderModel = 4.30f; // GLSL 4.30
|
||||||
|
else if (minor == 4)
|
||||||
|
shaderModel = 4.40f; // GLSL 4.40
|
||||||
|
else if (minor == 5)
|
||||||
|
shaderModel = 4.50f; // GLSL 4.50
|
||||||
|
else if (minor == 6)
|
||||||
|
shaderModel = 4.60f; // GLSL 4.60
|
||||||
|
}
|
||||||
toAdd->mCreateDeviceInstanceDelegate = mCreateDeviceInstance;
|
toAdd->mCreateDeviceInstanceDelegate = mCreateDeviceInstance;
|
||||||
|
|
||||||
// Enumerate all available resolutions:
|
// Enumerate all available resolutions:
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,15 @@ CubemapData::CubemapData()
|
||||||
|
|
||||||
CubemapData::~CubemapData()
|
CubemapData::~CubemapData()
|
||||||
{
|
{
|
||||||
mCubemap = NULL;
|
if (mCubeMapAsset.notNull())
|
||||||
|
{
|
||||||
|
mCubeMapAsset.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCubemap)
|
||||||
|
{
|
||||||
|
mCubemap.free();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleDocClass( CubemapData,
|
ConsoleDocClass( CubemapData,
|
||||||
|
|
@ -101,7 +109,7 @@ void CubemapData::createMap()
|
||||||
//check mCubeMapFile first
|
//check mCubeMapFile first
|
||||||
if (mCubeMapAsset.notNull())
|
if (mCubeMapAsset.notNull())
|
||||||
{
|
{
|
||||||
mCubemap = TEXMGR->createCubemap(mCubeMapAsset->getImageFile());
|
mCubemap = mCubeMapAsset->getTexture(&GFXCubemapStaticTextureProfile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -125,11 +133,14 @@ void CubemapData::createMap()
|
||||||
|
|
||||||
if( initSuccess )
|
if( initSuccess )
|
||||||
{
|
{
|
||||||
mCubemap = GFX->createCubemap();
|
if (mCubeMapFaceAsset->isNull())
|
||||||
if (mCubeMapFaceAsset->isNull())
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
mCubemap->initStatic(mCubeMapFaceTex);
|
mCubemap.set(mCubeMapFaceTex->getWidth(), mCubeMapFaceTex->getHeight(), mCubeMapFaceTex->getFormat(), &GFXCubemapStaticTextureProfile, "CubemapData-InitTexture", mCubeMapFaceTex->getPointer()->getMipLevels());
|
||||||
|
for (U32 i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
mCubemap->updateTextureSlot(mCubeMapFaceTex[i],0, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -141,7 +152,7 @@ void CubemapData::updateFaces()
|
||||||
//check mCubeMapFile first
|
//check mCubeMapFile first
|
||||||
if (mCubeMapAsset.notNull())
|
if (mCubeMapAsset.notNull())
|
||||||
{
|
{
|
||||||
mCubemap = TEXMGR->createCubemap(mCubeMapAsset->getImageFile());
|
mCubemap = mCubeMapAsset->getTexture(&GFXCubemapStaticTextureProfile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -166,11 +177,14 @@ void CubemapData::updateFaces()
|
||||||
if( initSuccess )
|
if( initSuccess )
|
||||||
{
|
{
|
||||||
mCubemap = NULL;
|
mCubemap = NULL;
|
||||||
mCubemap = GFX->createCubemap();
|
|
||||||
if (mCubeMapFaceAsset->isNull())
|
if (mCubeMapFaceAsset->isNull())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mCubemap->initStatic(mCubeMapFaceTex);
|
mCubemap.set(mCubeMapFaceTex->getWidth(), mCubeMapFaceTex->getHeight(), GFXFormatR16G16B16A16F, &GFXCubemapStaticTextureProfile, "CubemapData-InitTexture", mCubeMapFaceTex->getFormat());
|
||||||
|
for (U32 i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
mCubemap->updateTextureSlot(mCubeMapFaceTex[i], 0, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ class CubemapData : public SimObject
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GFXCubemapHandle mCubemap;
|
GFXTexHandle mCubemap;
|
||||||
|
|
||||||
CubemapData();
|
CubemapData();
|
||||||
~CubemapData();
|
~CubemapData();
|
||||||
|
|
|
||||||
|
|
@ -35,26 +35,11 @@
|
||||||
#include "gfx/util/gfxFrustumSaver.h"
|
#include "gfx/util/gfxFrustumSaver.h"
|
||||||
#include "math/mathUtils.h"
|
#include "math/mathUtils.h"
|
||||||
|
|
||||||
|
|
||||||
CubeLightShadowMap::CubeLightShadowMap( LightInfo *light )
|
CubeLightShadowMap::CubeLightShadowMap( LightInfo *light )
|
||||||
: Parent( light )
|
: Parent( light )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CubeLightShadowMap::setTextureStage( U32 currTexFlag, LightingShaderConstants* lsc )
|
|
||||||
{
|
|
||||||
if ( currTexFlag == Material::DynamicLight )
|
|
||||||
{
|
|
||||||
S32 reg = lsc->mShadowMapSC->getSamplerRegister();
|
|
||||||
if ( reg != -1 )
|
|
||||||
GFX->setCubeTexture( reg, mCubemap );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CubeLightShadowMap::setShaderParameters( GFXShaderConstBuffer *params,
|
void CubeLightShadowMap::setShaderParameters( GFXShaderConstBuffer *params,
|
||||||
LightingShaderConstants *lsc )
|
LightingShaderConstants *lsc )
|
||||||
{
|
{
|
||||||
|
|
@ -77,12 +62,6 @@ void CubeLightShadowMap::setShaderParameters( GFXShaderConstBuffer *params,
|
||||||
params->setSafe( lsc->mShadowSoftnessConst, p->shadowSoftness * ( 1.0f / mTexSize ) );
|
params->setSafe( lsc->mShadowSoftnessConst, p->shadowSoftness * ( 1.0f / mTexSize ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CubeLightShadowMap::releaseTextures()
|
|
||||||
{
|
|
||||||
Parent::releaseTextures();
|
|
||||||
mCubemap = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CubeLightShadowMap::_render( RenderPassManager* renderPass,
|
void CubeLightShadowMap::_render( RenderPassManager* renderPass,
|
||||||
const SceneRenderState *diffuseState )
|
const SceneRenderState *diffuseState )
|
||||||
{
|
{
|
||||||
|
|
@ -92,15 +71,16 @@ void CubeLightShadowMap::_render( RenderPassManager* renderPass,
|
||||||
const bool bUseLightmappedGeometry = lmParams ? !lmParams->representedInLightmap || lmParams->includeLightmappedGeometryInShadow : true;
|
const bool bUseLightmappedGeometry = lmParams ? !lmParams->representedInLightmap || lmParams->includeLightmappedGeometryInShadow : true;
|
||||||
|
|
||||||
const U32 texSize = getBestTexSize();
|
const U32 texSize = getBestTexSize();
|
||||||
|
if (mShadowMapTex.isNull() ||
|
||||||
if ( mCubemap.isNull() ||
|
mTexSize != texSize)
|
||||||
mTexSize != texSize )
|
|
||||||
{
|
{
|
||||||
mTexSize = texSize;
|
mTexSize = texSize;
|
||||||
mCubemap = GFX->createCubemap();
|
|
||||||
mCubemap->initDynamic( mTexSize, LightShadowMap::ShadowMapFormat );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
mShadowMapTex.set(mTexSize, mTexSize,
|
||||||
|
ShadowMapFormat, &CubeShadowMapProfile,
|
||||||
|
"CubeLightShadowMap");
|
||||||
|
mShadowMapDepth = _getDepthTarget(mShadowMapTex->getWidth(), mShadowMapTex->getHeight());
|
||||||
|
}
|
||||||
// Setup the world to light projection which is used
|
// Setup the world to light projection which is used
|
||||||
// in the shader to transform the light vector for the
|
// in the shader to transform the light vector for the
|
||||||
// shadow lookup.
|
// shadow lookup.
|
||||||
|
|
@ -155,20 +135,14 @@ void CubeLightShadowMap::_render( RenderPassManager* renderPass,
|
||||||
GFXDEBUGEVENT_START( CubeLightShadowMap_Render_Face, ColorI::RED );
|
GFXDEBUGEVENT_START( CubeLightShadowMap_Render_Face, ColorI::RED );
|
||||||
|
|
||||||
// create camera matrix
|
// create camera matrix
|
||||||
VectorF cross = mCross(vUpVec, vLookatPt);
|
|
||||||
cross.normalizeSafe();
|
|
||||||
|
|
||||||
MatrixF lightMatrix(true);
|
MatrixF lightMatrix(true);
|
||||||
lightMatrix.setColumn(0, cross);
|
lightMatrix.LookAt(mLight->getPosition(), vLookatPt, vUpVec);
|
||||||
lightMatrix.setColumn(1, vLookatPt);
|
|
||||||
lightMatrix.setColumn(2, vUpVec);
|
|
||||||
lightMatrix.setPosition( mLight->getPosition() );
|
|
||||||
lightMatrix.inverse();
|
lightMatrix.inverse();
|
||||||
|
|
||||||
GFX->setWorldMatrix( lightMatrix );
|
GFX->setWorldMatrix( lightMatrix );
|
||||||
|
|
||||||
mTarget->attachTexture(GFXTextureTarget::Color0, mCubemap, i);
|
mTarget->attachTexture(GFXTextureTarget::Color0, mShadowMapTex,0,0, i);
|
||||||
mTarget->attachTexture(GFXTextureTarget::DepthStencil, _getDepthTarget( mTexSize, mTexSize ));
|
mTarget->attachTexture(GFXTextureTarget::DepthStencil, _getDepthTarget(mShadowMapTex->getWidth(), mShadowMapTex->getHeight()));
|
||||||
GFX->setActiveRenderTarget(mTarget);
|
GFX->setActiveRenderTarget(mTarget);
|
||||||
GFX->clear( GFXClearTarget | GFXClearStencil | GFXClearZBuffer, ColorI(255,255,255,255), 0.0f, 0 );
|
GFX->clear( GFXClearTarget | GFXClearStencil | GFXClearZBuffer, ColorI(255,255,255,255), 0.0f, 0 );
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,18 +39,9 @@ public:
|
||||||
|
|
||||||
CubeLightShadowMap( LightInfo *light );
|
CubeLightShadowMap( LightInfo *light );
|
||||||
|
|
||||||
// LightShadowMap
|
|
||||||
bool hasShadowTex() const override { return mCubemap.isValid(); }
|
|
||||||
ShadowType getShadowType() const override { return ShadowType_CubeMap; }
|
ShadowType getShadowType() const override { return ShadowType_CubeMap; }
|
||||||
void _render( RenderPassManager* renderPass, const SceneRenderState *diffuseState ) override;
|
void _render( RenderPassManager* renderPass, const SceneRenderState *diffuseState ) override;
|
||||||
void setShaderParameters( GFXShaderConstBuffer* params, LightingShaderConstants* lsc ) override;
|
void setShaderParameters( GFXShaderConstBuffer* params, LightingShaderConstants* lsc ) override;
|
||||||
void releaseTextures() override;
|
|
||||||
bool setTextureStage( U32 currTexFlag, LightingShaderConstants* lsc ) override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/// The shadow cubemap.
|
|
||||||
GFXCubemapHandle mCubemap;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,13 @@ GFX_ImplementTextureProfile( ShadowMapProfile,
|
||||||
GFXTextureProfile::Pooled,
|
GFXTextureProfile::Pooled,
|
||||||
GFXTextureProfile::NONE );
|
GFXTextureProfile::NONE );
|
||||||
|
|
||||||
|
GFX_ImplementTextureProfile(CubeShadowMapProfile,
|
||||||
|
GFXTextureProfile::DiffuseMap,
|
||||||
|
GFXTextureProfile::PreserveSize |
|
||||||
|
GFXTextureProfile::RenderTarget |
|
||||||
|
GFXTextureProfile::Pooled | GFXTextureProfile::CubeMap,
|
||||||
|
GFXTextureProfile::NONE);
|
||||||
|
|
||||||
GFX_ImplementTextureProfile( ShadowMapZProfile,
|
GFX_ImplementTextureProfile( ShadowMapZProfile,
|
||||||
GFXTextureProfile::DiffuseMap,
|
GFXTextureProfile::DiffuseMap,
|
||||||
GFXTextureProfile::PreserveSize |
|
GFXTextureProfile::PreserveSize |
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,7 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
GFX_DeclareTextureProfile( ShadowMapProfile );
|
GFX_DeclareTextureProfile( ShadowMapProfile );
|
||||||
|
GFX_DeclareTextureProfile( CubeShadowMapProfile );
|
||||||
GFX_DeclareTextureProfile( ShadowMapZProfile );
|
GFX_DeclareTextureProfile( ShadowMapZProfile );
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ public:
|
||||||
TextureTable mTextures;
|
TextureTable mTextures;
|
||||||
|
|
||||||
/// The cubemap for this stage.
|
/// The cubemap for this stage.
|
||||||
GFXCubemap* mCubemap;
|
GFXTexHandle mCubemap;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
@ -204,10 +204,10 @@ public:
|
||||||
void getFeatureSet(FeatureSet* outFeatures) const;
|
void getFeatureSet(FeatureSet* outFeatures) const;
|
||||||
|
|
||||||
/// Returns the stage cubemap.
|
/// Returns the stage cubemap.
|
||||||
GFXCubemap* getCubemap() const { return mCubemap; }
|
GFXTexHandle getCubemap() const { return mCubemap; }
|
||||||
|
|
||||||
/// Set the stage cubemap.
|
/// Set the stage cubemap.
|
||||||
void setCubemap(GFXCubemap* cubemap) { mCubemap = cubemap; }
|
void setCubemap(GFXTexHandle cubemap) { mCubemap = cubemap; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -377,12 +377,12 @@ void ProcessedCustomMaterial::setTextureStages( SceneRenderState *state, const S
|
||||||
}
|
}
|
||||||
case Material::Cube:
|
case Material::Cube:
|
||||||
{
|
{
|
||||||
GFX->setCubeTexture( samplerRegister, rpd->mCubeMap );
|
GFX->setTexture( samplerRegister, rpd->mCubeMap );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Material::SGCube:
|
case Material::SGCube:
|
||||||
{
|
{
|
||||||
GFX->setCubeTexture( samplerRegister, sgData.cubemap );
|
GFX->setTexture( samplerRegister, sgData.cubemap );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Material::BackBuff:
|
case Material::BackBuff:
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ public:
|
||||||
/// The cubemap to use when the texture type is
|
/// The cubemap to use when the texture type is
|
||||||
/// set to Material::Cube.
|
/// set to Material::Cube.
|
||||||
/// @see mTexType
|
/// @see mTexType
|
||||||
GFXCubemapHandle mCubeMap;
|
GFXTexHandle mCubeMap;
|
||||||
|
|
||||||
U32 mNumTex;
|
U32 mNumTex;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -854,11 +854,11 @@ void ProcessedShaderMaterial::setTextureStages( SceneRenderState *state, const S
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Material::Cube:
|
case Material::Cube:
|
||||||
GFX->setCubeTexture( i, rpd->mCubeMap );
|
GFX->setTexture( i, rpd->mCubeMap );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Material::SGCube:
|
case Material::SGCube:
|
||||||
GFX->setCubeTexture( i, sgData.cubemap );
|
GFX->setTexture( i, sgData.cubemap );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Material::BackBuff:
|
case Material::BackBuff:
|
||||||
|
|
@ -1333,7 +1333,7 @@ void ProcessedShaderMaterial::setSceneInfo(SceneRenderState * state, const Scene
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sgData.cubemap)
|
if (sgData.cubemap)
|
||||||
shaderConsts->setSafe(handles->mCubeMipsSC, (F32)sgData.cubemap->getMipMapLevels());
|
shaderConsts->setSafe(handles->mCubeMipsSC, (F32)sgData.cubemap->getMipLevels());
|
||||||
else
|
else
|
||||||
shaderConsts->setSafe(handles->mCubeMipsSC, (F32)getBinLog2(PROBEMGR->getProbeTexSize()));
|
shaderConsts->setSafe(handles->mCubeMipsSC, (F32)getBinLog2(PROBEMGR->getProbeTexSize()));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ struct SceneData
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
const MatrixF *objTrans;
|
const MatrixF *objTrans;
|
||||||
GFXCubemap *cubemap;
|
GFXTexHandle cubemap;
|
||||||
F32 visibility;
|
F32 visibility;
|
||||||
|
|
||||||
/// Enables wireframe rendering for the object.
|
/// Enables wireframe rendering for the object.
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,7 @@ void bitmapConvertRGB_to_5551_mmx(U8 *src, U32 pixels)
|
||||||
void PlatformBlitInit()
|
void PlatformBlitInit()
|
||||||
{
|
{
|
||||||
bitmapExtrude5551 = bitmapExtrude5551_asm;
|
bitmapExtrude5551 = bitmapExtrude5551_asm;
|
||||||
bitmapExtrudeRGB = bitmapExtrudeRGB_c;
|
//bitmapExtrudeRGB = bitmapExtrudeRGB_c;
|
||||||
|
|
||||||
if (Platform::SystemInfo.processor.properties & CPU_PROP_MMX)
|
if (Platform::SystemInfo.processor.properties & CPU_PROP_MMX)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -374,7 +374,7 @@ void RenderDeferredMgr::render( SceneRenderState *state )
|
||||||
|
|
||||||
// init loop data
|
// init loop data
|
||||||
GFXTextureObject *lastLM = NULL;
|
GFXTextureObject *lastLM = NULL;
|
||||||
GFXCubemap *lastCubemap = NULL;
|
GFXTexHandle lastCubemap = NULL;
|
||||||
GFXTextureObject *lastReflectTex = NULL;
|
GFXTextureObject *lastReflectTex = NULL;
|
||||||
GFXTextureObject *lastAccuTex = NULL;
|
GFXTextureObject *lastAccuTex = NULL;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ void RenderMeshMgr::render(SceneRenderState * state)
|
||||||
|
|
||||||
// init loop data
|
// init loop data
|
||||||
GFXTextureObject *lastLM = NULL;
|
GFXTextureObject *lastLM = NULL;
|
||||||
GFXCubemap *lastCubemap = NULL;
|
GFXTexHandle lastCubemap = NULL;
|
||||||
GFXTextureObject *lastReflectTex = NULL;
|
GFXTextureObject *lastReflectTex = NULL;
|
||||||
GFXTextureObject *lastMiscTex = NULL;
|
GFXTextureObject *lastMiscTex = NULL;
|
||||||
GFXTextureObject *lastAccuTex = NULL;
|
GFXTextureObject *lastAccuTex = NULL;
|
||||||
|
|
|
||||||
|
|
@ -382,7 +382,7 @@ struct MeshRenderInst : public RenderInst
|
||||||
GFXTextureObject *reflectTex;
|
GFXTextureObject *reflectTex;
|
||||||
GFXTextureObject *miscTex;
|
GFXTextureObject *miscTex;
|
||||||
GFXTextureObject *accuTex;
|
GFXTextureObject *accuTex;
|
||||||
GFXCubemap *cubemap;
|
GFXTexHandle cubemap;
|
||||||
|
|
||||||
/// @name Hardware Skinning
|
/// @name Hardware Skinning
|
||||||
/// {
|
/// {
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,9 @@ RenderProbeMgr::~RenderProbeMgr()
|
||||||
SAFE_DELETE(i->value);
|
SAFE_DELETE(i->value);
|
||||||
}
|
}
|
||||||
mConstantLookup.clear();
|
mConstantLookup.clear();
|
||||||
|
|
||||||
|
mIrradianceArray.free();
|
||||||
|
mPrefilterArray.free();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderProbeMgr::onAdd()
|
bool RenderProbeMgr::onAdd()
|
||||||
|
|
@ -228,13 +231,11 @@ bool RenderProbeMgr::onAdd()
|
||||||
if (!Parent::onAdd())
|
if (!Parent::onAdd())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
mIrradianceArray = GFXCubemapArrayHandle(GFX->createCubemapArray());
|
|
||||||
mPrefilterArray = GFXCubemapArrayHandle(GFX->createCubemapArray());
|
|
||||||
|
|
||||||
U32 scaledSize = getProbeTexSize();
|
U32 scaledSize = getProbeTexSize();
|
||||||
//pre-allocate a few slots
|
//pre-allocate a few slots
|
||||||
mIrradianceArray->init(PROBE_ARRAY_SLOT_BUFFER_SIZE, scaledSize, PROBE_FORMAT);
|
mIrradianceArray.set(scaledSize, scaledSize, PROBE_FORMAT, &GFXCubemapStaticTextureProfile, "RenderProbeMgr::mIrradianceArray", 0,0, PROBE_ARRAY_SLOT_BUFFER_SIZE);
|
||||||
mPrefilterArray->init(PROBE_ARRAY_SLOT_BUFFER_SIZE, scaledSize, PROBE_FORMAT);
|
mPrefilterArray.set(scaledSize, scaledSize, PROBE_FORMAT, &GFXCubemapStaticTextureProfile, "RenderProbeMgr::mPrefilterArray", 0,0, PROBE_ARRAY_SLOT_BUFFER_SIZE);
|
||||||
|
|
||||||
mCubeSlotCount = PROBE_ARRAY_SLOT_BUFFER_SIZE;
|
mCubeSlotCount = PROBE_ARRAY_SLOT_BUFFER_SIZE;
|
||||||
|
|
||||||
String brdfTexturePath = GFXTextureManager::getBRDFTexturePath();
|
String brdfTexturePath = GFXTextureManager::getBRDFTexturePath();
|
||||||
|
|
@ -376,12 +377,12 @@ void RenderProbeMgr::registerProbe(ReflectionProbe::ProbeInfo* newProbe)
|
||||||
if (cubeIndex >= mCubeSlotCount)
|
if (cubeIndex >= mCubeSlotCount)
|
||||||
{
|
{
|
||||||
//alloc temp array handles
|
//alloc temp array handles
|
||||||
GFXCubemapArrayHandle irr = GFXCubemapArrayHandle(GFX->createCubemapArray());
|
GFXTexHandle irr;
|
||||||
GFXCubemapArrayHandle prefilter = GFXCubemapArrayHandle(GFX->createCubemapArray());
|
GFXTexHandle prefilter;
|
||||||
|
|
||||||
U32 scaledSize = getProbeTexSize();
|
U32 scaledSize = getProbeTexSize();
|
||||||
irr->init(mCubeSlotCount + PROBE_ARRAY_SLOT_BUFFER_SIZE, scaledSize, PROBE_FORMAT);
|
irr.set(scaledSize, scaledSize, PROBE_FORMAT, &GFXCubemapStaticTextureProfile, "RenderProbeMgr::mIrradianceArray_temp_expansion", 0, 0, mCubeSlotCount + PROBE_ARRAY_SLOT_BUFFER_SIZE);
|
||||||
prefilter->init(mCubeSlotCount + PROBE_ARRAY_SLOT_BUFFER_SIZE, scaledSize, PROBE_FORMAT);
|
prefilter.set(scaledSize, scaledSize, PROBE_FORMAT, &GFXCubemapStaticTextureProfile, "RenderProbeMgr::mPrefilterArray_temp_expansion", 0, 0, mCubeSlotCount + PROBE_ARRAY_SLOT_BUFFER_SIZE);
|
||||||
|
|
||||||
mIrradianceArray->copyTo(irr);
|
mIrradianceArray->copyTo(irr);
|
||||||
mPrefilterArray->copyTo(prefilter);
|
mPrefilterArray->copyTo(prefilter);
|
||||||
|
|
@ -390,6 +391,9 @@ void RenderProbeMgr::registerProbe(ReflectionProbe::ProbeInfo* newProbe)
|
||||||
mIrradianceArray = irr;
|
mIrradianceArray = irr;
|
||||||
mPrefilterArray = prefilter;
|
mPrefilterArray = prefilter;
|
||||||
|
|
||||||
|
irr.free();
|
||||||
|
prefilter.free();
|
||||||
|
|
||||||
mCubeSlotCount += PROBE_ARRAY_SLOT_BUFFER_SIZE;
|
mCubeSlotCount += PROBE_ARRAY_SLOT_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -466,15 +470,13 @@ void RenderProbeMgr::updateProbeTexture(ReflectionProbe::ProbeInfo* probeInfo)
|
||||||
return;
|
return;
|
||||||
U32 scaledSize = getProbeTexSize();
|
U32 scaledSize = getProbeTexSize();
|
||||||
//Some basic sanity checking that we have valid cubemaps to work with
|
//Some basic sanity checking that we have valid cubemaps to work with
|
||||||
if (probeInfo->mIrradianceCubemap.isNull() || !probeInfo->mIrradianceCubemap->isInitialized() ||
|
if (probeInfo->mIrradianceCubemap.isNull() || probeInfo->mIrradianceCubemap->getWidth() != scaledSize)
|
||||||
probeInfo->mIrradianceCubemap->getSize() != scaledSize)
|
|
||||||
{
|
{
|
||||||
Con::errorf("RenderProbeMgr::updateProbeTexture() - tried to update a probe's texture with an invalid or uninitialized irradiance map!");
|
Con::errorf("RenderProbeMgr::updateProbeTexture() - tried to update a probe's texture with an invalid or uninitialized irradiance map!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (probeInfo->mPrefilterCubemap.isNull() || !probeInfo->mPrefilterCubemap->isInitialized() ||
|
if (probeInfo->mPrefilterCubemap.isNull() || probeInfo->mPrefilterCubemap->getWidth() != scaledSize)
|
||||||
probeInfo->mPrefilterCubemap->getSize() != scaledSize)
|
|
||||||
{
|
{
|
||||||
Con::errorf("RenderProbeMgr::updateProbeTexture() - tried to update a probe's texture with an invalid or uninitialized specular map!");
|
Con::errorf("RenderProbeMgr::updateProbeTexture() - tried to update a probe's texture with an invalid or uninitialized specular map!");
|
||||||
return;
|
return;
|
||||||
|
|
@ -482,12 +484,13 @@ void RenderProbeMgr::updateProbeTexture(ReflectionProbe::ProbeInfo* probeInfo)
|
||||||
|
|
||||||
//Run the update on the array pair with the probe's cubemaps and index
|
//Run the update on the array pair with the probe's cubemaps and index
|
||||||
const U32 cubeIndex = probe->mCubemapIndex;
|
const U32 cubeIndex = probe->mCubemapIndex;
|
||||||
mIrradianceArray->updateTexture(probeInfo->mIrradianceCubemap, cubeIndex);
|
mIrradianceArray->updateTextureSlot(probeInfo->mIrradianceCubemap, cubeIndex);
|
||||||
mPrefilterArray->updateTexture(probeInfo->mPrefilterCubemap, cubeIndex);
|
|
||||||
|
mPrefilterArray->updateTextureSlot(probeInfo->mPrefilterCubemap, cubeIndex);
|
||||||
|
|
||||||
#ifdef TORQUE_DEBUG
|
#ifdef TORQUE_DEBUG
|
||||||
Con::warnf("UpdatedProbeTexture - probe id: %u on cubeIndex %u, Irrad validity: %d, Prefilter validity: %d", probeInfo->mObject->getId(), cubeIndex,
|
Con::warnf("UpdatedProbeTexture - probe id: %u on cubeIndex %u, Irrad validity: %d, Prefilter validity: %d", probeInfo->mObject->getId(), cubeIndex,
|
||||||
probeInfo->mIrradianceCubemap->isInitialized(), probeInfo->mPrefilterCubemap->isInitialized());
|
probeInfo->mIrradianceCubemap.isValid(), probeInfo->mPrefilterCubemap.isValid());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -616,8 +619,8 @@ void RenderProbeMgr::bakeProbe(ReflectionProbe* probe)
|
||||||
clientProbe->createClientResources();
|
clientProbe->createClientResources();
|
||||||
|
|
||||||
//Prep it with whatever resolution we've dictated for our bake
|
//Prep it with whatever resolution we've dictated for our bake
|
||||||
clientProbe->mIrridianceMap->mCubemap->initDynamic(resolution, reflectFormat);
|
clientProbe->mIrridianceMap->mCubemap.set(resolution, resolution, reflectFormat, &GFXCubemapRenderTargetProfile, "ReflectionProbe::mIrridianceMap", 0);
|
||||||
clientProbe->mPrefilterMap->mCubemap->initDynamic(resolution, reflectFormat);
|
clientProbe->mPrefilterMap->mCubemap.set(resolution, resolution, reflectFormat, &GFXCubemapRenderTargetProfile, "ReflectionProbe::mPrefilterMap", 0);
|
||||||
|
|
||||||
GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false);
|
GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false);
|
||||||
clientProbe->mPrefilterMap->mCubemap = cubeRefl.getCubemap();
|
clientProbe->mPrefilterMap->mCubemap = cubeRefl.getCubemap();
|
||||||
|
|
@ -807,9 +810,9 @@ void RenderProbeMgr::_update4ProbeConsts(const SceneData& sgData,
|
||||||
shaderConsts->setSafe(probeShaderConsts->mSkylightDampSC, (int)probeSet.skyLightDamp);
|
shaderConsts->setSafe(probeShaderConsts->mSkylightDampSC, (int)probeSet.skyLightDamp);
|
||||||
|
|
||||||
if (probeShaderConsts->mProbeSpecularCubemapArraySC->getSamplerRegister() != -1)
|
if (probeShaderConsts->mProbeSpecularCubemapArraySC->getSamplerRegister() != -1)
|
||||||
GFX->setCubeArrayTexture(probeShaderConsts->mProbeSpecularCubemapArraySC->getSamplerRegister(), mPrefilterArray);
|
GFX->setTexture(probeShaderConsts->mProbeSpecularCubemapArraySC->getSamplerRegister(), mPrefilterArray);
|
||||||
if (probeShaderConsts->mProbeIrradianceCubemapArraySC->getSamplerRegister() != -1)
|
if (probeShaderConsts->mProbeIrradianceCubemapArraySC->getSamplerRegister() != -1)
|
||||||
GFX->setCubeArrayTexture(probeShaderConsts->mProbeIrradianceCubemapArraySC->getSamplerRegister(), mIrradianceArray);
|
GFX->setTexture(probeShaderConsts->mProbeIrradianceCubemapArraySC->getSamplerRegister(), mIrradianceArray);
|
||||||
|
|
||||||
shaderConsts->setSafe(probeShaderConsts->mMaxProbeDrawDistanceSC, smMaxProbeDrawDistance);
|
shaderConsts->setSafe(probeShaderConsts->mMaxProbeDrawDistanceSC, smMaxProbeDrawDistance);
|
||||||
}
|
}
|
||||||
|
|
@ -875,8 +878,8 @@ void RenderProbeMgr::render( SceneRenderState *state )
|
||||||
mProbeArrayEffect->setShaderMacro("MAX_PROBES", probePerFrame);
|
mProbeArrayEffect->setShaderMacro("MAX_PROBES", probePerFrame);
|
||||||
|
|
||||||
mProbeArrayEffect->setTexture(3, mBRDFTexture);
|
mProbeArrayEffect->setTexture(3, mBRDFTexture);
|
||||||
mProbeArrayEffect->setCubemapArrayTexture(4, mPrefilterArray);
|
mProbeArrayEffect->setTexture(4, mPrefilterArray);
|
||||||
mProbeArrayEffect->setCubemapArrayTexture(5, mIrradianceArray);
|
mProbeArrayEffect->setTexture(5, mIrradianceArray);
|
||||||
mProbeArrayEffect->setTexture(6, mWetnessTexture);
|
mProbeArrayEffect->setTexture(6, mWetnessTexture);
|
||||||
//ssao mask
|
//ssao mask
|
||||||
if (AdvancedLightBinManager::smUseSSAOMask)
|
if (AdvancedLightBinManager::smUseSSAOMask)
|
||||||
|
|
@ -898,7 +901,7 @@ void RenderProbeMgr::render( SceneRenderState *state )
|
||||||
mProbeArrayEffect->setShaderConst("$skylightCubemapIdx", (S32)mProbeData.skyLightIdx);
|
mProbeArrayEffect->setShaderConst("$skylightCubemapIdx", (S32)mProbeData.skyLightIdx);
|
||||||
mProbeArrayEffect->setShaderConst(ShaderGenVars::skylightDamp, mProbeData.skyLightDamp);
|
mProbeArrayEffect->setShaderConst(ShaderGenVars::skylightDamp, mProbeData.skyLightDamp);
|
||||||
|
|
||||||
mProbeArrayEffect->setShaderConst("$cubeMips", (float)mPrefilterArray->getMipMapLevels());
|
mProbeArrayEffect->setShaderConst("$cubeMips", (float)mPrefilterArray->getMipLevels());
|
||||||
|
|
||||||
//also set up some colors
|
//also set up some colors
|
||||||
Vector<Point4F> contribColors;
|
Vector<Point4F> contribColors;
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,6 @@ public:
|
||||||
static F32 smMaxProbeDrawDistance;
|
static F32 smMaxProbeDrawDistance;
|
||||||
static S32 smMaxProbesPerFrame;
|
static S32 smMaxProbesPerFrame;
|
||||||
static S32 smProbeBakeResolution;
|
static S32 smProbeBakeResolution;
|
||||||
SceneRenderState *mState;
|
|
||||||
private:
|
private:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of registered probes. These are not necessarily rendered in a given frame
|
/// List of registered probes. These are not necessarily rendered in a given frame
|
||||||
|
|
@ -246,12 +245,12 @@ private:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The prefilter cubemap array
|
/// The prefilter cubemap array
|
||||||
/// </summary>
|
/// </summary>
|
||||||
GFXCubemapArrayHandle mPrefilterArray;
|
GFXTexHandle mPrefilterArray;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The irradiance cubemap array
|
/// The irradiance cubemap array
|
||||||
/// </summary>
|
/// </summary>
|
||||||
GFXCubemapArrayHandle mIrradianceArray;
|
GFXTexHandle mIrradianceArray;
|
||||||
|
|
||||||
//Utilized in forward rendering
|
//Utilized in forward rendering
|
||||||
|
|
||||||
|
|
@ -291,11 +290,6 @@ private:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool mUseHDRCaptures;
|
bool mUseHDRCaptures;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// holds the normal render state for light fade so we can capture them before and restore them after baking
|
|
||||||
/// </summary>
|
|
||||||
S32 mRenderMaximumNumOfLights;
|
|
||||||
bool mRenderUseLightFade;
|
|
||||||
protected:
|
protected:
|
||||||
/// The current active light manager.
|
/// The current active light manager.
|
||||||
static RenderProbeMgr* smProbeManager;
|
static RenderProbeMgr* smProbeManager;
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ void RenderTranslucentMgr::render( SceneRenderState *state )
|
||||||
|
|
||||||
// init loop data
|
// init loop data
|
||||||
GFXTextureObject *lastLM = NULL;
|
GFXTextureObject *lastLM = NULL;
|
||||||
GFXCubemap *lastCubemap = NULL;
|
GFXTexHandle lastCubemap = NULL;
|
||||||
GFXTextureObject *lastReflectTex = NULL;
|
GFXTextureObject *lastReflectTex = NULL;
|
||||||
GFXTextureObject *lastAccuTex = NULL;
|
GFXTextureObject *lastAccuTex = NULL;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "gfx/gfxCubemap.h"
|
#include "gfx/gfxCubemap.h"
|
||||||
#include "gfx/gfxDebugEvent.h"
|
#include "gfx/gfxDebugEvent.h"
|
||||||
#include "gfx/gfxTransformSaver.h"
|
#include "gfx/gfxTransformSaver.h"
|
||||||
|
#include "gfx/util/gfxFrustumSaver.h"
|
||||||
#include "scene/sceneManager.h"
|
#include "scene/sceneManager.h"
|
||||||
#include "scene/sceneRenderState.h"
|
#include "scene/sceneRenderState.h"
|
||||||
#include "core/stream/bitStream.h"
|
#include "core/stream/bitStream.h"
|
||||||
|
|
@ -319,15 +320,12 @@ void CubeReflector::updateReflection( const ReflectParams ¶ms, Point3F expli
|
||||||
mCubemap.isNull() ||
|
mCubemap.isNull() ||
|
||||||
mCubemap->getFormat() != reflectFormat )
|
mCubemap->getFormat() != reflectFormat )
|
||||||
{
|
{
|
||||||
mCubemap = GFX->createCubemap();
|
mCubemap.set(texDim, texDim, reflectFormat, &GFXCubemapRenderTargetProfile, "CubeReflector::updateReflection", 0);
|
||||||
mCubemap->initDynamic( texDim, reflectFormat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( mRenderTarget.isNull() )
|
if ( mRenderTarget.isNull() )
|
||||||
mRenderTarget = GFX->allocRenderToTextureTarget();
|
mRenderTarget = GFX->allocRenderToTextureTarget();
|
||||||
|
|
||||||
mDepthBuff = LightShadowMap::_getDepthTarget(texDim, texDim);
|
|
||||||
mRenderTarget->attachTexture(GFXTextureTarget::DepthStencil, mDepthBuff);
|
|
||||||
F32 oldVisibleDist = gClientSceneGraph->getVisibleDistance();
|
F32 oldVisibleDist = gClientSceneGraph->getVisibleDistance();
|
||||||
gClientSceneGraph->setVisibleDistance( mDesc->farDist );
|
gClientSceneGraph->setVisibleDistance( mDesc->farDist );
|
||||||
|
|
||||||
|
|
@ -335,15 +333,17 @@ void CubeReflector::updateReflection( const ReflectParams ¶ms, Point3F expli
|
||||||
TSShapeInstance::smDetailAdjust *= mDesc->detailAdjust;
|
TSShapeInstance::smDetailAdjust *= mDesc->detailAdjust;
|
||||||
|
|
||||||
// store current matrices
|
// store current matrices
|
||||||
|
GFXFrustumSaver fsaver;
|
||||||
GFXTransformSaver saver;
|
GFXTransformSaver saver;
|
||||||
|
{
|
||||||
// set projection to 90 degrees vertical and horizontal
|
// set projection to 90 degrees vertical and horizontal
|
||||||
F32 left, right, top, bottom;
|
F32 left, right, top, bottom;
|
||||||
MathUtils::makeFrustum(&left, &right, &top, &bottom, M_HALFPI_F, 1.0f, mDesc->nearDist);
|
MathUtils::makeFrustum(&left, &right, &top, &bottom, M_HALFPI_F, 1.0f, mDesc->nearDist);
|
||||||
GFX->setFrustum(left, right, bottom, top, mDesc->nearDist, mDesc->farDist);
|
GFX->setFrustum(left, right, bottom, top, mDesc->nearDist, mDesc->farDist);
|
||||||
|
}
|
||||||
|
|
||||||
GFX->pushActiveRenderTarget();
|
GFX->pushActiveRenderTarget();
|
||||||
for (S32 i = 5; i >= 0; i--) {
|
for (S32 i = 0; i < 6; i++) {
|
||||||
updateFace(params, i, explicitPostion);
|
updateFace(params, i, explicitPostion);
|
||||||
}
|
}
|
||||||
GFX->popActiveRenderTarget();
|
GFX->popActiveRenderTarget();
|
||||||
|
|
@ -352,7 +352,6 @@ void CubeReflector::updateReflection( const ReflectParams ¶ms, Point3F expli
|
||||||
|
|
||||||
mCubemap->generateMipMaps();
|
mCubemap->generateMipMaps();
|
||||||
|
|
||||||
|
|
||||||
gClientSceneGraph->setVisibleDistance(oldVisibleDist);
|
gClientSceneGraph->setVisibleDistance(oldVisibleDist);
|
||||||
|
|
||||||
mIsRendering = false;
|
mIsRendering = false;
|
||||||
|
|
@ -413,19 +412,19 @@ void CubeReflector::updateFace( const ReflectParams ¶ms, U32 faceidx, Point3
|
||||||
|
|
||||||
GFX->setWorldMatrix(lightMatrix);
|
GFX->setWorldMatrix(lightMatrix);
|
||||||
GFX->clearTextureStateImmediate(0);
|
GFX->clearTextureStateImmediate(0);
|
||||||
mRenderTarget->attachTexture( GFXTextureTarget::Color0, mCubemap, faceidx ); // Setup textures and targets...
|
|
||||||
S32 texDim = mDesc->texSize;
|
S32 texDim = mDesc->texSize;
|
||||||
texDim = getMax(texDim, 32);
|
texDim = getMax(texDim, 32);
|
||||||
|
mRenderTarget->attachTexture(GFXTextureTarget::Color0, mCubemap, 0, 0, faceidx); // Setup textures and targets...
|
||||||
mRenderTarget->attachTexture(GFXTextureTarget::DepthStencil, LightShadowMap::_getDepthTarget(texDim, texDim));
|
mRenderTarget->attachTexture(GFXTextureTarget::DepthStencil, LightShadowMap::_getDepthTarget(texDim, texDim));
|
||||||
|
|
||||||
GFX->setActiveRenderTarget(mRenderTarget);
|
GFX->setActiveRenderTarget(mRenderTarget, true);
|
||||||
GFX->clear( GFXClearStencil | GFXClearTarget | GFXClearZBuffer, gCanvasClearColor, 1.0f, 0);
|
GFX->clear( GFXClearStencil | GFXClearTarget | GFXClearZBuffer, gCanvasClearColor, 1.0f, 0);
|
||||||
|
|
||||||
SceneRenderState reflectRenderState
|
SceneRenderState reflectRenderState
|
||||||
(
|
(
|
||||||
gClientSceneGraph,
|
gClientSceneGraph,
|
||||||
SPT_Reflect,
|
SPT_Reflect,
|
||||||
SceneCameraState::fromGFX()
|
SceneCameraState::fromGFXWithViewport(GFX->getViewport())
|
||||||
);
|
);
|
||||||
|
|
||||||
reflectRenderState.getMaterialDelegate().bind( REFLECTMGR, &ReflectionManager::getReflectionMaterial );
|
reflectRenderState.getMaterialDelegate().bind( REFLECTMGR, &ReflectionManager::getReflectionMaterial );
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ class CubeReflector : public ReflectorBase
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CubeReflector();
|
CubeReflector();
|
||||||
virtual ~CubeReflector() {}
|
virtual ~CubeReflector() { mCubemap.free(); }
|
||||||
|
|
||||||
void registerReflector( SceneObject *inObject,
|
void registerReflector( SceneObject *inObject,
|
||||||
ReflectorDesc *inDesc );
|
ReflectorDesc *inDesc );
|
||||||
|
|
@ -153,7 +153,7 @@ public:
|
||||||
void unregisterReflector() override;
|
void unregisterReflector() override;
|
||||||
void updateReflection( const ReflectParams ¶ms, Point3F explicitPostion = Point3F::Max) override;
|
void updateReflection( const ReflectParams ¶ms, Point3F explicitPostion = Point3F::Max) override;
|
||||||
|
|
||||||
GFXCubemap* getCubemap() const { return mCubemap; }
|
GFXTexHandle getCubemap() const { return mCubemap; }
|
||||||
|
|
||||||
void updateFace( const ReflectParams ¶ms, U32 faceidx, Point3F explicitPostion = Point3F::Max);
|
void updateFace( const ReflectParams ¶ms, U32 faceidx, Point3F explicitPostion = Point3F::Max);
|
||||||
F32 calcFaceScore( const ReflectParams ¶ms, U32 faceidx );
|
F32 calcFaceScore( const ReflectParams ¶ms, U32 faceidx );
|
||||||
|
|
@ -162,7 +162,7 @@ protected:
|
||||||
|
|
||||||
GFXTexHandle mDepthBuff;
|
GFXTexHandle mDepthBuff;
|
||||||
GFXTextureTargetRef mRenderTarget;
|
GFXTextureTargetRef mRenderTarget;
|
||||||
GFXCubemapHandle mCubemap;
|
GFXTexHandle mCubemap;
|
||||||
U32 mLastTexSize;
|
U32 mLastTexSize;
|
||||||
|
|
||||||
class CubeFaceReflector : public ReflectorBase
|
class CubeFaceReflector : public ReflectorBase
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ protected:
|
||||||
|
|
||||||
const SceneRenderState *mState;
|
const SceneRenderState *mState;
|
||||||
|
|
||||||
GFXCubemap *mCubemap;
|
GFXTexHandle mCubemap;
|
||||||
|
|
||||||
/// Used to override the normal
|
/// Used to override the normal
|
||||||
/// fade value of an object.
|
/// fade value of an object.
|
||||||
|
|
@ -134,8 +134,8 @@ public:
|
||||||
void setSceneState( const SceneRenderState *state ) { mState = state; }
|
void setSceneState( const SceneRenderState *state ) { mState = state; }
|
||||||
|
|
||||||
///@see mCubemap
|
///@see mCubemap
|
||||||
GFXCubemap* getCubemap() const { return mCubemap; }
|
GFXTexHandle getCubemap() const { return mCubemap; }
|
||||||
void setCubemap( GFXCubemap *cubemap ) { mCubemap = cubemap; }
|
void setCubemap(GFXTexHandle cubemap ) { mCubemap = cubemap; }
|
||||||
|
|
||||||
///@see mFadeOverride
|
///@see mFadeOverride
|
||||||
F32 getFadeOverride() const { return mFadeOverride; }
|
F32 getFadeOverride() const { return mFadeOverride; }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue