Much much better

This commit is contained in:
2021-02-23 07:57:24 +11:00
parent adc7f5e208
commit 4f02128553
24 changed files with 371 additions and 360 deletions

View File

@ -0,0 +1,52 @@
/**
* Copyright (c) 2021 Dominic Msters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "render.h"
render_t * renderInit(char *name) {
// Initialize the renderer
render_t *render = malloc(sizeof(render_t));
if(!render) return NULL;
// render->width = WINDOW_WIDTH_DEFAULT;
// render->height = WINDOW_HEIGHT_DEFAULT;
//GLEnable Things
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
return render;
}
void renderFrame(render_t *render) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_TRIANGLES);
glColor3f(1, 0, 0);
glVertex3f(-1, -1, 0);
glColor3f(0, 1, 0);
glVertex3f(0, 1, 0);
glColor3f(0, 0, 1);
glVertex3f(1, -1, 0);
glEnd();
}
bool renderDispose(render_t *render) {
// Free up the renderer
free(render);
return true;
}
void renderSetResolution(render_t *render, uint32_t width, uint32_t height) {
render->width = width;
render->height = height;
glViewport(0, 0, width, height);
}

View File

@ -0,0 +1,57 @@
/**
* Copyright (c) 2021 Dominic Msters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <malloc.h>
#include <glad/glad.h>
#include <cglm/call.h>
/**
* Contains information about the current render state, can be used for querying
* how the renderer is currently set up.
*/
typedef struct {
/** Resolution (in pixels) */
int32_t width, height;
} render_t;
/**
* Initialize the renderer.
*
* @param name String of the windows' name.
* @return Rendering Context information.
*/
render_t * renderInit(char *name);
/**
* Render a single frame of the render loop. The renderer is not (currently)
* responsible for render looping.
*
* @param render The renderer to loop for.
*/
void renderFrame(render_t *render);
/**
* Cleanup a render context.
*
* @param render Renderer to cleanup.
* @return True or False if Successful/Not.
*/
bool renderDispose(render_t *render);
/**
* Set the internal display resolution.
*
* @param render Renderer to set resolution for.
* @param width Width (in pixels) of the viewport.
* @param height Height (in pixels) of the viewport.
*/
void renderSetResolution(render_t *render, uint32_t width, uint32_t height);

View File

@ -0,0 +1,95 @@
/**
* Copyright (c) 2021 Dominic Msters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "shader.h"
shader_t * shaderCompile(char *vertexShaderSource, char* fragmentShaderSource) {
int isSuccess, maxLength;
char *error;
GLuint shaderVertex, shaderFragment, shaderProgram;
// Load the vertex shader first
shaderVertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(shaderVertex, 1, &vertexShaderSource, 0);
glCompileShader(shaderVertex);
// Validate
glGetShaderiv(shaderVertex, GL_COMPILE_STATUS, &isSuccess);
if(!isSuccess) {
glGetShaderiv(shaderVertex, GL_INFO_LOG_LENGTH, &maxLength);
error = malloc(maxLength);
glGetShaderInfoLog(shaderVertex, maxLength, &maxLength, error);
printf("Failed to compile vertex shader %s\n", error);
free(error);
return NULL;
}
// Now load the Frag shader
shaderFragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(shaderFragment, 1, &fragmentShaderSource, 0);
glCompileShader(shaderFragment);
glGetShaderiv(shaderFragment, GL_COMPILE_STATUS, &isSuccess);
if(!isSuccess) {
glGetShaderiv(shaderFragment, GL_INFO_LOG_LENGTH, &maxLength);
error = malloc(maxLength);
glGetShaderInfoLog(shaderFragment, maxLength, &maxLength, error);
printf("Failed to compile fragment shader %s\n", error);
free(error);
glDeleteShader(shaderVertex);
return NULL;
}
// Now create the shader program.
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, shaderVertex);
glAttachShader(shaderProgram, shaderFragment);
//Bind, Verify & Use the shader program
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &isSuccess);
if(!isSuccess) {
glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &maxLength);
error = malloc(maxLength);
glGetProgramInfoLog(shaderProgram, maxLength, &maxLength, error);
printf("Failed to load shader program %s\n", error);
free(error);
glDeleteShader(shaderVertex);
glDeleteShader(shaderFragment);
return NULL;
}
// Everything is okay, let's create the encapsulated shader.
shader_t *shader = malloc(sizeof(shader_t));
if(shader == NULL) {
glDeleteProgram(shaderProgram);
glDeleteShader(shaderVertex);
glDeleteShader(shaderFragment);
return NULL;
}
shader->shaderVertex = shaderVertex;
shader->shaderFrag = shaderFragment;
shader->shaderProgram = shaderProgram;
// Bind the shader
shaderUse(shader);
// Fetch the uniforms.
return shader;
}
bool shaderDipose(shader_t *shader) {
glDeleteProgram(shader->shaderProgram);
glDeleteShader(shader->shaderVertex);
glDeleteShader(shader->shaderFrag);
free(shader);
return true;
}
void shaderUse(shader_t *shader) {
glUseProgram(shader->shaderProgram);
}

View File

@ -0,0 +1,51 @@
/**
* Copyright (c) 2021 Dominic Msters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include <glad/glad.h>
#include <stdio.h>
#include <stdbool.h>
#include <malloc.h>
/**
* Structure containing information about an OpenGL Shader. For simplicity sake
* we demand certain uninforms to be present on the shader target.
*/
typedef struct {
/** Pointer to an uploaded vertex shader program */
GLuint shaderVertex;
/** Pointer to an uploaded fragment shader program */
GLuint shaderFrag;
/** Pointer to an uploaded shader program linked */
GLuint shaderProgram;
} shader_t;
/**
* Create a shader from vertex and fragment shader code.
*
* @param vertexShaderSource The raw vertex shader code.
* @param fragmentShaderSource The raw fragment shader code.
* @return Pointer to the loaded shader.
*/
shader_t * shaderCompile(char *vertexShaderSource, char* fragmentShaderSource);
/**
* Cleanup and unload a previously loaded shader.
*
* @param shader The shader to unload
* @return True if successfully disposed.
*/
bool shaderDipose(shader_t *shader);
/**
* Attaches the supplied shader as the current shader.
* @param shader The shader to attach
*/
void shaderUse(shader_t *shader);

View File

@ -7,24 +7,23 @@
#include "engine.h"
engine_t * engineInit(
platform_t *platform, char *gameName, uint32_t inputCount
) {
engine_t * engineInit(platform_t *platform, char *name, uint32_t inputCount) {
// Create the engine instance.
engine_t *engine = malloc(sizeof(engine_t));
if(engine == NULL) return NULL;
engine->name = name;
engine->platform = platform;
// Setup the renderer.
engine->render = renderInit(gameName);
engine->render = renderInit(name);
if(engine->render == NULL) {
free(engine);
return NULL;
}
// Setup the input manager.
engine->input = inputInit(platform, inputCount);
engine->input = inputInit(inputCount);
if(engine->input == NULL) {
free(engine->render);
free(engine);
@ -34,13 +33,9 @@ engine_t * engineInit(
return engine;
}
void engineStart(engine_t *engine) {
while(!glfwWindowShouldClose(engine->render->window)) {
inputUpdate(engine->platform, engine->input);
renderFrame(engine->render);
glfwSwapBuffers(engine->render->window);
glfwPollEvents();
}
void engineUpdate(engine_t *engine) {
renderFrame(engine->render);
inputUpdate(engine->input);
}
bool engineDispose(engine_t *engine) {

View File

@ -5,17 +5,17 @@
#pragma once
#include <stdbool.h>
#include "../platform/platform.h"
#include "../display/render.h"
#include "../file/asset.h"
#include "../input/input.h"
#include "display/render.h"
#include "file/asset.h"
#include "input/input.h"
#include "./platform.h"
/** Information about the current engine context. */
typedef struct {
/** Name of the game running. */
char *gameName;
char *name;
/** Platform for the game */
/** Platform the game is running on */
platform_t *platform;
/** Renderer for the engine. */
@ -29,20 +29,18 @@ typedef struct {
* Initialize the engine context.
*
* @param platform The platform that the game is running on.
* @param gameName Name of the game being initialized.
* @param name Name of the game being initialized.
* @param inputCount Count of input binds that exist in-engine.
* @return The engine context.
*/
engine_t * engineInit(
platform_t *platform, char *gameName, uint32_t inputCount
);
engine_t * engineInit(platform_t *platform, char *name, uint32_t inputCount);
/**
* Start the main engine loop.
*
* @param engine The game to start the loop for.
*/
void engineStart(engine_t *engine);
void engineUpdate(engine_t *engine);
/**
* Cleanup a previously constructed game engine instance.

91
src/engine/file/asset.c Normal file
View File

@ -0,0 +1,91 @@
/**
* Copyright (c) 2021 Dominic Msters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "asset.h"
char * assetStringLoad(char *assetName) {
// Open a buffer.
FILE *fptr = assetBufferOpen(assetName);
if(fptr == NULL) return NULL;
// Read the count of bytes in the file
fseek(fptr, 0, SEEK_END);// Seek to the end
size_t length = ftell(fptr);// Get our current position (the end)
fseek(fptr, 0, SEEK_SET);// Reset the seek
// Create the string buffer
char *str = malloc(length + 1);// Add 1 for the null terminator.
if(str == NULL) {
assetBufferClose(fptr);
return NULL;
}
// Read and seal the string.
fread(str, 1, length, fptr);// Read all the bytes
str[length] = '\0';// Null terminate.
assetBufferClose(fptr); // Close the buffer.
return str;
}
FILE * assetBufferOpen(char *assetName) {
// Get the directory based on the raw input by creating a new string.
size_t lenAsset = strlen(assetName);// Get the length of asset
size_t lenPrefix = strlen(ASSET_PREFIX);// Get the length of the prefix
// Create str to house both the prefix and asset, and null terminator
char *joined = malloc(lenAsset + lenPrefix + 1);
if(joined == NULL) return NULL;// Mem okay?
joined[0] = '\0';//Start at null
strcat(joined, ASSET_PREFIX);//Add prefix
strcat(joined, assetName);//Add body
// Open the file pointer now.
FILE *fptr = fopen(joined, "rb");
free(joined);// Free the string we just created
if(!fptr) return NULL;// File available?
return fptr;
}
bool assetBufferClose(FILE *buffer) {
return fclose(buffer);
}
int32_t assetBufferRead(FILE *buffer, char *data, int32_t size) {
return (int32_t)fread(data, 1, size, buffer);
}
int32_t assetBufferEnd(FILE *buffer) {
return feof(buffer);
}
void assetBufferSkip(FILE *buffer, int32_t n) {
fseek(buffer, n, SEEK_CUR);
}
shader_t * assetShaderLoad(char *fileVertex, char *fileFragment) {
// Load the vertex shader into memory
char *vertexShader = assetStringLoad(fileVertex);
if(vertexShader == NULL) return NULL;
// Load the fragment shader into memory
char *fragmentShader = assetStringLoad(fileFragment);
if(fragmentShader == NULL) {
free(vertexShader);
return NULL;
}
// Now attempt to load the shader
shader_t *shader = shaderCompile(vertexShader, fragmentShader);
//Cleanup
free(vertexShader);
free(fragmentShader);
return shader;//shader may be NULL if loading failed, but not our problem.
}

75
src/engine/file/asset.h Normal file
View File

@ -0,0 +1,75 @@
/**
* Copyright (c) 2021 Dominic Msters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <malloc.h>
#include <string.h>
#include "../display/shader.h"
/** Prefix of all asset load methods, may be customizable in future. */
#define ASSET_PREFIX "../assets/"
/**
* Method to load an asset into memory as a raw string.
*
* @param assetName Path leading to the asset within the root asset directory.
* @return Pointer to char array of data from asset, NULL if unsuccesful.
*/
char * assetStringLoad(char *assetName);
/**
* Platform-centric method to open a file buffer to an asset.
*
* @param assetName The asset name to open a buffer for.
* @return Pointer to a buffer, NULL if unsuccessfuil.
*/
FILE * assetBufferOpen(char *assetName);
/**
* Closes a previously opened asset buffer.
*
* @param buffer Buffer to close.
* @return True if successful, otherwise false.
*/
bool assetBufferClose(FILE *buffer);
/**
* Read bytes from buffer.
*
* @param buffer The buffer pointing to an asset.
* @param data Pointer to a ubyte array to buffer data into.
* @param size Length of the data buffer. Represents how many bytes can be read.
* @return The count of bytes read. Complete when less than data array size.
*/
int32_t assetBufferRead(FILE *buffer, char *data, int32_t size);
/**
* Skip to the end of the buffer, useful to find the length of the buffer.
*
* @param Buffer The buffer pointing to an asset.
* @return How many bytes were skipped
*/
int32_t assetBufferEnd(FILE *buffer);
/**
* Method to skip n bytes in the buffer
*
* @param buffer The buffer pointing to an asset.
* @param n Count of bytes to skip.
*/
void assetBufferSkip(FILE *buffer, int32_t n);
/**
*
* @param fileVertex The file path of the vertex shader
* @param fileFragment The file path of the fragment shader
* @return The loaded shader_t instance (From shaderCompile)
*/
shader_t * assetShaderLoad(char *fileVertex, char *fileFragment);

43
src/engine/game/game.h Normal file
View File

@ -0,0 +1,43 @@
/**
* Copyright (c) 2021 Dominic Msters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include <stdbool.h>
#include "../engine.h"
#include "../platform.h"
/** Information about the current game context. */
typedef void game_t;
/**
* Initialize the game context.
*
* @return The game instance context.
*/
game_t * gameInit(platform_t *platform);
/**
* Start the main game loop.
*
* @param game The game to start the loop for.
*/
void gameUpdate(game_t *game);
/**
* Cleanup a previously constructed.
* @param game The game to cleanup.
*/
void gameDispose(game_t *game);
/**
* Because games are anonymously typed we simply request that they allow other
* parts of the software to access the engine directly.
*
* @param game The game context
* @return The engine context attached to the running game.
*/
engine_t * gameGetEngine(game_t *game);

108
src/engine/input/input.c Normal file
View File

@ -0,0 +1,108 @@
/**
* Copyright (c) 2021 Dominic Msters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "input.h"
input_t * inputInit(uint32_t inputBindCount) {
uint32_t i;
// Create the input manager
input_t *input = malloc(sizeof(input_t));
if(!input) return NULL;
// Setup the bind lists
input->inputBindCount = inputBindCount;
input->bindMap = malloc(sizeof(list_t) * inputBindCount);
for(i = 0; i < inputBindCount; i++) {
input->bindMap[i] = listCreate();
}
// Create the current & previous input states
input->current = malloc(sizeof(float) * inputBindCount);
input->previous = malloc(sizeof(float) * inputBindCount);
// Create the input actuate times array.
input->times = malloc(sizeof(float) * inputBindCount);
// Pass off the input manager
return input;
}
void inputUpdate(input_t *input) {
uint32_t i;
// Flip the states to save memory.
float * currentCurrent = input->current;
input->current = input->previous;
input->previous = currentCurrent;
// Now look at each bind, get the state from the platform
for(i = 0; i < input->inputBindCount; i++) {
// For this bind, get the sources.
}
}
void inputDispose(input_t *input) {
uint32_t i;
// Free up the bind lists
for(i = 0; i < input->inputBindCount; i++) {
listDispose(input->bindMap[i], false);
}
free(input->times);
free(input->previous);
free(input->current);
free(input->bindMap);
free(input);
}
void inputBind(input_t *input, inputbind_t bind, inputsource_t *source) {
listAdd(input->bindMap[bind], source);
}
void inputUnbind(input_t *input, inputbind_t bind,
inputsource_t *source
) {
listRemove(input->bindMap[bind], source);
}
bool inputIsDown(input_t *input, inputbind_t binding) {
return input->current[binding] != 0;
}
bool inputIsUp(input_t *input, inputbind_t binding) {
return input->current[binding] == 0;
}
bool inputIsPressed(input_t *input, inputbind_t binding) {
return (
input->previous[binding] == 0 &&
input->current[binding] != 0
);
}
bool inputIsReleased(input_t *input, inputbind_t binding) {
return (
input->current[binding] == 0 &&
input->previous[binding] != 0
);
}
float inputGetAxis(input_t *input, inputbind_t binding) {
return input->current[binding];
}
float inputGetFullAxis(input_t *input, inputbind_t positive,
inputbind_t negative
) {
return input->current[negative] + input->current[positive];
}
float inputGetAccuated(input_t *input, inputbind_t binding) {
return input->times[binding];
}

159
src/engine/input/input.h Normal file
View File

@ -0,0 +1,159 @@
// Copyright (c) 2021 Dominic Msters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <malloc.h>
#include "../util/list/list.h"
/////////////////////////////////// CONSTANTS //////////////////////////////////
#define INPUT_NULL (inputbind_t)0x00
#define INPUT_INPUTS_PER_BIND
/////////////////////////////// Type Definitions ///////////////////////////////
/**
* Input Bind, a specific action bind reference for the game engine to use.
* e.g. "Jump" or "Walk Forward".
*/
typedef uint8_t inputbind_t;
typedef void inputsource_t;
/**
* Structure for the entire input mapping.
*/
typedef struct {
/** How many input bindings are in the input managers' scope */
uint32_t inputBindCount;
/** Float of the input between 0 and 1. For teh current frame */
float *current;
/** Float of the input between 0 and 1. For the last frame */
float *previous;
/** Float of the GameTime that the input was actuated last. */
float *times;
/**
* Binding Map, Array of lists where index = binding and entry is a list of
* input sources.
*/
list_t **bindMap;
} input_t;
//////////////////////////////////// Methods ///////////////////////////////////
/**
* Initializes the input manager.
*
* @param inputCount The input binding counts to allow for.
* @return The input manager
*/
input_t * inputInit(uint32_t inputBindCount);
/**
* Tick the input manager.
* @param input The input to update.
*/
void inputUpdate(input_t *input);
/**
* Destroy the input manager and cleanup.
* @param input The input to destroy.
*/
void inputDispose(input_t *input);
/**
* Binds the given input binding to the input source. Essentially allowing any
* time we fetch the state of bind, we will read the value from source.
*
* @param input The input manager to bind for.
* @param bind The binding to bind against.
* @param source The source that is being bound.
*/
void inputBind(input_t *input, inputbind_t bind, inputsource_t *source);
/**
* Unbind a previously bound input source from a binding. This method is costly.
*
* @param input The input manager to bind for.
* @param bind The binding to unbind from.
* @param source The source that is being unbound.
*/
void inputUnbind(input_t *input, inputbind_t bind, inputsource_t *source);
/**
* Is the current input "down", not being pressed, being moved, not in a state
* of rest.
*
* @param state The input state to check against.
* @param binding The previously bound input binding.
* @return True if the input vector is non-zero.
*/
bool inputIsDown(input_t *state, inputbind_t binding);
/**
* Is the current input "up", in a state of rest, not being actioned, moved.
*
* @param state The input state to check against.
* @param binding The previously bound input binding.
* @return True if input vector is zero
*/
bool inputIsUp(input_t *state, inputbind_t binding);
/**
* Returns true on the first tick that an input was actioned/downed.
*
* @param input The input manager.
* @param binding The previously bound input binding.
* @return True if the input vector was non-zeroed this tick but not last.
*/
bool inputIsPressed(input_t *input, inputbind_t binding);
/**
* Returns true on the first tick that an input was released/upped.
*
* @param input The input manager.
* @param binding The previously bound input binding.
* @return True if the input vector was zeroed this tick but not last.
*/
bool inputIsReleased(input_t *input, inputbind_t binding);
/**
* Returns the raw input value as a float between 0 and 1. For digital (buttons)
* this will typicall be 0 or 1 only. Other analogue inputs will have anywhere
* within the range.
*
* @param input The input manager to check against.
* @param binding The previously bound input binding.
* @return A float between 0 and 1 representing the action force of the input.
*/
float inputGetAxis(input_t *input, inputbind_t binding);
/**
* Returns a raw input value between -1 and 1 between two axis. This would be
* indicitive of having an input with an axis that can be moved one direction
* for a positive input and another for a negative input, typically a game
* controller's analogue sticks.
*
* @param input The input manager to check against.
* @param postitive The positive axis binding.
* @param negative The negative axis binding.
* @return A float between -1 and 1 representing the result of both.
*/
float inputGetFullAxis(input_t *input, inputbind_t positive,
inputbind_t negative
);
/**
* Returns the time that an input was actuated at. Actuate would count as a
* non-zero input for analogue inputs.
*
* @param input The input manager to check against.
* @param binding The previously bound input binding.
* @return Game Engine time that an input was non-zeroed
*/
float inputGetAccuated(input_t *input, inputbind_t binding);

22
src/engine/platform.h Normal file
View File

@ -0,0 +1,22 @@
// Copyright (c) 2021 Dominic Msters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include <malloc.h>
#include <stdint.h>
/**
* Contains information about the running platform. Essentially this is just
* some context as to what is running the game engine itself. It's mostly for
* metadata purposes but there may be some technical information required for
* the engine.
*/
typedef struct {
/** Internal name of the platform */
char *name;
/** Dimensions of the screen (in pixels) */
uint32_t screenWidth, screenHeight;
} platform_t;

138
src/engine/util/list/list.c Normal file
View File

@ -0,0 +1,138 @@
/**
* Copyright (c) 2021 Dominic Msters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "list.h"
list_t * listCreate() {
list_t *list = malloc(sizeof(list_t));
if(list == NULL) return NULL;
list->start = NULL;
list->end = NULL;
list->size = 0;
return list;
}
listentry_t * listAdd(list_t *list, void *data) {
//Create the list entry
listentry_t *entry = malloc(sizeof(listentry_t));
if(entry == NULL) return NULL;
entry->data = data;
entry->next = NULL;
entry->prev = NULL;
//Add it to the list
listAddEntry(list, entry);
//Return the entry
return entry;
}
void listAddEntry(list_t *list, listentry_t *entry) {
//Is this the first / only thing in the list?
if(list->start == NULL) {
list->start = entry;
list->end = entry;
} else {
//Make the end's next be this entry, and this entry's prev the end, then
//make this the new end
entry->prev = list->end;
list->end->next = entry;
list->end = entry;
}
list->size++;
}
void listRemove(list_t *list, void *data) {
uint32_t i = 0;
listentry_t *previous = list->start;
while(previous != NULL) {
if(previous->data == data) {
listRemoveEntry(list, previous, false);
break;
}
i++;
previous = previous->next;
}
}
void listRemoveEntry(list_t *list, listentry_t *entry, bool freeData) {
//Update next and prev
if(entry->prev != NULL) entry->prev->next = entry->next;
if(entry->next != NULL) entry->next->prev = entry->prev;
//Was this at the end?
if(list->start == entry) list->start = entry->next;
if(list->end == entry) list->end = entry->prev;
if(freeData) free(entry->data);
free(entry);
list->size--;
}
listentry_t * listGetByIndex(list_t *list, uint32_t index) {
if(index >= list->size) return NULL;
//TODO: We can probably make this more efficient by deciding which way we
//should loop from based on the list size.
uint32_t i = 0;
listentry_t *previous = list->start;
while(previous != NULL) {
if(i == index) return previous;
i++;
previous = previous->next;
}
return NULL;
}
uint32_t listGetIndex(list_t *list, void* data) {
uint32_t i = 0;
listentry_t *previous = list->start;
while(previous != NULL) {
if(previous->data == data) return i;
i++;
previous = previous->next;
}
return -1;
}
uint32_t listGetEntryIndex(list_t *list, listentry_t *entry) {
uint32_t i = 0;
listentry_t *previous = list->start;
while(previous != NULL) {
if(previous == entry) return i;
i++;
previous = previous->next;
}
return -1;
}
void listDispose(list_t *list, bool freeData) {
//Free all of the entries
listentry_t *next = list->start;
listentry_t *current;
while(next != NULL) {
current = next;
next = current->next;
if(freeData) free(current->data);
free(current);
}
free(list);
}

106
src/engine/util/list/list.h Normal file
View File

@ -0,0 +1,106 @@
// Copyright (c) 2021 Dominic Msters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include <stdio.h>
#include <stdbool.h>
#include <malloc.h>
#include <stdint.h>
/**
* Entry within a given linked list.
* @param data* The pointer to the data that is within the entry.
* @param prev* Pointer to the previous entry in the list.
* @param next* Pointer to the next entry in the list.
*/
typedef struct listentry_t {
void *data;
struct listentry_t *prev;
struct listentry_t *next;
} listentry_t;
/**
* Linked List of elements, Doubly Linked.
* @param size The count of elements currently within the list
* @param start* First element within the list.
* @param end* Last element within the list.
*/
typedef struct {
uint32_t size;
listentry_t *start;
listentry_t *end;
} list_t;
//Method definitions
/**
* Creates a new linked list
* @return Pointer to a new linked list.
*/
list_t * listCreate();
/**
* Adds data to a linked list
*
* @param list* Pointer to a previously created linked list
* @param data* Pointer to your data
* @return A pointer to the new entry in the linked list that was created
*/
listentry_t * listAdd(list_t *list, void *data);
/**
* Internal function
*/
void listAddEntry(list_t *list, listentry_t *entry);
/**
* Remove data from a linked list.
*
* @param list Pointer to a previously created linked list.
* @param data* Pointer to your data.
*/
void listRemove(list_t *list, void *data);
/**
* Remove a list entry from the linked list.
*
* @param list* Pointer to a previously created linked list.
* @param entry* Pointer to the entry within the linked list.
* @param freeData If true the data of the listentry_t will be free()'d
*/
void listRemoveEntry(list_t *list, listentry_t *entry, bool freeData);
/**
* Returns the entry at a given index. This method is costly.
* @param list* Pointer to a previously created linked list
* @param index Index of element within the linked list to remove
* @return The entry at the index or NULL if outside the bounds.
*/
listentry_t * listGetByIndex(list_t *list, uint32_t index);
/**
* Returns the index of data within the linked list. This method is costly.
*
* @param list* Pointer to a previously created linked list
* @param data* Pointer to your data.
* @return The index within the list the entry is in, or -1 if not found.
*/
uint32_t listGetIndex(list_t *list, void* data);
/**
* Returns the index of an entry within the linked list. This method is costly.
*
* @param list* Pointer to a previously created linked list
* @param entry* Pointer to the entry within the linked list.
* @return The index within the list the entry is in, or -1 if not found.
*/
uint32_t listGetEntryIndex(list_t *list, listentry_t *entry);
/**
* Dispose a previously created link list.
* @param list* Pointer to a previously created linked list
* @param freeData If true the data within each listentry_t will be free()'d
*/
void listDispose(list_t *list, bool freeData);