| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625 |
- /*
- * Copyright (c) 2012-2024 Daniele Bartolini et al.
- * SPDX-License-Identifier: MIT
- */
- #include "config.h"
- #include "core/containers/array.inl"
- #include "core/containers/hash_map.inl"
- #include "core/filesystem/file.h"
- #include "core/filesystem/file_buffer.inl"
- #include "core/filesystem/filesystem.h"
- #include "core/json/json_object.inl"
- #include "core/json/sjson.h"
- #include "core/math/aabb.inl"
- #include "core/math/constants.h"
- #include "core/math/quaternion.inl"
- #include "core/math/sphere.inl"
- #include "core/memory/temp_allocator.inl"
- #include "core/strings/dynamic_string.inl"
- #include "core/strings/string.inl"
- #include "core/strings/string_id.inl"
- #include "resource/compile_options.inl"
- #include "resource/mesh.h"
- #include "resource/mesh_resource.h"
- #include "resource/physics_resource.h"
- #include "world/types.h"
- namespace crown
- {
- namespace physics_config_resource
- {
- const PhysicsMaterial *material(const PhysicsConfigResource *pcr, StringId32 name)
- {
- const PhysicsMaterial *begin = (PhysicsMaterial *)((const char *)pcr + pcr->materials_offset);
- for (u32 i = 0; i < pcr->num_materials; ++i) {
- if (begin[i].name == name)
- return &begin[i];
- }
- CE_FATAL("Material not found");
- return NULL;
- }
- const PhysicsActor *actor(const PhysicsConfigResource *pcr, StringId32 name)
- {
- const PhysicsActor *begin = (PhysicsActor *)((const char *)pcr + pcr->actors_offset);
- for (u32 i = 0; i < pcr->num_actors; ++i) {
- if (begin[i].name == name)
- return &begin[i];
- }
- CE_FATAL("Actor not found");
- return NULL;
- }
- const PhysicsCollisionFilter *filter(const PhysicsConfigResource *pcr, StringId32 name)
- {
- const PhysicsCollisionFilter *begin = (PhysicsCollisionFilter *)((const char *)pcr + pcr->filters_offset);
- for (u32 i = 0; i < pcr->num_filters; ++i) {
- if (begin[i].name == name)
- return &begin[i];
- }
- CE_FATAL("Filter not found");
- return NULL;
- }
- } // namespace physics_config_resource
- #if CROWN_CAN_COMPILE
- namespace physics_resource_internal
- {
- struct ColliderInfo
- {
- const char *name;
- ColliderType::Enum type;
- };
- static const ColliderInfo s_collider[] =
- {
- { "sphere", ColliderType::SPHERE },
- { "capsule", ColliderType::CAPSULE },
- { "box", ColliderType::BOX },
- { "convex_hull", ColliderType::CONVEX_HULL },
- { "mesh", ColliderType::MESH },
- { "heightfield", ColliderType::HEIGHTFIELD }
- };
- CE_STATIC_ASSERT(countof(s_collider) == ColliderType::COUNT);
- struct JointInfo
- {
- const char *name;
- JointType::Enum type;
- };
- static const JointInfo s_joint[] =
- {
- { "fixed", JointType::FIXED },
- { "hinge", JointType::HINGE },
- { "spring", JointType::SPRING }
- };
- CE_STATIC_ASSERT(countof(s_joint) == JointType::COUNT);
- static ColliderType::Enum shape_type_to_enum(const char *type)
- {
- for (u32 i = 0; i < countof(s_collider); ++i) {
- if (strcmp(type, s_collider[i].name) == 0)
- return s_collider[i].type;
- }
- return ColliderType::COUNT;
- }
- static JointType::Enum joint_type_to_enum(const char *type)
- {
- for (u32 i = 0; i < countof(s_joint); ++i) {
- if (strcmp(type, s_joint[i].name) == 0)
- return s_joint[i].type;
- }
- return JointType::COUNT;
- }
- void compile_sphere(ColliderDesc &sd, const Array<Vector3> &points)
- {
- AABB aabb;
- aabb::from_points(aabb, array::size(points), array::begin(points));
- const Vector3 origin = aabb::center(aabb);
- sd.local_tm.t = vector4(origin.x, origin.y, origin.z, 1.0f);
- sd.sphere.radius = max(0.0f, aabb.max.x - aabb.min.x);
- sd.sphere.radius = max(sd.sphere.radius, aabb.max.y - aabb.min.y);
- sd.sphere.radius = max(sd.sphere.radius, aabb.max.z - aabb.min.z);
- sd.sphere.radius *= 0.5f;
- }
- void compile_capsule(ColliderDesc &sd, const Array<Vector3> &points)
- {
- AABB aabb;
- aabb::from_points(aabb, array::size(points), array::begin(points));
- const Vector3 origin = aabb::center(aabb);
- sd.local_tm.t = vector4(origin.x, origin.y, origin.z, 1.0f);
- sd.capsule.radius = aabb::radius(aabb) / 2.0f;
- sd.capsule.height = (aabb.max.y - aabb.min.y) / 2.0f;
- }
- void compile_box(ColliderDesc &sd, const Array<Vector3> &points)
- {
- AABB aabb;
- aabb::from_points(aabb, array::size(points), array::begin(points));
- const Vector3 origin = aabb::center(aabb);
- sd.local_tm.t = vector4(origin.x, origin.y, origin.z, 1.0f);
- sd.box.half_size = (aabb.max - aabb.min) * 0.5f;
- }
- s32 compile_collider(Buffer &output, const char *json, CompileOptions &opts)
- {
- TempAllocator4096 ta;
- JsonObject obj(ta);
- sjson::parse(obj, json);
- DynamicString type(ta);
- sjson::parse_string(type, obj["shape"]);
- ColliderType::Enum st = shape_type_to_enum(type.c_str());
- DATA_COMPILER_ASSERT(st != ColliderType::COUNT
- , opts
- , "Unknown shape type: '%s'"
- , type.c_str()
- );
- ColliderDesc cd;
- memset((void *)&cd, 0, sizeof(cd));
- cd.type = st;
- cd.local_tm = MATRIX4X4_IDENTITY;
- cd.size = 0;
- Array<Vector3> points(default_allocator());
- Array<u16> point_indices(default_allocator());
- DynamicString source(ta);
- if (json_object::has(obj, "source"))
- sjson::parse_string(source, obj["source"]);
- bool explicit_collider = source == "mesh"
- || (source != "inline" && json_object::has(obj, "scene"));
- if (explicit_collider) {
- DynamicString scene(ta);
- DynamicString name(ta);
- sjson::parse_string(scene, obj["scene"]);
- sjson::parse_string(name, obj["name"]);
- // Parse mesh resource.
- Mesh mesh(default_allocator());
- s32 err = mesh::parse(mesh, opts, scene.c_str());
- DATA_COMPILER_ENSURE(err == 0, opts);
- Node deffault_node(default_allocator());
- Node &node = hash_map::get(mesh._nodes, name, deffault_node);
- DATA_COMPILER_ASSERT(&node != &deffault_node
- , opts
- , "Node '%s' does not exist"
- , name.c_str()
- );
- Geometry deffault_geometry(default_allocator());
- Geometry &geometry = hash_map::get(mesh._geometries, node._geometry, deffault_geometry);
- DATA_COMPILER_ASSERT(&geometry != &deffault_geometry
- , opts
- , "Geometry '%s' does not exist"
- , node._geometry.c_str()
- );
- for (u32 i = 0; i < array::size(geometry._positions); i += 3) {
- Vector3 p;
- p.x = geometry._positions[i + 0];
- p.y = geometry._positions[i + 1];
- p.z = geometry._positions[i + 2];
- array::push_back(points, p);
- }
- point_indices = geometry._position_indices;
- switch (cd.type) {
- case ColliderType::SPHERE: compile_sphere(cd, points); break;
- case ColliderType::CAPSULE: compile_capsule(cd, points); break;
- case ColliderType::BOX: compile_box(cd, points); break;
- case ColliderType::CONVEX_HULL: break;
- case ColliderType::MESH: break;
- case ColliderType::HEIGHTFIELD:
- DATA_COMPILER_ASSERT(false, opts, "Not implemented yet");
- break;
- default:
- DATA_COMPILER_ASSERT(false, opts, "Invalid collider type");
- break;
- }
- } else {
- JsonObject collider_data(ta);
- JsonArray org(ta);
- DATA_COMPILER_ASSERT(json_object::has(obj, "collider_data")
- , opts
- , "No collider_data found"
- );
- sjson::parse_object(collider_data, obj["collider_data"]);
- Quaternion rotation = sjson::parse_quaternion(collider_data["rotation"]);
- Vector3 position = sjson::parse_vector3(collider_data["position"]);
- Matrix4x4 matrix_local = from_quaternion_translation(rotation, position);
- cd.local_tm = matrix_local;
- if (cd.type == ColliderType::SPHERE) {
- cd.sphere.radius = sjson::parse_float(collider_data["radius"]);
- } else if (cd.type == ColliderType::BOX) {
- cd.box.half_size = sjson::parse_vector3(collider_data["half_extents"]);
- } else if (cd.type == ColliderType::CAPSULE) {
- cd.capsule.radius = sjson::parse_float(collider_data["radius"]);
- cd.capsule.height = sjson::parse_float(collider_data["height"]);
- } else {
- DATA_COMPILER_ASSERT(false, opts, "Invalid collider type");
- }
- }
- const bool needs_points = cd.type == ColliderType::CONVEX_HULL
- || cd.type == ColliderType::MESH;
- if (needs_points) {
- cd.size += sizeof(u32) + sizeof(Vector3)*array::size(points);
- if (cd.type == ColliderType::MESH)
- cd.size += sizeof(u32) + sizeof(u16)*array::size(point_indices);
- }
- FileBuffer fb(output);
- BinaryWriter bw(fb);
- bw.write(cd.type);
- bw.write(cd.local_tm);
- bw.write(cd.sphere.radius);
- bw.write(cd.capsule.radius);
- bw.write(cd.capsule.height);
- bw.write(cd.box.half_size);
- bw.write(cd.heightfield.width);
- bw.write(cd.heightfield.length);
- bw.write(cd.heightfield.height_scale);
- bw.write(cd.heightfield.height_min);
- bw.write(cd.heightfield.height_max);
- bw.write(cd.size);
- if (needs_points) {
- bw.write(array::size(points));
- for (u32 ii = 0; ii < array::size(points); ++ii)
- bw.write(points[ii]);
- if (cd.type == ColliderType::MESH) {
- bw.write(array::size(point_indices));
- for (u32 ii = 0; ii < array::size(point_indices); ++ii)
- bw.write(point_indices[ii]);
- }
- }
- return 0;
- }
- s32 compile_actor(Buffer &output, const char *json, CompileOptions & /*opts*/)
- {
- TempAllocator4096 ta;
- JsonObject obj(ta);
- sjson::parse(obj, json);
- u32 flags = 0;
- if (json_object::has(obj, "lock_translation_x") && sjson::parse_bool(obj["lock_translation_x"]))
- flags |= ActorFlags::LOCK_TRANSLATION_X;
- if (json_object::has(obj, "lock_translation_y") && sjson::parse_bool(obj["lock_translation_y"]))
- flags |= ActorFlags::LOCK_TRANSLATION_Y;
- if (json_object::has(obj, "lock_translation_z") && sjson::parse_bool(obj["lock_translation_z"]))
- flags |= ActorFlags::LOCK_TRANSLATION_Z;
- if (json_object::has(obj, "lock_rotation_x") && sjson::parse_bool(obj["lock_rotation_x"]))
- flags |= ActorFlags::LOCK_ROTATION_X;
- if (json_object::has(obj, "lock_rotation_y") && sjson::parse_bool(obj["lock_rotation_y"]))
- flags |= ActorFlags::LOCK_ROTATION_Y;
- if (json_object::has(obj, "lock_rotation_z") && sjson::parse_bool(obj["lock_rotation_z"]))
- flags |= ActorFlags::LOCK_ROTATION_Z;
- ActorResource ar;
- ar.actor_class = sjson::parse_string_id(obj["class"]);
- ar.mass = sjson::parse_float (obj["mass"]);
- ar.flags = flags;
- ar.collision_filter = sjson::parse_string_id(obj["collision_filter"]);
- ar.material = sjson::parse_string_id(obj["material"]);
- FileBuffer fb(output);
- BinaryWriter bw(fb);
- bw.write(ar.actor_class);
- bw.write(ar.mass);
- bw.write(ar.flags);
- bw.write(ar.collision_filter);
- bw.write(ar.material);
- return 0;
- }
- s32 compile_joint(Buffer &output, const char *json, CompileOptions &opts)
- {
- TempAllocator4096 ta;
- JsonObject obj(ta);
- sjson::parse(obj, json);
- DynamicString type(ta);
- sjson::parse_string(type, obj["type"]);
- JointType::Enum jt = joint_type_to_enum(type.c_str());
- DATA_COMPILER_ASSERT(jt != JointType::COUNT
- , opts
- , "Unknown joint type: '%s'"
- , type.c_str()
- );
- JointDesc jd;
- jd.type = jt;
- jd.anchor_0 = sjson::parse_vector3(obj["anchor_0"]);
- jd.anchor_1 = sjson::parse_vector3(obj["anchor_1"]);
- switch (jd.type) {
- case JointType::HINGE:
- jd.hinge.use_motor = sjson::parse_bool (obj["use_motor"]);
- jd.hinge.target_velocity = sjson::parse_float(obj["target_velocity"]);
- jd.hinge.max_motor_impulse = sjson::parse_float(obj["max_motor_impulse"]);
- jd.hinge.lower_limit = sjson::parse_float(obj["lower_limit"]);
- jd.hinge.upper_limit = sjson::parse_float(obj["upper_limit"]);
- jd.hinge.bounciness = sjson::parse_float(obj["bounciness"]);
- break;
- }
- FileBuffer fb(output);
- BinaryWriter bw(fb);
- bw.write(jd.type);
- bw.write(jd.anchor_0);
- bw.write(jd.anchor_1);
- bw.write(jd.breakable);
- bw.write(jd._pad[0]);
- bw.write(jd._pad[1]);
- bw.write(jd._pad[2]);
- bw.write(jd.break_force);
- bw.write(jd.hinge);
- bw.write(jd.hinge.axis);
- bw.write(jd.hinge.use_motor);
- bw.write(jd.hinge.target_velocity);
- bw.write(jd.hinge.max_motor_impulse);
- bw.write(jd.hinge.use_limits);
- bw.write(jd.hinge.lower_limit);
- bw.write(jd.hinge.upper_limit);
- bw.write(jd.hinge.bounciness);
- return 0;
- }
- } // namespace physics_resource_internal
- namespace physics_config_resource_internal
- {
- void parse_materials(const char *json, Array<PhysicsMaterial> &objects)
- {
- TempAllocator4096 ta;
- JsonObject obj(ta);
- sjson::parse(obj, json);
- auto cur = json_object::begin(obj);
- auto end = json_object::end(obj);
- for (; cur != end; ++cur) {
- JSON_OBJECT_SKIP_HOLE(obj, cur);
- const StringView key = cur->first;
- const char *value = cur->second;
- JsonObject material(ta);
- sjson::parse_object(material, value);
- PhysicsMaterial mat;
- mat.name = StringId32(key.data(), key.length());
- mat.friction = sjson::parse_float(material["friction"]);
- mat.rolling_friction = sjson::parse_float(material["rolling_friction"]);
- mat.restitution = sjson::parse_float(material["restitution"]);
- array::push_back(objects, mat);
- }
- }
- void parse_actors(const char *json, Array<PhysicsActor> &objects)
- {
- TempAllocator4096 ta;
- JsonObject obj(ta);
- sjson::parse(obj, json);
- auto cur = json_object::begin(obj);
- auto end = json_object::end(obj);
- for (; cur != end; ++cur) {
- JSON_OBJECT_SKIP_HOLE(obj, cur);
- const StringView key = cur->first;
- const char *value = cur->second;
- JsonObject actor(ta);
- sjson::parse_object(actor, value);
- PhysicsActor pa;
- pa.name = StringId32(key.data(), key.length());
- pa.linear_damping = 0.0f;
- pa.angular_damping = 0.0f;
- if (json_object::has(actor, "linear_damping"))
- pa.linear_damping = sjson::parse_float(actor["linear_damping"]);
- if (json_object::has(actor, "angular_damping"))
- pa.angular_damping = sjson::parse_float(actor["angular_damping"]);
- pa.flags = 0;
- if (json_object::has(actor, "dynamic") && sjson::parse_bool(actor["dynamic"]))
- pa.flags |= CROWN_PHYSICS_ACTOR_DYNAMIC;
- if (json_object::has(actor, "kinematic") && sjson::parse_bool(actor["kinematic"]))
- pa.flags |= CROWN_PHYSICS_ACTOR_KINEMATIC;
- if (json_object::has(actor, "disable_gravity") && sjson::parse_bool(actor["disable_gravity"]))
- pa.flags |= CROWN_PHYSICS_ACTOR_DISABLE_GRAVITY;
- if (json_object::has(actor, "trigger") && sjson::parse_bool(actor["trigger"]))
- pa.flags |= CROWN_PHYSICS_ACTOR_TRIGGER;
- array::push_back(objects, pa);
- }
- }
- struct CollisionFilterCompiler
- {
- CompileOptions &_opts;
- HashMap<StringId32, u32> _filter_map;
- Array<PhysicsCollisionFilter> _filters;
- u32 _filter;
- explicit CollisionFilterCompiler(CompileOptions &opts)
- : _opts(opts)
- , _filter_map(default_allocator())
- , _filters(default_allocator())
- , _filter(1)
- {
- }
- void parse(const char *json)
- {
- TempAllocator4096 ta;
- JsonObject obj(ta);
- sjson::parse(obj, json);
- auto cur = json_object::begin(obj);
- auto end = json_object::end(obj);
- for (; cur != end; ++cur) {
- JSON_OBJECT_SKIP_HOLE(obj, cur);
- const StringView key = cur->first;
- const StringId32 id = StringId32(key.data(), key.length());
- hash_map::set(_filter_map, id, new_filter_mask());
- }
- cur = json_object::begin(obj);
- end = json_object::end(obj);
- for (; cur != end; ++cur) {
- JSON_OBJECT_SKIP_HOLE(obj, cur);
- const StringView key = cur->first;
- const char *value = cur->second;
- const StringId32 id = StringId32(key.data(), key.length());
- TempAllocator4096 ta;
- JsonObject filter(ta);
- sjson::parse_object(filter, value);
- JsonArray collides_with(ta);
- sjson::parse_array(collides_with, filter["collides_with"]);
- u32 mask = 0;
- for (u32 i = 0; i < array::size(collides_with); ++i) {
- const StringId32 fi = sjson::parse_string_id(collides_with[i]);
- mask |= filter_to_mask(fi);
- }
- // Build mask
- PhysicsCollisionFilter pcf;
- pcf.name = id;
- pcf.me = filter_to_mask(id);
- pcf.mask = mask;
- array::push_back(_filters, pcf);
- }
- }
- u32 new_filter_mask()
- {
- DATA_COMPILER_ASSERT(_filter != 0x80000000u
- , _opts
- , "Too many collision filters"
- );
- const u32 f = _filter;
- _filter = _filter << 1;
- return f;
- }
- u32 filter_to_mask(StringId32 filter)
- {
- DATA_COMPILER_ASSERT(hash_map::has(_filter_map, filter)
- , _opts
- , "Filter not found"
- );
- return hash_map::get(_filter_map, filter, 0u);
- }
- };
- s32 compile(CompileOptions &opts)
- {
- Buffer buf = opts.read();
- TempAllocator4096 ta;
- JsonObject obj(ta);
- sjson::parse(obj, buf);
- Array<PhysicsMaterial> materials(default_allocator());
- Array<PhysicsActor> actors(default_allocator());
- CollisionFilterCompiler cfc(opts);
- // Parse materials
- if (json_object::has(obj, "collision_filters"))
- cfc.parse(obj["collision_filters"]);
- if (json_object::has(obj, "materials"))
- parse_materials(obj["materials"], materials);
- if (json_object::has(obj, "actors"))
- parse_actors(obj["actors"], actors);
- // Setup struct for writing
- PhysicsConfigResource pcr;
- pcr.version = RESOURCE_HEADER(RESOURCE_VERSION_PHYSICS_CONFIG);
- pcr.num_materials = array::size(materials);
- pcr.num_actors = array::size(actors);
- pcr.num_filters = array::size(cfc._filters);
- u32 offt = sizeof(PhysicsConfigResource);
- pcr.materials_offset = offt;
- offt += sizeof(PhysicsMaterial) * pcr.num_materials;
- pcr.actors_offset = offt;
- offt += sizeof(PhysicsActor) * pcr.num_actors;
- pcr.filters_offset = offt;
- // Write all
- opts.write(pcr.version);
- opts.write(pcr.num_materials);
- opts.write(pcr.materials_offset);
- opts.write(pcr.num_actors);
- opts.write(pcr.actors_offset);
- opts.write(pcr.num_filters);
- opts.write(pcr.filters_offset);
- // Write materials
- for (u32 i = 0; i < pcr.num_materials; ++i) {
- opts.write(materials[i].name._id);
- opts.write(materials[i].friction);
- opts.write(materials[i].rolling_friction);
- opts.write(materials[i].restitution);
- }
- // Write actors
- for (u32 i = 0; i < pcr.num_actors; ++i) {
- opts.write(actors[i].name._id);
- opts.write(actors[i].linear_damping);
- opts.write(actors[i].angular_damping);
- opts.write(actors[i].flags);
- }
- // Write collision filters
- for (u32 i = 0; i < array::size(cfc._filters); ++i) {
- opts.write(cfc._filters[i].name._id);
- opts.write(cfc._filters[i].me);
- opts.write(cfc._filters[i].mask);
- }
- return 0;
- }
- } // namespace physics_config_resource_internal
- #endif // if CROWN_CAN_COMPILE
- } // namespace crown
|