From f1fcce3ea0b96df13d7338c6aee3c8b4e74b1f37 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 11 May 2015 10:47:45 -0700 Subject: [PATCH] refactoring th ecube texure loading to support 2 different layouts --- libraries/gpu/src/gpu/GLBackendTexture.cpp | 123 ++++++++--------- libraries/gpu/src/gpu/Texture.cpp | 139 ++++++++++++++------ libraries/gpu/src/gpu/Texture.h | 77 +++++++---- libraries/model/src/model/Skybox.slv | 2 - libraries/render-utils/src/TextureCache.cpp | 35 ++++- 5 files changed, 235 insertions(+), 141 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index fa4e4c93ea..999173e5b7 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -295,8 +295,8 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { glBindTexture(GL_TEXTURE_2D, object->_texture); if (needUpdate) { - if (texture.isStoredMipAvailable(0)) { - Texture::PixelsPointer mip = texture.accessStoredMip(0); + if (texture.isStoredMipFaceAvailable(0)) { + Texture::PixelsPointer mip = texture.accessStoredMipFace(0); const GLvoid* bytes = mip->_sysmem.read(); Element srcFormat = mip->_format; @@ -318,15 +318,15 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { // At this point the mip piels have been loaded, we can notify - texture.notifyGPULoaded(0); + texture.notifyMipFaceGPULoaded(0, 0); object->_contentStamp = texture.getDataStamp(); } } else { const GLvoid* bytes = 0; Element srcFormat = texture.getTexelFormat(); - if (texture.isStoredMipAvailable(0)) { - Texture::PixelsPointer mip = texture.accessStoredMip(0); + if (texture.isStoredMipFaceAvailable(0)) { + Texture::PixelsPointer mip = texture.accessStoredMipFace(0); bytes = mip->_sysmem.read(); srcFormat = mip->_format; @@ -352,10 +352,11 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { syncSampler(texture.getSampler(), texture.getType(), object); - // At this point the mip piels have been loaded, we can notify - texture.notifyGPULoaded(0); + // At this point the mip pixels have been loaded, we can notify + texture.notifyMipFaceGPULoaded(0, 0); object->_storageStamp = texture.getStamp(); + object->_contentStamp = texture.getDataStamp(); object->_size = texture.getSize(); } @@ -370,75 +371,57 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture); const int NUM_FACES = 6; const GLenum FACE_LAYOUT[] = { -/* GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_X }; - */ GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; - - /* GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; -*/ - /* GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z };*/ if (needUpdate) { - if (texture.isStoredMipAvailable(0)) { - Texture::PixelsPointer mip = texture.accessStoredMip(0); - Element srcFormat = mip->_format; - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - - uint16 width = texture.getWidth(); - int faceSize = mip->_sysmem.getSize() / NUM_FACES; - - glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture); - for (int f = 0; f < NUM_FACES; f++) { - glTexSubImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, width, width, 0, - texelFormat.format, texelFormat.type, (GLvoid*) (mip->_sysmem.read() + f * faceSize)); - } - - if (texture.isAutogenerateMips()) { - glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - - object->_target = GL_TEXTURE_CUBE_MAP; - - syncSampler(texture.getSampler(), texture.getType(), object); - - // At this point the mip piels have been loaded, we can notify - texture.notifyGPULoaded(0); - - object->_contentStamp = texture.getDataStamp(); - } - } else { - const gpu::Byte* bytes = 0; - Element srcFormat = texture.getTexelFormat(); - uint16 width = texture.getWidth(); - int faceSize = 0; - - if (texture.isStoredMipAvailable(0)) { - Texture::PixelsPointer mip = texture.accessStoredMip(0); - - bytes = mip->_sysmem.read(); - srcFormat = mip->_format; - faceSize = mip->_sysmem.getSize() / NUM_FACES; - - object->_contentStamp = texture.getDataStamp(); - } - - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture); + + // transfer pixels from each faces for (int f = 0; f < NUM_FACES; f++) { - glTexImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, width, width, 0, - texelFormat.format, texelFormat.type, (GLvoid*) (bytes + f * faceSize)); + if (texture.isStoredMipFaceAvailable(0, f)) { + Texture::PixelsPointer mipFace = texture.accessStoredMipFace(0, f); + Element srcFormat = mipFace->_format; + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); + + glTexSubImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, texture.getWidth(), texture.getWidth(), 0, + texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->_sysmem.read())); + + // At this point the mip pixels have been loaded, we can notify + texture.notifyMipFaceGPULoaded(0, f); + } } - if (bytes && texture.isAutogenerateMips()) { + if (texture.isAutogenerateMips()) { + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } + + object->_target = GL_TEXTURE_CUBE_MAP; + + syncSampler(texture.getSampler(), texture.getType(), object); + + object->_contentStamp = texture.getDataStamp(); + + } else { + glBindTexture(GL_TEXTURE_CUBE_MAP, object->_texture); + + // transfer pixels from each faces + for (int f = 0; f < NUM_FACES; f++) { + if (texture.isStoredMipFaceAvailable(0, f)) { + Texture::PixelsPointer mipFace = texture.accessStoredMipFace(0, f); + Element srcFormat = mipFace->_format; + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); + + glTexImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, texture.getWidth(), texture.getWidth(), 0, + texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->_sysmem.read())); + + // At this point the mip pixels have been loaded, we can notify + texture.notifyMipFaceGPULoaded(0, f); + } + } + + if (texture.isAutogenerateMips()) { glGenerateMipmap(GL_TEXTURE_CUBE_MAP); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); } else { @@ -450,10 +433,8 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { syncSampler(texture.getSampler(), texture.getType(), object); - // At this point the mip piels have been loaded, we can notify - texture.notifyGPULoaded(0); - object->_storageStamp = texture.getStamp(); + object->_contentStamp = texture.getDataStamp(); object->_size = texture.getSize(); } diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index d4891fcf7c..07bb73a375 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -28,69 +28,103 @@ Texture::Pixels::~Pixels() { void Texture::Storage::assignTexture(Texture* texture) { _texture = texture; -} - -Stamp Texture::Storage::getStamp(uint16 level) const { - PixelsPointer mip = getMip(level); - if (mip) { - return mip->_sysmem.getStamp(); + if (_texture) { + _type = _texture->getType(); } - return 0; } void Texture::Storage::reset() { _mips.clear(); + bumpStamp(); } -Texture::PixelsPointer Texture::Storage::editMip(uint16 level) { +Texture::PixelsPointer Texture::Storage::editMipFace(uint16 level, uint8 face) { if (level < _mips.size()) { - return _mips[level]; + assert(face < _mips[level].size()); + bumpStamp(); + return _mips[level][face]; } return PixelsPointer(); } -const Texture::PixelsPointer Texture::Storage::getMip(uint16 level) const { +const Texture::PixelsPointer Texture::Storage::getMipFace(uint16 level, uint8 face) const { if (level < _mips.size()) { - return _mips[level]; + assert(face < _mips[level].size()); + return _mips[level][face]; } return PixelsPointer(); } -void Texture::Storage::notifyGPULoaded(uint16 level) const { - PixelsPointer mip = getMip(level); - if (mip) { - mip->_isGPULoaded = true; - mip->_sysmem.resize(0); +void Texture::Storage::notifyMipFaceGPULoaded(uint16 level, uint8 face) const { + PixelsPointer mipFace = getMipFace(level, face); + if (mipFace) { + mipFace->_isGPULoaded = true; + mipFace->_sysmem.resize(0); } } -bool Texture::Storage::isMipAvailable(uint16 level) const { - PixelsPointer mip = getMip(level); - return (mip && mip->_sysmem.getSize()); +bool Texture::Storage::isMipAvailable(uint16 level, uint8 face) const { + PixelsPointer mipFace = getMipFace(level, face); + return (mipFace && mipFace->_sysmem.getSize()); } bool Texture::Storage::allocateMip(uint16 level) { bool changed = false; if (level >= _mips.size()) { - _mips.resize(level+1, PixelsPointer()); + _mips.resize(level+1, std::vector(Texture::NUM_FACES_PER_TYPE[getType()])); changed = true; } - if (!_mips[level]) { - _mips[level] = PixelsPointer(new Pixels()); - changed = true; + auto& mip = _mips[level]; + for (auto& face : mip) { + if (!face) { + face.reset(new Pixels()); + changed = true; + } } + bumpStamp(); + return changed; } bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes) { - // Ok we should be able to do that... + + allocateMip(level); + auto& mip = _mips[level]; + + // here we grabbed an array of faces + // The bytes assigned here are supposed to contain all the faces bytes of the mip. + // For tex1D, 2D, 3D there is only one face + // For Cube, we expect the 6 faces in the order X+, X-, Y+, Y-, Z+, Z- + int sizePerFace = size / mip.size(); + auto faceBytes = bytes; + Size allocated = 0; + for (auto& face : mip) { + face->_format = format; + allocated += face->_sysmem.setData(sizePerFace, faceBytes); + face->_isGPULoaded = false; + faceBytes += sizePerFace; + } + + bumpStamp(); + + return allocated == size; +} + + +bool Texture::Storage::assignMipFaceData(uint16 level, const Element& format, Size size, const Byte* bytes, uint8 face) { + allocateMip(level); auto mip = _mips[level]; - mip->_format = format; - Size allocated = mip->_sysmem.setData(size, bytes); - mip->_isGPULoaded = false; + Size allocated = 0; + if (face < mip.size()) { + auto mipFace = mip[face]; + mipFace->_format = format; + allocated += mipFace->_sysmem.setData(size, bytes); + mipFace->_isGPULoaded = false; + bumpStamp(); + } return allocated == size; } @@ -115,8 +149,8 @@ Texture* Texture::create(Type type, const Element& texelFormat, uint16 width, ui { Texture* tex = new Texture(); tex->_storage.reset(new Storage()); - tex->_storage->_texture = tex; tex->_type = type; + tex->_storage->assignTexture(tex); tex->_maxMip = 0; tex->resize(type, texelFormat, width, height, depth, numSamples, numSlices); @@ -275,6 +309,37 @@ bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, co return false; } + +bool Texture::assignStoredMipFace(uint16 level, const Element& format, Size size, const Byte* bytes, uint8 face) { + // Check that level accessed make sense + if (level != 0) { + if (_autoGenerateMips) { + return false; + } + if (level >= evalNumMips()) { + return false; + } + } + + // THen check that the mem buffer passed make sense with its format + Size expectedSize = evalStoredMipFaceSize(level, format); + if (size == expectedSize) { + _storage->assignMipFaceData(level, format, size, bytes, face); + _stamp++; + return true; + } else if (size > expectedSize) { + // NOTE: We are facing this case sometime because apparently QImage (from where we get the bits) is generating images + // and alligning the line of pixels to 32 bits. + // We should probably consider something a bit more smart to get the correct result but for now (UI elements) + // it seems to work... + _storage->assignMipFaceData(level, format, size, bytes, face); + _stamp++; + return true; + } + + return false; +} + uint16 Texture::autoGenerateMips(uint16 maxMip) { _autoGenerateMips = true; _maxMip = std::min((uint16) (evalNumMips() - 1), maxMip); @@ -283,15 +348,15 @@ uint16 Texture::autoGenerateMips(uint16 maxMip) { } uint16 Texture::getStoredMipWidth(uint16 level) const { - PixelsPointer mip = accessStoredMip(level); - if (mip && mip->_sysmem.getSize()) { + PixelsPointer mipFace = accessStoredMipFace(level); + if (mipFace && mipFace->_sysmem.getSize()) { return evalMipWidth(level); } return 0; } uint16 Texture::getStoredMipHeight(uint16 level) const { - PixelsPointer mip = accessStoredMip(level); + PixelsPointer mip = accessStoredMipFace(level); if (mip && mip->_sysmem.getSize()) { return evalMipHeight(level); } @@ -299,24 +364,24 @@ uint16 Texture::getStoredMipHeight(uint16 level) const { } uint16 Texture::getStoredMipDepth(uint16 level) const { - PixelsPointer mip = accessStoredMip(level); - if (mip && mip->_sysmem.getSize()) { + PixelsPointer mipFace = accessStoredMipFace(level); + if (mipFace && mipFace->_sysmem.getSize()) { return evalMipDepth(level); } return 0; } uint32 Texture::getStoredMipNumTexels(uint16 level) const { - PixelsPointer mip = accessStoredMip(level); - if (mip && mip->_sysmem.getSize()) { + PixelsPointer mipFace = accessStoredMipFace(level); + if (mipFace && mipFace->_sysmem.getSize()) { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); } return 0; } uint32 Texture::getStoredMipSize(uint16 level) const { - PixelsPointer mip = accessStoredMip(level); - if (mip && mip->_sysmem.getSize()) { + PixelsPointer mipFace = accessStoredMipFace(level); + if (mipFace && mipFace->_sysmem.getSize()) { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize(); } return 0; diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 19add9a47e..35e7b9a4b7 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -112,28 +112,6 @@ public: }; typedef std::shared_ptr< Pixels > PixelsPointer; - class Storage { - public: - Storage() {} - virtual ~Storage() {} - virtual void reset(); - virtual PixelsPointer editMip(uint16 level); - virtual const PixelsPointer getMip(uint16 level) const; - virtual Stamp getStamp(uint16 level) const; - virtual bool allocateMip(uint16 level); - virtual bool assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes); - virtual bool isMipAvailable(uint16 level) const; - virtual void notifyGPULoaded(uint16 level) const; - - protected: - Texture* _texture; - std::vector _mips; - - virtual void assignTexture(Texture* tex); - - friend class Texture; - }; - enum Type { TEX_1D = 0, TEX_2D, @@ -143,6 +121,39 @@ public: NUM_TYPES, }; + class Storage { + public: + Storage() {} + virtual ~Storage() {} + virtual void reset(); + virtual PixelsPointer editMipFace(uint16 level, uint8 face = 0); + virtual const PixelsPointer getMipFace(uint16 level, uint8 face = 0) const; + virtual bool allocateMip(uint16 level); + virtual bool assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes); + virtual bool assignMipFaceData(uint16 level, const Element& format, Size size, const Byte* bytes, uint8 face); + virtual bool isMipAvailable(uint16 level, uint8 face = 0) const; + + Texture::Type getType() const { return _type; } + + Stamp getStamp() const { return _stamp; } + Stamp bumpStamp() { return ++_stamp; } + protected: + Stamp _stamp = 0; + Texture* _texture = nullptr; + Texture::Type _type = Texture::TEX_2D; // The type of texture is needed to know the number of faces to expect + std::vector> _mips; // an array of mips, each mip is an array of faces + + virtual void assignTexture(Texture* tex); // Texture storage is pointing to ONE corrresponding Texture. + const Texture* getTexture() const { return _texture; } + + friend class Texture; + + // THis should be only called by the Texture from the Backend to notify the storage that the specified mip face pixels + // have been uploaded to the GPU memory. IT is possible for the storage to free the system memory then + virtual void notifyMipFaceGPULoaded(uint16 level, uint8 face) const; + }; + + static Texture* create1D(const Element& texelFormat, uint16 width, const Sampler& sampler = Sampler()); static Texture* create2D(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler = Sampler()); static Texture* create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, const Sampler& sampler = Sampler()); @@ -155,7 +166,7 @@ public: ~Texture(); Stamp getStamp() const { return _stamp; } - Stamp getDataStamp(uint16 level = 0) const { return _storage->getStamp(level); } + Stamp getDataStamp() const { return _storage->getStamp(); } // The size in bytes of data stored in the texture Size getSize() const { return _size; } @@ -214,8 +225,16 @@ public: uint16 evalMipWidth(uint16 level) const { return std::max(_width >> level, 1); } uint16 evalMipHeight(uint16 level) const { return std::max(_height >> level, 1); } uint16 evalMipDepth(uint16 level) const { return std::max(_depth >> level, 1); } - uint32 evalMipNumTexels(uint16 level) const { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getNumFaces(); } + + // Size for each face of a mip at a particular level + uint32 evalMipFaceNumTexels(uint16 level) const { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); } + uint32 evalMipFaceSize(uint16 level) const { return evalMipFaceNumTexels(level) * getTexelFormat().getSize(); } + + // Total size for the mip + uint32 evalMipNumTexels(uint16 level) const { return evalMipFaceNumTexels(level) * getNumFaces(); } uint32 evalMipSize(uint16 level) const { return evalMipNumTexels(level) * getTexelFormat().getSize(); } + + uint32 evalStoredMipFaceSize(uint16 level, const Element& format) const { return evalMipFaceNumTexels(level) * format.getSize(); } uint32 evalStoredMipSize(uint16 level, const Element& format) const { return evalMipNumTexels(level) * format.getSize(); } uint32 evalTotalSize() const { @@ -256,11 +275,11 @@ public: // Explicitely assign mip data for a certain level // If Bytes is NULL then simply allocate the space so mip sysmem can be accessed bool assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes); + bool assignStoredMipFace(uint16 level, const Element& format, Size size, const Byte* bytes, uint8 face); // Access the the sub mips - bool isStoredMipAvailable(uint16 level) const { return _storage->isMipAvailable(level); } - const PixelsPointer accessStoredMip(uint16 level) const { return _storage->getMip(level); } - void notifyGPULoaded(uint16 level) const { return _storage->notifyGPULoaded(level); } + bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const { return _storage->isMipAvailable(level, face); } + const PixelsPointer accessStoredMipFace(uint16 level, uint8 face = 0) const { return _storage->getMipFace(level, face); } // access sizes for the stored mips uint16 getStoredMipWidth(uint16 level) const; @@ -277,6 +296,9 @@ public: const Sampler& getSampler() const { return _sampler; } Stamp getSamplerStamp() const { return _samplerStamp; } + // Only callable by the Backend + void notifyMipFaceGPULoaded(uint16 level, uint8 face) const { return _storage->notifyMipFaceGPULoaded(level, face); } + protected: std::unique_ptr< Storage > _storage; @@ -310,6 +332,7 @@ protected: mutable GPUObject* _gpuObject = NULL; void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } GPUObject* getGPUObject() const { return _gpuObject; } + friend class Backend; }; diff --git a/libraries/model/src/model/Skybox.slv b/libraries/model/src/model/Skybox.slv index 3c7ffbce2d..1236e0d384 100755 --- a/libraries/model/src/model/Skybox.slv +++ b/libraries/model/src/model/Skybox.slv @@ -31,9 +31,7 @@ void main(void) { vec3 eyeDir; <$transformClipToEyeDir(cam, clipDir, eyeDir)$>; - normal = normalize(eyeDir); <$transformEyeToWorldDir(cam, eyeDir, normal)$>; - normal = normalize(normal); // Position is supposed to cmoe in clip space gl_Position = vec4(texcoord.xy, 0.0, 1.0); diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 9a1b0da709..803350629d 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -524,10 +524,37 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo } if (_type == CUBE_TEXTURE) { - if (_height >= (6 * _width)) { - _gpuTexture = gpu::TexturePointer(gpu::Texture::createCube(formatGPU, image.width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP))); - _gpuTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); - _gpuTexture->autoGenerateMips(-1); + _gpuTexture = gpu::TexturePointer(gpu::Texture::createCube(formatGPU, image.width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP))); + _gpuTexture->autoGenerateMips(-1); + + std::vector faces; + if (_height == (6 * _width)) { + int faceWidth = _width; + + faces.push_back(image.copy(QRect(0, 0 * faceWidth, faceWidth, faceWidth))); + faces.push_back(image.copy(QRect(0, 1 * faceWidth, faceWidth, faceWidth))); + faces.push_back(image.copy(QRect(0, 2 * faceWidth, faceWidth, faceWidth))); + faces.push_back(image.copy(QRect(0, 3 * faceWidth, faceWidth, faceWidth))); + faces.push_back(image.copy(QRect(0, 4 * faceWidth, faceWidth, faceWidth))); + faces.push_back(image.copy(QRect(0, 5 * faceWidth, faceWidth, faceWidth))); + } else if ((_height / 3) == (_width / 4)) { + int faceWidth = _height / 3; + faces.push_back(image.copy(QRect(2 * faceWidth, faceWidth, faceWidth, faceWidth))); + faces.push_back(image.copy(QRect(0 * faceWidth, faceWidth, faceWidth, faceWidth))); + + faces.push_back(image.copy(QRect(1 * faceWidth, 0, faceWidth, faceWidth))); + faces.push_back(image.copy(QRect(1 * faceWidth, 0 * faceWidth, faceWidth, faceWidth))); + + faces.push_back(image.copy(QRect(3 * faceWidth, faceWidth, faceWidth, faceWidth))); + faces.push_back(image.copy(QRect(1 * faceWidth, faceWidth, faceWidth, faceWidth))); + } + + if (faces.size() == _gpuTexture->getNumFaces()) { + int f = 0; + for (auto& face : faces) { + _gpuTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f); + f++; + } } } else { _gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));