Project Alice
Loading...
Searching...
No Matches
xac.cpp
Go to the documentation of this file.
1#include "xac.hpp"
2#include "parsers.hpp"
3#include <cassert>
4
5/*
6==========================================================================================================
7FOR XAC FILES
8https://web.archive.org/web/20140816034951/https://dl.dropboxusercontent.com/u/60681258/xr/xac.txt
9vec3d = float x, float y, float z
10vec4d = float x, float y, float z, float w
11quat = float x, float y, float z, float w
12string = uint32 len, char[len]
13matrix44 = vec4d col1, vec4d col2, vec4d col3, vec4d pos
14
15file:
16 byte magic[4] = 58 41 43 20 ("XAC ")
17 byte majorVersion = 1
18 byte minorVersion = 0
19 byte bBigEndian
20 byte multiplyOrder
21
22 chunk[...]
23 int32 chunkType
24 int32 length (sometimes incorrect!)
25 int32 version
26 byte data[length]
27
28chunk 7: metadata (v2)
29 uint32 repositionMask
30 1 = repositionPos
31 2 = repositionRot
32 4 = repositionScale
33 int32 repositioningNode
34 byte exporterMajorVersion
35 byte exporterMinorVersion
36 byte unused[2]
37 float retargetRootOffset
38 string sourceApp
39 string origFileName
40 string exportDate
41 string actorName
42
43chunk B: node hierarchy (v1)
44 int32 numNodes
45 int32 numRootNodes (number of nodes with parentId = -1)
46
47 NodeData[numNodes]
48 quat rotation
49 quat scaleRotation
50 vec3d position
51 vec3d scale
52 float unused[3]
53 int32 -1 (?)
54 int32 -1 (?)
55 int32 parentNodeId (index of parent node or -1 for root nodes)
56 int32 numChildNodes (number of nodes with parentId = this node's index)
57 int32 bIncludeInBoundsCalc
58 matrix44 transform
59 float fImportanceFactor
60 string name
61
62chunk D: material totals (v1)
63 int32 numTotalMaterials
64 int32 numStandardMaterials
65 int32 numFxMaterials
66
67chunk 3: material definition (v2)
68 vec4d ambientColor
69 vec4d diffuseColor
70 vec4d specularColor
71 vec4d emissiveColor
72 float shine
73 float shineStrength
74 float opacity
75 float ior
76 byte bDoubleSided
77 byte bWireframe
78 byte unused
79 byte numLayers
80 string name
81
82 Layer[numLayers]:
83 float amount
84 float uOffset
85 float vOffset
86 float uTiling
87 float vTiling
88 float rotationInRadians
89 int16 materialId (index of the material this layer belongs to = number of preceding chunk 3's)
90 byte mapType
91 byte unused
92 string texture
93
94chunk 1: mesh (v1)
95 int32 nodeId
96 int32 numInfluenceRanges
97 int32 numVertices (total number of vertices of submeshes)
98 int32 numIndices (total number of indices of submeshes)
99 int32 numSubMeshes
100 int32 numAttribLayers
101 byte bIsCollisionMesh (each node can have 1 visual mesh and 1 collision mesh)
102 byte pad[3]
103
104 VerticesAttribute[numAttribLayers]
105 int32 type (determines meaning of data)
106 0 = positions (vec3d)
107 1 = normals (vec3d)
108 2 = tangents (vec4d)
109 3 = uv coords (vec2d)
110 4 = 32-bit colors (uint32)
111 5 = influence range indices (uint32) - index into the InfluenceRange[] array of chunk 2, indicating the bones that affect it
112 6 = 128-bit colors
113
114 typically: 1x positions, 1x normals, 2x tangents, 2x uv, 1x colors, 1x influence range indices
115 int32 attribSize (size of 1 attribute, for 1 vertex)
116 byte bKeepOriginals
117 byte bIsScaleFactor
118 byte pad[2]
119 byte data[numVertices * attribSize]
120
121 SubMesh[numSubMeshes]
122 int32 numIndices
123 int32 numVertices
124 int32 materialId
125 int32 numBones
126 int32 relativeIndices[numIndices] (actual index = relative index + total number of vertices of preceding submeshes. each group of 3 sequential indices (vertices) defines a polygon)
127 int32 boneIds[numBones] (unused)
128
129chunk 2: skinning (v3)
130 int32 nodeId
131 int32 numLocalBones (number of distinct boneId's in InfluenceData)
132 int32 numInfluences
133 byte bIsForCollisionMesh
134 byte pad[3]
135
136 InfluenceData[numInfluences]
137 float fWeight (0..1) (for every vertex, the resulting transformed position is calculated for every influencing bone;
138 int16 boneId the final position is the weighted average of these positions using fWeight as weight)
139 byte pad[2]
140
141 InfluenceRange[bIsForCollisionMesh ? nodes[nodeId].colMesh.numInfluenceRanges : nodes[nodeId].visualMesh.numInfluenceRanges]
142 int32 firstInfluenceIndex (index into InfluenceData)
143 int32 numInfluences (number of InfluenceData entries relevant for one or more vertices, starting at firstInfluenceIndex)
144
145chunk C: morph targets (v1)
146 int32 numMorphTargets
147 int32 lodMorphTargetIdx (presumably always 0; this is the index of a *collection* of numMorphTargets morph targets, not an
148 individual target, and an EmoActor only has one such collection)
149
150 MorphTarget[numMorphTargets]
151 float fRangeMin (at runtime, fMorphAmount must be >= fRangeMin)
152 float fRangeMax (at runtime, fMorphAmount must be <= fRangeMax)
153 int32 lodLevel (LOD of visual mesh; presumably always 0)
154 int32 numDeformations
155 int32 numTransformations
156 int32 phonemeSetBitmask (indicates which phonemes the morph target can be used for - facial animation)
157 0x1: neutral
158 0x2: M, B, P, X
159 0x4: AA, AO, OW
160 0x8: IH, AE, AH, EY, AY, H
161 0x10: AW
162 0x20: N, NG, CH, J, DH, D, G, T, K, Z, ZH, TH, S, SH
163 0x40: IY, EH, Y
164 0x80: UW, UH, OY
165 0x100: F, V
166 0x200: L, EL
167 0x400: W
168 0x800: R, ER
169
170 string name
171
172 Deformation[numDeformations]
173 int32 nodeId
174 float fMinValue
175 float fMaxValue
176 int32 numVertices
177 DeformVertex16 positionOffsets[numVertices]
178 uint16 x (fXOffset = fMinValue + (fMaxValue - fMinValue)*(x / 65535); vecDeformedPos.fX = vecPos.fX + fXOffset*fMorphAmount)
179 uint16 y
180 uint16 z
181 DeformVertex8 normalOffsets[numVertices]
182 byte x (fXOffset = x/127.5 - 1.0; vecDeformedNormal.fX = vecNormal.fX + fXOffset * fMorphAmount)
183 byte y
184 byte z
185 DeformVertex8 tangentOffsets[numVertices] (offsets for first tangent)
186 uint32 vertexIndices[numVertices] (index of the node's visual mesh vertex which the offsets apply to)
187
188 Transformation[numTransformations] (appears to be unused, i.e. numTransformations = 0)
189 int32 nodeId
190 quat rotation
191 quat scaleRotation
192 vec3d pos
193 vec3d scale
194
195==========================================================================================================
196FOR XSM FILES
197https://web.archive.org/web/20140816034945/https://dl.dropboxusercontent.com/u/60681258/xr/xsm.txt
198vec3d = float x, float y, float z
199quat16 = int16 x, int16 y, int16 z, int16 w; fX = x / 32767
200string = uint32 len, char[len]
201
202file:
203 byte magic[4] = 58 53 4D 20 ("XSM ")
204 byte majorVersion = 1
205 byte minorVersion = 0
206 byte bBigEndian
207 byte pad
208
209 chunk[...]
210 int32 chunkType
211 int32 length
212 int32 version
213 byte data[length]
214
215chunk C9: metadata (v2)
216 float unused = 1.0f
217 float fMaxAcceptableError
218 int32 fps
219 byte exporterMajorVersion
220 byte exporterMinorVersion
221 byte pad[2]
222 string sourceApp
223 string origFileName
224 string exportDate
225 string motionName
226
227chunk CA: bone animation (v2)
228 int32 numSubMotions
229 SkeletalSubMotion[numSubMotions]:
230 quat16 poseRot
231 quat16 bindPoseRot
232 quat16 poseScaleRot
233 quat16 bindPoseScaleRot
234 vec3D posePos
235 vec3D poseScale
236 vec3D bindPosePos
237 vec3D bindPoseScale
238 int32 numPosKeys
239 int32 numRotKeys
240 int32 numScaleKeys
241 int32 numScaleRotKeys
242 float fMaxError
243 string nodeName
244
245 // fTime of first item in each array must be 0
246
247 PosKey[numPosKeys]:
248 vec3d pos
249 float fTime
250
251 RotKey[numRotKeys]:
252 quat16 rot
253 float fTime
254
255 ScaleKey[numScaleKeys]:
256 vec3d scale
257 float fTime
258
259 ScaleRotKey[numScaleRotKeys]:
260 quat16 rot
261 float fTime
262*/
263
264namespace emfx {
265const char* parse_xac_cstring(const char* start, const char* end, parsers::error_handler& err) {
266 auto const len = parse_xac_any_binary<uint32_t>(&start, end, err);
267 return start + len;
268}
269
270const char* parse_xac_cstring_nodiscard(std::string& out, const char* start, const char* end, parsers::error_handler& err) {
271 auto const len = parse_xac_any_binary<uint32_t>(&start, end, err);
272 out.resize(size_t(len), '\0');
273 std::memcpy(&out[0], start, size_t(len));
274 out[len] = '\0';
275 return start + len;
276}
277
278const char* parse_xac_metadata_v2(xac_context& context, const char* start, const char* end, parsers::error_handler& err) {
279 auto const mh = parse_xac_any_binary<xac_metadata_chunk_header>(&start, end, err);
280#ifdef XAC_DEBUG
281 std::printf("program-name=%s\n", start + 4);
282#endif
283 start = parse_xac_cstring(start, end, err);
284#ifdef XAC_DEBUG
285 std::printf("workspace-folder-name=%s\n", start + 4);
286#endif
287 start = parse_xac_cstring(start, end, err);
288#ifdef XAC_DEBUG
289 std::printf("edition-or-creation-date=%s\n", start + 4);
290#endif
291 start = parse_xac_cstring(start, end, err);
292#ifdef XAC_DEBUG
293 std::printf("name-of-the-model=%s\n", start + 4);
294#endif
295 start = parse_xac_cstring(start, end, err);
296 return start;
297}
298
299const char* parse_xac_material_block_v1(xac_context& context, const char* start, const char* end, parsers::error_handler& err) {
300 auto const mh = parse_xac_any_binary<xac_material_block_v1_chunk_header>(&start, end, err);
301#ifdef XAC_DEBUG
302 std::printf("NumStd=%u,NumFx=%u\n", mh.num_standard_materials, mh.num_fx_materials);
303#endif
304 context.max_standard_materials = mh.num_standard_materials;
305 context.max_fx_materials = mh.num_fx_materials;
306 return start;
307}
308
309const char* parse_xac_material_v2(xac_context& context, const char* start, const char* end, parsers::error_handler& err) {
310 auto const mh = parse_xac_any_binary<xac_material_v2_chunk_header>(&start, end, err);
311 std::string name = "";
312 start = parse_xac_cstring_nodiscard(name, start, end, err);
313#ifdef XAC_DEBUG
314 std::printf("Name=%s,NumLayers=%u,sz=%zu\n", name.c_str(), mh.num_layers, sizeof(xac_material_v2_chunk_header));
315#endif
317 mat.ambient_color = mh.ambient_color;
318 mat.diffuse_color = mh.diffuse_color;
319 mat.double_sided = mh.double_sided;
320 mat.emissive_color = mh.emissive_color;
321 mat.ior = mh.ior;
322 mat.opacity = mh.opacity;
323 mat.shine = mh.shine;
324 mat.shine_strength = mh.shine_strength;
325 mat.specular_color = mh.specular_color;
326 mat.wireframe = mh.wireframe;
327 mat.name = name;
328 for(uint8_t i = 0; i < mh.num_layers; ++i) {
329 auto const mlh = parse_xac_any_binary<xac_material_layer_v2_header>(&start, end, err);
330 std::string layer_name = "";
331 start = parse_xac_cstring_nodiscard(layer_name, start, end, err);
332#ifdef XAC_DEBUG
333 std::printf("Name=%s,sz=%zu+%zu,MapType=%u\n", name.c_str(), sizeof(xac_material_layer_v2_header), name.size(), mlh.map_type);
334#endif
336 layer.amount = mlh.amount;
337 layer.u_offset = mlh.u_offset;
338 layer.v_offset = mlh.v_offset;
339 layer.u_tiling = mlh.u_tiling;
340 layer.v_tiling = mlh.v_tiling;
341 layer.rotation = mlh.rotation;
342 layer.material_id = mlh.material_id;
343 layer.map_type = xac_pp_material_map_type(mlh.map_type);
344 layer.texture = layer_name;
345 mat.layers.push_back(layer);
346 }
347 context.materials.push_back(mat);
348 if(context.materials.size() > context.max_standard_materials) {
349 err.accumulated_errors += "File reports maximum standard materials = " + std::to_string(context.max_standard_materials) + ", but the file defines more materials than that on " + err.file_name + "\n";
350 }
351 // Length does NOT align with the true size of the chunk!
352 context.ignore_length = true;
353 return start;
354}
355
356const char* parse_xac_node_hierachy_v1(xac_context& context, const char* start, const char* end, parsers::error_handler& err) {
357 auto const ch = parse_xac_any_binary<xac_node_hierachy_v1_chunk_header>(&start, end, err);
358 if(int32_t(ch.num_nodes) <= 0) {
359 err.accumulated_errors += "Unexpected number of nodes (on NodeHierachy) on " + err.file_name + "\n";
360 return start;
361 }
362 if(int32_t(ch.num_root_nodes) <= 0) {
363 err.accumulated_errors += "Unexpected number of RootNodes (on NodeHierachy) on " + err.file_name + "\n";
364 return start;
365 }
366 for(uint32_t i = 0; i < ch.num_nodes; i++) {
367 auto const mh = parse_xac_any_binary<xac_node_hierachy_v1_node_header>(&start, end, err);
368 std::string name = "";
369 start = parse_xac_cstring_nodiscard(name, start, end, err);
370#ifdef XAC_DEBUG
371 std::printf(">(Id=%u),Name=%s,IIBC=%x,Imp=%f,ParentId=%i,NumChild=%u,Unk=%x,%x\n", i, name.c_str(), mh.include_in_bounds_calc, mh.importance_factor, mh.parent_id, mh.num_children, mh.unknown[0], mh.unknown[1]);
372#endif
374 node.name = name;
375 node.position = mh.position;
376 node.rotation = mh.rotation;
377 node.scale_rotation = mh.scale_rotation;
378 node.scale = mh.scale;
379 node.transform = mh.transform;
380 node.parent_id = mh.parent_id;
381 if(mh.parent_id == -1) {
382 context.root_nodes.push_back(node);
383 } else {
384 if(size_t(mh.parent_id) >= context.nodes.size()) {
385 err.accumulated_errors += "Specified actor node " + node.name + " before parent " + err.file_name + "\n";
386 return start;
387 }
388 }
389 context.nodes.push_back(node);
390 }
391 return start;
392}
393
394const char* parse_xac_mesh_v1(xac_context& context, const char* start, const char* end, parsers::error_handler& err) {
395 auto const cd = parse_xac_any_binary<xac_mesh_v1_chunk_header>(&start, end, err);
396 if(cd.node_id >= int32_t(context.nodes.size())) {
397 err.accumulated_errors += "Object references OOB node (" + err.file_name + ")\n";
398 return start;
399 }
400#ifdef XAC_DEBUG
401 std::printf("N-AttribLayers=%u\n", cd.num_attribute_layers);
402 std::printf("IsCollision=%u,Pad=%u,%u,%u\n", cd.is_collision_mesh, cd.unused[0], cd.unused[1], cd.unused[2]);
403#endif
404 // Parse vertex blocks
405 xac_pp_actor_mesh obj{};
406 obj.influence_starts.resize(size_t(cd.num_influence_ranges), 0);
407 obj.influence_counts.resize(size_t(cd.num_influence_ranges), 0);
408 for(uint32_t i = 0; i < cd.num_attribute_layers; ++i) {
409 auto const vbh = parse_xac_any_binary<xac_vertex_block_v1_header>(&start, end, err);
410#ifdef XAC_DEBUG
411 std::printf("T=%u,AttribSize=%u,NumVertices=%u,IsKeep=%u,IsScale=%u\n", vbh.ident, vbh.size, cd.num_vertices, vbh.keep_original, vbh.is_scale_factor);
412#endif
413 for(uint32_t j = 0; j < cd.num_vertices; ++j) {
414 switch(xac_vertex_block_v1_type(vbh.ident)) {
416 if(vbh.size != sizeof(xac_vector3f)) {
417 err.accumulated_errors += "Attribute size doesn't match! [normal] (" + err.file_name + ")\n";
418 start += vbh.size;
419 } else {
420 auto const normal = parse_xac_any_binary<xac_vector3f>(&start, end, err);
421 obj.normals.push_back(normal);
422 }
423 break;
425 if(vbh.size != sizeof(xac_vector3f)) {
426 err.accumulated_errors += "Attribute size doesn't match! [vertex] (" + err.file_name + ")\n";
427 start += vbh.size;
428 } else {
429 auto const vertex = parse_xac_any_binary<xac_vector3f>(&start, end, err);
430 obj.vertices.push_back(vertex);
431 }
432 break;
434 if(vbh.size != sizeof(xac_vector2f)) {
435 err.accumulated_errors += "Attribute size doesn't match! [texcoord] (" + err.file_name + ")\n";
436 start += vbh.size;
437 } else {
438 auto const texcoord = parse_xac_any_binary<xac_vector2f>(&start, end, err);
439 obj.texcoords.push_back(texcoord);
440 }
441 break;
443 if(vbh.size != sizeof(xac_vector4f)) {
444 err.accumulated_errors += "Attribute size doesn't match! [weight] (" + err.file_name + ")\n";
445 start += vbh.size;
446 } else {
447 auto const weight = parse_xac_any_binary<xac_vector4f>(&start, end, err);
448 obj.weights.push_back(weight);
449 }
450 break;
452 if(vbh.size != sizeof(uint32_t)) {
453 err.accumulated_errors += "Attribute size doesn't match! [influenceRange] (" + err.file_name + ")\n";
454 start += vbh.size;
455 } else {
456 auto const influence_index = parse_xac_any_binary<uint32_t>(&start, end, err);
457 obj.influence_indices.push_back(influence_index);
458 }
459 break;
460 default:
461 err.accumulated_warnings += "Unknown vertex block type " + std::to_string(vbh.ident) + " on " + err.file_name + "\n";
462 start += vbh.size;
463 break;
464 }
465 }
466 }
467 uint32_t vertex_offset = 0;
468 for(uint32_t i = 0; i < cd.num_sub_meshes; i++) {
469 auto const smh = parse_xac_any_binary<xac_submesh_v1_header>(&start, end, err);
470#ifdef XAC_DEBUG
471 std::printf("SubObj,NumInd=%u,NumVert=%u,NumBone=%u\n", smh.num_indices, smh.num_vertices, smh.num_bones);
472#endif
473 if((int32_t(smh.num_indices) % 3) != 0) {
474 err.accumulated_warnings += "Indices not divisible by 3 " + std::to_string(smh.num_indices) + " (" + err.file_name + ")\n";
475 }
476 if(int32_t(smh.num_indices) < 0) {
477 err.accumulated_warnings += "Invalid number of indices " + std::to_string(smh.num_indices) + " (" + err.file_name + ")\n";
478 }
479 if(int32_t(smh.num_bones) < 0) {
480 err.accumulated_warnings += "Invalid number of bones " + std::to_string(smh.num_bones) + " (" + err.file_name + ")\n";
481 }
483 sub.material_id = smh.material_id;
484 sub.num_vertices = smh.num_vertices;
485 sub.vertex_offset = vertex_offset;
486 for(uint32_t j = 0; j < smh.num_indices; j++) {
487 auto index = parse_xac_any_binary<uint32_t>(&start, end, err);
488 if(index >= smh.num_vertices) {
489 err.accumulated_warnings += "submeshes index oob " + std::to_string(int32_t(index)) + " (" + err.file_name + ")\n";
490 }
491 sub.indices.push_back(index);
492 }
493 for(uint32_t j = 0; j < smh.num_bones; j++) {
494 auto index = parse_xac_any_binary<uint32_t>(&start, end, err);
495 sub.bone_ids.push_back(index);
496 }
497 obj.submeshes.push_back(sub);
498 vertex_offset += smh.num_vertices;
499 }
500 auto& node = context.nodes[cd.node_id];
501 if(cd.is_collision_mesh) {
502 if(node.collision_mesh >= 0)
503 err.accumulated_errors += "More than 1 collision object (" + err.file_name + ")\n";
504 //assert(node.meshes.size() < std::numeric_limits<int32_t>::max());
505 node.collision_mesh = int32_t(node.meshes.size());
506 } else {
507 if(node.visual_mesh >= 0)
508 err.accumulated_errors += "More than 1 visual object (" + err.file_name + ")\n";
509 //assert(node.meshes.size() < std::numeric_limits<int32_t>::max());
510 node.visual_mesh = int32_t(node.meshes.size());
511 }
512 //
513 if(vertex_offset != cd.num_vertices) {
514 err.accumulated_warnings += "Object total meshes doesn't add up to subojects " + std::to_string(vertex_offset) + " != " + std::to_string(cd.num_vertices) + " (" + err.file_name + ")\n";
515 }
516 node.meshes.push_back(obj);
517 return start;
518}
519
520const char* parse_xac_skinning_v3(xac_context& context, const char* start, const char* end, parsers::error_handler& err) {
521 auto const sh = parse_xac_any_binary<xac_skinning_v3_chunk_header>(&start, end, err);
522#ifdef XAC_DEBUG
523 std::printf("NInfluences=%u\n", sh.num_influences);
524#endif
525 std::vector<xac_skinning_v3_influence_entry> influence_data;
526 for(uint32_t i = 0; i < sh.num_influences; i++) {
527 auto const influence = parse_xac_any_binary<xac_skinning_v3_influence_entry>(&start, end, err);
528 influence_data.push_back(influence);
529 }
530 if(sh.node_id >= int32_t(context.nodes.size())) {
531 err.accumulated_errors += "Referencing a node in bone data which is OOB (" + err.file_name + ")\n";
532 return start;
533 } else if(sh.node_id < 0) {
534 err.accumulated_errors += "Bone with no associated node (" + err.file_name + ")\n";
535 return start;
536 }
537 //
538 auto& node = context.nodes[sh.node_id];
539 if(sh.is_for_collision_mesh) {
540 if(node.collision_mesh >= 0) {
541 auto& obj = node.meshes[node.collision_mesh];
542 for(const auto& influence : influence_data) {
543 xac_pp_bone_influence bone_influence{};
544 bone_influence.weight = influence.weight;
545 bone_influence.bone_id = influence.bone_id;
546 obj.influences.push_back(bone_influence);
547 }
548 for(uint32_t i = 0; i < uint32_t(obj.influence_starts.size()); i++) {
549 auto const range = parse_xac_any_binary<xac_skinning_v3_influence_range>(&start, end, err);
550 obj.influence_starts[i] = range.first_influence_index;
551 obj.influence_counts[i] = range.num_influences;
552 }
553 } else {
554 err.accumulated_errors += "Collision mesh not defined for \"" + node.name + "\" (" + err.file_name + ")\n";
555 return start;
556 }
557 } else {
558 if(node.visual_mesh >= 0) {
559 auto& obj = node.meshes[node.visual_mesh];
560 for(const auto& influence : influence_data) {
561 xac_pp_bone_influence bone_influence{};
562 bone_influence.weight = influence.weight;
563 bone_influence.bone_id = influence.bone_id;
564 obj.influences.push_back(bone_influence);
565 }
566 for(uint32_t i = 0; i < uint32_t(obj.influence_starts.size()); i++) {
567 auto const range = parse_xac_any_binary<xac_skinning_v3_influence_range>(&start, end, err);
568 obj.influence_starts[i] = range.first_influence_index;
569 obj.influence_counts[i] = range.num_influences;
570 }
571 } else {
572 err.accumulated_errors += "Visual mesh not defined for \"" + node.name + "\" (" + err.file_name + ")\n";
573 return start;
574 }
575 }
576 return start;
577}
578
579void parse_xac(xac_context& context, const char* start, const char* end, parsers::error_handler& err) {
580 const char* file_start = start;
581 auto const h = parse_xac_any_binary<xac_header>(&start, end, err);
582 if(h.ident[0] != uint8_t('X') || h.ident[1] != uint8_t('A') || h.ident[2] != uint8_t('C') || h.ident[3] != uint8_t(' ')) {
583 err.accumulated_errors += "Invalid XAC identifier on " + err.file_name + "\n";
584 return;
585 }
586#ifdef XAC_DEBUG
587 std::printf("XacFile-> version %u.%u, totalSize=%u\n", h.major_version, h.minor_version, uint32_t(end - start));
588#endif
589 while(start < end) {
590 auto const ch = parse_xac_any_binary<xac_chunk_header>(&start, end, err);
591#ifdef XAC_DEBUG
592 std::printf(">>> Id=%u,ChunkVersion=%u(Len=%u)\n", ch.ident, ch.version, ch.len);
593#endif
594 context.ignore_length = false; // Reset
595 const char* expected = start + ch.len;
596 switch(xac_chunk_type(ch.ident)) {
598 if(ch.version == 1) {
599 start = parse_xac_mesh_v1(context, start, end, err);
600 } else {
601 err.accumulated_errors += "unsupported version " + err.file_name + "\n";
602 }
603 break;
605 if(ch.version == 2) {
606 start = parse_xac_metadata_v2(context, start, end, err);
607 } else {
608 err.accumulated_errors += "unsupported version " + err.file_name + "\n";
609 }
610 break;
612 if(ch.version == 1) {
613 start = parse_xac_material_block_v1(context, start, end, err);
614 } else {
615 err.accumulated_errors += "unsupported version " + err.file_name + "\n";
616 }
617 break;
619 if(ch.version == 2) {
620 start = parse_xac_material_v2(context, start, end, err);
621 } else {
622 err.accumulated_errors += "unsupported version " + err.file_name + "\n";
623 }
624 break;
626 {
627 if(ch.version == 1) {
628 start = parse_xac_node_hierachy_v1(context, start, end, err);
629 } else {
630 err.accumulated_errors += "unsupported version " + err.file_name + "\n";
631 }
632 break;
634 if(ch.version == 3) {
635 start = parse_xac_skinning_v3(context, start, end, err);
636 } else {
637 err.accumulated_errors += "Unsupported version (" + err.file_name + ")\n";
638 }
639 break;
640 }
641 default:
642#ifdef XAC_DEBUG
643 std::printf("CT,Unknown-(%i)\n", int16_t(ch.ident));
644#endif
645 err.accumulated_warnings += "Unknown chunk block type " + std::to_string(int32_t(ch.ident)) + " (size " + std::to_string(ch.len) + " @ offset " + std::to_string(uint32_t(start - file_start)) + ") on " + err.file_name + "\n";
646 start += ch.len;
647 break;
648 }
649 if(!context.ignore_length && start != expected) {
650 err.accumulated_errors += "Incorrect parsing for chunk ident " + std::to_string(int32_t(ch.ident)) + " (difference from expected " + std::to_string(int32_t(expected - start)) + ") on " + err.file_name + "\n";
651 start = expected;
652 }
653 }
654#ifdef XAC_DEBUG
655 for(const auto& node : context.nodes) {
656 std::printf("Node: %s\n", node.name.c_str());
657 std::printf("* Meshes: %zu\n", node.meshes.size());
658 for(const auto& o : node.meshes) {
659 std::printf("\tMesh\n");
660 std::printf("\t* vertices: %zu\n", o.vertices.size());
661 std::printf("\t* normals: %zu\n", o.normals.size());
662 std::printf("\t* texcoords: %zu\n", o.texcoords.size());
663 }
664 }
665 std::printf("Errors:\n%s\n", err.accumulated_errors.c_str());
666 std::printf("Warns:\n%s\n", err.accumulated_warnings.c_str());
667#endif
668}
669
670void finish(xac_context& context) {
671 // Post-proccessing step: Transform ALL vectors using the given matrices
672 // for rotation and position, and scale too!
673 for(auto& node : context.nodes) {
674 for(auto& o : node.meshes) {
675 const emfx::xac_vector4f q = node.rotation;
676 const emfx::xac_mat4x4 qm{
677 2.f * (q.x * q.x + q.y * q.y) - 1.f, //0 * 4 + 0 = 0
678 2.f * (q.y * q.z - q.x * q.w), //0 * 4 + 1 = 1
679 2.f * (q.y * q.w + q.x * q.z), //0 * 4 + 2 = 2
680 0.f, //0 * 4 + 3 = 3
681 2.f * (q.y * q.z + q.x * q.w), //1 * 4 + 0 = 4
682 2.f * (q.x * q.x + q.z * q.z) - 1.f, //1 * 4 + 1 = 5
683 2.f * (q.z * q.w - q.x * q.y), //1 * 4 + 2 = 6
684 0.f, //1 * 4 + 3 = 7
685 2.f * (q.y * q.w - q.x * q.z), //2 * 4 + 0 = 8
686 2.f * (q.z * q.w + q.x * q.y), //2 * 4 + 1 = 9
687 2.f * (q.x * q.x + q.w * q.w) - 1.f, //2 * 4 + 2 = 10
688 0.f, //2 * 4 + 3 = 11
689 };
690 const emfx::xac_mat4x4 tm{
691 qm.m[0 * 4 + 0] * node.scale.x, //0 * 4 + 0 = 0
692 qm.m[0 * 4 + 1] * node.scale.y, //0 * 4 + 1 = 1
693 qm.m[0 * 4 + 2] * node.scale.z, //0 * 4 + 2 = 2
694 node.position.x, //0 * 4 + 3 = 3
695 qm.m[1 * 4 + 0] * node.scale.x, //1 * 4 + 0 = 4
696 qm.m[1 * 4 + 1] * node.scale.y, //1 * 4 + 1 = 5
697 qm.m[1 * 4 + 2] * node.scale.z, //1 * 4 + 2 = 6
698 node.position.y, //1 * 4 + 3 = 7
699 qm.m[2 * 4 + 0] * node.scale.x, //2 * 4 + 0 = 8
700 qm.m[2 * 4 + 1] * node.scale.y, //2 * 4 + 1 = 9
701 qm.m[2 * 4 + 2] * node.scale.z, //2 * 4 + 2 = 10
702 node.position.z, //2 * 4 + 3 = 11
703 };
704 for(uint32_t i = 0; i < o.vertices.size(); i++) {
705 emfx::xac_vector3f v = o.vertices[i];
706 v.x = tm.m[0 * 4 + 0] * v.x + tm.m[0 * 4 + 1] * v.y + tm.m[0 * 4 + 2] * v.z + tm.m[0 * 4 + 3] * 1.f; // w = 1.f
707 v.y = tm.m[1 * 4 + 0] * v.x + tm.m[1 * 4 + 1] * v.y + tm.m[1 * 4 + 2] * v.z + tm.m[1 * 4 + 3] * 1.f;
708 v.z = tm.m[2 * 4 + 0] * v.x + tm.m[2 * 4 + 1] * v.y + tm.m[2 * 4 + 2] * v.z + tm.m[2 * 4 + 3] * 1.f;
709 //v.w = tm.m[3 * 4 + 0] * v.x + tm.m[3 * 4 + 1] * v.y + tm.m[3 * 4 + 2] * v.z + tm.m[3 * 4 + 3] * 1.f;
710 o.vertices[i] = v;
711 }
712 }
713 }
714}
715}
std::string accumulated_errors
Definition: parsers.hpp:62
std::string accumulated_warnings
Definition: parsers.hpp:63
std::string file_name
Definition: parsers.hpp:61
Definition: xac.cpp:264
const char * parse_xac_metadata_v2(xac_context &context, const char *start, const char *end, parsers::error_handler &err)
Definition: xac.cpp:278
void parse_xac(xac_context &context, const char *start, const char *end, parsers::error_handler &err)
Definition: xac.cpp:579
const char * parse_xac_node_hierachy_v1(xac_context &context, const char *start, const char *end, parsers::error_handler &err)
Definition: xac.cpp:356
const char * parse_xac_material_v2(xac_context &context, const char *start, const char *end, parsers::error_handler &err)
Definition: xac.cpp:309
const char * parse_xac_material_block_v1(xac_context &context, const char *start, const char *end, parsers::error_handler &err)
Definition: xac.cpp:299
const char * parse_xac_skinning_v3(xac_context &context, const char *start, const char *end, parsers::error_handler &err)
Definition: xac.cpp:520
const char * parse_xac_cstring(const char *start, const char *end, parsers::error_handler &err)
Definition: xac.cpp:265
void finish(xac_context &context)
Definition: xac.cpp:670
xac_chunk_type
Definition: xac.hpp:10
xac_pp_material_map_type
Definition: xac.hpp:88
const char * parse_xac_cstring_nodiscard(std::string &out, const char *start, const char *end, parsers::error_handler &err)
Definition: xac.cpp:270
const char * parse_xac_mesh_v1(xac_context &context, const char *start, const char *end, parsers::error_handler &err)
Definition: xac.cpp:394
xac_vertex_block_v1_type
Definition: xac.hpp:219
uint uint32_t
uchar uint8_t
uint32_t max_standard_materials
Definition: xac.hpp:122
std::vector< xac_pp_actor_material > materials
Definition: xac.hpp:121
std::vector< xac_pp_actor_node > root_nodes
Definition: xac.hpp:119
uint32_t max_fx_materials
Definition: xac.hpp:123
std::vector< xac_pp_actor_node > nodes
Definition: xac.hpp:120
bool ignore_length
Definition: xac.hpp:124
float m[16]
Definition: xac.hpp:50
xac_pp_material_map_type map_type
Definition: xac.hpp:102
std::vector< xac_pp_actor_material_layer > layers
Definition: xac.hpp:106
xac_color_rgba emissive_color
Definition: xac.hpp:110
xac_color_rgba specular_color
Definition: xac.hpp:109
xac_color_rgba ambient_color
Definition: xac.hpp:107
xac_color_rgba diffuse_color
Definition: xac.hpp:108
std::vector< uint32_t > influence_starts
Definition: xac.hpp:73
std::string name
Definition: xac.hpp:77
xac_vector3f scale
Definition: xac.hpp:82
xac_vector3f position
Definition: xac.hpp:81
xac_vector4f rotation
Definition: xac.hpp:79
xac_vector4f scale_rotation
Definition: xac.hpp:80
xac_mat4x4 transform
Definition: xac.hpp:83