2019-11-23 20:27:39 +08:00
|
|
|
/****************************************************************************
|
|
|
|
Copyright (c) 2015-2016 Chukong Technologies Inc.
|
|
|
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
2021-12-25 10:04:45 +08:00
|
|
|
|
2022-01-04 12:36:20 +08:00
|
|
|
https://adxeproject.github.io/
|
2021-12-25 10:04:45 +08:00
|
|
|
|
2019-11-23 20:27:39 +08:00
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
2021-12-25 10:04:45 +08:00
|
|
|
|
2019-11-23 20:27:39 +08:00
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
2021-12-25 10:04:45 +08:00
|
|
|
|
2019-11-23 20:27:39 +08:00
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS 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.
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include "renderer/CCTextureCube.h"
|
|
|
|
#include "platform/CCImage.h"
|
|
|
|
#include "platform/CCFileUtils.h"
|
|
|
|
#include "renderer/backend/Texture.h"
|
|
|
|
#include "renderer/backend/Device.h"
|
2020-09-25 11:07:56 +08:00
|
|
|
#include "renderer/backend/TextureUtils.h"
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
NS_CC_BEGIN
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
unsigned char* getImageData(Image* img, backend::PixelFormat& ePixFmt)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
unsigned char* pTmpData = img->getData();
|
|
|
|
unsigned int* inPixel32 = nullptr;
|
|
|
|
unsigned char* inPixel8 = nullptr;
|
|
|
|
unsigned short* outPixel16 = nullptr;
|
|
|
|
bool bHasAlpha = img->hasAlpha();
|
|
|
|
size_t uBPP = img->getBitPerPixel();
|
2019-11-23 20:27:39 +08:00
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
int nWidth = img->getWidth();
|
|
|
|
int nHeight = img->getHeight();
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
// compute pixel format
|
|
|
|
if (bHasAlpha)
|
|
|
|
{
|
2020-09-25 11:07:56 +08:00
|
|
|
ePixFmt = backend::PixelFormat::RGBA8;
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (uBPP >= 8)
|
|
|
|
{
|
2020-09-25 11:07:56 +08:00
|
|
|
ePixFmt = backend::PixelFormat::RGB8;
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ePixFmt = backend::PixelFormat::RGB565;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Repack the pixel data into the right format
|
|
|
|
unsigned int uLen = nWidth * nHeight;
|
|
|
|
|
|
|
|
if (ePixFmt == backend::PixelFormat::RGB565)
|
|
|
|
{
|
|
|
|
if (bHasAlpha)
|
|
|
|
{
|
|
|
|
// Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB"
|
2021-12-25 10:04:45 +08:00
|
|
|
inPixel32 = (unsigned int*)img->getData();
|
|
|
|
pTmpData = (unsigned char*)malloc(nWidth * nHeight * 2);
|
2019-11-23 20:27:39 +08:00
|
|
|
outPixel16 = (unsigned short*)pTmpData;
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < uLen; ++i, ++inPixel32)
|
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
*outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R
|
|
|
|
((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | // G
|
|
|
|
((((*inPixel32 >> 16) & 0xFF) >> 3) << 0); // B
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Convert "RRRRRRRRGGGGGGGGBBBBBBBB" to "RRRRRGGGGGGBBBBB"
|
2021-12-25 10:04:45 +08:00
|
|
|
pTmpData = (unsigned char*)malloc(nWidth * nHeight * 2);
|
2019-11-23 20:27:39 +08:00
|
|
|
outPixel16 = (unsigned short*)pTmpData;
|
2021-12-25 10:04:45 +08:00
|
|
|
inPixel8 = (unsigned char*)img->getData();
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
for (unsigned int i = 0; i < uLen; ++i)
|
|
|
|
{
|
|
|
|
unsigned char R = *inPixel8++;
|
|
|
|
unsigned char G = *inPixel8++;
|
|
|
|
unsigned char B = *inPixel8++;
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
*outPixel16++ = ((R >> 3) << 11) | // R
|
|
|
|
((G >> 2) << 5) | // G
|
|
|
|
((B >> 3) << 0); // B
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-25 11:07:56 +08:00
|
|
|
if (bHasAlpha && ePixFmt == backend::PixelFormat::RGB8)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
// Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRRRRGGGGGGGGBBBBBBBB"
|
|
|
|
inPixel32 = (unsigned int*)img->getData();
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
pTmpData = (unsigned char*)malloc(nWidth * nHeight * 3);
|
2019-11-23 20:27:39 +08:00
|
|
|
unsigned char* outPixel8 = pTmpData;
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < uLen; ++i, ++inPixel32)
|
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
*outPixel8++ = (*inPixel32 >> 0) & 0xFF; // R
|
|
|
|
*outPixel8++ = (*inPixel32 >> 8) & 0xFF; // G
|
|
|
|
*outPixel8++ = (*inPixel32 >> 16) & 0xFF; // B
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pTmpData;
|
|
|
|
}
|
|
|
|
|
2021-12-31 12:12:40 +08:00
|
|
|
Image* createImage(std::string_view path)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
// Split up directory and filename
|
|
|
|
// MUTEX:
|
|
|
|
// Needed since addImageAsync calls this method from a different thread
|
|
|
|
|
|
|
|
std::string fullpath = FileUtils::getInstance()->fullPathForFilename(path);
|
2020-08-18 14:29:09 +08:00
|
|
|
if (fullpath.empty())
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// all images are handled by UIImage except PVR extension that is handled by our own handler
|
2021-12-08 00:11:53 +08:00
|
|
|
Image* image = new Image();
|
|
|
|
if (image->initWithImageFile(fullpath))
|
|
|
|
return image;
|
2021-12-25 10:04:45 +08:00
|
|
|
|
2021-12-08 00:11:53 +08:00
|
|
|
delete image;
|
|
|
|
return nullptr;
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TextureCube::TextureCube()
|
|
|
|
{
|
|
|
|
_imgPath.resize(6);
|
|
|
|
}
|
|
|
|
|
|
|
|
TextureCube::~TextureCube()
|
|
|
|
{
|
|
|
|
CC_SAFE_RELEASE_NULL(_texture);
|
|
|
|
}
|
|
|
|
|
2021-12-31 12:12:40 +08:00
|
|
|
TextureCube* TextureCube::create(std::string_view positive_x,
|
|
|
|
std::string_view negative_x,
|
|
|
|
std::string_view positive_y,
|
|
|
|
std::string_view negative_y,
|
|
|
|
std::string_view positive_z,
|
|
|
|
std::string_view negative_z)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
2021-12-08 00:11:53 +08:00
|
|
|
auto ret = new TextureCube();
|
|
|
|
if (ret->init(positive_x, negative_x, positive_y, negative_y, positive_z, negative_z))
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
ret->autorelease();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
CC_SAFE_DELETE(ret);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2021-12-31 12:12:40 +08:00
|
|
|
bool TextureCube::init(std::string_view positive_x,
|
|
|
|
std::string_view negative_x,
|
|
|
|
std::string_view positive_y,
|
|
|
|
std::string_view negative_y,
|
|
|
|
std::string_view positive_z,
|
|
|
|
std::string_view negative_z)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
_imgPath[0] = positive_x;
|
|
|
|
_imgPath[1] = negative_x;
|
|
|
|
_imgPath[2] = positive_y;
|
|
|
|
_imgPath[3] = negative_y;
|
|
|
|
_imgPath[4] = positive_z;
|
|
|
|
_imgPath[5] = negative_z;
|
|
|
|
|
|
|
|
std::vector<Image*> images(6);
|
|
|
|
|
|
|
|
images[0] = createImage(positive_x);
|
|
|
|
images[1] = createImage(negative_x);
|
|
|
|
images[2] = createImage(positive_y);
|
|
|
|
images[3] = createImage(negative_y);
|
|
|
|
images[4] = createImage(positive_z);
|
|
|
|
images[5] = createImage(negative_z);
|
|
|
|
|
|
|
|
int imageSize = images[0]->getHeight();
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
{
|
|
|
|
Image* img = images[i];
|
2021-12-25 10:04:45 +08:00
|
|
|
if (img->getWidth() != img->getHeight())
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
CCASSERT(false, "TextureCubemap: width should be equal to height!");
|
|
|
|
return false;
|
|
|
|
}
|
2021-12-25 10:04:45 +08:00
|
|
|
if (imageSize != img->getWidth())
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
CCASSERT(imageSize == img->getWidth(), "TextureCubmap: texture of each face should have same dimension");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
backend::TextureDescriptor textureDescriptor;
|
|
|
|
textureDescriptor.width = textureDescriptor.height = imageSize;
|
2021-12-25 10:04:45 +08:00
|
|
|
textureDescriptor.textureType = backend::TextureType::TEXTURE_CUBE;
|
|
|
|
textureDescriptor.samplerDescriptor.minFilter = backend::SamplerFilter::LINEAR;
|
|
|
|
textureDescriptor.samplerDescriptor.magFilter = backend::SamplerFilter::LINEAR;
|
|
|
|
textureDescriptor.samplerDescriptor.sAddressMode = backend::SamplerAddressMode::CLAMP_TO_EDGE;
|
|
|
|
textureDescriptor.samplerDescriptor.tAddressMode = backend::SamplerAddressMode::CLAMP_TO_EDGE;
|
|
|
|
_texture =
|
|
|
|
static_cast<backend::TextureCubemapBackend*>(backend::Device::getInstance()->newTexture(textureDescriptor));
|
2019-11-23 20:27:39 +08:00
|
|
|
CCASSERT(_texture != nullptr, "TextureCubemap: texture can not be nullptr");
|
|
|
|
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
{
|
|
|
|
Image* img = images[i];
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
backend::PixelFormat ePixelFmt;
|
|
|
|
unsigned char* pData = getImageData(img, ePixelFmt);
|
|
|
|
uint8_t* cData = nullptr;
|
|
|
|
uint8_t* useData = pData;
|
2019-11-23 20:27:39 +08:00
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
// convert pixel format to RGBA
|
2020-09-25 11:07:56 +08:00
|
|
|
if (ePixelFmt != backend::PixelFormat::RGBA8)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
size_t len = 0;
|
2021-12-25 10:04:45 +08:00
|
|
|
backend::PixelFormatUtils::convertDataToFormat(pData, img->getDataLen(), ePixelFmt,
|
|
|
|
backend::PixelFormat::RGBA8, &cData, &len);
|
|
|
|
if (cData != pData) // convert error
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
useData = cData;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
CCASSERT(false,
|
|
|
|
"error: CubeMap texture may be incorrect, failed to convert pixel format data to RGBA8888");
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_texture->updateFaceData(static_cast<backend::TextureCubeFace>(i), useData);
|
2021-12-25 10:04:45 +08:00
|
|
|
|
2019-11-23 20:27:39 +08:00
|
|
|
if (cData != pData)
|
|
|
|
free(cData);
|
|
|
|
|
|
|
|
if (pData != img->getData())
|
|
|
|
free(pData);
|
|
|
|
}
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
for (auto img : images)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
CC_SAFE_RELEASE(img);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextureCube::setTexParameters(const Texture2D::TexParams& texParams)
|
|
|
|
{
|
|
|
|
_texture->updateSamplerDescriptor(texParams);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TextureCube::reloadTexture()
|
|
|
|
{
|
|
|
|
return init(_imgPath[0], _imgPath[1], _imgPath[2], _imgPath[3], _imgPath[4], _imgPath[5]);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_CC_END
|