VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
glbContainerResource.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3//
4// Created by Arnis Lektauers 20.12.2025.
5//
7
10
11namespace visutwin::canvas
12{
14 {
15 auto* root = new Entity();
16
17 // container resource instantiateRenderEntity() produces an entity hierarchy
18 // with render components / mesh instances populated from parsed glTF payload and node transforms.
19 if (_nodePayloads.empty()) {
20 if (_meshPayloads.empty()) {
21 return root;
22 }
23
24 // Fallback for payloads without node metadata.
25 auto renderComponent = std::make_unique<RenderComponent>(nullptr, root);
26 auto* renderComponentRaw = renderComponent.get();
27 for (const auto& payload : _meshPayloads) {
28 if (!payload.mesh) {
29 continue;
30 }
31 auto* meshInstance = new MeshInstance(payload.mesh.get(), payload.material.get(), root);
32 renderComponentRaw->meshInstances().push_back(meshInstance);
33 }
34 root->addComponentInstance(std::move(renderComponent), componentTypeID<RenderComponent>());
35 return root;
36 }
37
38 std::vector<Entity*> nodeEntities(_nodePayloads.size(), nullptr);
39 for (size_t i = 0; i < _nodePayloads.size(); ++i) {
40 const auto& nodePayload = _nodePayloads[i];
41 if (nodePayload.skip) {
42 continue; // Consumed POINTS leaf — no entity created.
43 }
44 auto* nodeEntity = new Entity();
45 if (!nodePayload.name.empty()) {
46 nodeEntity->setName(nodePayload.name);
47 }
48 nodeEntity->setLocalPosition(
49 nodePayload.translation.getX(),
50 nodePayload.translation.getY(),
51 nodePayload.translation.getZ()
52 );
53 nodeEntity->setLocalRotation(nodePayload.rotation);
54 nodeEntity->setLocalScale(nodePayload.scale);
55
56 if (!nodePayload.meshPayloadIndices.empty()) {
57 auto renderComponent = std::make_unique<RenderComponent>(nullptr, nodeEntity);
58 auto* renderComponentRaw = renderComponent.get();
59 for (const auto meshPayloadIndex : nodePayload.meshPayloadIndices) {
60 if (meshPayloadIndex >= _meshPayloads.size()) {
61 continue;
62 }
63 const auto& meshPayload = _meshPayloads[meshPayloadIndex];
64 if (!meshPayload.mesh) {
65 continue;
66 }
67 auto* meshInstance = new MeshInstance(meshPayload.mesh.get(), meshPayload.material.get(), nodeEntity);
68 meshInstance->setCastShadow(meshPayload.castShadow);
69 renderComponentRaw->meshInstances().push_back(meshInstance);
70 }
71 nodeEntity->addComponentInstance(std::move(renderComponent), componentTypeID<RenderComponent>());
72 }
73
74 nodeEntities[i] = nodeEntity;
75 }
76
77 for (size_t i = 0; i < _nodePayloads.size(); ++i) {
78 auto* parent = nodeEntities[i];
79 if (!parent) {
80 continue;
81 }
82 for (const auto childIndex : _nodePayloads[i].children) {
83 if (childIndex < 0 || childIndex >= static_cast<int>(nodeEntities.size())) {
84 continue;
85 }
86 auto* child = nodeEntities[static_cast<size_t>(childIndex)];
87 if (child) {
88 parent->addChild(child);
89 }
90 }
91 }
92
93 if (_rootNodeIndices.empty()) {
94 std::vector<bool> isChild(nodeEntities.size(), false);
95 for (const auto& nodePayload : _nodePayloads) {
96 for (const auto childIndex : nodePayload.children) {
97 if (childIndex >= 0 && childIndex < static_cast<int>(isChild.size())) {
98 isChild[static_cast<size_t>(childIndex)] = true;
99 }
100 }
101 }
102
103 for (size_t i = 0; i < nodeEntities.size(); ++i) {
104 auto* nodeEntity = nodeEntities[i];
105 if (nodeEntity && !isChild[i]) {
106 root->addChild(nodeEntity);
107 }
108 }
109 } else {
110 for (const auto rootIndex : _rootNodeIndices) {
111 if (rootIndex < 0 || rootIndex >= static_cast<int>(nodeEntities.size())) {
112 continue;
113 }
114 auto* nodeEntity = nodeEntities[static_cast<size_t>(rootIndex)];
115 if (nodeEntity) {
116 root->addChild(nodeEntity);
117 }
118 }
119 }
120
121 // Attach AnimationComponent if the GLB contained animations.
122 //attaches animations to the instantiated entity.
123 if (!_animTracks.empty()) {
124 auto animComponent = std::make_unique<AnimationComponent>(nullptr, root);
125 for (const auto& [name, track] : _animTracks) {
126 animComponent->addAnimation(name, track);
127 }
128 root->addComponentInstance(std::move(animComponent), componentTypeID<AnimationComponent>());
129 }
130
131 return root;
132 }
133}
ECS entity — a GraphNode that hosts components defining its behavior.
Definition entity.h:32
Renderable instance of a Mesh with its own material, transform node, and optional GPU instancing.
ComponentTypeID componentTypeID()
Definition component.h:25