no message
This commit is contained in:
109
cocos/core/assets/Asset.cpp
Normal file
109
cocos/core/assets/Asset.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "core/assets/Asset.h"
|
||||
#include "base/DeferredReleasePool.h"
|
||||
#include "base/Macros.h"
|
||||
#include "core/utils/Path.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
//cjh TODO:
|
||||
ccstd::string getAssetUrlWithUuid(const ccstd::string &uuid, bool isNative, const ccstd::string &nativeExt, const ccstd::string &nativeName = "") { //NOLINT
|
||||
return "";
|
||||
}
|
||||
|
||||
ccstd::string Asset::getNativeUrl() const {
|
||||
if (_nativeUrl.empty()) {
|
||||
if (_native.empty()) {
|
||||
return "";
|
||||
}
|
||||
const auto &name = _native;
|
||||
if (name[0] == 47) { // '/'
|
||||
// remove library tag
|
||||
// not imported in library, just created on-the-fly
|
||||
return name.substr(1);
|
||||
}
|
||||
|
||||
if (name[0] == 46) { // '.'
|
||||
// imported in dir where json exist
|
||||
const_cast<Asset *>(this)->_nativeUrl = getAssetUrlWithUuid(_uuid, true, name);
|
||||
} else {
|
||||
// imported in an independent dir
|
||||
const_cast<Asset *>(this)->_nativeUrl = getAssetUrlWithUuid(_uuid, true, extname(name), name);
|
||||
}
|
||||
}
|
||||
return _nativeUrl;
|
||||
}
|
||||
Asset::Asset() = default;
|
||||
Asset::~Asset() = default;
|
||||
|
||||
NativeDep Asset::getNativeDep() const {
|
||||
if (!_native.empty()) {
|
||||
return NativeDep(true, _uuid, _native);
|
||||
}
|
||||
return NativeDep();
|
||||
}
|
||||
|
||||
void Asset::setRawAsset(const ccstd::string &filename, bool inLibrary /* = true*/) {
|
||||
if (inLibrary) {
|
||||
_native = filename;
|
||||
} else {
|
||||
_native = "/" + filename; // simply use '/' to tag location where is not in the library
|
||||
}
|
||||
}
|
||||
|
||||
void Asset::addAssetRef() {
|
||||
++_assetRefCount;
|
||||
}
|
||||
|
||||
void Asset::decAssetRef(bool autoRelease /* = true*/) {
|
||||
if (_assetRefCount > 0) {
|
||||
--_assetRefCount;
|
||||
}
|
||||
|
||||
if (autoRelease) {
|
||||
//cjh TODO:
|
||||
}
|
||||
}
|
||||
|
||||
void Asset::initDefault(const ccstd::optional<ccstd::string> &uuid) {
|
||||
if (uuid.has_value()) {
|
||||
_uuid = uuid.value();
|
||||
}
|
||||
_isDefault = true;
|
||||
}
|
||||
|
||||
bool Asset::destroy() {
|
||||
//cjh TODO: debug(getError(12101, this._uuid));
|
||||
return Super::destroy();
|
||||
}
|
||||
|
||||
void Asset::destruct() {
|
||||
CCObject::destruct();
|
||||
_native.clear();
|
||||
_nativeUrl.clear();
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
159
cocos/core/assets/Asset.h
Normal file
159
cocos/core/assets/Asset.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include "base/std/any.h"
|
||||
#include "base/std/optional.h"
|
||||
|
||||
#include "base/Macros.h"
|
||||
#include "core/Types.h"
|
||||
#include "core/data/Object.h"
|
||||
#include "core/event/EventTarget.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class Node;
|
||||
|
||||
class Asset : public CCObject {
|
||||
public:
|
||||
using Super = CCObject;
|
||||
|
||||
Asset();
|
||||
~Asset() override;
|
||||
|
||||
/**
|
||||
* @en
|
||||
* Returns the url of this asset's native object, if none it will returns an empty string.
|
||||
* @zh
|
||||
* 返回该资源对应的目标平台资源的 URL,如果没有将返回一个空字符串。
|
||||
* @readOnly
|
||||
*/
|
||||
ccstd::string getNativeUrl() const;
|
||||
|
||||
NativeDep getNativeDep() const;
|
||||
|
||||
inline const ccstd::string &getUuid() const { return _uuid; }
|
||||
inline void setUuid(const ccstd::string &uuid) { _uuid = uuid; }
|
||||
|
||||
/**
|
||||
* @en
|
||||
* The underlying native asset of this asset if one is available.<br>
|
||||
* This property can be used to access additional details or functionality related to the asset.<br>
|
||||
* This property will be initialized by the loader if `_native` is available.
|
||||
* @zh
|
||||
* 此资源的基础资源(如果有)。 此属性可用于访问与资源相关的其他详细信息或功能。<br>
|
||||
* 如果`_native`可用,则此属性将由加载器初始化。
|
||||
* @default null
|
||||
* @private
|
||||
*/
|
||||
virtual ccstd::any getNativeAsset() const {
|
||||
return _file;
|
||||
}
|
||||
|
||||
virtual void setNativeAsset(const ccstd::any &obj) {
|
||||
_file = obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param error - null or the error info
|
||||
* @param node - the created node or null
|
||||
*/
|
||||
using CreateNodeCallback = std::function<void(Error, Node *)>;
|
||||
/**
|
||||
* @en
|
||||
* Create a new node using this asset in the scene.<br/>
|
||||
* If this type of asset don't have its corresponding node type, this method should be null.
|
||||
* @zh
|
||||
* 使用该资源在场景中创建一个新节点。<br/>
|
||||
* 如果这类资源没有相应的节点类型,该方法应该是空的。
|
||||
*/
|
||||
virtual void createNode(const CreateNodeCallback &cb) {}
|
||||
|
||||
void addAssetRef();
|
||||
void decAssetRef(bool autoRelease = true);
|
||||
inline uint32_t getAssetRefCount() const { return _assetRefCount; }
|
||||
|
||||
virtual void onLoaded() {}
|
||||
|
||||
virtual void initDefault() { initDefault(ccstd::nullopt); }
|
||||
|
||||
virtual void initDefault(const ccstd::optional<ccstd::string> &uuid);
|
||||
|
||||
virtual bool validate() const { return true; }
|
||||
|
||||
bool isDefault() const { return _isDefault; }
|
||||
|
||||
bool destroy() override;
|
||||
|
||||
void destruct() override;
|
||||
|
||||
// SERIALIZATION
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
virtual ccstd::any serialize(const ccstd::any & /*ctxForExporting*/) { return ccstd::any{}; };
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
virtual void deserialize(const ccstd::any &serializedData, const ccstd::any &handle) {}
|
||||
|
||||
ccstd::string toString() const override { return _nativeUrl; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @en
|
||||
* Set native file name for this asset.
|
||||
* @zh
|
||||
* 为此资源设置原始文件名。
|
||||
* @seealso nativeUrl
|
||||
*
|
||||
* @param filename
|
||||
* @param inLibrary
|
||||
* @private
|
||||
*/
|
||||
void setRawAsset(const ccstd::string &filename, bool inLibrary = true);
|
||||
|
||||
// Make _native, _nativeUrl public for deserialization
|
||||
public:
|
||||
ccstd::string _native;
|
||||
ccstd::string _nativeUrl;
|
||||
|
||||
protected:
|
||||
ccstd::string _uuid;
|
||||
|
||||
ccstd::any _file;
|
||||
uint32_t _assetRefCount{0};
|
||||
|
||||
bool _loaded{true};
|
||||
bool _isDefault{false};
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(Asset);
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
305
cocos/core/assets/AssetEnum.h
Normal file
305
cocos/core/assets/AssetEnum.h
Normal file
@@ -0,0 +1,305 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "renderer/gfx-base/GFXDef.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
// define a specified number for the pixel format which gfx do not have a standard definition.
|
||||
#define CUSTOM_PIXEL_FORMAT (1024)
|
||||
|
||||
/**
|
||||
* @en
|
||||
* The texture pixel format, default value is RGBA8888,<br>
|
||||
* you should note that textures loaded by normal image files (png, jpg) can only support RGBA8888 format,<br>
|
||||
* other formats are supported by compressed file types or raw data.
|
||||
* @zh
|
||||
* 纹理像素格式,默认值为RGBA8888,<br>
|
||||
* 你应该注意到普通图像文件(png,jpg)加载的纹理只能支持RGBA8888格式,<br>
|
||||
* 压缩文件类型或原始数据支持其他格式。
|
||||
*/
|
||||
enum class PixelFormat : uint32_t {
|
||||
/**
|
||||
* @en
|
||||
* 16-bit pixel format containing red, green and blue channels
|
||||
* @zh
|
||||
* 包含 RGB 通道的 16 位纹理。
|
||||
*/
|
||||
RGB565 = static_cast<uint32_t>(gfx::Format::R5G6B5),
|
||||
/**
|
||||
* @en
|
||||
* 16-bit pixel format containing red, green, blue channels with 5 bits per channel and one bit alpha channel: RGB5A1
|
||||
* @zh
|
||||
* 包含 RGB(分别占 5 bits)和 1 bit 的 alpha 通道的 16 位纹理:RGB5A1。
|
||||
*/
|
||||
RGB5A1 = static_cast<uint32_t>(gfx::Format::RGB5A1),
|
||||
/**
|
||||
* @en
|
||||
* 16-bit pixel format containing red, green, blue and alpha channels: RGBA4444
|
||||
* @zh
|
||||
* 包含 RGBA 通道的 16 位纹理:RGBA4444。
|
||||
*/
|
||||
RGBA4444 = static_cast<uint32_t>(gfx::Format::RGBA4),
|
||||
/**
|
||||
* @en
|
||||
* 24-bit pixel format containing red, green and blue channels: RGB888
|
||||
* @zh
|
||||
* 包含 RGB 通道的 24 位纹理:RGB888。
|
||||
*/
|
||||
RGB888 = static_cast<uint32_t>(gfx::Format::RGB8),
|
||||
/**
|
||||
* @en
|
||||
* 32-bit float pixel format containing red, green and blue channels: RGBA32F
|
||||
* @zh
|
||||
* 包含 RGB 通道的 32 位浮点数像素格式:RGBA32F。
|
||||
*/
|
||||
RGB32F = static_cast<uint32_t>(gfx::Format::RGB32F),
|
||||
/**
|
||||
* @en
|
||||
* 32-bit pixel format containing red, green, blue and alpha channels: RGBA8888
|
||||
* @zh
|
||||
* 包含 RGBA 四通道的 32 位整形像素格式:RGBA8888。
|
||||
*/
|
||||
RGBA8888 = static_cast<uint32_t>(gfx::Format::RGBA8),
|
||||
/**
|
||||
* @en
|
||||
* 32-bit float pixel format containing red, green, blue and alpha channels: RGBA32F
|
||||
* @zh
|
||||
* 32位浮点数像素格式:RGBA32F。
|
||||
*/
|
||||
RGBA32F = static_cast<uint32_t>(gfx::Format::RGBA32F),
|
||||
/**
|
||||
* @en
|
||||
* 8-bit pixel format used as masks
|
||||
* @zh
|
||||
* 用作蒙版的8位纹理。
|
||||
*/
|
||||
A8 = static_cast<uint32_t>(gfx::Format::A8),
|
||||
/**
|
||||
* @en
|
||||
* 8-bit intensity pixel format
|
||||
* @zh
|
||||
* 8位强度纹理。
|
||||
*/
|
||||
I8 = static_cast<uint32_t>(gfx::Format::L8),
|
||||
/**
|
||||
* @en
|
||||
* 16-bit pixel format used as masks
|
||||
* @zh
|
||||
* 用作蒙版的16位纹理。
|
||||
*/
|
||||
AI8 = static_cast<uint32_t>(gfx::Format::LA8),
|
||||
/**
|
||||
* @en A pixel format containing red, green, and blue channels that is PVR 2bpp compressed.
|
||||
* @zh 包含 RGB 通道的 PVR 2BPP 压缩纹理格式
|
||||
*/
|
||||
RGB_PVRTC_2BPPV1 = static_cast<uint32_t>(gfx::Format::PVRTC_RGB2),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is PVR 2bpp compressed.
|
||||
* @zh 包含 RGBA 通道的 PVR 2BPP 压缩纹理格式
|
||||
*/
|
||||
RGBA_PVRTC_2BPPV1 = static_cast<uint32_t>(gfx::Format::PVRTC_RGBA2),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is PVR 2bpp compressed.
|
||||
* RGB_A_PVRTC_2BPPV1 texture is a 2x height RGB_PVRTC_2BPPV1 format texture.
|
||||
* It separate the origin alpha channel to the bottom half atlas, the origin rgb channel to the top half atlas.
|
||||
* @zh 包含 RGBA 通道的 PVR 2BPP 压缩纹理格式
|
||||
* 这种压缩纹理格式贴图的高度是普通 RGB_PVRTC_2BPPV1 贴图高度的两倍,使用上半部分作为原始 RGB 通道数据,下半部分用来存储透明通道数据。
|
||||
*/
|
||||
RGB_A_PVRTC_2BPPV1 = CUSTOM_PIXEL_FORMAT,
|
||||
/**
|
||||
* @en A pixel format containing red, green, and blue channels that is PVR 4bpp compressed.
|
||||
* @zh 包含 RGB 通道的 PVR 4BPP 压缩纹理格式
|
||||
*/
|
||||
RGB_PVRTC_4BPPV1 = static_cast<uint32_t>(gfx::Format::PVRTC_RGB4),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue and alpha channels that is PVR 4bpp compressed.
|
||||
* @zh 包含 RGBA 通道的 PVR 4BPP 压缩纹理格式
|
||||
*/
|
||||
RGBA_PVRTC_4BPPV1 = static_cast<uint32_t>(gfx::Format::PVRTC_RGBA4),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is PVR 4bpp compressed.
|
||||
* RGB_A_PVRTC_4BPPV1 texture is a 2x height RGB_PVRTC_4BPPV1 format texture.
|
||||
* It separate the origin alpha channel to the bottom half atlas, the origin rgb channel to the top half atlas.
|
||||
* @zh 包含 RGBA 通道的 PVR 4BPP 压缩纹理格式
|
||||
* 这种压缩纹理格式贴图的高度是普通 RGB_PVRTC_4BPPV1 贴图高度的两倍,使用上半部分作为原始 RGB 通道数据,下半部分用来存储透明通道数据。
|
||||
*/
|
||||
RGB_A_PVRTC_4BPPV1 = CUSTOM_PIXEL_FORMAT + 1,
|
||||
/**
|
||||
* @en A pixel format containing red, green, and blue channels that is ETC1 compressed.
|
||||
* @zh 包含 RGB 通道的 ETC1 压缩纹理格式
|
||||
*/
|
||||
RGB_ETC1 = static_cast<uint32_t>(gfx::Format::ETC_RGB8),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ETC1 compressed.
|
||||
* @zh 包含 RGBA 通道的 ETC1 压缩纹理格式
|
||||
*/
|
||||
RGBA_ETC1 = CUSTOM_PIXEL_FORMAT + 2,
|
||||
/**
|
||||
* @en A pixel format containing red, green, and blue channels that is ETC2 compressed.
|
||||
* @zh 包含 RGB 通道的 ETC2 压缩纹理格式
|
||||
*/
|
||||
RGB_ETC2 = static_cast<uint32_t>(gfx::Format::ETC2_RGB8),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ETC2 compressed.
|
||||
* @zh 包含 RGBA 通道的 ETC2 压缩纹理格式
|
||||
*/
|
||||
RGBA_ETC2 = static_cast<uint32_t>(gfx::Format::ETC2_RGBA8),
|
||||
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 4x4 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 4x4
|
||||
*/
|
||||
RGBA_ASTC_4X4 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_4X4),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 5x4 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 5x4
|
||||
*/
|
||||
RGBA_ASTC_5X4 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_5X4),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 5x5 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 5x5
|
||||
*/
|
||||
RGBA_ASTC_5X5 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_5X5),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 6x5 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 6x5
|
||||
*/
|
||||
RGBA_ASTC_6X5 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_6X5),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 6x6 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 6x6
|
||||
*/
|
||||
RGBA_ASTC_6X6 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_6X6),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 8x5 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 8x5
|
||||
*/
|
||||
RGBA_ASTC_8X5 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_8X5),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 8x6 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 8x6
|
||||
*/
|
||||
RGBA_ASTC_8X6 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_8X6),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 8x8 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 8x8
|
||||
*/
|
||||
RGBA_ASTC_8X8 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_8X8),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 10x5 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 10x5
|
||||
*/
|
||||
RGBA_ASTC_10X5 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_10X5),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 10x6 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 10x6
|
||||
*/
|
||||
RGBA_ASTC_10X6 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_10X6),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 10x8 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 10x8
|
||||
*/
|
||||
RGBA_ASTC_10X8 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_10X8),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 10x10 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 10x10
|
||||
*/
|
||||
RGBA_ASTC_10X10 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_10X10),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 12x10 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 12x10
|
||||
*/
|
||||
RGBA_ASTC_12X10 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_12X10),
|
||||
/**
|
||||
* @en A pixel format containing red, green, blue, and alpha channels that is ASTC compressed with 12x12 block size.
|
||||
* @zh 包含 RGBA 通道的 ASTC 压缩纹理格式,压缩分块大小为 12x12
|
||||
*/
|
||||
RGBA_ASTC_12X12 = static_cast<uint32_t>(gfx::Format::ASTC_RGBA_12X12),
|
||||
};
|
||||
|
||||
/**
|
||||
* @en
|
||||
* The texture wrap mode.
|
||||
* @zh
|
||||
* 纹理环绕方式。
|
||||
*/
|
||||
enum class WrapMode : uint32_t {
|
||||
/**
|
||||
* @en
|
||||
* Specifies that the repeat warp mode will be used.
|
||||
* @zh
|
||||
* 指定环绕模式:重复纹理图像。
|
||||
*/
|
||||
REPEAT = static_cast<uint32_t>(gfx::Address::WRAP),
|
||||
/**
|
||||
* @en
|
||||
* Specifies that the clamp to edge warp mode will be used.
|
||||
* @zh
|
||||
* 指定环绕模式:纹理边缘拉伸效果。
|
||||
*/
|
||||
CLAMP_TO_EDGE = static_cast<uint32_t>(gfx::Address::CLAMP),
|
||||
/**
|
||||
* @en
|
||||
* Specifies that the mirrored repeat warp mode will be used.
|
||||
* @zh
|
||||
* 指定环绕模式:以镜像模式重复纹理图像。
|
||||
*/
|
||||
MIRRORED_REPEAT = static_cast<uint32_t>(gfx::Address::MIRROR),
|
||||
/**
|
||||
* @en
|
||||
* Specifies that the clamp to border wrap mode will be used.
|
||||
* @zh
|
||||
* 指定环绕模式:超出纹理坐标部分以用户指定颜色填充。
|
||||
*/
|
||||
CLAMP_TO_BORDER = static_cast<uint32_t>(gfx::Address::BORDER),
|
||||
};
|
||||
|
||||
/**
|
||||
* @en
|
||||
* The texture filter mode
|
||||
* @zh
|
||||
* 纹理过滤模式。
|
||||
*/
|
||||
enum class Filter : uint32_t {
|
||||
NONE = static_cast<uint32_t>(gfx::Filter::NONE),
|
||||
/**
|
||||
* @en
|
||||
* Specifies linear filtering.
|
||||
* @zh
|
||||
* 线性过滤模式。
|
||||
*/
|
||||
LINEAR = static_cast<uint32_t>(gfx::Filter::LINEAR),
|
||||
/**
|
||||
* @en
|
||||
* Specifies nearest filtering.
|
||||
* @zh
|
||||
* 临近过滤模式。
|
||||
*/
|
||||
NEAREST = static_cast<uint32_t>(gfx::Filter::POINT),
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
39
cocos/core/assets/AssetsModuleHeader.h
Normal file
39
cocos/core/assets/AssetsModuleHeader.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/assets/Asset.h"
|
||||
#include "core/assets/BufferAsset.h"
|
||||
#include "core/assets/EffectAsset.h"
|
||||
#include "core/assets/ImageAsset.h"
|
||||
//#include "core/assets/JsonAsset.h"
|
||||
#include "core/assets/Material.h"
|
||||
//#include "core/assets/Prefab.h"
|
||||
#include "core/assets/RenderTexture.h"
|
||||
#include "core/assets/RenderingSubMesh.h"
|
||||
#include "core/assets/SceneAsset.h"
|
||||
#include "core/assets/TextAsset.h"
|
||||
#include "core/assets/Texture2D.h"
|
||||
#include "core/assets/TextureCube.h"
|
||||
205
cocos/core/assets/BitmapFont.cpp
Normal file
205
cocos/core/assets/BitmapFont.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "BitmapFont.h"
|
||||
#include "base/Log.h"
|
||||
#include "gfx-base/GFXDevice.h"
|
||||
#include "platform/Image.h"
|
||||
#include "tinyxml2/tinyxml2.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
/**
|
||||
* BitmapFontFace
|
||||
*/
|
||||
|
||||
BitmapFontFace::BitmapFontFace(Font *font)
|
||||
: FontFace(font) {
|
||||
}
|
||||
void BitmapFontFace::doInit(const FontFaceInfo & /*info*/) {
|
||||
const auto &fontPath = _font->getPath();
|
||||
const auto &fontData = _font->getData();
|
||||
if (fontData.empty()) {
|
||||
CC_LOG_ERROR("BitmapFontFace doInit failed: empty font data.");
|
||||
return;
|
||||
}
|
||||
|
||||
tinyxml2::XMLDocument doc;
|
||||
|
||||
auto error = doc.Parse(reinterpret_cast<const char *>(fontData.data()), fontData.size());
|
||||
if (error) {
|
||||
CC_LOG_ERROR("BitmapFontFace parse failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto *fontNode = doc.RootElement();
|
||||
auto *infoNode = fontNode->FirstChildElement("info");
|
||||
_fontSize = infoNode->UnsignedAttribute("size");
|
||||
|
||||
auto *commonNode = fontNode->FirstChildElement("common");
|
||||
_lineHeight = commonNode->UnsignedAttribute("lineHeight");
|
||||
_textureWidth = commonNode->UnsignedAttribute("scaleW");
|
||||
_textureHeight = commonNode->UnsignedAttribute("scaleH");
|
||||
uint32_t pages = commonNode->UnsignedAttribute("pages");
|
||||
int base = commonNode->IntAttribute("base");
|
||||
|
||||
// load glyphs
|
||||
auto *charsNode = fontNode->FirstChildElement("chars");
|
||||
auto *charNode = charsNode->FirstChildElement("char");
|
||||
while (charNode) {
|
||||
FontGlyph glyph;
|
||||
uint32_t value{0U};
|
||||
|
||||
uint32_t code = charNode->UnsignedAttribute("id");
|
||||
glyph.x = static_cast<int16_t>(charNode->IntAttribute("x"));
|
||||
glyph.y = static_cast<int16_t>(charNode->IntAttribute("y"));
|
||||
glyph.width = static_cast<uint16_t>(charNode->UnsignedAttribute("width"));
|
||||
glyph.height = static_cast<uint16_t>(charNode->UnsignedAttribute("height"));
|
||||
glyph.bearingX = static_cast<int16_t>(charNode->IntAttribute("xoffset"));
|
||||
glyph.bearingY = static_cast<int16_t>(base - charNode->IntAttribute("yoffset"));
|
||||
glyph.advance = static_cast<int16_t>(charNode->IntAttribute("xadvance"));
|
||||
glyph.page = charNode->UnsignedAttribute("page");
|
||||
|
||||
_glyphs[code] = glyph;
|
||||
charNode = charNode->NextSiblingElement();
|
||||
}
|
||||
|
||||
// load textures
|
||||
auto *pagesNode = fontNode->FirstChildElement("pages");
|
||||
auto *pageNode = pagesNode->FirstChildElement("page");
|
||||
_textures.resize(pages, nullptr);
|
||||
|
||||
ccstd::string path = fontPath;
|
||||
auto pos = fontPath.rfind('/');
|
||||
|
||||
if (pos == ccstd::string::npos) {
|
||||
pos = fontPath.rfind('\\');
|
||||
}
|
||||
|
||||
if (pos != ccstd::string::npos) {
|
||||
path = fontPath.substr(0, pos + 1);
|
||||
}
|
||||
|
||||
while (pageNode) {
|
||||
uint32_t id = pageNode->UnsignedAttribute("id");
|
||||
ccstd::string file = pageNode->Attribute("file");
|
||||
_textures[id] = loadTexture(path + file);
|
||||
|
||||
pageNode = pageNode->NextSiblingElement();
|
||||
}
|
||||
|
||||
// load kernings
|
||||
auto *kerningsNode = fontNode->FirstChildElement("kernings");
|
||||
auto *kerningNode = kerningsNode->FirstChildElement("kerning");
|
||||
while (kerningNode) {
|
||||
KerningPair pair;
|
||||
pair.prevCode = kerningNode->UnsignedAttribute("first");
|
||||
pair.nextCode = kerningNode->UnsignedAttribute("second");
|
||||
_kernings[pair] = static_cast<float>(kerningNode->IntAttribute("amount"));
|
||||
|
||||
kerningNode = kerningNode->NextSiblingElement();
|
||||
}
|
||||
}
|
||||
|
||||
const FontGlyph *BitmapFontFace::getGlyph(uint32_t code) {
|
||||
auto iter = _glyphs.find(code);
|
||||
if (iter != _glyphs.end()) {
|
||||
return &iter->second;
|
||||
}
|
||||
|
||||
CC_LOG_WARNING("BitmapFontFace getGlyph failed, character: %u.", code);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
float BitmapFontFace::getKerning(uint32_t prevCode, uint32_t nextCode) {
|
||||
if (_kernings.empty()) {
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
const auto &iter = _kernings.find({prevCode, nextCode});
|
||||
if (iter != _kernings.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
gfx::Texture *BitmapFontFace::loadTexture(const ccstd::string &path) {
|
||||
auto *image = ccnew Image();
|
||||
bool success = image->initWithImageFile(path);
|
||||
if (!success) {
|
||||
CC_LOG_WARNING("BitmapFontFace initWithImageFile failed, path: %s.", path.c_str());
|
||||
delete image;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (image->getRenderFormat() != gfx::Format::R8 && image->getRenderFormat() != gfx::Format::L8) {
|
||||
CC_LOG_WARNING("BitmapFontFace loadTexture with invalid format, path: %s.", path.c_str());
|
||||
delete image;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto width = static_cast<uint32_t>(image->getWidth());
|
||||
auto height = static_cast<uint32_t>(image->getHeight());
|
||||
|
||||
auto *device = gfx::Device::getInstance();
|
||||
auto *texture = device->createTexture({gfx::TextureType::TEX2D,
|
||||
gfx::TextureUsageBit::SAMPLED | gfx::TextureUsageBit::TRANSFER_DST,
|
||||
gfx::Format::R8,
|
||||
width,
|
||||
height});
|
||||
|
||||
gfx::BufferDataList buffers{image->getData()};
|
||||
gfx::BufferTextureCopyList regions = {{0U,
|
||||
0U,
|
||||
0U,
|
||||
{0U, 0U, 0U},
|
||||
{width, height, 1U},
|
||||
{0U, 0U, 1U}}};
|
||||
|
||||
device->copyBuffersToTexture(buffers, texture, regions);
|
||||
delete image;
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* BitmapFont
|
||||
*/
|
||||
BitmapFont::BitmapFont(const ccstd::string &path)
|
||||
: Font(FontType::BITMAP, path) {
|
||||
}
|
||||
|
||||
FontFace *BitmapFont::createFace(const FontFaceInfo &info) {
|
||||
auto *face = ccnew BitmapFontFace(this);
|
||||
face->doInit(info);
|
||||
|
||||
uint32_t fontSize = face->getFontSize();
|
||||
_faces[fontSize] = face;
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
67
cocos/core/assets/BitmapFont.h
Normal file
67
cocos/core/assets/BitmapFont.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include "Font.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
/**
|
||||
* BitmapFontFace
|
||||
*/
|
||||
class BitmapFontFace : public FontFace {
|
||||
public:
|
||||
explicit BitmapFontFace(Font *font);
|
||||
~BitmapFontFace() override = default;
|
||||
BitmapFontFace(const BitmapFontFace &) = delete;
|
||||
BitmapFontFace(BitmapFontFace &&) = delete;
|
||||
BitmapFontFace &operator=(const BitmapFontFace &) = delete;
|
||||
BitmapFontFace &operator=(BitmapFontFace &&) = delete;
|
||||
|
||||
const FontGlyph *getGlyph(uint32_t code) override;
|
||||
float getKerning(uint32_t prevCode, uint32_t nextCode) override;
|
||||
|
||||
private:
|
||||
void doInit(const FontFaceInfo &info) override;
|
||||
static gfx::Texture *loadTexture(const ccstd::string &path);
|
||||
|
||||
friend class BitmapFont;
|
||||
};
|
||||
|
||||
/**
|
||||
* BitmapFont
|
||||
*/
|
||||
class BitmapFont : public Font {
|
||||
public:
|
||||
explicit BitmapFont(const ccstd::string &path);
|
||||
~BitmapFont() override = default;
|
||||
BitmapFont(const BitmapFont &) = delete;
|
||||
BitmapFont(BitmapFont &&) = delete;
|
||||
BitmapFont &operator=(const BitmapFont &) = delete;
|
||||
BitmapFont &operator=(BitmapFont &&) = delete;
|
||||
|
||||
FontFace *createFace(const FontFaceInfo &info) override;
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
37
cocos/core/assets/BufferAsset.cpp
Normal file
37
cocos/core/assets/BufferAsset.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "core/assets/BufferAsset.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
ccstd::any BufferAsset::getNativeAsset() const {
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
void BufferAsset::setNativeAsset(const ccstd::any &obj) {
|
||||
_buffer = ccstd::any_cast<ArrayBuffer *>(obj);
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
52
cocos/core/assets/BufferAsset.h
Normal file
52
cocos/core/assets/BufferAsset.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/ArrayBuffer.h"
|
||||
#include "core/assets/Asset.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class BufferAsset final : public Asset {
|
||||
public:
|
||||
BufferAsset() = default;
|
||||
~BufferAsset() override = default;
|
||||
|
||||
inline ArrayBuffer *getBuffer() const { return _buffer; }
|
||||
|
||||
inline void setNativeAssetForJS(ArrayBuffer *buffer) { _buffer = buffer; }
|
||||
inline ArrayBuffer *getNativeAssetForJS() const { return _buffer; }
|
||||
|
||||
ccstd::any getNativeAsset() const override;
|
||||
void setNativeAsset(const ccstd::any &obj) override;
|
||||
bool validate() const override { return _buffer != nullptr; }
|
||||
|
||||
private:
|
||||
ArrayBuffer::Ptr _buffer;
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(BufferAsset);
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
354
cocos/core/assets/EffectAsset.cpp
Normal file
354
cocos/core/assets/EffectAsset.cpp
Normal file
@@ -0,0 +1,354 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "core/assets/EffectAsset.h"
|
||||
#include "ProgramUtils.h"
|
||||
#include "cocos.h"
|
||||
#include "cocos/renderer/pipeline/custom/RenderingModule.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/platform/Debug.h"
|
||||
#include "engine/BaseEngine.h"
|
||||
#include "renderer/core/ProgramLib.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
IPassStates::IPassStates(const IPassInfoFull &o) {
|
||||
*this = o;
|
||||
}
|
||||
|
||||
IPassStates &IPassStates::operator=(const IPassInfoFull &o) {
|
||||
priority = o.priority;
|
||||
primitive = o.primitive;
|
||||
stage = o.stage;
|
||||
rasterizerState = o.rasterizerState;
|
||||
depthStencilState = o.depthStencilState;
|
||||
blendState = o.blendState;
|
||||
dynamicStates = o.dynamicStates;
|
||||
phase = o.phase;
|
||||
subpass = o.subpass;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void IPassStates::overrides(const IPassInfoFull &o) {
|
||||
if (o.priority.has_value()) {
|
||||
this->priority = o.priority.value();
|
||||
}
|
||||
if (o.primitive.has_value()) {
|
||||
this->primitive = o.primitive.value();
|
||||
}
|
||||
if (o.stage.has_value()) {
|
||||
this->stage = o.stage.value();
|
||||
}
|
||||
if (o.rasterizerState.has_value()) {
|
||||
this->rasterizerState = o.rasterizerState.value();
|
||||
}
|
||||
if (o.depthStencilState.has_value()) {
|
||||
this->depthStencilState = o.depthStencilState.value();
|
||||
}
|
||||
if (o.blendState.has_value()) {
|
||||
this->blendState = o.blendState.value();
|
||||
}
|
||||
if (o.dynamicStates.has_value()) {
|
||||
this->dynamicStates = o.dynamicStates.value();
|
||||
}
|
||||
if (o.phase.has_value()) {
|
||||
this->phase = o.phase.value();
|
||||
}
|
||||
if (o.subpass.has_value()) {
|
||||
this->subpass = o.subpass.value();
|
||||
}
|
||||
}
|
||||
|
||||
EffectAsset::RegisteredEffectAssetMap EffectAsset::effects;
|
||||
bool EffectAsset::layoutValid = true;
|
||||
|
||||
/* static */
|
||||
void EffectAsset::registerAsset(EffectAsset *asset) {
|
||||
if (asset == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
EffectAsset::effects.emplace(asset->getName(), asset);
|
||||
layoutValid = false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void EffectAsset::remove(const ccstd::string &name) {
|
||||
auto iter = EffectAsset::effects.find(name);
|
||||
if (iter != EffectAsset::effects.end() && iter->second->getName() == name) {
|
||||
EffectAsset::effects.erase(iter);
|
||||
return;
|
||||
}
|
||||
|
||||
iter = EffectAsset::effects.begin();
|
||||
for (; iter != EffectAsset::effects.end(); ++iter) {
|
||||
if (iter->second->getUuid() == name) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iter != EffectAsset::effects.end()) {
|
||||
EffectAsset::effects.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void EffectAsset::remove(EffectAsset *asset) {
|
||||
if (asset == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto iter = EffectAsset::effects.find(asset->getName());
|
||||
if (iter != EffectAsset::effects.end() && iter->second == asset) {
|
||||
EffectAsset::effects.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
EffectAsset *EffectAsset::get(const ccstd::string &name) {
|
||||
auto iter = EffectAsset::effects.find(name);
|
||||
if (iter != EffectAsset::effects.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
iter = EffectAsset::effects.begin();
|
||||
for (; iter != EffectAsset::effects.end(); ++iter) {
|
||||
if (iter->second->getUuid() == name) {
|
||||
return iter->second;
|
||||
}
|
||||
}
|
||||
static ccstd::vector<ccstd::string> legacyBuiltinEffectNames{
|
||||
"planar-shadow",
|
||||
"skybox",
|
||||
"deferred-lighting",
|
||||
"bloom",
|
||||
"copy-pass",
|
||||
"post-process",
|
||||
"profiler",
|
||||
"splash-screen",
|
||||
"standard",
|
||||
"unlit",
|
||||
"sprite",
|
||||
"particle",
|
||||
"particle-gpu",
|
||||
"particle-trail",
|
||||
"billboard",
|
||||
"terrain",
|
||||
"graphics",
|
||||
"clear-stencil",
|
||||
"spine",
|
||||
"occlusion-query",
|
||||
"geometry-renderer",
|
||||
"debug-renderer"};
|
||||
for (auto &legacyName : legacyBuiltinEffectNames) {
|
||||
if (name == legacyName) {
|
||||
debug::warnID(16101, name);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void EffectAsset::onLoaded() {
|
||||
auto *programLib = render::getProgramLibrary();
|
||||
if (programLib) {
|
||||
render::addEffectDefaultProperties(*this);
|
||||
programLib->addEffect(this);
|
||||
} else {
|
||||
ProgramLib::getInstance()->registerEffect(this);
|
||||
}
|
||||
EffectAsset::registerAsset(this);
|
||||
#if !CC_EDITOR
|
||||
if (CC_CURRENT_ENGINE()->isInited()) {
|
||||
precompile();
|
||||
} else {
|
||||
_engineEventId = CC_CURRENT_ENGINE()->on<BaseEngine::EngineStatusChange>([this](BaseEngine * /*emitter*/, BaseEngine::EngineStatus status) {
|
||||
if (status == BaseEngine::EngineStatus::ON_START) {
|
||||
this->precompile();
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EffectAsset::destroy() {
|
||||
EffectAsset::remove(this);
|
||||
if (CC_CURRENT_ENGINE()->isInited()) {
|
||||
CC_CURRENT_ENGINE()->off(_engineEventId);
|
||||
}
|
||||
return Super::destroy();
|
||||
}
|
||||
|
||||
void EffectAsset::initDefault(const ccstd::optional<ccstd::string> &uuid) {
|
||||
Super::initDefault(uuid);
|
||||
const auto *effect = EffectAsset::get("builtin-unlit");
|
||||
_name = "builtin-unlit";
|
||||
_shaders = effect->_shaders;
|
||||
_combinations = effect->_combinations;
|
||||
_techniques = effect->_techniques; // NOTE: it will copy effect->_techniques to _techniques and _techniques will kept by SE_HOLD_RETURN_VALUE
|
||||
}
|
||||
|
||||
bool EffectAsset::validate() const {
|
||||
return !_techniques.empty() && !_shaders.empty();
|
||||
}
|
||||
|
||||
void EffectAsset::precompile() {
|
||||
Root *root = Root::getInstance();
|
||||
for (index_t i = 0; i < _shaders.size(); ++i) {
|
||||
auto shader = _shaders[i];
|
||||
if (i >= _combinations.size()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto combination = _combinations[i];
|
||||
if (combination.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Native Program Lib can not precompile shader variant without phaseID.
|
||||
// Shaders are compiled only during the compilation of PSO. A new mechanism may be needed for pre-compilation.
|
||||
auto *programLib = render::getProgramLibrary();
|
||||
if (programLib == nullptr) {
|
||||
ccstd::vector<MacroRecord> defines = EffectAsset::doCombine(
|
||||
ccstd::vector<MacroRecord>(), combination, combination.begin());
|
||||
for (auto &define: defines) {
|
||||
ProgramLib::getInstance()->getGFXShader(root->getDevice(), shader.name, define,
|
||||
root->getPipeline());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// input
|
||||
|
||||
const combination = {
|
||||
USE_TEXTURE: [true, false],
|
||||
COLOR_MODE: [0, 1, 2, 3],
|
||||
ROUGHNESS_CHANNEL: ['r', 'g', 'b'],
|
||||
};
|
||||
|
||||
// output
|
||||
|
||||
const defines = [
|
||||
{
|
||||
USE_TEXTURE: true,
|
||||
COLOR_MODE: 0,
|
||||
ROUGHNESS_CHANNEL: 'r'
|
||||
},
|
||||
{
|
||||
USE_TEXTURE: true,
|
||||
COLOR_MODE: 0,
|
||||
ROUGHNESS_CHANNEL: 'g'
|
||||
},
|
||||
{
|
||||
USE_TEXTURE: true,
|
||||
COLOR_MODE: 0,
|
||||
ROUGHNESS_CHANNEL: 'b'
|
||||
},
|
||||
{
|
||||
USE_TEXTURE: true,
|
||||
COLOR_MODE: 1,
|
||||
ROUGHNESS_CHANNEL: 'r'
|
||||
},
|
||||
// ... all the combinations (2x4x3 in this case)
|
||||
];
|
||||
*/
|
||||
ccstd::vector<MacroRecord> EffectAsset::doCombine(const ccstd::vector<MacroRecord> &cur, const IPreCompileInfo &info, IPreCompileInfo::iterator iter) { // NOLINT(misc-no-recursion)
|
||||
if (iter == info.end()) {
|
||||
return cur;
|
||||
}
|
||||
|
||||
const IPreCompileInfoValueType &values = iter->second;
|
||||
const ccstd::string &key = iter->first;
|
||||
|
||||
ccstd::vector<MacroRecord> records;
|
||||
if (cur.empty()) {
|
||||
records = EffectAsset::generateRecords(key, values);
|
||||
} else {
|
||||
records = EffectAsset::insertInfoValue(cur, key, values);
|
||||
}
|
||||
|
||||
return EffectAsset::doCombine(records, info, ++iter);
|
||||
}
|
||||
|
||||
ccstd::vector<MacroRecord> EffectAsset::generateRecords(const ccstd::string &key, const IPreCompileInfoValueType &infoValue) {
|
||||
ccstd::vector<MacroRecord> ret;
|
||||
if (const auto *boolValues = ccstd::get_if<ccstd::vector<bool>>(&infoValue)) {
|
||||
for (const bool value : *boolValues) {
|
||||
MacroRecord record;
|
||||
record[key] = value;
|
||||
ret.emplace_back(record);
|
||||
}
|
||||
} else if (const auto *intValues = ccstd::get_if<ccstd::vector<int32_t>>(&infoValue)) {
|
||||
for (const int32_t value : *intValues) {
|
||||
MacroRecord record;
|
||||
record[key] = value;
|
||||
ret.emplace_back(record);
|
||||
}
|
||||
} else if (const auto *stringValues = ccstd::get_if<ccstd::vector<ccstd::string>>(&infoValue)) {
|
||||
for (const ccstd::string &value : *stringValues) {
|
||||
MacroRecord record;
|
||||
record[key] = value;
|
||||
ret.emplace_back(record);
|
||||
}
|
||||
} else {
|
||||
CC_ABORT();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ccstd::vector<MacroRecord> EffectAsset::insertInfoValue(const ccstd::vector<MacroRecord> &records,
|
||||
const ccstd::string &key,
|
||||
const IPreCompileInfoValueType &infoValue) {
|
||||
ccstd::vector<MacroRecord> ret;
|
||||
for (const auto &record : records) {
|
||||
if (const auto *boolValues = ccstd::get_if<ccstd::vector<bool>>(&infoValue)) {
|
||||
for (const bool value : *boolValues) {
|
||||
MacroRecord tmpRecord = record;
|
||||
tmpRecord[key] = value;
|
||||
ret.emplace_back(tmpRecord);
|
||||
}
|
||||
} else if (const auto *intValues = ccstd::get_if<ccstd::vector<int32_t>>(&infoValue)) {
|
||||
for (const int32_t value : *intValues) {
|
||||
MacroRecord tmpRecord = record;
|
||||
tmpRecord[key] = value;
|
||||
ret.emplace_back(tmpRecord);
|
||||
}
|
||||
} else if (const auto *stringValues = ccstd::get_if<ccstd::vector<ccstd::string>>(&infoValue)) {
|
||||
for (const ccstd::string &value : *stringValues) {
|
||||
MacroRecord tmpRecord = record;
|
||||
tmpRecord[key] = value;
|
||||
ret.emplace_back(tmpRecord);
|
||||
}
|
||||
} else {
|
||||
CC_ABORT();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
706
cocos/core/assets/EffectAsset.h
Normal file
706
cocos/core/assets/EffectAsset.h
Normal file
@@ -0,0 +1,706 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/container/unordered_map.h"
|
||||
#include "base/std/optional.h"
|
||||
|
||||
#include "base/Value.h"
|
||||
#include "core/Types.h"
|
||||
#include "core/assets/Asset.h"
|
||||
#include "engine/BaseEngine.h"
|
||||
#include "renderer/core/PassUtils.h"
|
||||
#include "renderer/gfx-base/GFXDef.h"
|
||||
#include "renderer/pipeline/Define.h"
|
||||
namespace cc {
|
||||
|
||||
// To avoid errors when generating code using SWIG.
|
||||
#if !SWIGCOCOS
|
||||
|
||||
// The properties in Pass are obtained from an asset file. If they are directly stored in an unordered_map,
|
||||
// the order of these properties may become scrambled. To maintain their order, a vector<pair> is used
|
||||
// instead. Since there is no scenario where these data objects are randomly inserted,
|
||||
// only a find interface is provided.
|
||||
template <typename K, typename V>
|
||||
class StablePropertyMap : public ccstd::vector<std::pair<K, V>> { // NOLINT
|
||||
using Super = ccstd::vector<std::pair<K, V>>;
|
||||
|
||||
public:
|
||||
auto find(const K &key) const {
|
||||
auto *self = static_cast<const Super *>(this);
|
||||
return std::find_if(self->begin(), self->end(), [&](auto &ele) {
|
||||
return ele.first == key;
|
||||
});
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename K, typename V>
|
||||
using UnstablePropertyContainer = ccstd::unordered_map<K, V>;
|
||||
|
||||
template <typename K, typename V>
|
||||
using StablePropertyContainer = StablePropertyMap<K, V>;
|
||||
|
||||
#if CC_EDITOR
|
||||
template <typename K, typename V>
|
||||
using PropertyContainer = StablePropertyContainer<K, V>;
|
||||
#else
|
||||
template <typename K, typename V>
|
||||
using PropertyContainer = UnstablePropertyContainer<K, V>;
|
||||
#endif
|
||||
|
||||
using IPropertyHandleInfo = std::tuple<ccstd::string, uint32_t, gfx::Type>;
|
||||
|
||||
using IPropertyValue = ccstd::variant<ccstd::monostate, ccstd::vector<float>, ccstd::string>;
|
||||
|
||||
using IPropertyEditorValueType = ccstd::variant<ccstd::monostate, ccstd::string, bool, float, ccstd::vector<float>>;
|
||||
using IPropertyEditorInfo = PropertyContainer<ccstd::string, IPropertyEditorValueType>;
|
||||
|
||||
struct IPropertyInfo {
|
||||
int32_t type{0}; // auto-extracted from shader
|
||||
ccstd::optional<IPropertyHandleInfo> handleInfo; // auto-generated from 'target'
|
||||
ccstd::optional<ccstd::hash_t> samplerHash; // auto-generated from 'sampler'
|
||||
ccstd::optional<IPropertyValue> value; // default value
|
||||
ccstd::optional<bool> linear; // whether to convert the input to linear space first before applying
|
||||
IPropertyEditorInfo editor; // NOTE: used only by editor.
|
||||
};
|
||||
|
||||
struct IPassInfoFull;
|
||||
|
||||
struct RasterizerStateInfo {
|
||||
ccstd::optional<bool> isDiscard;
|
||||
ccstd::optional<bool> isFrontFaceCCW;
|
||||
ccstd::optional<bool> depthBiasEnabled;
|
||||
ccstd::optional<bool> isDepthClip;
|
||||
ccstd::optional<bool> isMultisample;
|
||||
|
||||
ccstd::optional<gfx::PolygonMode> polygonMode;
|
||||
ccstd::optional<gfx::ShadeModel> shadeModel;
|
||||
ccstd::optional<gfx::CullMode> cullMode;
|
||||
|
||||
ccstd::optional<float> depthBias;
|
||||
ccstd::optional<float> depthBiasClamp;
|
||||
ccstd::optional<float> depthBiasSlop;
|
||||
ccstd::optional<float> lineWidth;
|
||||
|
||||
void fromGFXRasterizerState(const gfx::RasterizerState &rs) {
|
||||
isDiscard = rs.isDiscard;
|
||||
isFrontFaceCCW = rs.isFrontFaceCCW;
|
||||
depthBiasEnabled = rs.depthBiasEnabled;
|
||||
isDepthClip = rs.isDepthClip;
|
||||
isMultisample = rs.isMultisample;
|
||||
|
||||
polygonMode = rs.polygonMode;
|
||||
shadeModel = rs.shadeModel;
|
||||
cullMode = rs.cullMode;
|
||||
|
||||
depthBias = rs.depthBias;
|
||||
depthBiasClamp = rs.depthBiasClamp;
|
||||
depthBiasSlop = rs.depthBiasSlop;
|
||||
lineWidth = rs.lineWidth;
|
||||
}
|
||||
|
||||
void assignToGFXRasterizerState(gfx::RasterizerState &rs) const {
|
||||
if (isDiscard.has_value()) {
|
||||
rs.isDiscard = isDiscard.value();
|
||||
}
|
||||
if (isFrontFaceCCW.has_value()) {
|
||||
rs.isFrontFaceCCW = isFrontFaceCCW.value();
|
||||
}
|
||||
if (depthBiasEnabled.has_value()) {
|
||||
rs.depthBiasEnabled = depthBiasEnabled.value();
|
||||
}
|
||||
if (isDepthClip.has_value()) {
|
||||
rs.isDepthClip = isDepthClip.value();
|
||||
}
|
||||
if (isMultisample.has_value()) {
|
||||
rs.isMultisample = isMultisample.value();
|
||||
}
|
||||
if (polygonMode.has_value()) {
|
||||
rs.polygonMode = polygonMode.value();
|
||||
}
|
||||
if (shadeModel.has_value()) {
|
||||
rs.shadeModel = shadeModel.value();
|
||||
}
|
||||
if (cullMode.has_value()) {
|
||||
rs.cullMode = cullMode.value();
|
||||
}
|
||||
if (depthBias.has_value()) {
|
||||
rs.depthBias = depthBias.value();
|
||||
}
|
||||
if (depthBiasClamp.has_value()) {
|
||||
rs.depthBiasClamp = depthBiasClamp.value();
|
||||
}
|
||||
if (depthBiasSlop.has_value()) {
|
||||
rs.depthBiasSlop = depthBiasSlop.value();
|
||||
}
|
||||
if (lineWidth.has_value()) {
|
||||
rs.lineWidth = lineWidth.value();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DepthStencilStateInfo {
|
||||
ccstd::optional<bool> depthTest;
|
||||
ccstd::optional<bool> depthWrite;
|
||||
ccstd::optional<bool> stencilTestFront;
|
||||
ccstd::optional<bool> stencilTestBack;
|
||||
|
||||
ccstd::optional<gfx::ComparisonFunc> depthFunc;
|
||||
ccstd::optional<gfx::ComparisonFunc> stencilFuncFront;
|
||||
ccstd::optional<uint32_t> stencilReadMaskFront;
|
||||
ccstd::optional<uint32_t> stencilWriteMaskFront;
|
||||
ccstd::optional<gfx::StencilOp> stencilFailOpFront;
|
||||
ccstd::optional<gfx::StencilOp> stencilZFailOpFront;
|
||||
ccstd::optional<gfx::StencilOp> stencilPassOpFront;
|
||||
ccstd::optional<uint32_t> stencilRefFront;
|
||||
|
||||
ccstd::optional<gfx::ComparisonFunc> stencilFuncBack;
|
||||
ccstd::optional<uint32_t> stencilReadMaskBack;
|
||||
ccstd::optional<uint32_t> stencilWriteMaskBack;
|
||||
ccstd::optional<gfx::StencilOp> stencilFailOpBack;
|
||||
ccstd::optional<gfx::StencilOp> stencilZFailOpBack;
|
||||
ccstd::optional<gfx::StencilOp> stencilPassOpBack;
|
||||
ccstd::optional<uint32_t> stencilRefBack;
|
||||
|
||||
void fromGFXDepthStencilState(const gfx::DepthStencilState &ds) {
|
||||
depthTest = ds.depthTest;
|
||||
depthWrite = ds.depthWrite;
|
||||
stencilTestFront = ds.stencilTestFront;
|
||||
stencilTestBack = ds.stencilTestBack;
|
||||
|
||||
depthFunc = ds.depthFunc;
|
||||
stencilFuncFront = ds.stencilFuncFront;
|
||||
stencilReadMaskFront = ds.stencilReadMaskFront;
|
||||
stencilWriteMaskFront = ds.stencilWriteMaskFront;
|
||||
stencilFailOpFront = ds.stencilFailOpFront;
|
||||
stencilZFailOpFront = ds.stencilZFailOpFront;
|
||||
stencilPassOpFront = ds.stencilPassOpFront;
|
||||
stencilRefFront = ds.stencilRefFront;
|
||||
|
||||
stencilFuncBack = ds.stencilFuncBack;
|
||||
stencilReadMaskBack = ds.stencilReadMaskBack;
|
||||
stencilWriteMaskBack = ds.stencilWriteMaskBack;
|
||||
stencilFailOpBack = ds.stencilFailOpBack;
|
||||
stencilZFailOpBack = ds.stencilZFailOpBack;
|
||||
stencilPassOpBack = ds.stencilPassOpBack;
|
||||
stencilRefBack = ds.stencilRefBack;
|
||||
}
|
||||
|
||||
void assignToGFXDepthStencilState(gfx::DepthStencilState &ds) const {
|
||||
if (depthTest.has_value()) {
|
||||
ds.depthTest = depthTest.value();
|
||||
}
|
||||
if (depthWrite.has_value()) {
|
||||
ds.depthWrite = depthWrite.value();
|
||||
}
|
||||
if (stencilTestFront.has_value()) {
|
||||
ds.stencilTestFront = stencilTestFront.value();
|
||||
}
|
||||
if (stencilTestBack.has_value()) {
|
||||
ds.stencilTestBack = stencilTestBack.value();
|
||||
}
|
||||
if (depthFunc.has_value()) {
|
||||
ds.depthFunc = depthFunc.value();
|
||||
}
|
||||
if (stencilFuncFront.has_value()) {
|
||||
ds.stencilFuncFront = stencilFuncFront.value();
|
||||
}
|
||||
if (stencilReadMaskFront.has_value()) {
|
||||
ds.stencilReadMaskFront = stencilReadMaskFront.value();
|
||||
}
|
||||
if (stencilWriteMaskFront.has_value()) {
|
||||
ds.stencilWriteMaskFront = stencilWriteMaskFront.value();
|
||||
}
|
||||
if (stencilFailOpFront.has_value()) {
|
||||
ds.stencilFailOpFront = stencilFailOpFront.value();
|
||||
}
|
||||
if (stencilZFailOpFront.has_value()) {
|
||||
ds.stencilZFailOpFront = stencilZFailOpFront.value();
|
||||
}
|
||||
if (stencilPassOpFront.has_value()) {
|
||||
ds.stencilPassOpFront = stencilPassOpFront.value();
|
||||
}
|
||||
if (stencilRefFront.has_value()) {
|
||||
ds.stencilRefFront = stencilRefFront.value();
|
||||
}
|
||||
if (stencilFuncBack.has_value()) {
|
||||
ds.stencilFuncBack = stencilFuncBack.value();
|
||||
}
|
||||
if (stencilReadMaskBack.has_value()) {
|
||||
ds.stencilReadMaskBack = stencilReadMaskBack.value();
|
||||
}
|
||||
if (stencilWriteMaskBack.has_value()) {
|
||||
ds.stencilWriteMaskBack = stencilWriteMaskBack.value();
|
||||
}
|
||||
if (stencilFailOpBack.has_value()) {
|
||||
ds.stencilFailOpBack = stencilFailOpBack.value();
|
||||
}
|
||||
if (stencilZFailOpBack.has_value()) {
|
||||
ds.stencilZFailOpBack = stencilZFailOpBack.value();
|
||||
}
|
||||
if (stencilPassOpBack.has_value()) {
|
||||
ds.stencilPassOpBack = stencilPassOpBack.value();
|
||||
}
|
||||
if (stencilRefBack.has_value()) {
|
||||
ds.stencilRefBack = stencilRefBack.value();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct BlendTargetInfo {
|
||||
ccstd::optional<bool> blend;
|
||||
ccstd::optional<gfx::BlendFactor> blendSrc;
|
||||
ccstd::optional<gfx::BlendFactor> blendDst;
|
||||
ccstd::optional<gfx::BlendOp> blendEq;
|
||||
ccstd::optional<gfx::BlendFactor> blendSrcAlpha;
|
||||
ccstd::optional<gfx::BlendFactor> blendDstAlpha;
|
||||
ccstd::optional<gfx::BlendOp> blendAlphaEq;
|
||||
ccstd::optional<gfx::ColorMask> blendColorMask;
|
||||
|
||||
void fromGFXBlendTarget(const gfx::BlendTarget &target) {
|
||||
blend = target.blend;
|
||||
blendSrc = target.blendSrc;
|
||||
blendDst = target.blendDst;
|
||||
blendEq = target.blendEq;
|
||||
blendSrcAlpha = target.blendSrcAlpha;
|
||||
blendDstAlpha = target.blendDstAlpha;
|
||||
blendAlphaEq = target.blendAlphaEq;
|
||||
blendColorMask = target.blendColorMask;
|
||||
}
|
||||
|
||||
void assignToGFXBlendTarget(gfx::BlendTarget &target) const {
|
||||
if (blend.has_value()) {
|
||||
target.blend = blend.value();
|
||||
}
|
||||
if (blendSrc.has_value()) {
|
||||
target.blendSrc = blendSrc.value();
|
||||
}
|
||||
if (blendDst.has_value()) {
|
||||
target.blendDst = blendDst.value();
|
||||
}
|
||||
if (blendEq.has_value()) {
|
||||
target.blendEq = blendEq.value();
|
||||
}
|
||||
if (blendSrcAlpha.has_value()) {
|
||||
target.blendSrcAlpha = blendSrcAlpha.value();
|
||||
}
|
||||
if (blendDstAlpha.has_value()) {
|
||||
target.blendDstAlpha = blendDstAlpha.value();
|
||||
}
|
||||
if (blendAlphaEq.has_value()) {
|
||||
target.blendAlphaEq = blendAlphaEq.value();
|
||||
}
|
||||
if (blendColorMask.has_value()) {
|
||||
target.blendColorMask = blendColorMask.value();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using BlendTargetInfoList = ccstd::vector<BlendTargetInfo>;
|
||||
|
||||
struct BlendStateInfo {
|
||||
ccstd::optional<bool> isA2C;
|
||||
ccstd::optional<bool> isIndepend;
|
||||
ccstd::optional<gfx::Color> blendColor;
|
||||
ccstd::optional<BlendTargetInfoList> targets;
|
||||
|
||||
void fromGFXBlendState(const gfx::BlendState &bs) {
|
||||
isA2C = bs.isA2C;
|
||||
isIndepend = bs.isIndepend;
|
||||
blendColor = bs.blendColor;
|
||||
size_t len = bs.targets.size();
|
||||
if (len > 0) {
|
||||
BlendTargetInfoList targetsList(len);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
targetsList[i].fromGFXBlendTarget(bs.targets[i]);
|
||||
}
|
||||
targets = targetsList;
|
||||
}
|
||||
}
|
||||
|
||||
void assignToGFXBlendState(gfx::BlendState &bs) const {
|
||||
if (targets.has_value()) {
|
||||
const auto &targetsVal = targets.value();
|
||||
bs.targets.resize(targetsVal.size());
|
||||
for (size_t i = 0, len = targetsVal.size(); i < len; ++i) {
|
||||
targetsVal[i].assignToGFXBlendTarget(bs.targets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isA2C.has_value()) {
|
||||
bs.isA2C = isA2C.value();
|
||||
}
|
||||
|
||||
if (isIndepend.has_value()) {
|
||||
bs.isIndepend = isIndepend.value();
|
||||
}
|
||||
|
||||
if (blendColor.has_value()) {
|
||||
bs.blendColor = blendColor.value();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Pass instance itself are compliant to IPassStates too
|
||||
struct IPassStates {
|
||||
ccstd::optional<int32_t> priority;
|
||||
ccstd::optional<gfx::PrimitiveMode> primitive;
|
||||
ccstd::optional<pipeline::RenderPassStage> stage;
|
||||
ccstd::optional<RasterizerStateInfo> rasterizerState;
|
||||
ccstd::optional<DepthStencilStateInfo> depthStencilState;
|
||||
ccstd::optional<BlendStateInfo> blendState;
|
||||
ccstd::optional<gfx::DynamicStateFlags> dynamicStates;
|
||||
ccstd::optional<ccstd::string> phase;
|
||||
ccstd::optional<ccstd::string> pass;
|
||||
ccstd::optional<ccstd::string> subpass;
|
||||
|
||||
IPassStates() = default;
|
||||
explicit IPassStates(const IPassInfoFull &o);
|
||||
IPassStates &operator=(const IPassInfoFull &o);
|
||||
void overrides(const IPassInfoFull &o);
|
||||
};
|
||||
using PassOverrides = IPassStates;
|
||||
|
||||
using PassPropertyInfoMap = PropertyContainer<ccstd::string, IPropertyInfo>;
|
||||
|
||||
struct IPassInfoFull final { // cjh } : public IPassInfo {
|
||||
// IPassStates
|
||||
ccstd::optional<int32_t> priority;
|
||||
ccstd::optional<gfx::PrimitiveMode> primitive;
|
||||
ccstd::optional<pipeline::RenderPassStage> stage;
|
||||
ccstd::optional<RasterizerStateInfo> rasterizerState;
|
||||
ccstd::optional<DepthStencilStateInfo> depthStencilState;
|
||||
ccstd::optional<BlendStateInfo> blendState;
|
||||
ccstd::optional<gfx::DynamicStateFlags> dynamicStates;
|
||||
ccstd::optional<ccstd::string> phase;
|
||||
ccstd::optional<ccstd::string> pass;
|
||||
ccstd::optional<ccstd::string> subpass;
|
||||
// IPassInfo
|
||||
ccstd::string program; // auto-generated from 'vert' and 'frag'
|
||||
ccstd::optional<MacroRecord> embeddedMacros;
|
||||
ccstd::optional<index_t> propertyIndex; // NOTE: needs to use ccstd::optional<> since jsb should return 'undefined' instead of '-1' to avoid wrong value checking logic.
|
||||
ccstd::optional<ccstd::string> switch_;
|
||||
ccstd::optional<PassPropertyInfoMap> properties;
|
||||
|
||||
// IPassInfoFull
|
||||
// generated part
|
||||
index_t passIndex{0};
|
||||
uint32_t passID = 0xFFFFFFFF;
|
||||
uint32_t subpassID = 0xFFFFFFFF;
|
||||
uint32_t phaseID = 0xFFFFFFFF;
|
||||
MacroRecord defines;
|
||||
ccstd::optional<PassOverrides> stateOverrides;
|
||||
|
||||
IPassInfoFull() = default;
|
||||
explicit IPassInfoFull(const IPassStates &o) {
|
||||
*this = o;
|
||||
}
|
||||
IPassInfoFull &operator=(const IPassStates &o) {
|
||||
priority = o.priority;
|
||||
primitive = o.primitive;
|
||||
stage = o.stage;
|
||||
rasterizerState = o.rasterizerState;
|
||||
depthStencilState = o.depthStencilState;
|
||||
blendState = o.blendState;
|
||||
dynamicStates = o.dynamicStates;
|
||||
phase = o.phase;
|
||||
subpass = o.subpass;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
using IPassInfo = IPassInfoFull;
|
||||
|
||||
struct ITechniqueInfo {
|
||||
ccstd::vector<IPassInfoFull> passes;
|
||||
ccstd::optional<ccstd::string> name;
|
||||
};
|
||||
|
||||
struct IBlockInfo {
|
||||
uint32_t binding{UINT32_MAX};
|
||||
ccstd::string name;
|
||||
ccstd::vector<gfx::Uniform> members;
|
||||
|
||||
gfx::ShaderStageFlags stageFlags{gfx::ShaderStageFlags::NONE};
|
||||
|
||||
ccstd::vector<ccstd::string> defines;
|
||||
};
|
||||
|
||||
struct ISamplerTextureInfo {
|
||||
uint32_t binding{UINT32_MAX};
|
||||
ccstd::string name;
|
||||
gfx::Type type{gfx::Type::UNKNOWN};
|
||||
uint32_t count{0};
|
||||
gfx::ShaderStageFlags stageFlags{gfx::ShaderStageFlags::NONE};
|
||||
ccstd::vector<ccstd::string> defines; // NOTE: used in Editor only
|
||||
};
|
||||
|
||||
struct ITextureInfo {
|
||||
uint32_t set{0};
|
||||
uint32_t binding{UINT32_MAX};
|
||||
ccstd::string name;
|
||||
gfx::Type type{gfx::Type::UNKNOWN};
|
||||
uint32_t count{0};
|
||||
gfx::ShaderStageFlags stageFlags{gfx::ShaderStageFlags::NONE};
|
||||
};
|
||||
|
||||
struct ISamplerInfo {
|
||||
uint32_t set{0};
|
||||
uint32_t binding{UINT32_MAX};
|
||||
ccstd::string name;
|
||||
uint32_t count{0};
|
||||
gfx::ShaderStageFlags stageFlags{gfx::ShaderStageFlags::NONE};
|
||||
};
|
||||
|
||||
struct IBufferInfo {
|
||||
uint32_t binding{UINT32_MAX};
|
||||
ccstd::string name;
|
||||
gfx::MemoryAccess memoryAccess{gfx::MemoryAccess::NONE};
|
||||
gfx::ShaderStageFlags stageFlags{gfx::ShaderStageFlags::NONE};
|
||||
};
|
||||
|
||||
struct IImageInfo {
|
||||
uint32_t binding{UINT32_MAX};
|
||||
ccstd::string name;
|
||||
gfx::Type type{gfx::Type::UNKNOWN};
|
||||
uint32_t count{0};
|
||||
gfx::MemoryAccess memoryAccess{gfx::MemoryAccess::NONE};
|
||||
gfx::ShaderStageFlags stageFlags{gfx::ShaderStageFlags::NONE};
|
||||
};
|
||||
|
||||
struct IInputAttachmentInfo {
|
||||
uint32_t set{0};
|
||||
uint32_t binding{UINT32_MAX};
|
||||
ccstd::string name;
|
||||
uint32_t count{0};
|
||||
gfx::ShaderStageFlags stageFlags{gfx::ShaderStageFlags::NONE};
|
||||
};
|
||||
|
||||
struct IAttributeInfo {
|
||||
ccstd::string name;
|
||||
gfx::Format format{gfx::Format::UNKNOWN};
|
||||
bool isNormalized{false};
|
||||
uint32_t stream{0U};
|
||||
bool isInstanced{false};
|
||||
uint32_t location{0U};
|
||||
|
||||
ccstd::vector<ccstd::string> defines;
|
||||
};
|
||||
|
||||
struct IDefineInfo {
|
||||
ccstd::string name;
|
||||
ccstd::string type;
|
||||
ccstd::optional<ccstd::vector<int32_t>> range; // cjh number is float? ?: number[];
|
||||
ccstd::optional<ccstd::vector<ccstd::string>> options;
|
||||
ccstd::optional<ccstd::string> defaultVal;
|
||||
ccstd::optional<ccstd::vector<ccstd::string>> defines; // NOTE: it's only used in Editor
|
||||
ccstd::optional<ccstd::unordered_map<ccstd::string, ccstd::variant<ccstd::string, bool>>> editor; // NOTE: it's only used in Editor
|
||||
};
|
||||
|
||||
struct IBuiltin {
|
||||
ccstd::string name;
|
||||
ccstd::vector<ccstd::string> defines;
|
||||
};
|
||||
|
||||
struct IBuiltinInfo {
|
||||
ccstd::vector<IBuiltin> buffers;
|
||||
ccstd::vector<IBuiltin> blocks;
|
||||
ccstd::vector<IBuiltin> samplerTextures;
|
||||
ccstd::vector<IBuiltin> images;
|
||||
};
|
||||
|
||||
using BuiltinsStatisticsType = ccstd::unordered_map<ccstd::string, int32_t>;
|
||||
|
||||
struct IBuiltins {
|
||||
IBuiltinInfo globals;
|
||||
IBuiltinInfo locals;
|
||||
BuiltinsStatisticsType statistics;
|
||||
};
|
||||
|
||||
struct IDescriptorInfo {
|
||||
uint32_t rate{0};
|
||||
ccstd::vector<IBlockInfo> blocks;
|
||||
ccstd::vector<ISamplerTextureInfo> samplerTextures;
|
||||
ccstd::vector<ISamplerInfo> samplers;
|
||||
ccstd::vector<ITextureInfo> textures;
|
||||
ccstd::vector<IBufferInfo> buffers;
|
||||
ccstd::vector<IImageInfo> images;
|
||||
ccstd::vector<IInputAttachmentInfo> subpassInputs;
|
||||
};
|
||||
|
||||
struct IShaderSource {
|
||||
ccstd::string vert;
|
||||
ccstd::string frag;
|
||||
ccstd::optional<ccstd::string> compute;
|
||||
};
|
||||
|
||||
struct IShaderInfo {
|
||||
ccstd::string name;
|
||||
ccstd::hash_t hash{gfx::INVALID_SHADER_HASH};
|
||||
IShaderSource glsl4;
|
||||
IShaderSource glsl3;
|
||||
IShaderSource glsl1;
|
||||
IBuiltins builtins;
|
||||
ccstd::vector<IDefineInfo> defines;
|
||||
ccstd::vector<IAttributeInfo> attributes;
|
||||
ccstd::vector<IBlockInfo> blocks;
|
||||
ccstd::vector<ISamplerTextureInfo> samplerTextures;
|
||||
ccstd::vector<ISamplerInfo> samplers;
|
||||
ccstd::vector<ITextureInfo> textures;
|
||||
ccstd::vector<IBufferInfo> buffers;
|
||||
ccstd::vector<IImageInfo> images;
|
||||
ccstd::vector<IInputAttachmentInfo> subpassInputs;
|
||||
ccstd::vector<IDescriptorInfo> descriptors;
|
||||
|
||||
const IShaderSource *getSource(const ccstd::string &version) const {
|
||||
if (version == "glsl1") return &glsl1;
|
||||
if (version == "glsl3") return &glsl3;
|
||||
if (version == "glsl4") return &glsl4;
|
||||
return nullptr;
|
||||
}
|
||||
IShaderSource *getSource(const ccstd::string &version) {
|
||||
if (version == "glsl1") return &glsl1;
|
||||
if (version == "glsl3") return &glsl3;
|
||||
if (version == "glsl4") return &glsl4;
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
using IPreCompileInfoValueType = ccstd::variant<ccstd::monostate, ccstd::vector<bool>, ccstd::vector<int32_t>, ccstd::vector<ccstd::string>>;
|
||||
using IPreCompileInfo = ccstd::unordered_map<ccstd::string, IPreCompileInfoValueType>;
|
||||
|
||||
class EffectAsset final : public Asset {
|
||||
public:
|
||||
using Super = Asset;
|
||||
|
||||
EffectAsset() = default;
|
||||
~EffectAsset() override = default;
|
||||
/**
|
||||
* @en Register the effect asset to the static map
|
||||
* @zh 将指定 effect 注册到全局管理器。
|
||||
*/
|
||||
static void registerAsset(EffectAsset *asset);
|
||||
|
||||
/**
|
||||
* @en Unregister the effect asset from the static map
|
||||
* @zh 将指定 effect 从全局管理器移除。
|
||||
*/
|
||||
static void remove(const ccstd::string &name);
|
||||
static void remove(EffectAsset *asset);
|
||||
|
||||
/**
|
||||
* @en Get the effect asset by the given name.
|
||||
* @zh 获取指定名字的 effect 资源。
|
||||
*/
|
||||
static EffectAsset *get(const ccstd::string &name);
|
||||
|
||||
using RegisteredEffectAssetMap = ccstd::unordered_map<ccstd::string, IntrusivePtr<EffectAsset>>;
|
||||
/**
|
||||
* @en Get all registered effect assets.
|
||||
* @zh 获取所有已注册的 effect 资源。
|
||||
*/
|
||||
static RegisteredEffectAssetMap &getAll() { return EffectAsset::effects; }
|
||||
|
||||
static bool isLayoutValid() { return layoutValid; }
|
||||
static void setLayoutValid() { layoutValid = true; }
|
||||
|
||||
inline void setTechniques(const ccstd::vector<ITechniqueInfo> &val) { _techniques = val; }
|
||||
inline void setShaders(const ccstd::vector<IShaderInfo> &val) { _shaders = val; }
|
||||
inline void setCombinations(const ccstd::vector<IPreCompileInfo> &val) { _combinations = val; }
|
||||
|
||||
inline const ccstd::vector<ITechniqueInfo> &getTechniques() const { return _techniques; }
|
||||
inline const ccstd::vector<IShaderInfo> &getShaders() const { return _shaders; }
|
||||
inline const ccstd::vector<IPreCompileInfo> &getCombinations() const { return _combinations; }
|
||||
|
||||
/*
|
||||
@serializable
|
||||
@editorOnly
|
||||
*/
|
||||
bool hideInEditor = false;
|
||||
|
||||
/**
|
||||
* @en The loaded callback which should be invoked by the [[Loader]], will automatically register the effect.
|
||||
* @zh 通过 [[Loader]] 加载完成时的回调,将自动注册 effect 资源。
|
||||
*/
|
||||
void onLoaded() override;
|
||||
bool destroy() override;
|
||||
void initDefault(const ccstd::optional<ccstd::string> &uuid) override;
|
||||
bool validate() const override;
|
||||
|
||||
protected:
|
||||
BaseEngine::EngineStatusChange::EventID _engineEventId;
|
||||
|
||||
static ccstd::vector<MacroRecord> doCombine(const ccstd::vector<MacroRecord> &cur, const IPreCompileInfo &info, IPreCompileInfo::iterator iter);
|
||||
static ccstd::vector<MacroRecord> generateRecords(const ccstd::string &key, const IPreCompileInfoValueType &value);
|
||||
static ccstd::vector<MacroRecord> insertInfoValue(const ccstd::vector<MacroRecord> &records,
|
||||
const ccstd::string &key,
|
||||
const IPreCompileInfoValueType &value);
|
||||
|
||||
void precompile();
|
||||
|
||||
// We need make it to public for deserialization
|
||||
public:
|
||||
/**
|
||||
* @en The techniques used by the current effect.
|
||||
* @zh 当前 effect 的所有可用 technique。
|
||||
|
||||
@serializable
|
||||
@editable*/
|
||||
ccstd::vector<ITechniqueInfo> _techniques;
|
||||
|
||||
/**
|
||||
* @en The shaders used by the current effect.
|
||||
* @zh 当前 effect 使用的所有 shader。
|
||||
|
||||
@serializable
|
||||
@editable*/
|
||||
ccstd::vector<IShaderInfo> _shaders;
|
||||
|
||||
/**
|
||||
* @en The preprocess macro combinations for the shader
|
||||
* @zh 每个 shader 需要预编译的宏定义组合。
|
||||
|
||||
@serializable
|
||||
@editable*/
|
||||
ccstd::vector<IPreCompileInfo> _combinations;
|
||||
//
|
||||
protected:
|
||||
static RegisteredEffectAssetMap effects; // cjh TODO: how to clear when game exits.
|
||||
static bool layoutValid;
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(EffectAsset);
|
||||
|
||||
friend class EffectAssetDeserializer;
|
||||
friend class Material;
|
||||
friend class ProgramLib;
|
||||
friend class MaterialInstance;
|
||||
friend class BuiltinResMgr;
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
116
cocos/core/assets/Font.cpp
Normal file
116
cocos/core/assets/Font.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "Font.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include "base/Data.h"
|
||||
#include "base/Log.h"
|
||||
#include "base/Macros.h"
|
||||
#include "base/memory/Memory.h"
|
||||
#include "base/std/hash/hash.h"
|
||||
#include "gfx-base/GFXTexture.h"
|
||||
#include "math/Math.h"
|
||||
#include "platform/FileUtils.h"
|
||||
#include "profiler/Profiler.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
ccstd::hash_t KerningHash::operator()(const KerningPair &k) const {
|
||||
ccstd::hash_t seed = 2;
|
||||
ccstd::hash_combine(seed, k.prevCode);
|
||||
ccstd::hash_combine(seed, k.nextCode);
|
||||
return seed;
|
||||
}
|
||||
|
||||
/**
|
||||
* FontFaceInfo
|
||||
*/
|
||||
FontFaceInfo::FontFaceInfo(uint32_t size)
|
||||
: fontSize(size) {}
|
||||
|
||||
FontFaceInfo::FontFaceInfo(uint32_t size, uint32_t width, uint32_t height)
|
||||
: fontSize(size), textureWidth(width), textureHeight(height) {
|
||||
CC_ASSERT(math::isPowerOfTwo(width) && math::isPowerOfTwo(height)); // Font texture size must be power of 2.
|
||||
|
||||
// preload digit & alphabet characters by default
|
||||
for (auto i = 0U; i < 128; i++) {
|
||||
if (std::isdigit(i) || std::isalpha(i)) {
|
||||
preLoadedCharacters.emplace_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FontFaceInfo::FontFaceInfo(uint32_t size, uint32_t width, uint32_t height, ccstd::vector<uint32_t> chars)
|
||||
: fontSize(size), textureWidth(width), textureHeight(height), preLoadedCharacters(std::move(chars)) {
|
||||
CC_ASSERT(math::isPowerOfTwo(width) && math::isPowerOfTwo(height)); // Font texture size must be power of 2.
|
||||
}
|
||||
|
||||
/**
|
||||
* FontFace
|
||||
*/
|
||||
FontFace::FontFace(Font *font)
|
||||
: _font(font) {
|
||||
}
|
||||
|
||||
FontFace::~FontFace() {
|
||||
for (auto *texture : _textures) {
|
||||
CC_SAFE_DESTROY_AND_DELETE(texture);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Font
|
||||
*/
|
||||
Font::Font(FontType type, const ccstd::string &path)
|
||||
: _type(type), _path(path) {
|
||||
load(path);
|
||||
}
|
||||
|
||||
Font::~Font() {
|
||||
releaseFaces();
|
||||
CC_PROFILE_MEMORY_DEC(Font, _data.size());
|
||||
}
|
||||
|
||||
void Font::load(const ccstd::string &path) {
|
||||
Data data = FileUtils::getInstance()->getDataFromFile(path);
|
||||
if (data.isNull()) {
|
||||
CC_LOG_WARNING("Font load failed, path: %s.", path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
_data.resize(data.getSize());
|
||||
memcpy(&_data[0], data.getBytes(), data.getSize());
|
||||
CC_PROFILE_MEMORY_INC(Font, _data.size());
|
||||
}
|
||||
|
||||
void Font::releaseFaces() {
|
||||
for (auto &iter : _faces) {
|
||||
delete iter.second;
|
||||
}
|
||||
|
||||
_faces.clear();
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
157
cocos/core/assets/Font.h
Normal file
157
cocos/core/assets/Font.h
Normal file
@@ -0,0 +1,157 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include "base/std/container/unordered_map.h"
|
||||
#include "base/std/container/vector.h"
|
||||
#include "core/assets/Asset.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace gfx {
|
||||
class Texture;
|
||||
}
|
||||
|
||||
class Font;
|
||||
|
||||
constexpr uint32_t DEFAULT_FREETYPE_TEXTURE_SIZE = 512U;
|
||||
constexpr uint32_t MIN_FONT_SIZE = 1U;
|
||||
constexpr uint32_t MAX_FONT_SIZE = 128U;
|
||||
|
||||
enum class FontType {
|
||||
INVALID,
|
||||
FREETYPE,
|
||||
BITMAP,
|
||||
};
|
||||
|
||||
struct FontGlyph {
|
||||
int16_t x{0};
|
||||
int16_t y{0};
|
||||
uint16_t width{0U};
|
||||
uint16_t height{0U};
|
||||
int16_t bearingX{0};
|
||||
int16_t bearingY{0};
|
||||
int32_t advance{0};
|
||||
uint32_t page{0U}; // index of textures
|
||||
};
|
||||
|
||||
struct KerningPair {
|
||||
uint32_t prevCode{0U};
|
||||
uint32_t nextCode{0U};
|
||||
|
||||
inline bool operator==(const KerningPair &k) const noexcept {
|
||||
return prevCode == k.prevCode && nextCode == k.nextCode;
|
||||
}
|
||||
|
||||
inline bool operator!=(const KerningPair &k) const noexcept {
|
||||
return !(*this == k);
|
||||
}
|
||||
};
|
||||
|
||||
struct KerningHash {
|
||||
ccstd::hash_t operator()(const KerningPair &k) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* FontFaceInfo
|
||||
*/
|
||||
struct FontFaceInfo {
|
||||
explicit FontFaceInfo(uint32_t size);
|
||||
FontFaceInfo(uint32_t size, uint32_t width, uint32_t height);
|
||||
FontFaceInfo(uint32_t size, uint32_t width, uint32_t height, ccstd::vector<uint32_t> chars);
|
||||
|
||||
// only used in freetype, for bitmap font, fontSize is determined by file.
|
||||
uint32_t fontSize{1U};
|
||||
uint32_t textureWidth{DEFAULT_FREETYPE_TEXTURE_SIZE};
|
||||
uint32_t textureHeight{DEFAULT_FREETYPE_TEXTURE_SIZE};
|
||||
ccstd::vector<uint32_t> preLoadedCharacters;
|
||||
//~
|
||||
};
|
||||
|
||||
/**
|
||||
* FontFace
|
||||
*/
|
||||
class FontFace {
|
||||
public:
|
||||
explicit FontFace(Font *font);
|
||||
virtual ~FontFace();
|
||||
FontFace(const FontFace &) = delete;
|
||||
FontFace(FontFace &&) = delete;
|
||||
FontFace &operator=(const FontFace &) = delete;
|
||||
FontFace &operator=(FontFace &&) = delete;
|
||||
|
||||
virtual const FontGlyph *getGlyph(uint32_t code) = 0;
|
||||
virtual float getKerning(uint32_t prevCode, uint32_t nextCode) = 0;
|
||||
|
||||
inline Font *getFont() const { return _font; }
|
||||
inline uint32_t getFontSize() const { return _fontSize; }
|
||||
inline uint32_t getLineHeight() const { return _lineHeight; }
|
||||
inline const ccstd::vector<gfx::Texture *> &getTextures() const { return _textures; }
|
||||
inline gfx::Texture *getTexture(uint32_t page) const { return _textures[page]; }
|
||||
inline uint32_t getTextureWidth() const { return _textureWidth; }
|
||||
inline uint32_t getTextureHeight() const { return _textureHeight; }
|
||||
|
||||
protected:
|
||||
virtual void doInit(const FontFaceInfo &info) = 0;
|
||||
|
||||
Font *_font{nullptr};
|
||||
uint32_t _fontSize{1U};
|
||||
uint32_t _lineHeight{0U};
|
||||
ccstd::unordered_map<uint32_t, FontGlyph> _glyphs;
|
||||
ccstd::unordered_map<KerningPair, float, KerningHash> _kernings;
|
||||
ccstd::vector<gfx::Texture *> _textures;
|
||||
uint32_t _textureWidth{0U};
|
||||
uint32_t _textureHeight{0U};
|
||||
};
|
||||
|
||||
/**
|
||||
* Font
|
||||
*/
|
||||
class Font : public Asset {
|
||||
public:
|
||||
Font(FontType type, const ccstd::string &path);
|
||||
~Font() override;
|
||||
Font(const Font &) = delete;
|
||||
Font(Font &&) = delete;
|
||||
Font &operator=(const Font &) = delete;
|
||||
Font &operator=(Font &&) = delete;
|
||||
|
||||
virtual FontFace *createFace(const FontFaceInfo &info) = 0;
|
||||
|
||||
inline FontType getType() const { return _type; }
|
||||
inline const ccstd::string &getPath() const { return _path; }
|
||||
inline const ccstd::vector<uint8_t> &getData() const { return _data; }
|
||||
inline FontFace *getFace(uint32_t fontSize) { return _faces[fontSize]; }
|
||||
void releaseFaces();
|
||||
|
||||
protected:
|
||||
void load(const ccstd::string &path);
|
||||
|
||||
FontType _type{FontType::INVALID};
|
||||
ccstd::string _path;
|
||||
ccstd::vector<uint8_t> _data;
|
||||
ccstd::unordered_map<uint32_t, FontFace *> _faces;
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
316
cocos/core/assets/FreeTypeFont.cpp
Normal file
316
cocos/core/assets/FreeTypeFont.cpp
Normal file
@@ -0,0 +1,316 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
Portions of this software are copyright ? <2022> The FreeType
|
||||
Project (www.freetype.org). All rights reserved.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "FreeTypeFont.h"
|
||||
#include <freetype/ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include <cstdint>
|
||||
#include "base/Log.h"
|
||||
#include "gfx-base/GFXDevice.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
/**
|
||||
* FTLibrary
|
||||
*/
|
||||
struct FTLibrary {
|
||||
FTLibrary() {
|
||||
FT_Error error = FT_Init_FreeType(&lib);
|
||||
if (error) {
|
||||
CC_LOG_ERROR("FreeType init failed, error code: %d.", error);
|
||||
}
|
||||
}
|
||||
|
||||
~FTLibrary() {
|
||||
if (lib) {
|
||||
FT_Error error = FT_Done_FreeType(lib);
|
||||
if (error) {
|
||||
CC_LOG_ERROR("FreeType exit failed, error code: %d.", error);
|
||||
}
|
||||
|
||||
lib = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
FT_Library lib{nullptr};
|
||||
};
|
||||
|
||||
/**
|
||||
* FTFace
|
||||
*/
|
||||
struct FTFace {
|
||||
explicit FTFace(FT_Face f)
|
||||
: face(f) {
|
||||
}
|
||||
|
||||
~FTFace() {
|
||||
if (face) {
|
||||
FT_Done_Face(face);
|
||||
face = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
FT_Face face{nullptr};
|
||||
};
|
||||
|
||||
/**
|
||||
* GlyphAllocator: allocate space for glyph from top to down, from left to right.
|
||||
*/
|
||||
class GlyphAllocator {
|
||||
public:
|
||||
GlyphAllocator(uint32_t maxWidth, uint32_t maxHeight)
|
||||
: _maxWidth(maxWidth), _maxHeight(maxHeight) {}
|
||||
|
||||
inline void reset() {
|
||||
_nextX = 0U;
|
||||
_nextY = 0U;
|
||||
_maxLineHeight = 0U;
|
||||
}
|
||||
|
||||
bool allocate(uint32_t width, uint32_t height, uint32_t &x, uint32_t &y) {
|
||||
// try current line
|
||||
if (_nextX + width <= _maxWidth && _nextY + height <= _maxHeight) {
|
||||
x = _nextX;
|
||||
y = _nextY;
|
||||
|
||||
_nextX += width;
|
||||
_maxLineHeight = std::max(_maxLineHeight, height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// try next line
|
||||
uint32_t nextY = _nextY + _maxLineHeight;
|
||||
if (width <= _maxWidth && nextY + height <= _maxHeight) {
|
||||
x = 0U;
|
||||
y = nextY;
|
||||
|
||||
_nextX = width;
|
||||
_nextY = nextY;
|
||||
_maxLineHeight = height;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
// texture resolution
|
||||
const uint32_t _maxWidth{0U};
|
||||
const uint32_t _maxHeight{0U};
|
||||
|
||||
// next space
|
||||
uint32_t _nextX{0U};
|
||||
uint32_t _nextY{0U};
|
||||
|
||||
// max height of current line
|
||||
uint32_t _maxLineHeight{0U};
|
||||
};
|
||||
|
||||
/**
|
||||
* FreeTypeFontFace
|
||||
*/
|
||||
FTLibrary *FreeTypeFontFace::library = nullptr;
|
||||
FreeTypeFontFace::FreeTypeFontFace(Font *font)
|
||||
: FontFace(font) {
|
||||
if (!library) {
|
||||
library = ccnew FTLibrary();
|
||||
}
|
||||
}
|
||||
|
||||
void FreeTypeFontFace::doInit(const FontFaceInfo &info) {
|
||||
const auto &fontData = _font->getData();
|
||||
if (fontData.empty()) {
|
||||
CC_LOG_ERROR("FreeTypeFontFace doInit failed: empty font data.");
|
||||
return;
|
||||
}
|
||||
|
||||
_fontSize = info.fontSize < MIN_FONT_SIZE ? MIN_FONT_SIZE : (info.fontSize > MAX_FONT_SIZE ? MAX_FONT_SIZE : info.fontSize);
|
||||
_textureWidth = info.textureWidth;
|
||||
_textureHeight = info.textureHeight;
|
||||
_allocator = std::make_unique<GlyphAllocator>(_textureWidth, _textureHeight);
|
||||
|
||||
FT_Face face{nullptr};
|
||||
FT_Error error = FT_New_Memory_Face(library->lib, fontData.data(), static_cast<FT_Long>(fontData.size()), 0, &face);
|
||||
if (error) {
|
||||
CC_LOG_ERROR("FT_New_Memory_Face failed, error code: %d.", error);
|
||||
return;
|
||||
}
|
||||
|
||||
error = FT_Set_Pixel_Sizes(face, 0, _fontSize);
|
||||
if (error) {
|
||||
CC_LOG_ERROR("FT_Set_Pixel_Sizes failed, error code: %d.", error);
|
||||
return;
|
||||
}
|
||||
|
||||
_face = std::make_unique<FTFace>(face);
|
||||
_lineHeight = static_cast<uint32_t>(face->size->metrics.height >> 6);
|
||||
|
||||
for (const auto &code : info.preLoadedCharacters) {
|
||||
loadGlyph(code);
|
||||
}
|
||||
}
|
||||
|
||||
const FontGlyph *FreeTypeFontFace::getGlyph(uint32_t code) {
|
||||
auto iter = _glyphs.find(code);
|
||||
if (iter != _glyphs.end()) {
|
||||
return &iter->second;
|
||||
}
|
||||
|
||||
return loadGlyph(code);
|
||||
}
|
||||
|
||||
float FreeTypeFontFace::getKerning(uint32_t prevCode, uint32_t nextCode) {
|
||||
FT_Face face = _face->face;
|
||||
if (!FT_HAS_KERNING(face)) {
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
const auto &iter = _kernings.find({prevCode, nextCode});
|
||||
if (iter != _kernings.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
FT_Vector kerning;
|
||||
FT_UInt prevIndex = FT_Get_Char_Index(face, prevCode);
|
||||
FT_UInt nextIndex = FT_Get_Char_Index(face, nextCode);
|
||||
FT_Error error = FT_Get_Kerning(face, prevIndex, nextIndex, FT_KERNING_DEFAULT, &kerning);
|
||||
|
||||
if (error) {
|
||||
CC_LOG_WARNING("FT_Get_Kerning failed, error code: %d, prevCode: %d, nextCode: %d", error, prevCode, nextCode);
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
auto result = static_cast<float>(kerning.x >> 6);
|
||||
_kernings[{prevCode, nextCode}] = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const FontGlyph *FreeTypeFontFace::loadGlyph(uint32_t code) {
|
||||
FT_Face face = _face->face;
|
||||
FT_Error error = FT_Load_Char(face, code, FT_LOAD_RENDER);
|
||||
if (error) {
|
||||
CC_LOG_WARNING("FT_Load_Char failed, error code: %d, character: %u.", error, code);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FontGlyph glyph;
|
||||
glyph.width = face->glyph->bitmap.width;
|
||||
glyph.height = face->glyph->bitmap.rows;
|
||||
glyph.bearingX = face->glyph->bitmap_left;
|
||||
glyph.bearingY = face->glyph->bitmap_top;
|
||||
glyph.advance = static_cast<int32_t>(face->glyph->advance.x >> 6); // advance.x's unit is 1/64 pixels
|
||||
|
||||
uint32_t x = 0U;
|
||||
uint32_t y = 0U;
|
||||
|
||||
if (_textures.empty()) {
|
||||
createTexture(_textureWidth, _textureHeight);
|
||||
}
|
||||
|
||||
if (glyph.width > 0U && glyph.height > 0U) {
|
||||
// try current texture
|
||||
if (!_allocator->allocate(glyph.width + 1, glyph.height + 1, x, y)) {
|
||||
createTexture(_textureWidth, _textureHeight);
|
||||
|
||||
// try new empty texture
|
||||
_allocator->reset();
|
||||
if (!_allocator->allocate(glyph.width + 1, glyph.height + 1, x, y)) {
|
||||
CC_LOG_WARNING("Glyph allocate failed, character: %u.", code);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
auto page = static_cast<uint32_t>(_textures.size() - 1);
|
||||
updateTexture(page, x, y, glyph.width, glyph.height, face->glyph->bitmap.buffer);
|
||||
|
||||
glyph.x = x;
|
||||
glyph.y = y;
|
||||
glyph.page = page;
|
||||
}
|
||||
|
||||
_glyphs[code] = glyph;
|
||||
|
||||
return &_glyphs[code];
|
||||
}
|
||||
|
||||
void FreeTypeFontFace::createTexture(uint32_t width, uint32_t height) {
|
||||
auto *device = gfx::Device::getInstance();
|
||||
auto *texture = device->createTexture({gfx::TextureType::TEX2D,
|
||||
gfx::TextureUsageBit::SAMPLED | gfx::TextureUsageBit::TRANSFER_DST,
|
||||
gfx::Format::R8,
|
||||
width,
|
||||
height});
|
||||
|
||||
_textures.push_back(texture);
|
||||
|
||||
std::vector<uint8_t> empty(width * height, 0);
|
||||
auto page = static_cast<uint32_t>(_textures.size() - 1);
|
||||
updateTexture(page, 0U, 0U, width, height, empty.data());
|
||||
}
|
||||
|
||||
void FreeTypeFontFace::updateTexture(uint32_t page, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const uint8_t *buffer) {
|
||||
auto *texture = getTexture(page);
|
||||
gfx::BufferDataList buffers{buffer};
|
||||
gfx::BufferTextureCopyList regions = {{0U,
|
||||
0U,
|
||||
0U,
|
||||
{static_cast<int32_t>(x), static_cast<int32_t>(y), 0U},
|
||||
{width, height, 1U},
|
||||
{0U, 0U, 1U}}};
|
||||
|
||||
auto *device = gfx::Device::getInstance();
|
||||
device->copyBuffersToTexture(buffers, texture, regions);
|
||||
}
|
||||
|
||||
void FreeTypeFontFace::destroyFreeType() {
|
||||
if (library) {
|
||||
delete library;
|
||||
library = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FreeTypeFont
|
||||
*/
|
||||
FreeTypeFont::FreeTypeFont(const ccstd::string &path)
|
||||
: Font(FontType::FREETYPE, path) {
|
||||
}
|
||||
|
||||
FontFace *FreeTypeFont::createFace(const FontFaceInfo &info) {
|
||||
auto *face = ccnew FreeTypeFontFace(this);
|
||||
face->doInit(info);
|
||||
|
||||
uint32_t fontSize = face->getFontSize();
|
||||
_faces[fontSize] = face;
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
85
cocos/core/assets/FreeTypeFont.h
Normal file
85
cocos/core/assets/FreeTypeFont.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
Portions of this software are copyright ? <2022> The FreeType
|
||||
Project (www.freetype.org). All rights reserved.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "Font.h"
|
||||
#include "base/std/container/string.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
struct FTLibrary;
|
||||
struct FTFace;
|
||||
class GlyphAllocator;
|
||||
|
||||
/**
|
||||
* FreeTypeFontFace
|
||||
*/
|
||||
class FreeTypeFontFace : public FontFace {
|
||||
public:
|
||||
explicit FreeTypeFontFace(Font *font);
|
||||
~FreeTypeFontFace() override = default;
|
||||
FreeTypeFontFace(const FreeTypeFontFace &) = delete;
|
||||
FreeTypeFontFace(FreeTypeFontFace &&) = delete;
|
||||
FreeTypeFontFace &operator=(const FreeTypeFontFace &) = delete;
|
||||
FreeTypeFontFace &operator=(FreeTypeFontFace &&) = delete;
|
||||
|
||||
const FontGlyph *getGlyph(uint32_t code) override;
|
||||
float getKerning(uint32_t prevCode, uint32_t nextCode) override;
|
||||
static void destroyFreeType();
|
||||
|
||||
private:
|
||||
void doInit(const FontFaceInfo &info) override;
|
||||
const FontGlyph *loadGlyph(uint32_t code);
|
||||
void createTexture(uint32_t width, uint32_t height);
|
||||
void updateTexture(uint32_t page, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const uint8_t *buffer);
|
||||
|
||||
std::unique_ptr<GlyphAllocator> _allocator{nullptr};
|
||||
std::unique_ptr<FTFace> _face;
|
||||
static FTLibrary *library;
|
||||
|
||||
friend class FreeTypeFont;
|
||||
};
|
||||
|
||||
/**
|
||||
* FreeTypeFont
|
||||
*/
|
||||
class FreeTypeFont : public Font {
|
||||
public:
|
||||
explicit FreeTypeFont(const ccstd::string &path);
|
||||
~FreeTypeFont() override = default;
|
||||
FreeTypeFont(const FreeTypeFont &) = delete;
|
||||
FreeTypeFont(FreeTypeFont &&) = delete;
|
||||
FreeTypeFont &operator=(const FreeTypeFont &) = delete;
|
||||
FreeTypeFont &operator=(FreeTypeFont &&) = delete;
|
||||
|
||||
FontFace *createFace(const FontFaceInfo &info) override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
137
cocos/core/assets/ImageAsset.cpp
Normal file
137
cocos/core/assets/ImageAsset.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "core/assets/ImageAsset.h"
|
||||
|
||||
#include "platform/Image.h"
|
||||
|
||||
#include "base/Log.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
ImageAsset::~ImageAsset() {
|
||||
if (_needFreeData && _data) {
|
||||
free(_data);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageAsset::setNativeAsset(const ccstd::any &obj) {
|
||||
if (obj.has_value()) {
|
||||
auto **pImage = const_cast<Image **>(ccstd::any_cast<Image *>(&obj));
|
||||
if (pImage != nullptr) {
|
||||
Image *image = *pImage;
|
||||
image->takeData(&_data);
|
||||
_needFreeData = true;
|
||||
|
||||
_width = image->getWidth();
|
||||
_height = image->getHeight();
|
||||
_format = static_cast<PixelFormat>(image->getRenderFormat());
|
||||
_url = image->getFilePath();
|
||||
_mipmapLevelDataSize = image->getMipmapLevelDataSize();
|
||||
} else {
|
||||
const auto *imageSource = ccstd::any_cast<IMemoryImageSource>(&obj);
|
||||
if (imageSource != nullptr) {
|
||||
_arrayBuffer = imageSource->data;
|
||||
_data = const_cast<uint8_t *>(_arrayBuffer->getData());
|
||||
_width = imageSource->width;
|
||||
_height = imageSource->height;
|
||||
_format = imageSource->format;
|
||||
_mipmapLevelDataSize = imageSource->mipmapLevelDataSize;
|
||||
} else {
|
||||
CC_LOG_WARNING("ImageAsset::setNativeAsset, unknown type!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IntrusivePtr<ImageAsset> ImageAsset::extractMipmap0() {
|
||||
auto *res = new ImageAsset;
|
||||
|
||||
res->_data = nullptr;
|
||||
res->_needFreeData = false;
|
||||
res->_width = _width;
|
||||
res->_height = _height;
|
||||
res->_format = _format;
|
||||
res->_uuid = _uuid;
|
||||
res->_data = _data;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<IntrusivePtr<ImageAsset>> ImageAsset::extractMipmaps() {
|
||||
std::vector<IntrusivePtr<ImageAsset>> res{};
|
||||
|
||||
if (!_mipmapLevelDataSize.empty()) {
|
||||
size_t offset = 0UL;
|
||||
auto height = _height;
|
||||
auto width = _width;
|
||||
for (auto mipmapSize : _mipmapLevelDataSize) {
|
||||
auto *mipmap = new ImageAsset;
|
||||
mipmap->_data = _data + offset;
|
||||
mipmap->_needFreeData = false;
|
||||
mipmap->_width = width;
|
||||
mipmap->_height = height;
|
||||
mipmap->_format = _format;
|
||||
mipmap->_uuid = _uuid;
|
||||
|
||||
offset += mipmapSize;
|
||||
width = std::max(width >> 1, 1U);
|
||||
height = std::max(height >> 1, 1U);
|
||||
res.emplace_back(mipmap);
|
||||
}
|
||||
} else {
|
||||
res.emplace_back(this);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
const uint8_t *ImageAsset::getData() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
uint32_t ImageAsset::getWidth() const {
|
||||
return _width;
|
||||
}
|
||||
|
||||
uint32_t ImageAsset::getHeight() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
PixelFormat ImageAsset::getFormat() const {
|
||||
return _format;
|
||||
}
|
||||
|
||||
const std::vector<uint32_t> &ImageAsset::getMipmapLevelDataSize() const {
|
||||
return _mipmapLevelDataSize;
|
||||
}
|
||||
|
||||
bool ImageAsset::isCompressed() const {
|
||||
return (_format >= PixelFormat::RGB_ETC1 && _format <= PixelFormat::RGBA_ASTC_12X12) || (_format >= PixelFormat::RGB_A_PVRTC_2BPPV1 && _format <= PixelFormat::RGBA_ETC1);
|
||||
}
|
||||
|
||||
const ccstd::string &ImageAsset::getUrl() const {
|
||||
return _url;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
138
cocos/core/assets/ImageAsset.h
Normal file
138
cocos/core/assets/ImageAsset.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/assets/Asset.h"
|
||||
#include "core/assets/AssetEnum.h"
|
||||
|
||||
#include "core/ArrayBuffer.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class Image;
|
||||
|
||||
/**
|
||||
* @en Image source in memory
|
||||
* @zh 内存图像源。
|
||||
*/
|
||||
struct IMemoryImageSource {
|
||||
ArrayBuffer::Ptr data;
|
||||
bool compressed{false};
|
||||
uint32_t width{0};
|
||||
uint32_t height{0};
|
||||
PixelFormat format{PixelFormat::RGBA8888};
|
||||
ccstd::vector<uint32_t> mipmapLevelDataSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* @en Image Asset.
|
||||
* @zh 图像资源。
|
||||
*/
|
||||
class ImageAsset final : public Asset {
|
||||
public:
|
||||
using Super = Asset;
|
||||
|
||||
ImageAsset() = default;
|
||||
~ImageAsset() override;
|
||||
|
||||
//minggo: do not need it in c++.
|
||||
// ccstd::any getNativeAsset() const override { return ccstd::any(_nativeData); }
|
||||
void setNativeAsset(const ccstd::any &obj) override;
|
||||
|
||||
/**
|
||||
* @en Image data.
|
||||
* @zh 此图像资源的图像数据。
|
||||
*/
|
||||
const uint8_t *getData() const;
|
||||
|
||||
/**
|
||||
* @en The pixel width of the image.
|
||||
* @zh 此图像资源的像素宽度。
|
||||
*/
|
||||
uint32_t getWidth() const;
|
||||
|
||||
/**
|
||||
* @en The pixel height of the image.
|
||||
* @zh 此图像资源的像素高度。
|
||||
*/
|
||||
uint32_t getHeight() const;
|
||||
|
||||
/**
|
||||
* @en The pixel format of the image.
|
||||
* @zh 此图像资源的像素格式。
|
||||
*/
|
||||
PixelFormat getFormat() const;
|
||||
|
||||
/**
|
||||
* @en The pixel mipmap level data size of the image.
|
||||
* @zh 此图像资源的mipmap层级大小。
|
||||
*/
|
||||
const ccstd::vector<uint32_t> &getMipmapLevelDataSize() const;
|
||||
|
||||
/**
|
||||
* @en Whether the image is in compressed texture format.
|
||||
* @zh 此图像资源是否为压缩像素格式。
|
||||
*/
|
||||
bool isCompressed() const;
|
||||
|
||||
/**
|
||||
* @en The original source image URL, it could be empty.
|
||||
* @zh 此图像资源的原始图像源的 URL。当原始图像元不是 HTML 文件时可能为空。
|
||||
* @deprecated Please use [[nativeUrl]]
|
||||
*/
|
||||
const ccstd::string &getUrl() const;
|
||||
|
||||
// Functions for TS.
|
||||
inline void setWidth(uint32_t width) { _width = width; }
|
||||
inline void setHeight(uint32_t height) { _height = height; }
|
||||
inline void setFormat(PixelFormat format) { _format = format; }
|
||||
inline void setData(uint8_t *data) { _data = data; }
|
||||
inline void setNeedFreeData(bool v) { _needFreeData = v; }
|
||||
inline void setUrl(const ccstd::string &url) { _url = url; }
|
||||
inline void setMipmapLevelDataSize(const ccstd::vector<uint32_t> &mipmapLevelDataSize) { _mipmapLevelDataSize = mipmapLevelDataSize; }
|
||||
|
||||
// Functions for Utils.
|
||||
IntrusivePtr<ImageAsset> extractMipmap0();
|
||||
std::vector<IntrusivePtr<ImageAsset>> extractMipmaps();
|
||||
|
||||
private:
|
||||
uint8_t *_data{nullptr};
|
||||
|
||||
PixelFormat _format{PixelFormat::RGBA8888};
|
||||
uint32_t _width{0};
|
||||
uint32_t _height{0};
|
||||
|
||||
bool _needFreeData{false}; // Should free data if the data is assigned in C++.
|
||||
|
||||
ArrayBuffer::Ptr _arrayBuffer; //minggo: hold the data from ImageSource.
|
||||
|
||||
ccstd::string _url;
|
||||
|
||||
ccstd::vector<uint32_t> _mipmapLevelDataSize;
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(ImageAsset);
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
447
cocos/core/assets/Material.cpp
Normal file
447
cocos/core/assets/Material.cpp
Normal file
@@ -0,0 +1,447 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "core/assets/Material.h"
|
||||
|
||||
#include "base/Utils.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/assets/EffectAsset.h"
|
||||
#include "core/builtin/BuiltinResMgr.h"
|
||||
#include "core/platform/Debug.h"
|
||||
#include "math/Color.h"
|
||||
#include "renderer/pipeline/helper/Utils.h"
|
||||
#include "scene/Pass.h"
|
||||
namespace cc {
|
||||
|
||||
/* static */
|
||||
ccstd::hash_t Material::getHashForMaterial(Material *material) {
|
||||
if (material == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ccstd::hash_t hash = 0U;
|
||||
const auto &passes = *material->_passes;
|
||||
for (const auto &pass : passes) {
|
||||
hash ^= pass->getHash();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
Material::Material() {
|
||||
_passes = std::make_shared<ccstd::vector<IntrusivePtr<scene::Pass>>>();
|
||||
}
|
||||
|
||||
Material::~Material() = default;
|
||||
|
||||
void Material::initialize(const IMaterialInfo &info) {
|
||||
auto &passes = *_passes;
|
||||
if (!passes.empty()) {
|
||||
debug::warnID(12005);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_defines.empty()) {
|
||||
_defines.clear();
|
||||
}
|
||||
if (!_states.empty()) {
|
||||
_states.clear();
|
||||
}
|
||||
if (!_props.empty()) {
|
||||
_props.clear();
|
||||
}
|
||||
|
||||
fillInfo(info);
|
||||
update();
|
||||
}
|
||||
|
||||
void Material::reset(const IMaterialInfo &info) { // to be consistent with other assets
|
||||
initialize(info);
|
||||
}
|
||||
|
||||
bool Material::destroy() {
|
||||
doDestroy();
|
||||
return Super::destroy();
|
||||
}
|
||||
|
||||
void Material::doDestroy() {
|
||||
auto &passes = *_passes;
|
||||
if (!passes.empty()) {
|
||||
for (const auto &pass : passes) {
|
||||
pass->destroy();
|
||||
}
|
||||
}
|
||||
passes.clear();
|
||||
emit<PassesUpdated>();
|
||||
}
|
||||
|
||||
void Material::recompileShaders(const MacroRecord & /*overrides*/, index_t /*passIdx*/) {
|
||||
CC_ABORT();
|
||||
CC_LOG_WARNING("Shaders in material asset '%s' cannot be modified at runtime, please instantiate the material first.", _name.c_str());
|
||||
}
|
||||
|
||||
void Material::overridePipelineStates(const PassOverrides & /*overrides*/, index_t /*passIdx*/) {
|
||||
CC_ABORT();
|
||||
CC_LOG_WARNING("Pipeline states in material asset '%s' cannot be modified at runtime, please instantiate the material first.", _name.c_str());
|
||||
}
|
||||
|
||||
void Material::onLoaded() {
|
||||
update();
|
||||
}
|
||||
|
||||
void Material::resetUniforms(bool clearPasses /* = true */) {
|
||||
const auto &passes = *_passes;
|
||||
_props.resize(passes.size());
|
||||
|
||||
if (!clearPasses) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &pass : passes) {
|
||||
pass->resetUBOs();
|
||||
pass->resetTextures();
|
||||
}
|
||||
}
|
||||
|
||||
void Material::setProperty(const ccstd::string &name, const MaterialPropertyVariant &val, index_t passIdx /* = CC_INVALID_INDEX */) {
|
||||
const auto &passes = *_passes;
|
||||
bool success = false;
|
||||
if (passIdx == CC_INVALID_INDEX) { // try set property for all applicable passes
|
||||
size_t len = passes.size();
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
const auto &pass = passes[i];
|
||||
if (uploadProperty(pass, name, val)) {
|
||||
_props[pass->getPropertyIndex()][name] = val;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (passIdx >= passes.size()) {
|
||||
CC_LOG_WARNING("illegal pass index: %d.", passIdx);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &pass = passes[passIdx];
|
||||
if (uploadProperty(pass, name, val)) {
|
||||
_props[pass->getPropertyIndex()][name] = val;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
CC_LOG_WARNING("illegal property name: %s.", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Material::setPropertyNull(const ccstd::string &name, index_t passIdx) {
|
||||
MaterialPropertyVariant val;
|
||||
setProperty(name, val, passIdx);
|
||||
}
|
||||
|
||||
#define CC_MATERIAL_SETPROPERTY_IMPL(funcNameSuffix, type) \
|
||||
void Material::setProperty##funcNameSuffix(const ccstd::string &name, type val, index_t passIdx /* = CC_INVALID_INDEX*/) { \
|
||||
setProperty(name, val, passIdx); \
|
||||
}
|
||||
|
||||
CC_MATERIAL_SETPROPERTY_IMPL(Float32, float)
|
||||
CC_MATERIAL_SETPROPERTY_IMPL(Int32, int32_t)
|
||||
CC_MATERIAL_SETPROPERTY_IMPL(Vec2, const Vec2 &)
|
||||
CC_MATERIAL_SETPROPERTY_IMPL(Vec3, const Vec3 &)
|
||||
CC_MATERIAL_SETPROPERTY_IMPL(Vec4, const Vec4 &)
|
||||
CC_MATERIAL_SETPROPERTY_IMPL(Color, const cc::Color &)
|
||||
CC_MATERIAL_SETPROPERTY_IMPL(Mat3, const Mat3 &)
|
||||
CC_MATERIAL_SETPROPERTY_IMPL(Mat4, const Mat4 &)
|
||||
CC_MATERIAL_SETPROPERTY_IMPL(Quaternion, const Quaternion &)
|
||||
CC_MATERIAL_SETPROPERTY_IMPL(TextureBase, TextureBase *)
|
||||
CC_MATERIAL_SETPROPERTY_IMPL(GFXTexture, gfx::Texture *)
|
||||
|
||||
#undef CC_MATERIAL_SETPROPERTY_IMPL
|
||||
|
||||
#define CC_MATERIAL_SETPROPERTY_ARRAY_IMPL(funcNameSuffix, type) \
|
||||
void Material::setProperty##funcNameSuffix##Array(const ccstd::string &name, const ccstd::vector<type> &val, index_t /*passIdx = CC_INVALID_INDEX*/) { \
|
||||
MaterialPropertyList propertyArr; \
|
||||
propertyArr.reserve(val.size()); \
|
||||
for (const auto &e : val) { \
|
||||
propertyArr.emplace_back(e); \
|
||||
} \
|
||||
setProperty(name, propertyArr); \
|
||||
}
|
||||
|
||||
CC_MATERIAL_SETPROPERTY_ARRAY_IMPL(Float32, float)
|
||||
CC_MATERIAL_SETPROPERTY_ARRAY_IMPL(Int32, int32_t)
|
||||
CC_MATERIAL_SETPROPERTY_ARRAY_IMPL(Vec2, Vec2)
|
||||
CC_MATERIAL_SETPROPERTY_ARRAY_IMPL(Vec3, Vec3)
|
||||
CC_MATERIAL_SETPROPERTY_ARRAY_IMPL(Vec4, Vec4)
|
||||
CC_MATERIAL_SETPROPERTY_ARRAY_IMPL(Color, Color)
|
||||
CC_MATERIAL_SETPROPERTY_ARRAY_IMPL(Mat3, Mat3)
|
||||
CC_MATERIAL_SETPROPERTY_ARRAY_IMPL(Mat4, Mat4)
|
||||
CC_MATERIAL_SETPROPERTY_ARRAY_IMPL(Quaternion, Quaternion)
|
||||
CC_MATERIAL_SETPROPERTY_ARRAY_IMPL(TextureBase, TextureBase *)
|
||||
CC_MATERIAL_SETPROPERTY_ARRAY_IMPL(GFXTexture, gfx::Texture *)
|
||||
|
||||
#undef CC_MATERIAL_SETPROPERTY_ARRAY_IMPL
|
||||
|
||||
const MaterialPropertyVariant *Material::getProperty(const ccstd::string &name, index_t passIdx) const {
|
||||
if (passIdx == CC_INVALID_INDEX) { // try get property in all possible passes
|
||||
const auto &propsArray = _props;
|
||||
size_t len = propsArray.size();
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
const auto &props = propsArray[i];
|
||||
auto iter = props.find(name);
|
||||
if (iter != props.end()) {
|
||||
return &iter->second;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (passIdx >= _props.size()) {
|
||||
CC_LOG_WARNING("illegal pass index: %d.", passIdx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto &passes = *_passes;
|
||||
const auto &props = _props[passes[passIdx]->getPropertyIndex()];
|
||||
auto iter = props.find(name);
|
||||
if (iter != props.end()) {
|
||||
return &iter->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Material::fillInfo(const IMaterialInfo &info) {
|
||||
if (info.technique != ccstd::nullopt) {
|
||||
_techIdx = info.technique.value();
|
||||
}
|
||||
|
||||
if (info.effectAsset != nullptr) {
|
||||
_effectAsset = info.effectAsset;
|
||||
} else if (info.effectName != ccstd::nullopt) {
|
||||
_effectAsset = EffectAsset::get(info.effectName.value());
|
||||
}
|
||||
|
||||
if (info.defines != ccstd::nullopt) {
|
||||
prepareInfo(info.defines.value(), _defines);
|
||||
}
|
||||
if (info.states != ccstd::nullopt) {
|
||||
prepareInfo(info.states.value(), _states);
|
||||
}
|
||||
}
|
||||
|
||||
void Material::copy(const Material *mat, IMaterialInfo *overrides) {
|
||||
if (mat == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
_techIdx = mat->_techIdx;
|
||||
_props.resize(mat->_props.size());
|
||||
for (size_t i = 0, len = mat->_props.size(); i < len; ++i) {
|
||||
_props[i] = mat->_props[i];
|
||||
}
|
||||
_defines.resize(mat->_defines.size());
|
||||
for (size_t i = 0, len = mat->_defines.size(); i < len; ++i) {
|
||||
_defines[i] = mat->_defines[i];
|
||||
}
|
||||
_states.resize(mat->_states.size());
|
||||
for (size_t i = 0, len = mat->_states.size(); i < len; ++i) {
|
||||
_states[i] = mat->_states[i];
|
||||
}
|
||||
_effectAsset = mat->_effectAsset;
|
||||
if (overrides) {
|
||||
fillInfo(*overrides);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void Material::update(bool keepProps /* = true*/) {
|
||||
if (_effectAsset) {
|
||||
*_passes = createPasses();
|
||||
CC_ASSERT(!_effectAsset->_techniques.empty());
|
||||
// handle property values
|
||||
size_t totalPasses = _effectAsset->_techniques[_techIdx].passes.size();
|
||||
_props.resize(totalPasses);
|
||||
if (keepProps) {
|
||||
auto cb = [this](auto *pass, size_t i) {
|
||||
if (i >= _props.size()) {
|
||||
_props.resize(i + 1);
|
||||
}
|
||||
|
||||
auto &props = _props[i];
|
||||
|
||||
if (pass->getPropertyIndex() != CC_INVALID_INDEX) {
|
||||
props = _props[pass->getPropertyIndex()];
|
||||
}
|
||||
|
||||
for (const auto &prop : props) {
|
||||
uploadProperty(pass, prop.first, prop.second);
|
||||
}
|
||||
};
|
||||
|
||||
const auto &passes = *_passes;
|
||||
for (size_t i = 0, len = passes.size(); i < len; ++i) {
|
||||
cb(passes[i].get(), i);
|
||||
}
|
||||
}
|
||||
|
||||
emit<PassesUpdated>();
|
||||
}
|
||||
_hash = Material::getHashForMaterial(this);
|
||||
}
|
||||
|
||||
ccstd::vector<IntrusivePtr<scene::Pass>> Material::createPasses() {
|
||||
ccstd::vector<IntrusivePtr<scene::Pass>> passes;
|
||||
ITechniqueInfo *tech = nullptr;
|
||||
if (_techIdx < _effectAsset->_techniques.size()) {
|
||||
tech = &_effectAsset->_techniques[_techIdx];
|
||||
}
|
||||
|
||||
if (tech == nullptr) {
|
||||
return passes;
|
||||
}
|
||||
|
||||
size_t passNum = tech->passes.size();
|
||||
for (size_t k = 0; k < passNum; ++k) {
|
||||
auto &passInfo = tech->passes[k];
|
||||
index_t propIdx = passInfo.passIndex = static_cast<index_t>(k);
|
||||
|
||||
if (propIdx >= _defines.size()) {
|
||||
_defines.resize(propIdx + 1);
|
||||
}
|
||||
passInfo.defines = _defines[propIdx];
|
||||
auto &defines = passInfo.defines;
|
||||
|
||||
if (propIdx >= _states.size()) {
|
||||
_states.resize(propIdx + 1);
|
||||
}
|
||||
passInfo.stateOverrides = _states[propIdx];
|
||||
|
||||
if (passInfo.propertyIndex.has_value()) {
|
||||
utils::mergeToMap(defines, _defines[passInfo.propertyIndex.value()]);
|
||||
}
|
||||
|
||||
if (passInfo.embeddedMacros.has_value()) {
|
||||
utils::mergeToMap(defines, passInfo.embeddedMacros.value());
|
||||
}
|
||||
|
||||
if (passInfo.switch_.has_value() && defines.find(passInfo.switch_.value()) == defines.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto *pass = ccnew scene::Pass(Root::getInstance());
|
||||
pass->initialize(passInfo);
|
||||
passes.emplace_back(pass);
|
||||
}
|
||||
return passes;
|
||||
}
|
||||
|
||||
bool Material::uploadProperty(scene::Pass *pass, const ccstd::string &name, const MaterialPropertyVariant &val) {
|
||||
uint32_t handle = pass->getHandle(name);
|
||||
if (!handle) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto type = scene::Pass::getTypeFromHandle(handle);
|
||||
if (type < gfx::Type::SAMPLER1D) {
|
||||
if (val.index() == MATERIAL_PROPERTY_INDEX_LIST) {
|
||||
pass->setUniformArray(handle, ccstd::get<MaterialPropertyList>(val));
|
||||
} else if (val.index() == MATERIAL_PROPERTY_INDEX_SINGLE) {
|
||||
const auto &passProps = pass->getProperties();
|
||||
auto iter = passProps.find(name);
|
||||
if (iter != passProps.end() && iter->second.linear.has_value()) {
|
||||
CC_ASSERT(ccstd::holds_alternative<MaterialProperty>(val));
|
||||
const auto &prop = ccstd::get<MaterialProperty>(val);
|
||||
Vec4 srgb;
|
||||
if (ccstd::holds_alternative<cc::Color>(prop)) {
|
||||
srgb = ccstd::get<cc::Color>(prop).toVec4();
|
||||
} else if (ccstd::holds_alternative<Vec4>(prop)) {
|
||||
srgb = ccstd::get<Vec4>(prop);
|
||||
} else {
|
||||
CC_ABORT();
|
||||
}
|
||||
|
||||
Vec4 linear;
|
||||
pipeline::srgbToLinear(&linear, srgb);
|
||||
linear.w = srgb.w;
|
||||
pass->setUniform(handle, linear);
|
||||
} else {
|
||||
pass->setUniform(handle, ccstd::get<MaterialProperty>(val));
|
||||
}
|
||||
} else {
|
||||
pass->resetUniform(name);
|
||||
}
|
||||
} else if (val.index() == MATERIAL_PROPERTY_INDEX_LIST) {
|
||||
const auto &textureArray = ccstd::get<MaterialPropertyList>(val);
|
||||
for (size_t i = 0; i < textureArray.size(); i++) {
|
||||
bindTexture(pass, handle, textureArray[i], static_cast<index_t>(i));
|
||||
}
|
||||
} else if (val.index() == MATERIAL_PROPERTY_INDEX_SINGLE) {
|
||||
bindTexture(pass, handle, ccstd::get<MaterialProperty>(val));
|
||||
} else {
|
||||
pass->resetTexture(name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Material::bindTexture(scene::Pass *pass, uint32_t handle, const MaterialProperty &val, uint32_t index) {
|
||||
if (pass == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t binding = scene::Pass::getBindingFromHandle(handle);
|
||||
if (const auto *pTexture = ccstd::get_if<IntrusivePtr<gfx::Texture>>(&val)) {
|
||||
pass->bindTexture(binding, const_cast<gfx::Texture *>(pTexture->get()), index);
|
||||
} else if (const auto *pTextureBase = ccstd::get_if<IntrusivePtr<TextureBase>>(&val)) {
|
||||
auto *textureBase = pTextureBase->get();
|
||||
gfx::Texture *texture = nullptr;
|
||||
if (textureBase != nullptr) {
|
||||
texture = textureBase->getGFXTexture();
|
||||
}
|
||||
|
||||
if (texture == nullptr) {
|
||||
CC_LOG_WARNING("Material(%p, %s)::bindTexture failed, texture is nullptr", this, _uuid.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (texture->getWidth() == 0 || texture->getHeight() == 0) {
|
||||
CC_LOG_WARNING("Material(%p, %s)::bindTexture failed, texture size is 0", this, _uuid.c_str());
|
||||
return;
|
||||
}
|
||||
pass->bindTexture(binding, texture, index);
|
||||
pass->bindSampler(binding, textureBase->getGFXSampler(), index);
|
||||
}
|
||||
}
|
||||
|
||||
void Material::initDefault(const ccstd::optional<ccstd::string> &uuid) {
|
||||
Super::initDefault(uuid);
|
||||
MacroRecord defines{{"USE_COLOR", true}};
|
||||
IMaterialInfo info;
|
||||
info.effectName = ccstd::string{"builtin-unlit"};
|
||||
info.defines = IMaterialInfo::DefinesType{defines};
|
||||
initialize(info);
|
||||
setProperty("mainColor", Color{0xFF, 0x00, 0xFF, 0xFF});
|
||||
}
|
||||
|
||||
bool Material::validate() const {
|
||||
return _effectAsset != nullptr && !_effectAsset->isDefault() && !_passes->empty();
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
361
cocos/core/assets/Material.h
Normal file
361
cocos/core/assets/Material.h
Normal file
@@ -0,0 +1,361 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Ptr.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/container/unordered_map.h"
|
||||
#include "base/std/optional.h"
|
||||
#include "base/std/variant.h"
|
||||
#include "core/assets/EffectAsset.h"
|
||||
#include "core/event/Event.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
// class RenderableComponent;
|
||||
|
||||
namespace scene {
|
||||
class Pass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en The basic infos for material initialization.
|
||||
* @zh 用来初始化材质的基本信息。
|
||||
*/
|
||||
struct IMaterialInfo {
|
||||
/**
|
||||
* @en The EffectAsset to use. Must provide if `effectName` is not specified.
|
||||
* @zh
|
||||
* 这个材质将使用的 EffectAsset,直接提供资源引用,和 `effectName` 至少要指定一个。
|
||||
*/
|
||||
EffectAsset *effectAsset{nullptr};
|
||||
/**
|
||||
* @en
|
||||
* The name of the EffectAsset to use. Must provide if `effectAsset` is not specified.
|
||||
* @zh
|
||||
* 这个材质将使用的 EffectAsset,通过 effect 名指定,和 `effectAsset` 至少要指定一个。
|
||||
*/
|
||||
ccstd::optional<ccstd::string> effectName;
|
||||
/**
|
||||
* @en
|
||||
* The index of the technique to use.
|
||||
* @zh
|
||||
* 这个材质将使用第几个 technique,默认为 0。
|
||||
*/
|
||||
ccstd::optional<uint32_t> technique;
|
||||
|
||||
using DefinesType = ccstd::variant<ccstd::monostate, MacroRecord, ccstd::vector<MacroRecord>>;
|
||||
/**
|
||||
* @en
|
||||
* The shader macro definitions. Default to 0 or the specified value in [[EffectAsset]].
|
||||
* @zh
|
||||
* 这个材质定义的预处理宏,默认全为 0,或 [[EffectAsset]] 中的指定值。
|
||||
*/
|
||||
ccstd::optional<DefinesType> defines;
|
||||
|
||||
using PassOverridesType = ccstd::variant<ccstd::monostate, PassOverrides, ccstd::vector<PassOverrides>>;
|
||||
/**
|
||||
* @en
|
||||
* The override values on top of the pipeline states specified in [[EffectAsset]].
|
||||
* @zh
|
||||
* 这个材质的自定义管线状态,将覆盖 effect 中的属性。<br>
|
||||
* 注意在可能的情况下请尽量少的自定义管线状态,以减小对渲染效率的影响。
|
||||
*/
|
||||
ccstd::optional<PassOverridesType> states;
|
||||
};
|
||||
|
||||
class Material : public Asset {
|
||||
IMPL_EVENT_TARGET(Material)
|
||||
DECLARE_TARGET_EVENT_BEGIN(Material)
|
||||
TARGET_EVENT_ARG0(PassesUpdated)
|
||||
DECLARE_TARGET_EVENT_END()
|
||||
public:
|
||||
using Super = Asset;
|
||||
/**
|
||||
* @en Get hash for a material
|
||||
* @zh 获取一个材质的哈希值
|
||||
* @param material
|
||||
*/
|
||||
static ccstd::hash_t getHashForMaterial(Material *material);
|
||||
|
||||
Material();
|
||||
~Material() override;
|
||||
|
||||
/**
|
||||
* @en Initialize this material with the given information.
|
||||
* @zh 根据所给信息初始化这个材质,初始化正常结束后材质即可立即用于渲染。
|
||||
* @param info Material description info.
|
||||
*/
|
||||
void initialize(const IMaterialInfo &info);
|
||||
void reset(const IMaterialInfo &info);
|
||||
|
||||
void initDefault(const ccstd::optional<ccstd::string> &uuid) override;
|
||||
bool validate() const override;
|
||||
|
||||
/**
|
||||
* @en
|
||||
* Destroy the material definitively.<br>
|
||||
* Cannot re-initialize after destroy.<br>
|
||||
* Modifications on active materials can be acheived by<br>
|
||||
* creating a new Material, invoke the `copy` function<br>
|
||||
* with the desired overrides, and assigning it to the target components.
|
||||
* @zh
|
||||
* 彻底销毁材质,注意销毁后无法重新初始化。<br>
|
||||
* 如需修改现有材质,请创建一个新材质,<br>
|
||||
* 调用 copy 函数传入需要的 overrides 并赋给目标组件。
|
||||
*/
|
||||
bool destroy() override;
|
||||
|
||||
/**
|
||||
* @en Recompile the shader with the specified macro overrides. Allowed only on material instances.
|
||||
* @zh 使用指定预处理宏重新编译当前 pass(数组)中的 shader。只允许对材质实例执行。
|
||||
* @param overrides The shader macro override values.
|
||||
* @param passIdx The pass to apply to. Will apply to all passes if not specified.
|
||||
*/
|
||||
virtual void recompileShaders(const MacroRecord &overrides) {
|
||||
Material::recompileShaders(overrides, CC_INVALID_INDEX);
|
||||
}
|
||||
virtual void recompileShaders(const MacroRecord &overrides, index_t passIdx);
|
||||
|
||||
/**
|
||||
* @en Override the passes with the specified pipeline states. Allowed only on material instances.
|
||||
* @zh 使用指定管线状态重载当前的 pass(数组)。只允许对材质实例执行。
|
||||
* @param overrides The pipeline state override values.
|
||||
* @param passIdx The pass to apply to. Will apply to all passes if not specified.
|
||||
*/
|
||||
virtual void overridePipelineStates(const PassOverrides &overrides) {
|
||||
Material::overridePipelineStates(overrides, CC_INVALID_INDEX);
|
||||
}
|
||||
virtual void overridePipelineStates(const PassOverrides &overrides, index_t passIdx);
|
||||
|
||||
/**
|
||||
* @en Callback function after material is loaded in [[Loader]]. Initialize the resources automatically.
|
||||
* @zh 通过 [[Loader]] 加载完成时的回调,将自动初始化材质资源。
|
||||
*/
|
||||
void onLoaded() override;
|
||||
|
||||
/**
|
||||
* @en Reset all the uniforms to the default value specified in [[EffectAsset]].
|
||||
* @zh 重置材质的所有 uniform 参数数据为 [[EffectAsset]] 中的默认初始值。
|
||||
* @param clearPasses Will the rendering data be cleared too?
|
||||
*/
|
||||
void resetUniforms(bool clearPasses = true);
|
||||
|
||||
/**
|
||||
* @en
|
||||
* Convenient property setter provided for quick material setup.<br>
|
||||
* [[Pass.setUniform]] should be used instead if you need to do per-frame uniform update.
|
||||
* @zh
|
||||
* 设置材质 uniform 参数的统一入口。<br>
|
||||
* 注意如果需要每帧更新 uniform,建议使用 [[Pass.setUniform]] 以获得更好的性能。
|
||||
* @param name The target uniform name.
|
||||
* @param val The target value.
|
||||
* @param passIdx The pass to apply to. Will apply to all passes if not specified.
|
||||
*/
|
||||
void setProperty(const ccstd::string &name, const MaterialPropertyVariant &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
|
||||
void setPropertyNull(const ccstd::string &name, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyFloat32(const ccstd::string &name, float val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyInt32(const ccstd::string &name, int32_t val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyVec2(const ccstd::string &name, const Vec2 &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyVec3(const ccstd::string &name, const Vec3 &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyVec4(const ccstd::string &name, const Vec4 &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyColor(const ccstd::string &name, const Color &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyMat3(const ccstd::string &name, const Mat3 &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyMat4(const ccstd::string &name, const Mat4 &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyQuaternion(const ccstd::string &name, const Quaternion &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyTextureBase(const ccstd::string &name, TextureBase *val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyGFXTexture(const ccstd::string &name, gfx::Texture *val, index_t passIdx = CC_INVALID_INDEX);
|
||||
|
||||
void setPropertyFloat32Array(const ccstd::string &name, const ccstd::vector<float> &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyInt32Array(const ccstd::string &name, const ccstd::vector<int32_t> &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyVec2Array(const ccstd::string &name, const ccstd::vector<Vec2> &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyVec3Array(const ccstd::string &name, const ccstd::vector<Vec3> &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyVec4Array(const ccstd::string &name, const ccstd::vector<Vec4> &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyColorArray(const ccstd::string &name, const ccstd::vector<cc::Color> &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyMat3Array(const ccstd::string &name, const ccstd::vector<Mat3> &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyMat4Array(const ccstd::string &name, const ccstd::vector<Mat4> &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyQuaternionArray(const ccstd::string &name, const ccstd::vector<Quaternion> &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyTextureBaseArray(const ccstd::string &name, const ccstd::vector<TextureBase *> &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
void setPropertyGFXTextureArray(const ccstd::string &name, const ccstd::vector<gfx::Texture *> &val, index_t passIdx = CC_INVALID_INDEX);
|
||||
|
||||
/**
|
||||
* @en
|
||||
* Get the specified uniform value for this material.<br>
|
||||
* Note that only uniforms set through [[Material.setProperty]] can be acquired here.<br>
|
||||
* For the complete rendering data, use [[Pass.getUniform]] instead.
|
||||
* @zh
|
||||
* 获取当前材质的指定 uniform 参数的值。<br>
|
||||
* 注意只有通过 [[Material.setProperty]] 函数设置的参数才能从此函数取出,<br>
|
||||
* 如需取出完整的渲染数据,请使用 [[Pass.getUniform]]。
|
||||
* @param name The property or uniform name.
|
||||
* @param passIdx The target pass index. If not specified, return the first found value in all passes.
|
||||
*/
|
||||
const MaterialPropertyVariant *getProperty(const ccstd::string &name, index_t passIdx = CC_INVALID_INDEX) const;
|
||||
|
||||
/**
|
||||
* @en Copy the target material, with optional overrides.
|
||||
* @zh 复制目标材质到当前实例,允许提供重载信息。。
|
||||
* @param mat The material to be copied.
|
||||
* @param overrides The overriding states on top of the original material.
|
||||
*/
|
||||
void copy(const Material *mat, IMaterialInfo *overrides = nullptr);
|
||||
|
||||
void fillInfo(const IMaterialInfo &info);
|
||||
|
||||
// For deserialization, we need to make the following properties public
|
||||
/* @type(EffectAsset) */
|
||||
IntrusivePtr<EffectAsset> _effectAsset;
|
||||
|
||||
/* @serializable */
|
||||
uint32_t _techIdx{0};
|
||||
|
||||
/* @serializable */
|
||||
ccstd::vector<MacroRecord> _defines;
|
||||
|
||||
/* @serializable */
|
||||
ccstd::vector<PassOverrides> _states;
|
||||
|
||||
/* @serializable */
|
||||
ccstd::vector<ccstd::unordered_map<ccstd::string, MaterialPropertyVariant>> _props;
|
||||
//
|
||||
|
||||
protected:
|
||||
std::shared_ptr<ccstd::vector<IntrusivePtr<scene::Pass>>> _passes;
|
||||
|
||||
ccstd::hash_t _hash{0U};
|
||||
|
||||
public:
|
||||
/**
|
||||
* @en Set current [[EffectAsset]].
|
||||
* @zh 设置使用的 [[EffectAsset]] 资源。
|
||||
*/
|
||||
inline void setEffectAsset(EffectAsset *val) {
|
||||
_effectAsset = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en The current [[EffectAsset]].
|
||||
* @zh 当前使用的 [[EffectAsset]] 资源。
|
||||
*/
|
||||
inline EffectAsset *getEffectAsset() const {
|
||||
return _effectAsset.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Name of the current [[EffectAsset]].
|
||||
* @zh 当前使用的 [[EffectAsset]] 资源名。
|
||||
*/
|
||||
inline ccstd::string getEffectName() const {
|
||||
return _effectAsset ? _effectAsset->getName() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @en The current technique index.
|
||||
* @zh 当前的 technique 索引。
|
||||
*/
|
||||
inline uint32_t getTechniqueIndex() const {
|
||||
return _techIdx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en The passes defined in this material.
|
||||
* @zh 当前正在使用的 pass 数组。
|
||||
*/
|
||||
std::shared_ptr<ccstd::vector<IntrusivePtr<scene::Pass>>> &getPasses() {
|
||||
return _passes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en The hash value of this material.
|
||||
* @zh 材质的 hash。
|
||||
*/
|
||||
inline ccstd::hash_t getHash() const {
|
||||
return _hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en The parent material
|
||||
* @zh 父材质
|
||||
*/
|
||||
virtual Material *getParent() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en The owner render component
|
||||
* @zh 该材质所归属的渲染组件
|
||||
*/
|
||||
// virtual RenderableComponent *getOwner() const {
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
protected:
|
||||
void update(bool keepProps = true);
|
||||
bool uploadProperty(scene::Pass *pass, const ccstd::string &name, const MaterialPropertyVariant &val);
|
||||
void bindTexture(scene::Pass *pass, uint32_t handle, const MaterialProperty &val, uint32_t index = 0);
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void prepareInfo(const T1 &patch, ccstd::vector<T2> &cur) {
|
||||
auto *pOneElement = ccstd::get_if<T2>(&patch);
|
||||
if (pOneElement != nullptr) {
|
||||
size_t len = _effectAsset != nullptr ? _effectAsset->_techniques[_techIdx].passes.size() : 1;
|
||||
|
||||
ccstd::vector<T2> patchArray;
|
||||
patchArray.reserve(len);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
patchArray.emplace_back(*pOneElement);
|
||||
}
|
||||
|
||||
cur.resize(patchArray.size());
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
cur[i] = patchArray[i];
|
||||
}
|
||||
} else {
|
||||
auto *pPatchArray = ccstd::get_if<ccstd::vector<T2>>(&patch);
|
||||
if (pPatchArray != nullptr) {
|
||||
const auto &patchArray = *pPatchArray;
|
||||
size_t len = patchArray.size();
|
||||
cur.resize(len);
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
cur[i] = patchArray[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void doDestroy();
|
||||
|
||||
virtual ccstd::vector<IntrusivePtr<scene::Pass>> createPasses();
|
||||
|
||||
private:
|
||||
friend class MaterialDeserializer;
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(Material);
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
175
cocos/core/assets/RenderTexture.cpp
Normal file
175
cocos/core/assets/RenderTexture.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "core/assets/RenderTexture.h"
|
||||
#include "core/Root.h"
|
||||
#include "core/platform/Debug.h"
|
||||
#include "core/utils/IDGenerator.h"
|
||||
#include "renderer/gfx-base/GFXDef-common.h"
|
||||
#include "scene/RenderWindow.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace {
|
||||
gfx::RenderPassInfo getDefaultRenderPassInfo(gfx::Device *device) {
|
||||
gfx::RenderPassInfo info;
|
||||
info.colorAttachments.push_back({
|
||||
gfx::Format::RGBA8,
|
||||
gfx::SampleCount::X1,
|
||||
gfx::LoadOp::CLEAR,
|
||||
gfx::StoreOp::STORE,
|
||||
device->getGeneralBarrier({
|
||||
gfx::AccessFlagBit::FRAGMENT_SHADER_READ_TEXTURE,
|
||||
gfx::AccessFlagBit::FRAGMENT_SHADER_READ_TEXTURE,
|
||||
}),
|
||||
});
|
||||
info.depthStencilAttachment.format = gfx::Format::DEPTH_STENCIL;
|
||||
return info;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
RenderTexture::RenderTexture() = default;
|
||||
RenderTexture::~RenderTexture() = default;
|
||||
|
||||
void RenderTexture::initialize(const IRenderTextureCreateInfo &info) {
|
||||
_name = info.name.has_value() ? info.name.value() : "";
|
||||
_width = info.width;
|
||||
_height = info.height;
|
||||
initWindow(info);
|
||||
}
|
||||
|
||||
void RenderTexture::reset(const IRenderTextureCreateInfo &info) {
|
||||
initialize(info);
|
||||
}
|
||||
|
||||
bool RenderTexture::destroy() {
|
||||
if (_window != nullptr) {
|
||||
Root::getInstance()->destroyWindow(_window);
|
||||
_window = nullptr;
|
||||
}
|
||||
return Super::destroy();
|
||||
}
|
||||
|
||||
void RenderTexture::resize(uint32_t width, uint32_t height) {
|
||||
_width = std::floor(clampf(static_cast<float>(width), 1.F, 2048.F));
|
||||
_height = std::floor(clampf(static_cast<float>(height), 1.F, 2048.F));
|
||||
if (_window != nullptr) {
|
||||
_window->resize(_width, _height);
|
||||
}
|
||||
// emit(ccstd::string("resize"), _window); //TODO(xwx): not inherit form Eventify in Asset base class
|
||||
}
|
||||
|
||||
gfx::Texture *RenderTexture::getGFXTexture() const {
|
||||
return _window ? _window->getFramebuffer()->getColorTextures()[0] : nullptr;
|
||||
}
|
||||
|
||||
void RenderTexture::onLoaded() {
|
||||
initWindow();
|
||||
}
|
||||
|
||||
void RenderTexture::initWindow() {
|
||||
auto *device{Root::getInstance()->getDevice()};
|
||||
|
||||
cc::scene::IRenderWindowInfo windowInfo;
|
||||
windowInfo.title = _name;
|
||||
windowInfo.width = _width;
|
||||
windowInfo.height = _height;
|
||||
windowInfo.renderPassInfo = getDefaultRenderPassInfo(device);
|
||||
|
||||
if (_window != nullptr) {
|
||||
_window->destroy();
|
||||
_window->initialize(device, windowInfo);
|
||||
} else {
|
||||
_window = Root::getInstance()->createWindow(windowInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderTexture::initWindow(const IRenderTextureCreateInfo &info) {
|
||||
auto *device{Root::getInstance()->getDevice()};
|
||||
|
||||
cc::scene::IRenderWindowInfo windowInfo;
|
||||
windowInfo.title = _name;
|
||||
windowInfo.width = _width;
|
||||
windowInfo.height = _height;
|
||||
if (info.passInfo.has_value()) {
|
||||
windowInfo.renderPassInfo = info.passInfo.value();
|
||||
} else {
|
||||
windowInfo.renderPassInfo = getDefaultRenderPassInfo(device);
|
||||
}
|
||||
|
||||
if (info.externalResLow.has_value()) {
|
||||
windowInfo.externalResLow = info.externalResLow.value();
|
||||
}
|
||||
|
||||
if (info.externalResHigh.has_value()) {
|
||||
windowInfo.externalResHigh = info.externalResHigh.value();
|
||||
}
|
||||
|
||||
if (info.externalFlag.has_value()) {
|
||||
windowInfo.externalFlag = info.externalFlag.value();
|
||||
}
|
||||
|
||||
if (_window != nullptr) {
|
||||
_window->destroy();
|
||||
_window->initialize(device, windowInfo);
|
||||
} else {
|
||||
_window = Root::getInstance()->createWindow(windowInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderTexture::initDefault(const ccstd::optional<ccstd::string> &uuid) {
|
||||
Super::initDefault(uuid);
|
||||
_width = 1;
|
||||
_height = 1;
|
||||
initWindow();
|
||||
}
|
||||
|
||||
bool RenderTexture::validate() const {
|
||||
return _width >= 1 && _width <= 2048 && _height >= 1 && _height <= 2048;
|
||||
}
|
||||
|
||||
ccstd::vector<uint8_t> RenderTexture::readPixels(uint32_t x, uint32_t y, uint32_t width, uint32_t height) const {
|
||||
auto *gfxTexture = getGFXTexture();
|
||||
if (!gfxTexture) {
|
||||
debug::errorID(7606);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto *gfxDevice = getGFXDevice();
|
||||
|
||||
gfx::BufferTextureCopy region0{};
|
||||
region0.texOffset.x = static_cast<int32_t>(x);
|
||||
region0.texOffset.y = static_cast<int32_t>(y);
|
||||
region0.texExtent.width = width;
|
||||
region0.texExtent.height = height;
|
||||
|
||||
ccstd::vector<uint8_t> buffer;
|
||||
buffer.resize(width * height * 4);
|
||||
uint8_t *pBuffer = buffer.data();
|
||||
gfxDevice->copyTextureToBuffers(gfxTexture, &pBuffer, ®ion0, 1);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
123
cocos/core/assets/RenderTexture.h
Normal file
123
cocos/core/assets/RenderTexture.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/assets/TextureBase.h"
|
||||
#include "renderer/gfx-base/GFXDef.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
struct IRenderTextureCreateInfo {
|
||||
ccstd::optional<ccstd::string> name;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
ccstd::optional<gfx::RenderPassInfo> passInfo;
|
||||
ccstd::optional<uint32_t> externalResLow; // for vulkan vkImage/opengl es texture created from external
|
||||
ccstd::optional<uint32_t> externalResHigh; // for vulkan vkImage created from external
|
||||
ccstd::optional<gfx::TextureFlags> externalFlag; // external texture type normal or oes
|
||||
};
|
||||
namespace scene {
|
||||
class RenderWindow;
|
||||
}
|
||||
|
||||
namespace gfx {
|
||||
class Texture;
|
||||
class Sampler;
|
||||
} // namespace gfx
|
||||
|
||||
/**
|
||||
* @en Render texture is a render target for [[Camera]] or [[Canvas]] component,
|
||||
* the render pipeline will use its [[RenderWindow]] as the target of the rendering process.
|
||||
* @zh 渲染贴图是 [[Camera]] 或 [[Canvas]] 组件的渲染目标对象,渲染管线会使用它的 [[RenderWindow]] 作为渲染的目标窗口。
|
||||
*/
|
||||
class RenderTexture final : public TextureBase {
|
||||
public:
|
||||
using Super = TextureBase;
|
||||
|
||||
RenderTexture();
|
||||
~RenderTexture() override;
|
||||
|
||||
/**
|
||||
* @en The render window for the render pipeline, it's created internally and cannot be modified.
|
||||
* @zh 渲染管线所使用的渲染窗口,内部逻辑创建,无法被修改。
|
||||
*/
|
||||
inline scene::RenderWindow *getWindow() const { return _window; }
|
||||
|
||||
void initialize(const IRenderTextureCreateInfo &info);
|
||||
void reset(const IRenderTextureCreateInfo &info); // to be consistent with other assets
|
||||
|
||||
bool destroy() override;
|
||||
|
||||
/**
|
||||
* @en Resize the render texture
|
||||
* @zh 修改渲染贴图的尺寸
|
||||
* @param width The pixel width, the range is from 1 to 2048
|
||||
* @param height The pixel height, the range is from 1 to 2048
|
||||
*/
|
||||
void resize(uint32_t width, uint32_t height);
|
||||
|
||||
// TODO(minggo): migration with TextureBase data
|
||||
// @ts-expect-error Hack
|
||||
// get _serialize () { return null; }
|
||||
// @ts-expect-error Hack
|
||||
// get _deserialize () { return null; }
|
||||
|
||||
// To be compatible with material property interface
|
||||
/**
|
||||
* @en Gets the related [[Texture]] resource, it's also the color attachment for the render window
|
||||
* @zh 获取渲染贴图的 GFX 资源,同时也是渲染窗口所指向的颜色缓冲贴图资源
|
||||
*/
|
||||
gfx::Texture *getGFXTexture() const override;
|
||||
|
||||
void onLoaded() override;
|
||||
|
||||
void initWindow();
|
||||
void initWindow(const IRenderTextureCreateInfo &info);
|
||||
|
||||
void initDefault(const ccstd::optional<ccstd::string> &uuid) override;
|
||||
|
||||
bool validate() const override;
|
||||
|
||||
/**
|
||||
* @en Read pixel buffer from render texture
|
||||
* @param x The location on x axis
|
||||
* @param y The location on y axis
|
||||
* @param width The pixel width
|
||||
* @param height The pixel height
|
||||
* @zh 从 render texture 读取像素数据
|
||||
* @param x 起始位置X轴坐标
|
||||
* @param y 起始位置Y轴坐标
|
||||
* @param width 像素宽度
|
||||
* @param height 像素高度
|
||||
*/
|
||||
ccstd::vector<uint8_t> readPixels(uint32_t x, uint32_t y, uint32_t width, uint32_t height) const;
|
||||
|
||||
private:
|
||||
scene::RenderWindow *_window{nullptr};
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(RenderTexture);
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
380
cocos/core/assets/RenderingSubMesh.cpp
Normal file
380
cocos/core/assets/RenderingSubMesh.cpp
Normal file
@@ -0,0 +1,380 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "core/assets/RenderingSubMesh.h"
|
||||
#include <cstdint>
|
||||
#include "3d/assets/Mesh.h"
|
||||
#include "3d/misc/Buffer.h"
|
||||
#include "core/DataView.h"
|
||||
#include "core/TypedArray.h"
|
||||
#include "math/Utils.h"
|
||||
#include "math/Vec3.h"
|
||||
#include "renderer/gfx-base/GFXBuffer.h"
|
||||
#include "renderer/gfx-base/GFXDevice.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
RenderingSubMesh::RenderingSubMesh(const gfx::BufferList &vertexBuffers,
|
||||
const gfx::AttributeList &attributes,
|
||||
gfx::PrimitiveMode primitiveMode)
|
||||
: RenderingSubMesh(vertexBuffers, attributes, primitiveMode, nullptr, nullptr, true) {
|
||||
}
|
||||
|
||||
RenderingSubMesh::RenderingSubMesh(const gfx::BufferList &vertexBuffers,
|
||||
const gfx::AttributeList &attributes,
|
||||
gfx::PrimitiveMode primitiveMode,
|
||||
gfx::Buffer *indexBuffer)
|
||||
: RenderingSubMesh(vertexBuffers, attributes, primitiveMode, indexBuffer, nullptr, true) {
|
||||
}
|
||||
|
||||
RenderingSubMesh::RenderingSubMesh(const gfx::BufferList &vertexBuffers,
|
||||
const gfx::AttributeList &attributes,
|
||||
gfx::PrimitiveMode primitiveMode,
|
||||
gfx::Buffer *indexBuffer,
|
||||
gfx::Buffer *indirectBuffer)
|
||||
: RenderingSubMesh(vertexBuffers, attributes, primitiveMode, indexBuffer, indirectBuffer, true) {
|
||||
}
|
||||
|
||||
RenderingSubMesh::RenderingSubMesh(const gfx::BufferList &vertexBuffers,
|
||||
const gfx::AttributeList &attributes,
|
||||
gfx::PrimitiveMode primitiveMode,
|
||||
gfx::Buffer *indexBuffer,
|
||||
gfx::Buffer *indirectBuffer,
|
||||
bool isOwnerOfIndexBuffer)
|
||||
: _vertexBuffers(vertexBuffers),
|
||||
_attributes(attributes),
|
||||
_primitiveMode(primitiveMode),
|
||||
_indexBuffer(indexBuffer),
|
||||
_indirectBuffer(indirectBuffer),
|
||||
_isOwnerOfIndexBuffer(isOwnerOfIndexBuffer) {
|
||||
_iaInfo.attributes = attributes;
|
||||
_iaInfo.vertexBuffers = vertexBuffers;
|
||||
_iaInfo.indexBuffer = indexBuffer;
|
||||
_iaInfo.indirectBuffer = indirectBuffer;
|
||||
}
|
||||
|
||||
RenderingSubMesh::~RenderingSubMesh() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
const IGeometricInfo &RenderingSubMesh::getGeometricInfo() {
|
||||
if (_geometricInfo.has_value()) {
|
||||
return _geometricInfo.value();
|
||||
}
|
||||
// NOLINTNEXTLINE
|
||||
static const IGeometricInfo EMPTY_GEOMETRIC_INFO;
|
||||
if (_mesh == nullptr) {
|
||||
return EMPTY_GEOMETRIC_INFO;
|
||||
}
|
||||
|
||||
if (!_subMeshIdx.has_value()) {
|
||||
return EMPTY_GEOMETRIC_INFO;
|
||||
}
|
||||
|
||||
auto iter = std::find_if(_attributes.cbegin(), _attributes.cend(), [](const gfx::Attribute &element) -> bool {
|
||||
return element.name == gfx::ATTR_NAME_POSITION;
|
||||
});
|
||||
if (iter == _attributes.end()) {
|
||||
return EMPTY_GEOMETRIC_INFO;
|
||||
}
|
||||
|
||||
const auto &attri = *iter;
|
||||
const uint32_t count = gfx::GFX_FORMAT_INFOS[static_cast<uint32_t>(attri.format)].count;
|
||||
|
||||
auto index = static_cast<index_t>(_subMeshIdx.value());
|
||||
const auto &positionsVar = _mesh->readAttribute(index, gfx::ATTR_NAME_POSITION);
|
||||
|
||||
Float32Array const *pPositions = nullptr;
|
||||
switch (attri.format) {
|
||||
case gfx::Format::RG32F:
|
||||
case gfx::Format::RGB32F: {
|
||||
pPositions = ccstd::get_if<Float32Array>(&positionsVar);
|
||||
if (pPositions == nullptr) {
|
||||
return EMPTY_GEOMETRIC_INFO;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case gfx::Format::RGBA32F: {
|
||||
const auto *data = ccstd::get_if<Float32Array>(&positionsVar);
|
||||
if (data == nullptr) {
|
||||
return EMPTY_GEOMETRIC_INFO;
|
||||
}
|
||||
const auto count = data->length() / 4;
|
||||
auto *pos = ccnew Float32Array(count * 3);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
const auto dstPtr = i * 3;
|
||||
const auto srcPtr = i * 4;
|
||||
(*pos)[dstPtr] = (*data)[srcPtr];
|
||||
(*pos)[dstPtr + 1] = (*data)[srcPtr + 1];
|
||||
(*pos)[dstPtr + 2] = (*data)[srcPtr + 2];
|
||||
}
|
||||
pPositions = pos;
|
||||
break;
|
||||
}
|
||||
case gfx::Format::RG16F:
|
||||
case gfx::Format::RGB16F: {
|
||||
const auto *data = ccstd::get_if<Uint16Array>(&positionsVar);
|
||||
if (data == nullptr) {
|
||||
return EMPTY_GEOMETRIC_INFO;
|
||||
}
|
||||
auto *pos = ccnew Float32Array(data->length());
|
||||
for (uint32_t i = 0; i < data->length(); ++i) {
|
||||
(*pos)[i] = mathutils::halfToFloat((*data)[i]);
|
||||
}
|
||||
pPositions = pos;
|
||||
break;
|
||||
}
|
||||
case gfx::Format::RGBA16F: {
|
||||
const auto *data = ccstd::get_if<Uint16Array>(&positionsVar);
|
||||
if (data == nullptr) {
|
||||
return EMPTY_GEOMETRIC_INFO;
|
||||
}
|
||||
const auto count = data->length() / 4;
|
||||
auto *pos = ccnew Float32Array(count * 3);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
const auto dstPtr = i * 3;
|
||||
const auto srcPtr = i * 4;
|
||||
(*pos)[dstPtr] = mathutils::halfToFloat((*data)[srcPtr]);
|
||||
(*pos)[dstPtr + 1] = mathutils::halfToFloat((*data)[srcPtr + 1]);
|
||||
(*pos)[dstPtr + 2] = mathutils::halfToFloat((*data)[srcPtr + 2]);
|
||||
}
|
||||
pPositions = pos;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return EMPTY_GEOMETRIC_INFO;
|
||||
};
|
||||
|
||||
const auto &positions = *pPositions;
|
||||
const auto &indicesVar = _mesh->readIndices(index);
|
||||
|
||||
Vec3 max;
|
||||
Vec3 min;
|
||||
|
||||
if (count == 2) {
|
||||
max.set(positions[0], positions[1], 0);
|
||||
min.set(positions[0], positions[1], 0);
|
||||
} else {
|
||||
max.set(positions[0], positions[1], positions[2]);
|
||||
min.set(positions[0], positions[1], positions[2]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < positions.length(); i += static_cast<int>(count)) {
|
||||
if (count == 2) {
|
||||
max.x = positions[i] > max.x ? positions[i] : max.x;
|
||||
max.y = positions[i + 1] > max.y ? positions[i + 1] : max.y;
|
||||
min.x = positions[i] < min.x ? positions[i] : min.x;
|
||||
min.y = positions[i + 1] < min.y ? positions[i + 1] : min.y;
|
||||
} else {
|
||||
max.x = positions[i] > max.x ? positions[i] : max.x;
|
||||
max.y = positions[i + 1] > max.y ? positions[i + 1] : max.y;
|
||||
max.z = positions[i + 2] > max.z ? positions[i + 2] : max.z;
|
||||
min.x = positions[i] < min.x ? positions[i] : min.x;
|
||||
min.y = positions[i + 1] < min.y ? positions[i + 1] : min.y;
|
||||
min.z = positions[i + 2] < min.z ? positions[i + 2] : min.z;
|
||||
}
|
||||
}
|
||||
|
||||
IGeometricInfo info;
|
||||
info.positions = positions;
|
||||
info.indices = indicesVar;
|
||||
info.boundingBox.max = max;
|
||||
info.boundingBox.min = min;
|
||||
|
||||
_geometricInfo = info;
|
||||
return _geometricInfo.value();
|
||||
}
|
||||
|
||||
void RenderingSubMesh::genFlatBuffers() {
|
||||
if (!_flatBuffers.empty() || _mesh == nullptr || !_subMeshIdx.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t idxCount = 0;
|
||||
const auto &prim = _mesh->getStruct().primitives[_subMeshIdx.value()];
|
||||
if (prim.indexView.has_value()) {
|
||||
idxCount = prim.indexView.value().count;
|
||||
}
|
||||
for (size_t i = 0; i < prim.vertexBundelIndices.size(); i++) {
|
||||
const uint32_t bundleIdx = prim.vertexBundelIndices[i];
|
||||
const Mesh::IVertexBundle &vertexBundle = _mesh->getStruct().vertexBundles[bundleIdx];
|
||||
const uint32_t vbCount = prim.indexView.has_value() ? prim.indexView.value().count : vertexBundle.view.count;
|
||||
const uint32_t vbStride = vertexBundle.view.stride;
|
||||
const uint32_t vbSize = vbStride * vbCount;
|
||||
Uint8Array view(_mesh->getData().buffer(), vertexBundle.view.offset, vertexBundle.view.length);
|
||||
Uint8Array sharedView(prim.indexView.has_value() ? vbSize : vertexBundle.view.length);
|
||||
|
||||
if (!prim.indexView.has_value()) {
|
||||
sharedView.set(_mesh->getData().subarray(vertexBundle.view.offset, vertexBundle.view.offset + vertexBundle.view.length));
|
||||
_flatBuffers.emplace_back(IFlatBuffer{vbStride, vbCount, sharedView});
|
||||
continue;
|
||||
}
|
||||
|
||||
IBArray ibView = _mesh->readIndices(static_cast<int>(_subMeshIdx.value()));
|
||||
// transform to flat buffer
|
||||
for (uint32_t n = 0; n < idxCount; ++n) {
|
||||
auto idx = getIBArrayValue<int32_t>(ibView, static_cast<int>(n));
|
||||
uint32_t offset = n * vbStride;
|
||||
uint32_t srcOffset = idx * vbStride;
|
||||
for (uint32_t m = 0; m < vbStride; ++m) {
|
||||
sharedView[static_cast<int>(offset + m)] = view[static_cast<int>(srcOffset + m)];
|
||||
}
|
||||
}
|
||||
_flatBuffers.emplace_back(IFlatBuffer{vbStride, vbCount, std::move(sharedView)});
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingSubMesh::enableVertexIdChannel(gfx::Device *device) {
|
||||
if (_vertexIdChannel.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto streamIndex = static_cast<uint32_t>(_vertexBuffers.size());
|
||||
const auto attributeIndex = static_cast<uint32_t>(_attributes.size());
|
||||
|
||||
gfx::Buffer *vertexIdBuffer = allocVertexIdBuffer(device);
|
||||
_vertexBuffers.pushBack(vertexIdBuffer);
|
||||
_attributes.push_back({"a_vertexId", gfx::Format::R32F, false, streamIndex, false, 0});
|
||||
|
||||
_iaInfo.attributes = _attributes;
|
||||
_iaInfo.vertexBuffers = _vertexBuffers.get();
|
||||
|
||||
_vertexIdChannel = VertexIdChannel{
|
||||
streamIndex,
|
||||
attributeIndex,
|
||||
};
|
||||
}
|
||||
|
||||
bool RenderingSubMesh::destroy() {
|
||||
_vertexBuffers.clear();
|
||||
_indexBuffer = nullptr;
|
||||
_indirectBuffer = nullptr;
|
||||
|
||||
if (!_jointMappedBuffers.empty() && !_jointMappedBufferIndices.empty()) {
|
||||
for (uint32_t index : _jointMappedBufferIndices) {
|
||||
_jointMappedBuffers.at(index)->destroy();
|
||||
}
|
||||
_jointMappedBuffers.clear();
|
||||
_jointMappedBufferIndices.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const gfx::BufferList &RenderingSubMesh::getJointMappedBuffers() {
|
||||
if (!_jointMappedBuffers.empty()) {
|
||||
return _jointMappedBuffers.get();
|
||||
}
|
||||
|
||||
auto &buffers = _jointMappedBuffers;
|
||||
auto &indices = _jointMappedBufferIndices;
|
||||
|
||||
if (!_mesh || !_subMeshIdx.has_value()) {
|
||||
_jointMappedBuffers = _vertexBuffers;
|
||||
return _jointMappedBuffers.get();
|
||||
}
|
||||
|
||||
const auto &structInfo = _mesh->getStruct();
|
||||
const auto &prim = structInfo.primitives[_subMeshIdx.value()];
|
||||
if (!structInfo.jointMaps.has_value() || !prim.jointMapIndex.has_value() || structInfo.jointMaps.value()[prim.jointMapIndex.value()].empty()) {
|
||||
_jointMappedBuffers = _vertexBuffers;
|
||||
return _jointMappedBuffers.get();
|
||||
}
|
||||
gfx::Format jointFormat = gfx::Format::UNKNOWN;
|
||||
int32_t jointOffset = 0;
|
||||
gfx::Device *device = gfx::Device::getInstance();
|
||||
for (size_t i = 0; i < prim.vertexBundelIndices.size(); i++) {
|
||||
const auto &bundle = structInfo.vertexBundles[prim.vertexBundelIndices[i]];
|
||||
jointOffset = 0;
|
||||
jointFormat = gfx::Format::UNKNOWN;
|
||||
for (const auto &attr : bundle.attributes) {
|
||||
if (attr.name == gfx::ATTR_NAME_JOINTS) {
|
||||
jointFormat = attr.format;
|
||||
break;
|
||||
}
|
||||
jointOffset += static_cast<int32_t>(gfx::GFX_FORMAT_INFOS[static_cast<int32_t>(attr.format)].size);
|
||||
}
|
||||
if (jointFormat != gfx::Format::UNKNOWN) {
|
||||
Uint8Array data{_mesh->getData().buffer(), bundle.view.offset, bundle.view.length};
|
||||
DataView dataView(data.slice().buffer());
|
||||
const auto &idxMap = structInfo.jointMaps.value()[prim.jointMapIndex.value()];
|
||||
|
||||
mapBuffer(
|
||||
dataView, [&](const DataVariant &cur, uint32_t /*idx*/, const DataView & /*view*/) -> DataVariant {
|
||||
if (ccstd::holds_alternative<int32_t>(cur)) {
|
||||
auto iter = std::find(idxMap.begin(), idxMap.end(), ccstd::get<int32_t>(cur));
|
||||
if (iter != idxMap.end()) {
|
||||
return static_cast<int32_t>(iter - idxMap.begin());
|
||||
}
|
||||
}
|
||||
CC_ABORT();
|
||||
return -1;
|
||||
},
|
||||
jointFormat, jointOffset, bundle.view.length, bundle.view.stride, &dataView);
|
||||
|
||||
auto *buffer = device->createBuffer(gfx::BufferInfo{
|
||||
gfx::BufferUsageBit::VERTEX | gfx::BufferUsageBit::TRANSFER_DST,
|
||||
gfx::MemoryUsageBit::DEVICE,
|
||||
bundle.view.length,
|
||||
bundle.view.stride});
|
||||
|
||||
buffer->update(dataView.buffer()->getData());
|
||||
buffers.pushBack(buffer);
|
||||
indices.emplace_back(i);
|
||||
} else {
|
||||
buffers.pushBack(_vertexBuffers.at(prim.vertexBundelIndices[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (_vertexIdChannel) {
|
||||
buffers.pushBack(allocVertexIdBuffer(device));
|
||||
}
|
||||
return buffers.get();
|
||||
}
|
||||
|
||||
gfx::Buffer *RenderingSubMesh::allocVertexIdBuffer(gfx::Device *device) {
|
||||
const uint32_t vertexCount = (_vertexBuffers.empty() || _vertexBuffers.at(0)->getStride() == 0)
|
||||
? 0
|
||||
// TODO(minggo): This depends on how stride of a vertex buffer is defined; Consider padding problem.
|
||||
: _vertexBuffers.at(0)->getSize() / _vertexBuffers.at(0)->getStride();
|
||||
|
||||
ccstd::vector<float> vertexIds(vertexCount);
|
||||
for (int iVertex = 0; iVertex < vertexCount; ++iVertex) {
|
||||
// `+0.5` because on some platforms, the "fetched integer" may have small error.
|
||||
// For example `26` may yield `25.99999`, which is convert to `25` instead of `26` using `int()`.
|
||||
vertexIds[iVertex] = static_cast<float>(iVertex) + 0.5F;
|
||||
}
|
||||
|
||||
uint32_t vertexIdxByteLength = sizeof(float) * vertexCount;
|
||||
gfx::Buffer *vertexIdBuffer = device->createBuffer({
|
||||
gfx::BufferUsageBit::VERTEX | gfx::BufferUsageBit::TRANSFER_DST,
|
||||
gfx::MemoryUsageBit::DEVICE,
|
||||
vertexIdxByteLength,
|
||||
sizeof(float),
|
||||
});
|
||||
vertexIdBuffer->update(vertexIds.data(), vertexIdxByteLength);
|
||||
|
||||
return vertexIdBuffer;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
230
cocos/core/assets/RenderingSubMesh.h
Normal file
230
cocos/core/assets/RenderingSubMesh.h
Normal file
@@ -0,0 +1,230 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "3d/assets/Types.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "base/RefVector.h"
|
||||
#include "base/std/variant.h"
|
||||
#include "core/TypedArray.h"
|
||||
#include "core/Types.h"
|
||||
#include "renderer/gfx-base/GFXDef.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class Mesh;
|
||||
|
||||
/**
|
||||
* @en The interface of geometric information
|
||||
* @zh 几何信息。
|
||||
*/
|
||||
struct IGeometricInfo {
|
||||
/**
|
||||
* @en Vertex positions
|
||||
* @zh 顶点位置。
|
||||
*/
|
||||
Float32Array positions;
|
||||
|
||||
/**
|
||||
* @en Indices data
|
||||
* @zh 索引数据。
|
||||
*/
|
||||
ccstd::optional<IBArray> indices;
|
||||
|
||||
/**
|
||||
* @en Whether the geometry is treated as double sided
|
||||
* @zh 是否将图元按双面对待。
|
||||
*/
|
||||
ccstd::optional<bool> doubleSided;
|
||||
|
||||
/**
|
||||
* @en The bounding box
|
||||
* @zh 此几何体的轴对齐包围盒。
|
||||
*/
|
||||
BoundingBox boundingBox;
|
||||
};
|
||||
|
||||
/**
|
||||
* @en Flat vertex buffer
|
||||
* @zh 扁平化顶点缓冲区
|
||||
*/
|
||||
struct IFlatBuffer {
|
||||
uint32_t stride{0};
|
||||
uint32_t count{0};
|
||||
Uint8Array buffer;
|
||||
};
|
||||
|
||||
namespace gfx {
|
||||
class Buffer;
|
||||
}
|
||||
/**
|
||||
* @en Sub mesh for rendering which contains all geometry data, it can be used to create [[InputAssembler]].
|
||||
* @zh 包含所有顶点数据的渲染子网格,可以用来创建 [[InputAssembler]]。
|
||||
*/
|
||||
class RenderingSubMesh : public RefCounted {
|
||||
public:
|
||||
RenderingSubMesh(const gfx::BufferList &vertexBuffers,
|
||||
const gfx::AttributeList &attributes,
|
||||
gfx::PrimitiveMode primitiveMode);
|
||||
|
||||
RenderingSubMesh(const gfx::BufferList &vertexBuffers,
|
||||
const gfx::AttributeList &attributes,
|
||||
gfx::PrimitiveMode primitiveMode,
|
||||
gfx::Buffer *indexBuffer);
|
||||
|
||||
RenderingSubMesh(const gfx::BufferList &vertexBuffers,
|
||||
const gfx::AttributeList &attributes,
|
||||
gfx::PrimitiveMode primitiveMode,
|
||||
gfx::Buffer *indexBuffer,
|
||||
gfx::Buffer *indirectBuffer);
|
||||
|
||||
RenderingSubMesh(const gfx::BufferList &vertexBuffers,
|
||||
const gfx::AttributeList &attributes,
|
||||
gfx::PrimitiveMode primitiveMode,
|
||||
gfx::Buffer *indexBuffer,
|
||||
gfx::Buffer *indirectBuffer,
|
||||
bool isOwnerOfIndexBuffer);
|
||||
|
||||
~RenderingSubMesh() override;
|
||||
|
||||
/**
|
||||
* @en All vertex attributes used by the sub mesh
|
||||
* @zh 所有顶点属性。
|
||||
*/
|
||||
inline const gfx::AttributeList &getAttributes() const { return _attributes; }
|
||||
|
||||
/**
|
||||
* @en All vertex buffers used by the sub mesh
|
||||
* @zh 使用的所有顶点缓冲区。
|
||||
*/
|
||||
inline const gfx::BufferList &getVertexBuffers() const { return _vertexBuffers.get(); }
|
||||
|
||||
/**
|
||||
* @en Index buffer used by the sub mesh
|
||||
* @zh 使用的索引缓冲区,若未使用则无需指定。
|
||||
*/
|
||||
inline gfx::Buffer *getIndexBuffer() const { return _indexBuffer; }
|
||||
|
||||
/**
|
||||
* @en Indirect buffer used by the sub mesh
|
||||
* @zh 间接绘制缓冲区。
|
||||
*/
|
||||
inline gfx::Buffer *indirectBuffer() const { return _indirectBuffer; }
|
||||
|
||||
/**
|
||||
* @en The geometric info of the sub mesh, used for raycast.
|
||||
* @zh (用于射线检测的)几何信息。
|
||||
*/
|
||||
const IGeometricInfo &getGeometricInfo();
|
||||
|
||||
/**
|
||||
* @en Invalidate the geometric info of the sub mesh after geometry changed.
|
||||
* @zh 网格更新后,设置(用于射线检测的)几何信息为无效,需要重新计算。
|
||||
*/
|
||||
inline void invalidateGeometricInfo() { _geometricInfo.reset(); }
|
||||
|
||||
/**
|
||||
* @en Primitive mode used by the sub mesh
|
||||
* @zh 图元类型。
|
||||
*/
|
||||
inline gfx::PrimitiveMode getPrimitiveMode() const { return _primitiveMode; }
|
||||
|
||||
/**
|
||||
* @en Flatted vertex buffers
|
||||
* @zh 扁平化的顶点缓冲区。
|
||||
*/
|
||||
inline const ccstd::vector<IFlatBuffer> &getFlatBuffers() const { return _flatBuffers; }
|
||||
inline void setFlatBuffers(const ccstd::vector<IFlatBuffer> &flatBuffers) { _flatBuffers = flatBuffers; }
|
||||
|
||||
void genFlatBuffers();
|
||||
|
||||
inline const gfx::InputAssemblerInfo &getIaInfo() const { return _iaInfo; }
|
||||
inline gfx::InputAssemblerInfo &getIaInfo() { return _iaInfo; }
|
||||
|
||||
inline void setDrawInfo(const gfx::DrawInfo &info) { _drawInfo = info; }
|
||||
inline ccstd::optional<gfx::DrawInfo> &getDrawInfo() { return _drawInfo; }
|
||||
|
||||
/**
|
||||
* @en The vertex buffer for joint after mapping
|
||||
* @zh 骨骼索引按映射表处理后的顶点缓冲。
|
||||
*/
|
||||
const gfx::BufferList &getJointMappedBuffers();
|
||||
|
||||
bool destroy();
|
||||
|
||||
/**
|
||||
* @en Adds a vertex attribute input called 'a_vertexId' into this sub-mesh.
|
||||
* This is useful if you want to simulate `gl_VertexId` in WebGL context prior to 2.0.
|
||||
* Once you call this function, the vertex attribute is permanently added.
|
||||
* Subsequent calls to this function take no effect.
|
||||
* @param device Device used to create related rendering resources.
|
||||
*/
|
||||
void enableVertexIdChannel(gfx::Device *device);
|
||||
|
||||
inline void setMesh(Mesh *mesh) { _mesh = mesh; }
|
||||
inline Mesh *getMesh() const { return _mesh; }
|
||||
|
||||
inline void setSubMeshIdx(const ccstd::optional<uint32_t> &idx) { _subMeshIdx = idx; }
|
||||
inline const ccstd::optional<uint32_t> &getSubMeshIdx() const { return _subMeshIdx; }
|
||||
|
||||
private:
|
||||
gfx::Buffer *allocVertexIdBuffer(gfx::Device *device);
|
||||
|
||||
bool _isOwnerOfIndexBuffer{true};
|
||||
|
||||
// Mesh will includes RenderingSubMesh, so use Mesh* here.
|
||||
Mesh *_mesh{nullptr};
|
||||
ccstd::optional<uint32_t> _subMeshIdx;
|
||||
|
||||
ccstd::vector<IFlatBuffer> _flatBuffers;
|
||||
|
||||
// As gfx::InputAssemblerInfo needs the data structure, so not use IntrusivePtr.
|
||||
RefVector<gfx::Buffer *> _jointMappedBuffers;
|
||||
|
||||
ccstd::vector<uint32_t> _jointMappedBufferIndices;
|
||||
|
||||
ccstd::optional<VertexIdChannel> _vertexIdChannel;
|
||||
|
||||
ccstd::optional<IGeometricInfo> _geometricInfo;
|
||||
|
||||
// As gfx::InputAssemblerInfo needs the data structure, so not use IntrusivePtr.
|
||||
RefVector<gfx::Buffer *> _vertexBuffers;
|
||||
|
||||
gfx::AttributeList _attributes;
|
||||
|
||||
IntrusivePtr<gfx::Buffer> _indexBuffer;
|
||||
|
||||
IntrusivePtr<gfx::Buffer> _indirectBuffer;
|
||||
|
||||
gfx::PrimitiveMode _primitiveMode{gfx::PrimitiveMode::TRIANGLE_LIST};
|
||||
|
||||
gfx::InputAssemblerInfo _iaInfo;
|
||||
|
||||
ccstd::optional<gfx::DrawInfo> _drawInfo;
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(RenderingSubMesh);
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
45
cocos/core/assets/SceneAsset.cpp
Normal file
45
cocos/core/assets/SceneAsset.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "core/assets/SceneAsset.h"
|
||||
#include "base/memory/Memory.h"
|
||||
#include "core/scene-graph/Scene.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
SceneAsset::SceneAsset() = default;
|
||||
SceneAsset::~SceneAsset() = default;
|
||||
|
||||
bool SceneAsset::validate() const {
|
||||
return _scene.get() != nullptr;
|
||||
}
|
||||
|
||||
void SceneAsset::setScene(Scene *scene) { _scene = scene; };
|
||||
|
||||
void SceneAsset::initDefault(const ccstd::optional<ccstd::string> &uuid) {
|
||||
Super::initDefault(uuid);
|
||||
_scene = ccnew Scene("New Scene");
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
59
cocos/core/assets/SceneAsset.h
Normal file
59
cocos/core/assets/SceneAsset.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Ptr.h"
|
||||
#include "core/assets/Asset.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class Scene;
|
||||
|
||||
class SceneAsset final : public Asset {
|
||||
public:
|
||||
using Super = Asset;
|
||||
SceneAsset();
|
||||
~SceneAsset() override;
|
||||
|
||||
void initDefault(const ccstd::optional<ccstd::string> &uuid) override;
|
||||
|
||||
bool validate() const override;
|
||||
|
||||
inline Scene *getScene() const { return _scene.get(); }
|
||||
void setScene(Scene *scene);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @en The scene node
|
||||
* @zh 场景节点。
|
||||
|
||||
@editable
|
||||
@serializable*/
|
||||
IntrusivePtr<Scene> _scene;
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(SceneAsset);
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
233
cocos/core/assets/SimpleTexture.cpp
Normal file
233
cocos/core/assets/SimpleTexture.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "core/assets/SimpleTexture.h"
|
||||
#include "core/assets/ImageAsset.h"
|
||||
#include "core/platform/Debug.h"
|
||||
#include "core/platform/Macro.h"
|
||||
#include "renderer/gfx-base/GFXDevice.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace {
|
||||
|
||||
uint32_t getMipLevel(uint32_t width, uint32_t height) {
|
||||
uint32_t size = std::max(width, height);
|
||||
uint32_t level = 0;
|
||||
while (size) {
|
||||
size >>= 1;
|
||||
level++;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
bool isPOT(uint32_t n) { return n && (n & (n - 1)) == 0; }
|
||||
|
||||
bool canGenerateMipmap(uint32_t w, uint32_t h) {
|
||||
return isPOT(w) && isPOT(h);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SimpleTexture::SimpleTexture() = default;
|
||||
SimpleTexture::~SimpleTexture() = default;
|
||||
|
||||
bool SimpleTexture::destroy() {
|
||||
tryDestroyTextureView();
|
||||
tryDestroyTexture();
|
||||
return Super::destroy();
|
||||
}
|
||||
|
||||
void SimpleTexture::updateImage() {
|
||||
updateMipmaps(0, 0);
|
||||
}
|
||||
|
||||
void SimpleTexture::uploadDataWithArrayBuffer(const ArrayBuffer &source, uint32_t level /* = 0 */, uint32_t arrayIndex /* = 0 */) {
|
||||
uploadData(source.getData(), level, arrayIndex);
|
||||
}
|
||||
|
||||
void SimpleTexture::uploadData(const uint8_t *source, uint32_t level /* = 0 */, uint32_t arrayIndex /* = 0 */) {
|
||||
if (!_gfxTexture || _mipmapLevel <= level) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *gfxDevice = getGFXDevice();
|
||||
if (!gfxDevice) {
|
||||
return;
|
||||
}
|
||||
|
||||
gfx::BufferTextureCopy region;
|
||||
region.texExtent.width = _textureWidth >> level;
|
||||
region.texExtent.height = _textureHeight >> level;
|
||||
region.texSubres.mipLevel = level;
|
||||
region.texSubres.baseArrayLayer = arrayIndex;
|
||||
|
||||
const uint8_t *buffers[1]{source};
|
||||
gfxDevice->copyBuffersToTexture(buffers, _gfxTexture, ®ion, 1);
|
||||
}
|
||||
|
||||
void SimpleTexture::assignImage(ImageAsset *image, uint32_t level, uint32_t arrayIndex /* = 0 */) {
|
||||
const uint8_t *data = image->getData();
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
uploadData(data, level, arrayIndex);
|
||||
checkTextureLoaded();
|
||||
|
||||
emit<AfterAssignImage>(image);
|
||||
}
|
||||
|
||||
void SimpleTexture::checkTextureLoaded() {
|
||||
textureReady();
|
||||
}
|
||||
|
||||
void SimpleTexture::textureReady() {
|
||||
_loaded = true;
|
||||
//cjh this.emit('load');
|
||||
}
|
||||
|
||||
void SimpleTexture::setMipmapLevel(uint32_t value) {
|
||||
_mipmapLevel = value < 1 ? 1 : value;
|
||||
}
|
||||
|
||||
void SimpleTexture::tryReset() {
|
||||
tryDestroyTextureView();
|
||||
tryDestroyTexture();
|
||||
if (_mipmapLevel == 0) {
|
||||
return;
|
||||
}
|
||||
auto *device = getGFXDevice();
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
createTexture(device);
|
||||
_gfxTextureView = createTextureView(device);
|
||||
}
|
||||
|
||||
void SimpleTexture::createTexture(gfx::Device *device) {
|
||||
if (_width == 0 || _height == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto flags = gfx::TextureFlagBit::NONE;
|
||||
auto usage = gfx::TextureUsageBit::SAMPLED | gfx::TextureUsageBit::TRANSFER_DST;
|
||||
if (_mipFilter != Filter::NONE && canGenerateMipmap(_width, _height)) {
|
||||
_mipmapLevel = getMipLevel(_width, _height);
|
||||
if (!isUsingOfflineMipmaps() && !isCompressed()) {
|
||||
flags = gfx::TextureFlagBit::GEN_MIPMAP;
|
||||
}
|
||||
}
|
||||
|
||||
const auto gfxFormat = getGFXFormat();
|
||||
if (hasFlag(gfx::Device::getInstance()->getFormatFeatures(gfxFormat), gfx::FormatFeatureBit::RENDER_TARGET)) {
|
||||
usage |= gfx::TextureUsageBit::COLOR_ATTACHMENT;
|
||||
}
|
||||
|
||||
auto textureCreateInfo = getGfxTextureCreateInfo(
|
||||
usage,
|
||||
gfxFormat,
|
||||
_mipmapLevel,
|
||||
flags);
|
||||
|
||||
//cjh if (!textureCreateInfo) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
auto *texture = device->createTexture(textureCreateInfo);
|
||||
_textureWidth = textureCreateInfo.width;
|
||||
_textureHeight = textureCreateInfo.height;
|
||||
|
||||
_gfxTexture = texture;
|
||||
|
||||
notifyTextureUpdated();
|
||||
}
|
||||
|
||||
gfx::Texture *SimpleTexture::createTextureView(gfx::Device *device) {
|
||||
if (!_gfxTexture) {
|
||||
return nullptr;
|
||||
}
|
||||
const uint32_t maxLevel = _maxLevel < _mipmapLevel ? _maxLevel : _mipmapLevel - 1;
|
||||
auto textureViewCreateInfo = getGfxTextureViewCreateInfo(
|
||||
_gfxTexture,
|
||||
getGFXFormat(),
|
||||
_baseLevel,
|
||||
maxLevel - _baseLevel + 1);
|
||||
|
||||
//TODO(minggo)
|
||||
// if (!textureViewCreateInfo) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
return device->createTexture(textureViewCreateInfo);
|
||||
}
|
||||
|
||||
void SimpleTexture::tryDestroyTexture() {
|
||||
if (_gfxTexture != nullptr) {
|
||||
_gfxTexture->destroy();
|
||||
_gfxTexture = nullptr;
|
||||
|
||||
notifyTextureUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleTexture::tryDestroyTextureView() {
|
||||
if (_gfxTextureView != nullptr) {
|
||||
_gfxTextureView->destroy();
|
||||
_gfxTextureView = nullptr;
|
||||
|
||||
//TODO(minggo): should notify JS if the performance is low.
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleTexture::setMipRange(uint32_t baseLevel, uint32_t maxLevel) {
|
||||
debug::assertID(baseLevel <= maxLevel, 3124);
|
||||
|
||||
setMipRangeInternal(baseLevel, maxLevel);
|
||||
|
||||
auto *device = getGFXDevice();
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
// create a new texture view before the destruction of the previous one to bypass the bug that
|
||||
// vulkan destroys textureview in use. This is a temporary solution, should be fixed later.
|
||||
gfx::Texture *textureView = createTextureView(device);
|
||||
tryDestroyTextureView();
|
||||
_gfxTextureView = textureView;
|
||||
}
|
||||
|
||||
bool SimpleTexture::isUsingOfflineMipmaps() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SimpleTexture::setMipRangeInternal(uint32_t baseLevel, uint32_t maxLevel) {
|
||||
_baseLevel = baseLevel < 1 ? 0 : baseLevel;
|
||||
_maxLevel = _maxLevel < 1 ? 0 : maxLevel;
|
||||
}
|
||||
|
||||
void SimpleTexture::notifyTextureUpdated() {
|
||||
emit<TextureUpdated>(_gfxTexture.get());
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
171
cocos/core/assets/SimpleTexture.h
Normal file
171
cocos/core/assets/SimpleTexture.h
Normal file
@@ -0,0 +1,171 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/ArrayBuffer.h"
|
||||
#include "core/assets/TextureBase.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class ImageAsset;
|
||||
|
||||
/**
|
||||
* @en The simple texture base class.
|
||||
* It create the GFX Texture and can set mipmap levels.
|
||||
* @zh 简单贴图基类。
|
||||
* 简单贴图内部创建了 GFX 贴图和该贴图上的 GFX 贴图视图。
|
||||
* 简单贴图允许指定不同的 Mipmap 层级。
|
||||
*/
|
||||
class SimpleTexture : public TextureBase {
|
||||
IMPL_EVENT_TARGET(SimpleTexture)
|
||||
DECLARE_TARGET_EVENT_BEGIN_WITH_PARENTS(SimpleTexture, TextureBase)
|
||||
TARGET_EVENT_ARG1(TextureUpdated, cc::gfx::Texture *)
|
||||
TARGET_EVENT_ARG1(AfterAssignImage, cc::ImageAsset *)
|
||||
DECLARE_TARGET_EVENT_END()
|
||||
public:
|
||||
~SimpleTexture() override;
|
||||
|
||||
using Super = TextureBase;
|
||||
/**
|
||||
* @en The mipmap level of the texture
|
||||
* @zh 贴图中的 Mipmap 层级数量
|
||||
*/
|
||||
inline uint32_t mipmapLevel() const {
|
||||
return _mipmapLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en The GFX Texture resource
|
||||
* @zh 获取此贴图底层的 GFX 贴图对象。
|
||||
*/
|
||||
gfx::Texture *getGFXTexture() const override {
|
||||
return _gfxTextureView.get();
|
||||
}
|
||||
|
||||
bool destroy() override;
|
||||
|
||||
/**
|
||||
* @en Update the level 0 mipmap image.
|
||||
* @zh 更新 0 级 Mipmap。
|
||||
*/
|
||||
void updateImage();
|
||||
|
||||
/**
|
||||
* @en Update the given level mipmap image.
|
||||
* @zh 更新指定层级范围内的 Mipmap。当 Mipmap 数据发生了改变时应调用此方法提交更改。
|
||||
* 若指定的层级范围超出了实际已有的层级范围,只有覆盖的那些层级范围会被更新。
|
||||
* @param firstLevel First level to be updated
|
||||
* @param count Mipmap level count to be updated
|
||||
*/
|
||||
virtual void updateMipmaps(uint32_t firstLevel, uint32_t count) {}
|
||||
|
||||
/**
|
||||
* @en Upload data to the given mipmap level.
|
||||
* The size of the image will affect how the mipmap is updated.
|
||||
* - When the image is an ArrayBuffer, the size of the image must match the mipmap size.
|
||||
* - If the image size matches the mipmap size, the mipmap data will be updated entirely.
|
||||
* - If the image size is smaller than the mipmap size, the mipmap will be updated from top left corner.
|
||||
* - If the image size is larger, an error will be raised
|
||||
* @zh 上传图像数据到指定层级的 Mipmap 中。
|
||||
* 图像的尺寸影响 Mipmap 的更新范围:
|
||||
* - 当图像是 `ArrayBuffer` 时,图像的尺寸必须和 Mipmap 的尺寸一致;否则,
|
||||
* - 若图像的尺寸与 Mipmap 的尺寸相同,上传后整个 Mipmap 的数据将与图像数据一致;
|
||||
* - 若图像的尺寸小于指定层级 Mipmap 的尺寸(不管是长或宽),则从贴图左上角开始,图像尺寸范围内的 Mipmap 会被更新;
|
||||
* - 若图像的尺寸超出了指定层级 Mipmap 的尺寸(不管是长或宽),都将引起错误。
|
||||
* @param source The source image or image data
|
||||
* @param level Mipmap level to upload the image to
|
||||
* @param arrayIndex The array index
|
||||
*/
|
||||
void uploadDataWithArrayBuffer(const ArrayBuffer &source, uint32_t level = 0, uint32_t arrayIndex = 0);
|
||||
void uploadData(const uint8_t *source, uint32_t level = 0, uint32_t arrayIndex = 0);
|
||||
|
||||
void assignImage(ImageAsset *image, uint32_t level, uint32_t arrayIndex = 0);
|
||||
|
||||
void checkTextureLoaded();
|
||||
|
||||
/**
|
||||
* Set mipmap level of this texture.
|
||||
* The value is passes as presumed info to `this._getGfxTextureCreateInfo()`.
|
||||
* @param value The mipmap level.
|
||||
* @warn As it is invoked by subclass(TextureCube) in TS, so should make it as public.
|
||||
*/
|
||||
void setMipmapLevel(uint32_t value);
|
||||
|
||||
/**
|
||||
* Set mipmap level range for this texture.
|
||||
* @param baseLevel The base mipmap level.
|
||||
* @param maxLevel The maximum mipmap level.
|
||||
*/
|
||||
void setMipRange(uint32_t baseLevel, uint32_t maxLevel);
|
||||
|
||||
/**
|
||||
* @en Whether mipmaps are baked convolutional maps.
|
||||
* @zh mipmaps是否为烘焙出来的卷积图。
|
||||
*/
|
||||
virtual bool isUsingOfflineMipmaps();
|
||||
|
||||
protected:
|
||||
SimpleTexture();
|
||||
void textureReady();
|
||||
|
||||
/**
|
||||
* @en This method is override by derived classes to provide GFX texture info.
|
||||
* @zh 这个方法被派生类重写以提供 GFX 纹理信息。
|
||||
* @param presumed The presumed GFX texture info.
|
||||
*/
|
||||
virtual gfx::TextureInfo getGfxTextureCreateInfo(gfx::TextureUsageBit usage, gfx::Format format, uint32_t levelCount, gfx::TextureFlagBit flags) = 0;
|
||||
|
||||
/**
|
||||
* @en This method is overrided by derived classes to provide GFX TextureViewInfo.
|
||||
* @zh 这个方法被派生类重写以提供 GFX 纹理视图信息。
|
||||
* @param presumed The presumed GFX TextureViewInfo.
|
||||
*/
|
||||
virtual gfx::TextureViewInfo getGfxTextureViewCreateInfo(gfx::Texture *texture, gfx::Format format, uint32_t baseLevel, uint32_t levelCount) = 0;
|
||||
|
||||
void tryReset();
|
||||
|
||||
void createTexture(gfx::Device *device);
|
||||
gfx::Texture *createTextureView(gfx::Device *device);
|
||||
|
||||
void tryDestroyTexture();
|
||||
void tryDestroyTextureView();
|
||||
void notifyTextureUpdated();
|
||||
void setMipRangeInternal(uint32_t baseLevel, uint32_t maxLevel);
|
||||
|
||||
IntrusivePtr<gfx::Texture> _gfxTexture;
|
||||
IntrusivePtr<gfx::Texture> _gfxTextureView;
|
||||
|
||||
uint32_t _mipmapLevel{1};
|
||||
// Cache these data to reduce JSB invoking.
|
||||
uint32_t _textureWidth{0};
|
||||
uint32_t _textureHeight{0};
|
||||
|
||||
uint32_t _baseLevel{0};
|
||||
uint32_t _maxLevel{1000};
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(SimpleTexture);
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
55
cocos/core/assets/TextAsset.h
Normal file
55
cocos/core/assets/TextAsset.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/assets/Asset.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
/**
|
||||
* @en Class for text file.
|
||||
* @zh 文本资源。
|
||||
*/
|
||||
class TextAsset final : public Asset {
|
||||
public:
|
||||
explicit TextAsset() = default;
|
||||
~TextAsset() override = default;
|
||||
/**
|
||||
* @en The text content.
|
||||
* @zh 此资源包含的文本。
|
||||
|
||||
@serializable
|
||||
@editable*/
|
||||
ccstd::string text;
|
||||
|
||||
ccstd::string toString() const override {
|
||||
return text;
|
||||
}
|
||||
|
||||
private:
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(TextAsset);
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
242
cocos/core/assets/Texture2D.cpp
Normal file
242
cocos/core/assets/Texture2D.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "core/assets/Texture2D.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "base/Log.h"
|
||||
#include "core/assets/ImageAsset.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
Texture2D::Texture2D() = default;
|
||||
Texture2D::~Texture2D() = default;
|
||||
|
||||
void Texture2D::syncMipmapsForJS(const ccstd::vector<IntrusivePtr<ImageAsset>> &value) {
|
||||
_mipmaps = value;
|
||||
}
|
||||
|
||||
void Texture2D::setMipmaps(const ccstd::vector<IntrusivePtr<ImageAsset>> &value) {
|
||||
_mipmaps = value;
|
||||
|
||||
auto mipmaps = ccstd::vector<IntrusivePtr<ImageAsset>>{};
|
||||
|
||||
if (value.size() == 1) {
|
||||
const auto images = value[0]->extractMipmaps();
|
||||
std::copy(std::cbegin(images), std::cend(images), std::back_inserter(mipmaps));
|
||||
} else if (value.size() > 1) {
|
||||
for (const auto &image : value) {
|
||||
mipmaps.emplace_back(image->extractMipmap0());
|
||||
}
|
||||
}
|
||||
|
||||
setMipmapParams(mipmaps);
|
||||
}
|
||||
|
||||
void Texture2D::setMipmapParams(const ccstd::vector<IntrusivePtr<ImageAsset>> &value) {
|
||||
_generatedMipmaps = value;
|
||||
setMipmapLevel(static_cast<uint32_t>(_generatedMipmaps.size()));
|
||||
if (!_generatedMipmaps.empty()) {
|
||||
ImageAsset *imageAsset = _generatedMipmaps[0];
|
||||
ITexture2DCreateInfo info;
|
||||
info.width = imageAsset->getWidth();
|
||||
info.height = imageAsset->getHeight();
|
||||
info.format = imageAsset->getFormat();
|
||||
info.mipmapLevel = static_cast<uint32_t>(_generatedMipmaps.size());
|
||||
info.baseLevel = _baseLevel;
|
||||
info.maxLevel = _maxLevel;
|
||||
reset(info);
|
||||
|
||||
for (size_t i = 0, len = _generatedMipmaps.size(); i < len; ++i) {
|
||||
assignImage(_generatedMipmaps[i], static_cast<uint32_t>(i));
|
||||
}
|
||||
|
||||
} else {
|
||||
ITexture2DCreateInfo info;
|
||||
info.width = 0;
|
||||
info.height = 0;
|
||||
info.mipmapLevel = static_cast<uint32_t>(_generatedMipmaps.size());
|
||||
info.baseLevel = _baseLevel;
|
||||
info.maxLevel = _maxLevel;
|
||||
reset(info);
|
||||
}
|
||||
}
|
||||
|
||||
void Texture2D::initialize() {
|
||||
setMipmaps(_mipmaps);
|
||||
}
|
||||
|
||||
void Texture2D::onLoaded() {
|
||||
initialize();
|
||||
}
|
||||
|
||||
void Texture2D::reset(const ITexture2DCreateInfo &info) {
|
||||
_width = info.width;
|
||||
_height = info.height;
|
||||
setGFXFormat(info.format);
|
||||
|
||||
const uint32_t mipLevels = info.mipmapLevel.has_value() ? info.mipmapLevel.value() : 1;
|
||||
setMipmapLevel(mipLevels);
|
||||
|
||||
const uint32_t minLod = info.baseLevel.has_value() ? info.baseLevel.value() : 0;
|
||||
const uint32_t maxLod = info.maxLevel.has_value() ? info.maxLevel.value() : 1000;
|
||||
setMipRange(minLod, maxLod);
|
||||
|
||||
tryReset();
|
||||
}
|
||||
|
||||
void Texture2D::create(uint32_t width, uint32_t height, PixelFormat format /* = PixelFormat::RGBA8888*/, uint32_t mipmapLevel /* = 1*/, uint32_t baseLevel, uint32_t maxLevel) {
|
||||
reset({width,
|
||||
height,
|
||||
format,
|
||||
mipmapLevel,
|
||||
baseLevel,
|
||||
maxLevel});
|
||||
}
|
||||
|
||||
ccstd::string Texture2D::toString() const {
|
||||
ccstd::string ret;
|
||||
if (!_mipmaps.empty()) {
|
||||
ret = _mipmaps[0]->getUrl();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Texture2D::updateMipmaps(uint32_t firstLevel, uint32_t count) {
|
||||
if (firstLevel >= _generatedMipmaps.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto nUpdate = static_cast<uint32_t>(std::min(
|
||||
(count == 0 ? _generatedMipmaps.size() : count),
|
||||
(_generatedMipmaps.size() - firstLevel)));
|
||||
|
||||
for (uint32_t i = 0; i < nUpdate; ++i) {
|
||||
const uint32_t level = firstLevel + i;
|
||||
assignImage(_generatedMipmaps[level], level);
|
||||
}
|
||||
}
|
||||
|
||||
bool Texture2D::destroy() {
|
||||
_mipmaps.clear();
|
||||
_generatedMipmaps.clear();
|
||||
return Super::destroy();
|
||||
}
|
||||
|
||||
ccstd::string Texture2D::description() const {
|
||||
std::stringstream ret;
|
||||
ccstd::string url;
|
||||
if (!_mipmaps.empty()) {
|
||||
url = _mipmaps[0]->getUrl();
|
||||
}
|
||||
ret << "<cc.Texture2D | Name = " << url << " | Dimension" << _width << " x " << _height << ">";
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
void Texture2D::releaseTexture() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
ccstd::any Texture2D::serialize(const ccstd::any & /*ctxForExporting*/) {
|
||||
// if (EDITOR || TEST) {
|
||||
// return {
|
||||
// base: super._serialize(ctxForExporting),
|
||||
// mipmaps: this._mipmaps.map((mipmap) => {
|
||||
// if (!mipmap || !mipmap._uuid) {
|
||||
// return null;
|
||||
// }
|
||||
// if (ctxForExporting && ctxForExporting._compressUuid) {
|
||||
// // ctxForExporting.dependsOn('_textureSource', texture); TODO
|
||||
// return EditorExtends.UuidUtils.compressUuid(mipmap._uuid, true);
|
||||
// }
|
||||
// return mipmap._uuid;
|
||||
// }),
|
||||
// };
|
||||
// }
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Texture2D::deserialize(const ccstd::any &serializedData, const ccstd::any &handle) {
|
||||
const auto *data = ccstd::any_cast<ITexture2DSerializeData>(&serializedData);
|
||||
if (data == nullptr) {
|
||||
CC_LOG_WARNING("serializedData is not ITexture2DSerializeData");
|
||||
return;
|
||||
}
|
||||
Super::deserialize(data->base, handle);
|
||||
|
||||
_mipmaps.resize(data->mipmaps.size());
|
||||
for (size_t i = 0; i < data->mipmaps.size(); ++i) {
|
||||
// Prevent resource load failed
|
||||
_mipmaps[i] = ccnew ImageAsset();
|
||||
if (data->mipmaps[i].empty()) {
|
||||
continue;
|
||||
}
|
||||
ccstd::string mipmapUUID = data->mipmaps[i];
|
||||
//cjh TODO: handle.result.push(this._mipmaps, `${i}`, mipmapUUID, js.getClassId(ImageAsset));
|
||||
}
|
||||
}
|
||||
|
||||
gfx::TextureInfo Texture2D::getGfxTextureCreateInfo(gfx::TextureUsageBit usage, gfx::Format format, uint32_t levelCount, gfx::TextureFlagBit flags) {
|
||||
gfx::TextureInfo texInfo;
|
||||
texInfo.type = gfx::TextureType::TEX2D;
|
||||
texInfo.width = _width;
|
||||
texInfo.height = _height;
|
||||
texInfo.usage = usage;
|
||||
texInfo.format = format;
|
||||
texInfo.levelCount = levelCount;
|
||||
texInfo.flags = flags;
|
||||
return texInfo;
|
||||
}
|
||||
|
||||
gfx::TextureViewInfo Texture2D::getGfxTextureViewCreateInfo(gfx::Texture *texture, gfx::Format format, uint32_t baseLevel, uint32_t levelCount) {
|
||||
gfx::TextureViewInfo texViewInfo;
|
||||
texViewInfo.type = gfx::TextureType::TEX2D;
|
||||
texViewInfo.texture = texture;
|
||||
texViewInfo.format = format;
|
||||
texViewInfo.baseLevel = baseLevel;
|
||||
texViewInfo.levelCount = levelCount;
|
||||
return texViewInfo;
|
||||
}
|
||||
|
||||
void Texture2D::initDefault(const ccstd::optional<ccstd::string> &uuid) {
|
||||
Super::initDefault(uuid);
|
||||
auto *imageAsset = ccnew ImageAsset();
|
||||
imageAsset->initDefault(ccstd::nullopt);
|
||||
setImage(imageAsset);
|
||||
}
|
||||
|
||||
void Texture2D::setImage(ImageAsset *value) {
|
||||
ccstd::vector<IntrusivePtr<ImageAsset>> mipmaps;
|
||||
if (value != nullptr) {
|
||||
mipmaps.emplace_back(value);
|
||||
}
|
||||
setMipmaps(mipmaps);
|
||||
}
|
||||
|
||||
bool Texture2D::validate() const {
|
||||
return !_mipmaps.empty();
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
216
cocos/core/assets/Texture2D.h
Normal file
216
cocos/core/assets/Texture2D.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Ptr.h"
|
||||
#include "base/std/optional.h"
|
||||
#include "core/assets/Asset.h"
|
||||
#include "core/assets/AssetEnum.h"
|
||||
#include "core/assets/SimpleTexture.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
struct ITexture2DSerializeData {
|
||||
ccstd::string base;
|
||||
ccstd::vector<ccstd::string> mipmaps;
|
||||
};
|
||||
|
||||
/**
|
||||
* @en The create information for [[Texture2D]]
|
||||
* @zh 用来创建贴图的信息。
|
||||
*/
|
||||
struct ITexture2DCreateInfo {
|
||||
/**
|
||||
* @en The pixel width
|
||||
* @zh 像素宽度。
|
||||
*/
|
||||
uint32_t width{0};
|
||||
|
||||
/**
|
||||
* @en The pixel height
|
||||
* @zh 像素高度。
|
||||
*/
|
||||
uint32_t height{0};
|
||||
|
||||
/**
|
||||
* @en The pixel format
|
||||
* @zh 像素格式。
|
||||
* @default PixelFormat.RGBA8888
|
||||
*/
|
||||
ccstd::optional<PixelFormat> format;
|
||||
|
||||
/**
|
||||
* @en The mipmap level count
|
||||
* @zh mipmap 层级。
|
||||
* @default 1
|
||||
*/
|
||||
ccstd::optional<uint32_t> mipmapLevel;
|
||||
|
||||
/**
|
||||
* @en The selected base mipmap level
|
||||
* @zh 选择使用的最小 mipmap 层级。
|
||||
* @default 1
|
||||
*/
|
||||
ccstd::optional<uint32_t> baseLevel;
|
||||
|
||||
/**
|
||||
* @en The selected maximum mipmap level
|
||||
* @zh 选择使用的最大 mipmap 层级。
|
||||
* @default 1
|
||||
*/
|
||||
ccstd::optional<uint32_t> maxLevel;
|
||||
};
|
||||
|
||||
/**
|
||||
* @en The 2D texture asset. It supports mipmap, each level of mipmap use an [[ImageAsset]].
|
||||
* @zh 二维贴图资源。二维贴图资源的每个 Mipmap 层级都为一张 [[ImageAsset]]。
|
||||
*/
|
||||
class Texture2D final : public SimpleTexture {
|
||||
public:
|
||||
using Super = SimpleTexture;
|
||||
|
||||
Texture2D();
|
||||
~Texture2D() override;
|
||||
|
||||
/**
|
||||
* @en All levels of mipmap images, be noted, automatically generated mipmaps are not included.
|
||||
* When setup mipmap, the size of the texture and pixel format could be modified.
|
||||
* @zh 所有层级 Mipmap,注意,这里不包含自动生成的 Mipmap。
|
||||
* 当设置 Mipmap 时,贴图的尺寸以及像素格式可能会改变。
|
||||
*/
|
||||
const ccstd::vector<IntrusivePtr<ImageAsset>> &getMipmaps() const {
|
||||
return _mipmaps;
|
||||
}
|
||||
|
||||
const ccstd::vector<ccstd::string> &getMipmapsUuids() const { // TODO(xwx): temporary use _mipmaps as string array
|
||||
return _mipmapsUuids;
|
||||
}
|
||||
|
||||
//cjh TODO: TextureCube also needs this method.
|
||||
void syncMipmapsForJS(const ccstd::vector<IntrusivePtr<ImageAsset>> &value);
|
||||
|
||||
void setMipmaps(const ccstd::vector<IntrusivePtr<ImageAsset>> &value);
|
||||
|
||||
/**
|
||||
* @en Level 0 mipmap image.
|
||||
* Be noted, `this.image = img` equals `this.mipmaps = [img]`,
|
||||
* sets image will clear all previous mipmaps.
|
||||
* @zh 0 级 Mipmap。
|
||||
* 注意,`this.image = img` 等价于 `this.mipmaps = [img]`,
|
||||
* 也就是说,通过 `this.image` 设置 0 级 Mipmap 时将隐式地清除之前的所有 Mipmap。
|
||||
*/
|
||||
inline ImageAsset *getImage() const {
|
||||
return _mipmaps.empty() ? nullptr : _mipmaps[0].get();
|
||||
}
|
||||
|
||||
void setImage(ImageAsset *value);
|
||||
|
||||
void initialize();
|
||||
|
||||
void onLoaded() override;
|
||||
|
||||
/**
|
||||
* @en Reset the current texture with given size, pixel format and mipmap images.
|
||||
* After reset, the gfx resource will become invalid, you must use [[uploadData]] explicitly to upload the new mipmaps to GPU resources.
|
||||
* @zh 将当前贴图重置为指定尺寸、像素格式以及指定 mipmap 层级。重置后,贴图的像素数据将变为未定义。
|
||||
* mipmap 图像的数据不会自动更新到贴图中,你必须显式调用 [[uploadData]] 来上传贴图数据。
|
||||
* @param info The create information
|
||||
*/
|
||||
void reset(const ITexture2DCreateInfo &info);
|
||||
|
||||
/**
|
||||
* @en Reset the current texture with given size, pixel format and mipmap images.
|
||||
* After reset, the gfx resource will become invalid, you must use [[uploadData]] explicitly to upload the new mipmaps to GPU resources.
|
||||
* @zh 将当前贴图重置为指定尺寸、像素格式以及指定 mipmap 层级。重置后,贴图的像素数据将变为未定义。
|
||||
* mipmap 图像的数据不会自动更新到贴图中,你必须显式调用 [[uploadData]] 来上传贴图数据。
|
||||
* @param width Pixel width
|
||||
* @param height Pixel height
|
||||
* @param format Pixel format
|
||||
* @param mipmapLevel Mipmap level count
|
||||
* @param baseLevel Mipmap base level
|
||||
* @param maxLevel Mipmap maximum level
|
||||
|
||||
* @deprecated since v1.0 please use [[reset]] instead
|
||||
*/
|
||||
void create(uint32_t width, uint32_t height, PixelFormat format = PixelFormat::RGBA8888, uint32_t mipmapLevel = 1, uint32_t baseLevel = 0, uint32_t maxLevel = 1000);
|
||||
|
||||
ccstd::string toString() const override;
|
||||
|
||||
void updateMipmaps(uint32_t firstLevel, uint32_t count) override;
|
||||
|
||||
/**
|
||||
* @en Destroy the current 2d texture, clear up all mipmap levels and the related GPU resources.
|
||||
* @zh 销毁此贴图,清空所有 Mipmap 并释放占用的 GPU 资源。
|
||||
*/
|
||||
bool destroy() override;
|
||||
|
||||
/**
|
||||
* @en Gets the description of the 2d texture
|
||||
* @zh 返回此贴图的描述。
|
||||
* @returns The description
|
||||
*/
|
||||
ccstd::string description() const;
|
||||
|
||||
/**
|
||||
* @en Release used GPU resources.
|
||||
* @zh 释放占用的 GPU 资源。
|
||||
* @deprecated please use [[destroy]] instead
|
||||
*/
|
||||
void releaseTexture();
|
||||
|
||||
// SERIALIZATION
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
ccstd::any serialize(const ccstd::any &ctxForExporting) override;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
void deserialize(const ccstd::any &serializedData, const ccstd::any &handle) override;
|
||||
|
||||
gfx::TextureInfo getGfxTextureCreateInfo(gfx::TextureUsageBit usage, gfx::Format format, uint32_t levelCount, gfx::TextureFlagBit flags) override;
|
||||
gfx::TextureViewInfo getGfxTextureViewCreateInfo(gfx::Texture *texture, gfx::Format format, uint32_t baseLevel, uint32_t levelCount) override;
|
||||
|
||||
void initDefault(const ccstd::optional<ccstd::string> &uuid) override;
|
||||
|
||||
bool validate() const override;
|
||||
|
||||
private:
|
||||
void setMipmapParams(const ccstd::vector<IntrusivePtr<ImageAsset>> &value);
|
||||
|
||||
ccstd::vector<IntrusivePtr<ImageAsset>> _mipmaps;
|
||||
ccstd::vector<IntrusivePtr<ImageAsset>> _generatedMipmaps;
|
||||
|
||||
ccstd::vector<ccstd::string> _mipmapsUuids; // TODO(xwx): temporary use _mipmaps as UUIDs string array
|
||||
|
||||
friend class Texture2DDeserializer;
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(Texture2D);
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
190
cocos/core/assets/TextureBase.cpp
Normal file
190
cocos/core/assets/TextureBase.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "core/assets/TextureBase.h"
|
||||
#include "base/StringUtil.h"
|
||||
#include "cocos/core/platform/Debug.h"
|
||||
#include "core/utils/IDGenerator.h"
|
||||
|
||||
#include "renderer/gfx-base/GFXDevice.h"
|
||||
#include "renderer/pipeline/Define.h"
|
||||
|
||||
#include "base/std/hash/hash.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace {
|
||||
IDGenerator idGenerator("Tex");
|
||||
}
|
||||
|
||||
TextureBase::TextureBase() {
|
||||
// Id for generate hash in material
|
||||
_id = idGenerator.getNewId();
|
||||
_gfxDevice = getGFXDevice();
|
||||
ccstd::hash_t seed = 666;
|
||||
ccstd::hash_range(seed, _id.begin(), _id.end());
|
||||
_textureHash = seed;
|
||||
}
|
||||
|
||||
TextureBase::~TextureBase() = default;
|
||||
|
||||
void TextureBase::setWrapMode(WrapMode wrapS, WrapMode wrapT, WrapMode wrapR) {
|
||||
_wrapS = wrapS;
|
||||
_samplerInfo.addressU = static_cast<gfx::Address>(wrapS),
|
||||
|
||||
_wrapT = wrapT;
|
||||
_samplerInfo.addressV = static_cast<gfx::Address>(wrapT),
|
||||
|
||||
_wrapR = wrapR;
|
||||
_samplerInfo.addressW = static_cast<gfx::Address>(wrapR);
|
||||
|
||||
if (_gfxDevice != nullptr) {
|
||||
_gfxSampler = _gfxDevice->getSampler(_samplerInfo);
|
||||
}
|
||||
|
||||
notifySamplerUpdated();
|
||||
}
|
||||
|
||||
void TextureBase::setWrapMode(WrapMode wrapS, WrapMode wrapT) {
|
||||
setWrapMode(wrapS, wrapT, wrapS); // wrap modes should be as consistent as possible for performance
|
||||
}
|
||||
|
||||
void TextureBase::setFilters(Filter minFilter, Filter magFilter) {
|
||||
_minFilter = minFilter;
|
||||
_samplerInfo.minFilter = static_cast<gfx::Filter>(minFilter);
|
||||
_magFilter = magFilter;
|
||||
_samplerInfo.magFilter = static_cast<gfx::Filter>(magFilter);
|
||||
|
||||
if (_gfxDevice != nullptr) {
|
||||
_gfxSampler = _gfxDevice->getSampler(_samplerInfo);
|
||||
}
|
||||
|
||||
notifySamplerUpdated();
|
||||
}
|
||||
|
||||
void TextureBase::setMipFilter(Filter mipFilter) {
|
||||
_mipFilter = mipFilter;
|
||||
_samplerInfo.mipFilter = static_cast<gfx::Filter>(mipFilter);
|
||||
|
||||
if (_gfxDevice != nullptr) {
|
||||
_gfxSampler = _gfxDevice->getSampler(_samplerInfo);
|
||||
}
|
||||
|
||||
notifySamplerUpdated();
|
||||
}
|
||||
|
||||
void TextureBase::setAnisotropy(uint32_t anisotropy) {
|
||||
_anisotropy = anisotropy;
|
||||
_samplerInfo.maxAnisotropy = anisotropy;
|
||||
|
||||
if (_gfxDevice != nullptr) {
|
||||
_gfxSampler = _gfxDevice->getSampler(_samplerInfo);
|
||||
}
|
||||
|
||||
notifySamplerUpdated();
|
||||
}
|
||||
|
||||
bool TextureBase::destroy() {
|
||||
const bool destroyed = Super::destroy();
|
||||
//cjh TODO: if (destroyed && legacyCC.director.root?.batcher2D) {
|
||||
// legacyCC.director.root.batcher2D._releaseDescriptorSetCache(this._textureHash);
|
||||
// }
|
||||
return destroyed;
|
||||
}
|
||||
|
||||
gfx::Sampler *TextureBase::getGFXSampler() const {
|
||||
if (_gfxSampler == nullptr) {
|
||||
if (_gfxDevice != nullptr) {
|
||||
const_cast<TextureBase *>(this)->_gfxSampler = _gfxDevice->getSampler(_samplerInfo);
|
||||
} else {
|
||||
debug::errorID(9302);
|
||||
}
|
||||
}
|
||||
return _gfxSampler;
|
||||
}
|
||||
|
||||
ccstd::any TextureBase::serialize(const ccstd::any & /*ctxForExporting*/) {
|
||||
//cjh TODO: if (EDITOR || TEST) {
|
||||
// return `${this._minFilter},${this._magFilter},${
|
||||
// this._wrapS},${this._wrapT},${
|
||||
// this._mipFilter},${this._anisotropy}`;
|
||||
// }
|
||||
return ccstd::string("");
|
||||
}
|
||||
|
||||
void TextureBase::deserialize(const ccstd::any &serializedData, const ccstd::any & /*handle*/) {
|
||||
const auto *pData = ccstd::any_cast<const ccstd::string>(&serializedData);
|
||||
if (pData == nullptr) {
|
||||
return;
|
||||
}
|
||||
const ccstd::string &data = *pData;
|
||||
auto fields = StringUtil::split(data, ",");
|
||||
fields.insert(fields.begin(), "");
|
||||
|
||||
if (fields.size() >= 5) {
|
||||
// decode filters
|
||||
setFilters(static_cast<Filter>(atoi(fields[1].c_str())), static_cast<Filter>(atoi(fields[2].c_str())));
|
||||
// decode wraps
|
||||
setWrapMode(static_cast<WrapMode>(atoi(fields[3].c_str())), static_cast<WrapMode>(atoi(fields[4].c_str())));
|
||||
}
|
||||
|
||||
if (fields.size() >= 7) {
|
||||
setMipFilter(static_cast<Filter>(atoi(fields[5].c_str())));
|
||||
setAnisotropy(atoi(fields[6].c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Device *TextureBase::getGFXDevice() {
|
||||
return gfx::Device::getInstance();
|
||||
}
|
||||
|
||||
gfx::Format TextureBase::getGFXFormat() const {
|
||||
return getGFXPixelFormat(_format);
|
||||
}
|
||||
|
||||
void TextureBase::setGFXFormat(const ccstd::optional<PixelFormat> &format) {
|
||||
_format = format.has_value() ? format.value() : PixelFormat::RGBA8888;
|
||||
}
|
||||
|
||||
gfx::Format TextureBase::getGFXPixelFormat(PixelFormat format) {
|
||||
if (format == PixelFormat::RGBA_ETC1) {
|
||||
format = PixelFormat::RGB_ETC1;
|
||||
} else if (format == PixelFormat::RGB_A_PVRTC_4BPPV1) {
|
||||
format = PixelFormat::RGB_PVRTC_4BPPV1;
|
||||
} else if (format == PixelFormat::RGB_A_PVRTC_2BPPV1) {
|
||||
format = PixelFormat::RGB_PVRTC_2BPPV1;
|
||||
}
|
||||
return static_cast<gfx::Format>(format);
|
||||
}
|
||||
|
||||
bool TextureBase::isCompressed() const {
|
||||
return (_format >= PixelFormat::RGB_ETC1 && _format <= PixelFormat::RGBA_ASTC_12X12) || (_format >= PixelFormat::RGB_A_PVRTC_2BPPV1 && _format <= PixelFormat::RGBA_ETC1);
|
||||
}
|
||||
|
||||
void TextureBase::notifySamplerUpdated() {
|
||||
// emit(EventTypesToJS::TEXTURE_BASE_GFX_SAMPLER_UPDATED, _gfxSampler);
|
||||
emit<SamplerUpdated>(_gfxSampler);
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
261
cocos/core/assets/TextureBase.h
Normal file
261
cocos/core/assets/TextureBase.h
Normal file
@@ -0,0 +1,261 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "base/Ptr.h"
|
||||
#include "core/assets/Asset.h"
|
||||
#include "core/assets/AssetEnum.h"
|
||||
#include "renderer/gfx-base/GFXDef.h"
|
||||
#include "base/std/container/unordered_map.h"
|
||||
|
||||
#include "base/std/any.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace gfx {
|
||||
class Sampler;
|
||||
class Device;
|
||||
class Texture;
|
||||
} // namespace gfx
|
||||
/**
|
||||
* @en The base texture class, it defines features shared by all textures.
|
||||
* @zh 贴图资源基类。它定义了所有贴图共用的概念。
|
||||
*/
|
||||
class TextureBase : public Asset {
|
||||
IMPL_EVENT_TARGET(TextureBase)
|
||||
DECLARE_TARGET_EVENT_BEGIN(TextureBase)
|
||||
TARGET_EVENT_ARG1(SamplerUpdated, cc::gfx::Sampler *)
|
||||
DECLARE_TARGET_EVENT_END()
|
||||
public:
|
||||
using Super = Asset;
|
||||
|
||||
/**
|
||||
* @en The pixel format enum.
|
||||
* @zh 像素格式枚举类型
|
||||
*/
|
||||
using PixelFormat = cc::PixelFormat;
|
||||
|
||||
/**
|
||||
* @en The wrap mode enum.
|
||||
* @zh 环绕模式枚举类型
|
||||
*/
|
||||
using WrapMode = cc::WrapMode;
|
||||
|
||||
/**
|
||||
* @en The texture filter mode enum
|
||||
* @zh 纹理过滤模式枚举类型
|
||||
*/
|
||||
using Filter = cc::Filter;
|
||||
|
||||
TextureBase(); // NOTE: Editor needs to invoke 'new TextureBase' in JS, so we need to make the constructor public.
|
||||
~TextureBase() override;
|
||||
/**
|
||||
* @en Whether the pixel data is compressed.
|
||||
* @zh 此贴图是否为压缩的像素格式。
|
||||
*/
|
||||
bool isCompressed() const;
|
||||
|
||||
/**
|
||||
* @en Pixel width of the texture
|
||||
* @zh 此贴图的像素宽度。
|
||||
*/
|
||||
uint32_t getWidth() const {
|
||||
return _width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Pixel height of the texture
|
||||
* @zh 此贴图的像素高度。
|
||||
*/
|
||||
uint32_t getHeight() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
// Functions for TS deserialization.
|
||||
inline void setWidth(uint32_t width) { _width = width; }
|
||||
inline void setHeight(uint32_t height) { _height = height; }
|
||||
|
||||
/**
|
||||
* @en Gets the id of the texture
|
||||
* @zh 获取标识符。
|
||||
* @returns The id
|
||||
*/
|
||||
inline const ccstd::string &getId() const {
|
||||
return _id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Gets the pixel format
|
||||
* @zh 获取像素格式。
|
||||
* @returns The pixel format
|
||||
*/
|
||||
inline PixelFormat getPixelFormat() const {
|
||||
return _format;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Gets the anisotropy
|
||||
* @zh 获取各向异性。
|
||||
* @returns The anisotropy
|
||||
*/
|
||||
inline uint32_t getAnisotropy() const {
|
||||
return _anisotropy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Sets the wrap mode of the texture.
|
||||
* Be noted, if the size of the texture is not power of two, only [[WrapMode.CLAMP_TO_EDGE]] is allowed.
|
||||
* @zh 设置此贴图的缠绕模式。
|
||||
* 注意,若贴图尺寸不是 2 的整数幂,缠绕模式仅允许 [[WrapMode.CLAMP_TO_EDGE]]。
|
||||
* @param wrapS S(U) coordinate wrap mode
|
||||
* @param wrapT T(V) coordinate wrap mode
|
||||
* @param wrapR R(W) coordinate wrap mode
|
||||
*/
|
||||
void setWrapMode(WrapMode wrapS, WrapMode wrapT, WrapMode wrapR);
|
||||
void setWrapMode(WrapMode wrapS, WrapMode wrapT);
|
||||
|
||||
/**
|
||||
* @en Sets the texture's filter mode
|
||||
* @zh 设置此贴图的过滤算法。
|
||||
* @param minFilter Filter mode for scale down
|
||||
* @param magFilter Filter mode for scale up
|
||||
*/
|
||||
void setFilters(Filter minFilter, Filter magFilter);
|
||||
|
||||
/**
|
||||
* @en Sets the texture's mip filter
|
||||
* @zh 设置此贴图的缩小过滤算法。
|
||||
* @param mipFilter Filter mode for scale down
|
||||
*/
|
||||
void setMipFilter(Filter mipFilter);
|
||||
|
||||
/**
|
||||
* @en Sets the texture's anisotropy
|
||||
* @zh 设置此贴图的各向异性。
|
||||
* @param anisotropy
|
||||
*/
|
||||
void setAnisotropy(uint32_t anisotropy);
|
||||
|
||||
/**
|
||||
* @en Destroy the current texture, clear up the related GPU resources.
|
||||
* @zh 销毁此贴图,并释放占用的 GPU 资源。
|
||||
*/
|
||||
bool destroy() override;
|
||||
|
||||
/**
|
||||
* @en Gets the texture hash.
|
||||
* @zh 获取此贴图的哈希值。
|
||||
*/
|
||||
inline ccstd::hash_t getHash() const {
|
||||
return _textureHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Gets the GFX Texture resource
|
||||
* @zh 获取此贴图底层的 GFX 贴图对象。
|
||||
*/
|
||||
virtual gfx::Texture *getGFXTexture() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Gets the internal GFX sampler information.
|
||||
* @zh 获取此贴图内部使用的 GFX 采样器信息。
|
||||
* @private
|
||||
*/
|
||||
virtual const gfx::SamplerInfo &getSamplerInfo() const {
|
||||
return _samplerInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Gets the sampler resource for the texture
|
||||
* @zh 获取此贴图底层的 GFX 采样信息。
|
||||
*/
|
||||
virtual gfx::Sampler *getGFXSampler() const;
|
||||
|
||||
// SERIALIZATION
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
ccstd::any serialize(const ccstd::any &ctxForExporting) override;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
void deserialize(const ccstd::any &serializedData, const ccstd::any &handle) override;
|
||||
|
||||
protected:
|
||||
static gfx::Device *getGFXDevice();
|
||||
static gfx::Format getGFXPixelFormat(PixelFormat format);
|
||||
|
||||
gfx::Format getGFXFormat() const;
|
||||
|
||||
void setGFXFormat(const ccstd::optional<PixelFormat> &format);
|
||||
|
||||
private:
|
||||
void notifySamplerUpdated();
|
||||
|
||||
public:
|
||||
/*@serializable*/
|
||||
PixelFormat _format{PixelFormat::RGBA8888};
|
||||
|
||||
/*@serializable*/
|
||||
Filter _minFilter{Filter::LINEAR};
|
||||
|
||||
/*@serializable*/
|
||||
Filter _magFilter{Filter::LINEAR};
|
||||
|
||||
/*@serializable*/
|
||||
Filter _mipFilter{Filter::NONE};
|
||||
|
||||
/*@serializable*/
|
||||
WrapMode _wrapS{WrapMode::REPEAT};
|
||||
|
||||
/*@serializable*/
|
||||
WrapMode _wrapT{WrapMode::REPEAT};
|
||||
|
||||
/*@serializable*/
|
||||
WrapMode _wrapR{WrapMode::REPEAT};
|
||||
|
||||
/*@serializable*/
|
||||
uint32_t _anisotropy{0};
|
||||
|
||||
protected:
|
||||
uint32_t _width{1};
|
||||
uint32_t _height{1};
|
||||
ccstd::string _id;
|
||||
gfx::SamplerInfo _samplerInfo;
|
||||
gfx::Sampler *_gfxSampler{nullptr};
|
||||
gfx::Device *_gfxDevice{nullptr};
|
||||
|
||||
ccstd::hash_t _textureHash{0U};
|
||||
|
||||
private:
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(TextureBase);
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
407
cocos/core/assets/TextureCube.cpp
Normal file
407
cocos/core/assets/TextureCube.cpp
Normal file
@@ -0,0 +1,407 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "core/assets/TextureCube.h"
|
||||
#include "core/assets/ImageAsset.h"
|
||||
#include "core/assets/Texture2D.h"
|
||||
#include "renderer/gfx-base/GFXTexture.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace {
|
||||
|
||||
using ForEachFaceCallback = std::function<void(ImageAsset *face, TextureCube::FaceIndex faceIndex)>;
|
||||
/**
|
||||
* @param {Mipmap} mipmap
|
||||
* @param {(face: ImageAsset) => void} callback
|
||||
*/
|
||||
void forEachFace(const ITextureCubeMipmap &mipmap, const ForEachFaceCallback &callback) {
|
||||
callback(mipmap.front, TextureCube::FaceIndex::FRONT);
|
||||
callback(mipmap.back, TextureCube::FaceIndex::BACK);
|
||||
callback(mipmap.left, TextureCube::FaceIndex::LEFT);
|
||||
callback(mipmap.right, TextureCube::FaceIndex::RIGHT);
|
||||
callback(mipmap.top, TextureCube::FaceIndex::TOP);
|
||||
callback(mipmap.bottom, TextureCube::FaceIndex::BOTTOM);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/* static */
|
||||
TextureCube *TextureCube::fromTexture2DArray(const ccstd::vector<Texture2D *> &textures) {
|
||||
size_t nMipmaps = textures.size() / 6;
|
||||
ccstd::vector<ITextureCubeMipmap> mipmaps;
|
||||
mipmaps.reserve(nMipmaps);
|
||||
for (size_t i = 0; i < nMipmaps; i++) {
|
||||
size_t x = i * 6;
|
||||
|
||||
ITextureCubeMipmap mipmap;
|
||||
mipmap.front = textures[x + static_cast<uint32_t>(FaceIndex::FRONT)]->getImage(),
|
||||
mipmap.back = textures[x + static_cast<uint32_t>(FaceIndex::BACK)]->getImage(),
|
||||
mipmap.left = textures[x + static_cast<uint32_t>(FaceIndex::LEFT)]->getImage(),
|
||||
mipmap.right = textures[x + static_cast<uint32_t>(FaceIndex::RIGHT)]->getImage(),
|
||||
mipmap.top = textures[x + static_cast<uint32_t>(FaceIndex::TOP)]->getImage(),
|
||||
mipmap.bottom = textures[x + static_cast<uint32_t>(FaceIndex::BOTTOM)]->getImage(),
|
||||
|
||||
mipmaps.emplace_back(mipmap);
|
||||
}
|
||||
auto *out = ccnew TextureCube();
|
||||
out->setMipmaps(mipmaps);
|
||||
return out;
|
||||
}
|
||||
|
||||
TextureCube::TextureCube() = default;
|
||||
|
||||
TextureCube::~TextureCube() = default;
|
||||
|
||||
void TextureCube::setMipmaps(const ccstd::vector<ITextureCubeMipmap> &value) {
|
||||
_mipmaps = value;
|
||||
|
||||
auto cubeMaps = ccstd::vector<ITextureCubeMipmap>{};
|
||||
if (value.size() == 1) {
|
||||
const auto &cubeMipmap = value.at(0);
|
||||
const auto &front = cubeMipmap.front->extractMipmaps();
|
||||
const auto &back = cubeMipmap.back->extractMipmaps();
|
||||
const auto &left = cubeMipmap.left->extractMipmaps();
|
||||
const auto &right = cubeMipmap.right->extractMipmaps();
|
||||
const auto &top = cubeMipmap.top->extractMipmaps();
|
||||
const auto &bottom = cubeMipmap.bottom->extractMipmaps();
|
||||
|
||||
if (front.size() != back.size() ||
|
||||
front.size() != left.size() ||
|
||||
front.size() != right.size() ||
|
||||
front.size() != top.size() ||
|
||||
front.size() != bottom.size()) {
|
||||
assert("different faces should have the same mipmap level");
|
||||
this->setMipmapParams({});
|
||||
return;
|
||||
}
|
||||
|
||||
const auto level = front.size();
|
||||
|
||||
for (auto i = 0U; i < level; i++) {
|
||||
const auto cubeMap = ITextureCubeMipmap{
|
||||
front[i],
|
||||
back[i],
|
||||
left[i],
|
||||
right[i],
|
||||
top[i],
|
||||
bottom[i],
|
||||
};
|
||||
cubeMaps.emplace_back(cubeMap);
|
||||
}
|
||||
} else if (value.size() > 1) {
|
||||
for (const auto &mipmap : value) {
|
||||
const auto cubeMap = ITextureCubeMipmap{
|
||||
mipmap.front->extractMipmap0(),
|
||||
mipmap.back->extractMipmap0(),
|
||||
mipmap.left->extractMipmap0(),
|
||||
mipmap.right->extractMipmap0(),
|
||||
mipmap.top->extractMipmap0(),
|
||||
mipmap.bottom->extractMipmap0(),
|
||||
};
|
||||
cubeMaps.emplace_back(cubeMap);
|
||||
}
|
||||
}
|
||||
|
||||
setMipmapParams(cubeMaps);
|
||||
}
|
||||
|
||||
void TextureCube::setMipmapParams(const ccstd::vector<ITextureCubeMipmap> &value) {
|
||||
_generatedMipmaps = value;
|
||||
setMipmapLevel(static_cast<uint32_t>(_generatedMipmaps.size()));
|
||||
if (!_generatedMipmaps.empty()) {
|
||||
ImageAsset *imageAsset = _generatedMipmaps[0].front;
|
||||
reset({imageAsset->getWidth(),
|
||||
imageAsset->getHeight(),
|
||||
imageAsset->getFormat(),
|
||||
static_cast<uint32_t>(_generatedMipmaps.size()),
|
||||
_baseLevel,
|
||||
_maxLevel});
|
||||
|
||||
for (size_t level = 0, len = _generatedMipmaps.size(); level < len; ++level) {
|
||||
forEachFace(_generatedMipmaps[level], [this, level](ImageAsset *face, TextureCube::FaceIndex faceIndex) {
|
||||
assignImage(face, static_cast<uint32_t>(level), static_cast<uint32_t>(faceIndex));
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
reset({0,
|
||||
0,
|
||||
ccstd::nullopt,
|
||||
static_cast<uint32_t>(_generatedMipmaps.size()),
|
||||
_baseLevel,
|
||||
_maxLevel});
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCube::setMipmapAtlas(const TextureCubeMipmapAtlasInfo &value) {
|
||||
if (value.layout.empty()) {
|
||||
return;
|
||||
}
|
||||
_mipmapAtlas = value;
|
||||
const ITextureCubeMipmap &atlas = _mipmapAtlas.atlas;
|
||||
const ccstd::vector<MipmapAtlasLayoutInfo> &layouts = _mipmapAtlas.layout;
|
||||
setMipmapLevel(static_cast<uint32_t>(layouts.size()));
|
||||
|
||||
const MipmapAtlasLayoutInfo &lv0Layout = layouts[0];
|
||||
const ImageAsset *imageAsset = atlas.front;
|
||||
|
||||
reset({lv0Layout.width,
|
||||
lv0Layout.height,
|
||||
imageAsset->getFormat(),
|
||||
static_cast<uint32_t>(layouts.size()),
|
||||
_baseLevel,
|
||||
_maxLevel});
|
||||
|
||||
const uint32_t pixelSize = gfx::GFX_FORMAT_INFOS[static_cast<uint32_t>(imageAsset->getFormat())].size;
|
||||
|
||||
for (size_t level = 0; level < layouts.size(); level++) {
|
||||
const MipmapAtlasLayoutInfo &layoutInfo = layouts[level];
|
||||
uint32_t currentSize = layoutInfo.width * layoutInfo.height * pixelSize;
|
||||
|
||||
//Upload 6 sides by level
|
||||
forEachFace(atlas, [this, currentSize, lv0Layout, layoutInfo, level, pixelSize](ImageAsset *face, TextureCube::FaceIndex faceIndex) {
|
||||
auto *buffer = ccnew uint8_t[currentSize];
|
||||
memset(buffer, 0, currentSize);
|
||||
const uint8_t *data = face->getData();
|
||||
//Splitting Atlas
|
||||
if (level == 0) {
|
||||
memcpy(buffer, data, currentSize);
|
||||
} else {
|
||||
uint32_t bufferOffset = 0;
|
||||
uint32_t dateOffset = lv0Layout.width * lv0Layout.height * pixelSize;
|
||||
uint32_t leftOffset = layoutInfo.left * pixelSize;
|
||||
for (size_t j = 0; j < layoutInfo.height; j++) {
|
||||
memcpy(buffer + bufferOffset, data + dateOffset + leftOffset, layoutInfo.width * pixelSize);
|
||||
bufferOffset += layoutInfo.width * pixelSize;
|
||||
dateOffset += lv0Layout.width * pixelSize;
|
||||
}
|
||||
}
|
||||
auto *tempAsset = ccnew ImageAsset();
|
||||
tempAsset->addRef();
|
||||
auto *arrayBuffer = ccnew ArrayBuffer(buffer, static_cast<uint32_t>(currentSize));
|
||||
IMemoryImageSource source{arrayBuffer, face->isCompressed(), layoutInfo.width, layoutInfo.height, face->getFormat()};
|
||||
tempAsset->setNativeAsset(source);
|
||||
|
||||
assignImage(tempAsset, static_cast<uint32_t>(level), static_cast<uint32_t>(faceIndex));
|
||||
CC_SAFE_DELETE_ARRAY(buffer);
|
||||
tempAsset->release();
|
||||
tempAsset = nullptr;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCube::setMipmapsForJS(const ccstd::vector<ITextureCubeMipmap> &value) {
|
||||
_mipmaps = value;
|
||||
}
|
||||
|
||||
void TextureCube::setMipmapAtlasForJS(const TextureCubeMipmapAtlasInfo &value) {
|
||||
_mipmapAtlas = value;
|
||||
}
|
||||
|
||||
void TextureCube::setImage(const ITextureCubeMipmap *value) {
|
||||
if (value != nullptr) {
|
||||
setMipmaps({*value});
|
||||
} else {
|
||||
setMipmaps({});
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCube::reset(const ITextureCubeCreateInfo &info) {
|
||||
_width = info.width;
|
||||
_height = info.height;
|
||||
setGFXFormat(info.format);
|
||||
|
||||
uint32_t mipLevels = info.mipmapLevel.has_value() ? info.mipmapLevel.value() : 1;
|
||||
setMipmapLevel(mipLevels);
|
||||
|
||||
uint32_t minLod = info.baseLevel.has_value() ? info.baseLevel.value() : 0;
|
||||
uint32_t maxLod = info.maxLevel.has_value() ? info.maxLevel.value() : 1000;
|
||||
setMipRange(minLod, maxLod);
|
||||
|
||||
tryReset();
|
||||
}
|
||||
|
||||
void TextureCube::releaseTexture() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
void TextureCube::updateMipmaps(uint32_t firstLevel, uint32_t count) {
|
||||
if (firstLevel >= _generatedMipmaps.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto nUpdate = static_cast<uint32_t>(std::min(
|
||||
count == 0 ? _generatedMipmaps.size() : count,
|
||||
_generatedMipmaps.size() - firstLevel));
|
||||
|
||||
for (uint32_t i = 0; i < nUpdate; ++i) {
|
||||
uint32_t level = firstLevel + i;
|
||||
forEachFace(_generatedMipmaps[level], [this, level](auto face, auto faceIndex) {
|
||||
assignImage(face, level, static_cast<uint32_t>(faceIndex));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool TextureCube::isUsingOfflineMipmaps() {
|
||||
return _mipmapMode == MipmapMode::BAKED_CONVOLUTION_MAP;
|
||||
}
|
||||
|
||||
void TextureCube::initialize() {
|
||||
if (_mipmapMode == MipmapMode::BAKED_CONVOLUTION_MAP) {
|
||||
setMipmapAtlas(_mipmapAtlas);
|
||||
} else {
|
||||
setMipmaps(_mipmaps);
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCube::onLoaded() {
|
||||
initialize();
|
||||
}
|
||||
|
||||
bool TextureCube::destroy() {
|
||||
_mipmaps.clear();
|
||||
_generatedMipmaps.clear();
|
||||
_mipmapAtlas.layout.clear();
|
||||
return Super::destroy();
|
||||
}
|
||||
|
||||
ccstd::any TextureCube::serialize(const ccstd::any & /*ctxForExporting*/) {
|
||||
//cjh TODO: if (EDITOR || TEST) {
|
||||
// return {
|
||||
// base: super._serialize(ctxForExporting),
|
||||
// rgbe: this.isRGBE,
|
||||
// mipmaps: this._mipmaps.map((mipmap) => ((ctxForExporting && ctxForExporting._compressUuid) ? {
|
||||
// front: EditorExtends.UuidUtils.compressUuid(mipmap.front._uuid, true),
|
||||
// back: EditorExtends.UuidUtils.compressUuid(mipmap.back._uuid, true),
|
||||
// left: EditorExtends.UuidUtils.compressUuid(mipmap.left._uuid, true),
|
||||
// right: EditorExtends.UuidUtils.compressUuid(mipmap.right._uuid, true),
|
||||
// top: EditorExtends.UuidUtils.compressUuid(mipmap.top._uuid, true),
|
||||
// bottom: EditorExtends.UuidUtils.compressUuid(mipmap.bottom._uuid, true),
|
||||
// } : {
|
||||
// front: mipmap.front._uuid,
|
||||
// back: mipmap.back._uuid,
|
||||
// left: mipmap.left._uuid,
|
||||
// right: mipmap.right._uuid,
|
||||
// top: mipmap.top._uuid,
|
||||
// bottom: mipmap.bottom._uuid,
|
||||
// })),
|
||||
// };
|
||||
// }
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TextureCube::deserialize(const ccstd::any &serializedData, const ccstd::any &handle) {
|
||||
const auto *data = ccstd::any_cast<TextureCubeSerializeData>(&serializedData);
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
Super::deserialize(data->base, handle);
|
||||
isRGBE = data->rgbe;
|
||||
_mipmapMode = data->mipmapMode;
|
||||
|
||||
_mipmaps.resize(data->mipmaps.size());
|
||||
for (size_t i = 0; i < data->mipmaps.size(); ++i) {
|
||||
// Prevent resource load failed
|
||||
ITextureCubeMipmap mipmap;
|
||||
mipmap.front = ccnew ImageAsset(),
|
||||
mipmap.back = ccnew ImageAsset(),
|
||||
mipmap.left = ccnew ImageAsset(),
|
||||
mipmap.right = ccnew ImageAsset(),
|
||||
mipmap.top = ccnew ImageAsset(),
|
||||
mipmap.bottom = ccnew ImageAsset();
|
||||
_mipmaps[i] = mipmap;
|
||||
// auto* mipmap = data->mipmaps[i];
|
||||
|
||||
//cjh TODO: what's handle.result?? const imageAssetClassId = js.getClassId(ImageAsset);
|
||||
//
|
||||
// handle.result.push(this._mipmaps[i], `front`, mipmap.front, imageAssetClassId);
|
||||
// handle.result.push(this._mipmaps[i], `back`, mipmap.back, imageAssetClassId);
|
||||
// handle.result.push(this._mipmaps[i], `left`, mipmap.left, imageAssetClassId);
|
||||
// handle.result.push(this._mipmaps[i], `right`, mipmap.right, imageAssetClassId);
|
||||
// handle.result.push(this._mipmaps[i], `top`, mipmap.top, imageAssetClassId);
|
||||
// handle.result.push(this._mipmaps[i], `bottom`, mipmap.bottom, imageAssetClassId);
|
||||
}
|
||||
}
|
||||
|
||||
gfx::TextureInfo TextureCube::getGfxTextureCreateInfo(gfx::TextureUsageBit usage, gfx::Format format, uint32_t levelCount, gfx::TextureFlagBit flags) {
|
||||
gfx::TextureInfo texInfo;
|
||||
texInfo.type = gfx::TextureType::CUBE;
|
||||
texInfo.width = _width;
|
||||
texInfo.height = _height;
|
||||
texInfo.layerCount = 6;
|
||||
texInfo.usage = usage;
|
||||
texInfo.format = format;
|
||||
texInfo.levelCount = levelCount;
|
||||
texInfo.flags = flags;
|
||||
return texInfo;
|
||||
}
|
||||
|
||||
gfx::TextureViewInfo TextureCube::getGfxTextureViewCreateInfo(gfx::Texture *texture, gfx::Format format, uint32_t baseLevel, uint32_t levelCount) {
|
||||
gfx::TextureViewInfo texViewInfo;
|
||||
texViewInfo.type = gfx::TextureType::CUBE;
|
||||
texViewInfo.baseLayer = 0;
|
||||
texViewInfo.layerCount = 6;
|
||||
texViewInfo.texture = texture;
|
||||
texViewInfo.format = format;
|
||||
texViewInfo.baseLevel = baseLevel;
|
||||
texViewInfo.levelCount = levelCount;
|
||||
return texViewInfo;
|
||||
}
|
||||
|
||||
void TextureCube::initDefault(const ccstd::optional<ccstd::string> &uuid) {
|
||||
Super::initDefault(uuid);
|
||||
|
||||
auto *imageAsset = ccnew ImageAsset();
|
||||
imageAsset->initDefault(ccstd::nullopt);
|
||||
|
||||
ITextureCubeMipmap mipmap;
|
||||
|
||||
mipmap.front = imageAsset;
|
||||
mipmap.back = imageAsset;
|
||||
mipmap.top = imageAsset;
|
||||
mipmap.bottom = imageAsset;
|
||||
mipmap.left = imageAsset;
|
||||
mipmap.right = imageAsset;
|
||||
|
||||
setMipmaps({mipmap});
|
||||
}
|
||||
|
||||
bool TextureCube::validate() const {
|
||||
if (_mipmapMode == MipmapMode::BAKED_CONVOLUTION_MAP) {
|
||||
if (_mipmapAtlas.layout.empty()) {
|
||||
return false;
|
||||
}
|
||||
return (_mipmapAtlas.atlas.top && _mipmapAtlas.atlas.bottom && _mipmapAtlas.atlas.front && _mipmapAtlas.atlas.back && _mipmapAtlas.atlas.left && _mipmapAtlas.atlas.right);
|
||||
}
|
||||
if (_mipmaps.empty()) {
|
||||
return false;
|
||||
}
|
||||
return std::all_of(_mipmaps.begin(),
|
||||
_mipmaps.end(),
|
||||
[&](const ITextureCubeMipmap &mipmap) {
|
||||
return (mipmap.top && mipmap.bottom && mipmap.front && mipmap.back && mipmap.left && mipmap.right);
|
||||
});
|
||||
}
|
||||
} // namespace cc
|
||||
270
cocos/core/assets/TextureCube.h
Normal file
270
cocos/core/assets/TextureCube.h
Normal file
@@ -0,0 +1,270 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/assets/Asset.h"
|
||||
#include "core/assets/SimpleTexture.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class ImageAsset;
|
||||
class Texture2D;
|
||||
struct ITexture2DCreateInfo;
|
||||
|
||||
using ITextureCubeCreateInfo = ITexture2DCreateInfo;
|
||||
|
||||
/**
|
||||
* @en The texture cube mipmap interface
|
||||
* @zh 立方体贴图的 Mipmap 接口。
|
||||
*/
|
||||
struct ITextureCubeMipmap {
|
||||
IntrusivePtr<ImageAsset> front;
|
||||
IntrusivePtr<ImageAsset> back;
|
||||
IntrusivePtr<ImageAsset> left;
|
||||
IntrusivePtr<ImageAsset> right;
|
||||
IntrusivePtr<ImageAsset> top;
|
||||
IntrusivePtr<ImageAsset> bottom;
|
||||
};
|
||||
|
||||
struct ITextureCubeSerializeMipmapData {
|
||||
ccstd::string front;
|
||||
ccstd::string back;
|
||||
ccstd::string left;
|
||||
ccstd::string right;
|
||||
ccstd::string top;
|
||||
ccstd::string bottom;
|
||||
};
|
||||
|
||||
/**
|
||||
* @en The MipmapAtlas region interface
|
||||
* @zh MipmapAtlas的region接口。
|
||||
*/
|
||||
struct MipmapAtlasLayoutInfo {
|
||||
uint32_t left{0};
|
||||
uint32_t top{0};
|
||||
uint32_t width{0};
|
||||
uint32_t height{0};
|
||||
uint32_t level{0};
|
||||
};
|
||||
/**
|
||||
* @en The texture cube MipmapAtlas interface
|
||||
* @zh 立方体贴图的 MipmapAtlas 接口。
|
||||
*/
|
||||
struct TextureCubeMipmapAtlasInfo {
|
||||
ITextureCubeMipmap atlas;
|
||||
ccstd::vector<MipmapAtlasLayoutInfo> layout;
|
||||
};
|
||||
|
||||
/**
|
||||
* @en The way to fill mipmaps.
|
||||
* @zh 填充mipmaps的方式。
|
||||
*/
|
||||
enum class MipmapMode {
|
||||
/**
|
||||
* @zh
|
||||
* 不使用mipmaps
|
||||
* @en
|
||||
* Not using mipmaps
|
||||
* @readonly
|
||||
*/
|
||||
NONE = 0,
|
||||
/**
|
||||
* @zh
|
||||
* 使用自动生成的mipmaps
|
||||
* @en
|
||||
* Using the automatically generated mipmaps
|
||||
* @readonly
|
||||
*/
|
||||
AUTO = 1,
|
||||
/**
|
||||
* @zh
|
||||
* 使用卷积图填充mipmaps
|
||||
* @en
|
||||
* Filling mipmaps with convolutional maps.
|
||||
* @readonly
|
||||
*/
|
||||
BAKED_CONVOLUTION_MAP = 2
|
||||
};
|
||||
struct TextureCubeSerializeData {
|
||||
ccstd::string base;
|
||||
bool rgbe{false};
|
||||
MipmapMode mipmapMode{MipmapMode::NONE};
|
||||
ccstd::vector<ITextureCubeSerializeMipmapData> mipmaps;
|
||||
TextureCubeMipmapAtlasInfo mipmapAtlas;
|
||||
};
|
||||
|
||||
/**
|
||||
* @en The texture cube asset.
|
||||
* Each mipmap level of a texture cube have 6 [[ImageAsset]], represents 6 faces of the cube.
|
||||
* @zh 立方体贴图资源。
|
||||
* 立方体贴图资源的每个 Mipmap 层级都为 6 张 [[ImageAsset]],分别代表了立方体贴图的 6 个面。
|
||||
*/
|
||||
class TextureCube final : public SimpleTexture {
|
||||
public:
|
||||
using Super = SimpleTexture;
|
||||
|
||||
TextureCube();
|
||||
~TextureCube() override;
|
||||
|
||||
/**
|
||||
* @en The index for all faces of the cube
|
||||
* @zh 立方体每个面的约定索引。
|
||||
*/
|
||||
enum class FaceIndex {
|
||||
RIGHT = 0,
|
||||
LEFT = 1,
|
||||
TOP = 2,
|
||||
BOTTOM = 3,
|
||||
FRONT = 4,
|
||||
BACK = 5,
|
||||
};
|
||||
|
||||
/**
|
||||
* @en Create a texture cube with an array of [[Texture2D]] which represents 6 faces of the texture cube.
|
||||
* @zh 通过二维贴图数组指定每个 Mipmap 的每个面创建立方体贴图。
|
||||
* @param textures Texture array, the texture count must be multiple of 6. Every 6 textures are 6 faces of a mipmap level.
|
||||
* The order should obey [[FaceIndex]] order.
|
||||
* @param out Output texture cube, if not given, will create a new texture cube.
|
||||
* @returns The created texture cube.
|
||||
* @example
|
||||
* ```ts
|
||||
* const textures = new Array<Texture2D>(6);
|
||||
* textures[TextureCube.FaceIndex.front] = frontImage;
|
||||
* textures[TextureCube.FaceIndex.back] = backImage;
|
||||
* textures[TextureCube.FaceIndex.left] = leftImage;
|
||||
* textures[TextureCube.FaceIndex.right] = rightImage;
|
||||
* textures[TextureCube.FaceIndex.top] = topImage;
|
||||
* textures[TextureCube.FaceIndex.bottom] = bottomImage;
|
||||
* const textureCube = TextureCube.fromTexture2DArray(textures);
|
||||
* ```
|
||||
*/
|
||||
static TextureCube *fromTexture2DArray(const ccstd::vector<Texture2D *> &textures);
|
||||
|
||||
/**
|
||||
* @en All levels of mipmap images, be noted, automatically generated mipmaps are not included.
|
||||
* When setup mipmap, the size of the texture and pixel format could be modified.
|
||||
* @zh 所有层级 Mipmap,注意,这里不包含自动生成的 Mipmap。
|
||||
* 当设置 Mipmap 时,贴图的尺寸以及像素格式可能会改变。
|
||||
*/
|
||||
const ccstd::vector<ITextureCubeMipmap> &getMipmaps() const {
|
||||
return _mipmaps;
|
||||
}
|
||||
|
||||
inline const TextureCubeMipmapAtlasInfo &getMipmapAtlas() const {
|
||||
return _mipmapAtlas;
|
||||
}
|
||||
|
||||
void setMipmaps(const ccstd::vector<ITextureCubeMipmap> &value);
|
||||
|
||||
void setMipmapsForJS(const ccstd::vector<ITextureCubeMipmap> &value);
|
||||
|
||||
void setMipmapAtlasForJS(const TextureCubeMipmapAtlasInfo &value);
|
||||
|
||||
/**
|
||||
* @en Fill mipmaps with convolutional maps.
|
||||
* @zh 使用卷积图填充mipmaps。
|
||||
* @param value All mipmaps of each face of the cube map are stored in the form of atlas.
|
||||
* and the value contains the atlas of the 6 faces and the layout information of each mipmap layer.
|
||||
*/
|
||||
void setMipmapAtlas(const TextureCubeMipmapAtlasInfo &value);
|
||||
|
||||
/**
|
||||
* @en Level 0 mipmap image.
|
||||
* Be noted, `this.image = img` equals `this.mipmaps = [img]`,
|
||||
* sets image will clear all previous mipmaps.
|
||||
* @zh 0 级 Mipmap。
|
||||
* 注意,`this.image = img` 等价于 `this.mipmaps = [img]`,
|
||||
* 也就是说,通过 `this.image` 设置 0 级 Mipmap 时将隐式地清除之前的所有 Mipmap。
|
||||
*/
|
||||
const ITextureCubeMipmap *getImage() const {
|
||||
return _mipmaps.empty() ? nullptr : &_mipmaps[0];
|
||||
}
|
||||
|
||||
void setImage(const ITextureCubeMipmap *value);
|
||||
|
||||
/**
|
||||
* @en Reset the current texture with given size, pixel format and mipmap images.
|
||||
* After reset, the gfx resource will become invalid, you must use [[uploadData]] explicitly to upload the new mipmaps to GPU resources.
|
||||
* @zh 将当前贴图重置为指定尺寸、像素格式以及指定 mipmap 层级。重置后,贴图的像素数据将变为未定义。
|
||||
* mipmap 图像的数据不会自动更新到贴图中,你必须显式调用 [[uploadData]] 来上传贴图数据。
|
||||
* @param info The create information
|
||||
*/
|
||||
void reset(const ITextureCubeCreateInfo &info);
|
||||
|
||||
/**
|
||||
* @en Release used GPU resources.
|
||||
* @zh 释放占用的 GPU 资源。
|
||||
* @deprecated please use [[destroy]] instead
|
||||
*/
|
||||
void releaseTexture();
|
||||
|
||||
// Override functions
|
||||
void updateMipmaps(uint32_t firstLevel, uint32_t count) override;
|
||||
|
||||
/**
|
||||
* @en Whether mipmaps are baked convolutional maps.
|
||||
* @zh mipmaps是否为烘焙出来的卷积图。
|
||||
*/
|
||||
bool isUsingOfflineMipmaps() override;
|
||||
|
||||
void initialize();
|
||||
void onLoaded() override;
|
||||
/**
|
||||
* 销毁此贴图,清空所有 Mipmap 并释放占用的 GPU 资源。
|
||||
*/
|
||||
bool destroy() override;
|
||||
|
||||
ccstd::any serialize(const ccstd::any &ctxForExporting) override;
|
||||
void deserialize(const ccstd::any &serializedData, const ccstd::any &handle) override;
|
||||
|
||||
gfx::TextureInfo getGfxTextureCreateInfo(gfx::TextureUsageBit usage, gfx::Format format, uint32_t levelCount, gfx::TextureFlagBit flags) override;
|
||||
gfx::TextureViewInfo getGfxTextureViewCreateInfo(gfx::Texture *texture, gfx::Format format, uint32_t baseLevel, uint32_t levelCount) override;
|
||||
|
||||
void initDefault(const ccstd::optional<ccstd::string> &uuid) override;
|
||||
|
||||
bool validate() const override;
|
||||
//
|
||||
|
||||
/*@serializable*/
|
||||
MipmapMode _mipmapMode{MipmapMode::NONE};
|
||||
|
||||
/*@serializable*/
|
||||
bool isRGBE{false};
|
||||
|
||||
private:
|
||||
void setMipmapParams(const ccstd::vector<ITextureCubeMipmap> &value);
|
||||
|
||||
/*@serializable*/
|
||||
ccstd::vector<ITextureCubeMipmap> _mipmaps;
|
||||
|
||||
ccstd::vector<ITextureCubeMipmap> _generatedMipmaps;
|
||||
|
||||
/*@serializable*/
|
||||
TextureCubeMipmapAtlasInfo _mipmapAtlas;
|
||||
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(TextureCube);
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
Reference in New Issue
Block a user