techkaczynski.dev / code

summaryrefslogtreecommitdiff
path: root/ent.c
diff options
context:
space:
mode:
Diffstat (limited to 'ent.c')
-rw-r--r--ent.c184
1 files changed, 167 insertions, 17 deletions
diff --git a/ent.c b/ent.c
index 2f61aa7..d8a3a16 100644
--- a/ent.c
+++ b/ent.c
@@ -275,7 +275,9 @@ entity_draw_mdl(u64 id) {
Vec2 uv_scale = {1, 1};
Vec2 uv_offset = {0, 0};
- cstr shader_key = "default";
+ cstr shader_key = mdl->meshes[i].boneCount > 0
+ ? "skinned"
+ : "default";
if (mat_idx < model->mat_cnt) {
const MaterialOverride *override;
@@ -292,7 +294,12 @@ entity_draw_mdl(u64 id) {
}
if (override->shader_key) {
- shader_key = override->shader_key;
+ if (strcmp(override->shader_key,
+ "default") != 0 &&
+ strcmp(shader_key,
+ "skinned") != 0) {
+ shader_key = override->shader_key;
+ }
}
}
@@ -326,18 +333,18 @@ entity_draw_mdl(u64 id) {
(u8)((int)colour.a * tint.a / 255),
};
- /* Preserve DrawModel's GPU skinning support. */
- // int loc = SHADER_LOC_MATRIX_BONETRANSFORMS;
- // if (material.shader.locs != NULL &&
- // material.shader.locs[loc] != -1 &&
- // mdl->boneMatrices != NULL) {
- // rlEnableShader(material.shader.id);
- // rlSetUniformMatrices(
- // material.shader.locs[loc],
- // mdl->boneMatrices,
- // mdl->skeleton.boneCount
- // );
- // }
+ if (strcmp(shader_key, "skinned") == 0 &&
+ mdl->boneMatrices != NULL) {
+ int loc = fun_shader_uniform(shader_key,
+ "boneMatrices");
+
+ rlEnableShader(material.shader.id);
+ rlSetUniformMatrices(
+ loc,
+ mdl->boneMatrices,
+ mdl->skeleton.boneCount
+ );
+ }
bool nocull =
strcmp(shader_key, "alpha_cutoff_nocull") == 0 ||
@@ -607,6 +614,18 @@ entity_physics_clear(PhysicsCmp *phys) {
if (b3Body_IsValid(bdy->id)) {
b3DestroyBody(bdy->id);
}
+
+ if (bdy->meshes) {
+ for (u32 j = 0;
+ j < phys->bodies[i].shape_cnt;
+ ++j) {
+ if (bdy->meshes[j]) {
+ b3DestroyMesh(bdy->meshes[j]);
+ }
+ }
+ }
+
+ free(bdy->meshes);
free(bdy->shapes);
}
}
@@ -629,10 +648,12 @@ physics_build_shapes(u64 id, u32 body_index) {
runtime->shapes = calloc(
body->shape_cnt, sizeof(*runtime->shapes));
+ runtime->meshes = calloc(
+ body->shape_cnt, sizeof(*runtime->meshes));
- if (!runtime->shapes) {
- perror("physics shape handles allocation failed");
- exit(EXIT_FAILURE);
+ if (!runtime->shapes || !runtime->meshes) {
+ perror("physics shape allocation failed");
+ exit(1);
}
Matrix entity_world = entity_world_matrix(id);
@@ -826,6 +847,135 @@ physics_build_shapes(u64 id, u32 body_index) {
break;
}
+ case PHYS_SHAPE_CONVEX_HULL:
+ case PHYS_SHAPE_STATIC_TRIMESH: {
+ bool trimesh = shape->tag == PHYS_SHAPE_STATIC_TRIMESH;
+ if (trimesh && body->mode != PHYS_MODE_STATIC) {
+ TraceLog(LOG_WARNING,
+ "trimesh requires a static body");
+ break;
+ }
+
+ Vec3 *source = trimesh
+ ? shape->TriMesh.points
+ : shape->ConvexHull.points;
+
+ u32 point_cnt = trimesh
+ ? shape->TriMesh.point_cnt
+ : shape->ConvexHull.point_cnt;
+
+ if (!source || point_cnt < (trimesh ? 3u : 4u) ||
+ point_cnt > INT32_MAX) {
+ break;
+ }
+
+ b3Vec3 *points = malloc(point_cnt * sizeof(*points));
+ if (!points) {
+ perror("physics points allocation failed");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Bake the full transform into body-local geometry. */
+ for (u32 k = 0; k < point_cnt; ++k) {
+ Vec3 point =
+ Vector3Transform(source[k], world);
+ point = Vector3RotateByQuaternion(
+ Vector3Subtract(point, pos),
+ inverse_rot);
+
+ points[k] = (b3Vec3){
+ point.x, point.y, point.z,
+ };
+ }
+
+ if (!trimesh) {
+ b3HullData *hull =
+ b3CreateHull(
+ points,
+ (int)point_cnt,
+ (int)point_cnt);
+
+ if (hull) {
+ runtime->shapes[j] =
+ b3CreateTransformedHullShape(
+ runtime->id,
+ &def,
+ hull,
+ b3Transform_identity,
+ (b3Vec3){1, 1, 1});
+
+ b3DestroyHull(hull);
+ } else {
+ TraceLog(LOG_WARNING,
+ "convex hull creation failed");
+ }
+
+ free(points);
+ break;
+ }
+
+ u32 idx_cnt = shape->TriMesh.idx_cnt;
+ if (!shape->TriMesh.indices ||
+ idx_cnt < 3 || idx_cnt % 3 != 0 ||
+ idx_cnt > INT32_MAX) {
+ free(points);
+ break;
+ }
+
+ int32_t *indices = malloc(idx_cnt * sizeof(*indices));
+ if (!indices) {
+ perror("physics indices allocation failed");
+ exit(EXIT_FAILURE);
+ }
+
+ u32 k = 0;
+ for (; k < idx_cnt; ++k) {
+ u32 index = shape->TriMesh.indices[k];
+ if (index >= point_cnt) {
+ break;
+ }
+ indices[k] = (int32_t)index;
+ }
+
+ if (k != idx_cnt) {
+ TraceLog(LOG_WARNING,
+ "triangle mesh index out of range");
+ free(indices);
+ free(points);
+ break;
+ }
+
+ b3MeshDef mesh_def = {0};
+ mesh_def.vertices = points;
+ mesh_def.vertexCount = (int)point_cnt;
+ mesh_def.indices = indices;
+ mesh_def.triangleCount = (int)(idx_cnt / 3);
+ mesh_def.identifyEdges = true;
+
+ /* Preserve outward winding when the transform mirrors geometry. */
+ mesh_def.clockWiseWinding = Vector3DotProduct(
+ Vector3CrossProduct(
+ (Vec3){world.m0, world.m1, world.m2},
+ (Vec3){world.m4, world.m5, world.m6}),
+ (Vec3){world.m8, world.m9, world.m10}) < 0;
+
+ b3MeshData *mesh = b3CreateMesh(&mesh_def, NULL, 0);
+
+ free(indices);
+ free(points);
+
+ if (!mesh) {
+ TraceLog(LOG_WARNING,
+ "triangle mesh creation failed");
+ break;
+ }
+
+ runtime->meshes[j] = mesh;
+ runtime->shapes[j] = b3CreateMeshShape(
+ runtime->id, &def, mesh, (b3Vec3){1, 1, 1});
+ break;
+ }
+
default:
break;
}