mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-19 20:24:49 +00:00
Merge pull request #1632 from marauder2k9-torque/GFXTexture-And-GBitmap-updates
Some checks are pending
Linux Build / ${{matrix.config.name}} (map[build_type:Release cc:gcc cxx:g++ generator:Ninja name:Ubuntu Latest GCC]) (push) Waiting to run
MacOSX Build / ${{matrix.config.name}} (map[build_type:Release cc:clang cxx:clang++ generator:Ninja name:MacOSX Latest Clang]) (push) Waiting to run
Windows Build / ${{matrix.config.name}} (map[build_type:Release cc:cl cxx:cl environment_script:C:/Program Files (x86)/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvars64.bat generator:Visual Studio 17 2022 name:Windows Latest MSVC]) (push) Waiting to run
Some checks are pending
Linux Build / ${{matrix.config.name}} (map[build_type:Release cc:gcc cxx:g++ generator:Ninja name:Ubuntu Latest GCC]) (push) Waiting to run
MacOSX Build / ${{matrix.config.name}} (map[build_type:Release cc:clang cxx:clang++ generator:Ninja name:MacOSX Latest Clang]) (push) Waiting to run
Windows Build / ${{matrix.config.name}} (map[build_type:Release cc:cl cxx:cl environment_script:C:/Program Files (x86)/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvars64.bat generator:Visual Studio 17 2022 name:Windows Latest MSVC]) (push) Waiting to run
Update GFXTextureManager and GBitmap
This commit is contained in:
commit
f55d061c92
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
namespace IBLUtilities
|
||||
{
|
||||
void GenerateIrradianceMap(GFXTextureTargetRef renderTarget, GFXCubemapHandle cubemap, GFXCubemapHandle &cubemapOut)
|
||||
void GenerateIrradianceMap(GFXTextureTargetRef renderTarget, GFXTexHandle cubemap, GFXTexHandle &cubemapOut)
|
||||
{
|
||||
GFXTransformSaver saver;
|
||||
|
||||
|
|
@ -65,11 +65,11 @@ namespace IBLUtilities
|
|||
GFX->setShaderConstBuffer(irrConsts);
|
||||
GFX->setStateBlock(irrStateBlock);
|
||||
GFX->setVertexBuffer(NULL);
|
||||
GFX->setCubeTexture(0, cubemap);
|
||||
GFX->setTexture(0, cubemap);
|
||||
|
||||
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);
|
||||
GFX->setActiveRenderTarget(renderTarget);
|
||||
GFX->clear(GFXClearTarget, LinearColorF::BLACK, 1.0f, 0);
|
||||
|
|
@ -80,7 +80,7 @@ namespace IBLUtilities
|
|||
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())
|
||||
{
|
||||
|
|
@ -101,7 +101,7 @@ namespace IBLUtilities
|
|||
}
|
||||
}
|
||||
|
||||
void SaveCubeMap(String outputPath, GFXCubemapHandle &cubemap)
|
||||
void SaveCubeMap(String outputPath, GFXTexHandle &cubemap)
|
||||
{
|
||||
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;
|
||||
|
||||
|
|
@ -153,9 +153,9 @@ namespace IBLUtilities
|
|||
GFX->pushActiveRenderTarget();
|
||||
GFX->setShader(prefilterShader);
|
||||
GFX->setShaderConstBuffer(prefilterConsts);
|
||||
GFX->setCubeTexture(0, cubemap);
|
||||
GFX->setTexture(0, cubemap);
|
||||
|
||||
U32 prefilterSize = cubemapOut->getSize();
|
||||
U32 prefilterSize = cubemapOut->getWidth();
|
||||
|
||||
U32 resolutionSize = prefilterSize;
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ namespace IBLUtilities
|
|||
prefilterConsts->setSafe(prefilterRoughnessSC, roughness);
|
||||
prefilterConsts->setSafe(prefilterMipSizeSC, mipSize);
|
||||
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->setViewport(RectI(0, 0, size, size));
|
||||
GFX->clear(GFXClearTarget, LinearColorF::BLACK, 1.0f, 0);
|
||||
|
|
@ -183,7 +183,7 @@ namespace IBLUtilities
|
|||
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())
|
||||
{
|
||||
|
|
@ -504,7 +504,7 @@ namespace IBLUtilities
|
|||
//SH Calculations
|
||||
// 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
|
||||
void calculateSHTerms(GFXCubemapHandle cubemap, LinearColorF SHTerms[9], F32 SHConstants[5])
|
||||
void calculateSHTerms(GFXTexHandle cubemap, LinearColorF SHTerms[9], F32 SHConstants[5])
|
||||
{
|
||||
if (!cubemap)
|
||||
return;
|
||||
|
|
@ -525,7 +525,7 @@ namespace IBLUtilities
|
|||
VectorF(0.0f, 0.0f, -1.0f),
|
||||
};
|
||||
|
||||
U32 cubemapResolution = cubemap->getSize();
|
||||
U32 cubemapResolution = cubemap->getWidth();
|
||||
|
||||
GBitmap* cubeFaceBitmaps[6];
|
||||
|
||||
|
|
|
|||
|
|
@ -38,13 +38,13 @@
|
|||
|
||||
namespace IBLUtilities
|
||||
{
|
||||
void GenerateIrradianceMap(GFXTextureTargetRef renderTarget, GFXCubemapHandle cubemap, GFXCubemapHandle &cubemapOut);
|
||||
void GenerateAndSaveIrradianceMap(String outputPath, S32 resolution, GFXCubemapHandle cubemap, GFXCubemapHandle &cubemapOut);
|
||||
void GenerateIrradianceMap(GFXTextureTargetRef renderTarget, GFXTexHandle cubemap, GFXTexHandle& cubemapOut);
|
||||
void GenerateAndSaveIrradianceMap(String outputPath, S32 resolution, GFXTexHandle cubemap, GFXTexHandle& cubemapOut);
|
||||
|
||||
void GeneratePrefilterMap(GFXTextureTargetRef renderTarget, GFXCubemapHandle cubemap, U32 mipLevels, GFXCubemapHandle &cubemapOut);
|
||||
void GenerateAndSavePrefilterMap(String outputPath, S32 resolution, GFXCubemapHandle cubemap, U32 mipLevels, GFXCubemapHandle &cubemapOut);
|
||||
void GeneratePrefilterMap(GFXTextureTargetRef renderTarget, GFXTexHandle cubemap, U32 mipLevels, GFXTexHandle &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);
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ namespace IBLUtilities
|
|||
//SH Calculations
|
||||
// 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
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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" },
|
||||
EndImplementEnumType;
|
||||
|
||||
void ReflectionProbe::ProbeInfo::clear()
|
||||
{
|
||||
mPrefilterCubemap.free();
|
||||
mIrradianceCubemap.free();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object setup and teardown
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -146,11 +153,18 @@ ReflectionProbe::~ReflectionProbe()
|
|||
if (mReflectionModeType == StaticCubemap && mStaticCubemap)
|
||||
mStaticCubemap->deleteObject();
|
||||
|
||||
if (mIrridianceMap)
|
||||
mIrridianceMap->deleteObject();
|
||||
mProbeInfo.clear();
|
||||
|
||||
if (mIrridianceMap) {
|
||||
if (mIrridianceMap->isProperlyAdded() && !mIrridianceMap->isRemoved())
|
||||
mIrridianceMap->deleteObject();
|
||||
}
|
||||
|
||||
if (mPrefilterMap)
|
||||
mPrefilterMap->deleteObject();
|
||||
{
|
||||
if (mPrefilterMap->isProperlyAdded() && !mPrefilterMap->isRemoved())
|
||||
mPrefilterMap->deleteObject();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -603,7 +617,7 @@ void ReflectionProbe::processBakedCubemap()
|
|||
return;
|
||||
|
||||
String irrPath = getIrradianceMapPath();
|
||||
if (Platform::isFile(irrPath))
|
||||
if ((mIrridianceMap == nullptr || mIrridianceMap->mCubemap.isNull()) && Platform::isFile(irrPath))
|
||||
{
|
||||
mIrridianceMap->setCubemapFile(FileName(irrPath));
|
||||
mIrridianceMap->updateFaces();
|
||||
|
|
@ -616,7 +630,7 @@ void ReflectionProbe::processBakedCubemap()
|
|||
}
|
||||
|
||||
String prefilPath = getPrefilterMapPath();
|
||||
if (Platform::isFile(prefilPath))
|
||||
if ((mPrefilterMap == nullptr || mPrefilterMap->mCubemap.isNull()) && Platform::isFile(prefilPath))
|
||||
{
|
||||
mPrefilterMap->setCubemapFile(FileName(prefilPath));
|
||||
mPrefilterMap->updateFaces();
|
||||
|
|
@ -631,7 +645,7 @@ void ReflectionProbe::processBakedCubemap()
|
|||
mProbeInfo.mPrefilterCubemap = mPrefilterMap->mCubemap;
|
||||
mProbeInfo.mIrradianceCubemap = mIrridianceMap->mCubemap;
|
||||
|
||||
if (mEnabled && mProbeInfo.mPrefilterCubemap->isInitialized() && mProbeInfo.mIrradianceCubemap->isInitialized())
|
||||
if (mEnabled && !mProbeInfo.mPrefilterCubemap.isNull() && !mProbeInfo.mIrradianceCubemap.isNull())
|
||||
{
|
||||
//mProbeInfo.mIsEnabled = true;
|
||||
|
||||
|
|
@ -698,7 +712,7 @@ void ReflectionProbe::processStaticCubemap()
|
|||
return;
|
||||
}
|
||||
|
||||
if (mStaticCubemap->mCubemap == nullptr)
|
||||
if (mStaticCubemap->mCubemap.isNull())
|
||||
{
|
||||
mStaticCubemap->createMap();
|
||||
mStaticCubemap->updateFaces();
|
||||
|
|
@ -706,13 +720,13 @@ void ReflectionProbe::processStaticCubemap()
|
|||
|
||||
if (mUseHDRCaptures)
|
||||
{
|
||||
mIrridianceMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR16G16B16A16F);
|
||||
mPrefilterMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR16G16B16A16F);
|
||||
mIrridianceMap->mCubemap.set(mPrefilterSize, mPrefilterSize, GFXFormatR16G16B16A16F, &GFXCubemapRenderTargetProfile, "ReflectionProbe::mIrridianceMap_HDR");
|
||||
mPrefilterMap->mCubemap.set(mPrefilterSize, mPrefilterSize, GFXFormatR16G16B16A16F, &GFXCubemapRenderTargetProfile, "ReflectionProbe::mPrefilterMap_HDR");
|
||||
}
|
||||
else
|
||||
{
|
||||
mIrridianceMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR8G8B8A8);
|
||||
mPrefilterMap->mCubemap->initDynamic(mPrefilterSize, GFXFormatR8G8B8A8);
|
||||
mIrridianceMap->mCubemap.set(mPrefilterSize, mPrefilterSize, GFXFormatR8G8B8A8, &GFXCubemapRenderTargetProfile, "ReflectionProbe::mIrridianceMap");
|
||||
mPrefilterMap->mCubemap.set(mPrefilterSize, mPrefilterSize, GFXFormatR8G8B8A8, &GFXCubemapRenderTargetProfile, "ReflectionProbe::mPrefilterMap");
|
||||
}
|
||||
|
||||
GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false);
|
||||
|
|
@ -730,7 +744,7 @@ void ReflectionProbe::processStaticCubemap()
|
|||
mProbeInfo.mIrradianceCubemap = mIrridianceMap->mCubemap;
|
||||
}
|
||||
|
||||
if (mEnabled && mProbeInfo.mPrefilterCubemap->isInitialized() && mProbeInfo.mIrradianceCubemap->isInitialized())
|
||||
if (mEnabled && mProbeInfo.mPrefilterCubemap.isValid() && mProbeInfo.mIrradianceCubemap.isValid())
|
||||
{
|
||||
mProbeInfo.mIsEnabled = true;
|
||||
|
||||
|
|
@ -1009,7 +1023,7 @@ void ReflectionProbe::setPreviewMatParameters(SceneRenderState* renderState, Bas
|
|||
GFX->setTexture(0, deferredTexObject);
|
||||
|
||||
//Set the cubemap
|
||||
GFX->setCubeTexture(1, mPrefilterMap->mCubemap);
|
||||
GFX->setTexture(1, mPrefilterMap->mCubemap);
|
||||
|
||||
//Set the invViewMat
|
||||
MatrixSet &matrixSet = renderState->getRenderPass()->getMatrixSet();
|
||||
|
|
@ -1036,3 +1050,4 @@ DefineEngineMethod(ReflectionProbe, Bake, void, (), ,
|
|||
clientProbe->bake();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,8 +94,8 @@ public:
|
|||
|
||||
F32 mScore;
|
||||
|
||||
GFXCubemapHandle mPrefilterCubemap;
|
||||
GFXCubemapHandle mIrradianceCubemap;
|
||||
GFXTexHandle mPrefilterCubemap;
|
||||
GFXTexHandle mIrradianceCubemap;
|
||||
|
||||
/// The priority of this light used for
|
||||
/// light and shadow scoring.
|
||||
|
|
@ -233,7 +233,7 @@ protected:
|
|||
/// </summary>
|
||||
StringTableEntry mCubemapName;
|
||||
CubemapData *mStaticCubemap;
|
||||
GFXCubemapHandle mDynamicCubemap;
|
||||
GFXTexHandle mDynamicCubemap;
|
||||
|
||||
//String cubeDescName;
|
||||
//U32 cubeDescId;
|
||||
|
|
|
|||
|
|
@ -112,6 +112,21 @@ bool AssetManager::onAdd()
|
|||
|
||||
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?
|
||||
if ( !mAssetTagsManifest.isNull() )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1090,7 +1090,7 @@ void ScatterSky::_render( ObjectRenderInst *ri, SceneRenderState *state, BaseMat
|
|||
if ( !mNightCubemap->mCubemap )
|
||||
mNightCubemap->createMap();
|
||||
|
||||
GFX->setCubeTexture( 0, mNightCubemap->mCubemap );
|
||||
GFX->setTexture( 0, mNightCubemap->mCubemap );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -776,9 +776,9 @@ void WaterObject::setCustomTextures( S32 matIdx, U32 pass, const WaterMatParams
|
|||
}
|
||||
|
||||
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 )
|
||||
GFX->setCubeTexture( paramHandles.mCubemapSamplerSC->getSamplerRegister(pass), NULL );
|
||||
GFX->setTexture( paramHandles.mCubemapSamplerSC->getSamplerRegister(pass), NULL );
|
||||
}
|
||||
|
||||
void WaterObject::drawUnderwaterFilter( SceneRenderState *state )
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ GFXD3D11TextureTarget::GFXD3D11TextureTarget(bool genMips)
|
|||
mResolveTargets[i] = NULL;
|
||||
mTargetViews[i] = NULL;
|
||||
mTargetSRViews[i] = NULL;
|
||||
mTargetArrayIdx[i] = 0;
|
||||
}
|
||||
|
||||
mGenMips = genMips;
|
||||
|
|
@ -57,9 +58,9 @@ GFXD3D11TextureTarget::~GFXD3D11TextureTarget()
|
|||
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.");
|
||||
|
||||
|
|
@ -76,17 +77,17 @@ void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *te
|
|||
SAFE_RELEASE(mTargetViews[slot]);
|
||||
SAFE_RELEASE(mTargets[slot]);
|
||||
SAFE_RELEASE(mTargetSRViews[slot]);
|
||||
|
||||
mResolveTargets[slot] = NULL;
|
||||
mTargetArrayIdx[slot] = 0;
|
||||
|
||||
if(slot == Color0)
|
||||
if (slot == Color0)
|
||||
{
|
||||
mTargetSize = Point2I::Zero;
|
||||
mTargetFormat = GFXFormatR8G8B8A8;
|
||||
}
|
||||
|
||||
// Are we clearing?
|
||||
if(!tex)
|
||||
if (!tex)
|
||||
{
|
||||
// Yup - just exit, it'll stay NULL.
|
||||
return;
|
||||
|
|
@ -96,7 +97,7 @@ void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *te
|
|||
mTargetSRViews[slot] = NULL;
|
||||
|
||||
// Take care of default targets
|
||||
if( tex == GFXTextureTarget::sDefaultDepthStencil )
|
||||
if (tex == GFXTextureTarget::sDefaultDepthStencil)
|
||||
{
|
||||
mTargets[slot] = D3D11->mDeviceDepthStencil;
|
||||
mTargetViews[slot] = D3D11->mDeviceDepthStencilView;
|
||||
|
|
@ -108,81 +109,100 @@ void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *te
|
|||
// Cast the texture object to D3D...
|
||||
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.
|
||||
if( slot == DepthStencil )
|
||||
{
|
||||
if (slot == DepthStencil)
|
||||
{
|
||||
mTargets[slot] = d3dto->getSurface();
|
||||
if ( mTargets[slot] )
|
||||
if (mTargets[slot])
|
||||
mTargets[slot]->AddRef();
|
||||
|
||||
mTargetViews[slot] = d3dto->getDSView();
|
||||
if( mTargetViews[slot])
|
||||
mTargetViews[slot]->AddRef();
|
||||
if (mTargetViews[slot])
|
||||
mTargetViews[slot]->AddRef();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// getSurface will almost always return NULL. It will only return non-NULL
|
||||
// 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 (!isCube)
|
||||
{
|
||||
|
||||
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 )
|
||||
if (d3dto->getSurface() == NULL)
|
||||
{
|
||||
mTargetSize.set( tex->getSize().x, tex->getSize().y );
|
||||
mTargetFormat = tex->getFormat();
|
||||
mTargets[slot] = d3dto->get2DTex();
|
||||
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)
|
||||
{
|
||||
mTargetSRViews[slot] = d3dto->getSRView();
|
||||
mTargetSRViews[slot]->AddRef();
|
||||
if (mTargetSRViews[slot])
|
||||
mTargetSRViews[slot]->AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
// Update surface size
|
||||
if(slot == Color0)
|
||||
// Update color target info
|
||||
if (slot == Color0)
|
||||
{
|
||||
ID3D11Texture2D *surface = mTargets[Color0];
|
||||
if ( surface )
|
||||
ID3D11Texture2D* surface = mTargets[Color0];
|
||||
if (surface)
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC sd;
|
||||
surface->GetDesc(&sd);
|
||||
mTargetSize = Point2I(sd.Width, sd.Height);
|
||||
|
||||
S32 format = sd.Format;
|
||||
|
||||
if (format == DXGI_FORMAT_R8G8B8A8_TYPELESS || format == DXGI_FORMAT_B8G8R8A8_TYPELESS)
|
||||
{
|
||||
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*/ )
|
||||
{
|
||||
GFXDEBUGEVENT_SCOPE( GFXPCD3D11TextureTarget_attachTexture_Cubemap, ColorI::RED );
|
||||
|
|
@ -316,7 +336,9 @@ void GFXD3D11TextureTarget::resolveTo( GFXTextureObject *tex )
|
|||
|
||||
D3D11_TEXTURE2D_DESC 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;
|
||||
|
||||
U32 mTargetArrayIdx[MaxRenderSlotId];
|
||||
|
||||
public:
|
||||
|
||||
GFXD3D11TextureTarget(bool genMips);
|
||||
|
|
@ -57,7 +59,7 @@ public:
|
|||
// Public interface.
|
||||
const Point2I getSize() override { return mTargetSize; }
|
||||
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 resolve() override;
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ void GFXD3D11TextureManager::_innerCreateTexture( GFXD3D11TextureObject *retTex,
|
|||
GFXTextureProfile *profile,
|
||||
U32 numMipLevels,
|
||||
bool forceMips,
|
||||
S32 antialiasLevel)
|
||||
S32 antialiasLevel,
|
||||
U32 arraySize)
|
||||
{
|
||||
U32 usage = 0;
|
||||
U32 bindFlags = 0;
|
||||
|
|
@ -67,6 +68,9 @@ void GFXD3D11TextureManager::_innerCreateTexture( GFXD3D11TextureObject *retTex,
|
|||
retTex->isManaged = false;
|
||||
DXGI_FORMAT d3dTextureFormat = GFXD3D11TextureFormat[format];
|
||||
|
||||
if (retTex->isCubeMap())
|
||||
miscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
|
||||
|
||||
if( retTex->mProfile->isDynamic() )
|
||||
{
|
||||
usage = D3D11_USAGE_DYNAMIC;
|
||||
|
|
@ -199,7 +203,7 @@ void GFXD3D11TextureManager::_innerCreateTexture( GFXD3D11TextureObject *retTex,
|
|||
D3D11_TEXTURE2D_DESC desc;
|
||||
|
||||
ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
|
||||
desc.ArraySize = 1;
|
||||
desc.ArraySize = arraySize * (retTex->isCubeMap() ? 6 : 1);
|
||||
desc.BindFlags = bindFlags;
|
||||
desc.CPUAccessFlags = cpuFlags;
|
||||
desc.Format = d3dTextureFormat;
|
||||
|
|
@ -219,6 +223,7 @@ void GFXD3D11TextureManager::_innerCreateTexture( GFXD3D11TextureObject *retTex,
|
|||
|
||||
retTex->get2DTex()->GetDesc(&desc);
|
||||
retTex->mMipLevels = desc.MipLevels;
|
||||
retTex->mArraySize = arraySize;
|
||||
}
|
||||
|
||||
// start creating the resource views...
|
||||
|
|
@ -267,6 +272,7 @@ GFXTextureObject *GFXD3D11TextureManager::_createTextureObject( U32 height,
|
|||
U32 numMipLevels,
|
||||
bool forceMips,
|
||||
S32 antialiasLevel,
|
||||
U32 arraySize,
|
||||
GFXTextureObject *inTex )
|
||||
{
|
||||
GFXD3D11TextureObject *retTex;
|
||||
|
|
@ -278,11 +284,11 @@ GFXTextureObject *GFXD3D11TextureManager::_createTextureObject( U32 height,
|
|||
}
|
||||
else
|
||||
{
|
||||
retTex = new GFXD3D11TextureObject(GFX, profile);
|
||||
retTex = new GFXD3D11TextureObject(GFX, profile, arraySize);
|
||||
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;
|
||||
}
|
||||
|
|
@ -295,7 +301,9 @@ bool GFXD3D11TextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *p
|
|||
|
||||
// Check with profiler to see if we can do automatic mipmap generation.
|
||||
const bool supportsAutoMips = GFX->getCardProfiler()->queryProfile("autoMipMapLevel", true);
|
||||
|
||||
|
||||
const bool isCube = texture->isCubeMap() && pDL->getNumFaces() > 1;
|
||||
const U32 numFaces = isCube ? 6 : 1;
|
||||
// Helper bool
|
||||
const bool isCompressedTexFmt = ImageUtil::isCompressedFormat(aTexture->mFormat);
|
||||
|
||||
|
|
@ -312,98 +320,101 @@ bool GFXD3D11TextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *p
|
|||
|
||||
bool isDynamic = texture->mProfile->isDynamic();
|
||||
// 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)
|
||||
{
|
||||
U8* copyBuffer = NULL;
|
||||
if (!isDynamic)
|
||||
{
|
||||
U8* copyBuffer = NULL;
|
||||
|
||||
switch(texture->mFormat)
|
||||
{
|
||||
switch (texture->mFormat)
|
||||
{
|
||||
case GFXFormatR8G8B8:
|
||||
case GFXFormatR8G8B8_SRGB:
|
||||
{
|
||||
PROFILE_SCOPE(Swizzle24_Upload);
|
||||
{
|
||||
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));
|
||||
copyBuffer = new U8[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);
|
||||
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));
|
||||
copyBuffer = new U8[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);
|
||||
SAFE_DELETE_ARRAY(Bits);
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
case GFXFormatR8G8B8A8:
|
||||
case GFXFormatR8G8B8X8:
|
||||
case GFXFormatR8G8B8A8_SRGB:
|
||||
{
|
||||
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
|
||||
PROFILE_SCOPE(SwizzleNull_Upload);
|
||||
AssertFatal( pDL->getFormat() == texture->mFormat, "Format mismatch");
|
||||
dMemcpy(mapping.pData, pDL->getBits(i), pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel());
|
||||
}
|
||||
}
|
||||
AssertFatal(pDL->getFormat() == texture->mFormat, "Format mismatch");
|
||||
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;
|
||||
|
|
@ -487,7 +498,7 @@ bool GFXD3D11TextureManager::_refreshTexture(GFXTextureObject *texture)
|
|||
if(texture->mProfile->isRenderTarget() || texture->mProfile->isDynamic() || texture->mProfile->isZTarget())
|
||||
{
|
||||
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++;
|
||||
}
|
||||
|
||||
|
|
@ -519,14 +530,31 @@ bool GFXD3D11TextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *d
|
|||
GFXD3D11TextureObject *texture = static_cast<GFXD3D11TextureObject*>(aTexture);
|
||||
GFXD3D11Device* dev = static_cast<GFXD3D11Device *>(GFX);
|
||||
// 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);
|
||||
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subresource, 0, dds->mSurfaces[0]->mMips[i], dds->getSurfacePitch(i), 0);
|
||||
const U32 subresource = D3D11CalcSubresource(mip, face, aTexture->mMipLevels);
|
||||
|
||||
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;
|
||||
|
|
@ -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)
|
||||
{
|
||||
GFXD3D11TextureObject *tex = static_cast<GFXD3D11TextureObject*>(inTex);
|
||||
ID3D11Resource* resource = NULL;
|
||||
|
||||
if(tex->get2DTex())
|
||||
resource = tex->get2DTex();
|
||||
else if(tex->getSurface())
|
||||
resource = tex->getSurface();
|
||||
else
|
||||
resource = tex->get3DTex();
|
||||
ID3D11Resource* resource;
|
||||
|
||||
if (tex->get2DTex())
|
||||
resource = tex->get2DTex();
|
||||
else if (tex->getSurface())
|
||||
resource = tex->getSurface();
|
||||
else
|
||||
resource = tex->get3DTex();
|
||||
|
||||
HRESULT hr;
|
||||
//TODO: add MSAA support later.
|
||||
|
|
@ -567,11 +595,40 @@ void GFXD3D11TextureManager::createResourceView(U32 height, U32 width, U32 depth
|
|||
desc.Texture3D.MipLevels = -1;
|
||||
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;
|
||||
desc.Texture2D.MipLevels = -1;
|
||||
desc.Texture2D.MostDetailedMip = 0;
|
||||
if (tex->getArraySize() == 1)
|
||||
{
|
||||
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());
|
||||
|
|
@ -580,12 +637,29 @@ void GFXD3D11TextureManager::createResourceView(U32 height, U32 width, U32 depth
|
|||
|
||||
if(usageFlags & D3D11_BIND_RENDER_TARGET)
|
||||
{
|
||||
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 (tex->isCubeMap())
|
||||
{
|
||||
for (U32 face = 0; face < 6; face++)
|
||||
{
|
||||
D3D11_RENDER_TARGET_VIEW_DESC desc;
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ protected:
|
|||
U32 numMipLevels,
|
||||
bool forceMips = false,
|
||||
S32 antialiasLevel = 0,
|
||||
U32 arraySize = 1,
|
||||
GFXTextureObject *inTex = NULL ) override;
|
||||
|
||||
bool _loadTexture(GFXTextureObject *texture, DDSFile *dds) override;
|
||||
|
|
@ -56,7 +57,7 @@ protected:
|
|||
private:
|
||||
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
|
||||
|
|
|
|||
|
|
@ -33,26 +33,16 @@ U32 GFXD3D11TextureObject::mTexCount = 0;
|
|||
// 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.
|
||||
// DirectX 10-11 both have 24 bit format no longer.
|
||||
|
||||
|
||||
GFXD3D11TextureObject::GFXD3D11TextureObject( GFXDevice * d, GFXTextureProfile *profile) : GFXTextureObject( d, profile )
|
||||
GFXD3D11TextureObject::GFXD3D11TextureObject( GFXDevice * d, GFXTextureProfile *profile, const U32 arraySize) : GFXTextureObject( d, profile )
|
||||
{
|
||||
#ifdef D3D11_DEBUG_SPEW
|
||||
mTexCount++;
|
||||
Con::printf("+ texMake %d %x", mTexCount, this);
|
||||
#endif
|
||||
|
||||
mD3DTexture = NULL;
|
||||
mLocked = false;
|
||||
|
||||
mD3DSurface = NULL;
|
||||
isManaged = false;
|
||||
dMemset(&mLockRect, 0, sizeof(mLockRect));
|
||||
dMemset(&mLockBox, 0, sizeof(mLockBox));
|
||||
mLockedSubresource = 0;
|
||||
mDSView = NULL;
|
||||
mRTView = NULL;
|
||||
mSRView = NULL;
|
||||
isManaged = false;
|
||||
mArraySize = arraySize;
|
||||
}
|
||||
|
||||
GFXD3D11TextureObject::~GFXD3D11TextureObject()
|
||||
|
|
@ -64,53 +54,76 @@ GFXD3D11TextureObject::~GFXD3D11TextureObject()
|
|||
#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->getHeight() != getHeight() ||
|
||||
mStagingTex->getDepth() != getDepth())
|
||||
{
|
||||
if (getDepth() != 0)
|
||||
{
|
||||
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__));
|
||||
}
|
||||
mStagingTex.set(getWidth(), getHeight(), mFormat, &GFXSystemMemTextureProfile,
|
||||
avar("%s() - stagingTex", __FUNCTION__));
|
||||
}
|
||||
|
||||
ID3D11DeviceContext* pContext = D3D11DEVICECONTEXT;
|
||||
D3D11_MAPPED_SUBRESOURCE mapInfo;
|
||||
U32 offset = 0;
|
||||
mLockedSubresource = D3D11CalcSubresource(mipLevel, 0, getMipLevels());
|
||||
GFXD3D11TextureObject* pD3DStagingTex = (GFXD3D11TextureObject*)&(*mStagingTex);
|
||||
|
||||
//map staging texture
|
||||
HRESULT hr = pContext->Map(pD3DStagingTex->getResource(), mLockedSubresource, D3D11_MAP_WRITE, 0, &mapInfo);
|
||||
mLockedSubresource = D3D11CalcSubresource(mipLevel, faceIndex, getMipLevels());
|
||||
GFXD3D11TextureObject* staging = (GFXD3D11TextureObject*)&(*mStagingTex);
|
||||
|
||||
HRESULT hr = D3D11DEVICECONTEXT->Map(staging->getResource(), mLockedSubresource, D3D11_MAP_WRITE, 0, &mapInfo);
|
||||
if (FAILED(hr))
|
||||
AssertFatal(false, "GFXD3D11TextureObject:lock - failed to map render target resource!");
|
||||
|
||||
|
||||
const bool is3D = mStagingTex->getDepth() != 0;
|
||||
const U32 width = mTextureSize.x >> mipLevel;
|
||||
const U32 height = mTextureSize.y >> mipLevel;
|
||||
const U32 depth = is3D ? mTextureSize.z >> mipLevel : 1;
|
||||
U32 offset = 0;
|
||||
|
||||
//calculate locked box region and offset
|
||||
if (inRect)
|
||||
{
|
||||
if ((inRect->point.x + inRect->extent.x > width) || (inRect->point.y + inRect->extent.y > height))
|
||||
AssertFatal(false, "GFXD3D11TextureObject::lock - Rectangle too big!");
|
||||
AssertFatal(inRect->point.x + inRect->extent.x <= width, "GFXD3D11TextureObject::lock - Invalid lock rect width!");
|
||||
AssertFatal(inRect->point.y + inRect->extent.y <= height, "GFXD3D11TextureObject::lock - Invalid lock rect height!");
|
||||
|
||||
mLockBox.top = inRect->point.y;
|
||||
mLockBox.left = inRect->point.x;
|
||||
mLockBox.bottom = inRect->point.y + inRect->extent.y;
|
||||
mLockBox.right = inRect->point.x + inRect->extent.x;
|
||||
mLockBox.bottom = inRect->point.y + inRect->extent.y;
|
||||
mLockBox.back = depth;
|
||||
mLockBox.front = 0;
|
||||
|
||||
|
|
@ -121,49 +134,57 @@ GFXLockedRect *GFXD3D11TextureObject::lock(U32 mipLevel /*= 0*/, RectI *inRect /
|
|||
{
|
||||
mLockBox.top = 0;
|
||||
mLockBox.left = 0;
|
||||
mLockBox.bottom = height;
|
||||
mLockBox.right = width;
|
||||
mLockBox.bottom = height;
|
||||
mLockBox.back = depth;
|
||||
mLockBox.front = 0;
|
||||
|
||||
}
|
||||
|
||||
mLocked = true;
|
||||
mLockRect.pBits = static_cast<U8*>(mapInfo.pData) + offset;
|
||||
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_lockRT);
|
||||
PROFILE_START(GFXD3D11TextureObject_unlock);
|
||||
|
||||
ID3D11DeviceContext* pContext = D3D11DEVICECONTEXT;
|
||||
GFXD3D11TextureObject* pD3DStagingTex = (GFXD3D11TextureObject*)&(*mStagingTex);
|
||||
ID3D11Resource* pStagingResource = pD3DStagingTex->getResource();
|
||||
const bool is3D = mStagingTex->getDepth() != 0;
|
||||
GFXD3D11TextureObject* staging = (GFXD3D11TextureObject*)&(*mStagingTex);
|
||||
|
||||
//unmap staging texture
|
||||
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);
|
||||
D3D11DEVICECONTEXT->Unmap(staging->getResource(), mLockedSubresource);
|
||||
|
||||
PROFILE_END();
|
||||
// Copy from staging back to GPU texture
|
||||
D3D11DEVICECONTEXT->CopySubresourceRegion(
|
||||
mD3DTexture.Get(),
|
||||
mLockedSubresource,
|
||||
0, 0, 0,
|
||||
staging->getResource(),
|
||||
mLockedSubresource,
|
||||
&mLockBox
|
||||
);
|
||||
|
||||
mLockedSubresource = 0;
|
||||
mLocked = false;
|
||||
|
||||
PROFILE_END();
|
||||
}
|
||||
|
||||
void GFXD3D11TextureObject::release()
|
||||
{
|
||||
SAFE_RELEASE(mSRView);
|
||||
SAFE_RELEASE(mRTView);
|
||||
SAFE_RELEASE(mDSView);
|
||||
SAFE_RELEASE(mD3DTexture);
|
||||
SAFE_RELEASE(mD3DSurface);
|
||||
mSRView.Reset();
|
||||
mRTView.Reset();
|
||||
mDSView.Reset();
|
||||
mD3DTexture.Reset();
|
||||
mD3DSurface.Reset();
|
||||
|
||||
for (auto& faceRTV : mCubeRTV)
|
||||
faceRTV.Reset();
|
||||
}
|
||||
|
||||
void GFXD3D11TextureObject::zombify()
|
||||
|
|
@ -189,149 +210,206 @@ bool GFXD3D11TextureObject::copyToBmp(GBitmap* bmp)
|
|||
if (!bmp)
|
||||
return false;
|
||||
|
||||
// check format limitations
|
||||
// at the moment we only support RGBA for the source (other 4 byte formats should
|
||||
// be easy to add though)
|
||||
AssertFatal(mFormat == GFXFormatR16G16B16A16F || mFormat == GFXFormatR8G8B8A8 || mFormat == GFXFormatR8G8B8A8_LINEAR_FORCE || mFormat == GFXFormatR8G8B8A8_SRGB || mFormat == GFXFormatR8G8B8, "copyToBmp: invalid format");
|
||||
if (mFormat != GFXFormatR16G16B16A16F && mFormat != GFXFormatR8G8B8A8 && mFormat != GFXFormatR8G8B8A8_LINEAR_FORCE && mFormat != GFXFormatR8G8B8A8_SRGB && mFormat != GFXFormatR8G8B8)
|
||||
return false;
|
||||
AssertFatal(mFormat == GFXFormatR16G16B16A16F || mFormat == GFXFormatR8G8B8A8 ||
|
||||
mFormat == GFXFormatR8G8B8A8_LINEAR_FORCE || mFormat == GFXFormatR8G8B8A8_SRGB ||
|
||||
mFormat == GFXFormatR8G8B8,
|
||||
"GFXD3D11TextureObject::copyToBmp - Unsupported source format.");
|
||||
|
||||
PROFILE_START(GFXD3D11TextureObject_copyToBmp);
|
||||
|
||||
AssertFatal(bmp->getWidth() == getWidth(), avar("GFXGLTextureObject::copyToBmp - Width mismatch: %i vs %i", bmp->getWidth(), getWidth()));
|
||||
AssertFatal(bmp->getHeight() == getHeight(), avar("GFXGLTextureObject::copyToBmp - Height mismatch: %i vs %i", bmp->getHeight(), getHeight()));
|
||||
const U32 mipLevels = getMipLevels();
|
||||
AssertFatal(bmp->getWidth() == getWidth(), "Width mismatch between texture and bitmap.");
|
||||
AssertFatal(bmp->getHeight() == getHeight(), "Height mismatch between texture and bitmap.");
|
||||
|
||||
const U32 mipLevels = getMipLevels();
|
||||
bmp->setHasTransparency(mHasTransparency);
|
||||
|
||||
// set some constants
|
||||
U32 sourceBytesPerPixel = 4;
|
||||
U32 destBytesPerPixel = 0;
|
||||
// Figure out bytes per pixel
|
||||
const bool isFP16 = (bmp->getFormat() == GFXFormatR16G16B16A16F);
|
||||
const U32 destBpp = (bmp->getFormat() == GFXFormatR8G8B8 ? 3 :
|
||||
bmp->getFormat() == GFXFormatR16G16B16A16F ? 8 : 4);
|
||||
const U32 srcBpp = (mFormat == GFXFormatR16G16B16A16F ? 8 : 4);
|
||||
|
||||
const GFXFormat fmt = bmp->getFormat();
|
||||
bool fp16 = false;//is rgba16f format?
|
||||
if (fmt == GFXFormatR16G16B16A16F)
|
||||
{
|
||||
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);
|
||||
// --- Create staging texture ---
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
reinterpret_cast<ID3D11Texture2D*>(mD3DTexture.Get())->GetDesc(&desc);
|
||||
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.MiscFlags = 0;
|
||||
|
||||
ID3D11Texture2D* pStagingTexture = NULL;
|
||||
HRESULT hr = D3D11DEVICE->CreateTexture2D(&desc, NULL, &pStagingTexture);
|
||||
ComPtr<ID3D11Texture2D> stagingTex;
|
||||
HRESULT hr = D3D11DEVICE->CreateTexture2D(&desc, nullptr, stagingTex.GetAddressOf());
|
||||
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;
|
||||
}
|
||||
|
||||
//copy the classes texture to the staging texture
|
||||
D3D11DEVICECONTEXT->CopyResource(pStagingTexture, mD3DTexture);
|
||||
// --- Copy texture (handle cubemap or 2D) ---
|
||||
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);
|
||||
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))
|
||||
for (U32 mip = 0; mip < mipLevels; ++mip)
|
||||
{
|
||||
//cleanup
|
||||
SAFE_RELEASE(pStagingTexture);
|
||||
Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to map staging texture");
|
||||
return false;
|
||||
}
|
||||
const U32 srcSubRes = D3D11CalcSubresource(mip, face, mipLevels);
|
||||
// Always map mip-level 0..mipLevels-1 on *slice 0* of the staging texture
|
||||
const U32 dstSubRes = D3D11CalcSubresource(mip, face, mipLevels);
|
||||
|
||||
// set pointers
|
||||
const U8* srcPtr = (U8*)mappedRes.pData;
|
||||
U8* destPtr = bmp->getWritableBits(mip);
|
||||
D3D11DEVICECONTEXT->CopySubresourceRegion(
|
||||
stagingTex.Get(), dstSubRes, 0, 0, 0,
|
||||
mD3DTexture.Get(), srcSubRes, nullptr);
|
||||
|
||||
// we will want to skip over any D3D cache data in the source texture
|
||||
const S32 sourceCacheSize = mappedRes.RowPitch - width * sourceBytesPerPixel;
|
||||
AssertFatal(sourceCacheSize >= 0, "GFXD3D11TextureObject::copyToBmp - cache size is less than zero?");
|
||||
|
||||
// copy data into bitmap
|
||||
for (U32 row = 0; row < height; ++row)
|
||||
{
|
||||
for (U32 col = 0; col < width; ++col)
|
||||
D3D11_MAPPED_SUBRESOURCE mapped = {};
|
||||
hr = D3D11DEVICECONTEXT->Map(stagingTex.Get(), dstSubRes, D3D11_MAP_READ, 0, &mapped);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
//we can just copy data straight in with RGBA16F format
|
||||
if (fp16)
|
||||
{
|
||||
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;
|
||||
Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to map staging texture (0x%X)", hr);
|
||||
return false;
|
||||
}
|
||||
// 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();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ID3D11ShaderResourceView* GFXD3D11TextureObject::getSRView()
|
||||
void GFXD3D11TextureObject::generateMipMaps()
|
||||
{
|
||||
return mSRView;
|
||||
}
|
||||
ID3D11RenderTargetView* GFXD3D11TextureObject::getRTView()
|
||||
{
|
||||
return mRTView;
|
||||
}
|
||||
ID3D11DepthStencilView* GFXD3D11TextureObject::getDSView()
|
||||
{
|
||||
return mDSView;
|
||||
//Generate mips
|
||||
D3D11DEVICECONTEXT->GenerateMips(mSRView.Get());
|
||||
//get mip level count
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
|
||||
mSRView->GetDesc(&viewDesc);
|
||||
mMipLevels = viewDesc.TextureCube.MipLevels;
|
||||
}
|
||||
|
||||
ID3D11ShaderResourceView** GFXD3D11TextureObject::getSRViewPtr()
|
||||
void GFXD3D11TextureObject::updateTextureSlot(const GFXTexHandle& texHandle, const U32 slot, const S32 faceIdx /*=-1*/)
|
||||
{
|
||||
return &mSRView;
|
||||
}
|
||||
ID3D11RenderTargetView** GFXD3D11TextureObject::getRTViewPtr()
|
||||
{
|
||||
return &mRTView;
|
||||
AssertFatal(slot < getArraySize(), "updateTextureSlot - destination slot out of bounds");
|
||||
AssertFatal(mFormat == texHandle->getFormat(), "updateTextureSlot - format mismatch");
|
||||
AssertFatal(getMipLevels() == texHandle->getMipLevels(), "updateTextureSlot - mip level mismatch");
|
||||
|
||||
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/gfxTextureManager.h"
|
||||
|
||||
#include <wrl/client.h>
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
class GFXD3D11TextureObject : public GFXTextureObject
|
||||
{
|
||||
protected:
|
||||
static U32 mTexCount;
|
||||
|
||||
GFXTexHandle mStagingTex;
|
||||
DXGI_MAPPED_RECT mLockRect;
|
||||
D3D11_BOX mLockBox;
|
||||
bool mLocked;
|
||||
bool mLocked = false;
|
||||
|
||||
U32 mLockedSubresource;
|
||||
ID3D11Resource *mD3DTexture;
|
||||
U32 mLockedSubresource = 0;
|
||||
|
||||
// used for z buffers...
|
||||
ID3D11Texture2D *mD3DSurface;
|
||||
// Main GPU texture resource (2D / 3D / Cubemap)
|
||||
ComPtr<ID3D11Resource> mD3DTexture;
|
||||
|
||||
ID3D11ShaderResourceView* mSRView; // for shader resource input
|
||||
ID3D11RenderTargetView* mRTView; // for render targets
|
||||
ID3D11DepthStencilView* mDSView; //render target view for depth stencil
|
||||
// Used for Z-targets
|
||||
ComPtr<ID3D11Texture2D> mD3DSurface;
|
||||
|
||||
// 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:
|
||||
|
||||
GFXD3D11TextureObject( GFXDevice * d, GFXTextureProfile *profile);
|
||||
GFXD3D11TextureObject( GFXDevice * d, GFXTextureProfile *profile, const U32 arraySize = 1);
|
||||
~GFXD3D11TextureObject();
|
||||
|
||||
ID3D11Resource* getResource(){ return mD3DTexture; }
|
||||
ID3D11Texture2D* get2DTex(){ return (ID3D11Texture2D*) mD3DTexture; }
|
||||
ID3D11Texture2D** get2DTexPtr(){ return (ID3D11Texture2D**) &mD3DTexture; }
|
||||
ID3D11Texture3D* get3DTex(){ return (ID3D11Texture3D*) mD3DTexture; }
|
||||
ID3D11Texture3D** get3DTexPtr(){ return (ID3D11Texture3D**) &mD3DTexture; }
|
||||
|
||||
ID3D11ShaderResourceView* getSRView();
|
||||
ID3D11RenderTargetView* getRTView();
|
||||
ID3D11DepthStencilView* getDSView();
|
||||
// Accessors
|
||||
ID3D11Resource* getResource() const { return mD3DTexture.Get(); }
|
||||
ID3D11Texture2D* get2DTex() const;
|
||||
ID3D11Texture3D* get3DTex() const;
|
||||
ID3D11Texture2D** get2DTexPtr();
|
||||
ID3D11Texture3D** get3DTexPtr();
|
||||
|
||||
ID3D11ShaderResourceView** getSRViewPtr();
|
||||
ID3D11RenderTargetView** getRTViewPtr();
|
||||
ID3D11DepthStencilView** getDSViewPtr();
|
||||
|
||||
ID3D11ShaderResourceView* getSRView() const { return mSRView.Get(); }
|
||||
ID3D11RenderTargetView* getRTView() const { return mRTView.Get(); }
|
||||
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();
|
||||
|
||||
bool isManaged; //setting to true tells this texture not to be released from being zombify
|
||||
|
||||
GFXLockedRect * lock(U32 mipLevel = 0, RectI *inRect = NULL) override;
|
||||
void unlock(U32 mipLevel = 0 ) override;
|
||||
GFXLockedRect* lock(U32 mipLevel = 0, RectI* inRect = NULL, U32 faceIndex = 0) override;
|
||||
void unlock(U32 mipLevel = 0, U32 faceIndex = 0) override;
|
||||
|
||||
bool copyToBmp(GBitmap* bmp) override;
|
||||
ID3D11Texture2D* getSurface() {return mD3DSurface;}
|
||||
ID3D11Texture2D** getSurfacePtr() {return &mD3DSurface;}
|
||||
void generateMipMaps() override;
|
||||
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
|
||||
void zombify() override;
|
||||
|
|
|
|||
|
|
@ -72,10 +72,12 @@ public:
|
|||
void pureVirtualCrash() override {}
|
||||
#endif
|
||||
|
||||
GFXLockedRect * lock( U32 mipLevel = 0, RectI *inRect = NULL ) override { return NULL; };
|
||||
void unlock( U32 mipLevel = 0) override {};
|
||||
GFXLockedRect * lock( U32 mipLevel = 0, RectI *inRect = NULL, U32 faceIndex = 0)override { return NULL; };
|
||||
void unlock( U32 mipLevel = 0, U32 faceIndex = 0)override {};
|
||||
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 resurrect() override {}
|
||||
};
|
||||
|
|
@ -94,8 +96,8 @@ public:
|
|||
GFXTextureObject* createTexture(DDSFile* dds, GFXTextureProfile* profile, bool deleteDDS) 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, U32 depth, GFXFormat format, GFXTextureProfile* profile, U32 numMipLevels = 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, 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, U32 arraySize = 1) override { return nullptr; }
|
||||
GFXTextureObject* createCompositeTexture(GBitmap* bmp[4], U32 inputKey[4], const String& resourceName, GFXTextureProfile* profile, bool deleteBmp) override { return nullptr; }
|
||||
protected:
|
||||
GFXTextureObject *_createTextureObject( U32 height,
|
||||
|
|
@ -105,7 +107,8 @@ protected:
|
|||
GFXTextureProfile *profile,
|
||||
U32 numMipLevels,
|
||||
bool forceMips = false,
|
||||
S32 antialiasLevel = 0,
|
||||
S32 antialiasLevel = 0,
|
||||
U32 arraySize = 1,
|
||||
GFXTextureObject *inTex = NULL ) override
|
||||
{
|
||||
GFXNullTextureObject *retTex;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,11 @@
|
|||
|
||||
#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)
|
||||
{
|
||||
|
|
@ -67,7 +72,7 @@ void bitmapExtrude5551_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWi
|
|||
{
|
||||
U32 a = src[0];
|
||||
U32 c = src[stride];
|
||||
#if defined(TORQUE_OS_MAC)
|
||||
#if defined(TORQUE_BIG_ENDIAN)
|
||||
dst[y] = ((( (a >> 10) + (c >> 10)) >> 1) << 10) |
|
||||
((( ((a >> 5) & 0x1F) + ((c >> 5) & 0x1f)) >> 1) << 5) |
|
||||
((( ((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;
|
||||
U8 *dst = (U8 *) mip;
|
||||
U32 stride = srcHeight != 1 ? (srcWidth) * 3 : 0;
|
||||
U32 srcRowStride = srcHeight != 1 ? (srcWidth * bpp) / sizeof(T) : 0;
|
||||
U32 dstWidth = srcWidth > 1 ? srcWidth / 2 : 1;
|
||||
U32 dstHeight = srcHeight > 1 ? srcHeight / 2 : 1;
|
||||
U32 dstRowStride = dstHeight != 1 ? (dstWidth * bpp) / sizeof(T) : 0;
|
||||
|
||||
U32 width = srcWidth >> 1;
|
||||
U32 height = srcHeight >> 1;
|
||||
if (width == 0) width = 1;
|
||||
if (height == 0) height = 1;
|
||||
|
||||
if (srcWidth != 1)
|
||||
for (U32 y = 0; y < dstHeight; ++y)
|
||||
{
|
||||
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;
|
||||
src++;
|
||||
*dst++ = (U32(*src) + U32(src[3]) + U32(src[stride]) + U32(src[stride+3]) + 2) >> 2;
|
||||
src++;
|
||||
*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;
|
||||
U32 x0 = x * 2;
|
||||
U32 y0 = y * 2;
|
||||
U32 x1 = (x0 + 1 < srcWidth) ? x0 + 1 : x0;
|
||||
U32 y1 = (y0 + 1 < srcHeight) ? y0 + 1 : y0;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void bitmapExtrudeRGBA_c(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth)
|
||||
// 8-bit RGBA
|
||||
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;
|
||||
U8 *dst = (U8 *) mip;
|
||||
U32 stride = srcHeight != 1 ? (srcWidth) * 4 : 0;
|
||||
stbir_datatype datatype;
|
||||
stbir_pixel_layout layout;
|
||||
U32 bytesPerPixel;
|
||||
};
|
||||
|
||||
U32 width = srcWidth >> 1;
|
||||
U32 height = srcHeight >> 1;
|
||||
if (width == 0) width = 1;
|
||||
if (height == 0) height = 1;
|
||||
|
||||
if (srcWidth != 1)
|
||||
inline bool getStbResizeDesc(GFXFormat fmt, StbResizeDesc& out)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
*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
|
||||
if (fmt.bytesPerChannel == 2) // half float
|
||||
v = convertHalfToFloat(*(const U16*)(base + c * 2));
|
||||
else // full float
|
||||
v = *(const float*)(base + c * 4);
|
||||
}
|
||||
|
||||
if (fmt.srgb && fmt.semantic[c] != CH_A)
|
||||
v = srgbToLinear(v);
|
||||
|
||||
switch (fmt.semantic[c])
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
return p;
|
||||
}
|
||||
|
||||
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;
|
||||
U16 *dst = (U16 *)mip;
|
||||
U32 stride = srcHeight != 1 ? (srcWidth) * 8 : 0;
|
||||
ConversionPlan plan = decideConversion(srcFmt, dstFmt);
|
||||
if (!plan.bitDepthChange && !plan.channelRepack && !plan.colorspaceChange)
|
||||
return true; // nothing to do
|
||||
|
||||
U32 width = srcWidth >> 1;
|
||||
U32 height = srcHeight >> 1;
|
||||
if (width == 0) width = 1;
|
||||
if (height == 0) height = 1;
|
||||
void* dstBuffer = *srcBuffer;
|
||||
|
||||
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++)
|
||||
{
|
||||
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
|
||||
}
|
||||
LinearPixel p = loadPixel(*srcBuffer, srcFmt, i);
|
||||
storePixel(dstBuffer, dstFmt, i, p);
|
||||
}
|
||||
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;
|
||||
void (*bitmapExtrudeRGBA)(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth) = bitmapExtrudeRGBA_c;
|
||||
void (*bitmapExtrudeFPRGBA)(const void *srcMip, void *mip, U32 srcHeight, U32 srcWidth) = bitmapExtrudeFPRGBA_c;
|
||||
//--------------------------------------------------------------------------------
|
||||
// Entry point for GBitmap::setFormat
|
||||
bool bitmapALLConvertToOutput(U8** src, U32 pixels, GFXFormat srcFormat, GFXFormat dstFormat)
|
||||
{
|
||||
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 b = src[2] >> 3;
|
||||
|
||||
#if defined(TORQUE_OS_MAC)
|
||||
#if defined(TORQUE_BIG_ENDIAN)
|
||||
*dst++ = 0x8000 | (b << 10) | (g << 5) | (r << 0);
|
||||
#else
|
||||
*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 b = src[2] >> 3;
|
||||
|
||||
#if defined(TORQUE_OS_MAC)
|
||||
#if defined(TORQUE_BIG_ENDIAN)
|
||||
*dst++ = (1 << 15) | (b << 10) | (g << 5) | (r << 0);
|
||||
#else
|
||||
*dst++ = (b << 1) | (g << 6) | (r << 11) | 1;
|
||||
|
|
|
|||
|
|
@ -22,21 +22,148 @@
|
|||
|
||||
#ifndef _BITMAPUTILS_H_
|
||||
#define _BITMAPUTILS_H_
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
#ifndef _TORQUE_TYPES_H_
|
||||
#include "platform/types.h"
|
||||
#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 (*bitmapExtrudeRGB)(const void *srcMip, void *mip, U32 height, U32 width);
|
||||
extern void (*bitmapExtrudeRGBA)(const void *srcMip, void *mip, U32 height, U32 width);
|
||||
extern void(*bitmapExtrudeFPRGBA)(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, U32 bpp);
|
||||
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_1555)(U8 *src, U32 pixels);
|
||||
extern void (*bitmapConvertRGB_to_RGBX)( U8 **src, U32 pixels );
|
||||
extern void (*bitmapConvertRGBX_to_RGB)( 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_
|
||||
|
|
|
|||
|
|
@ -34,9 +34,7 @@
|
|||
|
||||
namespace CubemapSaver
|
||||
{
|
||||
const U32 CubeFaces = 6;
|
||||
|
||||
bool save(GFXCubemapHandle cubemap, const Torque::Path &path, GFXFormat compressionFormat)
|
||||
bool save(GFXTexHandle cubemap, const Torque::Path &path, GFXFormat compressionFormat)
|
||||
{
|
||||
if (!cubemap.isValid())
|
||||
{
|
||||
|
|
@ -44,43 +42,24 @@ namespace CubemapSaver
|
|||
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;
|
||||
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;
|
||||
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);
|
||||
bool result = pTextures[i].copyToBmp(pBitmaps[i]);
|
||||
if (!result)
|
||||
{
|
||||
Con::errorf("CubemapSaver: cubemap number %u failed to copy", i);
|
||||
error = true;
|
||||
}
|
||||
Con::errorf("CubemapSaver: cubemap failed to copy");
|
||||
error = true;
|
||||
}
|
||||
|
||||
if (!error)
|
||||
{
|
||||
DDSFile *pDds = DDSFile::createDDSCubemapFileFromGBitmaps(pBitmaps);
|
||||
DDSFile *pDds = DDSFile::createDDSFileFromGBitmap(temp);
|
||||
if (pDds)
|
||||
{
|
||||
// compressed and floating point don't need swizzling
|
||||
|
|
@ -103,14 +82,12 @@ namespace CubemapSaver
|
|||
}
|
||||
|
||||
//cleanup
|
||||
for (U32 i = 0; i < CubeFaces; i++)
|
||||
SAFE_DELETE(pBitmaps[i]);
|
||||
|
||||
SAFE_DELETE(temp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getBitmaps(GFXCubemapHandle cubemap, GFXFormat compressionFormat, GBitmap* faceBitmaps[6])
|
||||
bool getBitmaps(GFXTexHandle cubemap, GFXFormat compressionFormat, GBitmap* faceBitmaps[6])
|
||||
{
|
||||
if (!cubemap.isValid())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@
|
|||
namespace CubemapSaver
|
||||
{
|
||||
// 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 )
|
||||
{
|
||||
if( gbmp == NULL )
|
||||
|
|
@ -666,6 +672,11 @@ DDSFile *DDSFile::createDDSFileFromGBitmap( const GBitmap *gbmp )
|
|||
ret->mDepth = 0;
|
||||
ret->mFormat = gbmp->getFormat();
|
||||
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->mMipMapCount = gbmp->getNumMipLevels();
|
||||
ret->mHasTransparency = gbmp->getHasTransparency();
|
||||
|
|
@ -685,36 +696,39 @@ DDSFile *DDSFile::createDDSFileFromGBitmap( const GBitmap *gbmp )
|
|||
if( ret->mMipMapCount > 1 )
|
||||
ret->mFlags.set(MipMapsFlag);
|
||||
|
||||
// One surface per GBitmap
|
||||
ret->mSurfaces.push_back( new SurfaceData() );
|
||||
|
||||
// Load the mips
|
||||
for( S32 i = 0; i < ret->mMipMapCount; i++ )
|
||||
for (U32 face = 0; face < gbmp->getNumFaces(); face++)
|
||||
{
|
||||
const U32 mipSz = ret->getSurfaceSize(i);
|
||||
ret->mSurfaces.last()->mMips.push_back( new U8[mipSz] );
|
||||
// One surface per GBitmap
|
||||
ret->mSurfaces.push_back(new SurfaceData());
|
||||
|
||||
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), mipSz );
|
||||
else
|
||||
// Load the mips
|
||||
for (S32 i = 0; i < ret->mMipMapCount; i++)
|
||||
{
|
||||
// Assumption:
|
||||
AssertFatal( gbmp->getBytesPerPixel() + 1 == ret->mBytesPerPixel, "Assumption failed, not 24->32 bit straight convert." );
|
||||
const U32 mipSz = ret->getSurfaceSize(i);
|
||||
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];
|
||||
const U8 *src = &gbmp->getBits(i)[pxl * gbmp->getBytesPerPixel()];
|
||||
dMemcpy( dst, src, gbmp->getBytesPerPixel() * sizeof(U8) );
|
||||
dst[ret->mBytesPerPixel - 1] = 255;
|
||||
}
|
||||
}
|
||||
// Assumption:
|
||||
AssertFatal(gbmp->getBytesPerPixel() + 1 == ret->mBytesPerPixel, "Assumption failed, not 24->32 bit straight convert.");
|
||||
|
||||
// Uncomment to debug-dump each mip level
|
||||
//ret->mSurfaces.last()->dumpImage( ret, i, avar( "%d_Gbmp_xmip%d", ret, i ) );
|
||||
for (S32 pxl = 0; pxl < gbmp->getWidth(i) * gbmp->getHeight(i); pxl++)
|
||||
{
|
||||
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;
|
||||
|
|
@ -777,22 +791,50 @@ DDSFile *DDSFile::createDDSCubemapFileFromGBitmaps(GBitmap **gbmps)
|
|||
|
||||
bool DDSFile::decompressToGBitmap(GBitmap *dest)
|
||||
{
|
||||
const bool isCube = isCubemap();
|
||||
const U32 numFaces = isCube ? 6 : 1;
|
||||
// TBD: do we support other formats?
|
||||
if (mFormat != GFXFormatBC1 && mFormat != GFXFormatBC2 && mFormat != GFXFormatBC3)
|
||||
return false;
|
||||
if (!isCompressedFormat(mFormat))
|
||||
{
|
||||
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...
|
||||
|
||||
U32 numMips = getMipLevels();
|
||||
|
||||
for (U32 i = 0; i < numMips; i++)
|
||||
for (U32 face = 0; face < numFaces; face++)
|
||||
{
|
||||
U8 *addr = dest->getAddress(0, 0, i);
|
||||
const U8 *mipBuffer = mSurfaces[0]->mMips[i];
|
||||
ImageUtil::decompress(mipBuffer, addr, getWidth(i), getHeight(i), mFormat);
|
||||
for (U32 i = 0; i < numMips; i++)
|
||||
{
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -205,6 +205,8 @@ struct DDSFile
|
|||
mSurfaces.clear();
|
||||
}
|
||||
|
||||
bool isCompressedFormat(GFXFormat fmt);
|
||||
|
||||
static DDSFile *createDDSFileFromGBitmap( const GBitmap *gbmp );
|
||||
//Create a single cubemap texture from 6 GBitmap
|
||||
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,
|
||||
const U32 in_height,
|
||||
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
|
||||
// data (assumes that there is width * height * 4 U8's in data)
|
||||
GBitmap(const U32 in_width,
|
||||
const U32 in_height,
|
||||
const U8* data );
|
||||
const U8* data,
|
||||
const U32 in_numFaces = 1);
|
||||
|
||||
virtual ~GBitmap();
|
||||
|
||||
|
|
@ -163,12 +165,14 @@ public:
|
|||
void allocateBitmap(const U32 in_width,
|
||||
const U32 in_height,
|
||||
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,
|
||||
const U32 in_height,
|
||||
const U32 in_numMips,
|
||||
const GFXFormat in_format = GFXFormatR8G8B8);
|
||||
const U32 in_height,
|
||||
const U32 in_numMips,
|
||||
const GFXFormat in_format = GFXFormatR8G8B8,
|
||||
const U32 in_numFaces = 1);
|
||||
|
||||
void extrudeMipLevels(bool clearBorders = false);
|
||||
void chopTopMips(U32 mipsToChop);
|
||||
|
|
@ -191,16 +195,18 @@ public:
|
|||
|
||||
U32 getWidth(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;
|
||||
|
||||
U8* getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel = 0);
|
||||
const U8* getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel = 0) const;
|
||||
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 U32 face = 0) const;
|
||||
|
||||
const U8* getBits(const U32 in_mipLevel = 0) const;
|
||||
U8* getWritableBits(const U32 in_mipLevel = 0);
|
||||
const U8* getBits(const U32 in_mipLevel = 0, const U32 face = 0) const;
|
||||
U8* getWritableBits(const U32 in_mipLevel = 0, const U32 face = 0);
|
||||
|
||||
U32 getByteSize() const { return mByteSize; }
|
||||
U32 getBytesPerPixel() const { return mBytesPerPixel; }
|
||||
U32 getFormatBytesPerPixel(GFXFormat fmt);
|
||||
|
||||
U32 getSurfaceSize(const U32 mipLevel) const;
|
||||
|
||||
|
|
@ -220,6 +226,7 @@ public:
|
|||
bool getColor(const U32 x, const U32 y, ColorI& rColor) const;
|
||||
bool setColor(const U32 x, const U32 y, const ColorI& rColor);
|
||||
U8 getChanelValueAt(U32 x, U32 y, U32 chan);
|
||||
U32 getNumFaces() const { return mNumFaces; }
|
||||
|
||||
/// 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
|
||||
|
|
@ -275,7 +282,7 @@ public:
|
|||
|
||||
private:
|
||||
GFXFormat mInternalFormat;
|
||||
|
||||
U32 mNumFaces; // default 1, set to 6 for cubemap
|
||||
U8* mBits; // Master bytes
|
||||
U32 mByteSize;
|
||||
U32 mWidth;
|
||||
|
|
@ -284,6 +291,7 @@ private:
|
|||
|
||||
U32 mNumMipLevels;
|
||||
U32 mMipLevelOffsets[c_maxMipLevels];
|
||||
U32 mFaceOffsets[6]; // Maximum 6 for cubemaps; could also dynamically allocate if needed
|
||||
|
||||
bool mHasTransparency;
|
||||
|
||||
|
|
@ -316,32 +324,39 @@ inline U32 GBitmap::getHeight(const U32 in_mipLevel) const
|
|||
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,
|
||||
avar("GBitmap::getBits: mip level out of range: (%d, %d)",
|
||||
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,
|
||||
avar("GBitmap::getWritableBits: mip level out of range: (%d, %d)",
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "core/stream/memStream.h"
|
||||
#include "core/strings/stringFunctions.h"
|
||||
#include "gfx/bitmap/gBitmap.h"
|
||||
#include "gfx/bitmap/bitmapUtils.h"
|
||||
#include "gfx/bitmap/imageUtils.h"
|
||||
#include "gfx/bitmap/loaders/ies/ies_loader.h"
|
||||
#include "platform/profiler.h"
|
||||
|
|
@ -41,12 +42,12 @@
|
|||
#ifndef STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_STATIC
|
||||
#include "stb_image.h"
|
||||
#include "gfx/bitmap/loaders/stb/stb_image.h"
|
||||
#endif
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_STATIC
|
||||
#include "stb_image_write.h"
|
||||
#include "gfx/bitmap/loaders/stb/stb_image_write.h"
|
||||
|
||||
#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 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.
|
||||
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* stbErr = stbi_failure_reason();
|
||||
const char* filePath = path.getFullPath().c_str();
|
||||
|
||||
if (!stbErr)
|
||||
stbErr = "Unknown Error!";
|
||||
// Detect format
|
||||
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 (channels == 2)
|
||||
channels = 4;
|
||||
if (!ext.equal("png"))
|
||||
if (!data)
|
||||
{
|
||||
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();
|
||||
Con::errorf("sReadSTB() - Failed to load %s: %s", filePath, stbi_failure_reason());
|
||||
return false;
|
||||
}
|
||||
|
||||
// actually allocate the bitmap space...
|
||||
bitmap->allocateBitmap(x, y,
|
||||
false, // don't extrude miplevels...
|
||||
format); // use determined format...
|
||||
// Determine internal GFX format
|
||||
GFXFormat format = determineFormat(isHDR, is16Bit, n);
|
||||
|
||||
U8* pBase = (U8*)bitmap->getBits();
|
||||
// Allocate bitmap
|
||||
bitmap->deleteImage();
|
||||
bitmap->allocateBitmap(x, y, false, format);
|
||||
|
||||
U32 rowBytes = bitmap->getByteSize();
|
||||
|
||||
dMemcpy(pBase, data, rowBytes);
|
||||
//if (isHDR)
|
||||
//{
|
||||
// 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);
|
||||
// Check this bitmap for transparency
|
||||
if (channels == 4)
|
||||
bitmap->checkForTransparency();
|
||||
|
||||
bitmap->checkForTransparency();
|
||||
|
||||
PROFILE_END();
|
||||
return true;
|
||||
|
|
@ -331,45 +300,36 @@ bool sReadSTB(const Torque::Path& path, GBitmap* bitmap)
|
|||
bool sReadStreamSTB(Stream& stream, GBitmap* bitmap, U32 len)
|
||||
{
|
||||
PROFILE_SCOPE(sReadStreamSTB);
|
||||
// only used for font at the moment.
|
||||
|
||||
U8* data = new U8[len];
|
||||
stream.read(len, data);
|
||||
Vector<U8> data(len);
|
||||
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();
|
||||
|
||||
if (!stbErr)
|
||||
stbErr = "Unknown Error!";
|
||||
|
||||
Con::errorf("sReadStreamSTB Error: %s", stbErr);
|
||||
Con::errorf("sReadStreamSTB() - STB load failed: %s", stbi_failure_reason());
|
||||
return false;
|
||||
}
|
||||
|
||||
GFXFormat format = determineFormat(isHDR, is16Bit, n);
|
||||
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?
|
||||
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;
|
||||
}
|
||||
stbi_image_free(pixels);
|
||||
|
||||
bitmap->allocateBitmap(width, height, false, fmt);
|
||||
|
||||
U8* pBase = bitmap->getWritableBits(0);
|
||||
U32 rowBytes = bitmap->getByteSize();
|
||||
dMemcpy(pBase, pixelData, rowBytes);
|
||||
|
||||
dFree(data);
|
||||
dFree(pixelData);
|
||||
bitmap->checkForTransparency();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -401,47 +361,34 @@ bool sWriteSTB(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel)
|
|||
GFXFormat format = bitmap->getFormat();
|
||||
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"))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
Do this:
|
||||
|
|
@ -48,6 +48,8 @@ LICENSE
|
|||
|
||||
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.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug 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;
|
||||
}
|
||||
|
||||
// returns 1 if the product of two signed shorts is valid, 0 on overflow.
|
||||
static int stbi__mul2shorts_valid(short a, short b)
|
||||
// returns 1 if the product of two ints fits in a signed short, 0 on overflow.
|
||||
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 ((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;
|
||||
}
|
||||
|
||||
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
|
||||
// like a valid marker, resume there
|
||||
while (!stbi__at_eof(j->s)) {
|
||||
int x = stbi__get8(j->s);
|
||||
while (x == 255) { // might be a marker
|
||||
stbi_uc x = stbi__get8(j->s);
|
||||
while (x == 0xff) { // might be a marker
|
||||
if (stbi__at_eof(j->s)) return STBI__MARKER_none;
|
||||
x = stbi__get8(j->s);
|
||||
if (x != 0x00 && x != 0xff) {
|
||||
|
|
@ -4176,6 +4178,7 @@ typedef struct
|
|||
{
|
||||
stbi_uc *zbuffer, *zbuffer_end;
|
||||
int num_bits;
|
||||
int hit_zeof_once;
|
||||
stbi__uint32 code_buffer;
|
||||
|
||||
char *zout;
|
||||
|
|
@ -4242,9 +4245,20 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
|
|||
int b,s;
|
||||
if (a->num_bits < 16) {
|
||||
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];
|
||||
if (b) {
|
||||
|
|
@ -4309,6 +4323,13 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
|
|||
int len,dist;
|
||||
if (z == 256) {
|
||||
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;
|
||||
}
|
||||
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];
|
||||
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 + len > a->zout_end) {
|
||||
if (len > a->zout_end - zout) {
|
||||
if (!stbi__zexpand(a, zout, len)) return 0;
|
||||
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;
|
||||
a->num_bits = 0;
|
||||
a->code_buffer = 0;
|
||||
a->hit_zeof_once = 0;
|
||||
do {
|
||||
final = stbi__zreceive(a,1);
|
||||
type = stbi__zreceive(a,2);
|
||||
|
|
@ -4619,9 +4641,8 @@ enum {
|
|||
STBI__F_up=2,
|
||||
STBI__F_avg=3,
|
||||
STBI__F_paeth=4,
|
||||
// synthetic filters used for first scanline to avoid needing a dummy row of 0s
|
||||
STBI__F_avg_first,
|
||||
STBI__F_paeth_first
|
||||
// synthetic filter used for first scanline to avoid needing a dummy row of 0s
|
||||
STBI__F_avg_first
|
||||
};
|
||||
|
||||
static stbi_uc first_row_filter[5] =
|
||||
|
|
@ -4630,29 +4651,56 @@ static stbi_uc first_row_filter[5] =
|
|||
STBI__F_sub,
|
||||
STBI__F_none,
|
||||
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)
|
||||
{
|
||||
int p = a + b - c;
|
||||
int pa = abs(p-a);
|
||||
int pb = abs(p-b);
|
||||
int pc = abs(p-c);
|
||||
if (pa <= pb && pa <= pc) return a;
|
||||
if (pb <= pc) return b;
|
||||
return c;
|
||||
// This formulation looks very different from the reference in the PNG spec, but is
|
||||
// actually equivalent and has favorable data dependencies and admits straightforward
|
||||
// generation of branch-free code, which helps performance significantly.
|
||||
int thresh = c*3 - (a + b);
|
||||
int lo = a < b ? a : b;
|
||||
int hi = a < b ? b : a;
|
||||
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 };
|
||||
|
||||
// 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
|
||||
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__uint32 i,j,stride = x*out_n*bytes;
|
||||
stbi__uint32 img_len, img_width_bytes;
|
||||
stbi_uc *filter_buf;
|
||||
int all_ok = 1;
|
||||
int k;
|
||||
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
|
||||
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");
|
||||
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;
|
||||
|
||||
// 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.
|
||||
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) {
|
||||
stbi_uc *cur = a->out + stride*j;
|
||||
stbi_uc *prior;
|
||||
// cur/prior filter buffers alternate
|
||||
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++;
|
||||
|
||||
if (filter > 4)
|
||||
return stbi__err("invalid filter","Corrupt PNG");
|
||||
|
||||
if (depth < 8) {
|
||||
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;
|
||||
// check filter type
|
||||
if (filter > 4) {
|
||||
all_ok = stbi__err("invalid filter","Corrupt PNG");
|
||||
break;
|
||||
}
|
||||
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 (j == 0) filter = first_row_filter[filter];
|
||||
|
||||
// handle first byte explicitly
|
||||
for (k=0; k < filter_bytes; ++k) {
|
||||
switch (filter) {
|
||||
case STBI__F_none : cur[k] = raw[k]; break;
|
||||
case STBI__F_sub : cur[k] = raw[k]; break;
|
||||
case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
|
||||
case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
|
||||
case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
|
||||
case STBI__F_avg_first : cur[k] = raw[k]; break;
|
||||
case STBI__F_paeth_first: cur[k] = raw[k]; break;
|
||||
}
|
||||
// perform actual filtering
|
||||
switch (filter) {
|
||||
case STBI__F_none:
|
||||
memcpy(cur, raw, nk);
|
||||
break;
|
||||
case STBI__F_sub:
|
||||
memcpy(cur, raw, filter_bytes);
|
||||
for (k = filter_bytes; k < nk; ++k)
|
||||
cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]);
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
raw += nk;
|
||||
|
||||
// this is a little gross, so that we don't switch per-pixel or per-component
|
||||
if (depth < 8 || img_n == out_n) {
|
||||
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
|
||||
// expand decoded bits in cur to dest, also adding an extra alpha channel if desired
|
||||
if (depth < 8) {
|
||||
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.
|
||||
// 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
|
||||
|
||||
// expand bits to bytes first
|
||||
if (depth == 4) {
|
||||
for (k=x*img_n; k >= 2; k-=2, ++in) {
|
||||
*cur++ = scale * ((*in >> 4) );
|
||||
*cur++ = scale * ((*in ) & 0x0f);
|
||||
for (i=0; i < nsmp; ++i) {
|
||||
if ((i & 1) == 0) inb = *in++;
|
||||
*out++ = scale * (inb >> 4);
|
||||
inb <<= 4;
|
||||
}
|
||||
if (k > 0) *cur++ = scale * ((*in >> 4) );
|
||||
} else if (depth == 2) {
|
||||
for (k=x*img_n; k >= 4; k-=4, ++in) {
|
||||
*cur++ = scale * ((*in >> 6) );
|
||||
*cur++ = scale * ((*in >> 4) & 0x03);
|
||||
*cur++ = scale * ((*in >> 2) & 0x03);
|
||||
*cur++ = scale * ((*in ) & 0x03);
|
||||
for (i=0; i < nsmp; ++i) {
|
||||
if ((i & 3) == 0) inb = *in++;
|
||||
*out++ = scale * (inb >> 6);
|
||||
inb <<= 2;
|
||||
}
|
||||
if (k > 0) *cur++ = scale * ((*in >> 6) );
|
||||
if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
|
||||
if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
|
||||
} else if (depth == 1) {
|
||||
for (k=x*img_n; k >= 8; k-=8, ++in) {
|
||||
*cur++ = scale * ((*in >> 7) );
|
||||
*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);
|
||||
} else {
|
||||
STBI_ASSERT(depth == 1);
|
||||
for (i=0; i < nsmp; ++i) {
|
||||
if ((i & 7) == 0) inb = *in++;
|
||||
*out++ = scale * (inb >> 7);
|
||||
inb <<= 1;
|
||||
}
|
||||
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
|
||||
cur = a->out + stride*j;
|
||||
|
||||
// insert alpha=255 values if desired
|
||||
if (img_n != out_n)
|
||||
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) {
|
||||
for (q=x-1; q >= 0; --q) {
|
||||
cur[q*2+1] = 255;
|
||||
cur[q*2+0] = cur[q];
|
||||
for (i = 0; i < x; ++i, dest16 += 2, cur += 2) {
|
||||
dest16[0] = (cur[0] << 8) | cur[1];
|
||||
dest16[1] = 0xffff;
|
||||
}
|
||||
} else {
|
||||
STBI_ASSERT(img_n == 3);
|
||||
for (q=x-1; q >= 0; --q) {
|
||||
cur[q*4+3] = 255;
|
||||
cur[q*4+2] = cur[q*3+2];
|
||||
cur[q*4+1] = cur[q*3+1];
|
||||
cur[q*4+0] = cur[q*3+0];
|
||||
for (i = 0; i < x; ++i, dest16 += 4, cur += 6) {
|
||||
dest16[0] = (cur[0] << 8) | cur[1];
|
||||
dest16[1] = (cur[2] << 8) | cur[3];
|
||||
dest16[2] = (cur[4] << 8) | cur[5];
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -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.
|
||||
if (scan == STBI__SCAN_header) { ++s->img_n; return 1; }
|
||||
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 {
|
||||
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;
|
||||
|
|
@ -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
|
||||
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" }
|
||||
|
||||
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( GFXStencilOp );
|
||||
DefineEnumType( GFXBlendOp );
|
||||
DefineEnumType(GFXShaderConstType);
|
||||
DefineEnumType( GFXAdapterType );
|
||||
|
||||
DECLARE_STRUCT( GFXVideoMode );
|
||||
|
|
@ -57,5 +58,6 @@ DefineConsoleType( TypeGFXTextureFilterType, GFXTextureFilterType );
|
|||
DefineConsoleType( TypeGFXCullMode, GFXCullMode );
|
||||
DefineConsoleType( TypeGFXStencilOp, GFXStencilOp );
|
||||
DefineConsoleType( TypeGFXBlendOp, GFXBlendOp );
|
||||
DefineConsoleType( TypeGFXShaderConstType, GFXShaderConstType);
|
||||
|
||||
#endif // !_GFXAPI_H_
|
||||
|
|
|
|||
|
|
@ -42,8 +42,12 @@ GFXShader::GFXShader()
|
|||
|
||||
GFXShader::~GFXShader()
|
||||
{
|
||||
Torque::FS::RemoveChangeNotification( mVertexFile, this, &GFXShader::_onFileChanged );
|
||||
Torque::FS::RemoveChangeNotification( mPixelFile, this, &GFXShader::_onFileChanged );
|
||||
if (!mVertexFile.isEmpty())
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,9 @@ enum GFXShaderStage
|
|||
GEOMETRY_SHADER = BIT(2),
|
||||
DOMAIN_SHADER = BIT(3),
|
||||
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
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ public:
|
|||
/// @param mipLevel What level of this texture are we rendering to?
|
||||
/// @param zOffset If this is a depth texture, what z level are we
|
||||
/// 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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -137,19 +137,19 @@ bool GFXTexHandle::set( DDSFile *dds, GFXTextureProfile *profile, bool deleteDDS
|
|||
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
|
||||
// its memory is free for the new allocation.
|
||||
free();
|
||||
|
||||
// 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
|
||||
if ( getPointer() )
|
||||
|
|
@ -159,14 +159,14 @@ bool GFXTexHandle::set( U32 width, U32 height, GFXFormat format, GFXTextureProfi
|
|||
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
|
||||
// its memory is free for the new allocation.
|
||||
free();
|
||||
|
||||
// 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
|
||||
if ( getPointer() )
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ public:
|
|||
bool set( DDSFile *bmp, GFXTextureProfile *profile, bool deleteDDS, const String &desc );
|
||||
|
||||
// Sized bitmap
|
||||
GFXTexHandle( 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);
|
||||
bool set( U32 width, U32 height, U32 depth, GFXFormat format, GFXTextureProfile* profile, const String& desc, U32 numMipLevels = 1);
|
||||
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, U32 arraySize = 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.
|
||||
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 getHeight() const { return getPointer() ? getPointer()->getHeight() : 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; }
|
||||
|
||||
/// Reloads the texture.
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ GFXTextureObject *GFXTextureManager::_createTexture( GBitmap *bmp,
|
|||
if ( inObj->getWidth() != realWidth ||
|
||||
inObj->getHeight() != realHeight ||
|
||||
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
|
||||
ret = inObj;
|
||||
}
|
||||
|
|
@ -569,7 +569,7 @@ GFXTextureObject *GFXTextureManager::_createTexture( DDSFile *dds,
|
|||
inObj->getMipLevels() != numMips )
|
||||
ret = _createTextureObject( dds->getHeight(), dds->getWidth(), 0,
|
||||
fmt, profile, numMips,
|
||||
true, 0, inObj );
|
||||
true, 0, 1, inObj );
|
||||
else
|
||||
ret = inObj;
|
||||
}
|
||||
|
|
@ -744,7 +744,7 @@ GFXTextureObject *GFXTextureManager::createTexture( U32 width, U32 height, void
|
|||
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...
|
||||
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.
|
||||
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.
|
||||
if ( outTex && profile->isPooled() )
|
||||
|
|
@ -814,12 +814,13 @@ GFXTextureObject *GFXTextureManager::createTexture( U32 width,
|
|||
U32 depth,
|
||||
GFXFormat format,
|
||||
GFXTextureProfile *profile,
|
||||
U32 numMipLevels)
|
||||
U32 numMipLevels,
|
||||
U32 arraySize)
|
||||
{
|
||||
PROFILE_SCOPE( GFXTextureManager_CreateTexture_3D );
|
||||
|
||||
// Create texture...
|
||||
GFXTextureObject *ret = _createTextureObject( height, width, depth, format, profile, numMipLevels );
|
||||
GFXTextureObject *ret = _createTextureObject( height, width, depth, format, profile, numMipLevels, arraySize );
|
||||
|
||||
if(!ret)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -120,14 +120,16 @@ public:
|
|||
U32 depth,
|
||||
GFXFormat format,
|
||||
GFXTextureProfile *profile,
|
||||
U32 numMipLevels = 1);
|
||||
U32 numMipLevels = 1,
|
||||
U32 arraySize = 1);
|
||||
|
||||
virtual GFXTextureObject *createTexture( U32 width,
|
||||
U32 height,
|
||||
GFXFormat format,
|
||||
GFXTextureProfile *profile,
|
||||
U32 numMipLevels,
|
||||
S32 antialiasLevel);
|
||||
S32 antialiasLevel,
|
||||
U32 arraySize = 1);
|
||||
|
||||
Torque::Path validatePath(const Torque::Path &path);
|
||||
GBitmap *loadUncompressedTexture(const Torque::Path& path, GFXTextureProfile* profile, U32 width, U32 height, bool genMips = false);
|
||||
|
|
@ -319,7 +321,8 @@ protected:
|
|||
GFXTextureProfile *profile,
|
||||
U32 numMipLevels,
|
||||
bool forceMips = false,
|
||||
S32 antialiasLevel = 0,
|
||||
S32 antialiasLevel = 0,
|
||||
U32 arraySize = 1,
|
||||
GFXTextureObject *inTex = NULL ) = 0;
|
||||
|
||||
/// Load a texture from a proper DDSFile instance.
|
||||
|
|
|
|||
|
|
@ -99,6 +99,8 @@ GFXTextureObject::GFXTextureObject(GFXDevice *aDevice, GFXTextureProfile *aProfi
|
|||
|
||||
mHasTransparency = false;
|
||||
|
||||
mArraySize = 1;
|
||||
|
||||
#if defined(TORQUE_DEBUG)
|
||||
// Active object tracking.
|
||||
smActiveTOCount++;
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ class GFXTextureProfile;
|
|||
class GBitmap;
|
||||
struct DDSFile;
|
||||
class RectI;
|
||||
class GFXTexHandle;
|
||||
|
||||
/// Contains information on a locked region of a texture.
|
||||
///
|
||||
|
|
@ -92,6 +93,8 @@ public:
|
|||
|
||||
bool mDead;
|
||||
|
||||
U32 mArraySize;
|
||||
|
||||
/// The device this texture belongs to.
|
||||
GFXDevice *mDevice;
|
||||
|
||||
|
|
@ -150,10 +153,13 @@ public:
|
|||
U32 getBitmapHeight() const { return mBitmapSize.y; }
|
||||
U32 getBitmapDepth() const { return mBitmapSize.z; }
|
||||
GFXFormat getFormat() const { return mFormat; }
|
||||
U32 getArraySize() const { return mArraySize; }
|
||||
|
||||
/// Returns true if this texture is a render target.
|
||||
bool isRenderTarget() const { return mProfile->isRenderTarget(); }
|
||||
|
||||
bool isCubeMap() const { return mProfile->isCubeMap(); }
|
||||
|
||||
/// Returns the file path to the texture if
|
||||
/// it was loaded from disk.
|
||||
const String& getPath() const { return mPath; }
|
||||
|
|
@ -167,11 +173,11 @@ public:
|
|||
|
||||
/// Acquire a lock on part of the texture. The GFXLockedRect returned
|
||||
/// 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
|
||||
/// 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.
|
||||
// - 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.
|
||||
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
|
||||
|
||||
// It is important for any derived objects to define this method
|
||||
|
|
|
|||
|
|
@ -83,6 +83,21 @@ GFX_ImplementTextureProfile(GFXDynamicTextureSRGBProfile,
|
|||
GFXTextureProfile::DiffuseMap,
|
||||
GFXTextureProfile::Dynamic | GFXTextureProfile::SRGB,
|
||||
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?)
|
||||
ZTarget = BIT(8), ///< This texture will be used as a Z target.
|
||||
SRGB = BIT(9), ///< sRGB texture
|
||||
|
||||
CubeMap = BIT(10), ///< Cubemap texture
|
||||
/// Track and pool textures of this type for reuse.
|
||||
///
|
||||
/// You should use this profile flag sparingly. Odd
|
||||
|
|
@ -96,16 +96,15 @@ public:
|
|||
/// the pool to contain unused textures which will remain
|
||||
/// in memory until a flush occurs.
|
||||
///
|
||||
Pooled = BIT(10),
|
||||
Pooled = BIT(11),
|
||||
|
||||
/// A hint that the device is not allowed to discard the content
|
||||
/// of a target texture after presentation or deactivated.
|
||||
///
|
||||
/// This is mainly a depth buffer optimization.
|
||||
NoDiscard = BIT(11),
|
||||
NoDiscard = BIT(12),
|
||||
|
||||
|
||||
NoModify = BIT(11)
|
||||
NoModify = BIT(12)
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -173,6 +172,7 @@ public:
|
|||
inline bool isPooled() const { return testFlag(Pooled); }
|
||||
inline bool canDiscard() const { return !testFlag(NoDiscard); }
|
||||
inline bool isSRGB() const { return testFlag(SRGB); }
|
||||
inline bool isCubeMap() const { return testFlag(CubeMap); }
|
||||
//compare profile flags for equality
|
||||
inline bool compareFlags(const GFXTextureProfile& in_Cmp) const{ return (mProfile == in_Cmp.mProfile); }
|
||||
private:
|
||||
|
|
@ -209,7 +209,7 @@ private:
|
|||
#define GFX_DeclareTextureProfile(name) extern GFXTextureProfile name
|
||||
#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.
|
||||
GFX_DeclareTextureProfile(GFXRenderTargetProfile);
|
||||
GFX_DeclareTextureProfile(GFXRenderTargetSRGBProfile);
|
||||
|
|
@ -231,4 +231,14 @@ GFX_DeclareTextureProfile(GFXZTargetProfile);
|
|||
GFX_DeclareTextureProfile(GFXDynamicTextureProfile);
|
||||
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
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ GFXTextureObject *GFXGLTextureManager::_createTextureObject( U32 height,
|
|||
U32 numMipLevels,
|
||||
bool forceMips,
|
||||
S32 antialiasLevel,
|
||||
U32 arraySize,
|
||||
GFXTextureObject *inTex )
|
||||
{
|
||||
AssertFatal(format >= 0 && format < GFXFormat_COUNT, "GFXGLTextureManager::_createTexture - invalid format!");
|
||||
|
|
@ -73,7 +74,7 @@ GFXTextureObject *GFXGLTextureManager::_createTextureObject( U32 height,
|
|||
retTex->registerResourceWithDevice( GFX );
|
||||
}
|
||||
|
||||
innerCreateTexture(retTex, height, width, depth, format, profile, numMipLevels, forceMips);
|
||||
innerCreateTexture(retTex, height, width, depth, format, profile, numMipLevels, forceMips, arraySize);
|
||||
|
||||
return retTex;
|
||||
}
|
||||
|
|
@ -89,19 +90,40 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
|
|||
GFXFormat format,
|
||||
GFXTextureProfile *profile,
|
||||
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.
|
||||
if (format == GFXFormatR8G8B8)
|
||||
format = GFXFormatR8G8B8A8;
|
||||
else if (format == GFXFormatR8G8B8_SRGB)
|
||||
format = GFXFormatR8G8B8A8_SRGB;
|
||||
|
||||
|
||||
retTex->mProfile = profile;
|
||||
retTex->mFormat = format;
|
||||
retTex->mIsZombie = 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)
|
||||
retTex->mIsNPoT2 = true;
|
||||
retTex->mBinding = binding;
|
||||
|
|
@ -155,55 +177,155 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
|
|||
retTex->mMipLevels = getMaxMipmaps(width, height, 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)
|
||||
glTexStorage2D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height );
|
||||
else if(binding == GL_TEXTURE_1D)
|
||||
glTexStorage1D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], getMax(width, height) );
|
||||
else
|
||||
glTexStorage3D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height, depth );
|
||||
// Single cubemap: prefer glTexStorage2D if available, else per-face texImage2D
|
||||
if (hasTexStorage)
|
||||
{
|
||||
// Some drivers accept texStorage2D with GL_TEXTURE_CUBE_MAP
|
||||
glTexStorage2D(GL_TEXTURE_CUBE_MAP, retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height);
|
||||
}
|
||||
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
|
||||
//mipmap pyramid and instead just use glGenerateMipmap
|
||||
if(ImageUtil::isCompressedFormat(format))
|
||||
{
|
||||
AssertFatal(binding == GL_TEXTURE_2D,
|
||||
"GFXGLTextureManager::innerCreateTexture - Only compressed 2D textures are supported");
|
||||
|
||||
U32 tempWidth = width;
|
||||
U32 tempHeight = height;
|
||||
U32 size = getCompressedSurfaceSize(format,height,width);
|
||||
//Fill compressed images with 0's
|
||||
U8 *pTemp = (U8*)dMalloc(sizeof(U8)*size);
|
||||
dMemset(pTemp,0,size);
|
||||
|
||||
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);
|
||||
}
|
||||
// cube-map array: layers = arraySize * 6
|
||||
U32 layers = getMax(1u, arraySize) * 6u;
|
||||
if (hasTexStorage)
|
||||
{
|
||||
glTexStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height, layers);
|
||||
}
|
||||
else
|
||||
{
|
||||
// fallback to glTexImage3D with NULL data
|
||||
for (U32 mip = 0; mip < retTex->mMipLevels; ++mip)
|
||||
{
|
||||
U32 mipW = getMax(1u, width >> mip);
|
||||
U32 mipH = getMax(1u, height >> mip);
|
||||
glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, GFXGLTextureInternalFormat[format], mipW, mipH, layers, 0, GFXGLTextureFormat[format], GFXGLTextureType[format], NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 - 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])
|
||||
glTexParameteriv(binding, GL_TEXTURE_SWIZZLE_RGBA, GFXGLTextureSwizzle[format]);
|
||||
|
||||
// Get the size from GL (you never know...)
|
||||
GLint texHeight, texWidth, texDepth = 0;
|
||||
|
||||
glGetTexLevelParameteriv(binding, 0, GL_TEXTURE_WIDTH, &texWidth);
|
||||
glGetTexLevelParameteriv(binding, 0, GL_TEXTURE_HEIGHT, &texHeight);
|
||||
if(binding == GL_TEXTURE_3D)
|
||||
glGetTexLevelParameteriv(binding, 0, GL_TEXTURE_DEPTH, &texDepth);
|
||||
|
||||
GLint texHeight = 0, texWidth = 0, texDepth = 0;
|
||||
|
||||
GLenum queryTarget = binding;
|
||||
if (binding == GL_TEXTURE_CUBE_MAP)
|
||||
{
|
||||
// Query a specific face, e.g. +X
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -236,7 +364,7 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
|
|||
// 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());
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
else
|
||||
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)
|
||||
{
|
||||
PROFILE_SCOPE(GFXGLTextureManager_loadTexture);
|
||||
PROFILE_SCOPE(GFXGLTextureManager_loadTextureGBitmap);
|
||||
GFXGLTextureObject *texture = static_cast<GFXGLTextureObject*>(aTexture);
|
||||
|
||||
AssertFatal(texture->getBinding() == GL_TEXTURE_1D || texture->getBinding() == GL_TEXTURE_2D,
|
||||
"GFXGLTextureManager::_loadTexture(GBitmap) - This method can only be used with 1D/2D textures");
|
||||
|
||||
const GLenum target = texture->getBinding();
|
||||
|
||||
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)
|
||||
return false;
|
||||
|
||||
// No 24bit formats.
|
||||
if(pDL->getFormat() == GFXFormatR8G8B8)
|
||||
pDL->setFormat(GFXFormatR8G8B8A8);
|
||||
else if (pDL->getFormat() == GFXFormatR8G8B8_SRGB)
|
||||
pDL->setFormat(GFXFormatR8G8B8A8_SRGB);
|
||||
//
|
||||
//// No 24bit formats.
|
||||
//if(pDL->getFormat() == GFXFormatR8G8B8)
|
||||
// pDL->setFormat(GFXFormatR8G8B8A8);
|
||||
//else if (pDL->getFormat() == GFXFormatR8G8B8_SRGB)
|
||||
// pDL->setFormat(GFXFormatR8G8B8A8_SRGB);
|
||||
|
||||
// Bind to edit
|
||||
PRESERVE_TEXTURE(texture->getBinding());
|
||||
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()))
|
||||
glGenerateMipmap(texture->getBinding());
|
||||
|
||||
for (U32 mip = 0; mip < mipLevels; mip++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds)
|
||||
{
|
||||
PROFILE_SCOPE(GFXGLTextureManager_loadTextureDDS);
|
||||
GFXGLTextureObject* texture = static_cast<GFXGLTextureObject*>(aTexture);
|
||||
|
||||
AssertFatal(texture->getBinding() == GL_TEXTURE_2D,
|
||||
"GFXGLTextureManager::_loadTexture(DDSFile) - This method can only be used with 2D textures");
|
||||
|
||||
if(texture->getBinding() != GL_TEXTURE_2D)
|
||||
return false;
|
||||
|
||||
PRESERVE_TEXTURE(texture->getBinding());
|
||||
glBindTexture(texture->getBinding(), texture->getHandle());
|
||||
U32 numMips = dds->mSurfaces[0]->mMips.size();
|
||||
|
||||
const GLenum target = texture->getBinding();
|
||||
|
||||
const bool isCube = texture->getBinding() == GL_TEXTURE_CUBE_MAP && dds->isCubemap();
|
||||
const bool isCompressed = ImageUtil::isCompressedFormat(texture->mFormat);
|
||||
|
||||
AssertFatal(target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP,
|
||||
"GFXGLTextureManager::_loadTexture(DDS) - This method can only be used with 1D/2D and CubeMap textures");
|
||||
|
||||
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;
|
||||
|
||||
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];
|
||||
ImageUtil::decompress(dds->mSurfaces[0]->mMips[i],uncompressedTex, dds->getWidth(i), dds->getHeight(i), fmt);
|
||||
glTexSubImage2D(texture->getBinding(), i, 0, 0, dds->getWidth(i), dds->getHeight(i), GL_RGBA, GL_UNSIGNED_BYTE, uncompressedTex);
|
||||
delete[] uncompressedTex;
|
||||
// Handle NPOT workaround
|
||||
if ((!isPow2(mipWidth) || !isPow2(mipHeight)) && GFX->getCardProfiler()->queryProfile("GL::Workaround::noCompressedNPoTTextures"))
|
||||
{
|
||||
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
|
||||
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]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Swizzle<U8, 4> *pSwizzle = NULL;
|
||||
if (fmt == GFXFormatR8G8B8A8 || fmt == GFXFormatR8G8B8X8 || fmt == GFXFormatR8G8B8A8_SRGB || fmt == GFXFormatR8G8B8A8_LINEAR_FORCE || fmt == GFXFormatB8G8R8A8)
|
||||
pSwizzle = &Swizzles::bgra;
|
||||
{
|
||||
Swizzle<U8, 4>* pSwizzle = nullptr;
|
||||
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());
|
||||
|
||||
|
||||
glBindTexture(target, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ protected:
|
|||
U32 numMipLevels,
|
||||
bool forceMips = false,
|
||||
S32 antialiasLevel = 0,
|
||||
U32 arraySize = 1,
|
||||
GFXTextureObject *inTex = NULL ) override;
|
||||
bool _loadTexture(GFXTextureObject *texture, DDSFile *dds) override;
|
||||
bool _loadTexture(GFXTextureObject *texture, GBitmap *bmp) override;
|
||||
|
|
@ -56,7 +57,7 @@ private:
|
|||
friend class GFXGLTextureObject;
|
||||
|
||||
/// 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();
|
||||
}
|
||||
|
||||
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");
|
||||
U32 width = mTextureSize.x >> mipLevel;
|
||||
|
|
@ -100,7 +100,7 @@ GFXLockedRect* GFXGLTextureObject::lock(U32 mipLevel, RectI *inRect)
|
|||
return &mLockedRect;
|
||||
}
|
||||
|
||||
void GFXGLTextureObject::unlock(U32 mipLevel)
|
||||
void GFXGLTextureObject::unlock(U32 mipLevel /*= 0*/, U32 faceIndex /*= 0*/)
|
||||
{
|
||||
if(!mLockedRect.bits)
|
||||
return;
|
||||
|
|
@ -175,38 +175,231 @@ bool GFXGLTextureObject::copyToBmp(GBitmap * bmp)
|
|||
|
||||
FrameAllocatorMarker mem;
|
||||
|
||||
const bool isCubemap = (mBinding == GL_TEXTURE_CUBE_MAP);
|
||||
const U32 numFaces = isCubemap ? 6 : 1;
|
||||
|
||||
U32 mipLevels = getMipLevels();
|
||||
for (U32 mip = 0; mip < mipLevels; mip++)
|
||||
for (U32 mip = 0; mip < getMipLevels(); 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);
|
||||
U8* orig = (U8*)mem.alloc(srcPixelCount * srcBytesPerPixel);
|
||||
// Check if multisampled
|
||||
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);
|
||||
if (mFormat == GFXFormatR16G16B16A16F)
|
||||
glGetTexLevelParameteriv(target, mip, GL_TEXTURE_SAMPLES, &samples);
|
||||
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;
|
||||
dest += dstBytesPerPixel;
|
||||
for (U32 face = 0; face < numFaces; face++)
|
||||
{
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@
|
|||
#include "gfx/gfxTextureObject.h"
|
||||
#include "gfx/gl/tGL/tGL.h"
|
||||
#include "gfx/gfxStateBlock.h"
|
||||
|
||||
#ifndef _MRECT_H_
|
||||
#include "math/mRect.h"
|
||||
#endif
|
||||
class GFXGLDevice;
|
||||
|
||||
class GFXGLTextureObject : public GFXTextureObject
|
||||
|
|
@ -64,11 +66,13 @@ public:
|
|||
|
||||
/// 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.
|
||||
GFXLockedRect* lock(U32 mipLevel = 0, RectI *inRect = NULL) override;
|
||||
void unlock(U32 mipLevel = 0 ) override;
|
||||
GFXLockedRect* lock(U32 mipLevel = 0, RectI *inRect = NULL, U32 faceIndex = 0) override;
|
||||
void unlock(U32 mipLevel = 0, U32 faceIndex = 0) override;
|
||||
|
||||
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;
|
||||
|
||||
// GFXResource interface
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@ public:
|
|||
mipLevel(_mipLevel), zOffset(_zOffset)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual ~_GFXGLTargetDesc() {}
|
||||
|
||||
|
||||
virtual U32 getHandle() = 0;
|
||||
virtual U32 getWidth() = 0;
|
||||
virtual U32 getHeight() = 0;
|
||||
|
|
@ -49,10 +49,10 @@ public:
|
|||
virtual GLenum getBinding() = 0;
|
||||
virtual GFXFormat getFormat() = 0;
|
||||
virtual bool isCompatible(const GFXGLTextureObject* tex) = 0;
|
||||
|
||||
|
||||
U32 getMipLevel() { return mipLevel; }
|
||||
U32 getZOffset() { return zOffset; }
|
||||
|
||||
|
||||
private:
|
||||
U32 mipLevel;
|
||||
U32 zOffset;
|
||||
|
|
@ -62,19 +62,21 @@ private:
|
|||
class _GFXGLTextureTargetDesc : public _GFXGLTargetDesc
|
||||
{
|
||||
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() {}
|
||||
|
||||
|
||||
U32 getHandle() override { return mTex->getHandle(); }
|
||||
U32 getWidth() override { return mTex->getWidth(); }
|
||||
U32 getHeight() override { return mTex->getHeight(); }
|
||||
U32 getDepth() override { return mTex->getDepth(); }
|
||||
U32 getFace() { return mFace; }
|
||||
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(); }
|
||||
bool isCompatible(const GFXGLTextureObject* tex) override
|
||||
{
|
||||
|
|
@ -82,40 +84,12 @@ public:
|
|||
&& mTex->getWidth() == tex->getWidth()
|
||||
&& mTex->getHeight() == tex->getHeight();
|
||||
}
|
||||
GFXGLTextureObject* getTextureObject() const {return mTex; }
|
||||
|
||||
GFXGLTextureObject* getTextureObject() const { return mTex; }
|
||||
|
||||
private:
|
||||
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;
|
||||
bool mIsCube;
|
||||
};
|
||||
|
||||
// Internal implementations
|
||||
|
|
@ -123,9 +97,9 @@ class _GFXGLTextureTargetImpl // TODO OPENGL remove and implement on GFXGLTextur
|
|||
{
|
||||
public:
|
||||
GFXGLTextureTarget* mTarget;
|
||||
|
||||
|
||||
virtual ~_GFXGLTextureTargetImpl() {}
|
||||
|
||||
|
||||
virtual void applyState() = 0;
|
||||
virtual void makeActive() = 0;
|
||||
virtual void finish() = 0;
|
||||
|
|
@ -137,10 +111,10 @@ class _GFXGLTextureTargetFBOImpl : public _GFXGLTextureTargetImpl
|
|||
public:
|
||||
GLuint mFramebuffer;
|
||||
bool mGenMips;
|
||||
|
||||
|
||||
_GFXGLTextureTargetFBOImpl(GFXGLTextureTarget* target);
|
||||
virtual ~_GFXGLTextureTargetFBOImpl();
|
||||
|
||||
|
||||
void applyState() override;
|
||||
void makeActive() override;
|
||||
void finish() override;
|
||||
|
|
@ -159,42 +133,42 @@ _GFXGLTextureTargetFBOImpl::~_GFXGLTextureTargetFBOImpl()
|
|||
}
|
||||
|
||||
void _GFXGLTextureTargetFBOImpl::applyState()
|
||||
{
|
||||
{
|
||||
// REMINDER: When we implement MRT support, check against GFXGLDevice::getNumRenderTargets()
|
||||
|
||||
|
||||
PRESERVE_FRAMEBUFFER();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
bool drawbufs[16];
|
||||
int bufsize = 0;
|
||||
for (int i = 0; i < 16; i++)
|
||||
drawbufs[i] = false;
|
||||
drawbufs[i] = false;
|
||||
bool hasColor = false;
|
||||
for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
|
||||
{
|
||||
_GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ));
|
||||
if(color)
|
||||
for (int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
|
||||
{
|
||||
_GFXGLTargetDesc* color = mTarget->getTargetDesc(static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0 + i));
|
||||
if (color)
|
||||
{
|
||||
hasColor = true;
|
||||
const GLenum binding = color->getBinding();
|
||||
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( ) );
|
||||
else if( binding == GL_TEXTURE_1D )
|
||||
glFramebufferTexture1D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ) );
|
||||
else if( binding == GL_TEXTURE_3D )
|
||||
glFramebufferTexture3D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding( ), color->getHandle( ), color->getMipLevel( ), color->getZOffset( ) );
|
||||
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());
|
||||
else if (binding == GL_TEXTURE_1D)
|
||||
glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding(), color->getHandle(), color->getMipLevel());
|
||||
else if (binding == GL_TEXTURE_3D)
|
||||
glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, color->getBinding(), color->getHandle(), color->getMipLevel(), color->getZOffset());
|
||||
else
|
||||
Con::errorf("_GFXGLTextureTargetFBOImpl::applyState - Bad binding");
|
||||
Con::errorf("_GFXGLTextureTargetFBOImpl::applyState - Bad binding");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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);
|
||||
if(depthStecil)
|
||||
if (depthStecil)
|
||||
{
|
||||
// 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!");
|
||||
|
|
@ -206,40 +180,40 @@ void _GFXGLTextureTargetFBOImpl::applyState()
|
|||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
|
||||
}
|
||||
|
||||
GLenum *buf = new GLenum[bufsize];
|
||||
GLenum* buf = new GLenum[bufsize];
|
||||
int count = 0;
|
||||
for (int i = 0; i < bufsize; i++)
|
||||
{
|
||||
if (drawbufs[i])
|
||||
{
|
||||
buf[count] = GL_COLOR_ATTACHMENT0 + i;
|
||||
count++;
|
||||
}
|
||||
if (drawbufs[i])
|
||||
{
|
||||
buf[count] = GL_COLOR_ATTACHMENT0 + i;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
glDrawBuffers(bufsize, buf);
|
||||
|
||||
|
||||
delete[] buf;
|
||||
CHECK_FRAMEBUFFER_STATUS();
|
||||
}
|
||||
|
||||
void _GFXGLTextureTargetFBOImpl::makeActive()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
|
||||
GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, mFramebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
|
||||
GFXGL->getOpenglCache()->setCacheBinded(GL_FRAMEBUFFER, mFramebuffer);
|
||||
|
||||
int i = 0;
|
||||
GLenum draws[16];
|
||||
for( i = 0; i < GFXGL->getNumRenderTargets(); ++i)
|
||||
{
|
||||
_GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ));
|
||||
if(color)
|
||||
draws[i] = GL_COLOR_ATTACHMENT0 + i;
|
||||
else
|
||||
break;
|
||||
}
|
||||
int i = 0;
|
||||
GLenum draws[16];
|
||||
for (i = 0; i < GFXGL->getNumRenderTargets(); ++i)
|
||||
{
|
||||
_GFXGLTargetDesc* color = mTarget->getTargetDesc(static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0 + i));
|
||||
if (color)
|
||||
draws[i] = GL_COLOR_ATTACHMENT0 + i;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
glDrawBuffers( i, draws );
|
||||
glDrawBuffers(i, draws);
|
||||
}
|
||||
|
||||
void _GFXGLTextureTargetFBOImpl::finish()
|
||||
|
|
@ -250,20 +224,20 @@ void _GFXGLTextureTargetFBOImpl::finish()
|
|||
if (!mGenMips)
|
||||
return;
|
||||
|
||||
for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
|
||||
{
|
||||
_GFXGLTargetDesc* color = mTarget->getTargetDesc( static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0+i ) );
|
||||
if(!color || !(color->hasMips()))
|
||||
for (int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
|
||||
{
|
||||
_GFXGLTargetDesc* color = mTarget->getTargetDesc(static_cast<GFXTextureTarget::RenderSlot>(GFXTextureTarget::Color0 + i));
|
||||
if (!color || !(color->hasMips()))
|
||||
continue;
|
||||
|
||||
|
||||
// Generate mips if necessary
|
||||
// Assumes a 2D texture.
|
||||
GLenum binding = color->getBinding();
|
||||
binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;
|
||||
|
||||
PRESERVE_TEXTURE( binding );
|
||||
glBindTexture( binding, color->getHandle() );
|
||||
glGenerateMipmap( binding );
|
||||
PRESERVE_TEXTURE(binding);
|
||||
glBindTexture(binding, color->getHandle());
|
||||
glGenerateMipmap(binding);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -271,13 +245,13 @@ void _GFXGLTextureTargetFBOImpl::finish()
|
|||
GFXGLTextureTarget::GFXGLTextureTarget(bool genMips) : mCopyFboSrc(0), mCopyFboDst(0)
|
||||
{
|
||||
mGenMips = genMips;
|
||||
for(U32 i=0; i<MaxRenderSlotId; i++)
|
||||
for (U32 i = 0; i < MaxRenderSlotId; i++)
|
||||
mTargets[i] = NULL;
|
||||
|
||||
GFXTextureManager::addEventDelegate( this, &GFXGLTextureTarget::_onTextureEvent );
|
||||
|
||||
GFXTextureManager::addEventDelegate(this, &GFXGLTextureTarget::_onTextureEvent);
|
||||
|
||||
_impl = new _GFXGLTextureTargetFBOImpl(this);
|
||||
|
||||
|
||||
glGenFramebuffers(1, &mCopyFboSrc);
|
||||
glGenFramebuffers(1, &mCopyFboDst);
|
||||
}
|
||||
|
|
@ -292,7 +266,7 @@ GFXGLTextureTarget::~GFXGLTextureTarget()
|
|||
|
||||
const Point2I GFXGLTextureTarget::getSize()
|
||||
{
|
||||
if(mTargets[Color0].isValid())
|
||||
if (mTargets[Color0].isValid())
|
||||
return Point2I(mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight());
|
||||
|
||||
return Point2I(0, 0);
|
||||
|
|
@ -300,61 +274,50 @@ const Point2I GFXGLTextureTarget::getSize()
|
|||
|
||||
GFXFormat GFXGLTextureTarget::getFormat()
|
||||
{
|
||||
if(mTargets[Color0].isValid())
|
||||
if (mTargets[Color0].isValid())
|
||||
return mTargets[Color0]->getFormat();
|
||||
|
||||
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();
|
||||
|
||||
// are we readding the same thing, face and all?
|
||||
_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;
|
||||
|
||||
|
||||
// Triggers an update when we next render
|
||||
invalidateState();
|
||||
|
||||
// We stash the texture and info into an internal struct.
|
||||
GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(tex);
|
||||
if(tex && tex != GFXTextureTarget::sDefaultDepthStencil)
|
||||
mTargets[slot] = new _GFXGLTextureTargetDesc(glTexture, mipLevel, zOffset);
|
||||
if (tex && tex != GFXTextureTarget::sDefaultDepthStencil)
|
||||
{
|
||||
mTargets[slot] = new _GFXGLTextureTargetDesc(glTexture, mipLevel, zOffset, face, glTexture->isCubeMap());
|
||||
}
|
||||
else
|
||||
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()
|
||||
{
|
||||
deactivate();
|
||||
for(S32 i=1; i<MaxRenderSlotId; i++)
|
||||
for (S32 i = 1; i < MaxRenderSlotId; i++)
|
||||
attachTexture((RenderSlot)i, NULL);
|
||||
}
|
||||
|
||||
void GFXGLTextureTarget::zombify()
|
||||
{
|
||||
invalidateState();
|
||||
|
||||
|
||||
// Will be recreated in applyState
|
||||
_impl = NULL;
|
||||
}
|
||||
|
|
@ -376,15 +339,15 @@ void GFXGLTextureTarget::deactivate()
|
|||
|
||||
void GFXGLTextureTarget::applyState()
|
||||
{
|
||||
if(!isPendingState())
|
||||
if (!isPendingState())
|
||||
return;
|
||||
|
||||
// So we don't do this over and over again
|
||||
stateApplied();
|
||||
|
||||
if(_impl.isNull())
|
||||
|
||||
if (_impl.isNull())
|
||||
_impl = new _GFXGLTextureTargetFBOImpl(this);
|
||||
|
||||
|
||||
_impl->applyState();
|
||||
}
|
||||
|
||||
|
|
@ -394,7 +357,7 @@ _GFXGLTargetDesc* GFXGLTextureTarget::getTargetDesc(RenderSlot slot) const
|
|||
return mTargets[slot].ptr();
|
||||
}
|
||||
|
||||
void GFXGLTextureTarget::_onTextureEvent( GFXTexCallbackCode code )
|
||||
void GFXGLTextureTarget::_onTextureEvent(GFXTexCallbackCode code)
|
||||
{
|
||||
invalidateState();
|
||||
}
|
||||
|
|
@ -403,7 +366,7 @@ const String GFXGLTextureTarget::describeSelf() const
|
|||
{
|
||||
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);
|
||||
|
||||
|
||||
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");
|
||||
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;
|
||||
U32 srcStartDepth = binding == GL_TEXTURE_CUBE_MAP ? mTargets[Color0]->getBinding() - GL_TEXTURE_CUBE_MAP_POSITIVE_X : 0;
|
||||
glCopyImageSubData(
|
||||
mTargets[Color0]->getHandle(), binding, 0, 0, 0, srcStartDepth,
|
||||
glTexture->getHandle(), glTexture->getBinding(), 0, 0, 0, 0,
|
||||
mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(), 1);
|
||||
mTargets[Color0]->getHandle(), binding, 0, 0, 0, srcStartDepth,
|
||||
glTexture->getHandle(), glTexture->getBinding(), 0, 0, 0, 0,
|
||||
mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(), 1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PRESERVE_FRAMEBUFFER();
|
||||
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mCopyFboDst);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, glTexture->getBinding(), glTexture->getHandle(), 0);
|
||||
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, mCopyFboSrc);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTargets[Color0]->getBinding(), mTargets[Color0]->getHandle(), 0);
|
||||
|
||||
|
||||
glBlitFramebuffer(0, 0, mTargets[Color0]->getWidth(), mTargets[Color0]->getHeight(),
|
||||
0, 0, glTexture->getWidth(), glTexture->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,35 +50,35 @@ public:
|
|||
|
||||
const Point2I getSize() override;
|
||||
GFXFormat getFormat() override;
|
||||
void attachTexture(RenderSlot slot, GFXTextureObject *tex, U32 mipLevel=0, U32 zOffset = 0) override;
|
||||
void attachTexture(RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel=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;
|
||||
virtual void clearAttachments();
|
||||
|
||||
/// Functions to query internal state
|
||||
/// @{
|
||||
|
||||
|
||||
/// Returns the internal structure for the given slot. This should only be called by our internal implementations.
|
||||
_GFXGLTargetDesc* getTargetDesc(RenderSlot slot) const;
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
void deactivate() override;
|
||||
void zombify() override;
|
||||
void resurrect() override;
|
||||
const String describeSelf() const override;
|
||||
|
||||
|
||||
void resolve() override;
|
||||
|
||||
|
||||
void resolveTo(GFXTextureObject* obj) override;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
friend class GFXGLDevice;
|
||||
|
||||
/// The callback used to get texture events.
|
||||
/// @see GFXTextureManager::addEventDelegate
|
||||
void _onTextureEvent( GFXTexCallbackCode code );
|
||||
|
||||
void _onTextureEvent(GFXTexCallbackCode code);
|
||||
|
||||
/// Pointer to our internal implementation
|
||||
AutoPtr<_GFXGLTextureTargetImpl> _impl;
|
||||
|
||||
|
|
@ -87,10 +87,10 @@ protected:
|
|||
|
||||
/// These redirect to our internal implementation
|
||||
/// @{
|
||||
|
||||
|
||||
void applyState();
|
||||
void makeActive();
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
//copy FBO
|
||||
|
|
|
|||
|
|
@ -103,8 +103,6 @@ void GFXGLDevice::enumerateAdapters( Vector<GFXAdapter*> &adapterList )
|
|||
}
|
||||
|
||||
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_FRAMEBUFFER_SRGB_CAPABLE, 1);
|
||||
|
||||
|
|
@ -140,6 +138,10 @@ void GFXGLDevice::enumerateAdapters( Vector<GFXAdapter*> &adapterList )
|
|||
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
|
||||
if (!gglHasExtension(ARB_texture_cube_map_array))
|
||||
{
|
||||
|
|
@ -168,7 +170,24 @@ void GFXGLDevice::enumerateAdapters( Vector<GFXAdapter*> &adapterList )
|
|||
dStrcpy(toAdd->mName, "OpenGL", GFXAdapter::MaxAdapterNameLen);
|
||||
|
||||
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;
|
||||
|
||||
// Enumerate all available resolutions:
|
||||
|
|
|
|||
|
|
@ -45,7 +45,15 @@ CubemapData::CubemapData()
|
|||
|
||||
CubemapData::~CubemapData()
|
||||
{
|
||||
mCubemap = NULL;
|
||||
if (mCubeMapAsset.notNull())
|
||||
{
|
||||
mCubeMapAsset.clear();
|
||||
}
|
||||
|
||||
if (mCubemap)
|
||||
{
|
||||
mCubemap.free();
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleDocClass( CubemapData,
|
||||
|
|
@ -101,7 +109,7 @@ void CubemapData::createMap()
|
|||
//check mCubeMapFile first
|
||||
if (mCubeMapAsset.notNull())
|
||||
{
|
||||
mCubemap = TEXMGR->createCubemap(mCubeMapAsset->getImageFile());
|
||||
mCubemap = mCubeMapAsset->getTexture(&GFXCubemapStaticTextureProfile);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
|
@ -125,11 +133,14 @@ void CubemapData::createMap()
|
|||
|
||||
if( initSuccess )
|
||||
{
|
||||
mCubemap = GFX->createCubemap();
|
||||
if (mCubeMapFaceAsset->isNull())
|
||||
return;
|
||||
if (mCubeMapFaceAsset->isNull())
|
||||
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
|
||||
if (mCubeMapAsset.notNull())
|
||||
{
|
||||
mCubemap = TEXMGR->createCubemap(mCubeMapAsset->getImageFile());
|
||||
mCubemap = mCubeMapAsset->getTexture(&GFXCubemapStaticTextureProfile);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
|
@ -166,11 +177,14 @@ void CubemapData::updateFaces()
|
|||
if( initSuccess )
|
||||
{
|
||||
mCubemap = NULL;
|
||||
mCubemap = GFX->createCubemap();
|
||||
if (mCubeMapFaceAsset->isNull())
|
||||
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:
|
||||
|
||||
GFXCubemapHandle mCubemap;
|
||||
GFXTexHandle mCubemap;
|
||||
|
||||
CubemapData();
|
||||
~CubemapData();
|
||||
|
|
|
|||
|
|
@ -35,26 +35,11 @@
|
|||
#include "gfx/util/gfxFrustumSaver.h"
|
||||
#include "math/mathUtils.h"
|
||||
|
||||
|
||||
CubeLightShadowMap::CubeLightShadowMap( LightInfo *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,
|
||||
LightingShaderConstants *lsc )
|
||||
{
|
||||
|
|
@ -77,12 +62,6 @@ void CubeLightShadowMap::setShaderParameters( GFXShaderConstBuffer *params,
|
|||
params->setSafe( lsc->mShadowSoftnessConst, p->shadowSoftness * ( 1.0f / mTexSize ) );
|
||||
}
|
||||
|
||||
void CubeLightShadowMap::releaseTextures()
|
||||
{
|
||||
Parent::releaseTextures();
|
||||
mCubemap = NULL;
|
||||
}
|
||||
|
||||
void CubeLightShadowMap::_render( RenderPassManager* renderPass,
|
||||
const SceneRenderState *diffuseState )
|
||||
{
|
||||
|
|
@ -92,15 +71,16 @@ void CubeLightShadowMap::_render( RenderPassManager* renderPass,
|
|||
const bool bUseLightmappedGeometry = lmParams ? !lmParams->representedInLightmap || lmParams->includeLightmappedGeometryInShadow : true;
|
||||
|
||||
const U32 texSize = getBestTexSize();
|
||||
|
||||
if ( mCubemap.isNull() ||
|
||||
mTexSize != texSize )
|
||||
if (mShadowMapTex.isNull() ||
|
||||
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
|
||||
// in the shader to transform the light vector for the
|
||||
// shadow lookup.
|
||||
|
|
@ -155,20 +135,14 @@ void CubeLightShadowMap::_render( RenderPassManager* renderPass,
|
|||
GFXDEBUGEVENT_START( CubeLightShadowMap_Render_Face, ColorI::RED );
|
||||
|
||||
// create camera matrix
|
||||
VectorF cross = mCross(vUpVec, vLookatPt);
|
||||
cross.normalizeSafe();
|
||||
|
||||
MatrixF lightMatrix(true);
|
||||
lightMatrix.setColumn(0, cross);
|
||||
lightMatrix.setColumn(1, vLookatPt);
|
||||
lightMatrix.setColumn(2, vUpVec);
|
||||
lightMatrix.setPosition( mLight->getPosition() );
|
||||
lightMatrix.LookAt(mLight->getPosition(), vLookatPt, vUpVec);
|
||||
lightMatrix.inverse();
|
||||
|
||||
GFX->setWorldMatrix( lightMatrix );
|
||||
|
||||
mTarget->attachTexture(GFXTextureTarget::Color0, mCubemap, i);
|
||||
mTarget->attachTexture(GFXTextureTarget::DepthStencil, _getDepthTarget( mTexSize, mTexSize ));
|
||||
mTarget->attachTexture(GFXTextureTarget::Color0, mShadowMapTex,0,0, i);
|
||||
mTarget->attachTexture(GFXTextureTarget::DepthStencil, _getDepthTarget(mShadowMapTex->getWidth(), mShadowMapTex->getHeight()));
|
||||
GFX->setActiveRenderTarget(mTarget);
|
||||
GFX->clear( GFXClearTarget | GFXClearStencil | GFXClearZBuffer, ColorI(255,255,255,255), 0.0f, 0 );
|
||||
|
||||
|
|
|
|||
|
|
@ -39,18 +39,9 @@ public:
|
|||
|
||||
CubeLightShadowMap( LightInfo *light );
|
||||
|
||||
// LightShadowMap
|
||||
bool hasShadowTex() const override { return mCubemap.isValid(); }
|
||||
ShadowType getShadowType() const override { return ShadowType_CubeMap; }
|
||||
void _render( RenderPassManager* renderPass, const SceneRenderState *diffuseState ) 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::NONE );
|
||||
|
||||
GFX_ImplementTextureProfile(CubeShadowMapProfile,
|
||||
GFXTextureProfile::DiffuseMap,
|
||||
GFXTextureProfile::PreserveSize |
|
||||
GFXTextureProfile::RenderTarget |
|
||||
GFXTextureProfile::Pooled | GFXTextureProfile::CubeMap,
|
||||
GFXTextureProfile::NONE);
|
||||
|
||||
GFX_ImplementTextureProfile( ShadowMapZProfile,
|
||||
GFXTextureProfile::DiffuseMap,
|
||||
GFXTextureProfile::PreserveSize |
|
||||
|
|
|
|||
|
|
@ -266,6 +266,7 @@ protected:
|
|||
};
|
||||
|
||||
GFX_DeclareTextureProfile( ShadowMapProfile );
|
||||
GFX_DeclareTextureProfile( CubeShadowMapProfile );
|
||||
GFX_DeclareTextureProfile( ShadowMapZProfile );
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ public:
|
|||
TextureTable mTextures;
|
||||
|
||||
/// The cubemap for this stage.
|
||||
GFXCubemap* mCubemap;
|
||||
GFXTexHandle mCubemap;
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -204,10 +204,10 @@ public:
|
|||
void getFeatureSet(FeatureSet* outFeatures) const;
|
||||
|
||||
/// Returns the stage cubemap.
|
||||
GFXCubemap* getCubemap() const { return mCubemap; }
|
||||
GFXTexHandle getCubemap() const { return mCubemap; }
|
||||
|
||||
/// 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:
|
||||
{
|
||||
GFX->setCubeTexture( samplerRegister, rpd->mCubeMap );
|
||||
GFX->setTexture( samplerRegister, rpd->mCubeMap );
|
||||
break;
|
||||
}
|
||||
case Material::SGCube:
|
||||
{
|
||||
GFX->setCubeTexture( samplerRegister, sgData.cubemap );
|
||||
GFX->setTexture( samplerRegister, sgData.cubemap );
|
||||
break;
|
||||
}
|
||||
case Material::BackBuff:
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ public:
|
|||
/// The cubemap to use when the texture type is
|
||||
/// set to Material::Cube.
|
||||
/// @see mTexType
|
||||
GFXCubemapHandle mCubeMap;
|
||||
GFXTexHandle mCubeMap;
|
||||
|
||||
U32 mNumTex;
|
||||
|
||||
|
|
|
|||
|
|
@ -854,11 +854,11 @@ void ProcessedShaderMaterial::setTextureStages( SceneRenderState *state, const S
|
|||
break;
|
||||
|
||||
case Material::Cube:
|
||||
GFX->setCubeTexture( i, rpd->mCubeMap );
|
||||
GFX->setTexture( i, rpd->mCubeMap );
|
||||
break;
|
||||
|
||||
case Material::SGCube:
|
||||
GFX->setCubeTexture( i, sgData.cubemap );
|
||||
GFX->setTexture( i, sgData.cubemap );
|
||||
break;
|
||||
|
||||
case Material::BackBuff:
|
||||
|
|
@ -1333,7 +1333,7 @@ void ProcessedShaderMaterial::setSceneInfo(SceneRenderState * state, const Scene
|
|||
}
|
||||
}
|
||||
if (sgData.cubemap)
|
||||
shaderConsts->setSafe(handles->mCubeMipsSC, (F32)sgData.cubemap->getMipMapLevels());
|
||||
shaderConsts->setSafe(handles->mCubeMipsSC, (F32)sgData.cubemap->getMipLevels());
|
||||
else
|
||||
shaderConsts->setSafe(handles->mCubeMipsSC, (F32)getBinLog2(PROBEMGR->getProbeTexSize()));
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ struct SceneData
|
|||
|
||||
// misc
|
||||
const MatrixF *objTrans;
|
||||
GFXCubemap *cubemap;
|
||||
GFXTexHandle cubemap;
|
||||
F32 visibility;
|
||||
|
||||
/// Enables wireframe rendering for the object.
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ void bitmapConvertRGB_to_5551_mmx(U8 *src, U32 pixels)
|
|||
void PlatformBlitInit()
|
||||
{
|
||||
bitmapExtrude5551 = bitmapExtrude5551_asm;
|
||||
bitmapExtrudeRGB = bitmapExtrudeRGB_c;
|
||||
//bitmapExtrudeRGB = bitmapExtrudeRGB_c;
|
||||
|
||||
if (Platform::SystemInfo.processor.properties & CPU_PROP_MMX)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ void RenderDeferredMgr::render( SceneRenderState *state )
|
|||
|
||||
// init loop data
|
||||
GFXTextureObject *lastLM = NULL;
|
||||
GFXCubemap *lastCubemap = NULL;
|
||||
GFXTexHandle lastCubemap = NULL;
|
||||
GFXTextureObject *lastReflectTex = NULL;
|
||||
GFXTextureObject *lastAccuTex = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ void RenderMeshMgr::render(SceneRenderState * state)
|
|||
|
||||
// init loop data
|
||||
GFXTextureObject *lastLM = NULL;
|
||||
GFXCubemap *lastCubemap = NULL;
|
||||
GFXTexHandle lastCubemap = NULL;
|
||||
GFXTextureObject *lastReflectTex = NULL;
|
||||
GFXTextureObject *lastMiscTex = NULL;
|
||||
GFXTextureObject *lastAccuTex = NULL;
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ struct MeshRenderInst : public RenderInst
|
|||
GFXTextureObject *reflectTex;
|
||||
GFXTextureObject *miscTex;
|
||||
GFXTextureObject *accuTex;
|
||||
GFXCubemap *cubemap;
|
||||
GFXTexHandle cubemap;
|
||||
|
||||
/// @name Hardware Skinning
|
||||
/// {
|
||||
|
|
|
|||
|
|
@ -221,6 +221,9 @@ RenderProbeMgr::~RenderProbeMgr()
|
|||
SAFE_DELETE(i->value);
|
||||
}
|
||||
mConstantLookup.clear();
|
||||
|
||||
mIrradianceArray.free();
|
||||
mPrefilterArray.free();
|
||||
}
|
||||
|
||||
bool RenderProbeMgr::onAdd()
|
||||
|
|
@ -228,13 +231,11 @@ bool RenderProbeMgr::onAdd()
|
|||
if (!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
mIrradianceArray = GFXCubemapArrayHandle(GFX->createCubemapArray());
|
||||
mPrefilterArray = GFXCubemapArrayHandle(GFX->createCubemapArray());
|
||||
|
||||
U32 scaledSize = getProbeTexSize();
|
||||
//pre-allocate a few slots
|
||||
mIrradianceArray->init(PROBE_ARRAY_SLOT_BUFFER_SIZE, scaledSize, PROBE_FORMAT);
|
||||
mPrefilterArray->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.set(scaledSize, scaledSize, PROBE_FORMAT, &GFXCubemapStaticTextureProfile, "RenderProbeMgr::mPrefilterArray", 0,0, PROBE_ARRAY_SLOT_BUFFER_SIZE);
|
||||
|
||||
mCubeSlotCount = PROBE_ARRAY_SLOT_BUFFER_SIZE;
|
||||
|
||||
String brdfTexturePath = GFXTextureManager::getBRDFTexturePath();
|
||||
|
|
@ -376,12 +377,12 @@ void RenderProbeMgr::registerProbe(ReflectionProbe::ProbeInfo* newProbe)
|
|||
if (cubeIndex >= mCubeSlotCount)
|
||||
{
|
||||
//alloc temp array handles
|
||||
GFXCubemapArrayHandle irr = GFXCubemapArrayHandle(GFX->createCubemapArray());
|
||||
GFXCubemapArrayHandle prefilter = GFXCubemapArrayHandle(GFX->createCubemapArray());
|
||||
GFXTexHandle irr;
|
||||
GFXTexHandle prefilter;
|
||||
|
||||
U32 scaledSize = getProbeTexSize();
|
||||
irr->init(mCubeSlotCount + PROBE_ARRAY_SLOT_BUFFER_SIZE, scaledSize, PROBE_FORMAT);
|
||||
prefilter->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.set(scaledSize, scaledSize, PROBE_FORMAT, &GFXCubemapStaticTextureProfile, "RenderProbeMgr::mPrefilterArray_temp_expansion", 0, 0, mCubeSlotCount + PROBE_ARRAY_SLOT_BUFFER_SIZE);
|
||||
|
||||
mIrradianceArray->copyTo(irr);
|
||||
mPrefilterArray->copyTo(prefilter);
|
||||
|
|
@ -390,6 +391,9 @@ void RenderProbeMgr::registerProbe(ReflectionProbe::ProbeInfo* newProbe)
|
|||
mIrradianceArray = irr;
|
||||
mPrefilterArray = prefilter;
|
||||
|
||||
irr.free();
|
||||
prefilter.free();
|
||||
|
||||
mCubeSlotCount += PROBE_ARRAY_SLOT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
|
|
@ -466,15 +470,13 @@ void RenderProbeMgr::updateProbeTexture(ReflectionProbe::ProbeInfo* probeInfo)
|
|||
return;
|
||||
U32 scaledSize = getProbeTexSize();
|
||||
//Some basic sanity checking that we have valid cubemaps to work with
|
||||
if (probeInfo->mIrradianceCubemap.isNull() || !probeInfo->mIrradianceCubemap->isInitialized() ||
|
||||
probeInfo->mIrradianceCubemap->getSize() != scaledSize)
|
||||
if (probeInfo->mIrradianceCubemap.isNull() || probeInfo->mIrradianceCubemap->getWidth() != scaledSize)
|
||||
{
|
||||
Con::errorf("RenderProbeMgr::updateProbeTexture() - tried to update a probe's texture with an invalid or uninitialized irradiance map!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (probeInfo->mPrefilterCubemap.isNull() || !probeInfo->mPrefilterCubemap->isInitialized() ||
|
||||
probeInfo->mPrefilterCubemap->getSize() != scaledSize)
|
||||
if (probeInfo->mPrefilterCubemap.isNull() || probeInfo->mPrefilterCubemap->getWidth() != scaledSize)
|
||||
{
|
||||
Con::errorf("RenderProbeMgr::updateProbeTexture() - tried to update a probe's texture with an invalid or uninitialized specular map!");
|
||||
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
|
||||
const U32 cubeIndex = probe->mCubemapIndex;
|
||||
mIrradianceArray->updateTexture(probeInfo->mIrradianceCubemap, cubeIndex);
|
||||
mPrefilterArray->updateTexture(probeInfo->mPrefilterCubemap, cubeIndex);
|
||||
mIrradianceArray->updateTextureSlot(probeInfo->mIrradianceCubemap, cubeIndex);
|
||||
|
||||
mPrefilterArray->updateTextureSlot(probeInfo->mPrefilterCubemap, cubeIndex);
|
||||
|
||||
#ifdef TORQUE_DEBUG
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -616,8 +619,8 @@ void RenderProbeMgr::bakeProbe(ReflectionProbe* probe)
|
|||
clientProbe->createClientResources();
|
||||
|
||||
//Prep it with whatever resolution we've dictated for our bake
|
||||
clientProbe->mIrridianceMap->mCubemap->initDynamic(resolution, reflectFormat);
|
||||
clientProbe->mPrefilterMap->mCubemap->initDynamic(resolution, reflectFormat);
|
||||
clientProbe->mIrridianceMap->mCubemap.set(resolution, resolution, reflectFormat, &GFXCubemapRenderTargetProfile, "ReflectionProbe::mIrridianceMap", 0);
|
||||
clientProbe->mPrefilterMap->mCubemap.set(resolution, resolution, reflectFormat, &GFXCubemapRenderTargetProfile, "ReflectionProbe::mPrefilterMap", 0);
|
||||
|
||||
GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false);
|
||||
clientProbe->mPrefilterMap->mCubemap = cubeRefl.getCubemap();
|
||||
|
|
@ -807,9 +810,9 @@ void RenderProbeMgr::_update4ProbeConsts(const SceneData& sgData,
|
|||
shaderConsts->setSafe(probeShaderConsts->mSkylightDampSC, (int)probeSet.skyLightDamp);
|
||||
|
||||
if (probeShaderConsts->mProbeSpecularCubemapArraySC->getSamplerRegister() != -1)
|
||||
GFX->setCubeArrayTexture(probeShaderConsts->mProbeSpecularCubemapArraySC->getSamplerRegister(), mPrefilterArray);
|
||||
GFX->setTexture(probeShaderConsts->mProbeSpecularCubemapArraySC->getSamplerRegister(), mPrefilterArray);
|
||||
if (probeShaderConsts->mProbeIrradianceCubemapArraySC->getSamplerRegister() != -1)
|
||||
GFX->setCubeArrayTexture(probeShaderConsts->mProbeIrradianceCubemapArraySC->getSamplerRegister(), mIrradianceArray);
|
||||
GFX->setTexture(probeShaderConsts->mProbeIrradianceCubemapArraySC->getSamplerRegister(), mIrradianceArray);
|
||||
|
||||
shaderConsts->setSafe(probeShaderConsts->mMaxProbeDrawDistanceSC, smMaxProbeDrawDistance);
|
||||
}
|
||||
|
|
@ -875,8 +878,8 @@ void RenderProbeMgr::render( SceneRenderState *state )
|
|||
mProbeArrayEffect->setShaderMacro("MAX_PROBES", probePerFrame);
|
||||
|
||||
mProbeArrayEffect->setTexture(3, mBRDFTexture);
|
||||
mProbeArrayEffect->setCubemapArrayTexture(4, mPrefilterArray);
|
||||
mProbeArrayEffect->setCubemapArrayTexture(5, mIrradianceArray);
|
||||
mProbeArrayEffect->setTexture(4, mPrefilterArray);
|
||||
mProbeArrayEffect->setTexture(5, mIrradianceArray);
|
||||
mProbeArrayEffect->setTexture(6, mWetnessTexture);
|
||||
//ssao mask
|
||||
if (AdvancedLightBinManager::smUseSSAOMask)
|
||||
|
|
@ -898,7 +901,7 @@ void RenderProbeMgr::render( SceneRenderState *state )
|
|||
mProbeArrayEffect->setShaderConst("$skylightCubemapIdx", (S32)mProbeData.skyLightIdx);
|
||||
mProbeArrayEffect->setShaderConst(ShaderGenVars::skylightDamp, mProbeData.skyLightDamp);
|
||||
|
||||
mProbeArrayEffect->setShaderConst("$cubeMips", (float)mPrefilterArray->getMipMapLevels());
|
||||
mProbeArrayEffect->setShaderConst("$cubeMips", (float)mPrefilterArray->getMipLevels());
|
||||
|
||||
//also set up some colors
|
||||
Vector<Point4F> contribColors;
|
||||
|
|
|
|||
|
|
@ -184,7 +184,6 @@ public:
|
|||
static F32 smMaxProbeDrawDistance;
|
||||
static S32 smMaxProbesPerFrame;
|
||||
static S32 smProbeBakeResolution;
|
||||
SceneRenderState *mState;
|
||||
private:
|
||||
/// <summary>
|
||||
/// List of registered probes. These are not necessarily rendered in a given frame
|
||||
|
|
@ -246,12 +245,12 @@ private:
|
|||
/// <summary>
|
||||
/// The prefilter cubemap array
|
||||
/// </summary>
|
||||
GFXCubemapArrayHandle mPrefilterArray;
|
||||
GFXTexHandle mPrefilterArray;
|
||||
|
||||
/// <summary>
|
||||
/// The irradiance cubemap array
|
||||
/// </summary>
|
||||
GFXCubemapArrayHandle mIrradianceArray;
|
||||
GFXTexHandle mIrradianceArray;
|
||||
|
||||
//Utilized in forward rendering
|
||||
|
||||
|
|
@ -291,11 +290,6 @@ private:
|
|||
/// </summary>
|
||||
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:
|
||||
/// The current active light manager.
|
||||
static RenderProbeMgr* smProbeManager;
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ void RenderTranslucentMgr::render( SceneRenderState *state )
|
|||
|
||||
// init loop data
|
||||
GFXTextureObject *lastLM = NULL;
|
||||
GFXCubemap *lastCubemap = NULL;
|
||||
GFXTexHandle lastCubemap = NULL;
|
||||
GFXTextureObject *lastReflectTex = NULL;
|
||||
GFXTextureObject *lastAccuTex = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "gfx/gfxCubemap.h"
|
||||
#include "gfx/gfxDebugEvent.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "gfx/util/gfxFrustumSaver.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
|
|
@ -319,15 +320,12 @@ void CubeReflector::updateReflection( const ReflectParams ¶ms, Point3F expli
|
|||
mCubemap.isNull() ||
|
||||
mCubemap->getFormat() != reflectFormat )
|
||||
{
|
||||
mCubemap = GFX->createCubemap();
|
||||
mCubemap->initDynamic( texDim, reflectFormat);
|
||||
mCubemap.set(texDim, texDim, reflectFormat, &GFXCubemapRenderTargetProfile, "CubeReflector::updateReflection", 0);
|
||||
}
|
||||
|
||||
if ( mRenderTarget.isNull() )
|
||||
mRenderTarget = GFX->allocRenderToTextureTarget();
|
||||
|
||||
mDepthBuff = LightShadowMap::_getDepthTarget(texDim, texDim);
|
||||
mRenderTarget->attachTexture(GFXTextureTarget::DepthStencil, mDepthBuff);
|
||||
F32 oldVisibleDist = gClientSceneGraph->getVisibleDistance();
|
||||
gClientSceneGraph->setVisibleDistance( mDesc->farDist );
|
||||
|
||||
|
|
@ -335,15 +333,17 @@ void CubeReflector::updateReflection( const ReflectParams ¶ms, Point3F expli
|
|||
TSShapeInstance::smDetailAdjust *= mDesc->detailAdjust;
|
||||
|
||||
// store current matrices
|
||||
GFXFrustumSaver fsaver;
|
||||
GFXTransformSaver saver;
|
||||
|
||||
// set projection to 90 degrees vertical and horizontal
|
||||
F32 left, right, top, bottom;
|
||||
MathUtils::makeFrustum(&left, &right, &top, &bottom, M_HALFPI_F, 1.0f, mDesc->nearDist);
|
||||
GFX->setFrustum(left, right, bottom, top, mDesc->nearDist, mDesc->farDist);
|
||||
{
|
||||
// set projection to 90 degrees vertical and horizontal
|
||||
F32 left, right, top, bottom;
|
||||
MathUtils::makeFrustum(&left, &right, &top, &bottom, M_HALFPI_F, 1.0f, mDesc->nearDist);
|
||||
GFX->setFrustum(left, right, bottom, top, mDesc->nearDist, mDesc->farDist);
|
||||
}
|
||||
|
||||
GFX->pushActiveRenderTarget();
|
||||
for (S32 i = 5; i >= 0; i--) {
|
||||
for (S32 i = 0; i < 6; i++) {
|
||||
updateFace(params, i, explicitPostion);
|
||||
}
|
||||
GFX->popActiveRenderTarget();
|
||||
|
|
@ -352,7 +352,6 @@ void CubeReflector::updateReflection( const ReflectParams ¶ms, Point3F expli
|
|||
|
||||
mCubemap->generateMipMaps();
|
||||
|
||||
|
||||
gClientSceneGraph->setVisibleDistance(oldVisibleDist);
|
||||
|
||||
mIsRendering = false;
|
||||
|
|
@ -413,19 +412,19 @@ void CubeReflector::updateFace( const ReflectParams ¶ms, U32 faceidx, Point3
|
|||
|
||||
GFX->setWorldMatrix(lightMatrix);
|
||||
GFX->clearTextureStateImmediate(0);
|
||||
mRenderTarget->attachTexture( GFXTextureTarget::Color0, mCubemap, faceidx ); // Setup textures and targets...
|
||||
S32 texDim = mDesc->texSize;
|
||||
texDim = getMax(texDim, 32);
|
||||
mRenderTarget->attachTexture(GFXTextureTarget::Color0, mCubemap, 0, 0, faceidx); // Setup textures and targets...
|
||||
mRenderTarget->attachTexture(GFXTextureTarget::DepthStencil, LightShadowMap::_getDepthTarget(texDim, texDim));
|
||||
|
||||
GFX->setActiveRenderTarget(mRenderTarget);
|
||||
GFX->setActiveRenderTarget(mRenderTarget, true);
|
||||
GFX->clear( GFXClearStencil | GFXClearTarget | GFXClearZBuffer, gCanvasClearColor, 1.0f, 0);
|
||||
|
||||
SceneRenderState reflectRenderState
|
||||
(
|
||||
gClientSceneGraph,
|
||||
SPT_Reflect,
|
||||
SceneCameraState::fromGFX()
|
||||
SceneCameraState::fromGFXWithViewport(GFX->getViewport())
|
||||
);
|
||||
|
||||
reflectRenderState.getMaterialDelegate().bind( REFLECTMGR, &ReflectionManager::getReflectionMaterial );
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ class CubeReflector : public ReflectorBase
|
|||
public:
|
||||
|
||||
CubeReflector();
|
||||
virtual ~CubeReflector() {}
|
||||
virtual ~CubeReflector() { mCubemap.free(); }
|
||||
|
||||
void registerReflector( SceneObject *inObject,
|
||||
ReflectorDesc *inDesc );
|
||||
|
|
@ -153,7 +153,7 @@ public:
|
|||
void unregisterReflector() 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);
|
||||
F32 calcFaceScore( const ReflectParams ¶ms, U32 faceidx );
|
||||
|
|
@ -162,7 +162,7 @@ protected:
|
|||
|
||||
GFXTexHandle mDepthBuff;
|
||||
GFXTextureTargetRef mRenderTarget;
|
||||
GFXCubemapHandle mCubemap;
|
||||
GFXTexHandle mCubemap;
|
||||
U32 mLastTexSize;
|
||||
|
||||
class CubeFaceReflector : public ReflectorBase
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ protected:
|
|||
|
||||
const SceneRenderState *mState;
|
||||
|
||||
GFXCubemap *mCubemap;
|
||||
GFXTexHandle mCubemap;
|
||||
|
||||
/// Used to override the normal
|
||||
/// fade value of an object.
|
||||
|
|
@ -134,8 +134,8 @@ public:
|
|||
void setSceneState( const SceneRenderState *state ) { mState = state; }
|
||||
|
||||
///@see mCubemap
|
||||
GFXCubemap* getCubemap() const { return mCubemap; }
|
||||
void setCubemap( GFXCubemap *cubemap ) { mCubemap = cubemap; }
|
||||
GFXTexHandle getCubemap() const { return mCubemap; }
|
||||
void setCubemap(GFXTexHandle cubemap ) { mCubemap = cubemap; }
|
||||
|
||||
///@see mFadeOverride
|
||||
F32 getFadeOverride() const { return mFadeOverride; }
|
||||
|
|
|
|||
Loading…
Reference in a new issue