This commit is contained in:
2026-06-17 11:07:13 -05:00
parent 0ea6dd9219
commit f5db2458cd
14 changed files with 726 additions and 12 deletions
+5
View File
@@ -9,6 +9,11 @@ if(NOT cglm_FOUND)
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC cglm)
endif()
if(NOT yyjson_FOUND)
find_package(yyjson REQUIRED)
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC yyjson::yyjson)
endif()
if(DUSK_BACKTRACE)
target_link_options(${DUSK_LIBRARY_TARGET_NAME} PUBLIC -rdynamic)
+42 -3
View File
@@ -12,15 +12,17 @@
componentdefinition_t COMPONENT_DEFINITIONS[] = {
[COMPONENT_TYPE_NULL] = { 0 },
#define X(enm, type, field, iMethod, dMethod, rMethod) \
#define X(enm, type, field, iMethod, dMethod, rMethod, sMethod, dsMethod) \
[COMPONENT_TYPE_##enm] = { \
.enumName = #enm, \
.name = #field, \
.init = iMethod, \
.dispose = dMethod, \
.render = rMethod \
.render = rMethod, \
.serialize = sMethod, \
.deserialize = dsMethod \
},
#include "componentlist.h"
#undef X
@@ -130,6 +132,43 @@ errorret_t componentRenderAll(void) {
errorOk();
}
void componentSerialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_mut_doc *doc,
yyjson_mut_val *obj
) {
assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB");
assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB");
assertNotNull(doc, "JSON doc cannot be null");
assertNotNull(obj, "JSON obj cannot be null");
componentindex_t index = componentGetIndex(entityId, componentId);
component_t *cmp = &ENTITY_MANAGER.components[index];
if(cmp->type == COMPONENT_TYPE_NULL) return;
if(!COMPONENT_DEFINITIONS[cmp->type].serialize) return;
COMPONENT_DEFINITIONS[cmp->type].serialize(entityId, componentId, doc, obj);
}
errorret_t componentDeserialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_val *obj
) {
assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB");
assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB");
assertNotNull(obj, "JSON obj cannot be null");
componentindex_t index = componentGetIndex(entityId, componentId);
component_t *cmp = &ENTITY_MANAGER.components[index];
if(cmp->type == COMPONENT_TYPE_NULL) errorOk();
if(!COMPONENT_DEFINITIONS[cmp->type].deserialize) errorOk();
errorChain(
COMPONENT_DEFINITIONS[cmp->type].deserialize(entityId, componentId, obj)
);
errorOk();
}
void componentDispose(
const entityid_t entityId,
const componentid_t componentId
+49 -4
View File
@@ -7,14 +7,18 @@
#pragma once
#include "entitybase.h"
#include "error/error.h"
#define X(enumName, type, field, init, dispose, render) \
#include <yyjson.h>
#define X(enumName, type, field, init, dispose, render, serialize, deserialize) \
// do nothing
#include "componentlist.h"
#undef X
typedef union {
#define X(enumName, type, field, init, dispose, render) type field;
#define X(enumName, type, field, init, dispose, render, serialize, deserialize) \
type field;
#include "componentlist.h"
#undef X
} componentdata_t;
@@ -25,12 +29,23 @@ typedef struct {
void (*init)(const entityid_t, const componentid_t);
void (*dispose)(const entityid_t, const componentid_t);
errorret_t (*render)(const entityid_t, const componentid_t);
void (*serialize)(
const entityid_t,
const componentid_t,
yyjson_mut_doc *,
yyjson_mut_val *
);
errorret_t (*deserialize)(
const entityid_t,
const componentid_t,
yyjson_val *
);
} componentdefinition_t;
typedef enum {
COMPONENT_TYPE_NULL,
#define X(enumName, type, field, init, dispose, render) \
#define X(enumName, type, field, init, dispose, render, serialize, deserialize) \
COMPONENT_TYPE_##enumName,
#include "componentlist.h"
#undef X
@@ -117,4 +132,34 @@ void componentDispose(
*
* @return Error state.
*/
errorret_t componentRenderAll(void);
errorret_t componentRenderAll(void);
/**
* Serializes a component's configurable state into a JSON object. The caller
* is responsible for creating and owning the doc and obj.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param doc The mutable JSON document to allocate values from.
* @param obj The JSON object to write fields into.
*/
void componentSerialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_mut_doc *doc,
yyjson_mut_val *obj
);
/**
* Deserializes a component's configurable state from a JSON object.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param obj The JSON object to read fields from.
* @return Error state.
*/
errorret_t componentDeserialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_val *obj
);
@@ -10,6 +10,9 @@
#include "entity/component/display/entityposition.h"
#include "display/framebuffer/framebuffer.h"
#include "display/screen/screen.h"
#include "assert/assert.h"
#include "util/string.h"
#include <yyjson.h>
void entityCameraInit(const entityid_t ent, const componentid_t comp) {
entitycamera_t *cam = (entitycamera_t *)componentGetData(
@@ -117,4 +120,88 @@ void entityCameraGetRight(const entityid_t entityId, vec2 out) {
if(len > 1e-6f) { rx /= len; rz /= len; }
out[0] = rx;
out[1] = rz;
}
void entityCameraSerialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_mut_doc *doc,
yyjson_mut_val *obj
) {
entitycamera_t *cam = (entitycamera_t *)componentGetData(
entityId, componentId, COMPONENT_TYPE_CAMERA
);
assertNotNull(cam, "Failed to get camera component.");
const char_t *projStr = "perspective";
if(cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED) {
projStr = "perspective_flipped";
} else if(cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
projStr = "orthographic";
}
yyjson_mut_obj_add_str(doc, obj, "projType", projStr);
yyjson_mut_obj_add_real(doc, obj, "nearClip", (double)cam->nearClip);
yyjson_mut_obj_add_real(doc, obj, "farClip", (double)cam->farClip);
if(cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
yyjson_mut_obj_add_real(doc, obj, "left", (double)cam->orthographic.left);
yyjson_mut_obj_add_real(doc, obj, "right", (double)cam->orthographic.right);
yyjson_mut_obj_add_real(doc, obj, "top", (double)cam->orthographic.top);
yyjson_mut_obj_add_real(
doc, obj, "bottom", (double)cam->orthographic.bottom
);
} else {
yyjson_mut_obj_add_real(doc, obj, "fov", (double)cam->perspective.fov);
}
}
errorret_t entityCameraDeserialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_val *obj
) {
entitycamera_t *cam = (entitycamera_t *)componentGetData(
entityId, componentId, COMPONENT_TYPE_CAMERA
);
assertNotNull(cam, "Failed to get camera component.");
yyjson_val *v;
v = yyjson_obj_get(obj, "projType");
if(v && yyjson_is_str(v)) {
const char_t *s = yyjson_get_str(v);
if(stringCompare(s, "perspective_flipped") == 0) {
cam->projType = ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED;
} else if(stringCompare(s, "orthographic") == 0) {
cam->projType = ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC;
} else {
cam->projType = ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE;
}
}
v = yyjson_obj_get(obj, "nearClip");
if(v) cam->nearClip = (float_t)yyjson_get_num(v);
v = yyjson_obj_get(obj, "farClip");
if(v) cam->farClip = (float_t)yyjson_get_num(v);
if(cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
v = yyjson_obj_get(obj, "left");
if(v) cam->orthographic.left = (float_t)yyjson_get_num(v);
v = yyjson_obj_get(obj, "right");
if(v) cam->orthographic.right = (float_t)yyjson_get_num(v);
v = yyjson_obj_get(obj, "top");
if(v) cam->orthographic.top = (float_t)yyjson_get_num(v);
v = yyjson_obj_get(obj, "bottom");
if(v) cam->orthographic.bottom = (float_t)yyjson_get_num(v);
} else {
v = yyjson_obj_get(obj, "fov");
if(v) cam->perspective.fov = (float_t)yyjson_get_num(v);
}
errorOk();
}
@@ -7,6 +7,8 @@
#pragma once
#include "entity/entitybase.h"
#include "error/error.h"
#include <yyjson.h>
typedef enum {
ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE,
@@ -96,4 +98,35 @@ void entityCameraLookAtPixelPerfect(
const vec3 point,
const vec3 eyeOffset,
const float_t scale
);
/**
* Serializes camera projection settings to a JSON object. Writes "projType"
* as a string ("perspective", "perspective_flipped", or "orthographic"),
* "nearClip", "farClip", and the projection-specific parameters.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param doc The mutable JSON document to allocate values from.
* @param obj The JSON object to write fields into.
*/
void entityCameraSerialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_mut_doc *doc,
yyjson_mut_val *obj
);
/**
* Deserializes camera projection settings from a JSON object.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param obj The JSON object to read fields from.
* @return Error state.
*/
errorret_t entityCameraDeserialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_val *obj
);
@@ -6,6 +6,8 @@
*/
#include "entity/entitymanager.h"
#include "assert/assert.h"
#include <yyjson.h>
// Decompose localTransform into the PRS cache. Only called when PRS_DIRTY.
static void entityPositionEnsurePRS(entityposition_t *pos) {
@@ -628,3 +630,68 @@ void entityPositionDecompose(entityposition_t *pos) {
: -atan2f(r01, r11);
}
}
void entityPositionSerialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_mut_doc *doc,
yyjson_mut_val *obj
) {
entityposition_t *pos = entityPositionGet(entityId, componentId);
assertNotNull(pos, "Failed to get position component.");
yyjson_mut_val *arr;
arr = yyjson_mut_arr(doc);
yyjson_mut_arr_add_real(doc, arr, (double)pos->position[0]);
yyjson_mut_arr_add_real(doc, arr, (double)pos->position[1]);
yyjson_mut_arr_add_real(doc, arr, (double)pos->position[2]);
yyjson_mut_obj_add_val(doc, obj, "position", arr);
arr = yyjson_mut_arr(doc);
yyjson_mut_arr_add_real(doc, arr, (double)pos->rotation[0]);
yyjson_mut_arr_add_real(doc, arr, (double)pos->rotation[1]);
yyjson_mut_arr_add_real(doc, arr, (double)pos->rotation[2]);
yyjson_mut_obj_add_val(doc, obj, "rotation", arr);
arr = yyjson_mut_arr(doc);
yyjson_mut_arr_add_real(doc, arr, (double)pos->scale[0]);
yyjson_mut_arr_add_real(doc, arr, (double)pos->scale[1]);
yyjson_mut_arr_add_real(doc, arr, (double)pos->scale[2]);
yyjson_mut_obj_add_val(doc, obj, "scale", arr);
}
errorret_t entityPositionDeserialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_val *obj
) {
entityposition_t *pos = entityPositionGet(entityId, componentId);
assertNotNull(pos, "Failed to get position component.");
yyjson_val *v;
v = yyjson_obj_get(obj, "position");
if(v && yyjson_is_arr(v) && yyjson_arr_size(v) == 3) {
pos->position[0] = (float_t)yyjson_get_num(yyjson_arr_get(v, 0));
pos->position[1] = (float_t)yyjson_get_num(yyjson_arr_get(v, 1));
pos->position[2] = (float_t)yyjson_get_num(yyjson_arr_get(v, 2));
}
v = yyjson_obj_get(obj, "rotation");
if(v && yyjson_is_arr(v) && yyjson_arr_size(v) == 3) {
pos->rotation[0] = (float_t)yyjson_get_num(yyjson_arr_get(v, 0));
pos->rotation[1] = (float_t)yyjson_get_num(yyjson_arr_get(v, 1));
pos->rotation[2] = (float_t)yyjson_get_num(yyjson_arr_get(v, 2));
}
v = yyjson_obj_get(obj, "scale");
if(v && yyjson_is_arr(v) && yyjson_arr_size(v) == 3) {
pos->scale[0] = (float_t)yyjson_get_num(yyjson_arr_get(v, 0));
pos->scale[1] = (float_t)yyjson_get_num(yyjson_arr_get(v, 1));
pos->scale[2] = (float_t)yyjson_get_num(yyjson_arr_get(v, 2));
}
entityPositionRebuild(pos);
errorOk();
}
@@ -7,6 +7,8 @@
#pragma once
#include "entity/entitybase.h"
#include "error/error.h"
#include <yyjson.h>
/** Maximum number of child position components this node can track. */
#define ENTITY_POSITION_CHILDREN_MAX 8
@@ -373,3 +375,34 @@ void entityPositionDisposeDeep(
* @param pos The position component to decompose.
*/
void entityPositionDecompose(entityposition_t *pos);
/**
* Serializes position, rotation, and scale (local space) to a JSON object.
* Parent/child linkage and computed matrices are not included.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param doc The mutable JSON document to allocate values from.
* @param obj The JSON object to write fields into.
*/
void entityPositionSerialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_mut_doc *doc,
yyjson_mut_val *obj
);
/**
* Deserializes position, rotation, and scale from a JSON object and rebuilds
* the local transform.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param obj The JSON object to read fields from.
* @return Error state.
*/
errorret_t entityPositionDeserialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_val *obj
);
@@ -13,6 +13,8 @@
#include "display/mesh/cube.h"
#include "util/memory.h"
#include "assert/assert.h"
#include "util/string.h"
#include <yyjson.h>
void entityRenderableInit(
const entityid_t entityId,
@@ -140,3 +142,77 @@ errorret_t entityRenderableDraw(
assertUnreachable("Invalid renderable type");
}
}
void entityRenderableSerialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_mut_doc *doc,
yyjson_mut_val *obj
) {
entityrenderable_t *r = (entityrenderable_t *)componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
assertNotNull(r, "Failed to get renderable component.");
const char_t *typeStr = "custom";
if(r->type == ENTITY_RENDERABLE_TYPE_SPRITEBATCH) {
typeStr = "spritebatch";
} else if(r->type == ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL) {
typeStr = "shader_material";
}
yyjson_mut_obj_add_str(doc, obj, "type", typeStr);
yyjson_mut_obj_add_int(doc, obj, "priority", (int64_t)r->priority);
if(r->type == ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL) {
yyjson_mut_obj_add_int(
doc, obj, "shaderType", (int64_t)r->data.material.shaderType
);
yyjson_mut_obj_add_int(
doc, obj, "stateFlags", (int64_t)r->data.material.state.flags
);
}
}
errorret_t entityRenderableDeserialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_val *obj
) {
entityrenderable_t *r = (entityrenderable_t *)componentGetData(
entityId, componentId, COMPONENT_TYPE_RENDERABLE
);
assertNotNull(r, "Failed to get renderable component.");
yyjson_val *v;
v = yyjson_obj_get(obj, "type");
if(v && yyjson_is_str(v)) {
const char_t *s = yyjson_get_str(v);
if(stringCompare(s, "spritebatch") == 0) {
entityRenderableSetType(entityId, componentId,
ENTITY_RENDERABLE_TYPE_SPRITEBATCH);
} else if(stringCompare(s, "shader_material") == 0) {
entityRenderableSetType(entityId, componentId,
ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL);
} else {
entityRenderableSetType(entityId, componentId,
ENTITY_RENDERABLE_TYPE_CUSTOM);
}
}
v = yyjson_obj_get(obj, "priority");
if(v) r->priority = (int8_t)yyjson_get_sint(v);
if(r->type == ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL) {
v = yyjson_obj_get(obj, "shaderType");
if(v) {
r->data.material.shaderType = (shaderlistshader_t)yyjson_get_sint(v);
}
v = yyjson_obj_get(obj, "stateFlags");
if(v) r->data.material.state.flags = (uint8_t)yyjson_get_sint(v);
}
errorOk();
}
@@ -11,6 +11,7 @@
#include "display/shader/shadermaterial.h"
#include "display/spritebatch/spritebatch.h"
#include "display/displaystate.h"
#include <yyjson.h>
#define ENTITY_RENDERABLE_SPRITEBATCH_SPRITES_MAX 64
#define ENTITY_RENDERABLE_MESHES_MAX 8
@@ -145,3 +146,33 @@ errorret_t entityRenderableDraw(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Serializes renderable type, priority, and material settings to a JSON
* object. Custom and spritebatch renderables only serialize type and priority.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param doc The mutable JSON document to allocate values from.
* @param obj The JSON object to write fields into.
*/
void entityRenderableSerialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_mut_doc *doc,
yyjson_mut_val *obj
);
/**
* Deserializes renderable settings from a JSON object.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param obj The JSON object to read fields from.
* @return Error state.
*/
errorret_t entityRenderableDeserialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_val *obj
);
@@ -11,6 +11,8 @@
#include "physics/physicsmanager.h"
#include "assert/assert.h"
#include "util/memory.h"
#include "util/string.h"
#include <yyjson.h>
void entityPhysicsInit(
const entityid_t entityId,
@@ -124,3 +126,172 @@ void entityPhysicsDispose(
const componentid_t componentId
) {
}
void entityPhysicsSerialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_mut_doc *doc,
yyjson_mut_val *obj
) {
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
assertNotNull(phys, "Failed to get physics component.");
const char_t *bodyStr = "static";
if(phys->type == PHYSICS_BODY_DYNAMIC) {
bodyStr = "dynamic";
} else if(phys->type == PHYSICS_BODY_KINEMATIC) {
bodyStr = "kinematic";
}
yyjson_mut_obj_add_str(doc, obj, "bodyType", bodyStr);
const char_t *shapeStr = "cube";
if(phys->shape.type == PHYSICS_SHAPE_SPHERE) {
shapeStr = "sphere";
} else if(phys->shape.type == PHYSICS_SHAPE_CAPSULE) {
shapeStr = "capsule";
} else if(phys->shape.type == PHYSICS_SHAPE_PLANE) {
shapeStr = "plane";
}
yyjson_mut_obj_add_str(doc, obj, "shapeType", shapeStr);
switch(phys->shape.type) {
case PHYSICS_SHAPE_CUBE: {
yyjson_mut_val *he = yyjson_mut_arr(doc);
yyjson_mut_arr_add_real(
doc, he, (double)phys->shape.data.cube.halfExtents[0]
);
yyjson_mut_arr_add_real(
doc, he, (double)phys->shape.data.cube.halfExtents[1]
);
yyjson_mut_arr_add_real(
doc, he, (double)phys->shape.data.cube.halfExtents[2]
);
yyjson_mut_obj_add_val(doc, obj, "halfExtents", he);
break;
}
case PHYSICS_SHAPE_SPHERE:
yyjson_mut_obj_add_real(
doc, obj, "radius", (double)phys->shape.data.sphere.radius
);
break;
case PHYSICS_SHAPE_CAPSULE:
yyjson_mut_obj_add_real(
doc, obj, "radius", (double)phys->shape.data.capsule.radius
);
yyjson_mut_obj_add_real(
doc, obj, "halfHeight", (double)phys->shape.data.capsule.halfHeight
);
break;
case PHYSICS_SHAPE_PLANE: {
yyjson_mut_val *n = yyjson_mut_arr(doc);
yyjson_mut_arr_add_real(
doc, n, (double)phys->shape.data.plane.normal[0]
);
yyjson_mut_arr_add_real(
doc, n, (double)phys->shape.data.plane.normal[1]
);
yyjson_mut_arr_add_real(
doc, n, (double)phys->shape.data.plane.normal[2]
);
yyjson_mut_obj_add_val(doc, obj, "normal", n);
yyjson_mut_obj_add_real(
doc, obj, "distance", (double)phys->shape.data.plane.distance
);
break;
}
default:
break;
}
yyjson_mut_val *vel = yyjson_mut_arr(doc);
yyjson_mut_arr_add_real(doc, vel, (double)phys->velocity[0]);
yyjson_mut_arr_add_real(doc, vel, (double)phys->velocity[1]);
yyjson_mut_arr_add_real(doc, vel, (double)phys->velocity[2]);
yyjson_mut_obj_add_val(doc, obj, "velocity", vel);
yyjson_mut_obj_add_real(doc, obj, "gravityScale", (double)phys->gravityScale);
}
errorret_t entityPhysicsDeserialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_val *obj
) {
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
assertNotNull(phys, "Failed to get physics component.");
yyjson_val *v;
v = yyjson_obj_get(obj, "bodyType");
if(v && yyjson_is_str(v)) {
const char_t *s = yyjson_get_str(v);
if(stringCompare(s, "dynamic") == 0) {
phys->type = PHYSICS_BODY_DYNAMIC;
} else if(stringCompare(s, "kinematic") == 0) {
phys->type = PHYSICS_BODY_KINEMATIC;
} else {
phys->type = PHYSICS_BODY_STATIC;
}
}
v = yyjson_obj_get(obj, "shapeType");
if(v && yyjson_is_str(v)) {
physicsshape_t shape;
memoryZero(&shape, sizeof(physicsshape_t));
const char_t *s = yyjson_get_str(v);
if(stringCompare(s, "sphere") == 0) {
shape.type = PHYSICS_SHAPE_SPHERE;
yyjson_val *r = yyjson_obj_get(obj, "radius");
if(r) shape.data.sphere.radius = (float_t)yyjson_get_num(r);
} else if(stringCompare(s, "capsule") == 0) {
shape.type = PHYSICS_SHAPE_CAPSULE;
yyjson_val *r = yyjson_obj_get(obj, "radius");
if(r) shape.data.capsule.radius = (float_t)yyjson_get_num(r);
yyjson_val *hh = yyjson_obj_get(obj, "halfHeight");
if(hh) shape.data.capsule.halfHeight = (float_t)yyjson_get_num(hh);
} else if(stringCompare(s, "plane") == 0) {
shape.type = PHYSICS_SHAPE_PLANE;
yyjson_val *n = yyjson_obj_get(obj, "normal");
if(n && yyjson_is_arr(n) && yyjson_arr_size(n) == 3) {
shape.data.plane.normal[0] = (float_t)yyjson_get_num(
yyjson_arr_get(n, 0)
);
shape.data.plane.normal[1] = (float_t)yyjson_get_num(
yyjson_arr_get(n, 1)
);
shape.data.plane.normal[2] = (float_t)yyjson_get_num(
yyjson_arr_get(n, 2)
);
}
yyjson_val *d = yyjson_obj_get(obj, "distance");
if(d) shape.data.plane.distance = (float_t)yyjson_get_num(d);
} else {
shape.type = PHYSICS_SHAPE_CUBE;
yyjson_val *he = yyjson_obj_get(obj, "halfExtents");
if(he && yyjson_is_arr(he) && yyjson_arr_size(he) == 3) {
shape.data.cube.halfExtents[0] = (float_t)yyjson_get_num(
yyjson_arr_get(he, 0)
);
shape.data.cube.halfExtents[1] = (float_t)yyjson_get_num(
yyjson_arr_get(he, 1)
);
shape.data.cube.halfExtents[2] = (float_t)yyjson_get_num(
yyjson_arr_get(he, 2)
);
}
}
entityPhysicsSetShape(entityId, componentId, shape);
}
v = yyjson_obj_get(obj, "velocity");
if(v && yyjson_is_arr(v) && yyjson_arr_size(v) == 3) {
phys->velocity[0] = (float_t)yyjson_get_num(yyjson_arr_get(v, 0));
phys->velocity[1] = (float_t)yyjson_get_num(yyjson_arr_get(v, 1));
phys->velocity[2] = (float_t)yyjson_get_num(yyjson_arr_get(v, 2));
}
v = yyjson_obj_get(obj, "gravityScale");
if(v) phys->gravityScale = (float_t)yyjson_get_num(v);
errorOk();
}
@@ -9,6 +9,8 @@
#include "entity/entitybase.h"
#include "physics/physicsshape.h"
#include "physics/physicsbodytype.h"
#include "error/error.h"
#include <yyjson.h>
typedef struct {
physicsbodytype_t type;
@@ -155,3 +157,34 @@ void entityPhysicsDispose(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Serializes body type, shape, velocity, and gravity scale to a JSON object.
* Runtime state (onGround) is not included.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param doc The mutable JSON document to allocate values from.
* @param obj The JSON object to write fields into.
*/
void entityPhysicsSerialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_mut_doc *doc,
yyjson_mut_val *obj
);
/**
* Deserializes body type, shape, velocity, and gravity scale from a JSON
* object.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param obj The JSON object to read fields from.
* @return Error state.
*/
errorret_t entityPhysicsDeserialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_val *obj
);
@@ -6,6 +6,8 @@
*/
#include "entity/entitymanager.h"
#include "assert/assert.h"
#include <yyjson.h>
void entityTriggerInit(
const entityid_t entityId,
@@ -52,3 +54,54 @@ void entityTriggerSetBounds(
glm_vec3_copy((float_t*)min, t->min);
glm_vec3_copy((float_t*)max, t->max);
}
void entityTriggerSerialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_mut_doc *doc,
yyjson_mut_val *obj
) {
entitytrigger_t *trigger = entityTriggerGet(entityId, componentId);
assertNotNull(trigger, "Failed to get trigger component.");
yyjson_mut_val *arr;
arr = yyjson_mut_arr(doc);
yyjson_mut_arr_add_real(doc, arr, (double)trigger->min[0]);
yyjson_mut_arr_add_real(doc, arr, (double)trigger->min[1]);
yyjson_mut_arr_add_real(doc, arr, (double)trigger->min[2]);
yyjson_mut_obj_add_val(doc, obj, "min", arr);
arr = yyjson_mut_arr(doc);
yyjson_mut_arr_add_real(doc, arr, (double)trigger->max[0]);
yyjson_mut_arr_add_real(doc, arr, (double)trigger->max[1]);
yyjson_mut_arr_add_real(doc, arr, (double)trigger->max[2]);
yyjson_mut_obj_add_val(doc, obj, "max", arr);
}
errorret_t entityTriggerDeserialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_val *obj
) {
entitytrigger_t *trigger = entityTriggerGet(entityId, componentId);
assertNotNull(trigger, "Failed to get trigger component.");
yyjson_val *v;
v = yyjson_obj_get(obj, "min");
if(v && yyjson_is_arr(v) && yyjson_arr_size(v) == 3) {
trigger->min[0] = (float_t)yyjson_get_num(yyjson_arr_get(v, 0));
trigger->min[1] = (float_t)yyjson_get_num(yyjson_arr_get(v, 1));
trigger->min[2] = (float_t)yyjson_get_num(yyjson_arr_get(v, 2));
}
v = yyjson_obj_get(obj, "max");
if(v && yyjson_is_arr(v) && yyjson_arr_size(v) == 3) {
trigger->max[0] = (float_t)yyjson_get_num(yyjson_arr_get(v, 0));
trigger->max[1] = (float_t)yyjson_get_num(yyjson_arr_get(v, 1));
trigger->max[2] = (float_t)yyjson_get_num(yyjson_arr_get(v, 2));
}
errorOk();
}
@@ -7,6 +7,8 @@
#pragma once
#include "entity/entitybase.h"
#include "error/error.h"
#include <yyjson.h>
typedef struct {
vec3 min;
@@ -47,3 +49,32 @@ void entityTriggerSetBounds(
const vec3 min,
const vec3 max
);
/**
* Serializes the trigger's min and max bounds to a JSON object.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param doc The mutable JSON document to allocate values from.
* @param obj The JSON object to write fields into.
*/
void entityTriggerSerialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_mut_doc *doc,
yyjson_mut_val *obj
);
/**
* Deserializes the trigger's min and max bounds from a JSON object.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param obj The JSON object to read fields from.
* @return Error state.
*/
errorret_t entityTriggerDeserialize(
const entityid_t entityId,
const componentid_t componentId,
yyjson_val *obj
);
+15 -5
View File
@@ -17,11 +17,21 @@
// Init function (optional)
// Dispose function (optional)
// Render function (optional)
// Serialize function (optional)
// Deserialize function (optional)
X(POSITION, entityposition_t, position, entityPositionInit, NULL, NULL)
X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL, NULL)
X(POSITION, entityposition_t, position,
entityPositionInit, NULL, NULL,
entityPositionSerialize, entityPositionDeserialize)
X(CAMERA, entitycamera_t, camera,
entityCameraInit, NULL, NULL,
entityCameraSerialize, entityCameraDeserialize)
X(RENDERABLE, entityrenderable_t, renderable,
entityRenderableInit, entityRenderableDispose, NULL)
entityRenderableInit, entityRenderableDispose, NULL,
entityRenderableSerialize, entityRenderableDeserialize)
X(PHYSICS, entityphysics_t, physics,
entityPhysicsInit, entityPhysicsDispose, NULL)
X(TRIGGER, entitytrigger_t, trigger, entityTriggerInit, NULL, NULL)
entityPhysicsInit, entityPhysicsDispose, NULL,
entityPhysicsSerialize, entityPhysicsDeserialize)
X(TRIGGER, entitytrigger_t, trigger,
entityTriggerInit, NULL, NULL,
entityTriggerSerialize, entityTriggerDeserialize)