diff options
| author | tech kaczynski <tk@techkaczynski.dev> | 2026-11-04 05:56:35 +1000 |
|---|---|---|
| committer | tech kaczynski <tk@techkaczynski.dev> | 2026-11-04 05:56:35 +1000 |
| commit | ea84213ece95e3ef8ff7f0095cee73ee6bdd0f9a (patch) | |
| tree | 32a502e72438ba0c6b6fa00dbd9dbdf3603fe7e3 /ent.c | |
| parent | e5560f69e11051a85c1d54780a59a4fbd83d8ed9 (diff) | |
added convex hull and trimesh colliders. Fixed physics edit mode bugs. Added debug drawing for all supported collision types.
Diffstat (limited to 'ent.c')
| -rw-r--r-- | ent.c | 184 |
1 files changed, 167 insertions, 17 deletions
@@ -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; } |
