summaryrefslogtreecommitdiff
path: root/src/3d/scene_loader.cc
blob: f5b587ecb5557387faa6476e03e7c5873b93c557 (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
#include "3d/scene_loader.h"
#include "generated/assets.h"
#include "util/asset_manager.h"
#include "util/mini_math.h"
#include <cstdio>
#include <cstring>
#include <vector>
#include <memory> // For std::shared_ptr
#include <new>    // For std::nothrow
#include "plane_data.h"

// Local struct to hold plane-specific data
struct PlaneData {
  float distance;
};

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);

    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;
    vec4 color(cr, cg, cb, ca);

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

    // Mesh Asset Name Length
    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;
}