2#include "ModelLoader.h"
5#include "Resources/Buffer.h"
6#include "Resources/ResourceStore.h"
7#include "Resources/ModelManager.h"
8#include "Resources/MeshManager.h"
9#include "Resources/MaterialManager.h"
10#include "Resources/TextureManager.h"
11#include "Resources/AnimationManager.h"
12#include "Resources/BufferManager.h"
14#include "Platform/ResourceBufferBackedFileContents.h"
16#include "Foundation/Geometry/BoundingBox.hpp"
17#include "Foundation/Logging/Logger.h"
18#include "Foundation/Platform/FileHandle.h"
19#include "Foundation/Platform/IO.h"
20#include "Foundation/Platform/MMapBackedFileContents.h"
21#include "Foundation/Platform/Threads.h"
22#include "Foundation/Platform/Timer.h"
32#define COGS_MODELLOADER_MAX_TASKS 20
48 std::atomic<uint32_t> loadCount(0);
53 const T* base =
nullptr;
56 const T& operator[](
size_t i)
const { assert(i < count);
return base[i]; }
60 constexpr bool isValidIndex(T v)
62 static_assert(std::is_integral_v<T>);
69 std::unique_ptr<Cogs::FileContents> contents;
76 std::span<CogsBin::SectionInfo> sectionInfo;
77 std::vector<const uint8_t*> sectionPtr;
78 std::unique_ptr<Cogs::Mutex[]> sectionLocks;
79 Cogs::Mutex buffersMutex;
81 TypedView<CogsBin::Buffer> buffers;
82 TypedView<CogsBin::ExternalTexture> externalTextures;
83 TypedView<CogsBin::EmbeddedTexture> embeddedTextures;
84 TypedView<CogsBin::SamplerState> samplerStates;
85 TypedView<CogsBin::String> strings;
86 TypedView<char> stringData;
87 TypedView<CogsBin::Node> nodes;
88 TypedView<CogsBin::Transform> transforms;
89 TypedView<Cogs::Geometry::BoundingBox> boundingBoxes;
90 TypedView<CogsBin::MaterialInstance> materialInstances;
91 TypedView<CogsBin::Property> props;
92 TypedView<uint8_t> propData;
93 TypedView<CogsBin::Mesh> meshes;
94 TypedView<CogsBin::VertexStream> vertexStreams;
95 TypedView<CogsBin::VertexAttribute> vertexAttributes;
96 TypedView<CogsBin::Bone> bones;
97 TypedView<CogsBin::Skeleton> skeletons;
98 TypedView<CogsBin::AnimTrack> animTracks;
99 TypedView<CogsBin::AnimClip> animClips;
100 TypedView<CogsBin::Model> models;
102 std::vector<ResourceBufferHandle> bufferCache;
103 std::vector<TextureHandle> textureCache;
105 std::list<std::unique_ptr<uint8_t[]>> allocations;
110 switch (primitiveType) {
120 case CogsBin::PrimitiveType::ControlPoint1PatchList:
return Cogs::PrimitiveType::ControlPoint1PatchList;
break;
121 case CogsBin::PrimitiveType::ControlPoint2PatchList:
return Cogs::PrimitiveType::ControlPoint2PatchList;
break;
122 case CogsBin::PrimitiveType::ControlPoint3PatchList:
return Cogs::PrimitiveType::ControlPoint3PatchList;
break;
123 case CogsBin::PrimitiveType::ControlPoint4PatchList:
return Cogs::PrimitiveType::ControlPoint4PatchList;
break;
127 rctx.success =
false;
128 LOG_ERROR(logger,
"Illegal primitive type: %u",
unsigned(primitiveType));
132 const uint8_t* sectionPointer(ReadContext& rctx, uint32_t index)
135 thread_local ZSTD_DCtx* zstd_dctx =
nullptr;
137 assert(index < rctx.header->sectionCount);
139 Cogs::LockGuard lock(rctx.sectionLocks[index]);
140 const auto & sectionInfo = rctx.sectionInfo[index];
141 if (rctx.sectionPtr[index] ==
nullptr) {
149 switch (rctx.sectionInfo[index].compression)
151 case CogsBin::Compression::None:
152 rctx.sectionPtr[index] = rctx.contents->ptr + rctx.sectionInfo[index].fileOffset;
154 case CogsBin::Compression::ZSTD: {
155 if (zstd_dctx ==
nullptr) {
156 zstd_dctx = ZSTD_createDCtx();
162 rctx.allocations.emplace_back(
new uint8_t[sectionInfo.uncompressedSize ? sectionInfo.uncompressedSize : 1]);
163 rctx.sectionPtr[index] = rctx.allocations.back().get();
165 auto result = ZSTD_decompressDCtx(zstd_dctx,
166 rctx.allocations.back().get(), sectionInfo.uncompressedSize,
167 rctx.contents->ptr + sectionInfo.fileOffset, sectionInfo.fileSize);
168 if (ZSTD_isError(result)) {
169 LOG_ERROR(logger,
"zstd decompression failed: %s", ZSTD_getErrorName(result));
172 else if (result != sectionInfo.uncompressedSize) {
173 LOG_ERROR(logger,
"Uncompressed data size didn't match size recorded in file.");
179 LOG_ERROR(logger,
"Illegal compression flag on section.");
183 return rctx.sectionPtr[index];
188 if (ix < rctx.strings.count) {
189 auto & str = rctx.strings[ix];
194 else if (!isValidIndex(ix)) {
195 return std::string_view();
198 LOG_ERROR(logger,
"Invalid string index %u", ix);
199 rctx.success =
false;
204 const Cogs::Geometry::BoundingBox& getBoundingBox(ReadContext& rctx, uint32_t ix)
206 if (ix < rctx.boundingBoxes.count) {
207 return rctx.boundingBoxes[ix];
210 rctx.success =
false;
211 LOG_ERROR(logger,
"Invalid bounding box index %u", ix);
212 static const Cogs::Geometry::BoundingBox empty = Cogs::Geometry::makeEmptyBoundingBox<Cogs::Geometry::BoundingBox>();
217 Cogs::TextureFormat getTextureFormat(ReadContext& , CogsBin::Format format)
220 case CogsBin::Format::Unknown:
return Cogs::TextureFormat::Unknown;
break;
221 case CogsBin::Format::R8_UINT:
return Cogs::TextureFormat::R8_UINT;
break;
222 case CogsBin::Format::R8G8_UINT:
return Cogs::TextureFormat::R8G8_UINT;
break;
223 case CogsBin::Format::R8G8B8_UINT:
return Cogs::TextureFormat::R8G8B8_UINT;
break;
224 case CogsBin::Format::R8G8B8A8_UINT:
return Cogs::TextureFormat::R8G8B8A8_UINT;
break;
225 case CogsBin::Format::R16_UINT:
return Cogs::TextureFormat::R16_UINT;
break;
226 case CogsBin::Format::R16G16_UINT:
return Cogs::TextureFormat::R16G16_UINT;
break;
227 case CogsBin::Format::R16G16B16_UINT:
return Cogs::TextureFormat::R16G16B16_UINT;
break;
228 case CogsBin::Format::R16G16B16A16_UINT:
return Cogs::TextureFormat::R16G16B16A16_UINT;
break;
229 case CogsBin::Format::R32_UINT:
return Cogs::TextureFormat::R32_UINT;
break;
230 case CogsBin::Format::R32G32_UINT:
return Cogs::TextureFormat::R32G32_UINT;
break;
231 case CogsBin::Format::R32G32B32_UINT:
return Cogs::TextureFormat::R32G32B32_UINT;
break;
232 case CogsBin::Format::R32G32B32A32_UINT:
return Cogs::TextureFormat::R32G32B32A32_UINT;
break;
233 case CogsBin::Format::R8_SINT:
return Cogs::TextureFormat::R8_SINT;
break;
234 case CogsBin::Format::R8G8_SINT:
return Cogs::TextureFormat::R8G8_SINT;
break;
235 case CogsBin::Format::R8G8B8_SINT:
return Cogs::TextureFormat::R8G8B8_SINT;
break;
236 case CogsBin::Format::R8G8B8A8_SINT:
return Cogs::TextureFormat::R8G8B8A8_SINT;
break;
237 case CogsBin::Format::R16_SINT:
return Cogs::TextureFormat::R16_SINT;
break;
238 case CogsBin::Format::R16G16_SINT:
return Cogs::TextureFormat::R16G16_SINT;
break;
239 case CogsBin::Format::R16G16B16_SINT:
return Cogs::TextureFormat::R16G16B16_SINT;
break;
240 case CogsBin::Format::R16G16B16A16_SINT:
return Cogs::TextureFormat::R16G16B16A16_SINT;
break;
241 case CogsBin::Format::R32_SINT:
return Cogs::TextureFormat::R32_SINT;
break;
242 case CogsBin::Format::R32G32_SINT:
return Cogs::TextureFormat::R32G32_SINT;
break;
243 case CogsBin::Format::R32G32B32_SINT:
return Cogs::TextureFormat::R32G32B32_SINT;
break;
244 case CogsBin::Format::R32G32B32A32_SINT:
return Cogs::TextureFormat::R32G32B32A32_SINT;
break;
245 case CogsBin::Format::R16_FLOAT:
return Cogs::TextureFormat::R16_FLOAT;
break;
246 case CogsBin::Format::R16G16_FLOAT:
return Cogs::TextureFormat::R16G16_FLOAT;
break;
247 case CogsBin::Format::R16G16B16_FLOAT:
return Cogs::TextureFormat::R16G16B16_FLOAT;
break;
248 case CogsBin::Format::R16G16B16A16_FLOAT:
return Cogs::TextureFormat::R16G16B16A16_FLOAT;
break;
249 case CogsBin::Format::R32_FLOAT:
return Cogs::TextureFormat::R32_FLOAT;
break;
250 case CogsBin::Format::R32G32_FLOAT:
return Cogs::TextureFormat::R32G32_FLOAT;
break;
251 case CogsBin::Format::R32G32B32_FLOAT:
return Cogs::TextureFormat::R32G32B32_FLOAT;
break;
252 case CogsBin::Format::R32G32B32A32_FLOAT:
return Cogs::TextureFormat::R32G32B32A32_FLOAT;
break;
253 case CogsBin::Format::R64_FLOAT: assert(
false &&
"Illegal texture format");
break;
254 case CogsBin::Format::R64G64_FLOAT: assert(
false &&
"Illegal texture format");
break;
255 case CogsBin::Format::R64G64B64_FLOAT: assert(
false &&
"Illegal texture format");
break;
256 case CogsBin::Format::R64G65B64A64_FLOAT: assert(
false &&
"Illegal texture format");
break;
257 case CogsBin::Format::R8_UNORM:
return Cogs::TextureFormat::R8_UNORM;
break;
258 case CogsBin::Format::R8G8_UNORM:
return Cogs::TextureFormat::R8G8_UNORM;
break;
259 case CogsBin::Format::R8G8B8_UNORM:
return Cogs::TextureFormat::R8G8B8_UNORM;
break;
260 case CogsBin::Format::R8G8B8A8_UNORM:
return Cogs::TextureFormat::R8G8B8A8_UNORM;
break;
261 case CogsBin::Format::R16_UNORM:
return Cogs::TextureFormat::R16_UNORM;
break;
262 case CogsBin::Format::R16G16_UNORM:
return Cogs::TextureFormat::R16G16_UNORM;
break;
263 case CogsBin::Format::R16G16B16_UNORM:
return Cogs::TextureFormat::R16G16B16_UNORM;
break;
264 case CogsBin::Format::R16G16B16A16_UNORM:
return Cogs::TextureFormat::R16G16B16A16_UNORM;
break;
265 case CogsBin::Format::R8_SNORM:
return Cogs::TextureFormat::R8_SNORM;
break;
266 case CogsBin::Format::R8G8_SNORM:
return Cogs::TextureFormat::R8G8_SNORM;
break;
267 case CogsBin::Format::R8G8B8_SNORM:
return Cogs::TextureFormat::R8G8B8_SNORM;
break;
268 case CogsBin::Format::R8G8B8A8_SNORM:
return Cogs::TextureFormat::R8G8B8A8_SNORM;
break;
269 case CogsBin::Format::R16_SNORM:
return Cogs::TextureFormat::R16_SNORM;
break;
270 case CogsBin::Format::R16G16_SNORM:
return Cogs::TextureFormat::R16G16_SNORM;
break;
271 case CogsBin::Format::R16G16B16_SNORM:
return Cogs::TextureFormat::R16G16B16_SNORM;
break;
272 case CogsBin::Format::R16G16B16A16_SNORM:
return Cogs::TextureFormat::R16G16B16A16_SNORM;
break;
273 case CogsBin::Format::D16_UNORM:
return Cogs::TextureFormat::D16_UNORM;
break;
274 case CogsBin::Format::D24_UNORM:
return Cogs::TextureFormat::D24_UNORM;
break;
275 case CogsBin::Format::D24S8_UNORM:
return Cogs::TextureFormat::D24S8_UNORM;
break;
276 case CogsBin::Format::D32_FLOAT:
return Cogs::TextureFormat::D32_FLOAT;
break;
277 case CogsBin::Format::R32_TYPELESS:
return Cogs::TextureFormat::R32_TYPELESS;
break;
278 case CogsBin::Format::R16_TYPELESS:
return Cogs::TextureFormat::R16_TYPELESS;
break;
279 case CogsBin::Format::R8T:
return Cogs::TextureFormat::R8T;
break;
280 case CogsBin::Format::R8G8T:
return Cogs::TextureFormat::R8G8T;
break;
281 case CogsBin::Format::R8G8B8T:
return Cogs::TextureFormat::R8G8B8T;
break;
282 case CogsBin::Format::R8G8B8A8T:
return Cogs::TextureFormat::R8G8B8A8T;
break;
283 case CogsBin::Format::B8G8R8:
return Cogs::TextureFormat::B8G8R8;
break;
284 case CogsBin::Format::B8G8R8A8:
return Cogs::TextureFormat::B8G8R8A8;
break;
285 case CogsBin::Format::A8_UNORM:
return Cogs::TextureFormat::A8_UNORM;
break;
286 case CogsBin::Format::BC1_TYPELESS:
return Cogs::TextureFormat::BC1_TYPELESS;
break;
287 case CogsBin::Format::BC1_UNORM:
return Cogs::TextureFormat::BC1_UNORM;
break;
288 case CogsBin::Format::BC1_UNORM_SRGB:
return Cogs::TextureFormat::BC1_UNORM_SRGB;
break;
289 case CogsBin::Format::BC2_TYPELESS:
return Cogs::TextureFormat::BC2_TYPELESS;
break;
290 case CogsBin::Format::BC2_UNORM:
return Cogs::TextureFormat::BC2_UNORM;
break;
291 case CogsBin::Format::BC2_UNORM_SRGB:
return Cogs::TextureFormat::BC2_UNORM_SRGB;
break;
292 case CogsBin::Format::BC3_TYPELESS:
return Cogs::TextureFormat::BC3_TYPELESS;
break;
293 case CogsBin::Format::BC3_UNORM:
return Cogs::TextureFormat::BC3_UNORM;
break;
294 case CogsBin::Format::BC3_UNORM_SRGB:
return Cogs::TextureFormat::BC3_UNORM_SRGB;
break;
295 case CogsBin::Format::BC4_TYPELESS:
return Cogs::TextureFormat::BC4_TYPELESS;
break;
296 case CogsBin::Format::BC4_UNORM:
return Cogs::TextureFormat::BC4_UNORM;
break;
297 case CogsBin::Format::BC4_SNORM:
return Cogs::TextureFormat::BC4_SNORM;
break;
298 case CogsBin::Format::BC5_TYPELESS:
return Cogs::TextureFormat::BC5_TYPELESS;
break;
299 case CogsBin::Format::BC5_UNORM:
return Cogs::TextureFormat::BC5_UNORM;
break;
300 case CogsBin::Format::BC5_SNORM:
return Cogs::TextureFormat::BC5_SNORM;
break;
301 case CogsBin::Format::R8G8B8A8_UNORM_SRGB:
return Cogs::TextureFormat::R8G8B8A8_UNORM_SRGB;
break;
303 assert(
false &&
"Illegal format");
306 return Cogs::TextureFormat::Unknown;
309 Cogs::DataFormat decodeDataFormat(ReadContext& rctx, CogsBin::Format fmt)
311 if (rctx.version < 5) {
312 switch (
static_cast<CogsBin::DataFormatV4
>(fmt)) {
313 case CogsBin::DataFormatV4::Unknown:
return Cogs::DataFormat::Unknown;
314 case CogsBin::DataFormatV4::R8_UNORM:
return Cogs::DataFormat::R8_UNORM;
315 case CogsBin::DataFormatV4::R8G8_UNORM:
return Cogs::DataFormat::R8G8_UNORM;
316 case CogsBin::DataFormatV4::R8G8B8_UNORM:
return Cogs::DataFormat::R8G8B8_UNORM;
317 case CogsBin::DataFormatV4::R8G8B8A8_UNORM:
return Cogs::DataFormat::R8G8B8A8_UNORM;
318 case CogsBin::DataFormatV4::R16_UNORM:
return Cogs::DataFormat::R16_UNORM;
319 case CogsBin::DataFormatV4::R16G16_UNORM:
return Cogs::DataFormat::R16G16_UNORM;
320 case CogsBin::DataFormatV4::R16G16B16_UNORM:
return Cogs::DataFormat::R16G16B16_UNORM;
321 case CogsBin::DataFormatV4::R16G16B16A16_UNORM:
return Cogs::DataFormat::R16G16B16A16_UNORM;
322 case CogsBin::DataFormatV4::R8_SNORM:
return Cogs::DataFormat::R8_SNORM;
323 case CogsBin::DataFormatV4::R8G8_SNORM:
return Cogs::DataFormat::R8G8_SNORM;
324 case CogsBin::DataFormatV4::R8G8B8_SNORM:
return Cogs::DataFormat::R8G8B8_SNORM;
325 case CogsBin::DataFormatV4::R8G8B8A8_SNORM:
return Cogs::DataFormat::R8G8B8A8_SNORM;
326 case CogsBin::DataFormatV4::R16_SNORM:
return Cogs::DataFormat::R16_SNORM;
327 case CogsBin::DataFormatV4::R16G16_SNORM:
return Cogs::DataFormat::R16G16_SNORM;
328 case CogsBin::DataFormatV4::R16G16B16_SNORM:
return Cogs::DataFormat::R16G16B16_SNORM;
329 case CogsBin::DataFormatV4::R16G16B16A16_SNORM:
return Cogs::DataFormat::R16G16B16A16_SNORM;
330 case CogsBin::DataFormatV4::R8_UINT:
return Cogs::DataFormat::R8_UINT;
331 case CogsBin::DataFormatV4::R8G8_UINT:
return Cogs::DataFormat::R8G8_UINT;
332 case CogsBin::DataFormatV4::R8G8B8_UINT:
return Cogs::DataFormat::R8G8B8_UINT;
333 case CogsBin::DataFormatV4::R8G8B8A8_UINT:
return Cogs::DataFormat::R8G8B8A8_UINT;
334 case CogsBin::DataFormatV4::R16_UINT:
return Cogs::DataFormat::R16_UINT;
335 case CogsBin::DataFormatV4::R16G16_UINT:
return Cogs::DataFormat::R16G16_UINT;
336 case CogsBin::DataFormatV4::R16G16B16_UINT:
return Cogs::DataFormat::R16G16B16_UINT;
337 case CogsBin::DataFormatV4::R16G16B16A16_UINT:
return Cogs::DataFormat::R16G16B16A16_UINT;
338 case CogsBin::DataFormatV4::R32_UINT:
return Cogs::DataFormat::R32_UINT;
339 case CogsBin::DataFormatV4::R32G32_UINT:
return Cogs::DataFormat::R32G32_UINT;
340 case CogsBin::DataFormatV4::R32G32B32_UINT:
return Cogs::DataFormat::R32G32B32_UINT;
341 case CogsBin::DataFormatV4::R32G32B32A32_UINT:
return Cogs::DataFormat::R32G32B32A32_UINT;
342 case CogsBin::DataFormatV4::R8_SINT:
return Cogs::DataFormat::R8_SINT;
343 case CogsBin::DataFormatV4::R8G8_SINT:
return Cogs::DataFormat::R8G8_SINT;
344 case CogsBin::DataFormatV4::R8G8B8_SINT:
return Cogs::DataFormat::R8G8B8_SINT;
345 case CogsBin::DataFormatV4::R8G8B8A8_SINT:
return Cogs::DataFormat::R8G8B8A8_SINT;
346 case CogsBin::DataFormatV4::R16_SINT:
return Cogs::DataFormat::R16_SINT;
347 case CogsBin::DataFormatV4::R16G16_SINT:
return Cogs::DataFormat::R16G16_SINT;
348 case CogsBin::DataFormatV4::R16G16B16_SINT:
return Cogs::DataFormat::R16G16B16_SINT;
349 case CogsBin::DataFormatV4::R16G16B16A16_SINT:
return Cogs::DataFormat::R16G16B16A16_SINT;
350 case CogsBin::DataFormatV4::R32_SINT:
return Cogs::DataFormat::R32_SINT;
351 case CogsBin::DataFormatV4::R32G32_SINT:
return Cogs::DataFormat::R32G32_SINT;
352 case CogsBin::DataFormatV4::R32G32B32_SINT:
return Cogs::DataFormat::R32G32B32_SINT;
353 case CogsBin::DataFormatV4::R32G32B32A32_SINT:
return Cogs::DataFormat::R32G32B32A32_SINT;
354 case CogsBin::DataFormatV4::R16_FLOAT:
return Cogs::DataFormat::R16_FLOAT;
355 case CogsBin::DataFormatV4::R16G16_FLOAT:
return Cogs::DataFormat::R16G16_FLOAT;
356 case CogsBin::DataFormatV4::R16G16B16_FLOAT:
return Cogs::DataFormat::R16G16B16_FLOAT;
357 case CogsBin::DataFormatV4::R16G16B16A16_FLOAT:
return Cogs::DataFormat::R16G16B16A16_FLOAT;
358 case CogsBin::DataFormatV4::R32_FLOAT:
return Cogs::DataFormat::R32_FLOAT;
359 case CogsBin::DataFormatV4::R32G32_FLOAT:
return Cogs::DataFormat::R32G32_FLOAT;
360 case CogsBin::DataFormatV4::R32G32B32_FLOAT:
return Cogs::DataFormat::R32G32B32_FLOAT;
361 case CogsBin::DataFormatV4::R32G32B32A32_FLOAT:
return Cogs::DataFormat::R32G32B32A32_FLOAT;
362 case CogsBin::DataFormatV4::D16_UNORM:
return Cogs::DataFormat::D16_UNORM;
363 case CogsBin::DataFormatV4::D24_UNORM:
return Cogs::DataFormat::D24_UNORM;
364 case CogsBin::DataFormatV4::D24S8_UNORM:
return Cogs::DataFormat::D24S8_UNORM;
365 case CogsBin::DataFormatV4::D32_FLOAT:
return Cogs::DataFormat::D32_FLOAT;
366 case CogsBin::DataFormatV4::R32_TYPELESS:
return Cogs::DataFormat::R32_TYPELESS;
367 case CogsBin::DataFormatV4::R16_TYPELESS:
return Cogs::DataFormat::R16_TYPELESS;
368 case CogsBin::DataFormatV4::R8T:
return Cogs::DataFormat::R8T;
369 case CogsBin::DataFormatV4::R8G8T:
return Cogs::DataFormat::R8G8T;
370 case CogsBin::DataFormatV4::R8G8B8T:
return Cogs::DataFormat::R8G8B8T;
371 case CogsBin::DataFormatV4::R8G8B8A8T:
return Cogs::DataFormat::R8G8B8A8T;
372 case CogsBin::DataFormatV4::B8G8R8:
return Cogs::DataFormat::B8G8R8;
373 case CogsBin::DataFormatV4::B8G8R8A8:
return Cogs::DataFormat::B8G8R8A8;
374 case CogsBin::DataFormatV4::A8_UNORM:
return Cogs::DataFormat::A8_UNORM;
375 case CogsBin::DataFormatV4::BC1_TYPELESS:
return Cogs::DataFormat::BC1_TYPELESS;
376 case CogsBin::DataFormatV4::BC1_UNORM:
return Cogs::DataFormat::BC1_UNORM;
377 case CogsBin::DataFormatV4::BC1_UNORM_SRGB:
return Cogs::DataFormat::BC1_UNORM_SRGB;
378 case CogsBin::DataFormatV4::BC2_TYPELESS:
return Cogs::DataFormat::BC2_TYPELESS;
379 case CogsBin::DataFormatV4::BC2_UNORM:
return Cogs::DataFormat::BC2_UNORM;
380 case CogsBin::DataFormatV4::BC2_UNORM_SRGB:
return Cogs::DataFormat::BC2_UNORM_SRGB;
381 case CogsBin::DataFormatV4::BC3_TYPELESS:
return Cogs::DataFormat::BC3_TYPELESS;
382 case CogsBin::DataFormatV4::BC3_UNORM:
return Cogs::DataFormat::BC3_UNORM;
383 case CogsBin::DataFormatV4::BC3_UNORM_SRGB:
return Cogs::DataFormat::BC3_UNORM_SRGB;
384 case CogsBin::DataFormatV4::BC4_TYPELESS:
return Cogs::DataFormat::BC4_TYPELESS;
385 case CogsBin::DataFormatV4::BC4_UNORM:
return Cogs::DataFormat::BC4_UNORM;
386 case CogsBin::DataFormatV4::BC4_SNORM:
return Cogs::DataFormat::BC4_SNORM;
387 case CogsBin::DataFormatV4::BC5_TYPELESS:
return Cogs::DataFormat::BC5_TYPELESS;
388 case CogsBin::DataFormatV4::BC5_UNORM:
return Cogs::DataFormat::BC5_UNORM;
389 case CogsBin::DataFormatV4::BC5_SNORM:
return Cogs::DataFormat::BC5_SNORM;
390 case CogsBin::DataFormatV4::R8G8B8_UNORM_SRGB:
return Cogs::DataFormat::R8G8B8_UNORM_SRGB;
391 case CogsBin::DataFormatV4::R8G8B8A8_UNORM_SRGB:
return Cogs::DataFormat::R8G8B8A8_UNORM_SRGB;
392 case CogsBin::DataFormatV4::R10G10B10A2_TYPELESS:
return Cogs::DataFormat::R10G10B10A2_TYPELESS;
393 case CogsBin::DataFormatV4::R10G10B10A2_UNORM:
return Cogs::DataFormat::R10G10B10A2_UNORM;
394 case CogsBin::DataFormatV4::R10G10B10A2_UINT:
return Cogs::DataFormat::R10G10B10A2_UINT;
395 case CogsBin::DataFormatV4::R11G11B10_FLOAT:
return Cogs::DataFormat::R11G11B10_FLOAT;
396 case CogsBin::DataFormatV4::R5G6B5_UNORM:
return Cogs::DataFormat::R5G6B5_UNORM;
397 case CogsBin::DataFormatV4::R5G5B5A1_UNORM:
return Cogs::DataFormat::R5G5B5A1_UNORM;
398 case CogsBin::DataFormatV4::R4G4B4A4_UNORM:
return Cogs::DataFormat::R4G4B4A4_UNORM;
399 case CogsBin::DataFormatV4::R9G9B9E5_FLOAT:
return Cogs::DataFormat::R9G9B9E5_FLOAT;
400 case CogsBin::DataFormatV4::MAT4X4_FLOAT:
return Cogs::DataFormat::MAT4X4_FLOAT;
401 default:
return Cogs::DataFormat::Unknown;
405 switch (
static_cast<CogsBin::DataFormatV5
>(fmt)) {
406 case CogsBin::DataFormatV5::Unknown:
return Cogs::DataFormat::Unknown;
407 case CogsBin::DataFormatV5::R8_UNORM:
return Cogs::DataFormat::R8_UNORM;
408 case CogsBin::DataFormatV5::R8G8_UNORM:
return Cogs::DataFormat::R8G8_UNORM;
409 case CogsBin::DataFormatV5::R8G8B8_UNORM:
return Cogs::DataFormat::R8G8B8_UNORM;
410 case CogsBin::DataFormatV5::R8G8B8A8_UNORM:
return Cogs::DataFormat::R8G8B8A8_UNORM;
411 case CogsBin::DataFormatV5::R16_UNORM:
return Cogs::DataFormat::R16_UNORM;
412 case CogsBin::DataFormatV5::R16G16_UNORM:
return Cogs::DataFormat::R16G16_UNORM;
413 case CogsBin::DataFormatV5::R16G16B16_UNORM:
return Cogs::DataFormat::R16G16B16_UNORM;
414 case CogsBin::DataFormatV5::R16G16B16A16_UNORM:
return Cogs::DataFormat::R16G16B16A16_UNORM;
415 case CogsBin::DataFormatV5::R8_SNORM:
return Cogs::DataFormat::R8_SNORM;
416 case CogsBin::DataFormatV5::R8G8_SNORM:
return Cogs::DataFormat::R8G8_SNORM;
417 case CogsBin::DataFormatV5::R8G8B8_SNORM:
return Cogs::DataFormat::R8G8B8_SNORM;
418 case CogsBin::DataFormatV5::R8G8B8A8_SNORM:
return Cogs::DataFormat::R8G8B8A8_SNORM;
419 case CogsBin::DataFormatV5::R16_SNORM:
return Cogs::DataFormat::R16_SNORM;
420 case CogsBin::DataFormatV5::R16G16_SNORM:
return Cogs::DataFormat::R16G16_SNORM;
421 case CogsBin::DataFormatV5::R16G16B16_SNORM:
return Cogs::DataFormat::R16G16B16_SNORM;
422 case CogsBin::DataFormatV5::R16G16B16A16_SNORM:
return Cogs::DataFormat::R16G16B16A16_SNORM;
423 case CogsBin::DataFormatV5::R8_UINT:
return Cogs::DataFormat::R8_UINT;
424 case CogsBin::DataFormatV5::R8G8_UINT:
return Cogs::DataFormat::R8G8_UINT;
425 case CogsBin::DataFormatV5::R8G8B8_UINT:
return Cogs::DataFormat::R8G8B8_UINT;
426 case CogsBin::DataFormatV5::R8G8B8A8_UINT:
return Cogs::DataFormat::R8G8B8A8_UINT;
427 case CogsBin::DataFormatV5::R16_UINT:
return Cogs::DataFormat::R16_UINT;
428 case CogsBin::DataFormatV5::R16G16_UINT:
return Cogs::DataFormat::R16G16_UINT;
429 case CogsBin::DataFormatV5::R16G16B16_UINT:
return Cogs::DataFormat::R16G16B16_UINT;
430 case CogsBin::DataFormatV5::R16G16B16A16_UINT:
return Cogs::DataFormat::R16G16B16A16_UINT;
431 case CogsBin::DataFormatV5::R32_UINT:
return Cogs::DataFormat::R32_UINT;
432 case CogsBin::DataFormatV5::R32G32_UINT:
return Cogs::DataFormat::R32G32_UINT;
433 case CogsBin::DataFormatV5::R32G32B32_UINT:
return Cogs::DataFormat::R32G32B32_UINT;
434 case CogsBin::DataFormatV5::R32G32B32A32_UINT:
return Cogs::DataFormat::R32G32B32A32_UINT;
435 case CogsBin::DataFormatV5::R8_SINT:
return Cogs::DataFormat::R8_SINT;
436 case CogsBin::DataFormatV5::R8G8_SINT:
return Cogs::DataFormat::R8G8_SINT;
437 case CogsBin::DataFormatV5::R8G8B8_SINT:
return Cogs::DataFormat::R8G8B8_SINT;
438 case CogsBin::DataFormatV5::R8G8B8A8_SINT:
return Cogs::DataFormat::R8G8B8A8_SINT;
439 case CogsBin::DataFormatV5::R16_SINT:
return Cogs::DataFormat::R16_SINT;
440 case CogsBin::DataFormatV5::R16G16_SINT:
return Cogs::DataFormat::R16G16_SINT;
441 case CogsBin::DataFormatV5::R16G16B16_SINT:
return Cogs::DataFormat::R16G16B16_SINT;
442 case CogsBin::DataFormatV5::R16G16B16A16_SINT:
return Cogs::DataFormat::R16G16B16A16_SINT;
443 case CogsBin::DataFormatV5::R32_SINT:
return Cogs::DataFormat::R32_SINT;
444 case CogsBin::DataFormatV5::R32G32_SINT:
return Cogs::DataFormat::R32G32_SINT;
445 case CogsBin::DataFormatV5::R32G32B32_SINT:
return Cogs::DataFormat::R32G32B32_SINT;
446 case CogsBin::DataFormatV5::R32G32B32A32_SINT:
return Cogs::DataFormat::R32G32B32A32_SINT;
447 case CogsBin::DataFormatV5::R16_FLOAT:
return Cogs::DataFormat::R16_FLOAT;
448 case CogsBin::DataFormatV5::R16G16_FLOAT:
return Cogs::DataFormat::R16G16_FLOAT;
449 case CogsBin::DataFormatV5::R16G16B16_FLOAT:
return Cogs::DataFormat::R16G16B16_FLOAT;
450 case CogsBin::DataFormatV5::R16G16B16A16_FLOAT:
return Cogs::DataFormat::R16G16B16A16_FLOAT;
451 case CogsBin::DataFormatV5::R32_FLOAT:
return Cogs::DataFormat::R32_FLOAT;
452 case CogsBin::DataFormatV5::R32G32_FLOAT:
return Cogs::DataFormat::R32G32_FLOAT;
453 case CogsBin::DataFormatV5::R32G32B32_FLOAT:
return Cogs::DataFormat::R32G32B32_FLOAT;
454 case CogsBin::DataFormatV5::R32G32B32A32_FLOAT:
return Cogs::DataFormat::R32G32B32A32_FLOAT;
455 case CogsBin::DataFormatV5::D16_UNORM:
return Cogs::DataFormat::D16_UNORM;
456 case CogsBin::DataFormatV5::D24_UNORM:
return Cogs::DataFormat::D24_UNORM;
457 case CogsBin::DataFormatV5::D24S8_UNORM:
return Cogs::DataFormat::D24S8_UNORM;
458 case CogsBin::DataFormatV5::D32_FLOAT:
return Cogs::DataFormat::D32_FLOAT;
459 case CogsBin::DataFormatV5::R32_TYPELESS:
return Cogs::DataFormat::R32_TYPELESS;
460 case CogsBin::DataFormatV5::R16_TYPELESS:
return Cogs::DataFormat::R16_TYPELESS;
461 case CogsBin::DataFormatV5::R8T:
return Cogs::DataFormat::R8T;
462 case CogsBin::DataFormatV5::R8G8T:
return Cogs::DataFormat::R8G8T;
463 case CogsBin::DataFormatV5::R8G8B8T:
return Cogs::DataFormat::R8G8B8T;
464 case CogsBin::DataFormatV5::R8G8B8A8T:
return Cogs::DataFormat::R8G8B8A8T;
465 case CogsBin::DataFormatV5::B8G8R8:
return Cogs::DataFormat::B8G8R8;
466 case CogsBin::DataFormatV5::B8G8R8A8:
return Cogs::DataFormat::B8G8R8A8;
467 case CogsBin::DataFormatV5::A8_UNORM:
return Cogs::DataFormat::A8_UNORM;
468 case CogsBin::DataFormatV5::BC1_TYPELESS:
return Cogs::DataFormat::BC1_TYPELESS;
469 case CogsBin::DataFormatV5::BC1_UNORM:
return Cogs::DataFormat::BC1_UNORM;
470 case CogsBin::DataFormatV5::BC1_UNORM_SRGB:
return Cogs::DataFormat::BC1_UNORM_SRGB;
471 case CogsBin::DataFormatV5::BC2_TYPELESS:
return Cogs::DataFormat::BC2_TYPELESS;
472 case CogsBin::DataFormatV5::BC2_UNORM:
return Cogs::DataFormat::BC2_UNORM;
473 case CogsBin::DataFormatV5::BC2_UNORM_SRGB:
return Cogs::DataFormat::BC2_UNORM_SRGB;
474 case CogsBin::DataFormatV5::BC3_TYPELESS:
return Cogs::DataFormat::BC3_TYPELESS;
475 case CogsBin::DataFormatV5::BC3_UNORM:
return Cogs::DataFormat::BC3_UNORM;
476 case CogsBin::DataFormatV5::BC3_UNORM_SRGB:
return Cogs::DataFormat::BC3_UNORM_SRGB;
477 case CogsBin::DataFormatV5::BC4_TYPELESS:
return Cogs::DataFormat::BC4_TYPELESS;
478 case CogsBin::DataFormatV5::BC4_UNORM:
return Cogs::DataFormat::BC4_UNORM;
479 case CogsBin::DataFormatV5::BC4_SNORM:
return Cogs::DataFormat::BC4_SNORM;
480 case CogsBin::DataFormatV5::BC5_TYPELESS:
return Cogs::DataFormat::BC5_TYPELESS;
481 case CogsBin::DataFormatV5::BC5_UNORM:
return Cogs::DataFormat::BC5_UNORM;
482 case CogsBin::DataFormatV5::BC5_SNORM:
return Cogs::DataFormat::BC5_SNORM;
483 case CogsBin::DataFormatV5::BC6H_SIGNED_FLOAT_RGB:
return Cogs::DataFormat::BC6H_SIGNED_FLOAT_RGB;
484 case CogsBin::DataFormatV5::BC6H_UNSIGNED_FLOAT_RGB:
return Cogs::DataFormat::BC6H_UNSIGNED_FLOAT_RGB;
485 case CogsBin::DataFormatV5::BC7_UNORM_RGBA:
return Cogs::DataFormat::BC7_UNORM_RGBA;
486 case CogsBin::DataFormatV5::BC7_UNORM_SRGBA:
return Cogs::DataFormat::BC7_UNORM_SRGBA;
487 case CogsBin::DataFormatV5::PVRTC1_2BPP_UNORM_RGB:
return Cogs::DataFormat::PVRTC1_2BPP_UNORM_RGB;
488 case CogsBin::DataFormatV5::PVRTC1_4BPP_UNORM_RGB:
return Cogs::DataFormat::PVRTC1_4BPP_UNORM_RGB;
489 case CogsBin::DataFormatV5::PVRTC1_2BPP_UNORM_RGBA:
return Cogs::DataFormat::PVRTC1_2BPP_UNORM_RGBA;
490 case CogsBin::DataFormatV5::PVRTC1_4BPP_UNORM_RGBA:
return Cogs::DataFormat::PVRTC1_4BPP_UNORM_RGBA;
491 case CogsBin::DataFormatV5::EAC_BLOCK8_UNSIGNED_FLOAT_R:
return Cogs::DataFormat::EAC_BLOCK8_UNSIGNED_FLOAT_R;
492 case CogsBin::DataFormatV5::EAC_BLOCK8_SIGNED_FLOAT_R:
return Cogs::DataFormat::EAC_BLOCK8_SIGNED_FLOAT_R;
493 case CogsBin::DataFormatV5::EAC_BLOCK16_UNSIGNED_FLOAT_RG:
return Cogs::DataFormat::EAC_BLOCK16_UNSIGNED_FLOAT_RG;
494 case CogsBin::DataFormatV5::EAC_BLOCK16_SIGNED_FLOAT_RG:
return Cogs::DataFormat::EAC_BLOCK16_SIGNED_FLOAT_RG;
495 case CogsBin::DataFormatV5::ETC2_BLOCK8_UNORM_RGB:
return Cogs::DataFormat::ETC2_BLOCK8_UNORM_RGB;
496 case CogsBin::DataFormatV5::ETC2_BLOCK8_UNORM_SRGB:
return Cogs::DataFormat::ETC2_BLOCK8_UNORM_SRGB;
497 case CogsBin::DataFormatV5::ETC2_BLOCK16_UNORM_RGBA:
return Cogs::DataFormat::ETC2_BLOCK16_UNORM_RGBA;
498 case CogsBin::DataFormatV5::ETC2_BLOCK16_UNORM_SRGBA:
return Cogs::DataFormat::ETC2_BLOCK16_UNORM_SRGBA;
499 case CogsBin::DataFormatV5::ASTC_4x4_UNORM_RGBA:
return Cogs::DataFormat::ASTC_4x4_UNORM_RGBA;
500 case CogsBin::DataFormatV5::ASTC_5x4_UNORM_RGBA:
return Cogs::DataFormat::ASTC_5x4_UNORM_RGBA;
501 case CogsBin::DataFormatV5::ASTC_5x5_UNORM_RGBA:
return Cogs::DataFormat::ASTC_5x5_UNORM_RGBA;
502 case CogsBin::DataFormatV5::ASTC_6x5_UNORM_RGBA:
return Cogs::DataFormat::ASTC_6x5_UNORM_RGBA;
503 case CogsBin::DataFormatV5::ASTC_6x6_UNORM_RGBA:
return Cogs::DataFormat::ASTC_6x6_UNORM_RGBA;
504 case CogsBin::DataFormatV5::ASTC_8x5_UNORM_RGBA:
return Cogs::DataFormat::ASTC_8x5_UNORM_RGBA;
505 case CogsBin::DataFormatV5::ASTC_8x6_UNORM_RGBA:
return Cogs::DataFormat::ASTC_8x6_UNORM_RGBA;
506 case CogsBin::DataFormatV5::ASTC_8x8_UNORM_RGBA:
return Cogs::DataFormat::ASTC_8x8_UNORM_RGBA;
507 case CogsBin::DataFormatV5::ASTC_10x5_UNORM_RGBA:
return Cogs::DataFormat::ASTC_10x5_UNORM_RGBA;
508 case CogsBin::DataFormatV5::ASTC_10x6_UNORM_RGBA:
return Cogs::DataFormat::ASTC_10x6_UNORM_RGBA;
509 case CogsBin::DataFormatV5::ASTC_10x8_UNORM_RGBA:
return Cogs::DataFormat::ASTC_10x8_UNORM_RGBA;
510 case CogsBin::DataFormatV5::ASTC_10x10_UNORM_RGBA:
return Cogs::DataFormat::ASTC_10x10_UNORM_RGBA;
511 case CogsBin::DataFormatV5::ASTC_12x10_UNORM_RGBA:
return Cogs::DataFormat::ASTC_12x10_UNORM_RGBA;
512 case CogsBin::DataFormatV5::ASTC_12x12_UNORM_RGBA:
return Cogs::DataFormat::ASTC_12x12_UNORM_RGBA;
513 case CogsBin::DataFormatV5::ASTC_4x4_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_4x4_UNORM_SRGBA;
514 case CogsBin::DataFormatV5::ASTC_5x4_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_5x4_UNORM_SRGBA;
515 case CogsBin::DataFormatV5::ASTC_5x5_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_5x5_UNORM_SRGBA;
516 case CogsBin::DataFormatV5::ASTC_6x5_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_6x5_UNORM_SRGBA;
517 case CogsBin::DataFormatV5::ASTC_6x6_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_6x6_UNORM_SRGBA;
518 case CogsBin::DataFormatV5::ASTC_8x5_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_8x5_UNORM_SRGBA;
519 case CogsBin::DataFormatV5::ASTC_8x6_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_8x6_UNORM_SRGBA;
520 case CogsBin::DataFormatV5::ASTC_8x8_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_8x8_UNORM_SRGBA;
521 case CogsBin::DataFormatV5::ASTC_10x5_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_10x5_UNORM_SRGBA;
522 case CogsBin::DataFormatV5::ASTC_10x6_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_10x6_UNORM_SRGBA;
523 case CogsBin::DataFormatV5::ASTC_10x8_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_10x8_UNORM_SRGBA;
524 case CogsBin::DataFormatV5::ASTC_10x10_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_10x10_UNORM_SRGBA;
525 case CogsBin::DataFormatV5::ASTC_12x10_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_12x10_UNORM_SRGBA;
526 case CogsBin::DataFormatV5::ASTC_12x12_UNORM_SRGBA:
return Cogs::DataFormat::ASTC_12x12_UNORM_SRGBA;
527 case CogsBin::DataFormatV5::R8G8B8_UNORM_SRGB:
return Cogs::DataFormat::R8G8B8_UNORM_SRGB;
528 case CogsBin::DataFormatV5::R8G8B8A8_UNORM_SRGB:
return Cogs::DataFormat::R8G8B8A8_UNORM_SRGB;
529 case CogsBin::DataFormatV5::R10G10B10A2_TYPELESS:
return Cogs::DataFormat::R10G10B10A2_TYPELESS;
530 case CogsBin::DataFormatV5::R10G10B10A2_UNORM:
return Cogs::DataFormat::R10G10B10A2_UNORM;
531 case CogsBin::DataFormatV5::R10G10B10A2_UINT:
return Cogs::DataFormat::R10G10B10A2_UINT;
532 case CogsBin::DataFormatV5::R11G11B10_FLOAT:
return Cogs::DataFormat::R11G11B10_FLOAT;
533 case CogsBin::DataFormatV5::R5G6B5_UNORM:
return Cogs::DataFormat::R5G6B5_UNORM;
534 case CogsBin::DataFormatV5::R5G5B5A1_UNORM:
return Cogs::DataFormat::R5G5B5A1_UNORM;
535 case CogsBin::DataFormatV5::R4G4B4A4_UNORM:
return Cogs::DataFormat::R4G4B4A4_UNORM;
536 case CogsBin::DataFormatV5::R9G9B9E5_FLOAT:
return Cogs::DataFormat::R9G9B9E5_FLOAT;
537 case CogsBin::DataFormatV5::MAT4X4_FLOAT:
return Cogs::DataFormat::MAT4X4_FLOAT;
538 default:
return Cogs::DataFormat::Unknown;
544 Cogs::ResourceDimensions getTextureDimensions(CogsBin::TextureDimensions dimensions) {
545 switch (dimensions) {
546 case CogsBin::TextureDimensions::Unknown:
return Cogs::ResourceDimensions::Unknown;
break;
547 case CogsBin::TextureDimensions::Buffer:
return Cogs::ResourceDimensions::Buffer;
break;
548 case CogsBin::TextureDimensions::Texture1D:
return Cogs::ResourceDimensions::Texture1D;
break;
549 case CogsBin::TextureDimensions::Texture1DArray:
return Cogs::ResourceDimensions::Texture1DArray;
break;
550 case CogsBin::TextureDimensions::Texture2D:
return Cogs::ResourceDimensions::Texture2D;
break;
551 case CogsBin::TextureDimensions::Texture2DArray:
return Cogs::ResourceDimensions::Texture2DArray;
break;
552 case CogsBin::TextureDimensions::Texture2DMS:
return Cogs::ResourceDimensions::Texture2DMS;
break;
553 case CogsBin::TextureDimensions::Texture2DMSArray:
return Cogs::ResourceDimensions::Texture2DMSArray;
break;
554 case CogsBin::TextureDimensions::Texture3D:
return Cogs::ResourceDimensions::Texture3D;
break;
555 case CogsBin::TextureDimensions::Texture3DArray:
return Cogs::ResourceDimensions::Texture3DArray;
break;
556 case CogsBin::TextureDimensions::TextureCube:
return Cogs::ResourceDimensions::TextureCube;
break;
557 case CogsBin::TextureDimensions::TextureCubeArray:
return Cogs::ResourceDimensions::TextureCubeArray;
break;
559 assert(
false &&
"Illegal texture dimension");
562 return Cogs::ResourceDimensions::Unknown;
567 switch (addressMode) {
573 assert(
false &&
"Illegal texture addressing mode");
581 switch (filterMode) {
587 assert(
false &&
"Illegal texture addressing mode");
594 const auto * attributes = rctx.vertexAttributes.base + firstAttribute;
596 std::vector<Cogs::VertexElement> elements;
597 elements.resize(attributeCount);
598 for (
unsigned i = 0; i < attributeCount; i++) {
599 const auto & attribute = attributes[i];
601 auto & element = elements[i];
602 element.offset = attribute.offset;
603 element.format = decodeDataFormat(rctx, attribute.format);
605 switch (attribute.semantic) {
614 LOG_ERROR(logger,
"Illegal vertex element semantic %u",
unsigned(attribute.semantic));
617 element.semanticIndex = attribute.semanticIndex;
619 element.instanceStep = attribute.instanceStepRate;
622 return Cogs::VertexFormats::createVertexFormat(elements.data(), elements.size());
625 const uint8_t* resolveDataOffset(ReadContext& rctx, uint64_t offset, uint32_t size)
627 const auto sectionIx = uint16_t(offset >> 48);
628 const auto * section = sectionPointer(rctx, sectionIx);
629 if (section ==
nullptr) {
630 LOG_ERROR(logger,
"Failed to retrieve data section %u",
unsigned(sectionIx));
631 rctx.success =
false;
634 const auto sectionOffset = size_t(offset & 0xFFFFFFFFFFFFull);
635 if (rctx.sectionInfo[sectionIx].uncompressedSize < sectionOffset + size) {
636 LOG_ERROR(logger,
"Stream source offset %zX size %u is outside section memory range.", sectionOffset, size);
637 rctx.success =
false;
640 return section + sectionOffset;
643 template<
typename D,
typename S>
644 void widenAndCopy(std::span<D>& dstSpan,
const S* src, uint32_t count)
646 auto * dst = dstSpan.data();
649 constexpr auto notzero = std::numeric_limits<S>::max();
650 for (uint32_t i = 0; i < count; i++) {
651 const auto v = *src++;
652 if (v == notzero) *dst++ = ~D(0);
657 void populateMesh(ReadContext& rctx,
MeshHandle handle, uint32_t index)
659 const auto & srcMesh = rctx.meshes[index];
660 auto dstMesh = rctx.context->meshManager->lock(handle);
662 if (isValidIndex(srcMesh.name)) {
663 dstMesh->setName(getString(rctx, srcMesh.name));
665 if (isValidIndex(srcMesh.boundingBox)) {
666 dstMesh->setBounds(getBoundingBox(rctx, srcMesh.boundingBox));
668 if ((srcMesh.flags & CogsBin::MeshFlags::Clockwise) != 0) {
671 if ((srcMesh.flags & CogsBin::MeshFlags::Skinned) != 0) {
672 dstMesh->setMeshFlag(MeshFlags::Skinned);
675 dstMesh->primitiveType = translatePrimitiveType(rctx, srcMesh.primitiveType);
677 dstMesh->streams.resize(srcMesh.streamCount);
678 for (
size_t i = 0; i < srcMesh.streamCount; i++) {
679 assert(srcMesh.firstStream + i < rctx.vertexStreams.count);
680 const auto & srcStream = rctx.vertexStreams[srcMesh.firstStream + i];
682 auto & dstStream = dstMesh->streams[i];
685 Cogs::LockGuard lock(rctx.buffersMutex);
686 assert(srcStream.buffer < rctx.buffers.count);
688 if (rctx.bufferCache[srcStream.buffer]) {
689 dstStream.buffer = rctx.bufferCache[srcStream.buffer];
691 auto & dstBuffer = rctx.bufferCache[srcStream.buffer] = rctx.context->bufferManager->create();
692 dstStream.buffer = dstBuffer;
694 const auto & srcBuffer = rctx.buffers[srcStream.buffer];
695 const auto * srcData = resolveDataOffset(rctx, srcBuffer.sectionOffset, srcBuffer.size);
697 dstBuffer->reset(srcBuffer.size, rctx.context->memory->resourceAllocator);
698 std::memcpy(dstBuffer->data(), srcData, srcBuffer.size);
700 if ((srcBuffer.flags & CogsBin::BufferContentFlags::VertexData) != 0) {
704 if ((srcBuffer.flags & CogsBin::BufferContentFlags::IndexData) != 0) {
710 dstStream.numElements = srcStream.count;
712 dstStream.stride = srcStream.stride;
713 dstStream.offset = srcStream.offset;
715 dstMesh->streamIndexes[dstStream.type] = uint8_t(i);
716 dstMesh->streamsUpdated |=
Mesh::toFlag(dstStream.type);
719 if (srcStream.vertexDataType < VertexDataType::LastVertexType) {
720 dstStream.format = isValidIndex(srcStream.firstAttribute)
721 ? getVertexFormat(rctx, srcStream.firstAttribute, srcStream.attributeCount)
724 if (!dstStream.format) {
725 LOG_ERROR(logger,
"Stream %zu has illegal format", i);
729 if (!dstMesh->isIndexed()) {
730 switch (dstStream.type) {
731 case VertexDataType::Positions:
732 case VertexDataType::Interleaved0:
733 case VertexDataType::Interleaved1:
734 dstMesh->setCount(srcStream.count);
740 }
else if (srcStream.vertexDataType == VertexDataType::Indexes) {
741 dstMesh->setCount(srcStream.count);
744 }
else if (srcStream.vertexDataType == VertexDataType::SubMeshes) {
745 dstMesh->submeshCount = (uint16_t)srcStream.count;
754 if constexpr (
sizeof(T) <=
sizeof(uint32_t)) {
755 return *(
const T*)(&prop.value);
758 if (prop.value < rctx.propData.count) {
759 return *(
const T*)(rctx.propData.base + prop.value);
762 LOG_ERROR(logger,
"Illegal property data offset %u", prop.value);
769 TextureHandle populateEmbeddedTexture(ReadContext& rctx, uint32_t textureIx)
771 assert(textureIx < rctx.embeddedTextures.count);
772 if (
auto handle = rctx.textureCache[textureIx];
HandleIsValid(handle)) {
775 const auto & tex = rctx.embeddedTextures[textureIx];
777 assert(tex.buffer < rctx.buffers.count);
778 const auto & srcBuffer = rctx.buffers[tex.buffer];
779 const auto * bufferData = resolveDataOffset(rctx, srcBuffer.sectionOffset, srcBuffer.size) + tex.offset;
781 TextureLoadInfo * loadInfo = rctx.context->textureManager->createLoadInfo();
783 loadInfo->
resourceId = (uint32_t)NoResourceId;
785 if (isValidIndex(tex.name)) {
786 loadInfo->
resourceName = getString(rctx, tex.name).to_string();
788 loadInfo->
resourceData.assign(bufferData, bufferData + tex.size);
791 loadInfo->format = getTextureFormat(rctx, tex.format);
792 loadInfo->target = getTextureDimensions(tex.dimension);
793 loadInfo->width =
static_cast<int>(tex.width);
794 loadInfo->height =
static_cast<int>(tex.height);
795 loadInfo->depth =
static_cast<int>(tex.depth);
796 loadInfo->stride = 0;
801 auto handle = rctx.context->textureManager->loadTexture(loadInfo);
803 rctx.textureCache[textureIx] = handle;
810 const auto & srcMaterialInstance = rctx.materialInstances[materialInstanceIx];
811 if (!isValidIndex(srcMaterialInstance.material)) {
812 LOG_ERROR(logger,
"Material instance without material.");
813 rctx.success =
false;
817 auto materialName = getString(rctx, srcMaterialInstance.material);
818 if (materialName.empty()) {
819 LOG_ERROR(logger,
"Writer should not include empty strings.");
820 rctx.success =
false;
824 auto materialTemplate = rctx.context->materialManager->getMaterial(materialName);
825 if (!materialTemplate) {
826 LOG_ERROR(logger,
"Invalid material template %.*s", StringViewFormat(materialName));
827 rctx.success =
false;
832 auto material = rctx.context->materialInstanceManager->createMaterialInstance(materialTemplate);
834 if (isValidIndex(srcMaterialInstance.permutation)) {
835 material->setPermutation(getString(rctx, srcMaterialInstance.permutation));
838 for (uint32_t i = 0; i < srcMaterialInstance.propertyCount; i++) {
839 if (rctx.props.count <= srcMaterialInstance.propertyFirst + i) {
840 LOG_ERROR(logger,
"Invalid property index.");
841 rctx.success =
false;
845 auto & prop = rctx.props[srcMaterialInstance.propertyFirst + i];
846 switch (prop.keyType) {
847 case CogsBin::PropertyKeyType::Index:
848 assert(
false &&
"FIXME");
851 case CogsBin::PropertyKeyType::String: {
853 auto keyString = getString(rctx, prop.key);
854 switch (prop.valueType) {
856 case CogsBin::PropertyValueType::Bool:
857 if (
auto key = materialTemplate->getBoolKey(keyString); key != NoProperty)
858 material->setBoolProperty(key, getPropertyValue<uint32_t>(rctx, prop));
860 LOG_ERROR(logger,
"Invalid bool key %.*s", StringViewFormat(keyString));
863 case CogsBin::PropertyValueType::UInt:
864 if (
auto key = materialTemplate->getUIntKey(keyString); key != NoProperty)
865 material->setUIntProperty(key, getPropertyValue<uint32_t>(rctx, prop));
867 LOG_ERROR(logger,
"Invalid uint key %.*s", StringViewFormat(keyString));
870 case CogsBin::PropertyValueType::Float:
871 if (
auto key = materialTemplate->getFloatKey(keyString); key != NoProperty)
872 material->setFloatProperty(key, getPropertyValue<float>(rctx, prop));
874 LOG_ERROR(logger,
"Invalid float key %.*s", StringViewFormat(keyString));
877 case CogsBin::PropertyValueType::Float2:
878 if (
auto key = materialTemplate->getVec2Key(keyString); key != NoProperty)
879 material->setVec2Property(key, getPropertyValue<glm::vec2>(rctx, prop));
881 LOG_ERROR(logger,
"Invalid float2 key %.*s", StringViewFormat(keyString));
884 case CogsBin::PropertyValueType::Float3:
885 if (
auto key = materialTemplate->getVec3Key(keyString); key != NoProperty)
886 material->setVec3Property(key, getPropertyValue<glm::vec3>(rctx, prop));
888 LOG_ERROR(logger,
"Invalid float3 key %.*s", StringViewFormat(keyString));
891 case CogsBin::PropertyValueType::Float4:
892 if (
auto key = materialTemplate->getVec4Key(keyString); key != NoProperty)
893 material->setVec4Property(key, getPropertyValue<glm::vec4>(rctx, prop));
895 LOG_ERROR(logger,
"Invalid float4 key %.*s", StringViewFormat(keyString));
898 case CogsBin::PropertyValueType::ExternalTexture:
899 if (
auto key = materialTemplate->getTextureKey(keyString); key != NoProperty) {
900 auto textureFlags = TextureLoadFlags::None;
901 if (
const auto & mprop = materialTemplate->textureProperties[key]; ((
int)mprop.flags & (
int)MaterialPropertyFlags::sRGB) == 0) {
902 textureFlags |= TextureLoadFlags::LinearColorSpace;
904 auto textureIx = getPropertyValue<uint32_t>(rctx, prop);
905 assert(textureIx < rctx.externalTextures.count);
908 std::string sourcePath = getString(rctx, tex.source).to_string();
909 if (Cogs::IO::isRelative(sourcePath)) {
910 sourcePath = Cogs::IO::combine(Cogs::IO::parentPath(rctx.path), sourcePath);
912 auto texture = rctx.context->textureManager->loadTexture(sourcePath, NoResourceId, textureFlags);
913 material->setTextureProperty(key, texture);
915 assert(tex.samplerState < rctx.samplerStates.count);
918 material->setTextureAddressMode(key,
922 material->setTextureFilterMode(key, getTextureFilterMode(srcSampler.
filter));
925 LOG_ERROR(logger,
"Invalid string key %.*s", StringViewFormat(keyString));
928 case CogsBin::PropertyValueType::EmbeddedTexture:
929 if (
auto key = materialTemplate->getTextureKey(keyString); key != NoProperty) {
930 auto textureIx = getPropertyValue<uint32_t>(rctx, prop);
932 auto texture = populateEmbeddedTexture(rctx, textureIx);
933 material->setTextureProperty(key, texture);
936 assert(tex.samplerState < rctx.samplerStates.count);
939 material->setTextureAddressMode(key,
943 material->setTextureFilterMode(key, getTextureFilterMode(srcSampler.
filter));
947 case CogsBin::PropertyValueType::Variant: {
948 auto key = getString(rctx, prop.key);
949 auto val = getString(rctx, prop.value);
950 material->setVariant(key, val);
957 case CogsBin::PropertyValueType::Option: {
958 auto key = getString(rctx, prop.key);
959 auto val = getString(rctx, prop.value);
960 material->setOption(key, val);
968 LOG_ERROR(logger,
"Invalid property value type.");
969 rctx.success =
false;
975 LOG_ERROR(logger,
"Invalid property key type.");
976 rctx.success =
false;
984 template<
typename ResourceProxy>
990 part.boundsIndex = uint32_t(model->bounds.size());
991 model->bounds.emplace_back(getBoundingBox(rctx, node.
boundingBox));
994 const auto * m = rctx.transforms[node.
transform].m;
995 model->setPartTransform(part, glm::mat4(m[0], m[1], m[2], 0.f,
996 m[3], m[4], m[5], 0.f,
997 m[6], m[7], m[8], 0.f,
998 m[9], m[10], m[11], 1.f));
1000 if (isValidIndex(node.
name)) {
1001 model->setPartName(part, getString(rctx, node.
name));
1003 if (isValidIndex(node.
mesh)) {
1004 part.meshIndex = uint32_t(model->meshes.size());
1005 model->meshes.emplace_back(rctx.context->meshManager->create());
1006 if (rctx.group != NoTask) {
1007 rctx.context->taskManager->enqueueChild(rctx.group, [rc = &rctx, h = model->meshes.back(), ix = node.
mesh](){populateMesh(*rc, h, ix); });
1010 populateMesh(rctx, model->meshes.back(), node.
mesh);
1014 part.materialIndex = uint32_t(model->materials.size());
1015 model->materials.emplace_back(populateMaterialInstance(rctx, node.
materialInstance));
1017 if (node.
primitiveType != CogsBin::PrimitiveType::Unknown) {
1018 part.primitiveType = translatePrimitiveType(rctx, node.
primitiveType);
1020 part.primitiveType = (uint32_t)-1;
1026 void populateBone(ReadContext& rctx,
Bone& dstBone,
const uint32_t boneIx,
const uint32_t boneCount)
1028 if (rctx.bones.count <= boneIx) {
1029 LOG_ERROR(logger,
"Invalid bone index %u (bone count is %zu)", boneIx, rctx.bones.count);
1030 rctx.success =
false;
1033 const auto & srcBone = rctx.bones[boneIx];
1034 dstBone.name = getString(rctx, srcBone.name).to_string();
1035 if (isValidIndex(srcBone.parentBone)) {
1036 if (boneCount <= srcBone.parentBone) {
1037 LOG_ERROR(logger,
"Invalid parent bone index %u (skeleton bone count is %u)",
unsigned(srcBone.parentBone), boneCount);
1038 rctx.success =
false;
1041 dstBone.parentBone = srcBone.parentBone;
1044 dstBone.parentBone = (size_t)-1;
1046 dstBone.pos = srcBone.pos;
1047 dstBone.scale = srcBone.scale;
1048 dstBone.rot = srcBone.rot;
1049 dstBone.relative = srcBone.relative;
1050 dstBone.inverseBindPose = srcBone.inverseBindPose;
1051 dstBone.hasOffset = (srcBone.flags & CogsBin::BoneFlags::HasOffset) != 0;
1052 dstBone.used = (srcBone.flags & CogsBin::BoneFlags::Used) != 0;
1053 dstBone.animated = (srcBone.flags & CogsBin::BoneFlags::Animated) != 0;
1056 void populateSkeleton(ReadContext& rctx,
Skeleton& dstSkeleton,
const uint32_t skeletonIx)
1058 if (rctx.skeletons.count <= skeletonIx) {
1059 LOG_ERROR(logger,
"Invalid skeleton index %u (skeleton count is %zu)", skeletonIx, rctx.skeletons.count);
1060 rctx.success =
false;
1063 const auto & srcSkeleton = rctx.skeletons[skeletonIx];
1064 dstSkeleton.bindPose = srcSkeleton.bindPose;
1065 dstSkeleton.bones.resize(srcSkeleton.boneCount);
1066 for (uint32_t i = 0; i < srcSkeleton.boneCount && rctx.success; i++) {
1067 populateBone(rctx, dstSkeleton.bones[i], srcSkeleton.firstBone + i, srcSkeleton.boneCount);
1068 dstSkeleton.bonesByName[dstSkeleton.bones[i].name] = i;
1070 updateSkeletonPose(dstSkeleton);
1073 void populateAnimTrack(ReadContext& rctx,
AnimationTrack& dstTrack,
const uint32_t animTrackIx)
1075 assert(animTrackIx < rctx.animTracks.count);
1076 const auto & srcTrack = rctx.animTracks[animTrackIx];
1078 assert(srcTrack.buffer < rctx.buffers.count);
1079 const auto & buffer = rctx.buffers[srcTrack.buffer];
1080 const auto * bufferData = resolveDataOffset(rctx, buffer.sectionOffset, buffer.size);
1082 dstTrack.
boneIndex = isValidIndex(srcTrack.boneIndex) ? srcTrack.boneIndex : -1;
1084 const auto * translationSrc = (
const float*)(bufferData + srcTrack.translationOffset);
1085 dstTrack.translations.resize(srcTrack.translationCount);
1086 for (
unsigned i = 0; i < srcTrack.translationCount; i++) {
1087 dstTrack.translations[i].t = *translationSrc++;
1088 dstTrack.translations[i].value[0] = *translationSrc++;
1089 dstTrack.translations[i].value[1] = *translationSrc++;
1090 dstTrack.translations[i].value[2] = *translationSrc++;
1093 const auto * rotationSrc = (
const float*)(bufferData + srcTrack.rotationOffset);
1094 dstTrack.rotations.resize(srcTrack.rotationCount);
1095 for (
unsigned i = 0; i < srcTrack.rotationCount; i++) {
1096 dstTrack.rotations[i].t = *rotationSrc++;
1097 dstTrack.rotations[i].value[0] = *rotationSrc++;
1098 dstTrack.rotations[i].value[1] = *rotationSrc++;
1099 dstTrack.rotations[i].value[2] = *rotationSrc++;
1100 dstTrack.rotations[i].value[3] = *rotationSrc++;
1103 const auto * scaleSrc = (
const float*)(bufferData + srcTrack.scaleOffset);
1104 dstTrack.scales.resize(srcTrack.scaleCount);
1105 for (
unsigned i = 0; i < srcTrack.scaleCount; i++) {
1106 dstTrack.scales[i].t = *scaleSrc++;
1107 dstTrack.scales[i].value[0] = *scaleSrc++;
1108 dstTrack.scales[i].value[1] = *scaleSrc++;
1109 dstTrack.scales[i].value[2] = *scaleSrc++;
1113 void populateAnimClip(ReadContext& rctx,
AnimationClip& dstClip,
const uint32_t animClipIx)
1115 if (rctx.animClips.count <= animClipIx) {
1116 LOG_ERROR(logger,
"Invalid animation clip index %u (animation clip count is %zu)", animClipIx, rctx.animClips.count);
1117 rctx.success =
false;
1121 if (isValidIndex(srcClip.
name)) {
1122 dstClip.name = std::string(getString(rctx, srcClip.
name));
1124 dstClip.duration = srcClip.duration;
1125 dstClip.resolution = srcClip.resolution;
1126 dstClip.tracks.resize(srcClip.trackCount);
1127 for (
unsigned i = 0; i < srcClip.trackCount && rctx.success; i++) {
1128 populateAnimTrack(rctx, dstClip.tracks[i], srcClip.trackFirst + i);
1132 void populateModel(ReadContext& rctx,
ResourceHandleBase modelHandle,
const uint32_t modelIx)
1134 const auto & srcModel = rctx.models[modelIx];
1135 if (srcModel.nodeCount == 0)
return;
1137 assert(modelHandle &&
"Model handle without resource");
1138 auto dstModel = rctx.context->modelManager->lock(modelHandle);
1139 assert(dstModel->parts.empty() &&
"Destination model is not empty");
1142 if (isValidIndex(srcModel.skeleton)) populateSkeleton(rctx, dstModel->skeleton, srcModel.skeleton);
1145 if (srcModel.animClipCount != 0) {
1146 dstModel->animation = rctx.context->animationManager->create();
1148 auto * anim = dstModel->animation.resolve();
1149 anim->skeleton = dstModel->skeleton;
1150 anim->clips.resize(srcModel.animClipCount);
1151 for (uint32_t i = 0; i < srcModel.animClipCount && rctx.success; i++) {
1152 populateAnimClip(rctx, anim->clips[i], srcModel.animClipFirst + i);
1153 anim->clipsByName[anim->clips[i].name] = i;
1158 dstModel->parts.resize(srcModel.nodeCount);
1159 for (
size_t i = 0; i < srcModel.nodeCount && rctx.success; i++) {
1160 if (!isValidIndex(srcModel.firstNode) || rctx.nodes.count <= srcModel.firstNode + i) {
1161 LOG_ERROR(logger,
"Invalid node index %u (node count is %zu)", srcModel.firstNode, rctx.nodes.count);
1162 rctx.success =
false;
1165 const auto & node = rctx.nodes[srcModel.firstNode + i];
1166 auto & part = dstModel->parts[i];
1167 if (!isValidIndex(node.
parent)) {
1168 part.parentIndex = ~0u;
1170 else if (node.
parent < srcModel.firstNode || srcModel.firstNode + srcModel.nodeCount <= node.
parent) {
1171 LOG_ERROR(logger,
"Illegal parent node index %u (node count is %zu)", node.
parent, rctx.nodes.count);
1172 rctx.success =
false;
1176 part.parentIndex = node.
parent - srcModel.firstNode;
1178 populatePart(rctx, dstModel, part, node);
1189 if (extension ==
".cogsbin") {
1196bool Cogs::Core::CogsModelLoader::load(
Context * context,
const ModelLoadInfo & loadInfo, std::unique_ptr<FileContents> contents_)
1205 if (header->magic == CogsBin::HeaderMagic) {
1206 if(header->version == 1) {
1207 return loadCogsBin1(context, loadInfo, std::move(contents_));
1209 else if (header->version == 3) {
1210 return loadCogsBin3(context, loadInfo, std::move(contents_));
1212 else if (5 < header->version) {
1213 LOG_ERROR(logger,
"Unsupported file format version %u", header->version);
1218 LOG_ERROR(logger,
"Missing magic value");
1222 rctx.version = header->version;
1226 rctx.context = context;
1227 rctx.contents = std::move(contents_);
1229 if (loadCount.fetch_add(1) < COGS_MODELLOADER_MAX_TASKS) {
1233 rctx.success =
true;
1235 unsigned modelIx = 0u;
1236 if (
auto i = rctx.path.find(
'#'); i != std::string::npos) {
1237 if (i + 1 < rctx.path.length()) {
1238 modelIx = std::atoi(rctx.path.c_str() + i + 1);
1240 rctx.path.resize(i);
1244 LOG_ERROR(logger,
"Model file too small to contain a header, unable to load.");
1249 if (rctx.header->sectionCount == 0) {
1250 LOG_ERROR(logger,
"No sections in file.");
1253 if (rctx.header->fileLength != rctx.contents->size) {
1254 LOG_ERROR(logger,
"File size mismatch in read context, potentially corrupt or truncated model file.");
1260 rctx.sectionPtr.resize(rctx.header->sectionCount);
1261 rctx.sectionLocks.reset(
new Mutex[rctx.header->sectionCount]);
1263 LOG_TRACE(logger,
"Parsed header, %u sections, filesize=%zu", rctx.header->sectionCount, rctx.contents->size);
1266 if ((rctx.sectionInfo[0].type & CogsBin::SectionType::META) == 0) {
1267 LOG_ERROR(logger,
"First section is not a meta section.");
1271 const auto * sectionBase = sectionPointer(rctx, 0);
1272 if (sectionBase ==
nullptr)
return false;
1274 for (uint16_t sub = 0; sub < rctx.sectionInfo[0].subSectionCount; sub++) {
1276 switch (metaSubSection.type)
1278 case CogsBin::SubSectionType::Buffers:
1279 rctx.buffers.base = (
const CogsBin::Buffer*)(sectionBase + metaSubSection.offset);
1281 rctx.bufferCache.resize(rctx.buffers.count);
1284 case CogsBin::SubSectionType::ExternalTextures:
1289 case CogsBin::SubSectionType::EmbeddedTextures:
1292 rctx.textureCache.resize(rctx.embeddedTextures.count);
1295 case CogsBin::SubSectionType::SamplerStates:
1300 case CogsBin::SubSectionType::Strings:
1301 rctx.strings.base = (
const CogsBin::String*)(sectionBase + metaSubSection.offset);
1305 case CogsBin::SubSectionType::StringData:
1306 rctx.stringData.base = (
char*)(sectionBase + metaSubSection.offset);
1307 rctx.stringData.count = metaSubSection.size;
1310 case CogsBin::SubSectionType::Nodes:
1311 rctx.nodes.base = (
const CogsBin::Node*)(sectionBase + metaSubSection.offset);
1312 rctx.nodes.count = metaSubSection.size /
sizeof(
CogsBin::Node);
1315 case CogsBin::SubSectionType::Transforms:
1316 rctx.transforms.base = (
const CogsBin::Transform*)(sectionBase + metaSubSection.offset);
1320 case CogsBin::SubSectionType::BoundingBoxes:
1321 rctx.boundingBoxes.base = (
const Cogs::Geometry::BoundingBox*)(sectionBase + metaSubSection.offset);
1322 rctx.boundingBoxes.count = metaSubSection.size /
sizeof(Cogs::Geometry::BoundingBox);
1325 case CogsBin::SubSectionType::MaterialInstances:
1330 case CogsBin::SubSectionType::Properties:
1331 rctx.props.base = (
const CogsBin::Property*)(sectionBase + metaSubSection.offset);
1335 case CogsBin::SubSectionType::PropertyData:
1336 rctx.propData.base = sectionBase + metaSubSection.offset;
1337 rctx.propData.count = metaSubSection.size;
1340 case CogsBin::SubSectionType::Meshes:
1341 rctx.meshes.base = (
const CogsBin::Mesh*)(sectionBase + metaSubSection.offset);
1342 rctx.meshes.count = metaSubSection.size /
sizeof(
CogsBin::Mesh);
1345 case CogsBin::SubSectionType::VertexStreams:
1350 case CogsBin::SubSectionType::VertexAttributes:
1355 case CogsBin::SubSectionType::Bones:
1356 rctx.bones.base = (
const CogsBin::Bone*)(sectionBase + metaSubSection.offset);
1357 rctx.bones.count = metaSubSection.size /
sizeof(
CogsBin::Bone);
1360 case CogsBin::SubSectionType::Skeletons:
1361 rctx.skeletons.base = (
const CogsBin::Skeleton*)(sectionBase + metaSubSection.offset);
1365 case CogsBin::SubSectionType::AnimTracks:
1366 rctx.animTracks.base = (
const CogsBin::AnimTrack*)(sectionBase + metaSubSection.offset);
1370 case CogsBin::SubSectionType::AnimClips:
1371 rctx.animClips.base = (
const CogsBin::AnimClip*)(sectionBase + metaSubSection.offset);
1375 case CogsBin::SubSectionType::Models:
1376 rctx.models.base = (
const CogsBin::Model*)(sectionBase + metaSubSection.offset);
1377 rctx.models.count = metaSubSection.size /
sizeof(
CogsBin::Model);
1381 LOG_ERROR(logger,
"Unknown subsection type %u",
unsigned(metaSubSection.type));
1386 for (uint32_t i = 0; i < rctx.buffers.count; i++) {
1387 const auto & buffer = rctx.buffers[i];
1388 const auto sectionIx = buffer.sectionOffset >> 48;
1389 const auto sectionOffset = size_t(buffer.sectionOffset & 0xFFFFFFFFFFFFull);
1390 if (rctx.header->sectionCount <= sectionIx) {
1391 LOG_ERROR(logger,
"Illegal section index %u (section count is %u)",
unsigned(sectionIx), rctx.header->sectionCount);
1394 const auto & sectionInfo = rctx.sectionInfo[sectionIx];
1395 if (sectionInfo.uncompressedSize < sectionOffset + buffer.size) {
1396 LOG_ERROR(logger,
"Buffer out of bounds");
1401 for (uint32_t i = 0; i < rctx.embeddedTextures.count; i++) {
1402 const auto & tex = rctx.embeddedTextures[i];
1403 if (rctx.buffers.count <= tex.
buffer) { LOG_ERROR(logger,
"Texture has illegal buffer index %u", tex.
buffer);
return false; }
1404 auto & buf = rctx.buffers[tex.
buffer];
1405 if (buf.size < tex.
offset + tex.
size) { LOG_ERROR(logger,
"Texture buffer view outside buffer");
return false; }
1406 if (isValidIndex(tex.name) && rctx.strings.count <= tex.name) { LOG_ERROR(logger,
"Illegal name string %u", tex.name);
return false; }
1407 if (0x10000 < tex.width) { LOG_ERROR(logger,
"Suspicious texture width %u", tex.width);
return false; }
1408 if (0x10000 < tex.height) { LOG_ERROR(logger,
"Suspicious texture height %u", tex.height);
return false; }
1409 if (0x10000 < tex.depth) { LOG_ERROR(logger,
"Suspicious texture depth %u", tex.depth);
return false; }
1410 if (6 < tex.faces) { LOG_ERROR(logger,
"Suspicious texture faces %u", tex.faces);
return false; }
1411 if (0x10000 < tex.layers) { LOG_ERROR(logger,
"Suspicious texture layers %u", tex.layers);
return false; }
1412 if (CogsBin::Format::EnumSize <= tex.format) { LOG_ERROR(logger,
"Illegal format %u",
unsigned(tex.format));
return false; }
1413 if (CogsBin::TextureEncoding::EnumSize <= tex.encoding) { LOG_ERROR(logger,
"Illegal encoding %u",
unsigned(tex.encoding));
return false; }
1416 for (uint32_t i = 0; i < rctx.vertexStreams.count; i++) {
1417 const auto & dataStream = rctx.vertexStreams[i];
1418 if (rctx.buffers.count <= dataStream.buffer) {
1419 LOG_ERROR(logger,
"Vertex stream has illegal buffer index %u (count is %zu)", dataStream.buffer, rctx.buffers.count);
1422 if (dataStream.vertexDataType < VertexDataType::LastVertexType) {
1423 if (!isValidIndex(dataStream.firstAttribute)) {
1424 LOG_ERROR(logger,
"Vertex stream without attributes");
1427 if (rctx.vertexAttributes.count <= dataStream.firstAttribute || rctx.vertexAttributes.count < dataStream.firstAttribute + dataStream.attributeCount) {
1428 LOG_ERROR(logger,
"Vertex stream has illegal vertex attribute indices first=%u count=%u (total count is %zu)",
1429 dataStream.firstAttribute, dataStream.attributeCount, rctx.vertexAttributes.count);
1432 }
else if (dataStream.vertexDataType == VertexDataType::Indexes) {
1433 if (dataStream.stride != 4 && dataStream.stride != 2) {
1434 LOG_ERROR(logger,
"Index stream has unsupported stride.");
1439 if (!isValidIndex(dataStream.buffer)) {
1440 LOG_ERROR(logger,
"Data stream without valid buffer.");
1445 for (uint32_t i = 0; i < rctx.animTracks.count; i++) {
1446 const auto & track = rctx.animTracks[i];
1447 if (rctx.buffers.count <= track.buffer) {
1448 LOG_ERROR(logger,
"Anim track has illegal buffer index %u.", track.buffer);
1451 const auto & buffer = rctx.buffers[track.buffer];
1452 if (buffer.size < track.translationOffset + 4 *
sizeof(
float)*track.translationCount) {
1453 LOG_ERROR(logger,
"Anim track translation buffer view is outside buffer.");
1456 if (buffer.size < track.rotationOffset + 5 *
sizeof(
float)*track.rotationCount) {
1457 LOG_ERROR(logger,
"Anim track translation buffer view is outside buffer.");
1460 if (buffer.size < track.scaleOffset + 4 *
sizeof(
float)*track.scaleCount) {
1461 LOG_ERROR(logger,
"Anim track translation buffer view is outside buffer.");
1466 for (uint32_t i = 0; i < rctx.meshes.count; i++) {
1467 const auto & mesh = rctx.meshes[i];
1468 if (isValidIndex(mesh.name) && rctx.strings.count <= mesh.name) {
1469 LOG_ERROR(logger,
"Mesh name has illegal string index %u (string count is %zu)", mesh.name, rctx.strings.count);
1472 if (isValidIndex(mesh.boundingBox) && rctx.boundingBoxes.count <= mesh.boundingBox) {
1473 LOG_ERROR(logger,
"Mesh name has illegal boundingBox index %u (count is %zu)", mesh.boundingBox, rctx.boundingBoxes.count);
1476 if (isValidIndex(mesh.firstStream) && rctx.vertexStreams.count <= mesh.firstStream) {
1477 LOG_ERROR(logger,
"Mesh name has illegal data stream index %u (count is %zu)", mesh.firstStream, rctx.vertexStreams.count);
1482 if (modelIx < rctx.models.count) {
1483 populateModel(rctx, loadInfo.
handle, modelIx);
1486 LOG_ERROR(logger,
"Invalid model index %u (model count=%zu)", modelIx, rctx.models.count);
1487 rctx.success =
false;
1490 if (rctx.group != NoTask) {
1496 return rctx.success;
1502 LOG_DEBUG(logger,
"Loading model: %s", loadInfo.
resourceName.c_str());
1507 std::unique_ptr<Cogs::FileContents> contents;
1509 if (loadInfo.protocol == ResourceProtocol::Archive) {
1512 if (!buffer.
buffer->data()) {
1513 LOG_ERROR(logger,
"Could not load resource data for model %s.", loadInfo.
resourcePath.c_str());
1516 contents = std::make_unique<Cogs::Platform::ResourceBufferBackedFileContents>(buffer, loadInfo.
resourcePath, Cogs::FileContentsHints::None);
1520 Cogs::FileHandle::Ptr file = Cogs::IO::openFile(loadInfo.
resourcePath, Cogs::FileHandle::OpenMode::OpenAlways, Cogs::FileHandle::AccessMode::Read);
1522 LOG_ERROR(logger,
"Could not open file %s for mapping.", loadInfo.
resourcePath.c_str());
1526 size_t size = Cogs::IO::fileSize(file);
1528 LOG_ERROR(logger,
"File size invalid: %zd.", size);
1532 const uint8_t* ptr =
static_cast<const uint8_t*
>(Cogs::IO::mapFile(file, Cogs::FileHandle::ProtectionMode::ReadOnly, 0, size));
1534 LOG_ERROR(logger,
"Could not map file %s for reading model data.", loadInfo.
resourcePath.c_str());
1538 contents = std::make_unique<Cogs::MMapBackedFileContents>(ptr, size, file, loadInfo.
resourcePath, Cogs::FileContentsHints::None);
1542 double ioElapsed = ioTimer.elapsedSeconds();
1544 bool rv = load(context, loadInfo, std::move(contents));
1546 LOG_TRACE(logger,
"Elapsed: %f (IO: %f)", timer.elapsedSeconds(), ioElapsed);
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class TaskManager > taskManager
TaskManager service instance.
std::unique_ptr< class ResourceStore > resourceStore
ResourceStore service instance.
static constexpr TaskQueueId ResourceQueue
Resource task queue.
Log implementation class.
Provides a weakly referenced view over the contents of a string.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains all Cogs related functionality.
@ InstanceData
Per instance data.
@ VertexData
Per vertex data.
@ Position
Position semantic.
@ Tangent
Tangent semantic.
@ InstanceMatrix
Instance matrix semantic.
@ InstanceVector
Instance vector semantic.
@ TextureCoordinate
Texture coordinate semantic.
uint32_t boneIndex
Specifies which bone of a skeleton that is animated by this track.
@ VertexBuffer
Buffer can be bound as vertex buffer.
@ IndexBuffer
Buffer can be bound as index buffer.
uint32_t name
Offset into strings subsection of current section.
uint32_t size
Byte size of image data.
uint32_t offset
Byte offset within buffer for start of imagte data.
uint32_t buffer
Buffer that holds image data, index into buffers.
PrimitiveType primitiveType
Primitive type to use for this node.
uint32_t name
Name of node, offset into Strings subsection.
uint32_t vertexFirst
First vertex of mesh to draw.
uint32_t boundingBox
Bounding box of node, offset into BoundingBoxes subsection.
uint32_t materialInstance
Material instance of node, offset into MaterialInstances subsection.
uint32_t mesh
Mesh of node, offset into Meshes subsection.
uint32_t vertexCount
Number of vertices to draw.
uint32_t parent
Parent node, offset into Nodes subsection.
uint32_t transform
Transform of node, offset into Transforms subsection.
TextureAddressMode addressModeW
Specifies the addressing mode along the W axis in texture coordinate space.
TextureFilterMode filter
Specifies the filter to use for texture sampling.
TextureAddressMode addressModeS
Specifies the addressing mode along the S axis in texture coordinate space.
TextureAddressMode addressModeT
Specifies the addressing mode along the T axis in texture coordinate space.
@ StreamsChanged
One or more of the data streams in the mesh changed.
@ IndexesChanged
The index data of the mesh changed.
@ Indexed
The mesh should be drawn indexed, using index data to order the triangle vertexes.
@ ClockwiseWinding
The mesh uses clockwise winding order for it's triangles as opposed to the counter-clockwise default.
static constexpr uint16_t toFlag(VertexDataType::EVertexDataType type)
Convert the given type index to a flag.
std::shared_ptr< Memory::MemoryBuffer > buffer
Actual resource contents. Prefer using access methods.
Resource handle base class handling reference counting of resources derived from ResourceBase.
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
std::string resourcePath
Resource path. Used to locate resource.
std::string resourceName
Desired resource name. If no name is given, a default name will be chosen.
ResourceId resourceId
Unique resource identifier. Must be unique among resources of the same kind.
ResourceHandleBase handle
Handle to resource structure for holding actual resource data.
std::vector< uint8_t > resourceData
Resource load data.
Task id struct used to identify unique Task instances.
EVertexDataType
Contains data types.
EPrimitiveType
Primitive type enumeration.
@ LineStripAdjacency
Line strip with adjacency.
@ TriangleStrip
Triangle strip.
@ TriangleListAdjacency
List of triangles with adjacency.
@ PointList
List of points.
@ TriangleStripAdjacency
Triangle strip with adjacency.
@ LineListAdjacency
List of lines with adjacency.
@ TriangleList
List of triangles.
AddressMode
Addressing modes to use when sampling textures.
@ Clamp
Texture coordinates are clamped to the [0, 1] range.
@ Border
Texture color is set to the border color when outside [0, 1] range.
@ Wrap
Texture coordinates automatically wrap around to [0, 1] range.
@ Mirror
Texture coordinates are mirrored when outside [0, 1] range.
FilterMode
Filter modes to specify how texture data is treated when sampled.
@ ComparisonMinMagMipPoint
Comparison filter for depth sample comparisons using point sampling.
@ ComparisonMinMagMipLinear
Comparison filter for depth sample comparisons using linear interpolation sampling.
@ MinMagMipPoint
Point sampling for both minification and magnification.
@ MinMagMipLinear
Linear sampling for both minification and magnification.