mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-02-21 07:33:45 +00:00
Update GFXTextureManager and GBitmap
GBitmap Changes: Added all other formats to gbitmap that we support gbitmap now supports cubemaps added converters for all these other formats added stb_image_resize for extrudemips so we can extrude mipmaps for all other formats GFXTextureManager Can now directly make cubemaps and texture arrays based on the GFXTextureProfile API implementations for all functions that cubemaps and arrays needed
This commit is contained in:
parent
975fc924cc
commit
3aef90a6bc
66 changed files with 4235 additions and 2590 deletions
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue