From c277ae7aff96fa42f50383ba4479045a8be70c19 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Sun, 22 Mar 2026 18:14:56 -0500 Subject: [PATCH 1/2] DOlphin shader prog --- cmake/targets/linux.cmake | 1 - src/duskdolphin/display/CMakeLists.txt | 3 ++- src/duskdolphin/display/shader/CMakeLists.txt | 10 ++++++++++ src/duskdolphin/display/shader/shaderdolphin.c | 11 +++++++++++ src/duskdolphin/display/shader/shaderdolphin.h | 17 +++++++++++++++++ .../display/shader/shaderplatform.h | 18 ++++++++++++++++++ .../display/shader/shaderunlitdolphin.c | 11 +++++++++++ 7 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 src/duskdolphin/display/shader/CMakeLists.txt create mode 100644 src/duskdolphin/display/shader/shaderdolphin.c create mode 100644 src/duskdolphin/display/shader/shaderdolphin.h create mode 100644 src/duskdolphin/display/shader/shaderplatform.h create mode 100644 src/duskdolphin/display/shader/shaderunlitdolphin.c diff --git a/cmake/targets/linux.cmake b/cmake/targets/linux.cmake index bec0a02..f83d136 100644 --- a/cmake/targets/linux.cmake +++ b/cmake/targets/linux.cmake @@ -29,7 +29,6 @@ target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC DUSK_SDL2 DUSK_OPENGL DUSK_LINUX - DUSK_OPENGL_LEGACY DUSK_DISPLAY_SIZE_DYNAMIC DUSK_DISPLAY_WIDTH_DEFAULT=640 DUSK_DISPLAY_HEIGHT_DEFAULT=480 diff --git a/src/duskdolphin/display/CMakeLists.txt b/src/duskdolphin/display/CMakeLists.txt index c52ff4f..914771b 100644 --- a/src/duskdolphin/display/CMakeLists.txt +++ b/src/duskdolphin/display/CMakeLists.txt @@ -14,4 +14,5 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} add_subdirectory(camera) add_subdirectory(framebuffer) add_subdirectory(mesh) -add_subdirectory(texture) \ No newline at end of file +add_subdirectory(texture) +add_subdirectory(shader) \ No newline at end of file diff --git a/src/duskdolphin/display/shader/CMakeLists.txt b/src/duskdolphin/display/shader/CMakeLists.txt new file mode 100644 index 0000000..ac6648b --- /dev/null +++ b/src/duskdolphin/display/shader/CMakeLists.txt @@ -0,0 +1,10 @@ +# 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 + shaderdolphin.c +) \ No newline at end of file diff --git a/src/duskdolphin/display/shader/shaderdolphin.c b/src/duskdolphin/display/shader/shaderdolphin.c new file mode 100644 index 0000000..f79c390 --- /dev/null +++ b/src/duskdolphin/display/shader/shaderdolphin.c @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "shadergl.h" +#include "util/memory.h" +#include "util/string.h" +#include "display/shader/shaderunlit.h" diff --git a/src/duskdolphin/display/shader/shaderdolphin.h b/src/duskdolphin/display/shader/shaderdolphin.h new file mode 100644 index 0000000..04f1c74 --- /dev/null +++ b/src/duskdolphin/display/shader/shaderdolphin.h @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "error/error.h" + +typedef struct { + void *empty; +} shaderdolphin_t; + +typedef struct { + void *empty; +} shaderdefinitiondolphin_t; \ No newline at end of file diff --git a/src/duskdolphin/display/shader/shaderplatform.h b/src/duskdolphin/display/shader/shaderplatform.h new file mode 100644 index 0000000..5e7eb35 --- /dev/null +++ b/src/duskdolphin/display/shader/shaderplatform.h @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "shaderdolphin.h" + +typedef shaderdolphin_t shaderplatform_t; +typedef shaderdefinitiondolphin_t shaderdefinitionplatform_t; + +#define shaderInitPlatform shaderInitDolphin +#define shaderBindPlatform shaderBindDolphin +#define shaderSetMatrixPlatform shaderSetMatrixDolphin +// #define shaderSetTexturePlatform shaderSetTextureDolphin +#define shaderDisposePlatform shaderDisposeDolphin \ No newline at end of file diff --git a/src/duskdolphin/display/shader/shaderunlitdolphin.c b/src/duskdolphin/display/shader/shaderunlitdolphin.c new file mode 100644 index 0000000..c9f68fc --- /dev/null +++ b/src/duskdolphin/display/shader/shaderunlitdolphin.c @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "display/shader/shaderunlit.h" + +shaderdefinition_t SHADER_UNLIT_DEFINITION = { +}; \ No newline at end of file -- 2.49.1 From 97513e354c2ad9d50eb2c9125e35cee47f897354 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Sun, 22 Mar 2026 23:32:43 -0500 Subject: [PATCH 2/2] Dolphin shaders --- src/dusk/display/camera/camera.c | 2 +- src/dusk/display/display.c | 16 +- src/duskdolphin/display/mesh/meshdolphin.c | 4 + src/duskdolphin/display/shader/CMakeLists.txt | 1 + .../display/shader/shaderdolphin.c | 154 +++++++++++++++++- .../display/shader/shaderdolphin.h | 86 +++++++++- .../display/shader/shaderunlitdolphin.c | 1 + 7 files changed, 254 insertions(+), 10 deletions(-) diff --git a/src/dusk/display/camera/camera.c b/src/dusk/display/camera/camera.c index bcabaf0..4f31481 100644 --- a/src/dusk/display/camera/camera.c +++ b/src/dusk/display/camera/camera.c @@ -56,7 +56,7 @@ void cameraGetProjectionMatrix(camera_t *camera, mat4 dest) { glm_mat4_identity(dest); glm_perspective( camera->perspective.fov, - SCREEN.aspect, + (640.0f / 480.0f), camera->nearClip, camera->farClip, dest diff --git a/src/dusk/display/display.c b/src/dusk/display/display.c index 61ce15a..ff8ca75 100644 --- a/src/dusk/display/display.c +++ b/src/dusk/display/display.c @@ -58,11 +58,15 @@ errorret_t displayUpdate(void) { errorChain(shaderBind(&SHADER_UNLIT)); camera_t camera; - cameraInitOrthographic(&camera); - camera.orthographic.left = 0.0f; - camera.orthographic.right = SCREEN.width; - camera.orthographic.top = SCREEN.height; - camera.orthographic.bottom = 0.0f; + // cameraInitOrthographic(&camera); + // camera.orthographic.left = 0.0f; + // camera.orthographic.right = SCREEN.width; + // camera.orthographic.top = SCREEN.height; + // camera.orthographic.bottom = 0.0f; + cameraInitPerspective(&camera); + camera.lookat.position[0] = 10.0f; + camera.lookat.position[1] = 10.0f; + camera.lookat.position[2] = 10.0f; mat4 proj, view, model; cameraGetProjectionMatrix(&camera, proj); @@ -75,7 +79,7 @@ errorret_t displayUpdate(void) { errorChain(spriteBatchPush( NULL, - TIME.time * 2.0f, TIME.time * 3.0f, 100, 100, COLOR_WHITE, 0, 0, 1, 1 + 0.0f, 0.0f, 100, 100, COLOR_WHITE, 0, 0, 1, 1 )); errorChain(spriteBatchFlush()); diff --git a/src/duskdolphin/display/mesh/meshdolphin.c b/src/duskdolphin/display/mesh/meshdolphin.c index 39be77f..022bde2 100644 --- a/src/duskdolphin/display/mesh/meshdolphin.c +++ b/src/duskdolphin/display/mesh/meshdolphin.c @@ -8,6 +8,7 @@ #include "display/mesh/mesh.h" #include "display/texture/texture.h" #include "assert/assert.h" +#include "display/shader/shader.h" errorret_t meshInitDolphin( meshdolphin_t *mesh, @@ -53,6 +54,9 @@ errorret_t meshDrawDolphin( sizeof(meshvertex_t) * vertexCount ); + // Update matrix. + errorChain(shaderUpdateMVPDolphin()); + const uint8_t stride = (uint8_t)sizeof(meshvertex_t); GX_SetArray(GX_VA_POS, (void*)&mesh->vertices[vertexOffset].pos[0], stride); GX_SetArray(GX_VA_CLR0, (void*)&mesh->vertices[vertexOffset].color.r, stride); diff --git a/src/duskdolphin/display/shader/CMakeLists.txt b/src/duskdolphin/display/shader/CMakeLists.txt index ac6648b..2addb51 100644 --- a/src/duskdolphin/display/shader/CMakeLists.txt +++ b/src/duskdolphin/display/shader/CMakeLists.txt @@ -7,4 +7,5 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC shaderdolphin.c + shaderunlitdolphin.c ) \ No newline at end of file diff --git a/src/duskdolphin/display/shader/shaderdolphin.c b/src/duskdolphin/display/shader/shaderdolphin.c index f79c390..9b2eb95 100644 --- a/src/duskdolphin/display/shader/shaderdolphin.c +++ b/src/duskdolphin/display/shader/shaderdolphin.c @@ -5,7 +5,159 @@ * https://opensource.org/licenses/MIT */ -#include "shadergl.h" #include "util/memory.h" #include "util/string.h" #include "display/shader/shaderunlit.h" +#include "assert/assert.h" +#include "log/log.h" + +shaderdolphin_t *SHADER_BOUND; + +errorret_t shaderInitDolphin( + shaderdolphin_t *shader, + const shaderdefinitiondolphin_t *def +) { + assertNotNull(shader, "Shader must not be null"); + assertNotNull(def, "Shader definition must not be null"); + + memoryZero(shader, sizeof(shaderdolphin_t)); + + glm_mat4_identity(shader->view); + glm_mat4_identity(shader->proj); + glm_mat4_identity(shader->model); + shader->dirtyMatrix = ( + SHADER_DOLPHIN_DIRTY_MODEL | + SHADER_DOLPHIN_DIRTY_PROJ | + SHADER_DOLPHIN_DIRTY_VIEW + ); + + errorOk(); +} + +errorret_t shaderBindDolphin(shaderdolphin_t *shader) { + assertNotNull(shader, "Shader must not be null"); + + SHADER_BOUND = shader; + + + GX_LoadProjectionMtx( + shader->matrixProjection, + shader->isProjectionPerspective ? GX_PERSPECTIVE : GX_ORTHOGRAPHIC + ); + GX_LoadPosMtxImm(shader->matrixModelView, GX_PNMTX0); + + errorOk(); +} + +errorret_t shaderSetMatrixDolphin( + shaderdolphin_t *shader, + const char_t *name, + mat4 mat +) { + assertNotNull(shader, "Shader must not be null"); + assertNotNull(name, "Uniform name must not be null"); + assertStrLenMin(name, 1, "Uniform name cannot be empty"); + + if(stringCompare(name, SHADER_UNLIT_PROJECTION) == 0) { + shader->dirtyMatrix |= SHADER_DOLPHIN_DIRTY_PROJ; + glm_mat4_copy(mat, shader->proj); + + } else if(stringCompare(name, SHADER_UNLIT_VIEW) == 0) { + shader->dirtyMatrix |= SHADER_DOLPHIN_DIRTY_VIEW; + glm_mat4_copy(mat, shader->view); + + } else if(stringCompare(name, SHADER_UNLIT_MODEL) == 0) { + shader->dirtyMatrix |= SHADER_DOLPHIN_DIRTY_MODEL; + glm_mat4_copy(mat, shader->model); + + } else { + assertUnreachable("Cannot use a custom matrix on dolphin."); + } + + errorOk(); +} + +errorret_t shaderDisposeDolphin(shaderdolphin_t *shader) { + assertNotNull(shader, "Shader must not be null"); + + SHADER_BOUND = NULL; + + errorOk(); +} + +errorret_t shaderUpdateMVPDolphin() { + assertNotNull(SHADER_BOUND, "Shader must not be null"); + + // Any changes? + if(SHADER_BOUND->dirtyMatrix == 0) errorOk(); + + // Need to update projection? + if((SHADER_BOUND->dirtyMatrix & SHADER_DOLPHIN_DIRTY_PROJ) != 0) { + shaderMat4ToMtx44(SHADER_BOUND->proj, SHADER_BOUND->matrixProjection); + + // Fix projection Z mapping between GLM and GX. + float A = SHADER_BOUND->matrixProjection[2][2]; + float B = SHADER_BOUND->matrixProjection[2][3]; + SHADER_BOUND->matrixProjection[2][2] = 0.5f * (A + 1.0f); + SHADER_BOUND->matrixProjection[2][3] = 0.5f * B; + + // Is this perspective or ortho originally? Dolphin cares for some reason. + const float_t epsilon = 0.0001f; + SHADER_BOUND->isProjectionPerspective = ( + fabsf(SHADER_BOUND->proj[3][2]) > epsilon && + fabsf(SHADER_BOUND->proj[3][3]) < epsilon + ); + + GX_LoadProjectionMtx( + SHADER_BOUND->matrixProjection, + SHADER_BOUND->isProjectionPerspective ? GX_PERSPECTIVE : GX_ORTHOGRAPHIC + ); + } + + // Need to update view or model? + bool_t mvDirt = false; + if((SHADER_BOUND->dirtyMatrix & SHADER_DOLPHIN_DIRTY_VIEW) != 0) { + shaderMat4ToMtx(SHADER_BOUND->view, SHADER_BOUND->matrixView); + mvDirt = true; + } + + if((SHADER_BOUND->dirtyMatrix & SHADER_DOLPHIN_DIRTY_MODEL) != 0) { + shaderMat4ToMtx(SHADER_BOUND->model, SHADER_BOUND->matrixModel); + mvDirt = true; + } + + // Set Model/View Matrix + if(mvDirt) { + guMtxConcat( + SHADER_BOUND->matrixView, + SHADER_BOUND->matrixModel, + SHADER_BOUND->matrixModelView + ); + GX_LoadPosMtxImm(SHADER_BOUND->matrixModelView, GX_PNMTX0); + } + + SHADER_BOUND->dirtyMatrix = 0; + errorOk(); +} + +void shaderMat4ToMtx44(const mat4 inGlmMatrix, Mtx44 outGXMatrix) { + assertNotNull(inGlmMatrix, "Input matrix cannot be null"); + assertNotNull(outGXMatrix, "Output matrix cannot be null"); + + for(int row = 0; row < 4; ++row) { + for(int col = 0; col < 4; ++col) { + outGXMatrix[row][col] = inGlmMatrix[col][row]; + } + } +} + +void shaderMat4ToMtx(const mat4 inGlmMatrix, Mtx outGXMatrix) { + assertNotNull(inGlmMatrix, "Input matrix cannot be null"); + assertNotNull(outGXMatrix, "Output matrix cannot be null"); + + for(int row = 0; row < 3; ++row) { + for(int col = 0; col < 4; ++col) { + outGXMatrix[row][col] = inGlmMatrix[col][row]; + } + } +} \ No newline at end of file diff --git a/src/duskdolphin/display/shader/shaderdolphin.h b/src/duskdolphin/display/shader/shaderdolphin.h index 04f1c74..c8c8a6e 100644 --- a/src/duskdolphin/display/shader/shaderdolphin.h +++ b/src/duskdolphin/display/shader/shaderdolphin.h @@ -9,9 +9,91 @@ #include "error/error.h" typedef struct { - void *empty; + mat4 view; + mat4 proj; + mat4 model; + + bool_t isProjectionPerspective; + Mtx44 matrixProjection; + Mtx matrixView; + Mtx matrixModel; + Mtx matrixModelView; + + uint_fast8_t dirtyMatrix; } shaderdolphin_t; typedef struct { void *empty; -} shaderdefinitiondolphin_t; \ No newline at end of file +} shaderdefinitiondolphin_t; + +#define SHADER_DOLPHIN_DIRTY_MODEL (1 << 0) +#define SHADER_DOLPHIN_DIRTY_PROJ (1 << 1) +#define SHADER_DOLPHIN_DIRTY_VIEW (1 << 2) + +extern shaderdolphin_t *SHADER_BOUND; + +/** + * Initializes a dolphin shader. Basically a render parameter pipeline. + * + * @param shader Shader to initialize. + * @param def Definition of the shader to initialize with. + * @return Error code if failure. + */ +errorret_t shaderInitDolphin( + shaderdolphin_t *shader, + const shaderdefinitiondolphin_t *def +); + +/** + * Binds a dolphin shader. Basically sets the render parameters for rendering. + * + * @param shader Shader to bind. + * @return Error code if failure. + */ +errorret_t shaderBindDolphin(shaderdolphin_t *shader); + +/** + * Sets a matrix uniform in the dolphin shader. Basically does nothing. + * + * @param shader Shader to set the matrix in. + * @param name Name of the uniform to set. + * @param matrix Matrix to set. + * @return Error code if failure. + */ +errorret_t shaderSetMatrixDolphin( + shaderdolphin_t *shader, + const char_t *name, + mat4 matrix +); + +/** + * Disposes a dolphin shader. Basically does nothing. + * + * @param shader Shader to dispose. + * @return Error code if failure. + */ +errorret_t shaderDisposeDolphin(shaderdolphin_t *shader); + +/** + * Internal Dolphin method, called right before a draw call to perform a matrix + * update and recalc. + * + * @return Error code if failure. + */ +errorret_t shaderUpdateMVPDolphin(); + +/** + * Converts a glm style column major mat4 to a GX compatible row major Mtx44. + * + * @param in Matrix to convert. + * @param out Output converted matrix. + */ +void shaderMat4ToMtx44(const mat4 in, Mtx44 out); + +/** + * Converts a glm style column major mat4 to a GX compatible row major Mtx. + * + * @param inGlmMatrix Matrix to convert. + * @param outGXMatrix Output converted matrix. + */ +void shaderMat4ToMtx(const mat4 inGlmMatrix, Mtx outGXMatrix); \ No newline at end of file diff --git a/src/duskdolphin/display/shader/shaderunlitdolphin.c b/src/duskdolphin/display/shader/shaderunlitdolphin.c index c9f68fc..8bb0f9f 100644 --- a/src/duskdolphin/display/shader/shaderunlitdolphin.c +++ b/src/duskdolphin/display/shader/shaderunlitdolphin.c @@ -8,4 +8,5 @@ #include "display/shader/shaderunlit.h" shaderdefinition_t SHADER_UNLIT_DEFINITION = { + 0 }; \ No newline at end of file -- 2.49.1