142 lines
4.6 KiB
C
142 lines
4.6 KiB
C
#include "scene_serialize.h"
|
|
#include "scene_render.h"
|
|
#include "../ASM/math_c_fallback.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#ifndef PI
|
|
#define PI 3.14159265f
|
|
#endif
|
|
|
|
static int node_index(Scene* scene, SceneNode* node) {
|
|
if (!scene || !node) return -1;
|
|
return (int)(node - scene->nodes);
|
|
}
|
|
|
|
static const char* mesh_type_name(MeshType t) {
|
|
switch (t) {
|
|
case MESH_CUBE: return "CUBE";
|
|
case MESH_SPHERE: return "SPHERE";
|
|
case MESH_PLANE: return "PLANE";
|
|
case MESH_OBJ: return "OBJ";
|
|
default: return "NONE";
|
|
}
|
|
}
|
|
|
|
static MeshType parse_mesh_type(const char* s) {
|
|
if (!s) return MESH_NONE;
|
|
if (strcmp(s, "CUBE") == 0) return MESH_CUBE;
|
|
if (strcmp(s, "SPHERE") == 0) return MESH_SPHERE;
|
|
if (strcmp(s, "PLANE") == 0) return MESH_PLANE;
|
|
if (strcmp(s, "OBJ") == 0) return MESH_OBJ;
|
|
return MESH_NONE;
|
|
}
|
|
|
|
static void write_node(FILE* f, Scene* scene, SceneNode* node) {
|
|
if (!node) return;
|
|
int parent = (node == scene->root) ? -1 : node_index(scene, node->parent);
|
|
MeshRenderer* mr = scene_node_get_mesh_renderer(node);
|
|
MeshType type = mr ? mr->type : MESH_NONE;
|
|
const char* path = (mr && mr->path[0]) ? mr->path : "-";
|
|
|
|
float ex = 0.0f, ey = 0.0f, ez = 0.0f;
|
|
quat_to_euler(&node->rotation, &ex, &ey, &ez);
|
|
|
|
fprintf(f, "%s %d %s %s %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f\n",
|
|
node->name, parent, mesh_type_name(type), path,
|
|
node->position.x, node->position.y, node->position.z,
|
|
ex * 180.0f / PI, ey * 180.0f / PI, ez * 180.0f / PI,
|
|
node->scale.x, node->scale.y, node->scale.z);
|
|
|
|
for (int i = 0; i < node->child_count; i++) {
|
|
write_node(f, scene, node->children[i]);
|
|
}
|
|
}
|
|
|
|
int scene_save(Scene* scene, const char* path) {
|
|
if (!scene || !path) return 0;
|
|
FILE* f = fopen(path, "w");
|
|
if (!f) return 0;
|
|
fprintf(f, "LITY3D_SCENE 1\n");
|
|
write_node(f, scene, scene->root);
|
|
fclose(f);
|
|
return 1;
|
|
}
|
|
|
|
static Mesh* create_mesh_for_type(MeshType type, ID3D11Device* dev, const char* path) {
|
|
switch (type) {
|
|
case MESH_CUBE: return mesh_create_cube(dev);
|
|
case MESH_SPHERE: return mesh_create_sphere(dev, 1.0f, 16);
|
|
case MESH_PLANE: return mesh_create_plane(dev, 10.0f);
|
|
case MESH_OBJ: return path ? mesh_load_obj(dev, path) : NULL;
|
|
default: return NULL;
|
|
}
|
|
}
|
|
|
|
Scene* scene_load(const char* path, ID3D11Device* dev, Shader* default_shader) {
|
|
FILE* f = fopen(path, "r");
|
|
if (!f) return NULL;
|
|
|
|
char line[512];
|
|
if (!fgets(line, sizeof(line), f)) { fclose(f); return NULL; }
|
|
if (strncmp(line, "LITY3D_SCENE", 10) != 0) { fclose(f); return NULL; }
|
|
|
|
Scene* scene = (Scene*)malloc(sizeof(Scene));
|
|
if (!scene) { fclose(f); return NULL; }
|
|
scene_init(scene);
|
|
|
|
int capacity = 64;
|
|
SceneNode** nodes = (SceneNode**)malloc(sizeof(SceneNode*) * capacity);
|
|
int count = 0;
|
|
|
|
while (fgets(line, sizeof(line), f)) {
|
|
char name[64];
|
|
char type_str[16];
|
|
char path_str[256];
|
|
int parent_id;
|
|
float px, py, pz, degx, degy, degz, sx, sy, sz;
|
|
if (sscanf(line, "%63s %d %15s %255s %f %f %f %f %f %f %f %f %f",
|
|
name, &parent_id, type_str, path_str,
|
|
&px, &py, &pz, °x, °y, °z, &sx, &sy, &sz) != 13) {
|
|
continue;
|
|
}
|
|
|
|
if (count >= capacity) {
|
|
capacity *= 2;
|
|
nodes = (SceneNode**)realloc(nodes, sizeof(SceneNode*) * capacity);
|
|
}
|
|
|
|
SceneNode* parent = (parent_id < 0) ? scene->root : nodes[parent_id];
|
|
SceneNode* node = scene_create_node(scene, name);
|
|
if (!node) continue;
|
|
if (parent) scene_set_parent(node, parent);
|
|
|
|
node->position = (Vec3){px, py, pz};
|
|
node->scale = (Vec3){sx, sy, sz};
|
|
quat_from_euler(degx * PI / 180.0f, degy * PI / 180.0f, degz * PI / 180.0f, &node->rotation);
|
|
|
|
MeshType type = parse_mesh_type(type_str);
|
|
if (type != MESH_NONE) {
|
|
const char* mesh_path = (strcmp(path_str, "-") == 0) ? NULL : path_str;
|
|
Mesh* mesh = create_mesh_for_type(type, dev, mesh_path);
|
|
if (mesh) {
|
|
Material* mat = material_create(default_shader, NULL);
|
|
MeshRenderer* mr = mesh_renderer_create(type, mesh, mat);
|
|
if (mesh_path) strncpy(mr->path, mesh_path, sizeof(mr->path) - 1);
|
|
scene_node_set_mesh_renderer(node, mr);
|
|
}
|
|
}
|
|
|
|
nodes[count] = node;
|
|
count++;
|
|
}
|
|
|
|
free(nodes);
|
|
fclose(f);
|
|
|
|
scene_update(scene);
|
|
return scene;
|
|
}
|