Cogs.Core
ModelLoader.cpp
1#include "Context.h"
2#include "ModelLoader.h"
3#include "CogsBin.h"
4
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"
13
14#include "Platform/ResourceBufferBackedFileContents.h"
15
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"
23
24#include "zstd.h"
25#include <span>
26#include <type_traits>
27
28// Use of sub-tasks for loading will be disabled when more than the
29// following number of models are currently in flight...
30// Increasing this number could lead to a stack overflow if many
31// models are being loaded concurrently.
32#define COGS_MODELLOADER_MAX_TASKS 20
33
34//#pragma optimize( "", off )
35
36#ifndef EMSCRIPTEN
37// Toggle using memory mapped IO when reading file.
38#define COGS_USE_MMAP
39#endif
40
41// NOTE (chrisdy): I've tried to use asserts on errors resulting from bugs/illegal usage from cogs code,
42// But illegal data in file should only produce errors and bail out.
43
44namespace
45{
46 using namespace Cogs::Core;
47 Cogs::Logging::Log logger = Cogs::Logging::getLogger("ModelLoader");
48 std::atomic<uint32_t> loadCount(0);
49
50 template<typename T>
51 struct TypedView
52 {
53 const T* base = nullptr;
54 size_t count = 0;
55
56 const T& operator[](size_t i) const { assert(i < count); return base[i]; }
57 };
58
59 template<typename T>
60 constexpr bool isValidIndex(T v)
61 {
62 static_assert(std::is_integral_v<T>);
63 return v != T(-1);
64 }
65
66 struct ReadContext
67 {
68 Context* context = nullptr;
69 std::unique_ptr<Cogs::FileContents> contents;
70 Cogs::Core::TaskId group = NoTask;
71 std::string path;
72 uint32_t version = 0;
73 bool success = false;
74
75 CogsBin::Header* header = nullptr;
76 std::span<CogsBin::SectionInfo> sectionInfo;
77 std::vector<const uint8_t*> sectionPtr;
78 std::unique_ptr<Cogs::Mutex[]> sectionLocks;
79 Cogs::Mutex buffersMutex;
80
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;
101
102 std::vector<ResourceBufferHandle> bufferCache;
103 std::vector<TextureHandle> textureCache;
104
105 std::list<std::unique_ptr<uint8_t[]>> allocations; // we should have an arena here.
106 };
107
108 Cogs::PrimitiveType translatePrimitiveType(ReadContext& rctx, CogsBin::PrimitiveType primitiveType)
109 {
110 switch (primitiveType) {
111 case CogsBin::PrimitiveType::TriangleList: return Cogs::PrimitiveType::TriangleList; break;
112 case CogsBin::PrimitiveType::TriangleStrip: return Cogs::PrimitiveType::TriangleStrip; break;
113 case CogsBin::PrimitiveType::LineList: return Cogs::PrimitiveType::LineList; break;
114 case CogsBin::PrimitiveType::LineStrip: return Cogs::PrimitiveType::LineStrip; break;
115 case CogsBin::PrimitiveType::PointList: return Cogs::PrimitiveType::PointList; break;
116 case CogsBin::PrimitiveType::TriangleListAdjacency: return Cogs::PrimitiveType::TriangleListAdjacency; break;
117 case CogsBin::PrimitiveType::TriangleStripAdjacency: return Cogs::PrimitiveType::TriangleStripAdjacency; break;
118 case CogsBin::PrimitiveType::LineListAdjacency: return Cogs::PrimitiveType::LineListAdjacency; break;
119 case CogsBin::PrimitiveType::LineStripAdjacency: return Cogs::PrimitiveType::LineStripAdjacency; break;
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;
124 default:
125 break;
126 }
127 rctx.success = false;
128 LOG_ERROR(logger, "Illegal primitive type: %u", unsigned(primitiveType));
130 }
131
132 const uint8_t* sectionPointer(ReadContext& rctx, uint32_t index)
133 {
134 // FIXME (chrisdy): Should we leave this one around indefinitely?
135 thread_local ZSTD_DCtx* zstd_dctx = nullptr;
136
137 assert(index < rctx.header->sectionCount);
138
139 Cogs::LockGuard lock(rctx.sectionLocks[index]);
140 const auto & sectionInfo = rctx.sectionInfo[index];
141 if (rctx.sectionPtr[index] == nullptr) {
142 //LOG_DEBUG(logger, "%zx Resolving section %u (compr=%d, size=%zd, fileOffset=%zu, fileSize=%zu)",
143 // std::hash<std::thread::id>{}(std::this_thread::get_id()),
144 // index,
145 // sectionInfo.compression,
146 // size_t(sectionInfo.uncompressedSize),
147 // size_t(sectionInfo.fileOffset),
148 // size_t(sectionInfo.fileSize));
149 switch (rctx.sectionInfo[index].compression)
150 {
151 case CogsBin::Compression::None:
152 rctx.sectionPtr[index] = rctx.contents->ptr + rctx.sectionInfo[index].fileOffset;
153 break;
154 case CogsBin::Compression::ZSTD: {
155 if (zstd_dctx == nullptr) {
156 zstd_dctx = ZSTD_createDCtx();
157 }
158
159 // Allocate mem for uncompressed data. Clamp it to minimum 1 bytes so we don't get a nullptr
160 // for empty sections, as we use a null pointer to flag that something has gone horribly
161 // wrong and we give up.
162 rctx.allocations.emplace_back(new uint8_t[sectionInfo.uncompressedSize ? sectionInfo.uncompressedSize : 1]);
163 rctx.sectionPtr[index] = rctx.allocations.back().get();
164
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));
170 return nullptr;
171 }
172 else if (result != sectionInfo.uncompressedSize) {
173 LOG_ERROR(logger, "Uncompressed data size didn't match size recorded in file.");
174 return nullptr;
175 }
176 break;
177 }
178 default:
179 LOG_ERROR(logger, "Illegal compression flag on section.");
180 return nullptr;
181 }
182 }
183 return rctx.sectionPtr[index];
184 }
185
186 Cogs::StringView getString(ReadContext& rctx, uint32_t ix)
187 {
188 if (ix < rctx.strings.count) {
189 auto & str = rctx.strings[ix];
190 Cogs::StringView rv(rctx.stringData.base + str.offset, str.length);
191 //LOG_DEBUG(logger, "Retrieved string %.*s", StringViewFormat(rv));
192 return rv;
193 }
194 else if (!isValidIndex(ix)) {
195 return std::string_view();
196 }
197 else {
198 LOG_ERROR(logger, "Invalid string index %u", ix);
199 rctx.success = false;
200 return Cogs::StringView();
201 }
202 }
203
204 const Cogs::Geometry::BoundingBox& getBoundingBox(ReadContext& rctx, uint32_t ix)
205 {
206 if (ix < rctx.boundingBoxes.count) {
207 return rctx.boundingBoxes[ix];
208 }
209 else {
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>();
213 return empty;
214 }
215 }
216
217 Cogs::TextureFormat getTextureFormat(ReadContext& /*rctx*/, CogsBin::Format format)
218 {
219 switch (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;
302 default:
303 assert(false && "Illegal format");
304 break;
305 }
306 return Cogs::TextureFormat::Unknown;
307 }
308
309 Cogs::DataFormat decodeDataFormat(ReadContext& rctx, CogsBin::Format fmt)
310 {
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;
402 }
403 }
404 else {
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;
539 }
540 }
541 }
542
543
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;
558 default:
559 assert(false && "Illegal texture dimension");
560 break;
561 }
562 return Cogs::ResourceDimensions::Unknown;
563 }
564
565 Cogs::SamplerState::AddressMode getTextureAddressMode(CogsBin::TextureAddressMode addressMode)
566 {
567 switch (addressMode) {
568 case CogsBin::TextureAddressMode::Clamp: return Cogs::SamplerState::Clamp; break;
569 case CogsBin::TextureAddressMode::Wrap: return Cogs::SamplerState::Wrap; break;
570 case CogsBin::TextureAddressMode::Mirror: return Cogs::SamplerState::Mirror; break;
571 case CogsBin::TextureAddressMode::Border: return Cogs::SamplerState::Border; break;
572 default:
573 assert(false && "Illegal texture addressing mode");
574 break;
575 }
577 }
578
579 Cogs::SamplerState::FilterMode getTextureFilterMode(CogsBin::TextureFilterMode filterMode)
580 {
581 switch (filterMode) {
582 case CogsBin::TextureFilterMode::MinMagMipPoint: return Cogs::SamplerState::FilterMode::MinMagMipPoint;
583 case CogsBin::TextureFilterMode::MinMagMipLinear: return Cogs::SamplerState::FilterMode::MinMagMipLinear;
584 case CogsBin::TextureFilterMode::ComparisonMinMagMipPoint: return Cogs::SamplerState::FilterMode::ComparisonMinMagMipPoint;
585 case CogsBin::TextureFilterMode::ComparisonMinMagMipLinear: return Cogs::SamplerState::FilterMode::ComparisonMinMagMipLinear;
586 default:
587 assert(false && "Illegal texture addressing mode");
589 }
590 }
591
592 Cogs::VertexFormatHandle getVertexFormat(ReadContext& rctx, uint32_t firstAttribute, uint32_t attributeCount)
593 {
594 const auto * attributes = rctx.vertexAttributes.base + firstAttribute;
595
596 std::vector<Cogs::VertexElement> elements;
597 elements.resize(attributeCount);
598 for (unsigned i = 0; i < attributeCount; i++) {
599 const auto & attribute = attributes[i];
600
601 auto & element = elements[i];
602 element.offset = attribute.offset;
603 element.format = decodeDataFormat(rctx, attribute.format);
604
605 switch (attribute.semantic) {
606 case CogsBin::Semantic::Position: element.semantic = Cogs::ElementSemantic::Position; break;
607 case CogsBin::Semantic::Normal: element.semantic = Cogs::ElementSemantic::Normal; break;
608 case CogsBin::Semantic::Color: element.semantic = Cogs::ElementSemantic::Color; break;
609 case CogsBin::Semantic::TexCoord: element.semantic = Cogs::ElementSemantic::TextureCoordinate; break;
610 case CogsBin::Semantic::Tangent: element.semantic = Cogs::ElementSemantic::Tangent; break;
611 case CogsBin::Semantic::InstanceVector: element.semantic = Cogs::ElementSemantic::InstanceVector; break;
612 case CogsBin::Semantic::InstanceMatrix: element.semantic = Cogs::ElementSemantic::InstanceMatrix; break;
613 default:
614 LOG_ERROR(logger, "Illegal vertex element semantic %u", unsigned(attribute.semantic));
615 return {};
616 }
617 element.semanticIndex = attribute.semanticIndex;
618 element.inputType = attribute.instanceStepRate == 0 ? Cogs::InputType::VertexData : Cogs::InputType::InstanceData;
619 element.instanceStep = attribute.instanceStepRate;
620 }
621
622 return Cogs::VertexFormats::createVertexFormat(elements.data(), elements.size());
623 }
624
625 const uint8_t* resolveDataOffset(ReadContext& rctx, uint64_t offset, uint32_t size)
626 {
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;
632 return nullptr;
633 }
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;
638 return nullptr;
639 }
640 return section + sectionOffset;
641 }
642
643 template<typename D, typename S>
644 void widenAndCopy(std::span<D>& dstSpan, const S* src, uint32_t count)
645 {
646 auto * dst = dstSpan.data();
647 // preserve notzeros. When narrowing in the writer, we check for
648 // *less than*, so an actual value of 256 should trigger uint16_t storage.
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);
653 else *dst++ = D(v);
654 }
655 }
656
657 void populateMesh(ReadContext& rctx, MeshHandle handle, uint32_t index)
658 {
659 const auto & srcMesh = rctx.meshes[index];
660 auto dstMesh = rctx.context->meshManager->lock(handle);
661
662 if (isValidIndex(srcMesh.name)) {
663 dstMesh->setName(getString(rctx, srcMesh.name));
664 }
665 if (isValidIndex(srcMesh.boundingBox)) {
666 dstMesh->setBounds(getBoundingBox(rctx, srcMesh.boundingBox));
667 }
668 if ((srcMesh.flags & CogsBin::MeshFlags::Clockwise) != 0) {
669 dstMesh->setMeshFlag(MeshFlags::ClockwiseWinding);
670 }
671 if ((srcMesh.flags & CogsBin::MeshFlags::Skinned) != 0) {
672 dstMesh->setMeshFlag(MeshFlags::Skinned);
673 }
674
675 dstMesh->primitiveType = translatePrimitiveType(rctx, srcMesh.primitiveType);
676
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];
681
682 auto & dstStream = dstMesh->streams[i];
683
684 {
685 Cogs::LockGuard lock(rctx.buffersMutex);
686 assert(srcStream.buffer < rctx.buffers.count);
687
688 if (rctx.bufferCache[srcStream.buffer]) {
689 dstStream.buffer = rctx.bufferCache[srcStream.buffer];
690 } else {
691 auto & dstBuffer = rctx.bufferCache[srcStream.buffer] = rctx.context->bufferManager->create();
692 dstStream.buffer = dstBuffer;
693
694 const auto & srcBuffer = rctx.buffers[srcStream.buffer];
695 const auto * srcData = resolveDataOffset(rctx, srcBuffer.sectionOffset, srcBuffer.size);
696
697 dstBuffer->reset(srcBuffer.size, rctx.context->memory->resourceAllocator);
698 std::memcpy(dstBuffer->data(), srcData, srcBuffer.size);
699
700 if ((srcBuffer.flags & CogsBin::BufferContentFlags::VertexData) != 0) {
701 dstBuffer->setBindFlags(BufferBindFlags::VertexBuffer);
702 }
703
704 if ((srcBuffer.flags & CogsBin::BufferContentFlags::IndexData) != 0) {
705 dstBuffer->setBindFlags(BufferBindFlags::IndexBuffer);
706 }
707 }
708 }
709
710 dstStream.numElements = srcStream.count;
711 dstStream.type = VertexDataType::EVertexDataType(srcStream.vertexDataType);
712 dstStream.stride = srcStream.stride;
713 dstStream.offset = srcStream.offset;
714
715 dstMesh->streamIndexes[dstStream.type] = uint8_t(i);
716 dstMesh->streamsUpdated |= Mesh::toFlag(dstStream.type);
717 dstMesh->setMeshFlag(MeshFlags::StreamsChanged);
718
719 if (srcStream.vertexDataType < VertexDataType::LastVertexType) {
720 dstStream.format = isValidIndex(srcStream.firstAttribute)
721 ? getVertexFormat(rctx, srcStream.firstAttribute, srcStream.attributeCount)
723
724 if (!dstStream.format) {
725 LOG_ERROR(logger, "Stream %zu has illegal format", i);
726 return;
727 }
728
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);
735 break;
736 default:
737 break;
738 }
739 }
740 } else if (srcStream.vertexDataType == VertexDataType::Indexes) {
741 dstMesh->setCount(srcStream.count);
742 dstMesh->setMeshFlag(MeshFlags::Indexed);
743 dstMesh->setMeshFlag(MeshFlags::IndexesChanged);
744 } else if (srcStream.vertexDataType == VertexDataType::SubMeshes) {
745 dstMesh->submeshCount = (uint16_t)srcStream.count;
746 }
747 }
748 }
749
750
751 template<typename T>
752 const T& getPropertyValue(ReadContext& rctx, const CogsBin::Property& prop)
753 {
754 if constexpr (sizeof(T) <= sizeof(uint32_t)) {
755 return *(const T*)(&prop.value);
756 }
757 else {
758 if (prop.value < rctx.propData.count) {
759 return *(const T*)(rctx.propData.base + prop.value);
760 }
761 else {
762 LOG_ERROR(logger, "Illegal property data offset %u", prop.value);
763 static T t = {};
764 return t;
765 }
766 }
767 }
768
769 TextureHandle populateEmbeddedTexture(ReadContext& rctx, uint32_t textureIx)
770 {
771 assert(textureIx < rctx.embeddedTextures.count);
772 if (auto handle = rctx.textureCache[textureIx]; HandleIsValid(handle)) {
773 return handle;
774 }
775 const auto & tex = rctx.embeddedTextures[textureIx];
776
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;
780
781 TextureLoadInfo * loadInfo = rctx.context->textureManager->createLoadInfo();
782
783 loadInfo->resourceId = (uint32_t)NoResourceId;
784 //loadInfo.resourcePath;
785 if (isValidIndex(tex.name)) {
786 loadInfo->resourceName = getString(rctx, tex.name).to_string();
787 }
788 loadInfo->resourceData.assign(bufferData, bufferData + tex.size);
789 //loadInfo.resourceFlags;
790 //loadInfo.handle;
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;
797 //loadInfo.flip = 0;
798
799 // Setting loadInfo->addressMode has no effect.
800
801 auto handle = rctx.context->textureManager->loadTexture(loadInfo);
802
803 rctx.textureCache[textureIx] = handle;
804
805 return handle;
806 }
807
808 MaterialInstanceHandle populateMaterialInstance(ReadContext& rctx, uint32_t materialInstanceIx)
809 {
810 const auto & srcMaterialInstance = rctx.materialInstances[materialInstanceIx];
811 if (!isValidIndex(srcMaterialInstance.material)) {
812 LOG_ERROR(logger, "Material instance without material.");
813 rctx.success = false;
815 }
816
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;
822 }
823
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;
829 }
830 //LOG_DEBUG(logger, "Instancing material %.*s:", StringViewFormat(materialName));
831
832 auto material = rctx.context->materialInstanceManager->createMaterialInstance(materialTemplate);
833
834 if (isValidIndex(srcMaterialInstance.permutation)) {
835 material->setPermutation(getString(rctx, srcMaterialInstance.permutation));
836 }
837
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;
843 }
844
845 auto & prop = rctx.props[srcMaterialInstance.propertyFirst + i];
846 switch (prop.keyType) {
847 case CogsBin::PropertyKeyType::Index:
848 assert(false && "FIXME");
849 break;
850
851 case CogsBin::PropertyKeyType::String: {
852
853 auto keyString = getString(rctx, prop.key);
854 switch (prop.valueType) {
855
856 case CogsBin::PropertyValueType::Bool:
857 if (auto key = materialTemplate->getBoolKey(keyString); key != NoProperty)
858 material->setBoolProperty(key, getPropertyValue<uint32_t>(rctx, prop));
859 else
860 LOG_ERROR(logger, "Invalid bool key %.*s", StringViewFormat(keyString));
861 break;
862
863 case CogsBin::PropertyValueType::UInt:
864 if (auto key = materialTemplate->getUIntKey(keyString); key != NoProperty)
865 material->setUIntProperty(key, getPropertyValue<uint32_t>(rctx, prop));
866 else
867 LOG_ERROR(logger, "Invalid uint key %.*s", StringViewFormat(keyString));
868 break;
869
870 case CogsBin::PropertyValueType::Float:
871 if (auto key = materialTemplate->getFloatKey(keyString); key != NoProperty)
872 material->setFloatProperty(key, getPropertyValue<float>(rctx, prop));
873 else
874 LOG_ERROR(logger, "Invalid float key %.*s", StringViewFormat(keyString));
875 break;
876
877 case CogsBin::PropertyValueType::Float2:
878 if (auto key = materialTemplate->getVec2Key(keyString); key != NoProperty)
879 material->setVec2Property(key, getPropertyValue<glm::vec2>(rctx, prop));
880 else
881 LOG_ERROR(logger, "Invalid float2 key %.*s", StringViewFormat(keyString));
882 break;
883
884 case CogsBin::PropertyValueType::Float3:
885 if (auto key = materialTemplate->getVec3Key(keyString); key != NoProperty)
886 material->setVec3Property(key, getPropertyValue<glm::vec3>(rctx, prop));
887 else
888 LOG_ERROR(logger, "Invalid float3 key %.*s", StringViewFormat(keyString));
889 break;
890
891 case CogsBin::PropertyValueType::Float4:
892 if (auto key = materialTemplate->getVec4Key(keyString); key != NoProperty)
893 material->setVec4Property(key, getPropertyValue<glm::vec4>(rctx, prop));
894 else
895 LOG_ERROR(logger, "Invalid float4 key %.*s", StringViewFormat(keyString));
896 break;
897
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;
903 }
904 auto textureIx = getPropertyValue<uint32_t>(rctx, prop);
905 assert(textureIx < rctx.externalTextures.count);
906 const CogsBin::ExternalTexture& tex = rctx.externalTextures[textureIx];
907
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);
911 }
912 auto texture = rctx.context->textureManager->loadTexture(sourcePath, NoResourceId, textureFlags);
913 material->setTextureProperty(key, texture);
914
915 assert(tex.samplerState < rctx.samplerStates.count);
916 CogsBin::SamplerState srcSampler = rctx.samplerStates[tex.samplerState];
917 // Currently, just the texture addressing mode is used.
918 material->setTextureAddressMode(key,
919 getTextureAddressMode(srcSampler.addressModeS),
920 getTextureAddressMode(srcSampler.addressModeT),
921 getTextureAddressMode(srcSampler.addressModeW));
922 material->setTextureFilterMode(key, getTextureFilterMode(srcSampler.filter));
923 }
924 else
925 LOG_ERROR(logger, "Invalid string key %.*s", StringViewFormat(keyString));
926 break;
927
928 case CogsBin::PropertyValueType::EmbeddedTexture:
929 if (auto key = materialTemplate->getTextureKey(keyString); key != NoProperty) {
930 auto textureIx = getPropertyValue<uint32_t>(rctx, prop);
931
932 auto texture = populateEmbeddedTexture(rctx, textureIx);
933 material->setTextureProperty(key, texture);
934
935 const CogsBin::EmbeddedTexture& tex = rctx.embeddedTextures[textureIx];
936 assert(tex.samplerState < rctx.samplerStates.count);
937 CogsBin::SamplerState srcSampler = rctx.samplerStates[tex.samplerState];
938 // Currently, just the texture addressing mode is used.
939 material->setTextureAddressMode(key,
940 getTextureAddressMode(srcSampler.addressModeS),
941 getTextureAddressMode(srcSampler.addressModeT),
942 getTextureAddressMode(srcSampler.addressModeW));
943 material->setTextureFilterMode(key, getTextureFilterMode(srcSampler.filter));
944 }
945 break;
946
947 case CogsBin::PropertyValueType::Variant: {
948 auto key = getString(rctx, prop.key);
949 auto val = getString(rctx, prop.value);
950 material->setVariant(key, val);
951 //LOG_DEBUG(logger, "Variant %.*s=%.*s",
952 // StringViewFormat(key),
953 // StringViewFormat(val));
954 break;
955 }
956
957 case CogsBin::PropertyValueType::Option: {
958 auto key = getString(rctx, prop.key);
959 auto val = getString(rctx, prop.value);
960 material->setOption(key, val);
961 //LOG_DEBUG(logger, "Option %.*s=%.*s",
962 // StringViewFormat(key),
963 // StringViewFormat(val));
964 break;
965 }
966
967 default:
968 LOG_ERROR(logger, "Invalid property value type.");
969 rctx.success = false;
971 }
972 break;
973 }
974 default:
975 LOG_ERROR(logger, "Invalid property key type.");
976 rctx.success = false;
978 }
979 }
980 return material;
981
982 }
983
984 template<typename ResourceProxy>
985 void populatePart(ReadContext& rctx, ResourceProxy& model, ModelPart& part, const CogsBin::Node& node)
986 {
987 // parentIndex is populated by caller
988
989 if (isValidIndex(node.boundingBox)) {
990 part.boundsIndex = uint32_t(model->bounds.size());
991 model->bounds.emplace_back(getBoundingBox(rctx, node.boundingBox));
992 }
993 if (isValidIndex(node.transform)) {
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));
999 }
1000 if (isValidIndex(node.name)) {
1001 model->setPartName(part, getString(rctx, node.name));
1002 }
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); });
1008 }
1009 else {
1010 populateMesh(rctx, model->meshes.back(), node.mesh);
1011 }
1012 }
1013 if (isValidIndex(node.materialInstance)) {
1014 part.materialIndex = uint32_t(model->materials.size());
1015 model->materials.emplace_back(populateMaterialInstance(rctx, node.materialInstance));
1016 }
1017 if (node.primitiveType != CogsBin::PrimitiveType::Unknown) {
1018 part.primitiveType = translatePrimitiveType(rctx, node.primitiveType);
1019 }
1020 else {
1021 part.primitiveType = Cogs::PrimitiveType::None;
1022 }
1023 part.startIndex = node.vertexFirst;
1024 part.vertexCount = node.vertexCount;
1025 }
1026
1027 void populateBone(ReadContext& rctx, Bone& dstBone, const uint32_t boneIx, const uint32_t boneCount)
1028 {
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;
1032 return;
1033 }
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;
1040 return;
1041 }
1042 dstBone.parentBone = srcBone.parentBone;
1043 }
1044 else {
1045 dstBone.parentBone = (size_t)-1;
1046 }
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;
1055 }
1056
1057 void populateSkeleton(ReadContext& rctx, Skeleton& dstSkeleton, const uint32_t skeletonIx)
1058 {
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;
1062 return;
1063 }
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;
1070 }
1071 updateSkeletonPose(dstSkeleton);
1072 }
1073
1074 void populateAnimTrack(ReadContext& rctx, AnimationTrack& dstTrack, const uint32_t animTrackIx)
1075 {
1076 assert(animTrackIx < rctx.animTracks.count);
1077 const auto & srcTrack = rctx.animTracks[animTrackIx];
1078
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);
1082
1083 dstTrack.boneIndex = isValidIndex(srcTrack.boneIndex) ? srcTrack.boneIndex : -1;
1084
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++;
1092 }
1093
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++;
1102 }
1103
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++;
1111 }
1112 }
1113
1114 void populateAnimClip(ReadContext& rctx, AnimationClip& dstClip, const uint32_t animClipIx)
1115 {
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;
1119 return;
1120 }
1121 const CogsBin::AnimClip& srcClip = rctx.animClips[animClipIx];
1122 if (isValidIndex(srcClip.name)) {
1123 dstClip.name = std::string(getString(rctx, srcClip.name));
1124 }
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);
1130 }
1131 }
1132
1133 void populateModel(ReadContext& rctx, ResourceHandleBase modelHandle, const uint32_t modelIx)
1134 {
1135 const auto & srcModel = rctx.models[modelIx];
1136 if (srcModel.nodeCount == 0) return;
1137
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");
1141
1142 // Populate skeleton
1143 if (isValidIndex(srcModel.skeleton)) populateSkeleton(rctx, dstModel->skeleton, srcModel.skeleton);
1144
1145 // Populate animation
1146 if (srcModel.animClipCount != 0) {
1147 dstModel->animation = rctx.context->animationManager->create();
1148
1149 auto * anim = dstModel->animation.resolve();
1150 anim->skeleton = dstModel->skeleton; // use model skeleton as animation 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;
1155 }
1156 }
1157
1158 // Populate parts
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;
1164 return;
1165 }
1166 const auto & node = rctx.nodes[srcModel.firstNode + i];
1167 auto & part = dstModel->parts[i];
1168 if (!isValidIndex(node.parent)) {
1169 part.parentIndex = ~0u;
1170 }
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;
1174 return;
1175 }
1176 else {
1177 part.parentIndex = node.parent - srcModel.firstNode;
1178 }
1179 populatePart(rctx, dstModel, part, node);
1180 }
1181 }
1182
1183
1184}
1185
1186bool Cogs::Core::CogsModelLoader::canLoad(Context * /*context*/, const ModelLoadInfo & loadInfo)
1187{
1188 auto extension = IO::extension(loadInfo.resourcePath);
1189
1190 if (extension == ".cogsbin") {
1191 return true;
1192 }
1193
1194 return false;
1195}
1196
1197bool Cogs::Core::CogsModelLoader::load(Context * context, const ModelLoadInfo & loadInfo, std::unique_ptr<FileContents> contents_)
1198{
1199 if (!contents_ || contents_->size < sizeof(CogsBin::Header)) {
1200 return false;
1201 }
1202
1203 ReadContext rctx;
1204 {
1205 const CogsBin::Header* header = (const CogsBin::Header*)contents_->ptr;
1206 if (header->magic == CogsBin::HeaderMagic) {
1207 if(header->version == 1) {
1208 return loadCogsBin1(context, loadInfo, std::move(contents_));
1209 }
1210 else if (header->version == 3) {
1211 return loadCogsBin3(context, loadInfo, std::move(contents_));
1212 }
1213 else if (5 < header->version) {
1214 LOG_ERROR(logger, "Unsupported file format version %u", header->version);
1215 return false;
1216 }
1217 }
1218 else {
1219 LOG_ERROR(logger, "Missing magic value");
1220 return false;
1221 }
1222
1223 rctx.version = header->version;
1224 }
1225 // TODO: Check alignment restrictions for cogsbin2, cogsbin1 handles in its load func.
1226
1227 rctx.context = context;
1228 rctx.contents = std::move(contents_);
1229
1230 if (loadCount.fetch_add(1) < COGS_MODELLOADER_MAX_TASKS) {
1231 rctx.group = context->taskManager->createGroup(TaskManager::ResourceQueue);
1232 }
1233 rctx.path = loadInfo.resourcePath;
1234 rctx.success = true;
1235
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);
1240 }
1241 rctx.path.resize(i);
1242 }
1243
1244 if (rctx.contents->size < sizeof(CogsBin::Header)) {
1245 LOG_ERROR(logger, "Model file too small to contain a header, unable to load.");
1246 return false;
1247 }
1248
1249 rctx.header = (CogsBin::Header *)rctx.contents->ptr;
1250 if (rctx.header->sectionCount == 0) {
1251 LOG_ERROR(logger, "No sections in file.");
1252 return false;
1253 }
1254 if (rctx.header->fileLength != rctx.contents->size) {
1255 LOG_ERROR(logger, "File size mismatch in read context, potentially corrupt or truncated model file.");
1256 return false;
1257 }
1258
1259 rctx.sectionInfo = std::span<CogsBin::SectionInfo>((CogsBin::SectionInfo*)(rctx.contents->ptr + sizeof(CogsBin::Header)),
1260 (CogsBin::SectionInfo*)(rctx.contents->ptr + sizeof(CogsBin::Header)) + rctx.header->sectionCount);
1261 rctx.sectionPtr.resize(rctx.header->sectionCount);
1262 rctx.sectionLocks.reset(new Mutex[rctx.header->sectionCount]);
1263
1264 LOG_TRACE(logger, "Parsed header, %u sections, filesize=%zu", rctx.header->sectionCount, rctx.contents->size);
1265
1266
1267 if ((rctx.sectionInfo[0].type & CogsBin::SectionType::META) == 0) {
1268 LOG_ERROR(logger, "First section is not a meta section.");
1269 return false;
1270 }
1271
1272 const auto * sectionBase = sectionPointer(rctx, 0);
1273 if (sectionBase == nullptr) return false;
1274
1275 for (uint16_t sub = 0; sub < rctx.sectionInfo[0].subSectionCount; sub++) {
1276 const auto & metaSubSection = ((CogsBin::SubSectionInfo*)sectionBase)[sub];
1277 switch (metaSubSection.type)
1278 {
1279 case CogsBin::SubSectionType::Buffers:
1280 rctx.buffers.base = (const CogsBin::Buffer*)(sectionBase + metaSubSection.offset);
1281 rctx.buffers.count = metaSubSection.size / sizeof(CogsBin::Buffer);
1282 rctx.bufferCache.resize(rctx.buffers.count);
1283 //LOG_DEBUG(logger, "Found %zu buffers.", rctx.buffers.count);
1284 break;
1285 case CogsBin::SubSectionType::ExternalTextures:
1286 rctx.externalTextures.base = (const CogsBin::ExternalTexture*)(sectionBase + metaSubSection.offset);
1287 rctx.externalTextures.count = metaSubSection.size / sizeof(CogsBin::ExternalTexture);
1288 //LOG_DEBUG(logger, "Found %zu textures.", rctx.textures.count);
1289 break;
1290 case CogsBin::SubSectionType::EmbeddedTextures:
1291 rctx.embeddedTextures.base = (const CogsBin::EmbeddedTexture*)(sectionBase + metaSubSection.offset);
1292 rctx.embeddedTextures.count = metaSubSection.size / sizeof(CogsBin::EmbeddedTexture);
1293 rctx.textureCache.resize(rctx.embeddedTextures.count);
1294 //LOG_DEBUG(logger, "Found %zu embedded textures.", rctx.embeddedTextures.count);
1295 break;
1296 case CogsBin::SubSectionType::SamplerStates:
1297 rctx.samplerStates.base = (const CogsBin::SamplerState*)(sectionBase + metaSubSection.offset);
1298 rctx.samplerStates.count = metaSubSection.size / sizeof(CogsBin::SamplerState);
1299 //LOG_DEBUG(logger, "Found %zu sampler states.", rctx.samplerStates.count);
1300 break;
1301 case CogsBin::SubSectionType::Strings:
1302 rctx.strings.base = (const CogsBin::String*)(sectionBase + metaSubSection.offset);
1303 rctx.strings.count = metaSubSection.size / sizeof(CogsBin::String);
1304 //LOG_DEBUG(logger, "Found %zu strings.", rctx.strings.count);
1305 break;
1306 case CogsBin::SubSectionType::StringData:
1307 rctx.stringData.base = (char*)(sectionBase + metaSubSection.offset);
1308 rctx.stringData.count = metaSubSection.size;
1309 //LOG_DEBUG(logger, "Found %zu stringData bytes.", rctx.stringData.count);
1310 break;
1311 case CogsBin::SubSectionType::Nodes:
1312 rctx.nodes.base = (const CogsBin::Node*)(sectionBase + metaSubSection.offset);
1313 rctx.nodes.count = metaSubSection.size / sizeof(CogsBin::Node);
1314 //LOG_DEBUG(logger, "Found %zu nodes.", rctx.nodes.count);
1315 break;
1316 case CogsBin::SubSectionType::Transforms:
1317 rctx.transforms.base = (const CogsBin::Transform*)(sectionBase + metaSubSection.offset);
1318 rctx.transforms.count = metaSubSection.size / sizeof(CogsBin::Transform);
1319 //LOG_DEBUG(logger, "Found %zu transforms.", rctx.transforms.count);
1320 break;
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);
1324 //LOG_DEBUG(logger, "Found %zu bounding boxes.", rctx.boundingBoxes.count);
1325 break;
1326 case CogsBin::SubSectionType::MaterialInstances:
1327 rctx.materialInstances.base = (const CogsBin::MaterialInstance*)(sectionBase + metaSubSection.offset);
1328 rctx.materialInstances.count = metaSubSection.size / sizeof(CogsBin::MaterialInstance);
1329 //LOG_DEBUG(logger, "Found %zu material instances.", rctx.materialInstances.count);
1330 break;
1331 case CogsBin::SubSectionType::Properties:
1332 rctx.props.base = (const CogsBin::Property*)(sectionBase + metaSubSection.offset);
1333 rctx.props.count = metaSubSection.size / sizeof(CogsBin::Property);
1334 //LOG_DEBUG(logger, "Found %zu properties.", rctx.props.count);
1335 break;
1336 case CogsBin::SubSectionType::PropertyData:
1337 rctx.propData.base = sectionBase + metaSubSection.offset;
1338 rctx.propData.count = metaSubSection.size;
1339 //LOG_DEBUG(logger, "Found %zu propData bytes.", rctx.propData.count);
1340 break;
1341 case CogsBin::SubSectionType::Meshes:
1342 rctx.meshes.base = (const CogsBin::Mesh*)(sectionBase + metaSubSection.offset);
1343 rctx.meshes.count = metaSubSection.size / sizeof(CogsBin::Mesh);
1344 //LOG_DEBUG(logger, "Found %zu meshes.", rctx.meshes.count);
1345 break;
1346 case CogsBin::SubSectionType::VertexStreams:
1347 rctx.vertexStreams.base = (const CogsBin::VertexStream*)(sectionBase + metaSubSection.offset);
1348 rctx.vertexStreams.count = metaSubSection.size / sizeof(CogsBin::VertexStream);
1349 //LOG_DEBUG(logger, "Found %zu vertex streams.", rctx.vertexStreams.count);
1350 break;
1351 case CogsBin::SubSectionType::VertexAttributes:
1352 rctx.vertexAttributes.base = (const CogsBin::VertexAttribute*)(sectionBase + metaSubSection.offset);
1353 rctx.vertexAttributes.count = metaSubSection.size / sizeof(CogsBin::VertexAttribute);
1354 //LOG_DEBUG(logger, "Found %zu vertex attributes.", rctx.vertexAttributes.count);
1355 break;
1356 case CogsBin::SubSectionType::Bones:
1357 rctx.bones.base = (const CogsBin::Bone*)(sectionBase + metaSubSection.offset);
1358 rctx.bones.count = metaSubSection.size / sizeof(CogsBin::Bone);
1359 //LOG_DEBUG(logger, "Found %zu bones.", rctx.bones.count);
1360 break;
1361 case CogsBin::SubSectionType::Skeletons:
1362 rctx.skeletons.base = (const CogsBin::Skeleton*)(sectionBase + metaSubSection.offset);
1363 rctx.skeletons.count = metaSubSection.size / sizeof(CogsBin::Skeleton);
1364 //LOG_DEBUG(logger, "Found %zu skeletons.", rctx.skeletons.count);
1365 break;
1366 case CogsBin::SubSectionType::AnimTracks:
1367 rctx.animTracks.base = (const CogsBin::AnimTrack*)(sectionBase + metaSubSection.offset);
1368 rctx.animTracks.count = metaSubSection.size / sizeof(CogsBin::AnimTrack);
1369 //LOG_DEBUG(logger, "Found %zu anim tracks.", rctx.animTracks.count);
1370 break;
1371 case CogsBin::SubSectionType::AnimClips:
1372 rctx.animClips.base = (const CogsBin::AnimClip*)(sectionBase + metaSubSection.offset);
1373 rctx.animClips.count = metaSubSection.size / sizeof(CogsBin::AnimClip);
1374 //LOG_DEBUG(logger, "Found %zu anim clips.", rctx.animClips.count);
1375 break;
1376 case CogsBin::SubSectionType::Models:
1377 rctx.models.base = (const CogsBin::Model*)(sectionBase + metaSubSection.offset);
1378 rctx.models.count = metaSubSection.size / sizeof(CogsBin::Model);
1379 //LOG_DEBUG(logger, "Found %zu models.", rctx.models.count);
1380 break;
1381 default:
1382 LOG_ERROR(logger, "Unknown subsection type %u", unsigned(metaSubSection.type));
1383 }
1384 }
1385
1386 // Try to detect problems upfront gracefully
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);
1393 return false;
1394 }
1395 const auto & sectionInfo = rctx.sectionInfo[sectionIx];
1396 if (sectionInfo.uncompressedSize < sectionOffset + buffer.size) {
1397 LOG_ERROR(logger, "Buffer out of bounds");
1398 return false;
1399 }
1400 }
1401
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; }
1415 }
1416
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);
1421 return false;
1422 }
1423 if (dataStream.vertexDataType < VertexDataType::LastVertexType) {
1424 if (!isValidIndex(dataStream.firstAttribute)) {
1425 LOG_ERROR(logger, "Vertex stream without attributes");
1426 return false;
1427 }
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);
1431 return false;
1432 }
1433 } else if (dataStream.vertexDataType == VertexDataType::Indexes) {
1434 if (dataStream.stride != 4 && dataStream.stride != 2) {
1435 LOG_ERROR(logger, "Index stream has unsupported stride.");
1436 return false;
1437 }
1438 }
1439
1440 if (!isValidIndex(dataStream.buffer)) {
1441 LOG_ERROR(logger, "Data stream without valid buffer.");
1442 return false;
1443 }
1444 }
1445
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);
1450 return false;
1451 }
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.");
1455 return false;
1456 }
1457 if (buffer.size < track.rotationOffset + 5 * sizeof(float)*track.rotationCount) {
1458 LOG_ERROR(logger, "Anim track translation buffer view is outside buffer.");
1459 return false;
1460 }
1461 if (buffer.size < track.scaleOffset + 4 * sizeof(float)*track.scaleCount) {
1462 LOG_ERROR(logger, "Anim track translation buffer view is outside buffer.");
1463 return false;
1464 }
1465 }
1466
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);
1471 return false;
1472 }
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);
1475 return false;
1476 }
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);
1479 return false;
1480 }
1481 }
1482
1483 if (modelIx < rctx.models.count) {
1484 populateModel(rctx, loadInfo.handle, modelIx);
1485 }
1486 else {
1487 LOG_ERROR(logger, "Invalid model index %u (model count=%zu)", modelIx, rctx.models.count);
1488 rctx.success = false;
1489 }
1490
1491 if (rctx.group != NoTask) {
1492 // wait here before we release the memory mapping.
1493 context->taskManager->wait(rctx.group);
1494 }
1495 loadCount--;
1496
1497 return rctx.success;
1498}
1499
1500
1501bool Cogs::Core::CogsModelLoader::load(Context * context, const ModelLoadInfo & loadInfo)
1502{
1503 LOG_DEBUG(logger, "Loading model: %s", loadInfo.resourceName.c_str());
1504
1505 Cogs::Timer ioTimer = Timer::startNew();
1506 Cogs::Timer timer = Timer::startNew();
1507
1508 std::unique_ptr<Cogs::FileContents> contents;
1509#ifdef COGS_USE_MMAP
1510 if (loadInfo.protocol == ResourceProtocol::Archive) {
1511#endif
1512 ResourceBuffer buffer = context->resourceStore->getResourceContents(loadInfo.resourcePath);
1513 if (!buffer.buffer->data()) {
1514 LOG_ERROR(logger, "Could not load resource data for model %s.", loadInfo.resourcePath.c_str());
1515 return false;
1516 }
1517 contents = std::make_unique<Cogs::Platform::ResourceBufferBackedFileContents>(buffer, loadInfo.resourcePath, Cogs::FileContentsHints::None);
1518#ifdef COGS_USE_MMAP
1519 }
1520 else {
1521 Cogs::FileHandle::Ptr file = Cogs::IO::openFile(loadInfo.resourcePath, Cogs::FileHandle::OpenMode::OpenAlways, Cogs::FileHandle::AccessMode::Read);
1522 if (!file) {
1523 LOG_ERROR(logger, "Could not open file %s for mapping.", loadInfo.resourcePath.c_str());
1524 return false;
1525 }
1526
1527 size_t size = Cogs::IO::fileSize(file);
1528 if (!size) {
1529 LOG_ERROR(logger, "File size invalid: %zd.", size);
1530 return false;
1531 }
1532
1533 const uint8_t* ptr = static_cast<const uint8_t*>(Cogs::IO::mapFile(file, Cogs::FileHandle::ProtectionMode::ReadOnly, 0, size));
1534 if (!ptr) {
1535 LOG_ERROR(logger, "Could not map file %s for reading model data.", loadInfo.resourcePath.c_str());
1536 return false;
1537 }
1538
1539 contents = std::make_unique<Cogs::MMapBackedFileContents>(ptr, size, file, loadInfo.resourcePath, Cogs::FileContentsHints::None);
1540 }
1541#endif
1542
1543 double ioElapsed = ioTimer.elapsedSeconds();
1544
1545 bool rv = load(context, loadInfo, std::move(contents));
1546
1547 LOG_TRACE(logger, "Elapsed: %f (IO: %f)", timer.elapsedSeconds(), ioElapsed);
1548
1549 return rv;
1550}
1551
1552
1553// #pragma optimize( "", on )
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
std::unique_ptr< class TaskManager > taskManager
TaskManager service instance.
Definition: Context.h:186
std::unique_ptr< class ResourceStore > resourceStore
ResourceStore service instance.
Definition: Context.h:210
static constexpr TaskQueueId ResourceQueue
Resource task queue.
Definition: TaskManager.h:232
Log implementation class.
Definition: LogManager.h:140
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
Old timer class.
Definition: Timer.h:37
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
Definition: LogManager.h:181
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
@ InstanceData
Per instance data.
@ VertexData
Per vertex data.
PrimitiveType
Primitive types for interpreting vertex data sent to the graphics pipeline.
Definition: Common.h:112
@ PointList
List of points.
@ TriangleStrip
Triangle strip.
@ LineList
List of lines.
@ TriangleStripAdjacency
Triangle strip with adjacency.
@ LineStripAdjacency
Line strip with adjacency.
@ LineListAdjacency
List of lines with adjacency.
@ TriangleListAdjacency
List of triangles with adjacency.
@ LineStrip
Line strip.
@ TriangleList
List of triangles.
@ Position
Position semantic.
@ Tangent
Tangent semantic.
@ Normal
Normal semantic.
@ InstanceMatrix
Instance matrix semantic.
@ InstanceVector
Instance vector semantic.
@ Color
Color semantic.
@ TextureCoordinate
Texture coordinate semantic.
uint32_t boneIndex
Specifies which bone of a skeleton that is animated by this track.
Definition: Animation.h:38
@ VertexBuffer
Buffer can be bound as vertex buffer.
Definition: Buffer.h:40
@ IndexBuffer
Buffer can be bound as index buffer.
Definition: Buffer.h:42
uint32_t name
Offset into strings subsection of current section.
Definition: CogsBin.h:765
Generic blob of data.
Definition: CogsBin.h:515
uint32_t size
Byte size of image data.
Definition: CogsBin.h:646
uint32_t offset
Byte offset within buffer for start of imagte data.
Definition: CogsBin.h:645
uint32_t buffer
Buffer that holds image data, index into buffers.
Definition: CogsBin.h:644
PrimitiveType primitiveType
Primitive type to use for this node.
Definition: CogsBin.h:780
uint32_t name
Name of node, offset into Strings subsection.
Definition: CogsBin.h:775
uint32_t vertexFirst
First vertex of mesh to draw.
Definition: CogsBin.h:781
uint32_t boundingBox
Bounding box of node, offset into BoundingBoxes subsection.
Definition: CogsBin.h:778
uint32_t materialInstance
Material instance of node, offset into MaterialInstances subsection.
Definition: CogsBin.h:777
uint32_t mesh
Mesh of node, offset into Meshes subsection.
Definition: CogsBin.h:776
uint32_t vertexCount
Number of vertices to draw.
Definition: CogsBin.h:782
uint32_t parent
Parent node, offset into Nodes subsection.
Definition: CogsBin.h:774
uint32_t transform
Transform of node, offset into Transforms subsection.
Definition: CogsBin.h:779
TextureAddressMode addressModeW
Specifies the addressing mode along the W axis in texture coordinate space.
Definition: CogsBin.h:602
TextureFilterMode filter
Specifies the filter to use for texture sampling.
Definition: CogsBin.h:604
TextureAddressMode addressModeS
Specifies the addressing mode along the S axis in texture coordinate space.
Definition: CogsBin.h:600
TextureAddressMode addressModeT
Specifies the addressing mode along the T axis in texture coordinate space.
Definition: CogsBin.h:601
@ StreamsChanged
One or more of the data streams in the mesh changed.
Definition: Mesh.h:59
@ IndexesChanged
The index data of the mesh changed.
Definition: Mesh.h:61
@ Indexed
The mesh should be drawn indexed, using index data to order the triangle vertexes.
Definition: Mesh.h:65
@ ClockwiseWinding
The mesh uses clockwise winding order for it's triangles as opposed to the counter-clockwise default.
Definition: Mesh.h:63
static constexpr uint16_t toFlag(VertexDataType::EVertexDataType type)
Convert the given type index to a flag.
Definition: Mesh.h:577
std::shared_ptr< Memory::MemoryBuffer > buffer
Actual resource contents. Prefer using access methods.
Definition: ResourceStore.h:61
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.
Definition: TaskManager.h:20
EVertexDataType
Contains data types.
Definition: Mesh.h:26
AddressMode
Addressing modes to use when sampling textures.
Definition: SamplerState.h:15
@ Clamp
Texture coordinates are clamped to the [0, 1] range.
Definition: SamplerState.h:17
@ Border
Texture color is set to the border color when outside [0, 1] range.
Definition: SamplerState.h:23
@ Wrap
Texture coordinates automatically wrap around to [0, 1] range.
Definition: SamplerState.h:19
@ Mirror
Texture coordinates are mirrored when outside [0, 1] range.
Definition: SamplerState.h:21
FilterMode
Filter modes to specify how texture data is treated when sampled.
Definition: SamplerState.h:31
@ ComparisonMinMagMipPoint
Comparison filter for depth sample comparisons using point sampling.
Definition: SamplerState.h:38
@ ComparisonMinMagMipLinear
Comparison filter for depth sample comparisons using linear interpolation sampling.
Definition: SamplerState.h:40
@ MinMagMipPoint
Point sampling for both minification and magnification.
Definition: SamplerState.h:33
@ MinMagMipLinear
Linear sampling for both minification and magnification.
Definition: SamplerState.h:35