Basic window.
This commit is contained in:
29
src/duskgl/CMakeLists.txt
Normal file
29
src/duskgl/CMakeLists.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Libs
|
||||
target_link_libraries(${DUSK_TARGET_NAME}
|
||||
PUBLIC
|
||||
cglm
|
||||
archive_static
|
||||
m
|
||||
spng_static
|
||||
)
|
||||
|
||||
# Includes
|
||||
target_include_directories(${DUSK_TARGET_NAME}
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
asset.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(assert)
|
||||
add_subdirectory(display)
|
10
src/duskgl/assert/CMakeLists.txt
Normal file
10
src/duskgl/assert/CMakeLists.txt
Normal 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
|
||||
assertgl.c
|
||||
)
|
68
src/duskgl/assert/assertgl.c
Normal file
68
src/duskgl/assert/assertgl.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assert/assertgl.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
void assertNotGLErrorCheck(const char_t *file, const int32_t line) {
|
||||
assertNotNull(file, "File is an invlaid string");
|
||||
assertTrue(line > 0, "assertNotGLErrorCheck: line is invalid");
|
||||
|
||||
char_t *buffer;
|
||||
GLenum errorCode;
|
||||
int32_t errorCount = 0;
|
||||
|
||||
while((errorCode = glGetError()) != GL_NO_ERROR) {
|
||||
if(errorCount == 0) {
|
||||
buffer = malloc(sizeof(char_t) * 4096);
|
||||
sprintf(buffer, "assertNotGLErrorCheck: %s:%d\n", file, line);
|
||||
}
|
||||
|
||||
errorCount++;
|
||||
|
||||
switch (errorCode) {
|
||||
case GL_INVALID_ENUM:
|
||||
sprintf(buffer, "%s\nINVALID_ENUM", buffer);
|
||||
break;
|
||||
|
||||
case GL_INVALID_VALUE:
|
||||
sprintf(buffer, "%s\nINVALID_ENUM", buffer);
|
||||
break;
|
||||
|
||||
case GL_INVALID_OPERATION:
|
||||
sprintf(buffer, "%s\nINVALID_OPERATION", buffer);
|
||||
break;
|
||||
|
||||
// case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||
// sprintf(buffer, "%s\nINVALID_FRAMEBUFFER_OPERATION", buffer);
|
||||
// break;
|
||||
|
||||
case GL_OUT_OF_MEMORY:
|
||||
sprintf(buffer, "%s\nOUT_OF_MEMORY", buffer);
|
||||
break;
|
||||
|
||||
case GL_STACK_UNDERFLOW:
|
||||
sprintf(buffer, "%s\nSTACK_UNDERFLOW", buffer);
|
||||
break;
|
||||
|
||||
case GL_STACK_OVERFLOW:
|
||||
sprintf(buffer, "%s\nSTACK_OVERFLOW", buffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf(buffer, "%s\nUNKNOWN_ERROR", buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(buffer, "%s (%i)\n", buffer, errorCode);
|
||||
}
|
||||
|
||||
if(errorCount > 0) {
|
||||
assertUnreachable(buffer);
|
||||
free(buffer);
|
||||
}
|
||||
}
|
22
src/duskgl/assert/assertgl.h
Normal file
22
src/duskgl/assert/assertgl.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "duskgl.h"
|
||||
|
||||
/**
|
||||
* Asserts that there are no OpenGL errors.
|
||||
*
|
||||
* @param file The file the assertion is being made in.
|
||||
* @param line The line the assertion is being made in.
|
||||
*/
|
||||
void assertNotGLErrorCheck(const char_t *file, const int32_t line);
|
||||
|
||||
/**
|
||||
* Asserts that there are no OpenGL errors.
|
||||
*/
|
||||
#define assertNoGLError() assertNotGLErrorCheck(__FILE__, __LINE__)
|
222
src/duskgl/asset.c
Normal file
222
src/duskgl/asset.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "asset.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/math.h"
|
||||
|
||||
asset_t ASSET;
|
||||
|
||||
void assetInit() {
|
||||
const char_t *assetFilename = "dusk.tar";
|
||||
char_t assetPath[FILENAME_MAX];
|
||||
const char_t* scanLocations[] = {
|
||||
EXECUTABLE_DIRECTORY
|
||||
};
|
||||
|
||||
memset(&ASSET, 0, sizeof(asset_t));
|
||||
|
||||
// Try and find the asset file.
|
||||
for(int32_t i = 0; i < sizeof(scanLocations) / sizeof(char_t*); i++) {
|
||||
sprintf(assetPath, "%s/%s", scanLocations[i], assetFilename);
|
||||
|
||||
FILE *file = fopen(assetPath, "rb");
|
||||
if(file == NULL) continue;
|
||||
|
||||
// File found.
|
||||
ASSET.file = file;
|
||||
}
|
||||
|
||||
// Ensure we found it.
|
||||
assertNotNull(ASSET.file, "Failed to find asset file!");
|
||||
}
|
||||
|
||||
void assetOpen(const char_t *path) {
|
||||
assertNotNull(path, "Path is not valid!");
|
||||
assertStrLen(path, FILENAME_MAX, "Path is too long!");
|
||||
assertStrLenMin(path, 1, "Path is empty!");
|
||||
|
||||
// Make sure things are clean
|
||||
assertNull(ASSET.archive, "Archive is not NULL!");
|
||||
assertNull(ASSET.entry, "Entry is not NULL!");
|
||||
assertNotNull(ASSET.file, "File is NULL!");
|
||||
|
||||
// Store path
|
||||
strcpy(ASSET.path, path);
|
||||
|
||||
// Prepare data
|
||||
ASSET.archive = archive_read_new();
|
||||
assertNotNull(ASSET.archive, "Failed to init archive reader");
|
||||
|
||||
// Set up the reader
|
||||
// archive_read_support_filter_bzip2(ASSET_ARCHIVE);
|
||||
archive_read_support_format_tar(ASSET.archive);
|
||||
|
||||
// Set the archive reader callbacks
|
||||
archive_read_set_open_callback(ASSET.archive, &assetArchiveOpen);
|
||||
archive_read_set_read_callback(ASSET.archive, &assetArchiveRead);
|
||||
archive_read_set_seek_callback(ASSET.archive, &assetArchiveSeek);
|
||||
archive_read_set_close_callback(ASSET.archive, &assetArchiveClose);
|
||||
archive_read_set_callback_data(ASSET.archive, ASSET.buffer);// TODO: Not needed?
|
||||
|
||||
// Open the archive
|
||||
int32_t ret = archive_read_open1(ASSET.archive);
|
||||
assertTrue(ret == ARCHIVE_OK, "Failed to open archive!");
|
||||
|
||||
// Iterate over each file.
|
||||
while(archive_read_next_header(ASSET.archive, &ASSET.entry) == ARCHIVE_OK) {
|
||||
// What file is at this position?
|
||||
const char_t *headerFile = (char_t*)archive_entry_pathname(ASSET.entry);
|
||||
|
||||
// Compare if this is the file we are looking for, if it is just exit the
|
||||
// function
|
||||
if(strcmp(headerFile, ASSET.path) == 0) return;
|
||||
|
||||
// It is not, skip it.
|
||||
int32_t ret = archive_read_data_skip(ASSET.archive);
|
||||
assertTrue(ret == ARCHIVE_OK, "Failed to skip data!");
|
||||
}
|
||||
|
||||
// If we get here we did not find the find in the archive.
|
||||
assertUnreachable("Failed to find file!");
|
||||
}
|
||||
|
||||
size_t assetGetSize() {
|
||||
assertNotNull(ASSET.archive, "Archive is NULL!");
|
||||
assertNotNull(ASSET.entry, "Entry is NULL!");
|
||||
assertTrue(archive_entry_size_is_set(ASSET.entry), "Entry size is not set!");
|
||||
return archive_entry_size(ASSET.entry);
|
||||
}
|
||||
|
||||
size_t assetRead(
|
||||
uint8_t *buffer,
|
||||
const size_t bufferSize
|
||||
) {
|
||||
assertNotNull(ASSET.archive, "Archive is NULL!");
|
||||
assertNotNull(ASSET.entry, "Entry is NULL!");
|
||||
assertNotNull(buffer, "Buffer is NULL!");
|
||||
assertTrue(bufferSize > 0, "Buffer size must be greater than 0!");
|
||||
|
||||
ssize_t read = archive_read_data(ASSET.archive, buffer, bufferSize);
|
||||
if(read == ARCHIVE_FATAL) {
|
||||
assertUnreachable(archive_error_string(ASSET.archive));
|
||||
return -1;
|
||||
}
|
||||
|
||||
assertTrue(read != ARCHIVE_RETRY, "Failed to read data (RETRY)!");
|
||||
assertTrue(read != ARCHIVE_WARN, "Failed to read data (WARN)!");
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
size_t assetReadUntil(
|
||||
uint8_t *buffer,
|
||||
const char_t c,
|
||||
const size_t maxLength
|
||||
) {
|
||||
if(buffer == NULL) {
|
||||
assertTrue(
|
||||
maxLength == -1, "If no buffer is provided, maxLength must be -1."
|
||||
);
|
||||
uint8_t tBuffer[1];
|
||||
size_t read = 0;
|
||||
while(assetRead(tBuffer, 1) == 1 && (char_t)tBuffer[0] != c) read++;
|
||||
return read;
|
||||
}
|
||||
|
||||
size_t read = 0;
|
||||
while(read < maxLength) {
|
||||
// TODO: Read more than 1 char at a time.
|
||||
read += assetRead(buffer + read, 1);
|
||||
if((char_t)buffer[read-1] == c) return read - 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void assetSkip(const size_t length) {
|
||||
assertNotNull(ASSET.archive, "Archive is NULL!");
|
||||
assertNotNull(ASSET.entry, "Entry is NULL!");
|
||||
|
||||
// Asset archive does not support skipping, so we have to read and discard.
|
||||
uint8_t buffer[ASSET_BUFFER_SIZE];
|
||||
size_t remaining = length;
|
||||
do {
|
||||
size_t toRead = mathMin(remaining, ASSET_BUFFER_SIZE);
|
||||
size_t read = assetRead(buffer, toRead);
|
||||
assertTrue(read == toRead, "Failed to skip data! (overskip?)");
|
||||
remaining -= read;
|
||||
} while(remaining > 0);
|
||||
}
|
||||
|
||||
void assetClose() {
|
||||
if(ASSET.archive == NULL) return;
|
||||
|
||||
assertNotNull(ASSET.archive, "Archive is NULL!");
|
||||
assertNotNull(ASSET.entry, "Entry is NULL!");
|
||||
|
||||
int32_t ret = archive_read_free(ASSET.archive);
|
||||
assertTrue(ret == ARCHIVE_OK, "Failed to close archive!");
|
||||
|
||||
assertNull(ASSET.archive, "Archive is not NULL? Cleanup incorrect.");
|
||||
}
|
||||
|
||||
void assetDispose() {
|
||||
assertNull(ASSET.archive, "Asset disposing but asset is currently open?");
|
||||
assertNull(ASSET.entry, "Asset disposing but entry is currently open?");
|
||||
assertNotNull(ASSET.file, "Asset disposing but file is NULL?");
|
||||
|
||||
fclose(ASSET.file);
|
||||
memset(&ASSET, 0, sizeof(asset_t));
|
||||
}
|
||||
|
||||
// Libarchive callbacks
|
||||
|
||||
ssize_t assetArchiveRead(
|
||||
struct archive *archive,
|
||||
void *data,
|
||||
const void **buffer
|
||||
) {
|
||||
assertNotNull(archive, "Archive is NULL!");
|
||||
assertNotNull(data, "Data is NULL!");
|
||||
assertNotNull(buffer, "Buffer is NULL!");
|
||||
|
||||
*buffer = data;
|
||||
size_t read = fread(data, 1, ASSET_BUFFER_SIZE, ASSET.file);
|
||||
if(ferror(ASSET.file)) return ARCHIVE_FATAL;
|
||||
return read;
|
||||
}
|
||||
|
||||
int64_t assetArchiveSeek(
|
||||
struct archive *archive,
|
||||
void *data,
|
||||
int64_t offset,
|
||||
int32_t whence
|
||||
) {
|
||||
assertNotNull(archive, "Archive is NULL!");
|
||||
assertNotNull(data, "Data is NULL!");
|
||||
assertTrue(offset > 0, "Offset must be greater than 0!");
|
||||
assertNotNull(ASSET.file, "File is NULL!");
|
||||
int32_t ret = fseek(ASSET.file, offset, whence);
|
||||
assertTrue(ret == 0, "Failed to seek!");
|
||||
return ftell(ASSET.file);
|
||||
}
|
||||
|
||||
int32_t assetArchiveOpen(struct archive *a, void *data) {
|
||||
int32_t ret = fseek(ASSET.file, 0, SEEK_SET);
|
||||
assertTrue(ret == 0, "Failed to seek to start of file!");
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
int32_t assetArchiveClose(struct archive *a, void *data) {
|
||||
assertNotNull(ASSET.file, "File is NULL!");
|
||||
|
||||
ASSET.archive = NULL;
|
||||
ASSET.entry = NULL;
|
||||
|
||||
return ARCHIVE_OK;
|
||||
}
|
137
src/duskgl/asset.h
Normal file
137
src/duskgl/asset.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "duskgl.h"
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
#define ASSET_BUFFER_SIZE 32768
|
||||
|
||||
typedef struct {
|
||||
FILE *file;
|
||||
struct archive *archive;
|
||||
struct archive_entry *entry;
|
||||
uint8_t buffer[ASSET_BUFFER_SIZE];
|
||||
|
||||
// ?
|
||||
char_t path[FILENAME_MAX];
|
||||
} asset_t;
|
||||
|
||||
extern asset_t ASSET;
|
||||
|
||||
/**
|
||||
* Initializes the asset manager.
|
||||
*/
|
||||
void assetInit();
|
||||
|
||||
/**
|
||||
* Opens an asset by its filename (within the asset archive). Asset paths should
|
||||
* always use the unix forward slash '/' as a path separator.
|
||||
*
|
||||
* @param path The path to the asset within the archive.
|
||||
*/
|
||||
void assetOpen(const char *path);
|
||||
|
||||
/**
|
||||
* Returns the size of the asset.
|
||||
*
|
||||
* @return The size of the asset.
|
||||
*/
|
||||
size_t assetGetSize();
|
||||
|
||||
/**
|
||||
* Reads the asset into the buffer.
|
||||
*
|
||||
* @param buffer The buffer to read the asset into.
|
||||
* @param bufferSize The size of the buffer.
|
||||
* @return The amount of data read.
|
||||
*/
|
||||
size_t assetRead(uint8_t *buffer, const size_t bufferSize);
|
||||
|
||||
/**
|
||||
* Reads ahead in the buffer until either the end of the buffer, or the
|
||||
* specified character is found. Return value will be -1 if the character was
|
||||
* not found.
|
||||
*
|
||||
* Buffer can be NULL if you just want to skip ahead.
|
||||
*
|
||||
* Returned value will be either the amount of data read into the buffer, which
|
||||
* excludes the extra 1 character that was read from the asset. If the character
|
||||
* was not found, -1 will be returned.
|
||||
*
|
||||
* @param buffer Buffer to read into.
|
||||
* @param c Character to read until.
|
||||
* @param maxLength Maximum length to read.
|
||||
* @return -1 if the character was not found, otherwise the amount of data read.
|
||||
*/
|
||||
size_t assetReadUntil(uint8_t *buffer, const char c, const size_t maxLength);
|
||||
|
||||
/**
|
||||
* Skips ahead in the buffer by the specified length.
|
||||
*
|
||||
* @param length The length to skip ahead by.
|
||||
*/
|
||||
void assetSkip(const size_t length);
|
||||
|
||||
/**
|
||||
* Closes the asset.
|
||||
*/
|
||||
void assetClose();
|
||||
|
||||
/**
|
||||
* Destroys and cleans up the asset manager.
|
||||
*/
|
||||
void assetDispose();
|
||||
|
||||
/**
|
||||
* Internal read method provided to libarchive api.
|
||||
*
|
||||
* @param archive The archive to read from.
|
||||
* @param data The data to read into.
|
||||
* @param buffer The buffer to read from.
|
||||
* @return The amount of data read.
|
||||
*/
|
||||
ssize_t assetArchiveRead(
|
||||
struct archive *archive,
|
||||
void *data,
|
||||
const void **buffer
|
||||
);
|
||||
|
||||
/**
|
||||
* Internal seek method provided to libarchive api.
|
||||
*
|
||||
* @param archive The archive to seek in.
|
||||
* @param data The data to seek in.
|
||||
* @param offset Offset bytes to seek.
|
||||
* @param whence Relative to whence to seek.
|
||||
* @return The new position.
|
||||
*/
|
||||
int64_t assetArchiveSeek(
|
||||
struct archive *archive,
|
||||
void *data,
|
||||
int64_t offset,
|
||||
int32_t whence
|
||||
);
|
||||
|
||||
/**
|
||||
* Internal open method provided to libarchive api.
|
||||
*
|
||||
* @param archive The archive to open.
|
||||
* @param data The data to open.
|
||||
* @return The result of the open.
|
||||
*/
|
||||
int32_t assetArchiveOpen(struct archive *a, void *data);
|
||||
|
||||
/**
|
||||
* Internal close method provided to libarchive api.
|
||||
*
|
||||
* @param archive The archive to close.
|
||||
* @param data The data to close.
|
||||
* @return The result of the close.
|
||||
*/
|
||||
int32_t assetArchiveClose(struct archive *a, void *data);
|
12
src/duskgl/display/CMakeLists.txt
Normal file
12
src/duskgl/display/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
# 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
|
||||
render.c
|
||||
)
|
||||
|
||||
# Subdirs
|
24
src/duskgl/display/render.c
Normal file
24
src/duskgl/display/render.c
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assert/assertgl.h"
|
||||
#include "render.h"
|
||||
|
||||
render_t RENDER;
|
||||
|
||||
void renderInit() {
|
||||
memset(&RENDER, 0, sizeof(render_t));
|
||||
}
|
||||
|
||||
void renderUpdate() {
|
||||
}
|
||||
|
||||
void renderOverworld() {
|
||||
}
|
||||
|
||||
void renderDispose() {
|
||||
}
|
35
src/duskgl/display/render.h
Normal file
35
src/duskgl/display/render.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "duskgl.h"
|
||||
|
||||
typedef struct {
|
||||
int32_t nothing;
|
||||
} render_t;
|
||||
|
||||
extern render_t RENDER;
|
||||
|
||||
/**
|
||||
* Initializes the render system.
|
||||
*/
|
||||
void renderInit();
|
||||
|
||||
/**
|
||||
* Updates the render system.
|
||||
*/
|
||||
void renderUpdate();
|
||||
|
||||
/**
|
||||
* Renders the overworld scene.
|
||||
*/
|
||||
void renderOverworld();
|
||||
|
||||
/**
|
||||
* Disposes of the render system.
|
||||
*/
|
||||
void renderDispose();
|
20
src/duskgl/duskgl.h
Normal file
20
src/duskgl/duskgl.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "duskglimpl.h"
|
||||
|
||||
#include <cglm/cglm.h>
|
||||
#include <libgen.h>
|
||||
#include <float.h>
|
||||
|
||||
typedef float float_t;
|
||||
typedef double double_t;
|
||||
|
||||
extern char_t EXECUTABLE_PATH[];
|
||||
extern char_t EXECUTABLE_DIRECTORY[];
|
Reference in New Issue
Block a user