55 spdlog::info(
"Asset::resource loading '{}' type '{}'", _name, _type);
56 if (_resources.empty()) {
58 auto graphicsDevice = _defaultGraphicsDevice.lock();
59 if (!graphicsDevice) {
60 spdlog::error(
"Cannot load container asset '{}': no graphics device set", _name);
65 const bool isObj = _file.size() >= 4 &&
66 (_file.compare(_file.size() - 4, 4,
".obj") == 0 ||
67 _file.compare(_file.size() - 4, 4,
".OBJ") == 0);
69 const bool isStl = _file.size() >= 4 &&
70 (_file.compare(_file.size() - 4, 4,
".stl") == 0 ||
71 _file.compare(_file.size() - 4, 4,
".STL") == 0);
73 const bool isAssimp = _file.size() >= 4 &&
74 (_file.compare(_file.size() - 4, 4,
".dae") == 0 ||
75 _file.compare(_file.size() - 4, 4,
".DAE") == 0 ||
76 _file.compare(_file.size() - 4, 4,
".fbx") == 0 ||
77 _file.compare(_file.size() - 4, 4,
".FBX") == 0 ||
78 _file.compare(_file.size() - 4, 4,
".3ds") == 0 ||
79 _file.compare(_file.size() - 4, 4,
".ply") == 0 ||
80 _file.compare(_file.size() - 4, 4,
".PLY") == 0);
82 std::unique_ptr<GlbContainerResource> container;
87 }
else if (isAssimp) {
97 auto graphicsDevice = _defaultGraphicsDevice.lock();
98 if (!graphicsDevice) {
99 spdlog::error(
"Cannot load texture asset '{}': no graphics device set", _name);
107 stbi_set_flip_vertically_on_load(
false);
109 const bool isHdr = _file.size() >= 4 &&
110 _file.compare(_file.size() - 4, 4,
".hdr") == 0;
114 float* hdrPixels = stbi_loadf(_file.c_str(), &width, &height, &channels, 0);
115 if (!hdrPixels || width <= 0 || height <= 0) {
116 spdlog::error(
"Failed to decode HDR texture asset '{}' from '{}'", _name, _file);
118 stbi_image_free(hdrPixels);
124 const size_t pixelCount =
static_cast<size_t>(width) *
static_cast<size_t>(height);
125 std::vector<float> rgbaData(pixelCount * 4);
126 for (
size_t i = 0; i < pixelCount; ++i) {
127 rgbaData[i * 4 + 0] = hdrPixels[i * channels + 0];
128 rgbaData[i * 4 + 1] = channels > 1 ? hdrPixels[i * channels + 1] : hdrPixels[i * channels + 0];
129 rgbaData[i * 4 + 2] = channels > 2 ? hdrPixels[i * channels + 2] : hdrPixels[i * channels + 0];
130 rgbaData[i * 4 + 3] = 1.0f;
132 stbi_image_free(hdrPixels);
135 options.
width =
static_cast<uint32_t
>(width);
136 options.
height =
static_cast<uint32_t
>(height);
138 options.
mipmaps = _data.mipmaps;
139 options.
numLevels = _data.mipmaps ? 0 : 1;
140 options.
name = _name;
142 auto* texture =
new Texture(graphicsDevice.get(), options);
144 const auto dataSize = pixelCount * 4 *
sizeof(float);
145 texture->setLevelData(0,
reinterpret_cast<const uint8_t*
>(rgbaData.data()), dataSize);
148 spdlog::info(
"Loaded HDR texture '{}': {}x{} channels={}", _name, width, height, channels);
149 _resources.push_back(texture);
152 stbi_uc* pixels = stbi_load(_file.c_str(), &width, &height, &channels, STBI_rgb_alpha);
153 if (!pixels || width <= 0 || height <= 0) {
154 spdlog::error(
"Failed to decode texture asset '{}' from '{}'", _name, _file);
156 stbi_image_free(pixels);
162 options.
width =
static_cast<uint32_t
>(width);
163 options.
height =
static_cast<uint32_t
>(height);
165 options.
mipmaps = _data.mipmaps;
166 options.
numLevels = _data.mipmaps ? 0 : 1;
167 options.
name = _name;
169 auto* texture =
new Texture(graphicsDevice.get(), options);
177 const auto dataSize =
static_cast<size_t>(width) *
static_cast<size_t>(height) * 4u;
178 texture->setLevelData(0,
reinterpret_cast<const uint8_t*
>(pixels), dataSize);
181 stbi_image_free(pixels);
182 _resources.push_back(texture);
185 auto graphicsDevice = _defaultGraphicsDevice.lock();
186 if (!graphicsDevice) {
187 spdlog::error(
"Cannot load font asset '{}': no graphics device set", _name);
192 if (!font.has_value()) {
193 spdlog::error(
"Failed to decode bitmap font asset '{}' from '{}'", _name, _file);
196 _resources.push_back(*font);
200 if (!_resources.empty()) {
201 return _resources[0];
207 std::function<
void(std::optional<Resource>)> callback)
210 if (!_resources.empty()) {
211 spdlog::info(
"Asset::loadAsync '{}' already loaded — returning cached", _name);
212 if (callback) callback(_resources[0]);
216 auto graphicsDevice = _defaultGraphicsDevice.lock();
217 if (!graphicsDevice) {
218 spdlog::error(
"Cannot async-load asset '{}': no graphics device set", _name);
219 if (callback) callback(std::nullopt);
225 const std::string& handlerType = _type;
235 auto device = graphicsDevice;
237 spdlog::info(
"Asset::loadAsync queuing '{}' type '{}'", _name, _type);
239 loader.
load(_file, handlerType,
241 [self,
name,
type,
file,
data, device, callback](std::unique_ptr<LoadedData> loaded) {
244 auto& pd = *loaded->pixelData;
247 options.
width =
static_cast<uint32_t
>(pd.width);
248 options.
height =
static_cast<uint32_t
>(pd.height);
255 auto* texture =
new Texture(device.get(), options);
265 texture->setLevelData(0,
266 reinterpret_cast<const uint8_t*
>(pd.hdrPixels.data()),
267 pd.hdrPixels.size() *
sizeof(
float));
269 texture->setLevelData(0, pd.pixels.data(), pd.pixels.size());
273 spdlog::info(
"Asset::loadAsync texture '{}' GPU upload done {}x{}",
274 name, pd.width, pd.height);
276 self->_resources.push_back(texture);
277 if (callback) callback(texture);
280 std::unique_ptr<GlbContainerResource> container;
287 if (loaded->preparsed && loaded->preparedData) {
288 auto model = std::static_pointer_cast<tinygltf::Model>(loaded->preparsed);
289 auto prepared = std::static_pointer_cast<PreparedGlbData>(loaded->preparedData);
291 }
else if (loaded->preparsed) {
293 auto model = std::static_pointer_cast<tinygltf::Model>(loaded->preparsed);
298 const bool isGlb =
file.size() >= 4 &&
299 (
file.compare(
file.size() - 4, 4,
".glb") == 0 ||
300 file.compare(
file.size() - 4, 4,
".GLB") == 0);
302 const bool isGltf =
file.size() >= 5 &&
303 (
file.compare(
file.size() - 5, 5,
".gltf") == 0 ||
304 file.compare(
file.size() - 5, 5,
".GLTF") == 0);
306 if ((isGlb || isGltf) && !loaded->bytes.empty()) {
308 loaded->bytes.data(), loaded->bytes.size(), device,
name);
313 const bool isObj =
file.size() >= 4 &&
314 (
file.compare(
file.size() - 4, 4,
".obj") == 0 ||
315 file.compare(
file.size() - 4, 4,
".OBJ") == 0);
317 const bool isStl =
file.size() >= 4 &&
318 (
file.compare(
file.size() - 4, 4,
".stl") == 0 ||
319 file.compare(
file.size() - 4, 4,
".STL") == 0);
321 const bool isAssimp =
file.size() >= 4 &&
322 (
file.compare(
file.size() - 4, 4,
".dae") == 0 ||
323 file.compare(
file.size() - 4, 4,
".DAE") == 0 ||
324 file.compare(
file.size() - 4, 4,
".fbx") == 0 ||
325 file.compare(
file.size() - 4, 4,
".FBX") == 0 ||
326 file.compare(
file.size() - 4, 4,
".3ds") == 0 ||
327 file.compare(
file.size() - 4, 4,
".ply") == 0 ||
328 file.compare(
file.size() - 4, 4,
".PLY") == 0);
334 }
else if (isAssimp) {
338 if (!loaded->bytes.empty()) {
340 loaded->bytes.data(), loaded->bytes.size(),
349 self->_resources.push_back(res);
350 spdlog::info(
"Asset::loadAsync container '{}' parse done",
name);
351 if (callback) callback(res);
353 spdlog::error(
"Asset::loadAsync container '{}' parse failed",
name);
354 if (callback) callback(std::nullopt);
361 if (font.has_value()) {
362 self->_resources.push_back(*font);
363 spdlog::info(
"Asset::loadAsync font '{}' parse done",
name);
364 if (callback) callback(*font);
366 spdlog::error(
"Asset::loadAsync font '{}' parse failed",
name);
367 if (callback) callback(std::nullopt);
371 spdlog::warn(
"Asset::loadAsync '{}' unsupported type '{}'",
name,
type);
372 if (callback) callback(std::nullopt);
376 [
name, callback](
const std::string& error) {
377 spdlog::error(
"Asset::loadAsync '{}' failed: {}",
name, error);
378 if (callback) callback(std::nullopt);
GPU texture resource supporting 2D, cubemap, volume, and array formats with mipmap management.
constexpr const char * TEXTURETYPE_RGBM
constexpr const char * TEXTURETYPE_RGBP