This commit is contained in:
2026-04-10 07:31:31 -05:00
parent 42099f7241
commit 0778ffb57a
35 changed files with 187 additions and 794 deletions
@@ -14,11 +14,6 @@
#error "cameraPushMatrixPlatform must be defined"
#endif
typedef enum {
CAMERA_PROJECTION_TYPE_PERSPECTIVE,
CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED,
CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC
} cameraprojectiontype_t;
typedef enum {
CAMERA_VIEW_TYPE_MATRIX,
-1
View File
@@ -10,7 +10,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
)
# Subdirectories
add_subdirectory(camera)
add_subdirectory(framebuffer)
add_subdirectory(mesh)
add_subdirectory(screen)
+21 -9
View File
@@ -37,17 +37,29 @@ errorret_t displayInit(void) {
errorChain(screenInit());
// Setup initial shader with default values
mat4 view, proj, model;
glm_lookat(
(vec3){ 0.0f, 0.0f, 1.0f },
(vec3){ 0.0f, 0.0f, 0.0f },
(vec3){ 0.0f, 1.0f, 0.0f },
view
);
glm_perspective(
glm_rad(45.0f),
(float_t)SCREEN.width / (float_t)SCREEN.height,
0.1f,
100.0f,
proj
);
glm_mat4_identity(model);
errorChain(shaderInit(&SHADER_UNLIT, &SHADER_UNLIT_DEFINITION));
camera_t cam;
cameraInit(&cam);
mat4 mat;
cameraGetProjectionMatrix(&cam, mat);
errorChain(shaderBind(&SHADER_UNLIT));
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_PROJECTION, mat));
cameraGetViewMatrix(&cam, mat);
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, mat));
glm_mat4_identity(mat);
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_MODEL, mat));
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_PROJECTION, proj));
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, view));
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_MODEL, model));
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, NULL));
errorOk();
-1
View File
@@ -7,7 +7,6 @@
#pragma once
#include "display/displayplatform.h"
#include "display/camera/camera.h"
// Expecting some definitions to be provided
#ifndef DUSK_DISPLAY_SIZE_DYNAMIC
+8 -14
View File
@@ -22,12 +22,6 @@ errorret_t screenInit() {
SCREEN.mode = SCREEN_MODE_FIXED_VIEWPORT_HEIGHT;
SCREEN.fixedHeight.height = DUSK_DISPLAY_SCREEN_HEIGHT;
cameraInitOrthographic(&SCREEN.framebufferCamera);
SCREEN.framebufferCamera.viewType = CAMERA_VIEW_TYPE_2D;
SCREEN.framebufferCamera._2d.position[0] = 0;
SCREEN.framebufferCamera._2d.position[1] = 0;
SCREEN.framebufferCamera._2d.zoom = 1.0f;
quadBuffer(
SCREEN.frameBufferMeshVertices,
0.0f, 0.0f,
@@ -352,13 +346,17 @@ errorret_t screenRender() {
fbY = (bbHeight - fbHeight) * 0.5f;
}
// Determine back buffer matricies
float_t centerX = bbWidth * 0.5f;
float_t centerY = bbHeight * 0.5f;
mat4 view, proj, model;
glm_ortho(
0.0f, bbWidth, bbHeight, 0.0f, 0.01f, 1.0f,
proj
);
glm_mat4_identity(view);
glm_mat4_identity(model);
SCREEN.framebufferCamera.orthographic.left = 0.0f;
SCREEN.framebufferCamera.orthographic.right = bbWidth;
SCREEN.framebufferCamera.orthographic.top = 0.0f;
SCREEN.framebufferCamera.orthographic.bottom = bbHeight;
quadBuffer(
SCREEN.frameBufferMeshVertices,
centerX - fbWidth * 0.5f, centerY + fbHeight * 0.5f, // top-left
@@ -374,10 +372,6 @@ errorret_t screenRender() {
);
shaderBind(&SHADER_UNLIT);
mat4 proj, view, model;
cameraGetProjectionMatrix(&SCREEN.framebufferCamera, proj);
cameraGetViewMatrix(&SCREEN.framebufferCamera, view);
glm_mat4_identity(model);
shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_PROJECTION, proj);
shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, view);
shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_MODEL, model);
+1 -2
View File
@@ -8,7 +8,6 @@
#pragma once
#include "dusk.h"
#include "display/framebuffer/framebuffer.h"
#include "display/camera/camera.h"
#include "display/mesh/quad.h"
#include "display/color.h"
@@ -50,7 +49,7 @@ typedef struct {
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
framebuffer_t framebuffer;
bool_t framebufferReady;
camera_t framebufferCamera;
// camera_t framebufferCamera;
mesh_t frameBufferMesh;
meshvertex_t frameBufferMeshVertices[QUAD_VERTEX_COUNT];
#endif
+21 -5
View File
@@ -68,26 +68,42 @@ componentindex_t componentGetIndex(
entityid_t componentGetEntitiesWithComponent(
const componenttype_t type,
entityid_t outEntities[ENTITY_COUNT_MAX]
entityid_t outEntities[ENTITY_COUNT_MAX],
componentid_t outComponents[ENTITY_COUNT_MAX]
) {
assertTrue(type < COMPONENT_TYPE_COUNT, "Component type OOB");
assertTrue(type != COMPONENT_TYPE_NULL, "Cannot check NULL type");
assertNotNull(outEntities, "Output entities array cannot be null");
assertNotNull(outComponents, "Output components array cannot be null");
entityid_t written = 0;
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
entityid_t used = ENTITY_MANAGER.entitiesWithComponent[
componentid_t used = ENTITY_MANAGER.entitiesWithComponent[
type * ENTITY_COUNT_MAX + i
];
if(used == 0xFF) continue;
outEntities[written++] = used;
assertTrue(
used == i, "Entity ID mismatch in entitiesWithComponent lookup"
ENTITY_MANAGER.components[componentGetIndex(i, used)].type == type,
"Component type mismatch in entitiesWithComponent lookup"
);
assertTrue(
(ENTITY_MANAGER.entities[used].state & ENTITY_STATE_ACTIVE) != 0,
(ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) != 0,
"Inactive entity in entitiesWithComponent lookup"
);
assertTrue(
used < ENTITY_COMPONENT_COUNT_MAX,
"Component ID OOB in entitiesWithComponent lookup"
);
assertTrue(
componentGetIndex(i, used) < ENTITY_COUNT_MAX * ENTITY_COMPONENT_COUNT_MAX,
"Component index OOB in entitiesWithComponent lookup"
);
assertTrue(
ENTITY_MANAGER.components[componentGetIndex(i,used)].type == type,
"Component type mismatch in entitiesWithComponent lookup"
);
outComponents[written] = used;
outEntities[written++] = i;
}
return written;
}
+3 -1
View File
@@ -87,11 +87,13 @@ componentindex_t componentGetIndex(
* @param type The type of the component to get entities for.
* @param outEntities An array to write the entity IDs to, must be at least
* ENTITY_COUNT_MAX in size.
* @param outComponents An array to write the component IDs to.
* @return The number of entity IDs written to outEntities.
*/
entityid_t componentGetEntitiesWithComponent(
const componenttype_t type,
entityid_t outEntities[ENTITY_COUNT_MAX]
entityid_t outEntities[ENTITY_COUNT_MAX],
componentid_t outComponents[ENTITY_COUNT_MAX]
);
/**
@@ -15,8 +15,8 @@ void entityCameraInit(const entityid_t ent, const componentid_t comp) {
);
cam->nearClip = 0.1f;
cam->farClip = 100.0f;
cam->projType = CAMERA_PROJECTION_TYPE_PERSPECTIVE;
cam->perspective.fov = 60.0f;
cam->projType = ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE;
cam->perspective.fov = glm_rad(45.0f);
}
void entityCameraGetProjection(
@@ -29,8 +29,8 @@ void entityCameraGetProjection(
);
if(
cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE ||
cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED
cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE ||
cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED
) {
glm_mat4_identity(out);
glm_perspective(
@@ -41,10 +41,10 @@ void entityCameraGetProjection(
out
);
if(cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED) {
if(cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED) {
out[1][1] *= -1.0f;
}
} else if(cam->projType == CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
} else if(cam->projType == ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
glm_mat4_identity(out);
glm_ortho(
cam->orthographic.left,
@@ -7,7 +7,12 @@
#pragma once
#include "entity/entitybase.h"
#include "display/camera/camera.h"
typedef enum {
ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE,
ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED,
ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC
} entitycameraprojectiontype_t;
typedef struct {
union {
@@ -25,7 +30,7 @@ typedef struct {
float_t nearClip;
float_t farClip;
cameraprojectiontype_t projType;
entitycameraprojectiontype_t projType;
} entitycamera_t;
/**
@@ -30,3 +30,14 @@ void entityPositionLookAt(
);
glm_lookat(eye, target, up, pos->transform);
}
void entityPositionGetTransform(
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_mat4_copy(pos->transform, dest);
}
@@ -39,3 +39,16 @@ void entityPositionLookAt(
vec3 up,
vec3 eye
);
/**
* Gets the transform matrix of the entity position component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest The destination matrix to write the transform to.
*/
void entityPositionGetTransform(
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
);
+23 -2
View File
@@ -37,11 +37,17 @@ componentid_t entityAddComponent(
for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) {
compInd = componentGetIndex(entityId, i);
if(ENTITY_MANAGER.components[compInd].type != COMPONENT_TYPE_NULL) continue;
if(ENTITY_MANAGER.components[compInd].type != COMPONENT_TYPE_NULL) {
assertTrue(
ENTITY_MANAGER.components[compInd].type != type,
"Entity already has component of this type"
);
continue;
}
componentInit(entityId, i, type);
ENTITY_MANAGER.entitiesWithComponent[
type * ENTITY_COUNT_MAX + entityId
] = entityId;
] = i;
return i;
}
@@ -49,6 +55,21 @@ componentid_t entityAddComponent(
return 0xFF;
}
componentid_t entityGetComponent(
const entityid_t entityId,
const componenttype_t type
) {
componentid_t compId = ENTITY_MANAGER.entitiesWithComponent[
type * ENTITY_COUNT_MAX + entityId
];
if(compId == 0xFF) return compId;
assertTrue(
ENTITY_MANAGER.components[componentGetIndex(entityId, compId)].type == type,
"Component type mismatch"
);
return compId;
}
void entityDispose(const entityid_t entityId) {
componentindex_t compInd;
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
+12
View File
@@ -33,6 +33,18 @@ componentid_t entityAddComponent(
const componenttype_t type
);
/**
* Gets the ID of the component of the given type on the entity with the given ID.
*
* @param entityId The ID of the entity to get the component from.
* @param type The type of the component to get.
* @return The ID of the component.
*/
componentid_t entityGetComponent(
const entityid_t entityId,
const componenttype_t type
);
/**
* Disposes of an entity with the given ID.
*
+1 -1
View File
@@ -11,7 +11,7 @@
typedef struct {
entity_t entities[ENTITY_COUNT_MAX];
component_t components[ENTITY_COUNT_MAX * ENTITY_COMPONENT_COUNT_MAX];
entityid_t entitiesWithComponent[COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX];
componentid_t entitiesWithComponent[COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX];
} entitymanager_t;
extern entitymanager_t ENTITY_MANAGER;
+46 -1
View File
@@ -8,8 +8,9 @@
#include "util/memory.h"
#include "log/log.h"
#include "time/time.h"
#include "display/camera/camera.h"
#include "display/screen/screen.h"
#include "entity/entitymanager.h"
#include "display/shader/shaderunlit.h"
scene_t SCENE;
@@ -31,7 +32,51 @@ errorret_t sceneUpdate(void) {
errorret_t sceneRender(void) {
// For each camera
entityid_t camEnts[ENTITY_COUNT_MAX];
componentid_t camComps[ENTITY_COUNT_MAX];
entityid_t camCount = componentGetEntitiesWithComponent(
COMPONENT_TYPE_CAMERA, camEnts, camComps
);
if(camCount == 0) errorOk();
// Matricies
mat4 view, proj, model;
for(entityid_t camIndex = 0; camIndex < camCount; camIndex++) {
entityid_t camEnt = camEnts[camIndex];
componentid_t camComp = camComps[camIndex];
componentid_t camPos = entityGetComponent(camEnt, COMPONENT_TYPE_POSITION);
if(camPos == 0xFF) {
logError("Camera entity without entity position found\n");
continue;
}
entityCameraGetProjection(camEnt, camComp, proj);
entityPositionGetTransform(camEnt, camPos, view);
}
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();
}
@@ -7,7 +7,6 @@
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
moduleglm.c
modulecamera.c
modulespritebatch.c
moduleglm.c
modulecolor.c
@@ -1,333 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "modulecamera.h"
#include "assert/assert.h"
#include "display/camera/camera.h"
#include "util/memory.h"
#include "util/string.h"
void moduleCamera(scriptcontext_t *context) {
assertNotNull(context, "Context cannot be NULL.");
// Create metatable for camera structure.
if(luaL_newmetatable(context->luaState, "camera_mt")) {
// Metatable methods
lua_pushcfunction(context->luaState, moduleCameraIndex);
lua_setfield(context->luaState, -2, "__index");
lua_pushcfunction(context->luaState, moduleCameraNewIndex);
lua_setfield(context->luaState, -2, "__newindex");
lua_pop(context->luaState, 1);
}
// Definitions
#define MODULE_CAMERA_SCRIPT_LEN 64
char_t buffer[MODULE_CAMERA_SCRIPT_LEN];
#define MODULE_CAMERA_DEF(str, val) \
snprintf( \
buffer, \
MODULE_CAMERA_SCRIPT_LEN, \
"%s = %d", \
str, \
val \
); \
scriptContextExec(context, buffer);
MODULE_CAMERA_DEF(
"CAMERA_PROJECTION_TYPE_PERSPECTIVE",
CAMERA_PROJECTION_TYPE_PERSPECTIVE
);
MODULE_CAMERA_DEF(
"CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED",
CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED
);
MODULE_CAMERA_DEF(
"CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC",
CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC
);
MODULE_CAMERA_DEF(
"CAMERA_VIEW_TYPE_MATRIX",
CAMERA_VIEW_TYPE_MATRIX
);
MODULE_CAMERA_DEF(
"CAMERA_VIEW_TYPE_LOOKAT",
CAMERA_VIEW_TYPE_LOOKAT
);
MODULE_CAMERA_DEF(
"CAMERA_VIEW_TYPE_2D",
CAMERA_VIEW_TYPE_2D
);
MODULE_CAMERA_DEF(
"CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT",
CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT
);
// Methods
lua_register(context->luaState, "cameraCreate", moduleCameraCreate);
lua_register(
context->luaState,
"cameraGetProjectionMatrix",
moduleCameraGetProjectionMatrix
);
lua_register(
context->luaState,
"cameraGetViewMatrix",
moduleCameraGetViewMatrix
);
}
int moduleCameraCreate(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL.");
scriptcontext_t *context = *(scriptcontext_t **)lua_getextraspace(L);
assertNotNull(context, "Script context cannot be NULL.");
// If we are provided a projection type, use it.
cameraprojectiontype_t projType = CAMERA_PROJECTION_TYPE_PERSPECTIVE;
if(lua_gettop(L) >= 1) {
if(!lua_isnumber(L, 1)) {
luaL_error(L, "Camera projection type must be a number.");
return 0;
}
projType = (cameraprojectiontype_t)lua_tonumber(L, 1);
}
// Create camera that Lua will own
camera_t *cam = (camera_t *)lua_newuserdata(L, sizeof(camera_t));
memoryZero(cam, sizeof(camera_t));
// Set metatable
luaL_getmetatable(L, "camera_mt");
lua_setmetatable(L, -2);
// Init camera
switch(projType) {
case CAMERA_PROJECTION_TYPE_PERSPECTIVE:
case CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED:
cameraInitPerspective(cam);
cam->projType = projType;
break;
case CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC:
cameraInitOrthographic(cam);
cam->projType = projType;
break;
default:
luaL_error(L, "Invalid camera projection type specified.");
break;
}
return 1;
}
int moduleCameraIndex(lua_State *l) {
assertNotNull(l, "Lua state cannot be NULL.");
const char_t *key = luaL_checkstring(l, 2);
assertStrLenMin(key, 1, "Key cannot be empty.");
camera_t *cam = (camera_t *)luaL_checkudata(l, 1, "camera_mt");
assertNotNull(cam, "Camera pointer cannot be NULL.");
if(stringCompare(key, "near") == 0) {
lua_pushnumber(l, cam->nearClip);
return 1;
} else if(stringCompare(key, "far") == 0) {
lua_pushnumber(l, cam->farClip);
return 1;
} else if(stringCompare(key, "nearClip") == 0) {
lua_pushnumber(l, cam->nearClip);
return 1;
} else if(stringCompare(key, "farClip") == 0) {
lua_pushnumber(l, cam->farClip);
return 1;
}
// Perspective relative values
if(cam->projType == CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
if(stringCompare(key, "left") == 0) {
lua_pushnumber(l, cam->orthographic.left);
return 1;
} else if(stringCompare(key, "right") == 0) {
lua_pushnumber(l, cam->orthographic.right);
return 1;
} else if(stringCompare(key, "top") == 0) {
lua_pushnumber(l, cam->orthographic.top);
return 1;
} else if(stringCompare(key, "bottom") == 0) {
lua_pushnumber(l, cam->orthographic.bottom);
return 1;
}
} else if(
cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE ||
cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED
) {
if(stringCompare(key, "fov") == 0) {
lua_pushnumber(l, cam->perspective.fov);
return 1;
}
}
// View type relative values.
if(cam->viewType == CAMERA_VIEW_TYPE_MATRIX) {
} else if(cam->viewType == CAMERA_VIEW_TYPE_LOOKAT) {
if(stringCompare(key, "position") == 0) {
vec3 *v = (vec3 *)lua_newuserdata(l, sizeof(vec3));
memoryCopy(v, &cam->lookat.position, sizeof(vec3));
luaL_getmetatable(l, "vec3_mt");
lua_setmetatable(l, -2);
return 1;
} else if(stringCompare(key, "target") == 0) {
vec3 *v = (vec3 *)lua_newuserdata(l, sizeof(vec3));
memoryCopy(v, &cam->lookat.target, sizeof(vec3));
luaL_getmetatable(l, "vec3_mt");
lua_setmetatable(l, -2);
return 1;
} else if(stringCompare(key, "up") == 0) {
vec3 *v = (vec3 *)lua_newuserdata(l, sizeof(vec3));
memoryCopy(v, &cam->lookat.up, sizeof(vec3));
luaL_getmetatable(l, "vec3_mt");
lua_setmetatable(l, -2);
return 1;
}
} else if(cam->viewType == CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT) {
} else if(cam->viewType == CAMERA_VIEW_TYPE_2D) {
}
lua_pushnil(l);
return 1;
}
int moduleCameraNewIndex(lua_State *l) {
assertNotNull(l, "Lua state cannot be NULL.");
const char_t *key = luaL_checkstring(l, 2);
assertStrLenMin(key, 1, "Key cannot be empty.");
camera_t *cam = (camera_t *)luaL_checkudata(l, 1, "camera_mt");
assertNotNull(cam, "Camera pointer cannot be NULL.");
if(stringCompare(key, "near") == 0 || stringCompare(key, "nearClip") == 0) {
if(!lua_isnumber(l, 3)) {
luaL_error(l, "Camera near clip must be a number.");
}
cam->nearClip = (float_t)lua_tonumber(l, 3);
return 0;
}
if(stringCompare(key, "far") == 0 || stringCompare(key, "farClip") == 0) {
if(!lua_isnumber(l, 3)) {
luaL_error(l, "Camera far clip must be a number.");
}
cam->farClip = (float_t)lua_tonumber(l, 3);
return 0;
}
// Perspective relative values
if(cam->projType == CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
if(stringCompare(key, "left") == 0) {
if(!lua_isnumber(l, 3)) {
luaL_error(l, "Camera orthographic left must be a number.");
}
cam->orthographic.left = (float_t)lua_tonumber(l, 3);
return 0;
}
if(stringCompare(key, "right") == 0) {
if(!lua_isnumber(l, 3)) {
luaL_error(l, "Camera orthographic right must be a number.");
}
cam->orthographic.right = (float_t)lua_tonumber(l, 3);
return 0;
}
if(stringCompare(key, "top") == 0) {
if(!lua_isnumber(l, 3)) {
luaL_error(l, "Camera orthographic top must be a number.");
}
cam->orthographic.top = (float_t)lua_tonumber(l, 3);
return 0;
}
if(stringCompare(key, "bottom") == 0) {
if(!lua_isnumber(l, 3)) {
luaL_error(l, "Camera orthographic bottom must be a number.");
}
cam->orthographic.bottom = (float_t)lua_tonumber(l, 3);
return 0;
}
} else if(
cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE ||
cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED
) {
if(stringCompare(key, "fov") == 0) {
if(!lua_isnumber(l, 3)) {
luaL_error(l, "Camera perspective FOV must be a number.");
}
cam->perspective.fov = (float_t)lua_tonumber(l, 3);
return 0;
}
}
if(cam->viewType == CAMERA_VIEW_TYPE_LOOKAT) {
if(stringCompare(key, "position") == 0) {
vec3 *v = (vec3 *)luaL_checkudata(l, 3, "vec3_mt");
assertNotNull(v, "Vec3 pointer cannot be NULL.");
memoryCopy(&cam->lookat.position, v, sizeof(vec3));
return 0;
} else if(stringCompare(key, "target") == 0) {
vec3 *v = (vec3 *)luaL_checkudata(l, 3, "vec3_mt");
assertNotNull(v, "Vec3 pointer cannot be NULL.");
memoryCopy(&cam->lookat.target, v, sizeof(vec3));
return 0;
} else if(stringCompare(key, "up") == 0) {
vec3 *v = (vec3 *)luaL_checkudata(l, 3, "vec3_mt");
assertNotNull(v, "Vec3 pointer cannot be NULL.");
memoryCopy(&cam->lookat.up, v, sizeof(vec3));
return 0;
}
}
return 0;
}
int moduleCameraGetProjectionMatrix(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL.");
camera_t *cam = (camera_t *)luaL_checkudata(L, 1, "camera_mt");
assertNotNull(cam, "Camera pointer cannot be NULL.");
// Create mat4
mat4 test;
cameraGetProjectionMatrix(cam, test);
// Lua needs to own this matrix now
mat4 *m = (mat4 *)lua_newuserdata(L, sizeof(mat4));
memoryCopy(m, test, sizeof(mat4));
return 1;
}
int moduleCameraGetViewMatrix(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL.");
camera_t *cam = (camera_t *)luaL_checkudata(L, 1, "camera_mt");
assertNotNull(cam, "Camera pointer cannot be NULL.");
// Create mat4
mat4 test;
cameraGetViewMatrix(cam, test);
// Lua needs to own this matrix now
mat4 *m = (mat4 *)lua_newuserdata(L, sizeof(mat4));
memoryCopy(m, test, sizeof(mat4));
return 1;
}
@@ -1,54 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/scriptcontext.h"
/**
* Register camera functions to the given script context.
*
* @param context The script context to register camera functions to.
*/
void moduleCamera(scriptcontext_t *context);
/**
* Script binding for creating a new camera.
*
* @param L The Lua state.
* @return Number of return values on the Lua stack.
*/
int moduleCameraCreate(lua_State *L);
/**
* Getter for camera structure fields.
*
* @param l The Lua state.
*/
int moduleCameraIndex(lua_State *l);
/**
* Setter for camera structure fields.
*
* @param l The Lua state.
*/
int moduleCameraNewIndex(lua_State *l);
/**
* Script binding for getting a camera's projection matrix.
*
* @param L The Lua state.
* @return Number of return values on the Lua stack.
*/
int moduleCameraGetProjectionMatrix(lua_State *L);
/**
* Script binding for getting a camera's view matrix.
*
* @param L The Lua state.
* @return Number of return values on the Lua stack.
*/
int moduleCameraGetViewMatrix(lua_State *L);
@@ -9,7 +9,6 @@
#include "assert/assert.h"
#include "display/shader/shader.h"
#include "display/shader/shaderunlit.h"
#include "display/camera/camera.h"
void moduleShader(scriptcontext_t *context) {
assertNotNull(context, "Context cannot be NULL.");
-2
View File
@@ -15,7 +15,6 @@
#include "script/module/event/moduleevent.h"
#include "script/module/display/modulecolor.h"
#include "script/module/display/modulespritebatch.h"
#include "script/module/display/modulecamera.h"
#include "script/module/display/moduleglm.h"
#include "script/module/display/moduleshader.h"
#include "script/module/ui/moduleui.h"
@@ -36,7 +35,6 @@ const scriptmodule_t SCRIPT_MODULE_LIST[] = {
{ .name = "time", .callback = moduleTime },
{ .name = "event", .callback = moduleEvent },
{ .name = "spritebatch", .callback = moduleSpriteBatch },
{ .name = "camera", .callback = moduleCamera },
{ .name = "glm", .callback = moduleGLM },
{ .name = "ui", .callback = moduleUi },
{ .name = "text", .callback = moduleText },
+9 -9
View File
@@ -16,9 +16,9 @@ ui_t UI;
errorret_t uiInit(void) {
memoryZero(&UI, sizeof(ui_t));
cameraInitOrthographic(&UI.camera);
UI.camera.orthographic.left = 0;
UI.camera.orthographic.bottom = 0;
// cameraInitOrthographic(&UI.camera);
// UI.camera.orthographic.left = 0;
// UI.camera.orthographic.bottom = 0;
errorOk();
}
@@ -27,14 +27,14 @@ void uiUpdate(void) {
}
void uiRender(void) {
UI.camera.orthographic.right = SCREEN.width;
UI.camera.orthographic.top = SCREEN.height;
// UI.camera.orthographic.right = SCREEN.width;
// UI.camera.orthographic.top = SCREEN.height;
// cameraPushMatrix(&UI.camera);
spriteBatchClear();
// // cameraPushMatrix(&UI.camera);
// spriteBatchClear();
spriteBatchFlush();
// cameraPopMatrix();
// spriteBatchFlush();
// // cameraPopMatrix();
}
void uiDispose(void) {
+1 -2
View File
@@ -6,11 +6,10 @@
*/
#pragma once
#include "display/camera/camera.h"
#include "error/error.h"
typedef struct {
camera_t camera;
void *nothing;
} ui_t;
extern ui_t UI;
-1
View File
@@ -11,7 +11,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
)
# Subdirs
add_subdirectory(camera)
add_subdirectory(framebuffer)
add_subdirectory(mesh)
add_subdirectory(texture)
@@ -1,11 +0,0 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
cameradolphin.c
)
@@ -1,111 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "display/camera/camera.h"
#include "display/framebuffer/framebuffer.h"
#include "assert/assert.h"
void cameraPushMatrixDolphin(camera_t *camera) {
assertNotNull(camera, "Camera cannot be null");
assertTrue(
camera->nearClip > 0.0f,
"Camera near clip must be greater than 0 for Dolphin"
);
Mtx44 guProjection;
Mtx guView;
Mtx modelView;
switch(camera->projType) {
case CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC:
guOrtho(
guProjection,
camera->orthographic.top,
camera->orthographic.bottom,
camera->orthographic.left,
camera->orthographic.right,
camera->nearClip,
camera->farClip
);
break;
case CAMERA_PROJECTION_TYPE_PERSPECTIVE:
guPerspective(
guProjection,
// FOV is in degrees.
camera->perspective.fov * (180.0f / GLM_PIf),
(float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND) /
(float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND),
camera->nearClip,
camera->farClip
);
break;
case CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED:
assertUnreachable("Flipped perspective not implemented on Dolphin");
break;
default:
assertUnreachable("Invalid camera projection type");
}
switch(camera->viewType) {
case CAMERA_VIEW_TYPE_LOOKAT:
guVector eye = {
camera->lookat.position[0],
camera->lookat.position[1],
camera->lookat.position[2]
};
guVector up = {
camera->lookat.up[0],
camera->lookat.up[1],
camera->lookat.up[2]
};
guVector look = {
camera->lookat.target[0],
camera->lookat.target[1],
camera->lookat.target[2]
};
guLookAt(guView, &eye, &up, &look);
break;
case CAMERA_VIEW_TYPE_MATRIX:
assertUnreachable("Matrix camera not implemented");
break;
case CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT:
assertUnreachable("Pixel perfect camera not implemented");
break;
case CAMERA_VIEW_TYPE_2D:
guMtxIdentity(guView);
guMtxTrans(guView, -camera->_2d.position[0], -camera->_2d.position[1], 0.0f);
guMtxScale(guView, camera->_2d.zoom, camera->_2d.zoom, 1.0f);
break;
default:
assertUnreachable("Invalid camera view type");
}
// Set Projection Matrix
GX_LoadProjectionMtx(
guProjection,
camera->projType == CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC ?
GX_ORTHOGRAPHIC :
GX_PERSPECTIVE
);
// Set view and model matrix. Dunno how I'll handle models but whatever.
guMtxIdentity(modelView);
guMtxTransApply(modelView, modelView, 0.0F, 0.0F, 0.0F);
guMtxConcat(guView,modelView,modelView);
GX_LoadPosMtxImm(modelView, GX_PNMTX0);
}
void cameraPopMatrixDolphin(void) {
}
@@ -1,23 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct camera_s camera_t;
/**
* Pushes the camera's transformation matrix onto the graphics stack.
*
* @param camera The camera to push the matrix of.
*/
void cameraPushMatrixDolphin(camera_t *camera);
/**
* Pops the camera's transformation matrix from the graphics stack.
*/
void cameraPopMatrixDolphin(void);
@@ -1,12 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "cameradolphin.h"
#define cameraPushMatrixPlatform cameraPushMatrixDolphin
#define cameraPopMatrixPlatform cameraPopMatrixDolphin
-1
View File
@@ -10,7 +10,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
)
# Subdirs
add_subdirectory(camera)
add_subdirectory(framebuffer)
add_subdirectory(texture)
add_subdirectory(mesh)
-10
View File
@@ -1,10 +0,0 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
cameragl.c
)
-135
View File
@@ -1,135 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "display/camera/camera.h"
#include "display/framebuffer/framebuffer.h"
#include "display/screen/screen.h"
#include "assert/assertgl.h"
void cameraPushMatrixGL(camera_t *camera) {
assertNotNull(camera, "Not a camera component");
mat4 projection;
mat4 view;
switch(camera->projType) {
case CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC: {
assertTrue(
camera->orthographic.right != camera->orthographic.left &&
camera->orthographic.top != camera->orthographic.bottom,
"Invalid orthographic projection parameters"
);
glm_ortho(
camera->orthographic.left,
camera->orthographic.right,
camera->orthographic.bottom,
camera->orthographic.top,
camera->nearClip,
camera->farClip,
projection
);
break;
}
case CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED:
case CAMERA_PROJECTION_TYPE_PERSPECTIVE: {
const float_t aspect = (
(float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND) /
(float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND)
);
glm_perspective(
camera->perspective.fov,
aspect,
camera->nearClip,
camera->farClip,
projection
);
if(camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED) {
// Flip Y axis
projection[1][1] *= -1;
}
break;
}
}
switch(camera->viewType) {
case CAMERA_VIEW_TYPE_MATRIX:
glm_mat4_ucopy(camera->view, view);
break;
case CAMERA_VIEW_TYPE_LOOKAT:
glm_lookat(
camera->lookat.position,
camera->lookat.target,
camera->lookat.up,
view
);
break;
case CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT:
assertTrue(
camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE ||
camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED,
"Pixel perfect camera view requires perspective projection"
);
// const float_t viewportHeight = (
// (float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND)
// );
const float_t viewportHeight = (float_t)SCREEN.height;
const float_t z = (viewportHeight / 2.0f) / (
camera->lookatPixelPerfect.pixelsPerUnit *
tanf(camera->perspective.fov / 2.0f)
);
vec3 position;
glm_vec3_copy(camera->lookatPixelPerfect.target, position);
glm_vec3_add(position, camera->lookatPixelPerfect.offset, position);
position[2] += z;
glm_lookat(
position,
camera->lookatPixelPerfect.target,
camera->lookatPixelPerfect.up,
view
);
break;
case CAMERA_VIEW_TYPE_2D:
glm_mat4_identity(view);
glm_translate(view, (vec3){
-camera->_2d.position[0],
-camera->_2d.position[1],
0.0f
});
glm_scale(view, (vec3){
camera->_2d.zoom,
camera->_2d.zoom,
1.0f
});
break;
default:
assertUnreachable("Invalid camera view type");
}
// glPushMatrix();
// glMatrixMode(GL_PROJECTION);
// glLoadIdentity();
// glLoadMatrixf((const GLfloat*)projection);
assertNoGLError("Failed to set projection matrix");
// glMatrixMode(GL_MODELVIEW);
// glLoadIdentity();
// glLoadMatrixf((const GLfloat*)view);
assertNoGLError("Failed to set view matrix");
}
void cameraPopMatrixGL(void) {
// glPopMatrix();
assertNoGLError("Failed to pop camera matrix");
}
-22
View File
@@ -1,22 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
typedef struct camera_s camera_t;
/**
* Initializes a camera with default perspective parameters.
*
* @param camera The camera to initialize.
*/
void cameraPushMatrixGL(camera_t *camera);
/**
* Removes the previously pushed camera matrix off the matrix stack.
*/
void cameraPopMatrixGL(void);
@@ -1,12 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "cameragl.h"
#define cameraPushMatrixPlatform cameraPushMatrixGL
#define cameraPopMatrixPlatform cameraPopMatrixGL