summaryrefslogtreecommitdiff
path: root/src/3d/scene_loader.cc
blob: 286edca148a143ec6a98ed6e2625c9900a6d8e2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include "3d/scene_loader.h"
#include "generated/assets.h"
#include "plane_data.h"
#include "util/asset_manager.h"
#include "util/mini_math.h"
#include <cstdio>
#include <cstring>
#include <memory> // For std::shared_ptr
#include <new>    // For std::nothrow
#include <vector>

bool SceneLoader::LoadScene(Scene& scene, const uint8_t* data, size_t size) {
  if (!data || size < 16) { // Header size check
    printf("SceneLoader: Data too small\n");
    return false;
  }

  // Check Magic
  if (std::memcmp(data, "SCN1", 4) != 0) {
    printf("SceneLoader: Invalid magic (expected SCN1)\n");
    return false;
  }

  size_t offset = 4;

  uint32_t num_objects = *reinterpret_cast<const uint32_t*>(data + offset);
  offset += 4;
  uint32_t num_cameras = *reinterpret_cast<const uint32_t*>(data + offset);
  offset += 4;
  uint32_t num_lights = *reinterpret_cast<const uint32_t*>(data + offset);
  offset += 4;

  // printf("SceneLoader: Loading %d objects, %d cameras, %d lights\n",
  // num_objects, num_cameras, num_lights);

  for (uint32_t i = 0; i < num_objects; ++i) {
    if (offset + 64 > size)
      return false; // Name check

    char name[65] = {0};
    std::memcpy(name, data + offset, 64);
    offset += 64;

    if (offset + 4 > size)
      return false;
    uint32_t type_val = *reinterpret_cast<const uint32_t*>(data + offset);
    offset += 4;
    ObjectType type = (ObjectType)type_val;

    if (offset + 12 + 16 + 12 + 16 > size)
      return false; // Transforms + Color

    float px = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    float py = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    float pz = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    vec3 pos(px, py, pz);

    float rx = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    float ry = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    float rz = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    float rw = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    quat rot(rx, ry, rz, rw);

    float sx = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    float sy = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    float sz = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    vec3 scale(sx, sy, sz);

    // Color components (cr, cg, cb, ca)
    float cr = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    float cg = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    float cb = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    // Read ca, advance offset AFTER reading ca, then construct color
    float ca = *reinterpret_cast<const float*>(data + offset);
    offset += 4; // Offset is now after ca
    vec4 color(cr, cg, cb, ca);

    // Plane Distance (if type == PLANE)
    float plane_distance = 0.0f;
    if (type == ObjectType::PLANE) {
      // Check bounds before reading plane_distance
      if (offset + 4 > size)
        return false;
      plane_distance = *reinterpret_cast<const float*>(data + offset);
      offset += 4; // Advance offset after reading plane_distance
    }

    // Mesh Asset Name Length
    // The offset is now correctly positioned for name_len,
    // either after ca (if not PLANE) or after plane_distance (if PLANE).
    if (offset + 4 > size)
      return false;
    uint32_t name_len = *reinterpret_cast<const uint32_t*>(data + offset);
    offset += 4;

    AssetId mesh_id = (AssetId)0; // Default or INVALID (if 0 is invalid)

    if (name_len > 0) {
      if (offset + name_len > size)
        return false;
      char mesh_name[128] = {0};
      if (name_len < 128) {
        std::memcpy(mesh_name, data + offset, name_len);
      }
      offset += name_len;

      // Resolve Asset ID
      mesh_id = GetAssetIdByName(mesh_name);
      if (mesh_id == AssetId::ASSET_LAST_ID) {
        printf(
            "SceneLoader: Warning: Mesh asset '%s' not found for object '%s'\n",
            mesh_name, name);
      }
    }

    // Physics properties
    if (offset + 4 + 4 + 4 > size)
      return false;
    float mass = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    float restitution = *reinterpret_cast<const float*>(data + offset);
    offset += 4;
    uint32_t is_static_u32 = *reinterpret_cast<const uint32_t*>(data + offset);
    offset += 4;
    bool is_static = (is_static_u32 != 0);

    // Create Object3D
    Object3D obj(type);
    obj.position = pos;
    obj.rotation = rot;
    obj.scale = scale;
    obj.color = color;
    obj.mesh_asset_id = mesh_id;
    obj.mass = mass;
    obj.restitution = restitution;
    obj.is_static = is_static;
    // user_data is nullptr by default

    // Store plane distance in shared_user_data if it's a plane
    if (type == ObjectType::PLANE) {
      // Allocate PlaneData on the heap and manage with shared_ptr
      // Use std::make_shared for exception safety and efficiency
      obj.shared_user_data = std::make_shared<PlaneData>();
      // Assign the plane distance
      // Safely cast void* to PlaneData* using static_cast on the shared_ptr's
      // get()
      static_cast<PlaneData*>(obj.shared_user_data.get())->distance =
          plane_distance;
    }

    // Add to scene
    scene.add_object(obj);
  }

  return true;
}