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;
108 Cogs::PrimitiveType translatePrimitiveType(ReadContext& rctx, CogsBin::PrimitiveType primitiveType)
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);
1021 part.primitiveType = Cogs::PrimitiveType::None;
1027 void populateBone(ReadContext& rctx,
Bone& dstBone,
const uint32_t boneIx,
const uint32_t boneCount)
1029 if (rctx.bones.count <= boneIx) {
1030 LOG_ERROR(logger,
"Invalid bone index %u (bone count is %zu)", boneIx, rctx.bones.count);
1031 rctx.success =
false;
1034 const auto & srcBone = rctx.bones[boneIx];
1035 dstBone.name = getString(rctx, srcBone.name).to_string();
1036 if (isValidIndex(srcBone.parentBone)) {
1037 if (boneCount <= srcBone.parentBone) {
1038 LOG_ERROR(logger,
"Invalid parent bone index %u (skeleton bone count is %u)",
unsigned(srcBone.parentBone), boneCount);
1039 rctx.success =
false;
1042 dstBone.parentBone = srcBone.parentBone;
1045 dstBone.parentBone = (size_t)-1;
1047 dstBone.pos = srcBone.pos;
1048 dstBone.scale = srcBone.scale;
1049 dstBone.rot = srcBone.rot;
1050 dstBone.relative = srcBone.relative;
1051 dstBone.inverseBindPose = srcBone.inverseBindPose;
1052 dstBone.hasOffset = (srcBone.flags & CogsBin::BoneFlags::HasOffset) != 0;
1053 dstBone.used = (srcBone.flags & CogsBin::BoneFlags::Used) != 0;
1054 dstBone.animated = (srcBone.flags & CogsBin::BoneFlags::Animated) != 0;
1057 void populateSkeleton(ReadContext& rctx,
Skeleton& dstSkeleton,
const uint32_t skeletonIx)
1059 if (rctx.skeletons.count <= skeletonIx) {
1060 LOG_ERROR(logger,
"Invalid skeleton index %u (skeleton count is %zu)", skeletonIx, rctx.skeletons.count);
1061 rctx.success =
false;
1064 const auto & srcSkeleton = rctx.skeletons[skeletonIx];
1065 dstSkeleton.bindPose = srcSkeleton.bindPose;
1066 dstSkeleton.bones.resize(srcSkeleton.boneCount);
1067 for (uint32_t i = 0; i < srcSkeleton.boneCount && rctx.success; i++) {
1068 populateBone(rctx, dstSkeleton.bones[i], srcSkeleton.firstBone + i, srcSkeleton.boneCount);
1069 dstSkeleton.bonesByName[dstSkeleton.bones[i].name] = i;
1071 updateSkeletonPose(dstSkeleton);
1074 void populateAnimTrack(ReadContext& rctx,
AnimationTrack& dstTrack,
const uint32_t animTrackIx)
1076 assert(animTrackIx < rctx.animTracks.count);
1077 const auto & srcTrack = rctx.animTracks[animTrackIx];
1079 assert(srcTrack.buffer < rctx.buffers.count);
1080 const auto & buffer = rctx.buffers[srcTrack.buffer];
1081 const auto * bufferData = resolveDataOffset(rctx, buffer.sectionOffset, buffer.size);
1083 dstTrack.
boneIndex = isValidIndex(srcTrack.boneIndex) ? srcTrack.boneIndex : -1;
1085 const auto * translationSrc = (
const float*)(bufferData + srcTrack.translationOffset);
1086 dstTrack.translations.resize(srcTrack.translationCount);
1087 for (
unsigned i = 0; i < srcTrack.translationCount; i++) {
1088 dstTrack.translations[i].t = *translationSrc++;
1089 dstTrack.translations[i].value[0] = *translationSrc++;
1090 dstTrack.translations[i].value[1] = *translationSrc++;
1091 dstTrack.translations[i].value[2] = *translationSrc++;
1094 const auto * rotationSrc = (
const float*)(bufferData + srcTrack.rotationOffset);
1095 dstTrack.rotations.resize(srcTrack.rotationCount);
1096 for (
unsigned i = 0; i < srcTrack.rotationCount; i++) {
1097 dstTrack.rotations[i].t = *rotationSrc++;
1098 dstTrack.rotations[i].value[0] = *rotationSrc++;
1099 dstTrack.rotations[i].value[1] = *rotationSrc++;
1100 dstTrack.rotations[i].value[2] = *rotationSrc++;
1101 dstTrack.rotations[i].value[3] = *rotationSrc++;
1104 const auto * scaleSrc = (
const float*)(bufferData + srcTrack.scaleOffset);
1105 dstTrack.scales.resize(srcTrack.scaleCount);
1106 for (
unsigned i = 0; i < srcTrack.scaleCount; i++) {
1107 dstTrack.scales[i].t = *scaleSrc++;
1108 dstTrack.scales[i].value[0] = *scaleSrc++;
1109 dstTrack.scales[i].value[1] = *scaleSrc++;
1110 dstTrack.scales[i].value[2] = *scaleSrc++;
1114 void populateAnimClip(ReadContext& rctx,
AnimationClip& dstClip,
const uint32_t animClipIx)
1116 if (rctx.animClips.count <= animClipIx) {
1117 LOG_ERROR(logger,
"Invalid animation clip index %u (animation clip count is %zu)", animClipIx, rctx.animClips.count);
1118 rctx.success =
false;
1122 if (isValidIndex(srcClip.
name)) {
1123 dstClip.name = std::string(getString(rctx, srcClip.
name));
1125 dstClip.duration = srcClip.duration;
1126 dstClip.resolution = srcClip.resolution;
1127 dstClip.tracks.resize(srcClip.trackCount);
1128 for (
unsigned i = 0; i < srcClip.trackCount && rctx.success; i++) {
1129 populateAnimTrack(rctx, dstClip.tracks[i], srcClip.trackFirst + i);
1133 void populateModel(ReadContext& rctx,
ResourceHandleBase modelHandle,
const uint32_t modelIx)
1135 const auto & srcModel = rctx.models[modelIx];
1136 if (srcModel.nodeCount == 0)
return;
1138 assert(modelHandle &&
"Model handle without resource");
1139 auto dstModel = rctx.context->modelManager->lock(modelHandle);
1140 assert(dstModel->parts.empty() &&
"Destination model is not empty");
1143 if (isValidIndex(srcModel.skeleton)) populateSkeleton(rctx, dstModel->skeleton, srcModel.skeleton);
1146 if (srcModel.animClipCount != 0) {
1147 dstModel->animation = rctx.context->animationManager->create();
1149 auto * anim = dstModel->animation.resolve();
1150 anim->skeleton = dstModel->skeleton;
1151 anim->clips.resize(srcModel.animClipCount);
1152 for (uint32_t i = 0; i < srcModel.animClipCount && rctx.success; i++) {
1153 populateAnimClip(rctx, anim->clips[i], srcModel.animClipFirst + i);
1154 anim->clipsByName[anim->clips[i].name] = i;
1159 dstModel->parts.resize(srcModel.nodeCount);
1160 for (
size_t i = 0; i < srcModel.nodeCount && rctx.success; i++) {
1161 if (!isValidIndex(srcModel.firstNode) || rctx.nodes.count <= srcModel.firstNode + i) {
1162 LOG_ERROR(logger,
"Invalid node index %u (node count is %zu)", srcModel.firstNode, rctx.nodes.count);
1163 rctx.success =
false;
1166 const auto & node = rctx.nodes[srcModel.firstNode + i];
1167 auto & part = dstModel->parts[i];
1168 if (!isValidIndex(node.
parent)) {
1169 part.parentIndex = ~0u;
1171 else if (node.
parent < srcModel.firstNode || srcModel.firstNode + srcModel.nodeCount <= node.
parent) {
1172 LOG_ERROR(logger,
"Illegal parent node index %u (node count is %zu)", node.
parent, rctx.nodes.count);
1173 rctx.success =
false;
1177 part.parentIndex = node.
parent - srcModel.firstNode;
1179 populatePart(rctx, dstModel, part, node);
1190 if (extension ==
".cogsbin") {
1197bool Cogs::Core::CogsModelLoader::load(
Context * context,
const ModelLoadInfo & loadInfo, std::unique_ptr<FileContents> contents_)
1206 if (header->magic == CogsBin::HeaderMagic) {
1207 if(header->version == 1) {
1208 return loadCogsBin1(context, loadInfo, std::move(contents_));
1210 else if (header->version == 3) {
1211 return loadCogsBin3(context, loadInfo, std::move(contents_));
1213 else if (5 < header->version) {
1214 LOG_ERROR(logger,
"Unsupported file format version %u", header->version);
1219 LOG_ERROR(logger,
"Missing magic value");
1223 rctx.version = header->version;
1227 rctx.context = context;
1228 rctx.contents = std::move(contents_);
1230 if (loadCount.fetch_add(1) < COGS_MODELLOADER_MAX_TASKS) {
1234 rctx.success =
true;
1236 unsigned modelIx = 0u;
1237 if (
auto i = rctx.path.find(
'#'); i != std::string::npos) {
1238 if (i + 1 < rctx.path.length()) {
1239 modelIx = std::atoi(rctx.path.c_str() + i + 1);
1241 rctx.path.resize(i);
1245 LOG_ERROR(logger,
"Model file too small to contain a header, unable to load.");
1250 if (rctx.header->sectionCount == 0) {
1251 LOG_ERROR(logger,
"No sections in file.");
1254 if (rctx.header->fileLength != rctx.contents->size) {
1255 LOG_ERROR(logger,
"File size mismatch in read context, potentially corrupt or truncated model file.");
1261 rctx.sectionPtr.resize(rctx.header->sectionCount);
1262 rctx.sectionLocks.reset(
new Mutex[rctx.header->sectionCount]);
1264 LOG_TRACE(logger,
"Parsed header, %u sections, filesize=%zu", rctx.header->sectionCount, rctx.contents->size);
1267 if ((rctx.sectionInfo[0].type & CogsBin::SectionType::META) == 0) {
1268 LOG_ERROR(logger,
"First section is not a meta section.");
1272 const auto * sectionBase = sectionPointer(rctx, 0);
1273 if (sectionBase ==
nullptr)
return false;
1275 for (uint16_t sub = 0; sub < rctx.sectionInfo[0].subSectionCount; sub++) {
1277 switch (metaSubSection.type)
1279 case CogsBin::SubSectionType::Buffers:
1280 rctx.buffers.base = (
const CogsBin::Buffer*)(sectionBase + metaSubSection.offset);
1282 rctx.bufferCache.resize(rctx.buffers.count);
1285 case CogsBin::SubSectionType::ExternalTextures:
1290 case CogsBin::SubSectionType::EmbeddedTextures:
1293 rctx.textureCache.resize(rctx.embeddedTextures.count);
1296 case CogsBin::SubSectionType::SamplerStates:
1301 case CogsBin::SubSectionType::Strings:
1302 rctx.strings.base = (
const CogsBin::String*)(sectionBase + metaSubSection.offset);
1306 case CogsBin::SubSectionType::StringData:
1307 rctx.stringData.base = (
char*)(sectionBase + metaSubSection.offset);
1308 rctx.stringData.count = metaSubSection.size;
1311 case CogsBin::SubSectionType::Nodes:
1312 rctx.nodes.base = (
const CogsBin::Node*)(sectionBase + metaSubSection.offset);
1313 rctx.nodes.count = metaSubSection.size /
sizeof(
CogsBin::Node);
1316 case CogsBin::SubSectionType::Transforms:
1317 rctx.transforms.base = (
const CogsBin::Transform*)(sectionBase + metaSubSection.offset);
1321 case CogsBin::SubSectionType::BoundingBoxes:
1322 rctx.boundingBoxes.base = (
const Cogs::Geometry::BoundingBox*)(sectionBase + metaSubSection.offset);
1323 rctx.boundingBoxes.count = metaSubSection.size /
sizeof(Cogs::Geometry::BoundingBox);
1326 case CogsBin::SubSectionType::MaterialInstances:
1331 case CogsBin::SubSectionType::Properties:
1332 rctx.props.base = (
const CogsBin::Property*)(sectionBase + metaSubSection.offset);
1336 case CogsBin::SubSectionType::PropertyData:
1337 rctx.propData.base = sectionBase + metaSubSection.offset;
1338 rctx.propData.count = metaSubSection.size;
1341 case CogsBin::SubSectionType::Meshes:
1342 rctx.meshes.base = (
const CogsBin::Mesh*)(sectionBase + metaSubSection.offset);
1343 rctx.meshes.count = metaSubSection.size /
sizeof(
CogsBin::Mesh);
1346 case CogsBin::SubSectionType::VertexStreams:
1351 case CogsBin::SubSectionType::VertexAttributes:
1356 case CogsBin::SubSectionType::Bones:
1357 rctx.bones.base = (
const CogsBin::Bone*)(sectionBase + metaSubSection.offset);
1358 rctx.bones.count = metaSubSection.size /
sizeof(
CogsBin::Bone);
1361 case CogsBin::SubSectionType::Skeletons:
1362 rctx.skeletons.base = (
const CogsBin::Skeleton*)(sectionBase + metaSubSection.offset);
1366 case CogsBin::SubSectionType::AnimTracks:
1367 rctx.animTracks.base = (
const CogsBin::AnimTrack*)(sectionBase + metaSubSection.offset);
1371 case CogsBin::SubSectionType::AnimClips:
1372 rctx.animClips.base = (
const CogsBin::AnimClip*)(sectionBase + metaSubSection.offset);
1376 case CogsBin::SubSectionType::Models:
1377 rctx.models.base = (
const CogsBin::Model*)(sectionBase + metaSubSection.offset);
1378 rctx.models.count = metaSubSection.size /
sizeof(
CogsBin::Model);
1382 LOG_ERROR(logger,
"Unknown subsection type %u",
unsigned(metaSubSection.type));
1387 for (uint32_t i = 0; i < rctx.buffers.count; i++) {
1388 const auto & buffer = rctx.buffers[i];
1389 const auto sectionIx = buffer.sectionOffset >> 48;
1390 const auto sectionOffset = size_t(buffer.sectionOffset & 0xFFFFFFFFFFFFull);
1391 if (rctx.header->sectionCount <= sectionIx) {
1392 LOG_ERROR(logger,
"Illegal section index %u (section count is %u)",
unsigned(sectionIx), rctx.header->sectionCount);
1395 const auto & sectionInfo = rctx.sectionInfo[sectionIx];
1396 if (sectionInfo.uncompressedSize < sectionOffset + buffer.size) {
1397 LOG_ERROR(logger,
"Buffer out of bounds");
1402 for (uint32_t i = 0; i < rctx.embeddedTextures.count; i++) {
1403 const auto & tex = rctx.embeddedTextures[i];
1404 if (rctx.buffers.count <= tex.
buffer) { LOG_ERROR(logger,
"Texture has illegal buffer index %u", tex.
buffer);
return false; }
1405 auto & buf = rctx.buffers[tex.
buffer];
1406 if (buf.size < tex.
offset + tex.
size) { LOG_ERROR(logger,
"Texture buffer view outside buffer");
return false; }
1407 if (isValidIndex(tex.name) && rctx.strings.count <= tex.name) { LOG_ERROR(logger,
"Illegal name string %u", tex.name);
return false; }
1408 if (0x10000 < tex.width) { LOG_ERROR(logger,
"Suspicious texture width %u", tex.width);
return false; }
1409 if (0x10000 < tex.height) { LOG_ERROR(logger,
"Suspicious texture height %u", tex.height);
return false; }
1410 if (0x10000 < tex.depth) { LOG_ERROR(logger,
"Suspicious texture depth %u", tex.depth);
return false; }
1411 if (6 < tex.faces) { LOG_ERROR(logger,
"Suspicious texture faces %u", tex.faces);
return false; }
1412 if (0x10000 < tex.layers) { LOG_ERROR(logger,
"Suspicious texture layers %u", tex.layers);
return false; }
1413 if (CogsBin::Format::EnumSize <= tex.format) { LOG_ERROR(logger,
"Illegal format %u",
unsigned(tex.format));
return false; }
1414 if (CogsBin::TextureEncoding::EnumSize <= tex.encoding) { LOG_ERROR(logger,
"Illegal encoding %u",
unsigned(tex.encoding));
return false; }
1417 for (uint32_t i = 0; i < rctx.vertexStreams.count; i++) {
1418 const auto & dataStream = rctx.vertexStreams[i];
1419 if (rctx.buffers.count <= dataStream.buffer) {
1420 LOG_ERROR(logger,
"Vertex stream has illegal buffer index %u (count is %zu)", dataStream.buffer, rctx.buffers.count);
1423 if (dataStream.vertexDataType < VertexDataType::LastVertexType) {
1424 if (!isValidIndex(dataStream.firstAttribute)) {
1425 LOG_ERROR(logger,
"Vertex stream without attributes");
1428 if (rctx.vertexAttributes.count <= dataStream.firstAttribute || rctx.vertexAttributes.count < dataStream.firstAttribute + dataStream.attributeCount) {
1429 LOG_ERROR(logger,
"Vertex stream has illegal vertex attribute indices first=%u count=%u (total count is %zu)",
1430 dataStream.firstAttribute, dataStream.attributeCount, rctx.vertexAttributes.count);
1433 }
else if (dataStream.vertexDataType == VertexDataType::Indexes) {
1434 if (dataStream.stride != 4 && dataStream.stride != 2) {
1435 LOG_ERROR(logger,
"Index stream has unsupported stride.");
1440 if (!isValidIndex(dataStream.buffer)) {
1441 LOG_ERROR(logger,
"Data stream without valid buffer.");
1446 for (uint32_t i = 0; i < rctx.animTracks.count; i++) {
1447 const auto & track = rctx.animTracks[i];
1448 if (rctx.buffers.count <= track.buffer) {
1449 LOG_ERROR(logger,
"Anim track has illegal buffer index %u.", track.buffer);
1452 const auto & buffer = rctx.buffers[track.buffer];
1453 if (buffer.size < track.translationOffset + 4 *
sizeof(
float)*track.translationCount) {
1454 LOG_ERROR(logger,
"Anim track translation buffer view is outside buffer.");
1457 if (buffer.size < track.rotationOffset + 5 *
sizeof(
float)*track.rotationCount) {
1458 LOG_ERROR(logger,
"Anim track translation buffer view is outside buffer.");
1461 if (buffer.size < track.scaleOffset + 4 *
sizeof(
float)*track.scaleCount) {
1462 LOG_ERROR(logger,
"Anim track translation buffer view is outside buffer.");
1467 for (uint32_t i = 0; i < rctx.meshes.count; i++) {
1468 const auto & mesh = rctx.meshes[i];
1469 if (isValidIndex(mesh.name) && rctx.strings.count <= mesh.name) {
1470 LOG_ERROR(logger,
"Mesh name has illegal string index %u (string count is %zu)", mesh.name, rctx.strings.count);
1473 if (isValidIndex(mesh.boundingBox) && rctx.boundingBoxes.count <= mesh.boundingBox) {
1474 LOG_ERROR(logger,
"Mesh has illegal boundingBox index %u (count is %zu)", mesh.boundingBox, rctx.boundingBoxes.count);
1477 if (isValidIndex(mesh.firstStream) && rctx.vertexStreams.count <= mesh.firstStream) {
1478 LOG_ERROR(logger,
"Mesh has illegal first data stream index %u (count is %zu)", mesh.firstStream, rctx.vertexStreams.count);
1483 if (modelIx < rctx.models.count) {
1484 populateModel(rctx, loadInfo.
handle, modelIx);
1487 LOG_ERROR(logger,
"Invalid model index %u (model count=%zu)", modelIx, rctx.models.count);
1488 rctx.success =
false;
1491 if (rctx.group != NoTask) {
1497 return rctx.success;
1503 LOG_DEBUG(logger,
"Loading model: %s", loadInfo.
resourceName.c_str());
1508 std::unique_ptr<Cogs::FileContents> contents;
1510 if (loadInfo.protocol == ResourceProtocol::Archive) {
1513 if (!buffer.
buffer->data()) {
1514 LOG_ERROR(logger,
"Could not load resource data for model %s.", loadInfo.
resourcePath.c_str());
1517 contents = std::make_unique<Cogs::Platform::ResourceBufferBackedFileContents>(buffer, loadInfo.
resourcePath, Cogs::FileContentsHints::None);
1521 Cogs::FileHandle::Ptr file = Cogs::IO::openFile(loadInfo.
resourcePath, Cogs::FileHandle::OpenMode::OpenAlways, Cogs::FileHandle::AccessMode::Read);
1523 LOG_ERROR(logger,
"Could not open file %s for mapping.", loadInfo.
resourcePath.c_str());
1527 size_t size = Cogs::IO::fileSize(file);
1529 LOG_ERROR(logger,
"File size invalid: %zd.", size);
1533 const uint8_t* ptr =
static_cast<const uint8_t*
>(Cogs::IO::mapFile(file, Cogs::FileHandle::ProtectionMode::ReadOnly, 0, size));
1535 LOG_ERROR(logger,
"Could not map file %s for reading model data.", loadInfo.
resourcePath.c_str());
1539 contents = std::make_unique<Cogs::MMapBackedFileContents>(ptr, size, file, loadInfo.
resourcePath, Cogs::FileContentsHints::None);
1543 double ioElapsed = ioTimer.elapsedSeconds();
1545 bool rv = load(context, loadInfo, std::move(contents));
1547 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.
PrimitiveType
Primitive types for interpreting vertex data sent to the graphics pipeline.
@ PointList
List of points.
@ TriangleStrip
Triangle strip.
@ TriangleStripAdjacency
Triangle strip with adjacency.
@ LineStripAdjacency
Line strip with adjacency.
@ LineListAdjacency
List of lines with adjacency.
@ TriangleListAdjacency
List of triangles with adjacency.
@ TriangleList
List of triangles.
@ 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.
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.