diff --git a/src/dusk/display/display.c b/src/dusk/display/display.c index 56c6d2af..8a48924c 100644 --- a/src/dusk/display/display.c +++ b/src/dusk/display/display.c @@ -10,6 +10,7 @@ #include "scene/scene.h" #include "display/spritebatch/spritebatch.h" #include "display/mesh/quad.h" +#include "display/mesh/cube.h" #include "display/screen/screen.h" #include "ui/ui.h" #include "display/text/text.h" @@ -31,6 +32,7 @@ errorret_t displayInit(void) { errorChain(displayPlatformInit()); #endif errorChain(quadInit()); + errorChain(cubeInit()); errorChain(frameBufferInitBackBuffer()); errorChain(spriteBatchInit()); errorChain(textInit()); diff --git a/src/dusk/display/mesh/CMakeLists.txt b/src/dusk/display/mesh/CMakeLists.txt index 10b3cbe3..872055e9 100644 --- a/src/dusk/display/mesh/CMakeLists.txt +++ b/src/dusk/display/mesh/CMakeLists.txt @@ -8,4 +8,5 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC mesh.c quad.c + cube.c ) \ No newline at end of file diff --git a/src/dusk/display/mesh/cube.c b/src/dusk/display/mesh/cube.c new file mode 100644 index 00000000..84852152 --- /dev/null +++ b/src/dusk/display/mesh/cube.c @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "cube.h" +#include "assert/assert.h" + +mesh_t CUBE_MESH_SIMPLE; +meshvertex_t CUBE_MESH_SIMPLE_VERTICES[CUBE_VERTEX_COUNT]; + +errorret_t cubeInit() { + vec3 min = { 0.0f, 0.0f, 0.0f }; + vec3 max = { 1.0f, 1.0f, 1.0f }; + cubeBuffer(CUBE_MESH_SIMPLE_VERTICES, min, max, COLOR_WHITE_4B); + errorChain(meshInit( + &CUBE_MESH_SIMPLE, + CUBE_PRIMITIVE_TYPE, + CUBE_VERTEX_COUNT, + CUBE_MESH_SIMPLE_VERTICES + )); + errorOk(); +} + +// Helper macro: set one vertex position, UV and color. +#define CUBE_VERT(i, px, py, pz, u, v) \ + vertices[i].pos[0] = (px); \ + vertices[i].pos[1] = (py); \ + vertices[i].pos[2] = (pz); \ + vertices[i].uv[0] = (u); \ + vertices[i].uv[1] = (v); \ + vertices[i].color = color + +void cubeBuffer( + meshvertex_t *vertices, + const vec3 min, + const vec3 max, + const color_t color +) { + assertNotNull(vertices, "Vertices cannot be NULL"); + assertNotNull(min, "Min vector cannot be NULL"); + assertNotNull(max, "Max vector cannot be NULL"); + + const float_t x0 = min[0], y0 = min[1], z0 = min[2]; + const float_t x1 = max[0], y1 = max[1], z1 = max[2]; + + // Front face (+Z normal) — CCW when viewed from +Z + CUBE_VERT( 0, x0, y0, z1, 0.0f, 0.0f); + CUBE_VERT( 1, x1, y0, z1, 1.0f, 0.0f); + CUBE_VERT( 2, x1, y1, z1, 1.0f, 1.0f); + CUBE_VERT( 3, x0, y0, z1, 0.0f, 0.0f); + CUBE_VERT( 4, x1, y1, z1, 1.0f, 1.0f); + CUBE_VERT( 5, x0, y1, z1, 0.0f, 1.0f); + + // Back face (-Z normal) — CCW when viewed from -Z + CUBE_VERT( 6, x1, y0, z0, 0.0f, 0.0f); + CUBE_VERT( 7, x0, y0, z0, 1.0f, 0.0f); + CUBE_VERT( 8, x0, y1, z0, 1.0f, 1.0f); + CUBE_VERT( 9, x1, y0, z0, 0.0f, 0.0f); + CUBE_VERT(10, x0, y1, z0, 1.0f, 1.0f); + CUBE_VERT(11, x1, y1, z0, 0.0f, 1.0f); + + // Right face (+X normal) — CCW when viewed from +X + CUBE_VERT(12, x1, y0, z1, 0.0f, 0.0f); + CUBE_VERT(13, x1, y0, z0, 1.0f, 0.0f); + CUBE_VERT(14, x1, y1, z0, 1.0f, 1.0f); + CUBE_VERT(15, x1, y0, z1, 0.0f, 0.0f); + CUBE_VERT(16, x1, y1, z0, 1.0f, 1.0f); + CUBE_VERT(17, x1, y1, z1, 0.0f, 1.0f); + + // Left face (-X normal) — CCW when viewed from -X + CUBE_VERT(18, x0, y0, z0, 0.0f, 0.0f); + CUBE_VERT(19, x0, y0, z1, 1.0f, 0.0f); + CUBE_VERT(20, x0, y1, z1, 1.0f, 1.0f); + CUBE_VERT(21, x0, y0, z0, 0.0f, 0.0f); + CUBE_VERT(22, x0, y1, z1, 1.0f, 1.0f); + CUBE_VERT(23, x0, y1, z0, 0.0f, 1.0f); + + // Top face (+Y normal) — CCW when viewed from +Y + CUBE_VERT(24, x0, y1, z1, 0.0f, 0.0f); + CUBE_VERT(25, x1, y1, z1, 1.0f, 0.0f); + CUBE_VERT(26, x1, y1, z0, 1.0f, 1.0f); + CUBE_VERT(27, x0, y1, z1, 0.0f, 0.0f); + CUBE_VERT(28, x1, y1, z0, 1.0f, 1.0f); + CUBE_VERT(29, x0, y1, z0, 0.0f, 1.0f); + + // Bottom face (-Y normal) — CCW when viewed from -Y + CUBE_VERT(30, x0, y0, z0, 0.0f, 0.0f); + CUBE_VERT(31, x1, y0, z0, 1.0f, 0.0f); + CUBE_VERT(32, x1, y0, z1, 1.0f, 1.0f); + CUBE_VERT(33, x0, y0, z0, 0.0f, 0.0f); + CUBE_VERT(34, x1, y0, z1, 1.0f, 1.0f); + CUBE_VERT(35, x0, y0, z1, 0.0f, 1.0f); + + #undef CUBE_VERT +} diff --git a/src/dusk/display/mesh/cube.h b/src/dusk/display/mesh/cube.h new file mode 100644 index 00000000..28c85c85 --- /dev/null +++ b/src/dusk/display/mesh/cube.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "display/mesh/mesh.h" +#include "display/color.h" + +#define CUBE_FACE_COUNT 6 +#define CUBE_VERTICES_PER_FACE 6 +#define CUBE_VERTEX_COUNT (CUBE_FACE_COUNT * CUBE_VERTICES_PER_FACE) +#define CUBE_PRIMITIVE_TYPE MESH_PRIMITIVE_TYPE_TRIANGLES + +extern mesh_t CUBE_MESH_SIMPLE; +extern meshvertex_t CUBE_MESH_SIMPLE_VERTICES[CUBE_VERTEX_COUNT]; + +/** + * Initializes the simple unit cube mesh (0,0,0) to (1,1,1). + * + * @return Error for initialization of the cube mesh. + */ +errorret_t cubeInit(); + +/** + * Buffers a 3D axis-aligned cube into the provided vertex array. + * Writes CUBE_VERTEX_COUNT vertices (6 faces x 6 vertices, CCW winding). + * + * @param vertices The vertex array to buffer into (must hold CUBE_VERTEX_COUNT). + * @param min The minimum XYZ corner of the cube. + * @param max The maximum XYZ corner of the cube. + * @param color The color applied to all vertices. + */ +void cubeBuffer( + meshvertex_t *vertices, + const vec3 min, + const vec3 max, + const color_t color +); diff --git a/src/dusk/engine/engine.c b/src/dusk/engine/engine.c index 9a7a168f..b653f61c 100644 --- a/src/dusk/engine/engine.c +++ b/src/dusk/engine/engine.c @@ -19,6 +19,8 @@ #include "entity/entitymanager.h" #include "game/game.h" +#include "display/mesh/cube.h" + engine_t ENGINE; errorret_t engineInit(const int32_t argc, const char_t **argv) { @@ -52,8 +54,17 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) { componentid_t camCam = entityAddComponent(cam, COMPONENT_TYPE_CAMERA); entityid_t ent1 = entityManagerAdd(); - - entityid_t ent2 = entityManagerAdd(); + componentid_t ent1Pos = entityAddComponent(ent1, COMPONENT_TYPE_POSITION); + componentid_t ent1Mesh = entityAddComponent(ent1, COMPONENT_TYPE_MESH); + + mesh_t *mesh = entityMeshGetMesh(ent1, ent1Mesh); + errorChain(meshInit( + mesh, + CUBE_PRIMITIVE_TYPE, + CUBE_VERTEX_COUNT, + CUBE_MESH_SIMPLE_VERTICES + )); + // EOF // Run the init script. diff --git a/src/dusk/entity/component/display/CMakeLists.txt b/src/dusk/entity/component/display/CMakeLists.txt index 42d047d4..193e309e 100644 --- a/src/dusk/entity/component/display/CMakeLists.txt +++ b/src/dusk/entity/component/display/CMakeLists.txt @@ -8,4 +8,5 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC entityposition.c entitycamera.c + entitymesh.c ) \ No newline at end of file diff --git a/src/dusk/entity/component/display/entitymesh.c b/src/dusk/entity/component/display/entitymesh.c new file mode 100644 index 00000000..00953fe5 --- /dev/null +++ b/src/dusk/entity/component/display/entitymesh.c @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "entity/entitymanager.h" + +void entityMeshInit( + const entityid_t entityId, + const componentid_t componentId +) { + entitymesh_t *comp = componentGetData( + entityId, componentId, COMPONENT_TYPE_MESH + ); + comp->mesh.vertexCount = 0; +} + +mesh_t * entityMeshGetMesh( + const entityid_t entityId, + const componentid_t componentId +) { + entitymesh_t *comp = componentGetData( + entityId, componentId, COMPONENT_TYPE_MESH + ); + return &comp->mesh; +} + +void entityMeshDispose( + const entityid_t entityId, + const componentid_t componentId +) { + entitymesh_t *comp = componentGetData( + entityId, componentId, COMPONENT_TYPE_MESH + ); + if(comp->mesh.vertexCount > 0) { + meshDispose(&comp->mesh); + comp->mesh.vertexCount = 0; + } +} diff --git a/src/dusk/entity/component/display/entitymesh.h b/src/dusk/entity/component/display/entitymesh.h new file mode 100644 index 00000000..c53d4223 --- /dev/null +++ b/src/dusk/entity/component/display/entitymesh.h @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "entity/entitybase.h" +#include "display/mesh/mesh.h" + +typedef struct { + mesh_t mesh; +} entitymesh_t; + +/** + * Initializes the entity mesh component. + * + * @param entityId The entity ID. + * @param componentId The component ID. + */ +void entityMeshInit( + const entityid_t entityId, + const componentid_t componentId +); + +/** + * Retrieves the mesh associated with the entity mesh component. + * + * @param entityId The entity ID. + * @param componentId The component ID. + * @return A pointer to the mesh associated with the entity mesh component. + */ +mesh_t * entityMeshGetMesh( + const entityid_t entityId, + const componentid_t componentId +); + +/** + * Disposes of the entity mesh component, freeing GPU resources if the mesh + * was initialized. + * + * @param entityId The entity ID. + * @param componentId The component ID. + */ +void entityMeshDispose( + const entityid_t entityId, + const componentid_t componentId +); diff --git a/src/dusk/entity/componentlist.h b/src/dusk/entity/componentlist.h index 88524620..5d3eaeb5 100644 --- a/src/dusk/entity/componentlist.h +++ b/src/dusk/entity/componentlist.h @@ -7,6 +7,8 @@ #include "entity/component/display/entityposition.h" #include "entity/component/display/entitycamera.h" +#include "entity/component/display/entitymesh.h" X(POSITION, entityposition_t, position, entityPositionInit, NULL) -X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL) \ No newline at end of file +X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL) +X(MESH, entitymesh_t, mesh, entityMeshInit, entityMeshDispose) \ No newline at end of file diff --git a/src/dusk/scene/scene.c b/src/dusk/scene/scene.c index e9860ffa..325552d2 100644 --- a/src/dusk/scene/scene.c +++ b/src/dusk/scene/scene.c @@ -11,6 +11,7 @@ #include "display/screen/screen.h" #include "entity/entitymanager.h" #include "display/shader/shaderunlit.h" +#include "display/mesh/cube.h" scene_t SCENE; @@ -31,7 +32,7 @@ errorret_t sceneUpdate(void) { } errorret_t sceneRender(void) { - // For each camera + // Get Cameras entityid_t camEnts[ENTITY_COUNT_MAX]; componentid_t camComps[ENTITY_COUNT_MAX]; entityid_t camCount = componentGetEntitiesWithComponent( @@ -39,8 +40,17 @@ errorret_t sceneRender(void) { ); if(camCount == 0) errorOk(); - // Matricies + // Get meshes + entityid_t meshEnts[ENTITY_COUNT_MAX]; + componentid_t meshComps[ENTITY_COUNT_MAX]; + entityid_t meshCount = componentGetEntitiesWithComponent( + COMPONENT_TYPE_MESH, meshEnts, meshComps + ); + if(meshCount == 0) errorOk(); + + // Prep Matricies mat4 view, proj, model; + errorChain(shaderBind(&SHADER_UNLIT)); for(entityid_t camIndex = 0; camIndex < camCount; camIndex++) { entityid_t camEnt = camEnts[camIndex]; @@ -53,31 +63,29 @@ errorret_t sceneRender(void) { entityCameraGetProjection(camEnt, camComp, proj); entityPositionGetTransform(camEnt, camPos, view); + + errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_PROJECTION, proj)); + errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, view)); + + // For each mesh. + for(entityid_t meshIndex = 0; meshIndex < meshCount; meshIndex++) { + entityid_t meshEnt = meshEnts[meshIndex]; + componentid_t meshComp = meshComps[meshIndex]; + componentid_t meshPos = entityGetComponent(meshEnt, COMPONENT_TYPE_POSITION); + if(meshPos == 0xFF) { + logError("Mesh entity without entity position found\n"); + continue; + } + + entityPositionGetTransform(meshEnt, meshPos, model); + errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_MODEL, model)); + + // Mesh + mesh_t *mesh = entityMeshGetMesh(meshEnt, meshComp); + errorChain(meshDraw(mesh, 0, -1)); + } } - glm_mat4_identity(model); - - // Shader - errorChain(shaderBind(&SHADER_UNLIT)); - errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_PROJECTION, proj)); - errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, view)); - errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_MODEL, model)); - - meshvertex_t quadVerts[QUAD_VERTEX_COUNT]; - quadBuffer( - quadVerts, - 0.0f, 0.0f, 1.0f, 1.0f, - COLOR_WHITE, - 0.0f, 0.0f, 1.0f, 1.0f - ); - mesh_t mesh; - errorChain(meshInit( - &mesh, MESH_PRIMITIVE_TYPE_TRIANGLES, - QUAD_VERTEX_COUNT, quadVerts - )); - errorChain(meshDraw(&mesh, 0, -1)); - meshDispose(&mesh); - errorOk(); }