Builds on PSP again.

This commit is contained in:
2025-08-15 21:37:44 -05:00
parent d1ab8b0cc8
commit 81ed15b171
15 changed files with 166 additions and 111 deletions

View File

@@ -10,8 +10,8 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
if(NOT DEFINED DUSK_TARGET_SYSTEM)
set(DUSK_TARGET_SYSTEM "linux")
# set(DUSK_TARGET_SYSTEM "psp")
# set(DUSK_TARGET_SYSTEM "linux")
set(DUSK_TARGET_SYSTEM "psp")
endif()
# Prep cache

View File

@@ -8,4 +8,5 @@ target_sources(${DUSK_TARGET_NAME}
PRIVATE
memory.c
string.c
math.c
)

19
src/dusk/util/math.c Normal file
View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "math.h"
uint32_t mathNextPowTwo(uint32_t value) {
if (value == 0) return 1; // Handle zero case
value--;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
return value + 1;
}

17
src/dusk/util/math.h Normal file
View File

@@ -0,0 +1,17 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
/**
* Finds the next power of two greater than or equal to the given value.
*
* @param value The value to find the next power of two for.
* @return The next power of two greater than or equal to the value.
*/
uint32_t mathNextPowTwo(uint32_t value);

View File

@@ -17,6 +17,7 @@ target_link_libraries(${DUSK_TARGET_NAME}
PUBLIC
SDL2::SDL2
OpenGL::GL
GL
)

View File

@@ -9,49 +9,51 @@
#include "assert/assert.h"
#include "util/memory.h"
void frameBufferInit(
framebuffer_t *framebuffer,
const uint32_t width,
const uint32_t height
) {
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
assertTrue(width > 0 && height > 0, "Width & height must be greater than 0");
#if RENDER_USE_FRAMEBUFFER
void frameBufferInit(
framebuffer_t *framebuffer,
const uint32_t width,
const uint32_t height
) {
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
assertTrue(width > 0 && height > 0, "Width & height must be greater than 0");
memoryZero(framebuffer, sizeof(framebuffer_t));
textureInit(&framebuffer->texture, width, height, NULL);
memoryZero(framebuffer, sizeof(framebuffer_t));
textureInit(&framebuffer->texture, width, height, NULL);
// Generate the framebuffer object
glGenFramebuffers(1, &framebuffer->id);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id);
// Generate the framebuffer object using EXT
glGenFramebuffersEXT(1, &framebuffer->id);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
// Attach the texture to the framebuffer
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, framebuffer->texture.id, 0
);
// Attach the texture to the framebuffer
glFramebufferTexture2DEXT(
GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, framebuffer->texture.id, 0
);
// Check if the framebuffer is complete
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
assertUnreachable("Framebuffer is not complete");
// Check if the framebuffer is complete
if(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) {
assertUnreachable("Framebuffer is not complete");
}
// Unbind the framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
// Unbind the framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void frameBufferBind(const framebuffer_t *framebuffer) {
if(framebuffer == NULL) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
return;
}
void frameBufferBind(const framebuffer_t *framebuffer) {
if(framebuffer == NULL) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return;
// Bind the framebuffer for rendering
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
}
// Bind the framebuffer for rendering
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id);
}
void frameBufferDispose(framebuffer_t *framebuffer) {
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
void frameBufferDispose(framebuffer_t *framebuffer) {
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
glDeleteFramebuffers(1, &framebuffer->id);
textureDispose(&framebuffer->texture);
}
glDeleteFramebuffersEXT(1, &framebuffer->id);
textureDispose(&framebuffer->texture);
}
#endif

View File

@@ -8,35 +8,37 @@
#pragma once
#include "display/texture/texture.h"
typedef struct {
GLuint id;
texture_t texture;
} framebuffer_t;
#if RENDER_USE_FRAMEBUFFER
typedef struct {
GLuint id;
texture_t texture;
} framebuffer_t;
/**
* Initializes a framebuffer.
*
* @param framebuffer The framebuffer to initialize.
* @param width The width of the framebuffer.
* @param height The height of the framebuffer.
* @return An error code indicating success or failure.
*/
void frameBufferInit(
framebuffer_t *framebuffer,
const uint32_t width,
const uint32_t height
);
/**
* Initializes a framebuffer using EXT methods.
*
* @param framebuffer The framebuffer to initialize.
* @param width The width of the framebuffer.
* @param height The height of the framebuffer.
* @return An error code indicating success or failure.
*/
void frameBufferInit(
framebuffer_t *framebuffer,
const uint32_t width,
const uint32_t height
);
/**
* Binds the framebuffer for rendering.
*
* @param framebuffer The framebuffer to bind, or NULL to unbind.
*/
void frameBufferBind(const framebuffer_t *framebuffer);
/**
* Binds the framebuffer for rendering using EXT methods.
*
* @param framebuffer The framebuffer to bind, or NULL to unbind.
*/
void frameBufferBind(const framebuffer_t *framebuffer);
/**
* Disposes of the framebuffer.
*
* @param framebuffer The framebuffer to dispose of.
*/
void frameBufferDispose(framebuffer_t *framebuffer);
/**
* Disposes of the framebuffer using EXT methods.
*
* @param framebuffer The framebuffer to dispose of.
*/
void frameBufferDispose(framebuffer_t *framebuffer);
#endif

View File

@@ -26,8 +26,6 @@ void meshInit(
mesh->primitiveType = primitiveType;
mesh->vertexCount = vertexCount;
mesh->vertices = vertices;
consolePrint("Init mesh");
}
void meshDraw(
@@ -50,19 +48,19 @@ void meshDraw(
const GLsizei stride = sizeof(meshvertex_t);
glColorPointer(
4,
MESH_VERTEX_COLOR_SIZE,
GL_UNSIGNED_BYTE,
stride,
(const GLvoid*)&mesh->vertices[offset].color[0]
);
glTexCoordPointer(
2,
MESH_VERTEX_UV_SIZE,
GL_FLOAT,
stride,
(const GLvoid*)&mesh->vertices[offset].uv[0]
);
glVertexPointer(
3,
MESH_VERTEX_POS_SIZE,
GL_FLOAT,
stride,
(const GLvoid*)&mesh->vertices[offset].pos[0]

View File

@@ -6,10 +6,14 @@
#pragma once
#include "dusksdl2.h"
#define MESH_VERTEX_COLOR_SIZE 4
#define MESH_VERTEX_UV_SIZE 2
#define MESH_VERTEX_POS_SIZE 3
typedef struct {
GLubyte color[4];
GLfloat uv[2];
GLfloat pos[3];
GLubyte color[MESH_VERTEX_COLOR_SIZE];
GLfloat uv[MESH_VERTEX_UV_SIZE];
GLfloat pos[MESH_VERTEX_POS_SIZE];
} meshvertex_t;
typedef struct {

View File

@@ -14,8 +14,6 @@
#include "dusksdl2input.h"
#include "renderscene.h"
#include "display/spritebatch/spritebatch.h"
#include "display/texture/texture.h"
#include "display/mesh/mesh.h"
#include "display/camera/camera.h"
SDL_Window *RENDER_WINDOW;
@@ -62,11 +60,11 @@ errorret_t renderInit(void) {
SDL_GL_SetSwapInterval(1);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);// PSP defaults this on?
glShadeModel(GL_SMOOTH); // Fixes color on PSP?
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_LIGHTING);// PSP defaults this on?
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH); // Fixes color on PSP?
glEnableClientState(GL_COLOR_ARRAY);// To confirm: every frame on PSP?
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
@@ -75,7 +73,7 @@ errorret_t renderInit(void) {
renderTextInit();
renderBackBufferInit();
renderSceneInit();
RENDER_RUNNING = true;
errorOk();
}
@@ -93,7 +91,8 @@ errorret_t renderDraw(void) {
}
}
// Bind the backbuffer
// Reset the state
spriteBatchClear();
renderBackBufferBind();
// Draw everything
@@ -108,6 +107,7 @@ errorret_t renderDraw(void) {
// Finish rendering, now render back buffer.
renderBackBufferUnbind();
renderBackBufferDraw();
textureBind(NULL);
SDL_GL_SwapWindow(RENDER_WINDOW);
errorOk();

View File

@@ -9,6 +9,8 @@
#include "render.h"
#include "assert/assert.h"
#include "display/spritebatch/spritebatch.h"
#include "util/memory.h"
#include "util/math.h"
texture_t RENDER_TEXT_TEXTURE;
@@ -20,19 +22,19 @@ void renderTextInit(void) {
const int32_t inputFontWidth = cols * FONT_TILE_WIDTH;
const int32_t inputFontHeight = rows * FONT_TILE_HEIGHT;
// Round up to nearest multiple of 4
int32_t outputFontWidth = inputFontWidth;
if(outputFontWidth % 4 != 0) {
outputFontWidth += 4 - (outputFontWidth % 4);
}
// Round up to nearest multiple of 2
int32_t outputFontHeight = inputFontHeight;
if(outputFontHeight % 2 != 0) {
outputFontHeight += 2 - (outputFontHeight % 2);
}
uint8_t pixels[outputFontWidth * outputFontHeight * sizeof(uint8_t) * 4];
// Round up to nearest power of 2
#if PSP
outputFontWidth = mathNextPowTwo(inputFontWidth);
outputFontHeight = mathNextPowTwo(inputFontHeight);
#endif
uint8_t *pixels = (uint8_t *)memoryAllocate(
outputFontWidth * outputFontHeight *
4 * sizeof(uint8_t)
);
// Buffer the pixels.
for(int tileIndex = 0; tileIndex < FONT_TILE_COUNT; ++tileIndex) {
@@ -53,12 +55,8 @@ void renderTextInit(void) {
}
}
textureInit(
&RENDER_TEXT_TEXTURE,
outputFontWidth,
outputFontHeight,
pixels
);
textureInit(&RENDER_TEXT_TEXTURE, outputFontWidth, outputFontHeight, pixels);
memoryFree(pixels);
}
void renderTextDrawChar(

View File

@@ -8,6 +8,7 @@
#include "spritebatch.h"
#include "assert/assert.h"
#include "util/memory.h"
#include "console/console.h"
spritebatch_t SPRITEBATCH;
@@ -19,7 +20,7 @@ void spriteBatchInit() {
&SPRITEBATCH.mesh,
GL_TRIANGLES,
SPRITEBATCH_VERTEX_COUNT,
SPRITEBATCH.vertices
&SPRITEBATCH.vertices[0]
);
}
@@ -47,7 +48,6 @@ void spriteBatchPush(
SPRITEBATCH.currentTexture = texture;
}
// Get the vertex to buffer
quadBuffer(
&SPRITEBATCH.vertices[SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT],
minX, minY, maxX, maxY,
@@ -66,7 +66,7 @@ void spriteBatchClear() {
void spriteBatchFlush() {
if(SPRITEBATCH.spriteCount == 0) return;
textureBind(SPRITEBATCH.currentTexture);
meshDraw(&SPRITEBATCH.mesh, -1, SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT);
meshDraw(&SPRITEBATCH.mesh, 0, QUAD_VERTEX_COUNT * SPRITEBATCH.spriteCount);
spriteBatchClear();
}

View File

@@ -9,9 +9,10 @@
#include "display/mesh/quad.h"
#include "display/texture/texture.h"
#define SPRITEBATCH_SPRITES_MAX 512
#define SPRITEBATCH_SPRITES_MAX 1
#define SPRITEBATCH_VERTEX_COUNT (SPRITEBATCH_SPRITES_MAX * QUAD_VERTEX_COUNT)
typedef struct {
mesh_t mesh;
int32_t spriteCount;

View File

@@ -8,6 +8,7 @@
#include "texture.h"
#include "assert/assert.h"
#include "util/memory.h"
#include "util/math.h"
void textureInit(
texture_t *texture,
@@ -18,14 +19,14 @@ void textureInit(
assertNotNull(texture, "Texture cannot be NULL");
assertTrue(width > 0 && height > 0, "Width and height must be greater than 0");
#if PSP || 1
#if PSP
assertTrue(
width % 4 == 0,
"Width must be multiples of 4 for PSP"
width == mathNextPowTwo(width),
"Width must be powers of 2 for PSP"
);
assertTrue(
height % 2 == 0,
"Height must be multiples of 2 for PSP"
height == mathNextPowTwo(height),
"Height must be powers of 2 for PSP"
);
#endif
@@ -44,15 +45,27 @@ void textureInit(
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
}
void textureBind(const texture_t *texture) {
if(texture == NULL) {
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
// glBindTexture(GL_TEXTURE_2D, 0);
return;
}
assertTrue(
texture->id != 0,
"Texture ID must not be 0"
);
assertTrue(
texture->width > 0 && texture->height > 0,
"Texture width and height must be greater than 0"
);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture->id);
}

View File

@@ -11,5 +11,4 @@
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/glext.h>