This commit is contained in:
2025-08-15 15:56:30 -05:00
parent 217f00ff4c
commit 3c908dc1ed
15 changed files with 403 additions and 87 deletions

View File

@@ -14,5 +14,7 @@ target_sources(${DUSK_TARGET_NAME}
) )
# Subdirs # Subdirs
add_subdirectory(camera)
add_subdirectory(mesh) add_subdirectory(mesh)
add_subdirectory(texture) add_subdirectory(texture)
add_subdirectory(spritebatch)

View File

@@ -0,0 +1,10 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
camera.c
)

View File

@@ -0,0 +1,25 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "camera.h"
#include "display/render.h"
void cameraUIPush(void) {
// Push the UI camera matrix onto the stack.
glPushMatrix();
glLoadIdentity();
glOrtho(
0.0f, (float_t)RENDER_WIDTH,
(float_t)RENDER_HEIGHT, 0.0f,
-1.0f, 1.0f
);
}
void cameraUIPop(void) {
// Pop the UI camera matrix from the stack.
glPopMatrix();
}

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusksdl2.h"
/**
* Pushes the UI camera matrix onto the stack.
*/
void cameraUIPush(void);
/**
* Pops the UI camera matrix from the stack.
*/
void cameraUIPop(void);

View File

@@ -6,8 +6,6 @@
# Sources # Sources
target_sources(${DUSK_TARGET_NAME} target_sources(${DUSK_TARGET_NAME}
PRIVATE PRIVATE
mesh mesh.c
) quad.c
)
# Subdirs
# add_subdirectory(draw)

View File

@@ -18,6 +18,14 @@ typedef struct {
GLenum primitiveType; GLenum primitiveType;
} mesh_t; } mesh_t;
/**
* Initializes a mesh.
*
* @param mesh The mesh to initialize.
* @param primitiveType The OpenGL primitive type (e.g., GL_TRIANGLES).
* @param vertexCount The number of vertices in the mesh.
* @param vertices The vertex data for the mesh.
*/
void meshInit( void meshInit(
mesh_t *mesh, mesh_t *mesh,
const GLenum primitiveType, const GLenum primitiveType,
@@ -25,10 +33,22 @@ void meshInit(
const meshvertex_t *vertices const meshvertex_t *vertices
); );
/**
* Draws a mesh.
*
* @param mesh The mesh to draw.
* @param vertexOffset The offset in the vertex array to start drawing from.
* @param vertexCount The number of vertices to draw. If -1, draws all vertices.
*/
void meshDraw( void meshDraw(
const mesh_t *mesh, const mesh_t *mesh,
const int32_t vertexOffset, const int32_t vertexOffset,
const int32_t vertexCount const int32_t vertexCount
); );
/**
* Disposes a mesh.
*
* @param mesh The mesh to dispose.
*/
void meshDispose(mesh_t *mesh); void meshDispose(mesh_t *mesh);

View File

@@ -0,0 +1,61 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "quad.h"
#include "assert/assert.h"
void quadBuffer(
meshvertex_t *vertices,
const float_t minX,
const float_t minY,
const float_t maxX,
const float_t maxY,
const uint8_t r,
const uint8_t g,
const uint8_t b,
const uint8_t a,
const float_t u0,
const float_t v0,
const float_t u1,
const float_t v1
) {
assertNotNull(vertices, "Vertices cannot be NULL");
// First triangle
vertices[0] = (meshvertex_t) {
{ r, g, b, a }, // Color
{ u0, v0 }, // UV
{ minX, minY, 0.0f } // Position
};
vertices[1] = (meshvertex_t) {
{ r, g, b, a }, // Color
{ u1, v0 }, // UV
{ maxX, minY, 0.0f } // Position
};
vertices[2] = (meshvertex_t) {
{ r, g, b, a }, // Color
{ u1, v1 }, // UV
{ maxX, maxY, 0.0f } // Position
};
// Second triangle
vertices[3] = (meshvertex_t) {
{ r, g, b, a }, // Color
{ u0, v0 }, // UV
{ minX, minY, 0.0f } // Position
};
vertices[4] = (meshvertex_t) {
{ r, g, b, a }, // Color
{ u1, v1 }, // UV
{ maxX, maxY, 0.0f } // Position
};
vertices[5] = (meshvertex_t) {
{ r, g, b, a }, // Color
{ u0, v1 }, // UV
{ minX, maxY, 0.0f } // Position
};
}

View File

@@ -0,0 +1,44 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "mesh.h"
#define QUAD_VERTEX_COUNT 6
/**
* Buffers a quad into the provided vertex array.
*
* @param vertices The vertex array to buffer into.
* @param minX The minimum X coordinate of the quad.
* @param minY The minimum Y coordinate of the quad.
* @param maxX The maximum X coordinate of the quad.
* @param maxY The maximum Y coordinate of the quad.
* @param r The red color component (0-255).
* @param g The green color component (0-255).
* @param b The blue color component (0-255).
* @param a The alpha color component (0-255).
* @param u0 The U texture coordinate for the first vertex.
* @param v0 The V texture coordinate for the first vertex.
* @param u1 The U texture coordinate for the second vertex.
* @param v1 The V texture coordinate for the second vertex.
*/
void quadBuffer(
meshvertex_t *vertices,
const float_t minX,
const float_t minY,
const float_t maxX,
const float_t maxY,
const uint8_t r,
const uint8_t g,
const uint8_t b,
const uint8_t a,
const float_t u0,
const float_t v0,
const float_t u1,
const float_t v1
);

View File

@@ -13,36 +13,16 @@
#include "console/console.h" #include "console/console.h"
#include "dusksdl2input.h" #include "dusksdl2input.h"
#include "renderscene.h" #include "renderscene.h"
#include "display/spritebatch/spritebatch.h"
#include "display/texture/texture.h" #include "display/texture/texture.h"
#include "display/mesh/mesh.h" #include "display/mesh/mesh.h"
#include "display/camera/camera.h"
SDL_Window *RENDER_WINDOW; SDL_Window *RENDER_WINDOW;
SDL_Renderer *RENDER_RENDERER; SDL_Renderer *RENDER_RENDERER;
SDL_GLContext RENDER_GL_CONTEXT; SDL_GLContext RENDER_GL_CONTEXT;
bool_t RENDER_RUNNING; bool_t RENDER_RUNNING;
static mesh_t TRIANGLE_MESH;
// Interleaved in native order: COORD -> COLOR -> VERTEX
static const meshvertex_t tri[3] = {
// Color then coord then vertex test
{ { 0xFF, 0, 0, 0xFF }, { 0.0f, 0.0f }, { -0.6f, -0.4f, 0.0f } }, // Red
{ { 0, 0xFF, 0, 0xFF }, { 1.0f, 0.0f }, { 0.6f, -0.4f, 0.0f } }, // Green
{ { 0, 0, 0xFF, 0xFF }, { 1.0f, 1.0f }, { 0.0f, 0.6f, 0.0f } } // Blue
};
static const meshvertex_t quad[6] = {
// First triangle
{ { 0xFF, 0xFF, 0xFF, 0xFF }, { 0.0f, 0.0f }, { -1.0f, -1.0f, 0.0f } }, // Red
{ { 0xFF, 0xFF, 0xFF, 0xFF }, { 1.0f, 0.0f }, { 1.0f, -1.0f, 0.0f } }, // Green
{ { 0xFF, 0xFF, 0xFF, 0xFF }, { 1.0f, 1.0f }, { 1.0f, 1.0f, 0.0f } }, // Blue
// Second triangle
{ { 0xFF, 0xFF, 0xFF, 0xFF }, { 0.0f, 0.0f }, { -1.0f, -1.0f, 0.0f } }, // Red
{ { 0xFF, 0xFF, 0xFF, 0xFF }, { 1.0f, 1.0f }, { 1.0f, 1.0f, 0.0f } }, // Blue
{ { 0xFF, 0xFF, 0xFF, 0xFF }, { 0.0f, 1.0f }, { -1.0f, 1.0f, 0.0f } } // Green
};
errorret_t renderInit(void) { errorret_t renderInit(void) {
// Init SDL // Init SDL
uint32_t flags = SDL_INIT_VIDEO; uint32_t flags = SDL_INIT_VIDEO;
@@ -89,14 +69,18 @@ errorret_t renderInit(void) {
// Disable GL crap we don't need // Disable GL crap we don't need
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glDisable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_LIGHTING);// PSP defaults this on? glDisable(GL_LIGHTING);// PSP defaults this on?
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH); glShadeModel(GL_SMOOTH); // Fixes color on PSP?
meshInit(
&TRIANGLE_MESH, GL_TRIANGLES, sizeof(quad) / sizeof(meshvertex_t), quad
);
// To confirm: does this need to be done every frame?
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
spriteBatchInit();
// Create back buffer. // Create back buffer.
// renderBackBufferInit(); // renderBackBufferInit();
@@ -129,7 +113,6 @@ errorret_t renderDraw(void) {
// Draw everything // Draw everything
// renderSceneDraw(); // renderSceneDraw();
// renderConsoleDraw();
// Unbind the backbuffer // Unbind the backbuffer
// renderBackBufferUnbind(); // renderBackBufferUnbind();
@@ -138,23 +121,18 @@ errorret_t renderDraw(void) {
glClearColor(0.392f, 0.584f, 0.929f, 1.0f); glClearColor(0.392f, 0.584f, 0.929f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
textureBind(&RENDER_TEXT_TEXTURE); cameraUIPush();
renderConsoleDraw();
spriteBatchFlush();
cameraUIPop();
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
meshDraw(&TRIANGLE_MESH, -1, -1);
textureBind(NULL);
// Present the renderer (swap OpenGL buffers)
SDL_GL_SwapWindow(RENDER_WINDOW); SDL_GL_SwapWindow(RENDER_WINDOW);
errorOk(); errorOk();
} }
errorret_t renderDispose(void) { errorret_t renderDispose(void) {
meshDispose(&TRIANGLE_MESH); spriteBatchDispose();
// renderTextDispose(); // renderTextDispose();
// renderSceneDispose(); // renderSceneDispose();

View File

@@ -22,7 +22,10 @@ void renderConsoleDraw(void) {
i++; i++;
continue; continue;
} }
renderTextDraw(0, (CONSOLE_HISTORY_MAX - i - 1) * FONT_TILE_HEIGHT, line); renderTextDraw(
0, (CONSOLE_HISTORY_MAX - i - 1) * FONT_TILE_HEIGHT, line,
0xFF, 0xFF, 0xFF
);
i++; i++;
} while(i < CONSOLE_HISTORY_MAX); } while(i < CONSOLE_HISTORY_MAX);
} }

View File

@@ -8,9 +8,12 @@
#include "rendertext.h" #include "rendertext.h"
#include "render.h" #include "render.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "display/spritebatch/spritebatch.h"
texture_t RENDER_TEXT_TEXTURE; texture_t RENDER_TEXT_TEXTURE;
static mesh_t RENDER_TEXT_QUAD_MESH;
void renderTextInit(void) { void renderTextInit(void) {
const int32_t cols = FONT_COLUMN_COUNT; const int32_t cols = FONT_COLUMN_COUNT;
const int32_t rows = (FONT_TILE_COUNT + cols - 1) / cols; const int32_t rows = (FONT_TILE_COUNT + cols - 1) / cols;
@@ -45,7 +48,7 @@ void renderTextInit(void) {
pixels[pixelOffset + 0] = value ? 0xFF : 0x00; // Red channel pixels[pixelOffset + 0] = value ? 0xFF : 0x00; // Red channel
pixels[pixelOffset + 1] = value ? 0xFF : 0x00; // Green channel pixels[pixelOffset + 1] = value ? 0xFF : 0x00; // Green channel
pixels[pixelOffset + 2] = value ? 0xFF : 0x00; // Blue channel pixels[pixelOffset + 2] = value ? 0xFF : 0x00; // Blue channel
pixels[pixelOffset + 3] = 0xFF; // Alpha channel pixels[pixelOffset + 3] = value ? 0xFF : 0x00; // Alpha channel
} }
} }
} }
@@ -61,57 +64,59 @@ void renderTextInit(void) {
void renderTextDrawChar( void renderTextDrawChar(
const float_t x, const float_t x,
const float_t y, const float_t y,
const char_t c const char_t c,
const uint8_t r,
const uint8_t g,
const uint8_t b
) { ) {
// int32_t tileIndex = (int32_t)(c) - FONT_CHAR_START; int32_t tileIndex = (int32_t)(c) - FONT_CHAR_START;
assertTrue(
tileIndex >= 0 && tileIndex < FONT_TILE_COUNT,
"Character is out of bounds for font tiles"
);
// assertTrue( const float_t w = (float)RENDER_TEXT_TEXTURE.width;
// tileIndex >= 0 && tileIndex < FONT_TILE_COUNT, const float_t h = (float)RENDER_TEXT_TEXTURE.height;
// "Character is out of bounds for font tiles" const int32_t tileX = (tileIndex % FONT_COLUMN_COUNT);
// ); const int32_t tileY = (tileIndex / FONT_COLUMN_COUNT);
// assertNotNull(RENDER_TEXT_TEXTURE, "Texture cannot be NULL");
// const int32_t tileX = (tileIndex % FONT_COLUMN_COUNT) * FONT_TILE_WIDTH;
// const int32_t tileY = (tileIndex / FONT_COLUMN_COUNT) * FONT_TILE_HEIGHT;
// SDL_Rect srcRect = { spriteBatchPush(
// .x = tileX, &RENDER_TEXT_TEXTURE,
// .y = tileY, x, y,
// .w = FONT_TILE_WIDTH, x + FONT_TILE_WIDTH, y + FONT_TILE_HEIGHT,
// .h = FONT_TILE_HEIGHT r, g, b, 0xFF,
// }; (tileX * FONT_TILE_WIDTH) / w,
(tileY * FONT_TILE_HEIGHT) / h,
// SDL_Rect dstRect = { ((tileX + 1) * FONT_TILE_WIDTH) / w,
// .x = (int32_t)roundf(x), ((tileY + 1) * FONT_TILE_HEIGHT) / h
// .y = (int32_t)roundf(y), );
// .w = FONT_TILE_WIDTH,
// .h = FONT_TILE_HEIGHT
// };
// SDL_RenderCopy(RENDER_RENDERER, RENDER_TEXT_TEXTURE, &srcRect, &dstRect);
} }
void renderTextDraw( void renderTextDraw(
const float_t x, const float_t x,
const float_t y, const float_t y,
const char_t *text const char_t *text,
const uint8_t r,
const uint8_t g,
const uint8_t b
) { ) {
// assertNotNull(text, "Text cannot be NULL"); assertNotNull(text, "Text cannot be NULL");
// float_t posX = x; float_t posX = x;
// float_t posY = y; float_t posY = y;
// char_t c; char_t c;
// int32_t i = 0; int32_t i = 0;
// while((c = text[i++]) != '\0') { while((c = text[i++]) != '\0') {
// if(c == '\n') { if(c == '\n') {
// posX = x; posX = x;
// posY += FONT_TILE_HEIGHT; posY += FONT_TILE_HEIGHT;
// continue; continue;
// } }
// renderTextDrawChar(posX, posY, c); renderTextDrawChar(posX, posY, c, r, g, b);
// posX += FONT_TILE_WIDTH; posX += FONT_TILE_WIDTH;
// } }
} }
void renderTextDispose(void) { void renderTextDispose(void) {

View File

@@ -23,11 +23,17 @@ void renderTextInit(void);
* @param x The x-coordinate to draw the character at. * @param x The x-coordinate to draw the character at.
* @param y The y-coordinate to draw the character at. * @param y The y-coordinate to draw the character at.
* @param c The character to draw. * @param c The character to draw.
* @param r The red component of the color (0-255).
* @param g The green component of the color (0-255).
* @param b The blue component of the color (0-255).
*/ */
void renderTextDrawChar( void renderTextDrawChar(
const float_t x, const float_t x,
const float_t y, const float_t y,
const char_t c const char_t c,
const uint8_t r,
const uint8_t g,
const uint8_t b
); );
/** /**
@@ -36,11 +42,17 @@ void renderTextDrawChar(
* @param x The x-coordinate to draw the text at. * @param x The x-coordinate to draw the text at.
* @param y The y-coordinate to draw the text at. * @param y The y-coordinate to draw the text at.
* @param text The null-terminated string of text to draw. * @param text The null-terminated string of text to draw.
* @param r The red component of the color (0-255).
* @param g The green component of the color (0-255).
* @param b The blue component of the color (0-255).
*/ */
void renderTextDraw( void renderTextDraw(
const float_t x, const float_t x,
const float_t y, const float_t y,
const char_t *text const char_t *text,
const uint8_t r,
const uint8_t g,
const uint8_t b
); );
/** /**

View File

@@ -0,0 +1,13 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
spritebatch.c
)
# Subdirs
# add_subdirectory(draw)

View File

@@ -0,0 +1,75 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "spritebatch.h"
#include "assert/assert.h"
#include "util/memory.h"
spritebatch_t SPRITEBATCH;
void spriteBatchInit() {
SPRITEBATCH.spriteCount = 0;
SPRITEBATCH.currentTexture = NULL;
meshInit(
&SPRITEBATCH.mesh,
GL_TRIANGLES,
SPRITEBATCH_VERTEX_COUNT,
SPRITEBATCH.vertices
);
}
void spriteBatchPush(
texture_t *texture,
const float_t minX,
const float_t minY,
const float_t maxX,
const float_t maxY,
const uint8_t r,
const uint8_t g,
const uint8_t b,
const uint8_t a,
const float_t u0,
const float_t v0,
const float_t u1,
const float_t v1
) {
// Need to flush?
if(
SPRITEBATCH.currentTexture != texture ||
SPRITEBATCH.spriteCount >= SPRITEBATCH_SPRITES_MAX
) {
spriteBatchFlush();
SPRITEBATCH.currentTexture = texture;
}
// Get the vertex to buffer
quadBuffer(
&SPRITEBATCH.vertices[SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT],
minX, minY, maxX, maxY,
r, g, b, a,
u0, v0, u1, v1
);
SPRITEBATCH.spriteCount++;
}
void spriteBatchClear() {
SPRITEBATCH.spriteCount = 0;
SPRITEBATCH.currentTexture = NULL;
}
void spriteBatchFlush() {
if(SPRITEBATCH.spriteCount == 0) return;
textureBind(SPRITEBATCH.currentTexture);
meshDraw(&SPRITEBATCH.mesh, -1, SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT);
spriteBatchClear();
}
void spriteBatchDispose() {
meshDispose(&SPRITEBATCH.mesh);
}

View File

@@ -0,0 +1,51 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/mesh/quad.h"
#include "display/texture/texture.h"
#define SPRITEBATCH_SPRITES_MAX 512
#define SPRITEBATCH_VERTEX_COUNT (SPRITEBATCH_SPRITES_MAX * QUAD_VERTEX_COUNT)
typedef struct {
mesh_t mesh;
int32_t spriteCount;
texture_t *currentTexture;
meshvertex_t vertices[SPRITEBATCH_VERTEX_COUNT];
} spritebatch_t;
extern spritebatch_t SPRITEBATCH;
/**
* Initializes a sprite batch.
*
* @param spriteBatch The sprite batch to initialize.
*/
void spriteBatchInit();
void spriteBatchPush(
texture_t *texture,
const float_t minX,
const float_t minY,
const float_t maxX,
const float_t maxY,
const uint8_t r,
const uint8_t g,
const uint8_t b,
const uint8_t a,
const float_t u0,
const float_t v0,
const float_t u1,
const float_t v1
);
void spriteBatchClear();
void spriteBatchFlush();
void spriteBatchDispose();