Moved a bunch of code around
This commit is contained in:
@@ -7,99 +7,7 @@
|
|||||||
|
|
||||||
#include "sdl2.h"
|
#include "sdl2.h"
|
||||||
|
|
||||||
void displaySDL2Init(void) {
|
|
||||||
uint32_t flags = SDL_INIT_VIDEO;
|
|
||||||
#if INPUT_GAMEPAD == 1
|
|
||||||
flags |= SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK;
|
|
||||||
#endif
|
|
||||||
if(SDL_Init(flags) != 0) {
|
|
||||||
errorThrow("SDL Failed to Initialize: %s", SDL_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set OpenGL attributes (Needs to be done now or later?)
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
||||||
|
|
||||||
// Create window with OpenGL flag.
|
|
||||||
DISPLAY.window = SDL_CreateWindow(
|
|
||||||
"Dusk",
|
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
|
||||||
DISPLAY_WINDOW_WIDTH_DEFAULT,
|
|
||||||
DISPLAY_WINDOW_HEIGHT_DEFAULT,
|
|
||||||
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI |
|
|
||||||
SDL_WINDOW_OPENGL
|
|
||||||
);
|
|
||||||
if(!DISPLAY.window) {
|
|
||||||
errorThrow("SDL_CreateWindow failed: %s", SDL_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create OpenGL context
|
|
||||||
DISPLAY.glContext = SDL_GL_CreateContext(DISPLAY.window);
|
|
||||||
if(!DISPLAY.glContext) {
|
|
||||||
errorThrow("SDL_GL_CreateContext failed: %s", SDL_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_GL_SetSwapInterval(1);
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
glDisable(GL_LIGHTING);// PSP defaults this on?
|
|
||||||
glShadeModel(GL_SMOOTH); // Fixes color on PSP?
|
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glDepthFunc(GL_LEQUAL);
|
|
||||||
glClearDepth(1.0f);
|
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
||||||
|
|
||||||
glEnableClientState(GL_COLOR_ARRAY);// To confirm: every frame on PSP?
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
|
|
||||||
// Get and validate GL state.
|
|
||||||
GLenum err = glGetError();
|
|
||||||
if(err != GL_NO_ERROR) {
|
|
||||||
assertUnreachable("GL Error before checking support");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if PSP
|
|
||||||
displayInitPSP();
|
|
||||||
#else
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void displaySDL2Update(void) {
|
void displaySDL2Update(void) {
|
||||||
SDL_Event event;
|
|
||||||
while(SDL_PollEvent(&event)) {
|
|
||||||
switch(event.type) {
|
|
||||||
case SDL_QUIT: {
|
|
||||||
ENGINE.running = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_WINDOWEVENT: {
|
|
||||||
switch(event.window.event) {
|
|
||||||
case SDL_WINDOWEVENT_CLOSE: {
|
|
||||||
ENGINE.running = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_GL_MakeCurrent(DISPLAY.window, DISPLAY.glContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void displaySDL2Swap(void) {
|
void displaySDL2Swap(void) {
|
||||||
|
|||||||
@@ -14,4 +14,7 @@ target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
|||||||
DUSK_SDL2
|
DUSK_SDL2
|
||||||
DUSK_OPENGL
|
DUSK_OPENGL
|
||||||
DUSK_LINUX
|
DUSK_LINUX
|
||||||
|
DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
|
DUSK_DISPLAY_WIDTH_DEFAULT=640
|
||||||
|
DUSK_DISPLAY_HEIGHT_DEFAULT=480
|
||||||
)
|
)
|
||||||
@@ -8,12 +8,12 @@ add_subdirectory(dusk)
|
|||||||
if(DUSK_TARGET_SYSTEM STREQUAL "linux")
|
if(DUSK_TARGET_SYSTEM STREQUAL "linux")
|
||||||
add_subdirectory(dusklinux)
|
add_subdirectory(dusklinux)
|
||||||
add_subdirectory(dusksdl2)
|
add_subdirectory(dusksdl2)
|
||||||
add_subdirectory(duskopengl)
|
add_subdirectory(duskgl)
|
||||||
|
|
||||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||||
add_subdirectory(duskpsp)
|
add_subdirectory(duskpsp)
|
||||||
add_subdirectory(dusksdl2)
|
add_subdirectory(dusksdl2)
|
||||||
add_subdirectory(duskopengl)
|
add_subdirectory(duskgl)
|
||||||
|
|
||||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii")
|
elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii")
|
||||||
add_subdirectory(duskdolphin)
|
add_subdirectory(duskdolphin)
|
||||||
|
|||||||
@@ -7,9 +7,6 @@
|
|||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
display.c
|
display.c
|
||||||
framebuffer.c
|
|
||||||
screen.c
|
|
||||||
spritebatch.c
|
|
||||||
text.c
|
text.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
#include "display/display.h"
|
#include "display/display.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "display/framebuffer.h"
|
#include "display/framebuffer/framebuffer.h"
|
||||||
#include "display/screen.h"
|
#include "display/screen/screen.h"
|
||||||
|
|
||||||
void cameraInit(camera_t *camera) {
|
void cameraInit(camera_t *camera) {
|
||||||
cameraInitPerspective(camera);
|
cameraInitPerspective(camera);
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
|
|
||||||
#include "display/display.h"
|
#include "display/display.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "display/framebuffer.h"
|
#include "display/framebuffer/framebuffer.h"
|
||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
#include "display/spritebatch.h"
|
#include "display/spritebatch/spritebatch.h"
|
||||||
#include "display/mesh/quad.h"
|
#include "display/mesh/quad.h"
|
||||||
#include "display/screen.h"
|
#include "display/screen/screen.h"
|
||||||
#include "ui/ui.h"
|
#include "ui/ui.h"
|
||||||
#include "debug/debug.h"
|
#include "debug/debug.h"
|
||||||
#include "display/text.h"
|
#include "display/text.h"
|
||||||
@@ -25,10 +25,8 @@ display_t DISPLAY = { 0 };
|
|||||||
errorret_t displayInit(void) {
|
errorret_t displayInit(void) {
|
||||||
memoryZero(&DISPLAY, sizeof(DISPLAY));
|
memoryZero(&DISPLAY, sizeof(DISPLAY));
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
#ifdef displayPlatformInit
|
||||||
displaySDL2Init();
|
errorChain(displayPlatformInit());
|
||||||
#elif DOLPHIN
|
|
||||||
displayDolphinInit();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
quadInit();
|
quadInit();
|
||||||
@@ -42,8 +40,8 @@ errorret_t displayInit(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
errorret_t displayUpdate(void) {
|
errorret_t displayUpdate(void) {
|
||||||
#if DISPLAY_SDL2
|
#ifdef displayPlatformUpdate
|
||||||
displaySDL2Update();
|
errorChain(displayPlatformUpdate());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Reset state
|
// Reset state
|
||||||
@@ -60,19 +58,16 @@ errorret_t displayUpdate(void) {
|
|||||||
errorChain(sceneRender());
|
errorChain(sceneRender());
|
||||||
|
|
||||||
// Render UI
|
// Render UI
|
||||||
// uiRender();
|
uiRender();
|
||||||
|
|
||||||
// Finish up
|
// Finish up
|
||||||
screenUnbind();
|
screenUnbind();
|
||||||
screenRender();
|
screenRender();
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
// Swap and return.
|
||||||
displaySDL2Swap();
|
#ifdef displayPlatformSwap
|
||||||
#elif DOLPHIN
|
errorChain(displayPlatformSwap());
|
||||||
displayDolphinSwap();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// For now, we just return an OK error.
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,8 +76,8 @@ errorret_t displayDispose(void) {
|
|||||||
screenDispose();
|
screenDispose();
|
||||||
textDispose();
|
textDispose();
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
#ifdef displayPlatformDispose
|
||||||
displaySDL2Dispose();
|
displayPlatformDispose();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// For now, we just return an OK error.
|
// For now, we just return an OK error.
|
||||||
|
|||||||
@@ -6,12 +6,35 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "displaydefs.h"
|
|
||||||
#include "error/error.h"
|
|
||||||
#include "display/camera/camera.h"
|
|
||||||
#include "display/framebuffer.h"
|
|
||||||
#include "display/displayplatform.h"
|
#include "display/displayplatform.h"
|
||||||
|
#include "display/camera/camera.h"
|
||||||
|
|
||||||
|
// Expecting some definitions to be provided
|
||||||
|
#ifndef DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
|
#ifndef DUSK_DISPLAY_WIDTH
|
||||||
|
#error "DUSK_DISPLAY_WIDTH must be defined."
|
||||||
|
#endif
|
||||||
|
#ifndef DUSK_DISPLAY_HEIGHT
|
||||||
|
#error "DUSK_DISPLAY_HEIGHT must be defined"
|
||||||
|
#endif
|
||||||
|
#define DISPLAY_WINDOW_WIDTH_DEFAULT DUSK_DISPLAY_WIDTH
|
||||||
|
#define DISPLAY_WINDOW_HEIGHT_DEFAULT DUSK_DISPLAY_HEIGHT
|
||||||
|
#else
|
||||||
|
#ifndef DUSK_DISPLAY_WIDTH_DEFAULT
|
||||||
|
#error "DUSK_DISPLAY_WIDTH_DEFAULT must be defined."
|
||||||
|
#endif
|
||||||
|
#ifndef DUSK_DISPLAY_HEIGHT_DEFAULT
|
||||||
|
#error "DUSK_DISPLAY_HEIGHT_DEFAULT must be defined."
|
||||||
|
#endif
|
||||||
|
#ifdef DUSK_DISPLAY_WIDTH
|
||||||
|
#error "DUSK_DISPLAY_WIDTH should not be defined."
|
||||||
|
#endif
|
||||||
|
#ifdef DUSK_DISPLAY_HEIGHT
|
||||||
|
#error "DUSK_DISPLAY_HEIGHT should not be defined."
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Main Display Struct, platform-speicifc
|
||||||
typedef displayplatform_t display_t;
|
typedef displayplatform_t display_t;
|
||||||
|
|
||||||
extern display_t DISPLAY;
|
extern display_t DISPLAY;
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
|
|
||||||
#define GL_GLEXT_PROTOTYPES
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#include <GL/glext.h>
|
|
||||||
|
|
||||||
#ifndef DISPLAY_SIZE_DYNAMIC
|
|
||||||
#define DISPLAY_SIZE_DYNAMIC 1
|
|
||||||
#endif
|
|
||||||
#elif DOLPHIN
|
|
||||||
// Dolphin.
|
|
||||||
#define DISPLAY_FIFO_SIZE (256*1024)
|
|
||||||
#else
|
|
||||||
#error "Need to specify display backend."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 0
|
|
||||||
#ifndef DISPLAY_WIDTH
|
|
||||||
#error "DISPLAY_WIDTH must be defined when DISPLAY_SIZE_DYNAMIC is 0."
|
|
||||||
#endif
|
|
||||||
#ifndef DISPLAY_HEIGHT
|
|
||||||
#error "DISPLAY_HEIGHT must be defined when DISPLAY_SIZE_DYNAMIC is 0."
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DISPLAY_WINDOW_WIDTH_DEFAULT
|
|
||||||
#error "DISPLAY_WINDOW_WIDTH_DEFAULT must be defined."
|
|
||||||
#endif
|
|
||||||
#ifndef DISPLAY_WINDOW_HEIGHT_DEFAULT
|
|
||||||
#define DISPLAY_WINDOW_HEIGHT_DEFAULT DISPLAY_HEIGHT
|
|
||||||
#endif
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "framebuffer.h"
|
|
||||||
#include "display/display.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
|
|
||||||
framebuffer_t FRAMEBUFFER_BACKBUFFER = {0};
|
|
||||||
const framebuffer_t *FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
|
|
||||||
|
|
||||||
void frameBufferInitBackbuffer() {
|
|
||||||
memoryZero(&FRAMEBUFFER_BACKBUFFER, sizeof(framebuffer_t));
|
|
||||||
|
|
||||||
FRAMEBUFFER_BACKBUFFER.id = -1;
|
|
||||||
FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 1
|
|
||||||
void frameBufferInit(
|
|
||||||
framebuffer_t *framebuffer,
|
|
||||||
const uint32_t width,
|
|
||||||
const uint32_t height
|
|
||||||
) {
|
|
||||||
#if DISPLAY_SDL2 == 1
|
|
||||||
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
|
|
||||||
assertTrue(width > 0 && height > 0, "W/H must be greater than 0");
|
|
||||||
|
|
||||||
memoryZero(framebuffer, sizeof(framebuffer_t));
|
|
||||||
textureInit(&framebuffer->texture, width, height, TEXTURE_FORMAT_RGBA,(texturedata_t){
|
|
||||||
.rgbaColors = NULL
|
|
||||||
});
|
|
||||||
|
|
||||||
glGenFramebuffersEXT(1, &framebuffer->id);
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
|
|
||||||
|
|
||||||
glFramebufferTexture2DEXT(
|
|
||||||
GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
|
||||||
GL_TEXTURE_2D, framebuffer->texture.id, 0
|
|
||||||
);
|
|
||||||
|
|
||||||
if(
|
|
||||||
glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) !=
|
|
||||||
GL_FRAMEBUFFER_COMPLETE_EXT
|
|
||||||
) {
|
|
||||||
assertUnreachable("Framebuffer is not complete");
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int32_t frameBufferGetWidth(const framebuffer_t *framebuffer) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 0
|
|
||||||
return DISPLAY_WIDTH;
|
|
||||||
#else
|
|
||||||
int32_t windowWidth, windowHeight;
|
|
||||||
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
|
|
||||||
return windowWidth;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return framebuffer->texture.width;
|
|
||||||
|
|
||||||
#elif DOLPHIN
|
|
||||||
return DISPLAY.screenMode->fbWidth;
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error "Unsupported DISPLAY_TYPE."
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t frameBufferGetHeight(const framebuffer_t *framebuffer) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 0
|
|
||||||
return DISPLAY_HEIGHT;
|
|
||||||
#else
|
|
||||||
int32_t windowWidth, windowHeight;
|
|
||||||
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
|
|
||||||
return windowHeight;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return framebuffer->texture.height;
|
|
||||||
|
|
||||||
#elif DOLPHIN
|
|
||||||
return DISPLAY.screenMode->efbHeight;
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error "Unsupported DISPLAY_TYPE."
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void frameBufferBind(const framebuffer_t *framebuffer) {
|
|
||||||
if(framebuffer == NULL) {
|
|
||||||
frameBufferBind(&FRAMEBUFFER_BACKBUFFER);
|
|
||||||
FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the framebuffer for rendering
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
|
||||||
#if PSP
|
|
||||||
|
|
||||||
#else
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
#if PSP
|
|
||||||
assertUnreachable("Framebuffers not supported on PSP");
|
|
||||||
#else
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
glViewport(
|
|
||||||
0, 0,
|
|
||||||
frameBufferGetWidth(framebuffer), frameBufferGetHeight(framebuffer)
|
|
||||||
);
|
|
||||||
|
|
||||||
#elif DOLPHIN
|
|
||||||
GX_InvVtxCache();
|
|
||||||
GX_InvalidateTexAll();
|
|
||||||
GX_SetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE);
|
|
||||||
|
|
||||||
GX_SetViewport(
|
|
||||||
0, 0,
|
|
||||||
frameBufferGetWidth(framebuffer),
|
|
||||||
frameBufferGetHeight(framebuffer),
|
|
||||||
0, 1
|
|
||||||
);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FRAMEBUFFER_BOUND = framebuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void frameBufferClear(uint8_t flags, color_t color) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
GLbitfield glFlags = 0;
|
|
||||||
|
|
||||||
if(flags & FRAMEBUFFER_CLEAR_COLOR) {
|
|
||||||
glFlags |= GL_COLOR_BUFFER_BIT;
|
|
||||||
glClearColor(
|
|
||||||
color.r / 255.0f,
|
|
||||||
color.g / 255.0f,
|
|
||||||
color.b / 255.0f,
|
|
||||||
color.a / 255.0f
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(flags & FRAMEBUFFER_CLEAR_DEPTH) {
|
|
||||||
glFlags |= GL_DEPTH_BUFFER_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
glClear(glFlags);
|
|
||||||
#elif DOLPHIN
|
|
||||||
GX_SetCopyClear(
|
|
||||||
(GXColor){ color.r, color.g, color.b, color.a },
|
|
||||||
GX_MAX_Z24
|
|
||||||
);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void frameBufferDispose(framebuffer_t *framebuffer) {
|
|
||||||
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
|
||||||
assertUnreachable("Cannot dispose of backbuffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 0
|
|
||||||
assertUnreachable("Dynamic size framebuffers not supported");
|
|
||||||
#else
|
|
||||||
textureDispose(&framebuffer->texture);
|
|
||||||
glDeleteFramebuffersEXT(1, &framebuffer->id);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
64
src/dusk/display/framebuffer/framebuffer.c
Normal file
64
src/dusk/display/framebuffer/framebuffer.c
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "framebuffer.h"
|
||||||
|
#include "display/display.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
|
||||||
|
framebuffer_t FRAMEBUFFER_BACKBUFFER = {0};
|
||||||
|
const framebuffer_t *FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
|
||||||
|
|
||||||
|
errorret_t frameBufferInitBackbuffer() {
|
||||||
|
memoryZero(&FRAMEBUFFER_BACKBUFFER, sizeof(framebuffer_t));
|
||||||
|
errorChain(frameBufferPlatformInitBackbuffer());
|
||||||
|
FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
void frameBufferBind(framebuffer_t *framebuffer) {
|
||||||
|
if(framebuffer == NULL) {
|
||||||
|
frameBufferBind(&FRAMEBUFFER_BACKBUFFER);
|
||||||
|
FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorChain(frameBufferPlatformBind(framebuffer));
|
||||||
|
FRAMEBUFFER_BOUND = framebuffer;
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void frameBufferDispose(framebuffer_t *framebuffer) {
|
||||||
|
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
|
||||||
|
|
||||||
|
#if DISPLAY_SDL2
|
||||||
|
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
||||||
|
assertUnreachable("Cannot dispose of backbuffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DISPLAY_SIZE_DYNAMIC == 0
|
||||||
|
assertUnreachable("Dynamic size framebuffers not supported");
|
||||||
|
#else
|
||||||
|
textureDispose(&framebuffer->texture);
|
||||||
|
glDeleteFramebuffersEXT(1, &framebuffer->id);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
|
errorret_t frameBufferInit(
|
||||||
|
framebuffer_t *fb,
|
||||||
|
const uint32_t width,
|
||||||
|
const uint32_t height
|
||||||
|
) {
|
||||||
|
assertNotNull(fb, "Framebuffer cannot be NULL");
|
||||||
|
assertTrue(width > 0 && height > 0, "W/H must be greater than 0");
|
||||||
|
|
||||||
|
memoryZero(fb, sizeof(framebuffer_t));
|
||||||
|
errorChain(frameBufferPlatformInit(fb, width, height));
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -6,46 +6,32 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "error/error.h"
|
||||||
|
#include "display/framebuffer/framebufferplatform.h"
|
||||||
#include "display/texture/texture.h"
|
#include "display/texture/texture.h"
|
||||||
|
|
||||||
|
// Expected defs.
|
||||||
|
#ifndef frameBufferPlatformInitBackBuffer
|
||||||
|
#error "frameBufferPlatformInitBackBuffer not defined for this platform"
|
||||||
|
#endif
|
||||||
|
#ifndef frameBufferPlatformBind
|
||||||
|
#error "frameBufferPlatformBind not defined for this platform"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define FRAMEBUFFER_CLEAR_COLOR (1 << 0)
|
#define FRAMEBUFFER_CLEAR_COLOR (1 << 0)
|
||||||
#define FRAMEBUFFER_CLEAR_DEPTH (1 << 1)
|
#define FRAMEBUFFER_CLEAR_DEPTH (1 << 1)
|
||||||
|
|
||||||
typedef struct {
|
typedef framebufferplatform_t framebuffer_t;
|
||||||
#if DISPLAY_SDL2 == 1
|
|
||||||
// OpenGL Framebuffer Object ID
|
|
||||||
GLuint id;
|
|
||||||
texture_t texture;
|
|
||||||
#elif DOLPHIN
|
|
||||||
// --- IGNORE ---
|
|
||||||
uint8_t id;
|
|
||||||
#else
|
|
||||||
#error "Framebuffers not implemented on this platform."
|
|
||||||
#endif
|
|
||||||
} framebuffer_t;
|
|
||||||
|
|
||||||
extern framebuffer_t FRAMEBUFFER_BACKBUFFER;
|
extern framebuffer_t FRAMEBUFFER_BACKBUFFER;
|
||||||
extern const framebuffer_t *FRAMEBUFFER_BOUND;
|
extern const framebuffer_t *FRAMEBUFFER_BOUND;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the backbuffer framebuffer.
|
* Initializes the backbuffer framebuffer.
|
||||||
*/
|
|
||||||
void frameBufferInitBackbuffer(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a framebuffer.
|
|
||||||
*
|
*
|
||||||
* @param framebuffer The framebuffer to initialize.
|
* @return Error for initialization of the backbuffer.
|
||||||
* @param width The width of the framebuffer.
|
|
||||||
* @param height The height of the framebuffer.
|
|
||||||
*/
|
*/
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 1
|
errorret_t frameBufferInitBackBuffer(void);
|
||||||
void frameBufferInit(
|
|
||||||
framebuffer_t *framebuffer,
|
|
||||||
const uint32_t width,
|
|
||||||
const uint32_t height
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the width of the framebuffer.
|
* Gets the width of the framebuffer.
|
||||||
@@ -53,7 +39,7 @@ void frameBufferInitBackbuffer(void);
|
|||||||
* @param framebuffer The framebuffer to get the width of.
|
* @param framebuffer The framebuffer to get the width of.
|
||||||
* @return The width of the framebuffer, or 0 if the framebuffer is NULL.
|
* @return The width of the framebuffer, or 0 if the framebuffer is NULL.
|
||||||
*/
|
*/
|
||||||
int32_t frameBufferGetWidth(const framebuffer_t *framebuffer);
|
uint32_t frameBufferGetWidth(const framebuffer_t *framebuffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the height of the framebuffer.
|
* Gets the height of the framebuffer.
|
||||||
@@ -61,7 +47,7 @@ int32_t frameBufferGetWidth(const framebuffer_t *framebuffer);
|
|||||||
* @param framebuffer The framebuffer to get the height of.
|
* @param framebuffer The framebuffer to get the height of.
|
||||||
* @return The height of the framebuffer, or 0 if the framebuffer is NULL.
|
* @return The height of the framebuffer, or 0 if the framebuffer is NULL.
|
||||||
*/
|
*/
|
||||||
int32_t frameBufferGetHeight(const framebuffer_t *framebuffer);
|
uint32_t frameBufferGetHeight(const framebuffer_t *framebuffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds the framebuffer for rendering, or the backbuffer if the framebuffer
|
* Binds the framebuffer for rendering, or the backbuffer if the framebuffer
|
||||||
@@ -80,30 +66,29 @@ void frameBufferBind(const framebuffer_t *framebuffer);
|
|||||||
void frameBufferClear(uint8_t flags, color_t color);
|
void frameBufferClear(uint8_t flags, color_t color);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disposes of the framebuffer using EXT methods.
|
* Disposes of the framebuffer. Will also be used for request disposing of the
|
||||||
|
* backbuffer.
|
||||||
*
|
*
|
||||||
* @param framebuffer The framebuffer to dispose of.
|
* @param framebuffer The framebuffer to dispose of.
|
||||||
*/
|
*/
|
||||||
void frameBufferDispose(framebuffer_t *framebuffer);
|
void frameBufferDispose(framebuffer_t *framebuffer);
|
||||||
|
|
||||||
// #if RENDER_USE_FRAMEBUFFER
|
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
// typedef struct {
|
#ifndef frameBufferPlatformInit
|
||||||
// GLuint id;
|
#error "frameBufferPlatformInit not defined for this platform"
|
||||||
// texture_t texture;
|
#endif
|
||||||
// } framebuffer_t;
|
|
||||||
|
|
||||||
// /**
|
/**
|
||||||
// * Initializes a framebuffer using EXT methods.
|
* Initializes a framebuffer.
|
||||||
// *
|
*
|
||||||
// * @param framebuffer The framebuffer to initialize.
|
* @param framebuffer The framebuffer to initialize.
|
||||||
// * @param width The width of the framebuffer.
|
* @param width The width of the framebuffer.
|
||||||
// * @param height The height of the framebuffer.
|
* @param height The height of the framebuffer.
|
||||||
// * @return An error code indicating success or failure.
|
* @return Error for initialization of the framebuffer.
|
||||||
// */
|
*/
|
||||||
// void frameBufferInit(
|
errorret_t frameBufferInit(
|
||||||
// framebuffer_t *framebuffer,
|
framebuffer_t *framebuffer,
|
||||||
// const uint32_t width,
|
const uint32_t width,
|
||||||
// const uint32_t height
|
const uint32_t height
|
||||||
// );
|
);
|
||||||
|
#endif
|
||||||
// #endif
|
|
||||||
@@ -11,9 +11,9 @@
|
|||||||
#include "util/math.h"
|
#include "util/math.h"
|
||||||
#include "display/display.h"
|
#include "display/display.h"
|
||||||
|
|
||||||
const texture_t *TEXTURE_BOUND = NULL;
|
texture_t *TEXTURE_BOUND = NULL;
|
||||||
|
|
||||||
void textureInit(
|
errorret_t textureInit(
|
||||||
texture_t *texture,
|
texture_t *texture,
|
||||||
const int32_t width,
|
const int32_t width,
|
||||||
const int32_t height,
|
const int32_t height,
|
||||||
@@ -22,401 +22,29 @@ void textureInit(
|
|||||||
) {
|
) {
|
||||||
assertNotNull(texture, "Texture cannot be NULL");
|
assertNotNull(texture, "Texture cannot be NULL");
|
||||||
assertTrue(width > 0 && height > 0, "width/height must be greater than 0");
|
assertTrue(width > 0 && height > 0, "width/height must be greater than 0");
|
||||||
|
|
||||||
memoryZero(texture, sizeof(texture_t));
|
memoryZero(texture, sizeof(texture_t));
|
||||||
texture->width = width;
|
texture->width = width;
|
||||||
texture->height = height;
|
texture->height = height;
|
||||||
texture->format = format;
|
texture->format = format;
|
||||||
|
|
||||||
assertTrue(width == mathNextPowTwo(width), "Width must be a power of 2.");
|
assertTrue(width == mathNextPowTwo(width), "Width must be a power of 2.");
|
||||||
assertTrue(height == mathNextPowTwo(height), "Height must be a power of 2.");
|
assertTrue(height == mathNextPowTwo(height), "Height must be a power of 2.");
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
errorChain(textureInitPlatform(texture, width, height, format, data));
|
||||||
glGenTextures(1, &texture->id);
|
errorOk();
|
||||||
glBindTexture(GL_TEXTURE_2D, texture->id);
|
|
||||||
|
|
||||||
switch(format) {
|
|
||||||
case TEXTURE_FORMAT_RGBA:
|
|
||||||
glTexImage2D(
|
|
||||||
GL_TEXTURE_2D, 0, format, width, height, 0,
|
|
||||||
format, GL_UNSIGNED_BYTE, (void*)data.rgbaColors
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TEXTURE_FORMAT_PALETTE:
|
|
||||||
assertNotNull(data.paletteData, "Palette texture data cannot be NULL");
|
|
||||||
|
|
||||||
if(DISPLAY.usingShaderedPalettes) {
|
|
||||||
// Palette textures not supported, convert to GL_RED style texture
|
|
||||||
// so shader can perform the lookup.
|
|
||||||
uint8_t formatted[width * height];
|
|
||||||
for(int32_t i = 0; i < width * height; i++) {
|
|
||||||
uint8_t index = data.paletteData[i];
|
|
||||||
formatted[i] = index * 128;
|
|
||||||
}
|
|
||||||
glTexImage2D(
|
|
||||||
GL_TEXTURE_2D, 0, GL_R8, width, height, 0,
|
|
||||||
GL_RED, GL_UNSIGNED_BYTE, (void*)formatted
|
|
||||||
);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
glTexImage2D(
|
|
||||||
GL_TEXTURE_2D,
|
|
||||||
0, GL_COLOR_INDEX8_EXT,
|
|
||||||
width, height,
|
|
||||||
0, GL_COLOR_INDEX8_EXT,
|
|
||||||
GL_UNSIGNED_BYTE, (void*)data.paletteData
|
|
||||||
);
|
|
||||||
// glColorTableEXT(
|
|
||||||
// GL_TEXTURE_2D, GL_RGBA, data.palette.palette->colorCount, GL_RGBA,
|
|
||||||
// GL_UNSIGNED_BYTE, (const void*)data.palette.palette->colors
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
GLenum err = glGetError();
|
|
||||||
if(err != GL_NO_ERROR) {
|
|
||||||
printf("GL Error uploading palette texture: %d\n", err);
|
|
||||||
assertUnreachable("GL error uploading palette texture");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assertUnreachable("Unknown texture format");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
texture->ready = true;
|
|
||||||
|
|
||||||
#elif DOLPHIN
|
|
||||||
|
|
||||||
switch(format) {
|
|
||||||
case TEXTURE_FORMAT_RGBA:
|
|
||||||
assertTrue(
|
|
||||||
(width % 4) == 0 && (height % 4) == 0,
|
|
||||||
"RGB5A3 requires w/h multiple of 4 (or pad)"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Convert to RGB5A3 format
|
|
||||||
size_t rgbaSize = width * height * sizeof(u16);
|
|
||||||
texture->rgba = (u16*)memalign(32, rgbaSize);
|
|
||||||
assertNotNull(texture->rgba, "Failed to allocate texture RGBA data");
|
|
||||||
|
|
||||||
for(uint32_t y = 0; y < height; ++y) {
|
|
||||||
for(uint32_t x = 0; x < width; ++x) {
|
|
||||||
const int src = y * width + x;
|
|
||||||
|
|
||||||
const int tileX = x >> 2;
|
|
||||||
const int tileY = y >> 2;
|
|
||||||
const int tilesPerRow = width >> 2;
|
|
||||||
const int tileIndex = tileY * tilesPerRow + tileX;
|
|
||||||
const int tileBaseWords = tileIndex * 16;
|
|
||||||
const int inTile = ((y & 3) << 2) + (x & 3);
|
|
||||||
const int dest = tileBaseWords + inTile;
|
|
||||||
|
|
||||||
color4b_t col = data.rgba.colors[src];
|
|
||||||
|
|
||||||
u16 outCol;
|
|
||||||
if(col.a < 255) {
|
|
||||||
// 0AAA RRRR GGGG BBBB
|
|
||||||
outCol = (
|
|
||||||
(0u << 15) |
|
|
||||||
((u16)(col.a >> 5) << 12) |
|
|
||||||
((u16)(col.r >> 4) << 8) |
|
|
||||||
((u16)(col.g >> 4) << 4) |
|
|
||||||
((u16)(col.b >> 4) << 0)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// 1RRRR RRGG GGGB BBBB
|
|
||||||
outCol = (
|
|
||||||
(1u << 15) |
|
|
||||||
((u16)(col.r >> 3) << 10) |
|
|
||||||
((u16)(col.g >> 3) << 5) |
|
|
||||||
((u16)(col.b >> 3) << 0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
texture->rgba[dest] = outCol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DCFlushRange(texture->rgba, rgbaSize);
|
|
||||||
GX_InitTexObj(
|
|
||||||
&texture->texObj,
|
|
||||||
texture->rgba,
|
|
||||||
width, height,
|
|
||||||
GX_TF_RGB5A3,
|
|
||||||
GX_REPEAT, GX_REPEAT,
|
|
||||||
GX_FALSE
|
|
||||||
);
|
|
||||||
|
|
||||||
DCFlushRange(texture->rgba, rgbaSize);
|
|
||||||
GX_InvalidateTexAll();
|
|
||||||
|
|
||||||
GX_InitTexObjLOD(
|
|
||||||
&texture->texObj,
|
|
||||||
GX_NEAR, GX_NEAR,
|
|
||||||
0.0f, 0.0f, 0.0f,
|
|
||||||
GX_FALSE,
|
|
||||||
GX_FALSE,
|
|
||||||
GX_ANISO_1
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TEXTURE_FORMAT_ALPHA: {
|
|
||||||
assertTrue(
|
|
||||||
(width % 4) == 0 && (height % 4) == 0,
|
|
||||||
"GX_TF_I8 requires w/h multiple of 4 (or pad)"
|
|
||||||
);
|
|
||||||
|
|
||||||
// 1 byte per pixel (I8), GX expects 4x4 tiled layout
|
|
||||||
const size_t alphaSize = (size_t)width * (size_t)height;
|
|
||||||
|
|
||||||
texture->alpha = (u8*)memalign(32, alphaSize);
|
|
||||||
assertNotNull(texture->alpha, "Failed to allocate alpha texture data");
|
|
||||||
|
|
||||||
const u32 tilesPerRow = ((u32)width) >> 3; // /8
|
|
||||||
|
|
||||||
for (u32 y = 0; y < (u32)height; ++y) {
|
|
||||||
const u32 tileY = y >> 2; // /4
|
|
||||||
const u32 inTileY = (y & 3) << 3; // (y%4)*8
|
|
||||||
|
|
||||||
for (u32 x = 0; x < (u32)width; ++x) {
|
|
||||||
const u32 srcI = y * (u32)width + x;
|
|
||||||
const u8 srcA = data.alpha.data[srcI]; // linear input
|
|
||||||
|
|
||||||
const u32 tileX = x >> 3; // /8
|
|
||||||
const u32 tileIndex = tileY * tilesPerRow + tileX;
|
|
||||||
|
|
||||||
const u32 tileBase = tileIndex * 32; // 8*4*1 = 32 bytes per tile
|
|
||||||
const u32 inTile = inTileY + (x & 7); // (y%4)*8 + (x%8)
|
|
||||||
|
|
||||||
texture->alpha[tileBase + inTile] = 0xFF - srcA;// Fixes inverted alpha.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush CPU cache so GX sees the swizzled I8 texture data
|
|
||||||
DCFlushRange(texture->alpha, alphaSize);
|
|
||||||
|
|
||||||
// Initialize GX texture object with swizzled data
|
|
||||||
GX_InitTexObj(
|
|
||||||
&texture->texObj,
|
|
||||||
texture->alpha,
|
|
||||||
width, height,
|
|
||||||
GX_TF_I8,
|
|
||||||
GX_REPEAT, GX_REPEAT,
|
|
||||||
GX_FALSE
|
|
||||||
);
|
|
||||||
|
|
||||||
GX_InitTexObjLOD(
|
|
||||||
&texture->texObj,
|
|
||||||
GX_NEAR, GX_NEAR,
|
|
||||||
0.0f, 0.0f, 0.0f,
|
|
||||||
GX_FALSE,
|
|
||||||
GX_FALSE,
|
|
||||||
GX_ANISO_1
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TEXTURE_FORMAT_PALETTE: {
|
|
||||||
// Not supported, convert to RGBA using lookup
|
|
||||||
color_t* formatted = memoryAllocate(width * height * sizeof(color_t));
|
|
||||||
for(int32_t i = 0; i < width * height; i++) {
|
|
||||||
uint8_t index = data.palette.data[i];
|
|
||||||
assertTrue(
|
|
||||||
index < data.palette.palette->colorCount,
|
|
||||||
"Palette index out of range"
|
|
||||||
);
|
|
||||||
formatted[i] = data.palette.palette->colors[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
textureInit(
|
|
||||||
texture, width, height, TEXTURE_FORMAT_RGBA,
|
|
||||||
(texturedata_t){
|
|
||||||
.rgba = { .colors = formatted }
|
|
||||||
}
|
|
||||||
);
|
|
||||||
memoryFree(formatted);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
assertUnreachable("Unsupported texture format for Dolphin");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
texture->ready = true;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void textureBind(texture_t *texture) {
|
errorret_t textureBind(texture_t *texture) {
|
||||||
if(TEXTURE_BOUND == texture) return;
|
errorChain(textureBindPlatform(texture));
|
||||||
|
errorOk();
|
||||||
if(texture == NULL) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
glDisable(GL_TEXTURE_2D);
|
|
||||||
#elif DOLPHIN
|
|
||||||
GX_SetNumChans(0);
|
|
||||||
#endif
|
|
||||||
TEXTURE_BOUND = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue(texture->ready, "Texture ID must be ready");
|
|
||||||
assertTrue(
|
|
||||||
texture->width > 0 && texture->height > 0,
|
|
||||||
"Texture width and height must be greater than 0"
|
|
||||||
);
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture->id);
|
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
||||||
#elif DOLPHIN
|
|
||||||
GX_SetNumChans(1);
|
|
||||||
GX_LoadTexObj(&texture->texObj, GX_TEXMAP0);
|
|
||||||
#endif
|
|
||||||
TEXTURE_BOUND = texture;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void textureDispose(texture_t *texture) {
|
errorret_t textureDispose(texture_t *texture) {
|
||||||
assertNotNull(texture, "Texture cannot be NULL");
|
assertNotNull(texture, "Texture cannot be NULL");
|
||||||
assertTrue(texture->ready, "Texture ID must be ready");
|
|
||||||
|
|
||||||
if(TEXTURE_BOUND == texture) {
|
if(TEXTURE_BOUND == texture) {
|
||||||
textureBind(NULL);
|
textureBind(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
errorChain(textureDisposePlatform(texture));
|
||||||
glDeleteTextures(1, &texture->id);
|
errorOk();
|
||||||
#elif DOLPHIN
|
|
||||||
switch(texture->format) {
|
|
||||||
case TEXTURE_FORMAT_RGBA:
|
|
||||||
free(texture->rgba);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TEXTURE_FORMAT_ALPHA:
|
|
||||||
free(texture->alpha);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
memoryZero(texture, sizeof(texture_t));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DOLPHIN
|
|
||||||
void textureDolphinUploadTEV() {
|
|
||||||
if(TEXTURE_BOUND == NULL) {
|
|
||||||
GX_SetNumTexGens(0);
|
|
||||||
GX_SetNumTevStages(1);
|
|
||||||
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add channel for vertex color
|
|
||||||
GX_SetNumChans(1);
|
|
||||||
GX_SetChanCtrl(
|
|
||||||
GX_COLOR0A0,// Store in color channel 0
|
|
||||||
GX_DISABLE,// Lighting disabled
|
|
||||||
GX_SRC_REG,// Ambient color?
|
|
||||||
GX_SRC_VTX,// Material color?
|
|
||||||
GX_LIGHTNULL,// Light Mask
|
|
||||||
GX_DF_NONE,// Diffuse function
|
|
||||||
GX_AF_NONE// Attenuation function
|
|
||||||
);
|
|
||||||
|
|
||||||
// One set of UVs
|
|
||||||
GX_SetNumTexGens(1);
|
|
||||||
GX_SetTexCoordGen(
|
|
||||||
GX_TEXCOORD0,
|
|
||||||
GX_TG_MTX2x4,
|
|
||||||
GX_TG_TEX0,
|
|
||||||
GX_IDENTITY
|
|
||||||
);
|
|
||||||
|
|
||||||
// Basically the shader setup
|
|
||||||
switch(TEXTURE_BOUND->format) {
|
|
||||||
case TEXTURE_FORMAT_RGBA:
|
|
||||||
// One TEV stage: vertex color * texture color
|
|
||||||
GX_SetNumTevStages(1);
|
|
||||||
GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
|
|
||||||
GX_SetTevOrder(
|
|
||||||
GX_TEVSTAGE0,
|
|
||||||
GX_TEXCOORD0,
|
|
||||||
GX_TEXMAP0,
|
|
||||||
GX_COLOR0A0
|
|
||||||
);
|
|
||||||
GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
|
||||||
GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TEXTURE_FORMAT_ALPHA:
|
|
||||||
// One TEV stage: vertex color * texture color
|
|
||||||
GX_SetNumTevStages(1);
|
|
||||||
GX_SetTevOrder(
|
|
||||||
GX_TEVSTAGE0,
|
|
||||||
GX_TEXCOORD0,
|
|
||||||
GX_TEXMAP0,
|
|
||||||
GX_COLOR0A0
|
|
||||||
);
|
|
||||||
|
|
||||||
// Color = vertex color
|
|
||||||
GX_SetTevColorIn(
|
|
||||||
GX_TEVSTAGE0,
|
|
||||||
GX_CC_RASC,
|
|
||||||
GX_CC_ZERO,
|
|
||||||
GX_CC_ZERO,
|
|
||||||
GX_CC_ZERO
|
|
||||||
);
|
|
||||||
GX_SetTevColorOp(
|
|
||||||
GX_TEVSTAGE0,
|
|
||||||
GX_TEV_ADD,
|
|
||||||
GX_TB_ZERO,
|
|
||||||
GX_CS_SCALE_1,
|
|
||||||
GX_TRUE,
|
|
||||||
GX_TEVPREV
|
|
||||||
);
|
|
||||||
|
|
||||||
// Alpha = vertex alpha * I8 intensity
|
|
||||||
GX_SetTevAlphaIn(
|
|
||||||
GX_TEVSTAGE0,
|
|
||||||
GX_CA_RASA,
|
|
||||||
GX_CA_ZERO,
|
|
||||||
GX_CA_TEXA,
|
|
||||||
GX_CA_ZERO
|
|
||||||
);
|
|
||||||
GX_SetTevAlphaOp(
|
|
||||||
GX_TEVSTAGE0,
|
|
||||||
GX_TEV_ADD,
|
|
||||||
GX_TB_ZERO,
|
|
||||||
GX_CS_SCALE_1,
|
|
||||||
GX_TRUE,
|
|
||||||
GX_TEVPREV
|
|
||||||
);
|
|
||||||
|
|
||||||
GX_SetBlendMode(
|
|
||||||
GX_BM_BLEND,
|
|
||||||
GX_BL_SRCALPHA,
|
|
||||||
GX_BL_INVSRCALPHA,
|
|
||||||
GX_LO_CLEAR
|
|
||||||
);
|
|
||||||
|
|
||||||
GX_SetColorUpdate(GX_TRUE);
|
|
||||||
GX_SetAlphaUpdate(GX_TRUE);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assertUnreachable("Unknown texture format in meshDraw");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -6,44 +6,30 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "error/error.h"
|
||||||
#include "display/color.h"
|
#include "display/color.h"
|
||||||
#include "display/displaydefs.h"
|
|
||||||
#include "display/texture/palette.h"
|
#include "display/texture/palette.h"
|
||||||
|
#include "display/texture/textureplatform.h"
|
||||||
|
|
||||||
typedef enum {
|
#ifndef textureInitPlatform
|
||||||
#if DISPLAY_SDL2
|
#error "textureInitPlatform should not be defined."
|
||||||
TEXTURE_FORMAT_RGBA = GL_RGBA,
|
#endif
|
||||||
TEXTURE_FORMAT_PALETTE = GL_COLOR_INDEX8_EXT,
|
#ifndef textureBindPlatform
|
||||||
#elif DOLPHIN
|
#error "textureBindPlatform should not be defined."
|
||||||
// TEXTURE_FORMAT_RGBA = GX_TF_RGBA8,
|
#endif
|
||||||
// TEXTURE_FORMAT_ALPHA = GX_TF_A8,
|
#ifndef textureDisposePlatform
|
||||||
TEXTURE_FORMAT_PALETTE = GX_TF_CI8,
|
#error "textureDisposePlatform should not be defined."
|
||||||
#endif
|
#endif
|
||||||
} textureformat_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef textureformatplatform_t textureformat_t;
|
||||||
#if DISPLAY_SDL2
|
typedef textureplatform_t texture_t;
|
||||||
GLuint id;
|
|
||||||
#elif DOLPHIN
|
|
||||||
GXTexObj texObj;
|
|
||||||
union {
|
|
||||||
u16 *rgba;
|
|
||||||
u8 *alpha;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
textureformat_t format;
|
typedef union texturedata_u {
|
||||||
bool_t ready;
|
|
||||||
int32_t width;
|
|
||||||
int32_t height;
|
|
||||||
} texture_t;
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
uint8_t *paletteData;
|
uint8_t *paletteData;
|
||||||
color_t *rgbaColors;
|
color_t *rgbaColors;
|
||||||
} texturedata_t;
|
} texturedata_t;
|
||||||
|
|
||||||
extern const texture_t *TEXTURE_BOUND;
|
extern texture_t *TEXTURE_BOUND;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a texture.
|
* Initializes a texture.
|
||||||
@@ -54,7 +40,7 @@ extern const texture_t *TEXTURE_BOUND;
|
|||||||
* @param format The format of the texture (e.g., GL_RGBA, GL_ALPHA).
|
* @param format The format of the texture (e.g., GL_RGBA, GL_ALPHA).
|
||||||
* @param data The data for the texture, the format changes per format.
|
* @param data The data for the texture, the format changes per format.
|
||||||
*/
|
*/
|
||||||
void textureInit(
|
errorret_t textureInit(
|
||||||
texture_t *texture,
|
texture_t *texture,
|
||||||
const int32_t width,
|
const int32_t width,
|
||||||
const int32_t height,
|
const int32_t height,
|
||||||
@@ -67,18 +53,11 @@ void textureInit(
|
|||||||
*
|
*
|
||||||
* @param texture The texture to bind.
|
* @param texture The texture to bind.
|
||||||
*/
|
*/
|
||||||
void textureBind(texture_t *texture);
|
errorret_t textureBind(texture_t *texture);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disposes a texture.
|
* Disposes a texture.
|
||||||
*
|
*
|
||||||
* @param texture The texture to dispose.
|
* @param texture The texture to dispose.
|
||||||
*/
|
*/
|
||||||
void textureDispose(texture_t *texture);
|
errorret_t textureDispose(texture_t *texture);
|
||||||
|
|
||||||
#if DOLPHIN
|
|
||||||
/**
|
|
||||||
* Uploads the TEV settings for the currently bound texture.
|
|
||||||
*/
|
|
||||||
void textureDolphinUploadTEV();
|
|
||||||
#endif
|
|
||||||
@@ -10,3 +10,5 @@ target_include_directories(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
||||||
|
add_subdirectory(display)
|
||||||
|
add_subdirectory(error)
|
||||||
14
src/duskgl/display/CMakeLists.txt
Normal file
14
src/duskgl/display/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# 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
|
||||||
|
displaygl.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# Subdirs
|
||||||
|
add_subdirectory(framebuffer)
|
||||||
|
add_subdirectory(texture)
|
||||||
31
src/duskgl/display/displaygl.c
Normal file
31
src/duskgl/display/displaygl.c
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "displaygl.h"
|
||||||
|
|
||||||
|
errorret_t displayOpenGLInit(void) {
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_LIGHTING);// PSP defaults this on?
|
||||||
|
glShadeModel(GL_SMOOTH); // Fixes color on PSP?
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
glClearDepth(1.0f);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);// To confirm: every frame on PSP?
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
}
|
||||||
14
src/duskgl/display/displaygl.h
Normal file
14
src/duskgl/display/displaygl.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "error/errorgl.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the OpenGL specific contexts for rendering.
|
||||||
|
*/
|
||||||
|
errorret_t displayOpenGLInit(void);
|
||||||
9
src/duskgl/display/framebuffer/CMakeLists.txt
Normal file
9
src/duskgl/display/framebuffer/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# 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
|
||||||
|
)
|
||||||
133
src/duskgl/display/framebuffer/framebuffergl.c
Normal file
133
src/duskgl/display/framebuffer/framebuffergl.c
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "display/display.h"
|
||||||
|
#include "display/framebuffer/framebuffer.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
|
errorret_t frameBufferGLInitBackBuffer(void) {
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t frameBufferGetWidth(const framebuffer_t *framebuffer) {
|
||||||
|
if(framebuffer == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
||||||
|
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
|
int32_t windowWidth, windowHeight;
|
||||||
|
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
|
||||||
|
return windowWidth;
|
||||||
|
#else
|
||||||
|
return DUSK_DISPLAY_WIDTH;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return framebuffer->texture.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t frameBufferGLGetHeight(const framebuffer_t *framebuffer) {
|
||||||
|
if(framebuffer == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
||||||
|
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
|
int32_t windowWidth, windowHeight;
|
||||||
|
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
|
||||||
|
return windowHeight;
|
||||||
|
#else
|
||||||
|
return DUSK_DISPLAY_HEIGHT;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return framebuffer->texture.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t frameBufferGLBind(framebuffer_t *framebuffer) {
|
||||||
|
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
|
||||||
|
|
||||||
|
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
|
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
||||||
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||||
|
} else {
|
||||||
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
glViewport(
|
||||||
|
0, 0,
|
||||||
|
frameBufferGetWidth(framebuffer), frameBufferGetHeight(framebuffer)
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
glViewport(
|
||||||
|
0, 0,
|
||||||
|
DUSK_DISPLAY_WIDTH, DUSK_DISPLAY_HEIGHT
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void frameBufferClear(const uint8_t flags, const color_t color) {
|
||||||
|
GLbitfield glFlags = 0;
|
||||||
|
|
||||||
|
if(flags & FRAMEBUFFER_CLEAR_COLOR) {
|
||||||
|
glFlags |= GL_COLOR_BUFFER_BIT;
|
||||||
|
glClearColor(
|
||||||
|
color.r / 255.0f,
|
||||||
|
color.g / 255.0f,
|
||||||
|
color.b / 255.0f,
|
||||||
|
color.a / 255.0f
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(flags & FRAMEBUFFER_CLEAR_DEPTH) {
|
||||||
|
glFlags |= GL_DEPTH_BUFFER_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
glClear(glFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
|
errorret_t frameBufferGLInit(
|
||||||
|
framebuffer_t *fb,
|
||||||
|
const uint32_t width,
|
||||||
|
const uint32_t height
|
||||||
|
) {
|
||||||
|
assertNotNull(fb, "Framebuffer cannot be NULL");
|
||||||
|
assertTrue(width > 0 && height > 0, "W/H must be greater than 0");
|
||||||
|
|
||||||
|
memoryZero(fb, sizeof(framebuffer_t));
|
||||||
|
textureInit(&fb->texture, width, height, TEXTURE_FORMAT_RGBA,(texturedata_t){
|
||||||
|
.rgbaColors = NULL
|
||||||
|
});
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
glGenFramebuffersEXT(1, &fb->id);
|
||||||
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->id);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
glFramebufferTexture2DEXT(
|
||||||
|
GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
||||||
|
GL_TEXTURE_2D, fb->texture.id, 0
|
||||||
|
);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
if(
|
||||||
|
glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) !=
|
||||||
|
GL_FRAMEBUFFER_COMPLETE_EXT
|
||||||
|
) {
|
||||||
|
assertUnreachable("Framebuffer is not complete");
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
36
src/duskgl/display/framebuffer/framebuffergl.h
Normal file
36
src/duskgl/display/framebuffer/framebuffergl.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "display/texture/texture.h"
|
||||||
|
#include "error/errorgl.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GLuint id;
|
||||||
|
texture_t texture;
|
||||||
|
} framebuffergl_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the backbuffer framebuffer. (OpenGL implementation).
|
||||||
|
*/
|
||||||
|
errorret_t frameBufferGLInitBackBuffer(void);
|
||||||
|
|
||||||
|
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
|
/**
|
||||||
|
* Initializes an OpenGL style framebuffer.
|
||||||
|
*
|
||||||
|
* @param fb The framebuffer to initialize.
|
||||||
|
* @param width The width of the framebuffer.
|
||||||
|
* @param height The height of the framebuffer.
|
||||||
|
* @return Either error or not.
|
||||||
|
*/
|
||||||
|
errorret_t frameBufferGLInit(
|
||||||
|
framebuffergl_t *fb,
|
||||||
|
const uint32_t width,
|
||||||
|
const uint32_t height
|
||||||
|
);
|
||||||
|
#endif
|
||||||
14
src/duskgl/display/framebuffer/framebufferplatform.h
Normal file
14
src/duskgl/display/framebuffer/framebufferplatform.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "display/framebuffer/framebuffergl.h"
|
||||||
|
typedef framebuffergl_t framebufferplatform_t;
|
||||||
|
|
||||||
|
#define frameBufferPlatformInitBackBuffer frameBufferGLInitBackBuffer
|
||||||
|
#define frameBufferPlatformInit frameBufferGLInit
|
||||||
|
#define frameBufferPlatformBind frameBufferGLBind
|
||||||
10
src/duskgl/display/texture/CMakeLists.txt
Normal file
10
src/duskgl/display/texture/CMakeLists.txt
Normal file
@@ -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
|
||||||
|
texturegl.c
|
||||||
|
)
|
||||||
86
src/duskgl/display/texture/texturegl.c
Normal file
86
src/duskgl/display/texture/texturegl.c
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "display/texture/texture.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "error/errorgl.h"
|
||||||
|
|
||||||
|
errorret_t textureInitGL(
|
||||||
|
texturegl_t *texture,
|
||||||
|
const int32_t width,
|
||||||
|
const int32_t height,
|
||||||
|
const textureformatgl_t format,
|
||||||
|
const texturedata_t data
|
||||||
|
) {
|
||||||
|
glGenTextures(1, &texture->id);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture->id);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
switch(format) {
|
||||||
|
case TEXTURE_FORMAT_RGBA:
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D, 0, format, width, height, 0,
|
||||||
|
format, GL_UNSIGNED_BYTE, (void*)data.rgbaColors
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TEXTURE_FORMAT_PALETTE:
|
||||||
|
assertNotNull(data.paletteData, "Palette texture data cannot be NULL");
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0, GL_COLOR_INDEX8_EXT,
|
||||||
|
width, height,
|
||||||
|
0, GL_COLOR_INDEX8_EXT,
|
||||||
|
GL_UNSIGNED_BYTE, (void*)data.paletteData
|
||||||
|
);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
glColorTableEXT(
|
||||||
|
GL_TEXTURE_2D, GL_RGBA, data.palette.palette->colorCount, GL_RGBA,
|
||||||
|
GL_UNSIGNED_BYTE, (const void*)data.palette.palette->colors
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assertUnreachable("Unknown texture format");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t textureBindGL(texturegl_t *texture) {
|
||||||
|
if(texture == NULL) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(texture->id != 0, "Texture ID must be valid");
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture->id);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t textureDisposeGL(texturegl_t *texture) {
|
||||||
|
assertNotNull(texture, "Texture cannot be NULL");
|
||||||
|
assertTrue(texture->id != 0, "Texture ID must be valid");
|
||||||
|
|
||||||
|
glDeleteTextures(1, &texture->id);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
57
src/duskgl/display/texture/texturegl.h
Normal file
57
src/duskgl/display/texture/texturegl.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
|
||||||
|
typedef union texturedata_u texturedata_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TEXTURE_FORMAT_RGBA = GL_RGBA,
|
||||||
|
TEXTURE_FORMAT_PALETTE = GL_COLOR_INDEX8_EXT,
|
||||||
|
} textureformatgl_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GLuint id;
|
||||||
|
textureformatgl_t format;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
} texturegl_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a texture.
|
||||||
|
*
|
||||||
|
* @param texture The texture to initialize.
|
||||||
|
* @param width The width of the texture.
|
||||||
|
* @param height The height of the texture.
|
||||||
|
* @param format The format of the texture (e.g., GL_RGBA, GL_ALPHA).
|
||||||
|
* @param data The data for the texture, the format changes per format.
|
||||||
|
* @return An error if the texture failed to initialize, otherwise success.
|
||||||
|
*/
|
||||||
|
errorret_t textureInitGL(
|
||||||
|
texturegl_t *texture,
|
||||||
|
const int32_t width,
|
||||||
|
const int32_t height,
|
||||||
|
const textureformatgl_t format,
|
||||||
|
const texturedata_t data
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds a texture for rendering. Providing NULL will unbind any texture.
|
||||||
|
*
|
||||||
|
* @param texture The texture to bind.
|
||||||
|
* @return An error if the texture failed to bind, otherwise success.
|
||||||
|
*/
|
||||||
|
errorret_t textureBindGL(texturegl_t *texture);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes a texture.
|
||||||
|
*
|
||||||
|
* @param texture The texture to dispose.
|
||||||
|
* @return An error if the texture failed to dispose, otherwise success.
|
||||||
|
*/
|
||||||
|
errorret_t textureDisposeGL(texturegl_t *texture);
|
||||||
16
src/duskgl/display/texture/textureplatform.h
Normal file
16
src/duskgl/display/texture/textureplatform.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "display/texture/texturegl.h"
|
||||||
|
|
||||||
|
typedef textureformatgl_t textureformatplatform_t;
|
||||||
|
typedef texturegl_t textureplatform_t;
|
||||||
|
|
||||||
|
#define textureInitPlatform textureInitGL
|
||||||
|
#define textureBindPlatform textureBindGL
|
||||||
|
#define textureDisposePlatform textureDisposeGL
|
||||||
@@ -6,4 +6,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "display/displaysdl2.h"
|
#define GL_GLEXT_PROTOTYPES
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glext.h>
|
||||||
10
src/duskgl/error/CMakeLists.txt
Normal file
10
src/duskgl/error/CMakeLists.txt
Normal file
@@ -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
|
||||||
|
errorgl.c
|
||||||
|
)
|
||||||
17
src/duskgl/error/errorgl.c
Normal file
17
src/duskgl/error/errorgl.c
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "errorgl.h"
|
||||||
|
|
||||||
|
errorret_t errorGLCheck(void) {
|
||||||
|
GLenum err = glGetError();
|
||||||
|
if(err != GL_NO_ERROR) {
|
||||||
|
errorThrow("GL Error: %d", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
16
src/duskgl/error/errorgl.h
Normal file
16
src/duskgl/error/errorgl.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "error/error.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the GL error (if any) and throws it as a dusk style error.
|
||||||
|
*
|
||||||
|
* @return Error code, if GL error present.
|
||||||
|
*/
|
||||||
|
errorret_t errorGLCheck(void);
|
||||||
16
src/dusklinux/display/displayplatform.h
Normal file
16
src/dusklinux/display/displayplatform.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "display/displaysdl2.h"
|
||||||
|
|
||||||
|
typedef displaysdl2_t displayplatform_t;
|
||||||
|
|
||||||
|
#define displayPlatformInit displaySDL2Init
|
||||||
|
#define displayPlatformUpdate displaySDL2Update
|
||||||
|
#define displayPlatformSwap displaySDL2Swap
|
||||||
|
#define displayPlatformDispose displaySDL2Dispose
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2026 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
@@ -10,3 +10,4 @@ target_include_directories(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
||||||
|
add_subdirectory(display)
|
||||||
12
src/dusksdl2/display/CMakeLists.txt
Normal file
12
src/dusksdl2/display/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# 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
|
||||||
|
displaysdl2.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# Subdirs
|
||||||
111
src/dusksdl2/display/displaysdl2.c
Normal file
111
src/dusksdl2/display/displaysdl2.c
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "display/display.h"
|
||||||
|
#include "engine/engine.h"
|
||||||
|
#include "display/displaygl.h"
|
||||||
|
|
||||||
|
erroret_t displaySDL2Init(void) {
|
||||||
|
uint32_t flags = SDL_INIT_VIDEO;
|
||||||
|
#if INPUT_GAMEPAD == 1
|
||||||
|
flags |= SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK;
|
||||||
|
#endif
|
||||||
|
if(SDL_Init(flags) != 0) {
|
||||||
|
errorThrow("SDL Failed to Initialize: %s", SDL_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set OpenGL attributes (Needs to be done now or later?)
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
|
|
||||||
|
// Create window with OpenGL flag.
|
||||||
|
DISPLAY.window = SDL_CreateWindow(
|
||||||
|
"Dusk",
|
||||||
|
SDL_WINDOWPOS_UNDEFINED,
|
||||||
|
SDL_WINDOWPOS_UNDEFINED,
|
||||||
|
DUSK_WINDOW_WIDTH_DEFAULT,
|
||||||
|
DUSK_WINDOW_HEIGHT_DEFAULT,
|
||||||
|
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI |
|
||||||
|
SDL_WINDOW_OPENGL
|
||||||
|
);
|
||||||
|
if(!DISPLAY.window) {
|
||||||
|
errorThrow("SDL_CreateWindow failed: %s", SDL_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create OpenGL context
|
||||||
|
DISPLAY.glContext = SDL_GL_CreateContext(DISPLAY.window);
|
||||||
|
if(!DISPLAY.glContext) {
|
||||||
|
errorThrow("SDL_GL_CreateContext failed: %s", SDL_GetError());
|
||||||
|
}
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
SDL_GL_SetSwapInterval(1);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
errorChain(displayOpenGLInit());
|
||||||
|
|
||||||
|
|
||||||
|
// #if DUSK_PSP
|
||||||
|
// errorChain(displayPSPInit());
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t displaySDL2Update(void) {
|
||||||
|
SDL_Event event;
|
||||||
|
while(SDL_PollEvent(&event)) {
|
||||||
|
switch(event.type) {
|
||||||
|
case SDL_QUIT: {
|
||||||
|
ENGINE.running = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDL_WINDOWEVENT: {
|
||||||
|
switch(event.window.event) {
|
||||||
|
case SDL_WINDOWEVENT_CLOSE: {
|
||||||
|
ENGINE.running = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GL_MakeCurrent(DISPLAY.window, DISPLAY.glContext);
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t displaySDL2Swap(void) {
|
||||||
|
SDL_GL_SwapWindow(DISPLAY.window);
|
||||||
|
|
||||||
|
GLenum err;
|
||||||
|
while((err = glGetError()) != GL_NO_ERROR) {
|
||||||
|
debugPrint("GL Error: %d\n", err);
|
||||||
|
}
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void displaySDL2Dispose(void) {
|
||||||
|
if(DISPLAY.glContext) {
|
||||||
|
SDL_GL_DeleteContext(DISPLAY.glContext);
|
||||||
|
DISPLAY.glContext = NULL;
|
||||||
|
}
|
||||||
|
if(DISPLAY.window) {
|
||||||
|
SDL_DestroyWindow(DISPLAY.window);
|
||||||
|
DISPLAY.window = NULL;
|
||||||
|
}
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
@@ -6,10 +6,30 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "dusk.h"
|
#include "error/error.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SDL_Window *window;
|
SDL_Window *window;
|
||||||
SDL_GLContext glContext;
|
SDL_GLContext glContext;
|
||||||
bool_t usingShaderedPalettes;
|
bool_t usingShaderedPalettes;
|
||||||
} displayplatform_t;
|
} displaysdl2_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the SDL2 display system.
|
||||||
|
*/
|
||||||
|
errorret_t displaySDL2Init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles SDL2 Updating (pre-render context initialization)
|
||||||
|
*/
|
||||||
|
errorret_t displaySDL2Update(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles SDL2 Display Swapping (to switch from frontbuffer to backbuffer).
|
||||||
|
*/
|
||||||
|
errorret_t displaySDL2Swap(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes/Cleans up the SDL2 Render system.
|
||||||
|
*/
|
||||||
|
void displaySDL2Dispose(void);
|
||||||
@@ -6,4 +6,5 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "duskopengl.h"
|
#include <SDL2/SDL.h>
|
||||||
|
#include "duskgl.h"
|
||||||
Reference in New Issue
Block a user