first commit

This commit is contained in:
2024-04-11 01:05:03 -04:00
commit 3398c52f8b
272 changed files with 35195 additions and 0 deletions

57
src/COMMON.h Normal file
View File

@@ -0,0 +1,57 @@
#pragma once
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <cglm/cglm.h>
#define PI (GLM_PI)
#define PI_FOURTH (PI / 4)
#define PI_EIGHTH (PI / 8)
#define PI_HALF (PI / 2)
#define TAU (PI * 2)
#define RADIANS(x) (x * (PI / 180))
#define RADIANS_MIN (0)
#define RADIANS_MAX (TAU)
#define MIN(x, min) (x < min ? min : x)
#define MAX(x, max) (x > max ? max : x)
#define CLAMP(x, min, max) (MIN(MAX(x, max), min))
#define RANDOM_SEED_SET(seed) (srand(seed))
#define RANDOM ((f32)rand() / (f32)RAND_MAX)
#define RANDOM_F32(min, max) ((f32)((RANDOM * (max - min + 1)) + min))
#define RANDOM_S32(min, max) ((s32)((RANDOM * (max - min + 1)) + min))
#define RANDOM_BOOL() (RANDOM_S32(0, 2))
#define DISTANCE_2D(x1, x2, y1, y2) (sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2)))
#define ATAN(x1, x2, y1, y2) (fmod((atan2(y2 - y1, x2 - x1) + TAU), TAU)) /* Range between 0 and 2PI */
#define MILLISECOND_TICK 600
#define SECOND_TICK 60
#define MINUTE_TICK 3600
#define HOUR_TICK 216000
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
typedef float f32;
typedef double f64;
typedef s32 (*SortCompareFunction)(const void*, const void*);
static const vec4 OPAQUE = {1.0f, 1.0f, 1.0f, 1.0f};
static const vec4 BLACK = {0.0f, 0.0f, 0.0f, 1.0f};
static const vec4 TRANSPARENT = {0.0f, 0.0f, 0.0f, 0.0f};

66
src/engine/camera.c Normal file
View File

@@ -0,0 +1,66 @@
#include "camera.h"
void
camera_orthographic_init(Camera* self, vec2 size)
{
memset(self, '\0', sizeof(Camera));
self->type = CAMERA_ORTHOGRAPHIC;
glm_vec2_copy(size, self->orthographic.size);
}
void
camera_view_get(Camera* self, mat4 view)
{
glm_mat4_identity(view);
switch (self->type)
{
case CAMERA_ORTHOGRAPHIC:
glm_mat4_identity(view);
break;
default:
break;
}
}
void
camera_projection_get(Camera* self, mat4 projection)
{
glm_mat4_identity(projection);
switch (self->type)
{
case CAMERA_ORTHOGRAPHIC:
glm_ortho
(
0.0f,
self->orthographic.size[0],
self->orthographic.size[1],
0.0f,
CAMERA_ORTHOGRAPHIC_NEAR,
CAMERA_ORTHOGRAPHIC_FAR,
projection
);
break;
default:
break;
}
}
void
camera_position_set(Camera* self, vec3 position)
{
glm_vec3_copy(position, self->position);
}
void
camera_orthographic_window_set(Camera* self, Window* window)
{
ivec2 size;
window_size_get(window, size);
self->orthographic.size[0] = (f32)size[0];
self->orthographic.size[1] = (f32)size[1];
}

41
src/engine/camera.h Normal file
View File

@@ -0,0 +1,41 @@
#pragma once
#include <GL/glew.h>
#include <GL/gl.h>
#include "window.h"
#define CAMERA_ORTHOGRAPHIC_FAR -1.0f
#define CAMERA_ORTHOGRAPHIC_NEAR 1.0f
typedef enum CameraType
{
CAMERA_PERSPECTIVE, // unsupported
CAMERA_ORTHOGRAPHIC
} CameraType;
typedef struct Camera
{
CameraType type;
vec3 position;
f32 yaw;
f32 pitch;
union
{
struct
{
vec2 size;
} orthographic;
struct
{
f32 fov;
f32 aspect;
} perspective;
};
} Camera;
void camera_orthographic_init(Camera* self, vec2 size);
void camera_orthographic_window_set(Camera* self, Window* window);
void camera_position_set(Camera* self, vec3 position);
void camera_projection_get(Camera* self, mat4 projection);
void camera_view_get(Camera* self, mat4 view);

42
src/engine/circle.c Normal file
View File

@@ -0,0 +1,42 @@
#include "circle.h"
bool
circle_collide_check(Circle* a, Circle* b)
{
f32 sum;
f32 distance;
distance = DISTANCE_2D
(
a->position[0],
b->position[0],
a->position[1],
b->position[1]
);
sum = a->radius + b->radius;
if (distance < sum)
return true;
return false;
}
bool
circle_has_point_check(Circle* self, vec2 point)
{
f32 distance;
distance = DISTANCE_2D
(
point[0],
self->position[0],
point[1],
self->position[1]
);
if (distance <= self->radius)
return true;
return false;
}

12
src/engine/circle.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include "../COMMON.h"
typedef struct Circle
{
f32 radius;
vec2 position;
} Circle;
bool circle_collide_check(Circle* a, Circle* b);
bool circle_has_point_check(Circle* self, vec2 point);

56
src/engine/debug.c Normal file
View File

@@ -0,0 +1,56 @@
#include "debug.h"
void
debug_vec2_print(const char* string, vec2 value)
{
if (string)
printf("%s %s {%.3f, %.3f}\n", STRING_DEBUG, string, value[0], value[1]);
else
printf("%s {%.3f, %.3f}\n", STRING_DEBUG, value[0], value[1]);
}
void
debug_vec3_print(const char* string, vec3 value)
{
if (string)
printf("%s %s {%.3f, %.3f, %.3f}\n", STRING_DEBUG, string, value[0], value[1], value[2]);
else
printf("%s {%.3f, %.3f, %.3f}\n", STRING_DEBUG, value[0], value[1], value[2]);
}
void
debug_mat4_print(const char* string, mat4 value)
{
if (string)
{
printf
(
"%s %s\n"
"\t %.3f %.3f %.3f %.3f\n"
"\t %.3f %.3f %.3f %.3f\n"
"\t %.3f %.3f %.3f %.3f\n"
"\t %.3f %.3f %.3f %.3f\n",
STRING_DEBUG, string,
value[0][0], value[0][1], value[0][2], value[0][3],
value[1][0], value[1][1], value[1][2], value[1][3],
value[2][0], value[2][1], value[2][2], value[2][3],
value[3][0], value[3][1], value[3][2], value[3][3]
);
}
else
{
printf
(
"%s\n"
"\t %.3f %.3f %.3f %.3f\n"
"\t %.3f %.3f %.3f %.3f\n"
"\t %.3f %.3f %.3f %.3f\n"
"\t %.3f %.3f %.3f %.3f\n",
STRING_DEBUG,
value[0][0], value[0][1], value[0][2], value[0][3],
value[1][0], value[1][1], value[1][2], value[1][3],
value[2][0], value[2][1], value[2][2], value[2][3],
value[3][0], value[3][1], value[3][2], value[3][3]
);
}
}

9
src/engine/debug.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#include "../COMMON.h"
#define STRING_DEBUG "[DEBUG]"
void debug_vec2_print(const char* string, vec2 value);
void debug_vec3_print(const char* string, vec3 value);
void debug_mat4_print(const char* string, mat4 value);

44
src/engine/event.c Normal file
View File

@@ -0,0 +1,44 @@
#include "event.h"
/* Updates events. */
void
event_update(Event* self)
{
SDL_Event event;
memcpy(&self->previous, &self->current, sizeof(bool) * EVENT_COUNT);
memset(&self->current, '\0', sizeof(bool) * EVENT_COUNT);
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
self->current[EVENT_QUIT] = true;
break;
default:
break;
}
}
}
/* Is a given event pressed? */
bool
event_press(Event* self, EventType type)
{
return (self->current[type] && !self->previous[type]);
}
/* Is a given event held? */
bool
event_held(Event* self, EventType type)
{
return (self->current[type] && self->previous[type]);
}
/* Is a given event released? */
bool
event_release(Event* self, EventType type)
{
return (!self->current[type] && self->previous[type]);
}

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

@@ -0,0 +1,22 @@
#pragma once
#include <SDL2/SDL.h>
#include "../COMMON.h"
#define EVENT_COUNT (EVENT_QUIT + 1)
typedef enum EventType
{
EVENT_QUIT
} EventType;
typedef struct Event
{
bool current[EVENT_COUNT];
bool previous[EVENT_COUNT];
} Event;
void event_update(Event* self);
bool event_press(Event* self, EventType type);
bool event_held(Event* self, EventType type);
bool event_release(Event* self, EventType type);

38
src/engine/fbo.c Normal file
View File

@@ -0,0 +1,38 @@
#include "fbo.h"
void
fbo_init(FBO* self)
{
glGenFramebuffers(1, &self->handle);
}
void
fbo_bind(FBO* self)
{
glBindFramebuffer(GL_FRAMEBUFFER, self->handle);
}
void
fbo_unbind(void)
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void
fbo_rbo_set(RBO* rbo)
{
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo->handle);
}
void
fbo_texture_set(Texture* texture)
{
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->handle, 0);
}
void
fbo_free(FBO* self)
{
glDeleteFramebuffers(1, &self->handle);
memset(self, '\0', sizeof(FBO));
}

16
src/engine/fbo.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
#include "rbo.h"
#include "texture.h"
typedef struct FBO
{
GLuint handle;
} FBO;
void fbo_init(FBO* self);
void fbo_bind(FBO* self);
void fbo_unbind(void);
void fbo_free(FBO* self);
void fbo_rbo_set(RBO* rbo);
void fbo_texture_set(Texture* texture);

53
src/engine/file.c Normal file
View File

@@ -0,0 +1,53 @@
#include "file.h"
bool
file_read(const char* path, void* buffer, size_t size, const char* mode)
{
SDL_RWops* io;
printf(STRING_FILE_READ_OPEN, path);
io = SDL_RWFromFile(path, mode);
if (!io)
{
printf(STRING_FILE_READ_ERROR, path);
return false;
}
SDL_RWread(io, buffer, size, 1);
printf(STRING_FILE_READ_SUCCESS, path);
SDL_RWclose(io);
printf(STRING_FILE_CLOSED, path);
return true;
}
bool
file_write(const char* path, void* data, size_t size, const char* mode)
{
SDL_RWops* io;
printf(STRING_FILE_WRITE_OPEN, path);
io = SDL_RWFromFile(path, mode);
if (!io)
{
printf(STRING_FILE_WRITE_ERROR, path);
return false;
}
SDL_RWwrite(io, data, size, 1);
printf(STRING_FILE_WRITE_SUCCESS, path);
SDL_RWclose(io);
printf(STRING_FILE_CLOSED, path);
return true;
}

15
src/engine/file.h Normal file
View File

@@ -0,0 +1,15 @@
#pragma once
#include <SDL2/SDL.h>
#include "../COMMON.h"
#define STRING_FILE_READ_OPEN "[INFO] Opened file to read: %s\n"
#define STRING_FILE_CLOSED "[INFO] Closed file: %s\n"
#define STRING_FILE_READ_SUCCESS "[INFO] Read from file: %s\n"
#define STRING_FILE_READ_ERROR "[ERROR] Unable to read from file: %s\n"
#define STRING_FILE_WRITE_OPEN "[INFO] Opened file to write: %s\n"
#define STRING_FILE_WRITE_ERROR "[ERROR] Unable to write to file: %s\n"
#define STRING_FILE_WRITE_SUCCESS "[INFO] Wrote to file: %s\n"
bool file_read(const char* path, void* buffer, size_t size, const char* mode);
bool file_write(const char* path, void* data, size_t size, const char* mode);

104
src/engine/font.c Normal file
View File

@@ -0,0 +1,104 @@
#include "font.h"
void
font_glyph_metrics_init(Font* self, GlyphMetrics* glyphMetrics, char glyph)
{
TTF_GlyphMetrics
(
self->ttf,
glyph,
&glyphMetrics->minX,
&glyphMetrics->maxX,
&glyphMetrics->minY,
&glyphMetrics->maxY,
&glyphMetrics->advance
);
}
s32
font_glyph_width_get(Font* self, char glyph)
{
GlyphMetrics glyphMetrics;
font_glyph_metrics_init(self, &glyphMetrics, glyph);
return glyphMetrics.maxX - glyphMetrics.minX;
}
s32
font_glyph_kerning_get(Font* self, char glyph, char nextGlyph)
{
return TTF_GetFontKerningSizeGlyphs(self->ttf, glyph, nextGlyph);
}
void
font_glyph_texture_init(Font* self, Texture* texture, char glyph)
{
SDL_Surface* surface;
SDL_Surface* textSurface;
ivec2 size;
size[0] = font_glyph_width_get(self, glyph);
size[1] = font_height_get(self);
surface_rgba_init(&surface, size);
textSurface = TTF_RenderGlyph_Blended(self->ttf, glyph, GLYPH_COLOR);
SDL_BlitSurface(textSurface, NULL, surface, NULL);
SDL_FreeSurface(textSurface);
texture_surface_init(texture, surface);
SDL_FreeSurface(surface);
}
s32
font_line_skip_get(Font* self)
{
return TTF_FontLineSkip(self->ttf);
}
s32
font_height_get(Font* self)
{
return TTF_FontHeight(self->ttf);
}
bool
font_init(Font* self, const char* path, u32 size)
{
self->ttf = TTF_OpenFont(path, size);
if (!self->ttf)
{
printf(STRING_SDL_TTF_FONT_ERROR, path, TTF_GetError());
return false;
}
printf(STRING_SDL_TTF_FONT_SUCCESS, path);
self->size = size;
self->isInit = true;
for (s32 i = 0; i < FONT_GLYPH_MAX; i++)
font_glyph_texture_init(self, &self->glyphTextures[i], (char)i);
return true;
}
void
font_free(Font* self)
{
if (self->isInit)
{
TTF_CloseFont(self->ttf);
for (s32 i = 0; i < FONT_GLYPH_MAX; i++)
texture_free(&self->glyphTextures[i]);
self->isInit = false;
}
}

39
src/engine/font.h Normal file
View File

@@ -0,0 +1,39 @@
#pragma once
#include <SDL2/SDL_ttf.h>
#include "texture.h"
#include "surface.h"
#define FONT_GLYPH_MAX 128
#define STRING_SDL_TTF_FONT_SUCCESS "[INFO] Loaded font: %s\n"
#define STRING_SDL_TTF_FONT_ERROR "[ERROR] Unable to load font: %s | %s\n"
typedef struct Font
{
TTF_Font* ttf;
Texture glyphTextures[FONT_GLYPH_MAX];
u32 size;
bool isInit;
} Font;
typedef struct GlyphMetrics
{
s32 minX;
s32 minY;
s32 maxX;
s32 maxY;
s32 advance;
} GlyphMetrics;
bool font_init(Font* self, const char* path, u32 size);
s32 font_glyph_kerning_get(Font* self, char glyph, char nextGlyph);
s32 font_glyph_width_get(Font* self, char glyph);
s32 font_height_get(Font* self);
s32 font_line_skip_get(Font* self);
void font_free(Font* self);
void font_glyph_metrics_init(Font* self, GlyphMetrics* glyphMetrics, char glyph);
void font_glyph_texture_init(Font* self, Texture* texture, char glyph);
static const SDL_Color GLYPH_COLOR = {255, 255, 255, 255};

22
src/engine/fullscreen.c Normal file
View File

@@ -0,0 +1,22 @@
#include "fullscreen.h"
/* Sets window to fullscreen. */
void
fullscreen_set(Window* self, Renderer* renderer)
{
SDL_SetWindowSize(self->sdl, self->expectedSize[0], self->expectedSize[1]);
renderer_update(renderer);
SDL_SetWindowFullscreen(self->sdl, SDL_WINDOW_FULLSCREEN_DESKTOP);
}
/* Exits fullscreen. */
void
fullscreen_exit(Window* self, Renderer* renderer)
{
SDL_SetWindowFullscreen(self->sdl, 0);
SDL_SetWindowSize(self->sdl, self->expectedSize[0], self->expectedSize[1]);
renderer_update(renderer);
}

7
src/engine/fullscreen.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#include "window.h"
#include "renderer.h"
void fullscreen_set(Window* window, Renderer* renderer);
void fullscreen_exit(Window* window, Renderer* renderer);

9
src/engine/glew.c Normal file
View File

@@ -0,0 +1,9 @@
#include "glew.h"
void
glew_init(void)
{
glewInit();
printf(STRING_GLEW_INIT);
}

9
src/engine/glew.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#include <GL/glew.h>
#include "../COMMON.h"
#define STRING_GLEW_INIT "[INFO] Initialized GLEW\n"
void glew_init(void);

32
src/engine/keyboard.c Normal file
View File

@@ -0,0 +1,32 @@
#include "keyboard.h"
void
keyboard_update(Keyboard* self)
{
const u8* state;
memcpy(&self->previous, &self->current, sizeof(u8) * KEYBOARD_KEY_COUNT);
memset(&self->current, '\0', sizeof(u8) * KEYBOARD_KEY_COUNT);
state = SDL_GetKeyboardState(NULL);
memcpy(&self->current, state, KEYBOARD_KEY_COUNT);
}
bool
keyboard_press(Keyboard* self, KeyboardKeyType type)
{
return (self->current[type] && !self->previous[type]);
}
bool
keyboard_held(Keyboard* self, KeyboardKeyType type)
{
return (self->current[type] && self->previous[type]);
}
bool
keyboard_release(Keyboard* self, KeyboardKeyType type)
{
return (!self->current[type] && self->previous[type]);
}

240
src/engine/keyboard.h Normal file
View File

@@ -0,0 +1,240 @@
#pragma once
#include <SDL2/SDL.h>
#include "../COMMON.h"
#define KEYBOARD_KEY_COUNT (255)
typedef enum KeyboardKeyType
{
KEYBOARD_KEY_UNKNOWN = 0,
KEYBOARD_KEY_UNKNOWN_TWO = 1,
KEYBOARD_KEY_UNKNOWN_THREE = 2,
KEYBOARD_KEY_UNKNOWN_FOUR = 3,
KEYBOARD_KEY_A = 4,
KEYBOARD_KEY_B = 5,
KEYBOARD_KEY_C = 6,
KEYBOARD_KEY_D = 7,
KEYBOARD_KEY_E = 8,
KEYBOARD_KEY_F = 9,
KEYBOARD_KEY_G = 10,
KEYBOARD_KEY_H = 11,
KEYBOARD_KEY_I = 12,
KEYBOARD_KEY_J = 13,
KEYBOARD_KEY_K = 14,
KEYBOARD_KEY_L = 15,
KEYBOARD_KEY_M = 16,
KEYBOARD_KEY_N = 17,
KEYBOARD_KEY_O = 18,
KEYBOARD_KEY_P = 19,
KEYBOARD_KEY_Q = 20,
KEYBOARD_KEY_R = 21,
KEYBOARD_KEY_S = 22,
KEYBOARD_KEY_T = 23,
KEYBOARD_KEY_U = 24,
KEYBOARD_KEY_V = 25,
KEYBOARD_KEY_W = 26,
KEYBOARD_KEY_X = 27,
KEYBOARD_KEY_Y = 28,
KEYBOARD_KEY_Z = 29,
KEYBOARD_KEY_1 = 30,
KEYBOARD_KEY_2 = 31,
KEYBOARD_KEY_3 = 32,
KEYBOARD_KEY_4 = 33,
KEYBOARD_KEY_5 = 34,
KEYBOARD_KEY_6 = 35,
KEYBOARD_KEY_7 = 36,
KEYBOARD_KEY_8 = 37,
KEYBOARD_KEY_9 = 38,
KEYBOARD_KEY_0 = 39,
KEYBOARD_KEY_RETURN = 40,
KEYBOARD_KEY_ESCAPE = 41,
KEYBOARD_KEY_BACKSPACE = 42,
KEYBOARD_KEY_TAB = 43,
KEYBOARD_KEY_SPACE = 44,
KEYBOARD_KEY_MINUS = 45,
KEYBOARD_KEY_EQUALS = 46,
KEYBOARD_KEY_LEFTBRACKET = 47,
KEYBOARD_KEY_RIGHTBRACKET = 48,
KEYBOARD_KEY_BACKSLASH = 49,
KEYBOARD_KEY_NONUSHASH = 50,
KEYBOARD_KEY_SEMICOLON = 51,
KEYBOARD_KEY_APOSTROPHE = 52,
KEYBOARD_KEY_GRAVE = 53,
KEYBOARD_KEY_COMMA = 54,
KEYBOARD_KEY_PERIOD = 55,
KEYBOARD_KEY_SLASH = 56,
KEYBOARD_KEY_CAPSLOCK = 57,
KEYBOARD_KEY_F1 = 58,
KEYBOARD_KEY_F2 = 59,
KEYBOARD_KEY_F3 = 60,
KEYBOARD_KEY_F4 = 61,
KEYBOARD_KEY_F5 = 62,
KEYBOARD_KEY_F6 = 63,
KEYBOARD_KEY_F7 = 64,
KEYBOARD_KEY_F8 = 65,
KEYBOARD_KEY_F9 = 66,
KEYBOARD_KEY_F10 = 67,
KEYBOARD_KEY_F11 = 68,
KEYBOARD_KEY_F12 = 69,
KEYBOARD_KEY_PRINTSCREEN = 70,
KEYBOARD_KEY_SCROLLLOCK = 71,
KEYBOARD_KEY_PAUSE = 72,
KEYBOARD_KEY_INSERT = 73,
KEYBOARD_KEY_HOME = 74,
KEYBOARD_KEY_PAGEUP = 75,
KEYBOARD_KEY_DELETE = 76,
KEYBOARD_KEY_END = 77,
KEYBOARD_KEY_PAGEDOWN = 78,
KEYBOARD_KEY_RIGHT = 79,
KEYBOARD_KEY_LEFT = 80,
KEYBOARD_KEY_DOWN = 81,
KEYBOARD_KEY_UP = 82,
KEYBOARD_KEY_NUMLOCKCLEAR = 83,
KEYBOARD_KEY_KP_DIVIDE = 84,
KEYBOARD_KEY_KP_MULTIPLY = 85,
KEYBOARD_KEY_KP_MINUS = 86,
KEYBOARD_KEY_KP_PLUS = 87,
KEYBOARD_KEY_KP_ENTER = 88,
KEYBOARD_KEY_KP_1 = 89,
KEYBOARD_KEY_KP_2 = 90,
KEYBOARD_KEY_KP_3 = 91,
KEYBOARD_KEY_KP_4 = 92,
KEYBOARD_KEY_KP_5 = 93,
KEYBOARD_KEY_KP_6 = 94,
KEYBOARD_KEY_KP_7 = 95,
KEYBOARD_KEY_KP_8 = 96,
KEYBOARD_KEY_KP_9 = 97,
KEYBOARD_KEY_KP_0 = 98,
KEYBOARD_KEY_KP_PERIOD = 99,
KEYBOARD_KEY_NONUSBACKSLASH = 100,
KEYBOARD_KEY_APPLICATION = 101,
KEYBOARD_KEY_POWER = 102,
KEYBOARD_KEY_KP_EQUALS = 103,
KEYBOARD_KEY_F13 = 104,
KEYBOARD_KEY_F14 = 105,
KEYBOARD_KEY_F15 = 106,
KEYBOARD_KEY_F16 = 107,
KEYBOARD_KEY_F17 = 108,
KEYBOARD_KEY_F18 = 109,
KEYBOARD_KEY_F19 = 110,
KEYBOARD_KEY_F20 = 111,
KEYBOARD_KEY_F21 = 112,
KEYBOARD_KEY_F22 = 113,
KEYBOARD_KEY_F23 = 114,
KEYBOARD_KEY_F24 = 115,
KEYBOARD_KEY_EXECUTE = 116,
KEYBOARD_KEY_HELP = 117,
KEYBOARD_KEY_MENU = 118,
KEYBOARD_KEY_SELECT = 119,
KEYBOARD_KEY_STOP = 120,
KEYBOARD_KEY_AGAIN = 121,
KEYBOARD_KEY_UNDO = 122,
KEYBOARD_KEY_CUT = 123,
KEYBOARD_KEY_COPY = 124,
KEYBOARD_KEY_PASTE = 125,
KEYBOARD_KEY_FIND = 126,
KEYBOARD_KEY_MUTE = 127,
KEYBOARD_KEY_VOLUMEUP = 128,
KEYBOARD_KEY_VOLUMEDOWN = 129,
KEYBOARD_KEY_LOCKINGCAPSLOCK = 130,
KEYBOARD_KEY_LOCKINGNUMLOCK = 131,
KEYBOARD_KEY_LOCKINGSCROLLLOCK = 132,
KEYBOARD_KEY_KP_COMMA = 133,
KEYBOARD_KEY_KP_EQUALSAS400 = 134,
KEYBOARD_KEY_INTERNATIONAL1 = 135,
KEYBOARD_KEY_INTERNATIONAL2 = 136,
KEYBOARD_KEY_INTERNATIONAL3 = 137,
KEYBOARD_KEY_INTERNATIONAL4 = 138,
KEYBOARD_KEY_INTERNATIONAL5 = 139,
KEYBOARD_KEY_INTERNATIONAL6 = 140,
KEYBOARD_KEY_INTERNATIONAL7 = 141,
KEYBOARD_KEY_INTERNATIONAL8 = 142,
KEYBOARD_KEY_INTERNATIONAL9 = 143,
KEYBOARD_KEY_LANG1 = 144,
KEYBOARD_KEY_LANG2 = 145,
KEYBOARD_KEY_LANG3 = 146,
KEYBOARD_KEY_LANG4 = 147,
KEYBOARD_KEY_LANG5 = 148,
KEYBOARD_KEY_LANG6 = 149,
KEYBOARD_KEY_LANG7 = 150,
KEYBOARD_KEY_LANG8 = 151,
KEYBOARD_KEY_LANG9 = 152,
KEYBOARD_KEY_ALTERASE = 153,
KEYBOARD_KEY_SYSREQ = 154,
KEYBOARD_KEY_CANCEL = 155,
KEYBOARD_KEY_CLEAR = 156,
KEYBOARD_KEY_PRIOR = 157,
KEYBOARD_KEY_RETURN2 = 158,
KEYBOARD_KEY_SEPARATOR = 159,
KEYBOARD_KEY_OUT = 160,
KEYBOARD_KEY_OPER = 161,
KEYBOARD_KEY_CLEARAGAIN = 162,
KEYBOARD_KEY_CRSEL = 163,
KEYBOARD_KEY_EXSEL = 164,
KEYBOARD_KEY_KP_00 = 176,
KEYBOARD_KEY_KP_000 = 177,
KEYBOARD_KEY_THOUSANDSSEPARATOR = 178,
KEYBOARD_KEY_DECIMALSEPARATOR = 179,
KEYBOARD_KEY_CURRENCYUNIT = 180,
KEYBOARD_KEY_CURRENCYSUBUNIT = 181,
KEYBOARD_KEY_KP_LEFTPAREN = 182,
KEYBOARD_KEY_KP_RIGHTPAREN = 183,
KEYBOARD_KEY_KP_LEFTBRACE = 184,
KEYBOARD_KEY_KP_RIGHTBRACE = 185,
KEYBOARD_KEY_KP_TAB = 186,
KEYBOARD_KEY_KP_BACKSPACE = 187,
KEYBOARD_KEY_KP_A = 188,
KEYBOARD_KEY_KP_B = 189,
KEYBOARD_KEY_KP_C = 190,
KEYBOARD_KEY_KP_D = 191,
KEYBOARD_KEY_KP_E = 192,
KEYBOARD_KEY_KP_F = 193,
KEYBOARD_KEY_KP_XOR = 194,
KEYBOARD_KEY_KP_POWER = 195,
KEYBOARD_KEY_KP_PERCENT = 196,
KEYBOARD_KEY_KP_LESS = 197,
KEYBOARD_KEY_KP_GREATER = 198,
KEYBOARD_KEY_KP_AMPERSAND = 199,
KEYBOARD_KEY_KP_DBLAMPERSAND = 200,
KEYBOARD_KEY_KP_VERTICALBAR = 201,
KEYBOARD_KEY_KP_DBLVERTICALBAR = 202,
KEYBOARD_KEY_KP_COLON = 203,
KEYBOARD_KEY_KP_HASH = 204,
KEYBOARD_KEY_KP_SPACE = 205,
KEYBOARD_KEY_KP_AT = 206,
KEYBOARD_KEY_KP_EXCLAM = 207,
KEYBOARD_KEY_KP_MEMSTORE = 208,
KEYBOARD_KEY_KP_MEMRECALL = 209,
KEYBOARD_KEY_KP_MEMCLEAR = 210,
KEYBOARD_KEY_KP_MEMADD = 211,
KEYBOARD_KEY_KP_MEMSUBTRACT = 212,
KEYBOARD_KEY_KP_MEMMULTIPLY = 213,
KEYBOARD_KEY_KP_MEMDIVIDE = 214,
KEYBOARD_KEY_KP_PLUSMINUS = 215,
KEYBOARD_KEY_KP_CLEAR = 216,
KEYBOARD_KEY_KP_CLEARENTRY = 217,
KEYBOARD_KEY_KP_BINARY = 218,
KEYBOARD_KEY_KP_OCTAL = 219,
KEYBOARD_KEY_KP_DECIMAL = 220,
KEYBOARD_KEY_KP_HEXADECIMAL = 221,
KEYBOARD_KEY_LCTRL = 224,
KEYBOARD_KEY_LSHIFT = 225,
KEYBOARD_KEY_LALT = 226,
KEYBOARD_KEY_LGUI = 227,
KEYBOARD_KEY_RCTRL = 228,
KEYBOARD_KEY_RSHIFT = 229,
KEYBOARD_KEY_RALT = 230,
KEYBOARD_KEY_RGUI = 231
} KeyboardKeyType;
typedef struct Keyboard
{
u8 current[KEYBOARD_KEY_COUNT];
u8 previous[KEYBOARD_KEY_COUNT];
} Keyboard;
void keyboard_update(Keyboard* self);
bool keyboard_press(Keyboard* self, KeyboardKeyType type);
bool keyboard_held(Keyboard* self, KeyboardKeyType type);
bool keyboard_release(Keyboard* self, KeyboardKeyType type);

74
src/engine/mouse.c Normal file
View File

@@ -0,0 +1,74 @@
#include "mouse.h"
void
mouse_update(Mouse* self)
{
s32 state;
s32 x;
s32 y;
memcpy(&self->previous, &self->current, sizeof(bool) * MOUSE_BUTTON_COUNT);
memset(&self->current, '\0', sizeof(bool) * MOUSE_BUTTON_COUNT);
state = SDL_GetMouseState(NULL, NULL);
if ((state & SDL_BUTTON_LMASK) != 0)
self->current[MOUSE_BUTTON_LEFT] = true;
if ((state & SDL_BUTTON_MMASK) != 0)
self->current[MOUSE_BUTTON_MIDDLE] = true;
if ((state & SDL_BUTTON_RMASK) != 0)
self->current[MOUSE_BUTTON_RIGHT] = true;
if ((state & SDL_BUTTON_X1) != 0)
self->current[MOUSE_BUTTON_X1] = true;
if ((state & SDL_BUTTON_X2) != 0)
self->current[MOUSE_BUTTON_X2] = true;
SDL_GetMouseState(&x, &y);
self->position[0] = x;
self->position[1] = y;
}
bool
mouse_press(Mouse* self, MouseButtonType type)
{
return (self->current[type] && !self->previous[type]);
}
bool
mouse_held(Mouse* self, MouseButtonType type)
{
return (self->current[type] && self->previous[type]);
}
bool
mouse_release(Mouse* self, MouseButtonType type)
{
return (!self->current[type] && self->previous[type]);
}
void
mouse_world_position_get(Mouse* self, Renderer* renderer, vec2 position)
{
vec2 mousePosition;
mousePosition[0] = (f32)self->position[0];
mousePosition[1] = (f32)self->position[1];
renderer_world_position_from_window_position(renderer, mousePosition, position);
}
f32
mouse_angle_from_world_position_get(Mouse* self, Renderer* renderer, vec2 position)
{
vec2 mousePosition;
f32 angle;
mouse_world_position_get(self, renderer, mousePosition);
return ATAN(mousePosition[0], position[0], mousePosition[1], position[1]);
}

30
src/engine/mouse.h Normal file
View File

@@ -0,0 +1,30 @@
#pragma once
#include <SDL2/SDL.h>
#include "renderer.h"
#define MOUSE_BUTTON_COUNT (MOUSE_BUTTON_X2 + 1)
typedef enum MouseButtonType
{
MOUSE_BUTTON_NONE,
MOUSE_BUTTON_LEFT,
MOUSE_BUTTON_MIDDLE,
MOUSE_BUTTON_RIGHT,
MOUSE_BUTTON_X1,
MOUSE_BUTTON_X2
} MouseButtonType;
typedef struct Mouse
{
ivec2 position;
bool current[MOUSE_BUTTON_COUNT];
bool previous[MOUSE_BUTTON_COUNT];
} Mouse;
void mouse_update(Mouse* self);
bool mouse_press(Mouse* self, MouseButtonType type);
bool mouse_held(Mouse* self, MouseButtonType type);
bool mouse_release(Mouse* self, MouseButtonType type);
void mouse_world_position_get(Mouse* mouse, Renderer* renderer, vec2 position);
f32 mouse_angle_from_world_position_get(Mouse* self, Renderer* renderer, vec2 position);

62
src/engine/music.c Normal file
View File

@@ -0,0 +1,62 @@
#include "music.h"
bool
music_init(Music* self, const char* path)
{
self->chunk = Mix_LoadMUS(path);
if (!self->chunk)
{
printf(STRING_SDL_MIXER_MUSIC_ERROR, path, Mix_GetError());
return false;
}
printf(STRING_SDL_MIXER_MUSIC_SUCCESS, path);
self->isInit = true;
return true;
}
void
music_free(Music* self)
{
if (self->isInit)
{
Mix_FreeMusic(self->chunk);
self->isInit = false;
}
}
void
music_play(Music* self, bool isLoop)
{
if (isLoop)
Mix_PlayMusic(self->chunk, -1);
else
Mix_PlayMusic(self->chunk, 0);
}
void
music_resume(void)
{
Mix_ResumeMusic();
}
void
music_pause(void)
{
Mix_PauseMusic();
}
void
music_stop(void)
{
Mix_HaltMusic();
}
bool
music_is_playing_check(void)
{
return Mix_PlayingMusic();
}

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

@@ -0,0 +1,22 @@
#pragma once
#include <SDL2/SDL_mixer.h>
#include "../COMMON.h"
#define STRING_SDL_MIXER_MUSIC_SUCCESS "[INFO] Loaded music: %s\n"
#define STRING_SDL_MIXER_MUSIC_ERROR "[ERROR] Unable to load music: %s | %s\n"
typedef struct Music
{
Mix_Music* chunk;
bool isInit;
} Music;
bool music_is_playing_check(void);
void music_free(Music* self);
bool music_init(Music* self, const char* path);
void music_pause(void);
void music_play(Music* self, bool isLoop);
void music_resume(void);
void music_stop(void);

32
src/engine/rbo.c Normal file
View File

@@ -0,0 +1,32 @@
#include "rbo.h"
void
rbo_init(RBO* self)
{
glGenRenderbuffers(1, &self->handle);
}
void
rbo_bind(RBO* self)
{
glBindRenderbuffer(GL_FRAMEBUFFER, self->handle);
}
void
rbo_unbind(void)
{
glBindRenderbuffer(GL_FRAMEBUFFER, 0);
}
void
rbo_storage_set(RBO* self, ivec2 size)
{
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, size[0], size[1]);
}
void
rbo_free(RBO* self)
{
glDeleteRenderbuffers(1, &self->handle);
memset(self, '\0', sizeof(RBO));
}

17
src/engine/rbo.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#include <GL/glew.h>
#include <GL/gl.h>
#include "../COMMON.h"
typedef struct RBO
{
GLuint handle;
} RBO;
void rbo_init(RBO* self);
void rbo_bind(RBO* self);
void rbo_unbind(void);
void rbo_free(RBO* self);
void rbo_storage_set(RBO* self, ivec2 size);

24
src/engine/rectangle.c Normal file
View File

@@ -0,0 +1,24 @@
#include "rectangle.h"
bool
rectangle_collide_intersection(Rectangle* a, Rectangle* b, Rectangle* intersection)
{
return SDL_IntersectFRect(a, b, intersection);
}
bool
rectangle_collide(Rectangle* a, Rectangle* b)
{
return SDL_HasIntersectionF(a, b);
}
bool
rectangle_has_point(Rectangle* self, vec2 point)
{
SDL_FPoint sdlPoint;
sdlPoint.x = point[0];
sdlPoint.y = point[1];
return SDL_PointInFRect(&sdlPoint, self);
}

11
src/engine/rectangle.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#include <SDL2/SDL.h>
#include "../COMMON.h"
typedef SDL_FRect Rectangle;
bool rectangle_collide(Rectangle* a, Rectangle* b);
bool rectangle_collide_intersection(Rectangle* a, Rectangle* b, Rectangle* intersection);
bool rectangle_has_point(Rectangle* self, vec2 point);

163
src/engine/renderer.c Normal file
View File

@@ -0,0 +1,163 @@
#include "renderer.h"
static void _renderer_viewport_window_set(Renderer* self);
void
renderer_buffer_init(Renderer* self, RendererBuffer buffer)
{
ivec2 size;
window_size_get(self->window, size);
fbo_init(&self->fbos[buffer]);
fbo_bind(&self->fbos[buffer]);
texture_init(&self->fboTextures[buffer], size, NULL);
texture_bind(&self->fboTextures[buffer]);
fbo_texture_set(&self->fboTextures[buffer]);
rbo_init(&self->rbos[buffer]);
rbo_bind(&self->rbos[buffer]);
rbo_storage_set(&self->rbos[buffer], size);
fbo_rbo_set(&self->rbos[buffer]);
rbo_unbind();
fbo_unbind();
}
void
renderer_buffer_free(Renderer* self, RendererBuffer buffer)
{
texture_free(&self->fboTextures[buffer]);
rbo_free(&self->rbos[buffer]);
fbo_free(&self->fbos[buffer]);
}
static void
_renderer_viewport_window_set(Renderer* self)
{
ivec4 viewport;
window_ivec4_get(self->window, viewport);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
}
void
renderer_init(Renderer* self, Window* window, CameraType type, ivec2 size)
{
vec2 cameraSize;
memset(self, '\0', sizeof(Renderer));
self->window = window;
self->glContext = SDL_GL_CreateContext(self->window->sdl);
glm_ivec2_copy((s32*)size, self->size);
glew_init();
vao_init(&self->vao);
vbo_init(&self->vbo, GL_ARRAY_BUFFER, true);
vbo_init(&self->ebo, GL_ELEMENT_ARRAY_BUFFER, true);
for (s32 i = 0; i < RENDERER_BUFFER_COUNT; i++)
renderer_buffer_init(self, (RendererBuffer)i);
cameraSize[0] = self->size[0];
cameraSize[1] = self->size[1];
switch (type)
{
case CAMERA_ORTHOGRAPHIC:
camera_orthographic_init(&self->camera, cameraSize);
break;
default:
break;
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
}
void
renderer_free(Renderer* self)
{
for (s32 i = 0; i < RENDERER_BUFFER_COUNT; i++)
renderer_buffer_free(self, (RendererBuffer)i);
vao_free(&self->vao);
vbo_free(&self->vbo);
vbo_free(&self->ebo);
memset(self, '\0', sizeof(Renderer));
SDL_GL_DeleteContext(self->glContext);
}
void
renderer_shader_use(Renderer* self, Shader* shader)
{
shader_use(shader);
}
void
renderer_clear_color_set(Renderer* self, vec4 color)
{
glClearColor(color[0], color[1], color[2], color[3]);
}
void
renderer_clear(Renderer* self)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void
renderer_present(Renderer* self)
{
SDL_GL_SwapWindow(self->window->sdl);
}
void
renderer_update(Renderer* self)
{
_renderer_viewport_window_set(self);
}
void
renderer_buffer_use(Renderer* self, RendererBuffer buffer)
{
fbo_bind(&self->fbos[buffer]);
}
void
renderer_buffer_unbind(void)
{
fbo_unbind();
}
void
renderer_world_position_from_window_position
(
Renderer* self,
vec2 windowPosition,
vec2 rendererPosition
)
{
ivec2 windowSize;
window_size_get(self->window, windowSize);
rendererPosition[0] = (windowPosition[0] / windowSize[0]) * self->size[0];
rendererPosition[1] = (windowPosition[1] / windowSize[1]) * self->size[1];
}

52
src/engine/renderer.h Normal file
View File

@@ -0,0 +1,52 @@
#pragma once
#include "camera.h"
#include "glew.h"
#include "window.h"
#include "shader.h"
#include "vao.h"
#include "fbo.h"
#include "rbo.h"
#include "vbo.h"
#include "vertexattribute.h"
#include "debug.h"
#define RENDERER_BUFFER_COUNT RENDERER_BUFFER_UI + 1
typedef enum RendererBuffer
{
RENDERER_BUFFER_WORLD,
RENDERER_BUFFER_UI
} RendererBuffer;
typedef struct Renderer
{
SDL_GLContext glContext;
Window* window;
Camera camera;
Texture fboTextures[RENDERER_BUFFER_COUNT];
FBO fbos[RENDERER_BUFFER_COUNT];
RBO rbos[RENDERER_BUFFER_COUNT];
VBO vbo;
VBO ebo;
VAO vao;
ivec2 size;
} Renderer;
void renderer_init(Renderer* self, Window* window, CameraType type, ivec2 size);
void renderer_clear_color_set(Renderer* self, vec4 color);
void renderer_clear(Renderer* self);
void renderer_shader_use(Renderer* self, Shader* shader);
void renderer_buffer_use(Renderer* self, RendererBuffer buffer);
void renderer_buffer_init(Renderer* self, RendererBuffer buffer);
void renderer_buffer_free(Renderer* self, RendererBuffer buffer);
void renderer_free(Renderer* self);
void renderer_update(Renderer* self);
void renderer_present(Renderer* self);
void renderer_buffer_unbind(void);
void renderer_world_position_from_window_position
(
Renderer* self,
vec2 windowPosition,
vec2 rendererPosition
);

64
src/engine/sdl.c Normal file
View File

@@ -0,0 +1,64 @@
#include "sdl.h"
/* Initializes SDL. */
void
sdl_init(void)
{
if (SDL_INIT_VIDEO < 0)
{
printf(STRING_SDL2_VIDEO_ERROR);
exit(EXIT_FAILURE);
}
else
printf(STRING_SDL2_VIDEO_INIT);
if (SDL_INIT_TIMER < 0)
{
printf(STRING_SDL2_TIMER_ERROR);
exit(EXIT_FAILURE);
}
else
printf(STRING_SDL2_TIMER_INIT);
if (IMG_Init(IMG_FLAGS) < 0)
{
printf(STRING_SDL_IMAGE_ERROR);
exit(EXIT_FAILURE);
}
else
printf(STRING_SDL_IMAGE_INIT);
if (TTF_Init() < 0)
{
printf(STRING_SDL_TTF_ERROR);
exit(EXIT_FAILURE);
}
else
printf(STRING_SDL_TTF_INIT);
if (Mix_OpenAudio(MIX_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_CHANNELS, MIX_SAMPLE_SIZE) < 0)
{
printf(STRING_SDL_MIXER_ERROR);
exit(EXIT_FAILURE);
}
else
printf(STRING_SDL_MIXER_INIT);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
}
/* Quits SDL. */
void
sdl_quit(void)
{
printf(STRING_SDL2_QUIT);
SDL_Quit();
}

29
src/engine/sdl.h Normal file
View File

@@ -0,0 +1,29 @@
#pragma once
#define SDL_MAIN_HANDLED
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_mixer.h>
#include <SDL2/SDL_ttf.h>
#include "../COMMON.h"
#define STRING_SDL2_VIDEO_ERROR "[ERROR] Unable to initialize SDL2 (Video): %s\n", SDL_GetError()
#define STRING_SDL2_VIDEO_INIT "[INFO] Initialized SDL2 (Video)\n"
#define STRING_SDL2_TIMER_ERROR "[ERROR] Unable to initialize SDL2 (Timer): %s\n", SDL_GetError()
#define STRING_SDL2_TIMER_INIT "[INFO] Initialized SDL2 (Timer)\n"
#define STRING_SDL_IMAGE_ERROR "[ERROR] Unable to initialize SDL_image: %s\n", IMG_GetError()
#define STRING_SDL_IMAGE_INIT "[INFO] Initialized SDL_image\n"
#define STRING_SDL_MIXER_ERROR "[ERROR] Unable to initialize SDL_mixer: %s\n", Mix_GetError()
#define STRING_SDL_MIXER_INIT "[INFO] Initialized SDL_mixer\n"
#define STRING_SDL_TTF_ERROR "[ERROR] Unable to initialize SDL_ttf: %s\n", TTF_GetError()
#define STRING_SDL_TTF_INIT "[INFO] Initialized SDL_ttf\n"
#define STRING_SDL2_QUIT "[INFO] Quitting SDL2\n"
#define MIX_FREQUENCY 44100
#define MIX_SAMPLE_SIZE 2048
#define IMG_FLAGS (IMG_INIT_PNG)
void sdl_init(void);
void sdl_quit(void);

128
src/engine/shader.c Normal file
View File

@@ -0,0 +1,128 @@
#include "shader.h"
static bool _shader_compile(u32 handle);
static bool
_shader_compile(u32 handle)
{
s32 success;
char log[SHADER_LOG_BUFFER_SIZE];
glCompileShader(handle);
glGetShaderiv(handle, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(handle, SHADER_LOG_BUFFER_SIZE, NULL, log);
printf(STRING_SHADER_COMPILE_ERROR, handle, log);
return false;
}
else
printf(STRING_SHADER_COMPILE_SUCCESS, handle);
return true;
}
bool
shader_init(Shader* self, const char* vertex, const char* fragment)
{
GLuint vertexHandle;
GLuint fragmentHandle;
memset(self, '\0', sizeof(struct Shader));
vertexHandle = glCreateShader(GL_VERTEX_SHADER);
fragmentHandle = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertexHandle, 1, &vertex, NULL);
glShaderSource(fragmentHandle, 1, &fragment, NULL);
if (!_shader_compile(vertexHandle) || !_shader_compile(fragmentHandle))
return false;
self->handle = glCreateProgram();
glAttachShader(self->handle, vertexHandle);
glAttachShader(self->handle, fragmentHandle);
glLinkProgram(self->handle);
glDeleteShader(vertexHandle);
glDeleteShader(fragmentHandle);
self->isInit = true;
return true;
}
void
shader_use(Shader* self)
{
glUseProgram(self->handle);
}
void
shader_free(Shader* self)
{
if (self->isInit)
{
glDeleteProgram(self->handle);
self->isInit = false;
}
}
void
shader_uniform_s32_set(Shader* self, const char* name, s32 value)
{
glUniform1i(glGetUniformLocation(self->handle, name), value);
}
void
shader_uniform_u32_set(Shader* self, const char* name, u32 value)
{
glUniform1ui(glGetUniformLocation(self->handle, name), value);
}
void
shader_uniform_bool_set(Shader* self, const char* name, bool value)
{
glUniform1i(glGetUniformLocation(self->handle, name), value);
}
void
shader_uniform_f32_set(Shader* self, const char* name, f32 value)
{
glUniform1f(glGetUniformLocation(self->handle, name), value);
}
void
shader_uniform_vec2_set(Shader* self, const char* name, vec2 value)
{
glUniform2fv(glGetUniformLocation(self->handle, name), 1, value);
}
void
shader_uniform_vec3_set(Shader* self, const char* name, vec3 value)
{
glUniform3fv(glGetUniformLocation(self->handle, name), 1, value);
}
void
shader_uniform_vec4_set(Shader* self, const char* name, vec4 value)
{
glUniform4fv(glGetUniformLocation(self->handle, name), 1, value);
}
void
shader_uniform_mat4_set(Shader* self, const char* name, mat4 value)
{
glUniformMatrix4fv(glGetUniformLocation(self->handle, name), 1, GL_FALSE, (f32*)value);
}
void
shader_uniform_texture_set(Shader* self, const char* name, Texture* texture, s32 index)
{
glActiveTexture(GL_TEXTURE0 + index);
texture_bind(texture);
glUniform1i(glGetUniformLocation(self->handle, name), index);
}

30
src/engine/shader.h Normal file
View File

@@ -0,0 +1,30 @@
#pragma once
#include <GL/glew.h>
#include <GL/gl.h>
#include "texture.h"
#define SHADER_LOG_BUFFER_SIZE 1024
#define STRING_SHADER_COMPILE_SUCCESS "[INFO] Compiled shader: #%i\n"
#define STRING_SHADER_COMPILE_ERROR "[ERROR] Unable to compile shader: #%i, %s\n"
typedef struct Shader
{
GLuint handle;
bool isInit;
} Shader;
bool shader_init(struct Shader* self, const char* vertex, const char* fragment);
void shader_use(struct Shader* self);
void shader_free(struct Shader* self);
void shader_uniform_f32_set(struct Shader* self, const char* name, f32 value);
void shader_uniform_s32_set(struct Shader* self, const char* name, s32 value);
void shader_uniform_u32_set(struct Shader* self, const char* name, u32 value);
void shader_uniform_bool_set(struct Shader* self, const char* name, bool value);
void shader_uniform_mat4_set(struct Shader* self, const char* name, mat4 value);
void shader_uniform_vec2_set(struct Shader* self, const char* name, vec2 value);
void shader_uniform_vec3_set(struct Shader* self, const char* name, vec3 value);
void shader_uniform_vec4_set(struct Shader* self, const char* name, vec4 value);
void shader_uniform_texture_set(struct Shader* self, const char* name, Texture* texture, s32 index);

45
src/engine/sound.c Normal file
View File

@@ -0,0 +1,45 @@
#include "sound.h"
/* Initializes a sound. */
bool
sound_init(Sound* self, const char* path)
{
self->chunk = Mix_LoadWAV(path);
if (!self->chunk)
{
printf(STRING_SDL_MIXER_SOUND_ERROR, path, Mix_GetError());
return false;
}
printf(STRING_SDL_MIXER_SOUND_SUCCESS, path);
self->isInit = true;
return true;
}
/* Frees a sound. */
void
sound_free(Sound* self)
{
if (self->isInit)
{
Mix_FreeChunk(self->chunk);
self->isInit = false;
}
}
/* Plays a sound, specifying a channel. */
void
sound_play(Sound* self, s32 channel)
{
Mix_PlayChannel(-1, self->chunk, 0);
}
/* Stops a channel. */
void
sound_channel_stop(s32 channel)
{
Mix_HaltChannel(channel);
}

21
src/engine/sound.h Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
#include <SDL2/SDL_mixer.h>
#include "../COMMON.h"
#define SOUND_NO_PRIORITY -1
#define STRING_SDL_MIXER_SOUND_SUCCESS "[INFO] Loaded sound: %s\n"
#define STRING_SDL_MIXER_SOUND_ERROR "[ERROR] Unable to load sound: %s | %s\n"
typedef struct Sound
{
Mix_Chunk* chunk;
bool isInit;
} Sound;
bool sound_init(Sound* self, const char* path);
void sound_free(Sound* self);
void sound_play(Sound* self, s32 channel);
void sound_channel_stop(s32 channel);

17
src/engine/surface.c Normal file
View File

@@ -0,0 +1,17 @@
#include "surface.h"
void
surface_rgba_init(SDL_Surface** self, ivec2 size)
{
*self = SDL_CreateRGBSurface
(
0,
size[0],
size[1],
32,
0xFF000000,
0x00FF0000,
0x0000FF00,
0x000000FF
);
}

7
src/engine/surface.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#include <SDL2/SDL.h>
#include "../COMMON.h"
void surface_rgba_init(SDL_Surface** self, ivec2 size);

84
src/engine/texture.c Normal file
View File

@@ -0,0 +1,84 @@
#include "texture.h"
void
texture_surface_init(Texture* self, SDL_Surface* surface)
{
ivec2 size;
size[0] = surface->w;
size[1] = surface->h;
texture_init(self, size, surface->pixels);
}
bool
texture_from_path_init(Texture* self, const char* path)
{
SDL_Surface* surface;
memset(self, '\0', sizeof(Texture));
surface = IMG_Load(path);
if (!surface)
{
printf(STRING_SDL_IMAGE_LOAD_ERROR, path, IMG_GetError());
return false;
}
printf(STRING_SDL_IMAGE_LOAD_SUCCESS, path);
texture_surface_init(self, surface);
SDL_FreeSurface(surface);
return true;
}
void
texture_init(Texture* self, ivec2 size, void* data)
{
glGenTextures(1, &self->handle);
texture_bind(self);
glm_ivec2_copy(size, self->size);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self->size[0], self->size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
texture_parameter_set(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
texture_parameter_set(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
texture_parameter_set(GL_TEXTURE_MIN_FILTER, GL_NEAREST);
texture_parameter_set(GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glGenerateMipmap(GL_TEXTURE_2D);
self->isInit = true;
texture_unbind();
}
void
texture_bind(Texture* self)
{
glBindTexture(GL_TEXTURE_2D, self->handle);
}
void
texture_parameter_set(GLenum pname, GLint parameter)
{
glTexParameteri(GL_TEXTURE_2D, pname, parameter);
}
void
texture_unbind(void)
{
glBindTexture(GL_TEXTURE_2D, 0);
}
void
texture_free(Texture* self)
{
glDeleteTextures(1, &self->handle);
memset(self, '\0', sizeof(Texture));
}

26
src/engine/texture.h Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
#include <GL/glew.h>
#include <GL/gl.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "../COMMON.h"
#define STRING_SDL_IMAGE_LOAD_ERROR "[ERROR] Unable to load image: %s | %s\n"
#define STRING_SDL_IMAGE_LOAD_SUCCESS "[INFO] Loaded image: %s\n"
typedef struct Texture
{
GLuint handle;
ivec2 size;
bool isInit;
} Texture;
bool texture_from_path_init(Texture* self, const char* path);
void texture_init(Texture* self, ivec2 size, void* data);
void texture_surface_init(Texture* self, SDL_Surface* surface);
void texture_parameter_set(GLenum pname, GLint parameter);
void texture_bind(Texture* self);
void texture_unbind(void);
void texture_free(Texture* self);

10
src/engine/tick.c Normal file
View File

@@ -0,0 +1,10 @@
#include "tick.h"
void
tick_update(Tick* self)
{
self->previous = self->current;
self->current = SDL_GetTicks64();
self->delta = self->current - self->previous;
self->cumulative += self->delta;
}

14
src/engine/tick.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include <SDL2/SDL.h>
#include "../COMMON.h"
typedef struct Tick
{
u64 current;
u64 previous;
u64 delta;
u64 cumulative;
} Tick;
void tick_update(Tick* self);

26
src/engine/vao.c Normal file
View File

@@ -0,0 +1,26 @@
#include "vao.h"
void
vao_init(VAO* self)
{
glGenVertexArrays(1, &self->handle);
}
void
vao_bind(VAO* self)
{
glBindVertexArray(self->handle);
}
void
vao_unbind(void)
{
glBindVertexArray(0);
}
void
vao_free(VAO* self)
{
glDeleteVertexArrays(1, &self->handle);
memset(self, '\0', sizeof(VAO));
}

16
src/engine/vao.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
#include <GL/glew.h>
#include <GL/gl.h>
#include "../COMMON.h"
typedef struct VAO
{
GLuint handle;
} VAO;
void vao_init(VAO* self);
void vao_bind(VAO* self);
void vao_unbind(void);
void vao_free(VAO* self);

29
src/engine/vbo.c Normal file
View File

@@ -0,0 +1,29 @@
#include "vbo.h"
void
vbo_init(VBO* self, GLint type, bool isDynamic)
{
self->isDynamic = isDynamic;
self->type = type;
glGenBuffers(1, &self->handle);
}
void
vbo_bind(VBO* self)
{
glBindBuffer(self->type, self->handle);
}
void
vbo_free(VBO* self)
{
glDeleteBuffers(1, &self->handle);
memset(self, '\0', sizeof(VBO));
}
void
vbo_buffer(VBO* self, size_t size, void* data)
{
glBufferData(self->type, size, data, self->isDynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
}

18
src/engine/vbo.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include <GL/glew.h>
#include <GL/gl.h>
#include "../COMMON.h"
typedef struct VBO
{
GLuint handle;
GLint type;
bool isDynamic;
} VBO;
void vbo_buffer(VBO* self, size_t size, void* data);
void vbo_bind(VBO* self);
void vbo_free(VBO* self);
void vbo_init(VBO* self, GLint type, bool isDynamic);

182
src/engine/vector.c Normal file
View File

@@ -0,0 +1,182 @@
#include "vector.h"
static void _vector_realloc(Vector* self);
static void _vector_forward(Vector* self, s32 index);
static void _vector_backward(Vector* self, s32 index);
static void
_vector_realloc(Vector* self)
{
if (self->count == 0)
{
self->data = NULL;
return;
}
self->data = realloc(self->data, vector_size_get(self));
}
static void
_vector_forward(Vector* self, s32 index)
{
s32 length;
length = ((self->count - 1) - index);
for (s32 i = 0; i < length; i++)
{
u8* data;
u8* nextData;
s32 currentIndex;
currentIndex = index + i;
data = (u8*)self->data + (currentIndex * self->itemSize);
nextData = data + self->itemSize;
memcpy((void*)data, (void*)nextData, self->itemSize);
}
}
static void
_vector_backward(Vector* self, s32 index)
{
s32 length;
if (self->count == 0)
return;
length = ((self->count - 1) - index);
for (s32 i = 0; i < length; i++)
{
u8* data;
u8* prevData;
s32 index;
index = (self->count - 1) - i;
data = (u8*)self->data + (index * self->itemSize);
prevData = (u8*)data - self->itemSize;
memcpy((void*)data, (void*)prevData, self->itemSize);
}
}
size_t
vector_size_get(Vector* self)
{
return self->count * self->itemSize;
}
void
vector_init(Vector* self, size_t size)
{
memset(self, '\0', sizeof(Vector));
self->itemSize = size;
_vector_realloc(self);
memset(self->data, '\0', vector_size_get(self));
}
void
vector_free(Vector* self)
{
if (self->data)
free(self->data);
self->count = 0;
}
void*
vector_push(Vector* self, void* data)
{
u8* pointer;
self->count++;
_vector_realloc(self);
pointer = (u8*)self->data + (vector_size_get(self) - self->itemSize);
if (data)
memcpy((void*)pointer, data, self->itemSize);
else
memset((void*)pointer, '\0', self->itemSize);
return pointer;
}
void
vector_pop(Vector* self)
{
self->count--;
_vector_realloc(self);
}
void
vector_clear(Vector* self)
{
self->count = 0;
_vector_realloc(self);
}
void*
vector_insert(Vector* self, void* data, s32 index)
{
u8* pointer;
_vector_backward(self, index);
self->count++;
_vector_realloc(self);
pointer = (u8*)self->data + (index * self->itemSize);
memcpy((void*)pointer, data, self->itemSize);
return pointer;
}
void
vector_remove(Vector* self, s32 index)
{
_vector_forward(self, index);
vector_pop(self);
}
void*
vector_get(Vector* self, s32 index)
{
return (void*)((u8*)self->data + (index * self->itemSize));
}
s32
vector_index_get(Vector* self, void* data)
{
s32 index;
index = ((u8*)data - (u8*)self->data) / self->itemSize;
return index;
}
void
vector_remove_from_data(Vector* self, void* data)
{
vector_remove(self, vector_index_get(self, data));
data = NULL;
}
void
vector_sort(Vector* self, SortCompareFunction function)
{
qsort(self->data, self->count, self->itemSize, function);
}

25
src/engine/vector.h Normal file
View File

@@ -0,0 +1,25 @@
#pragma once
#include "../COMMON.h"
typedef struct Vector
{
u32 count;
u32 limit;
size_t itemSize;
void* data;
} Vector;
s32 vector_index_get(Vector* self, void* data);
size_t vector_size_get(Vector* self);
void vector_free(Vector* self);
void vector_init(Vector* self, size_t size);
void vector_pop(Vector* self);
void vector_remove(Vector* self, s32 index);
void vector_clear(Vector* self);
void vector_remove_from_data(Vector* self, void* data);
void* vector_get(Vector* self, s32 index);
void* vector_insert(Vector* self, void* data, s32 index);
void* vector_push(Vector* self, void* data);
void vector_print(Vector* self);
void vector_sort(Vector* self, SortCompareFunction function);

View File

@@ -0,0 +1,24 @@
#include "vertexattribute.h"
void
vertex_attribute_set(GLuint index, GLint size, GLenum type, GLsizei stride, size_t offset)
{
switch (type)
{
case GL_BYTE:
case GL_UNSIGNED_BYTE:
case GL_SHORT:
case GL_UNSIGNED_SHORT:
case GL_INT:
case GL_UNSIGNED_INT:
case GL_INT_2_10_10_10_REV:
case GL_UNSIGNED_INT_2_10_10_10_REV:
glVertexAttribIPointer(index, size, type, stride, (void*)offset);
break;
default:
glVertexAttribPointer(index, size, type, GL_FALSE, stride, (void*)offset);
break;
}
glEnableVertexAttribArray(index);
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include <GL/glew.h>
#include <GL/gl.h>
#include "../COMMON.h"
void vertex_attribute_set(GLuint index, GLint size, GLenum type, GLsizei stride, size_t offset);

49
src/engine/window.c Normal file
View File

@@ -0,0 +1,49 @@
#include "window.h"
void
window_init(Window* self, char* name, ivec2 size, u32 flags)
{
memset(self, '\0', sizeof(Window));
glm_ivec2_copy(size, self->expectedSize);
self->sdl = SDL_CreateWindow
(
name,
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
size[0],
size[1],
flags
);
SDL_ShowCursor(SDL_DISABLE);
}
void
window_ivec4_get(struct Window* self, ivec4 value)
{
ivec2 size;
window_size_get(self, size);
value[0] = 0;
value[1] = 0;
value[2] = size[0];
value[3] = size[1];
}
void
window_size_get(Window* self, ivec2 size)
{
SDL_GetWindowSize(self->sdl, &size[0], &size[1]);
}
void
window_free(Window* self)
{
SDL_DestroyWindow(self->sdl);
memset(self, '\0', sizeof(Window));
}

17
src/engine/window.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#include <SDL2/SDL.h>
#include "../COMMON.h"
typedef struct Window
{
SDL_Window* sdl;
ivec2 expectedSize;
} Window;
void window_init(Window* self, char* name, ivec2 size, u32 flags);
void window_free(Window* self);
void window_ivec4_get(Window* self, ivec4 size);
void window_size_get(Window* self, ivec2 size);

21
src/game/GAME_COMMON.h Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
#include "state/state.h"
#include "../engine/tick.h"
#include "../engine/sdl.h"
#include "render/buffer.h"
typedef struct Game
{
ECS ecs;
Input input;
Renderer renderer;
Resources resources;
State state;
Tick tick;
Window window;
Postprocessing postprocessing[RENDERER_BUFFER_COUNT];
bool isPaused;
} Game;

62
src/game/ecs/ECS_COMMON.h Normal file
View File

@@ -0,0 +1,62 @@
#pragma once
#include "component/COMPONENT_COMMON.h"
#include "../../engine/vector.h"
#define ECS_FUNCTION_COUNT ECS_FUNCTION_DRAW + 1
typedef enum ECSFunctionType
{
ECS_FUNCTION_ADD,
ECS_FUNCTION_DELETE,
ECS_FUNCTION_TICK,
ECS_FUNCTION_UPDATE,
ECS_FUNCTION_DRAW
} ECSFunctionType;
typedef struct ECS ECS;
typedef struct Input Input;
typedef struct Renderer Renderer;
typedef struct Postprocessing Postprocessing;
typedef struct Resources Resources;
typedef u32 EntityID;
typedef void (*ECSFunction)(void*, ECS*);
typedef struct ECSComponent
{
EntityID id;
bool isDisabled;
bool isFunctionDisabled[ECS_FUNCTION_COUNT];
} ECSComponent;
typedef struct ECSSystem
{
ECSFunction functions[ECS_FUNCTION_COUNT];
} ECSSystem;
typedef struct ECSComponentInfo
{
ECSSystem system;
ECSComponentType type;
size_t size;
} ECSComponentInfo;
typedef struct ECSComponentList
{
ECS* ecs;
ECSSystem system;
ECSComponentType type;
Vector components;
} ECSComponentList;
typedef struct ECS
{
Input* input;
Renderer* renderer;
Resources* resources;
Postprocessing* postprocessing;
ECSComponentList lists[ECS_COMPONENT_COUNT];
EntityID nextID;
} ECS;

View File

@@ -0,0 +1,19 @@
#pragma once
#include "../../../COMMON.h"
#include "../../../engine/debug.h"
#define ECS_COMPONENT_COUNT ECS_COMPONENT_COPY_MOUSE_POSITION + 1
typedef enum ECSComponentType
{
ECS_COMPONENT_GAME_OBJECT,
ECS_COMPONENT_COUNTER,
ECS_COMPONENT_TIMER,
ECS_COMPONENT_TEXTURE_QUAD,
ECS_COMPONENT_TEXT,
ECS_COMPONENT_OUTLINE,
ECS_COMPONENT_ATLAS,
ECS_COMPONENT_PHYSICS,
ECS_COMPONENT_COPY_MOUSE_POSITION
} ECSComponentType;

View File

@@ -0,0 +1,58 @@
#include "component_game_object.h"
void
component_game_object_init
(
ComponentGameObject* self,
ECS* ecs,
Texture* texture,
RendererBuffer buffer,
vec2 size,
vec3 position
)
{
ComponentTextureQuad* textureQuad;
ComponentPhysics* physics;
textureQuad = ecs_component_get(ecs, ECS_COMPONENT_TEXTURE_QUAD, self->component.id);
physics = ecs_component_get(ecs, ECS_COMPONENT_PHYSICS, self->component.id);
component_texture_quad_init
(
textureQuad,
ecs,
texture,
&ecs->resources->shaders[SHADER_TEXTURE_QUAD],
COMPONENT_TEXTURE_QUAD_FLIP_DEFAULT,
ORIGIN_CENTER,
buffer,
COMPONENT_TEXTURE_QUAD_ROTATION_DEFAULT,
size,
(f32*)COMPONENT_TEXTURE_QUAD_SCALE_DEFAULT,
(f32*)COMPONENT_TEXTURE_QUAD_UV_MIN_DEFAULT,
(f32*)COMPONENT_TEXTURE_QUAD_UV_MAX_DEFAULT,
position,
(f32*)COMPONENT_TEXTURE_QUAD_OFFSET_DEFAULT,
(f32*)COMPONENT_TEXTURE_QUAD_COLOR_DEFAULT
);
glm_vec3_copy(position, physics->position);
}
void
component_game_object_add(ComponentGameObject* self, ECS* ecs)
{
ecs_components_add(ecs, COMPONENT_GAME_OBJECT_DEPENDENCIES, COMPONENT_GAME_OBJECT_DEPENDENCY_COUNT, self->component.id);
}
void
component_game_object_tick(ComponentGameObject* self, ECS* ecs)
{
ComponentTextureQuad* textureQuad;
ComponentPhysics* physics;
textureQuad = ecs_component_get(ecs, ECS_COMPONENT_TEXTURE_QUAD, self->component.id);
physics = ecs_component_get(ecs, ECS_COMPONENT_PHYSICS, self->component.id);
glm_vec3_copy(physics->position, textureQuad->position);
}

View File

@@ -0,0 +1,47 @@
#pragma once
#include "../visual/component_texture_quad.h"
#include "../physics/component_physics.h"
typedef struct ComponentGameObject
{
ECSComponent component;
} ComponentGameObject;
void
component_game_object_init
(
ComponentGameObject* self,
ECS* ecs,
Texture* texture,
RendererBuffer buffer,
vec2 size,
vec3 position
);
void component_game_object_add(ComponentGameObject* self, ECS* ecs);
void component_game_object_tick(ComponentGameObject* self, ECS* ecs);
#define COMPONENT_GAME_OBJECT_DEPENDENCY_COUNT 2
static const ECSComponentType COMPONENT_GAME_OBJECT_DEPENDENCIES[COMPONENT_GAME_OBJECT_DEPENDENCY_COUNT] =
{
ECS_COMPONENT_TEXTURE_QUAD,
ECS_COMPONENT_PHYSICS
};
static const ECSComponentInfo COMPONENT_GAME_OBJECT_INFO =
{
.system =
{
.functions =
{
(ECSFunction)component_game_object_add,
NULL,
(ECSFunction)component_game_object_tick,
NULL,
NULL
}
},
.type = ECS_COMPONENT_GAME_OBJECT,
.size = sizeof(ComponentGameObject)
};

View File

@@ -0,0 +1,15 @@
#include "component_copy_mouse_position.h"
void
component_copy_mouse_position_tick(ComponentCopyMousePosition* self, ECS* ecs)
{
ComponentPhysics* physics;
vec2 mousePosition;
physics = ecs_component_get(ecs, ECS_COMPONENT_PHYSICS, self->component.id);
mouse_world_position_get(&ecs->input->mouse, ecs->renderer, mousePosition);
physics->position[0] = mousePosition[0];
physics->position[1] = mousePosition[1];
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include "component_physics.h"
#include "../../../input/input.h"
typedef struct ComponentCopyMousePosition
{
ECSComponent component;
} ComponentCopyMousePosition;
void component_copy_mouse_position_tick(ComponentCopyMousePosition* self, ECS* ecs);
static const ECSComponentInfo COMPONENT_COPY_MOUSE_POSITION_INFO =
{
.system =
{
.functions =
{
NULL,
NULL,
(ECSFunction)component_copy_mouse_position_tick,
NULL,
NULL
}
},
.type = ECS_COMPONENT_COPY_MOUSE_POSITION,
.size = sizeof(ComponentCopyMousePosition)
};

View File

@@ -0,0 +1,10 @@
#include "component_physics.h"
void
component_physics_tick(ComponentPhysics* self, ECS* ecs)
{
glm_vec3_add(self->velocity, self->position, self->position);
if (keyboard_held(&ecs->input->keyboard, KEYBOARD_KEY_D))
self->position[0] += 1.0f;
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include "../../ecs_entity.h"
#include "../../../input/input.h"
typedef struct ComponentPhysics
{
ECSComponent component;
vec3 position;
vec3 velocity;
} ComponentPhysics;
void component_physics_tick(ComponentPhysics* self, ECS* ecs);
static const ECSComponentInfo COMPONENT_PHYSICS_INFO =
{
.system =
{
.functions =
{
NULL,
NULL,
(ECSFunction)component_physics_tick,
NULL,
NULL
}
},
.type = ECS_COMPONENT_PHYSICS,
.size = sizeof(ComponentPhysics)
};

View File

@@ -0,0 +1,29 @@
#include "component_counter.h"
void
component_counter_init(ComponentCounter* self, ECS* ecs, s32 value, s32 max)
{
self->value = value;
self->min = self->value;
self->max = self->max;
}
void
component_counter_add(ComponentCounter* self, ECS* ecs)
{
self->value = 0;
self->min = 0;
self->max = COMPONENT_COUNTER_MAX;
}
void
component_counter_tick(ComponentCounter* self, ECS* ecs)
{
if (self->value >= self->max)
{
self->value = self->min;
return;
}
self->value++;
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include "../../ecs_entity.h"
#define COMPONENT_COUNTER_MAX INT_MAX
typedef struct ComponentCounter
{
ECSComponent component;
s32 value;
s32 max;
s32 min;
} ComponentCounter;
void component_counter_init(ComponentCounter* self, ECS* ecs, s32 value, s32 max);
void component_counter_add(ComponentCounter* self, ECS* ecs);
void component_counter_tick(ComponentCounter* self, ECS* ecs);
static const ECSComponentInfo COMPONENT_COUNTER_INFO =
{
.system =
{
.functions =
{
(ECSFunction)component_counter_add,
NULL,
(ECSFunction)component_counter_tick,
NULL,
NULL,
}
},
.type = ECS_COMPONENT_COUNTER,
.size = sizeof(ComponentCounter)
};

View File

@@ -0,0 +1,23 @@
#include "component_timer.h"
void
component_timer_init(ComponentTimer* self, ECS* ecs, s32 value)
{
self->value = value;
}
void
component_timer_tick(ComponentTimer* self, ECS* ecs)
{
if (self->isFinished)
return;
if (self->value <= 0)
{
self->isFinished = true;
self->value = 0;
return;
}
self->value--;
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "../../ecs_entity.h"
typedef struct ComponentTimer
{
ECSComponent component;
s32 value;
bool isFinished;
} ComponentTimer;
void component_timer_init(ComponentTimer* self, ECS* ecs, s32 value);
void component_timer_tick(ComponentTimer* self, ECS* ecs);
static const ECSComponentInfo COMPONENT_TIMER_INFO =
{
.system =
{
.functions =
{
NULL,
NULL,
(ECSFunction)component_timer_tick,
NULL,
NULL,
}
},
.type = ECS_COMPONENT_TIMER,
.size = sizeof(ComponentTimer)
};

View File

@@ -0,0 +1,35 @@
#include "component_atlas.h"
void
component_atlas_uv_get(ComponentAtlas* self, Texture* texture, vec2 uvMin, vec2 uvMax)
{
vec2 position;
s32 col;
s32 row;
position[0] = (self->index % self->size[1]) * self->frameSize[1];
position[1] = (s32)((f32)self->index / self->size[1]) * self->frameSize[1];
uvMin[0] = (f32)position[0] / texture->size[0];
uvMin[1] = (f32)position[1] / texture->size[1];
uvMax[0] = (f32)(position[0] + self->frameSize[0]) / texture->size[0];
uvMax[1] = (f32)(position[1] + self->frameSize[1]) / texture->size[1];
}
void
component_atlas_init(ComponentAtlas* self, ECS* ecs, ivec2 frameSize, ivec2 size, u32 index)
{
glm_ivec2_copy(frameSize, self->frameSize);
glm_ivec2_copy(size, self->size);
self->index = index;
}
void
component_atlas_tick(ComponentAtlas* self, ECS* ecs)
{
ComponentTextureQuad* textureQuad;
textureQuad = ecs_component_get(ecs, ECS_COMPONENT_TEXTURE_QUAD, self->component.id);
component_atlas_uv_get(self, textureQuad->texture, textureQuad->uvMin, textureQuad->uvMax);
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include "component_texture_quad.h"
typedef struct ComponentAtlas
{
ECSComponent component;
ivec2 frameSize;
ivec2 size;
u32 index;
} ComponentAtlas;
void component_atlas_init(ComponentAtlas* self, ECS* ecs, ivec2 frameSize, ivec2 size, u32 index);
void component_atlas_tick(ComponentAtlas* self, ECS* ecs);
void component_atlas_uv_get(ComponentAtlas* self, Texture* texture, vec2 uvMin, vec2 uvMax);
static const ECSComponentInfo COMPONENT_ATLAS_INFO =
{
.system =
{
.functions =
{
NULL,
NULL,
(ECSFunction)component_atlas_tick,
NULL,
NULL,
}
},
.type = ECS_COMPONENT_ATLAS,
.size = sizeof(ComponentAtlas)
};

View File

@@ -0,0 +1,61 @@
#include "component_outline.h"
static void _component_outline_texture_quad_set(ComponentOutline* self, ECS* ecs);
static void
_component_outline_texture_quad_set(ComponentOutline* self, ECS* ecs)
{
ComponentTextureQuad* textureQuadOutline;
ComponentTextureQuad* textureQuad;
textureQuad = ecs_component_get(ecs, ECS_COMPONENT_TEXTURE_QUAD, self->component.id);
if (!self->isSpriteInit)
{
self->spriteID = entity_sprite_add
(
ecs,
textureQuad->texture,
textureQuad->buffer,
textureQuad->size,
textureQuad->position
);
self->isSpriteInit = true;
}
textureQuadOutline = ecs_component_get(ecs, ECS_COMPONENT_TEXTURE_QUAD, self->spriteID);
memcpy(textureQuadOutline, textureQuad, sizeof(ComponentTextureQuad));
textureQuadOutline->component.id = self->spriteID;
textureQuadOutline->position[2] += COMPONENT_OUTLINE_Z_OFFSET;
glm_vec4_copy(self->color, textureQuadOutline->color);
glm_vec2_adds(textureQuadOutline->size, self->size, textureQuadOutline->size);
textureQuadOutline->shader = &ecs->resources->shaders[SHADER_COLORED_TEXTURE_QUAD];
}
void
component_outline_init(ComponentOutline* self, ECS* ecs, vec4 color, f32 size)
{
glm_vec4_copy(color, self->color);
self->size = size;
}
void
component_outline_add(ComponentOutline* self, ECS* ecs)
{
component_outline_init(self, ecs, (f32*)COMPONENT_OUTLINE_COLOR, COMPONENT_OUTLINE_SIZE);
}
void
component_outline_delete(ComponentOutline* self, ECS* ecs)
{
ecs_entity_delete(ecs, self->spriteID);
}
void
component_outline_tick(ComponentOutline* self, ECS* ecs)
{
_component_outline_texture_quad_set(self, ecs);
}

View File

@@ -0,0 +1,40 @@
#pragma once
#include "../../entity/visual/entity_sprite.h"
#include "component_texture_quad.h"
#define COMPONENT_OUTLINE_SIZE 8
#define COMPONENT_OUTLINE_Z_OFFSET 0.001
static const vec4 COMPONENT_OUTLINE_COLOR = {1.0f, 1.0f, 1.0f, 1.0f};
typedef struct ComponentOutline
{
ECSComponent component;
vec4 color;
f32 size;
EntityID spriteID;
bool isSpriteInit;
} ComponentOutline;
void component_outline_init(ComponentOutline* self, ECS* ecs, vec4 color, f32 size);
void component_outline_tick(ComponentOutline* self, ECS* ecs);
void component_outline_add(ComponentOutline* self, ECS* ecs);
static const ECSComponentInfo COMPONENT_OUTLINE_INFO =
{
.system =
{
.functions =
{
(ECSFunction)component_outline_add,
NULL,
(ECSFunction)component_outline_tick,
NULL,
NULL
}
},
.type = ECS_COMPONENT_OUTLINE,
.size = sizeof(ComponentOutline)
};

View File

@@ -0,0 +1,225 @@
#include "component_text.h"
void
component_text_glyph_size_get(ComponentText* self, Texture* texture, vec2 size)
{
size[0] = texture->size[0] * self->scale[0];
size[1] = texture->size[1] * self->scale[1];
}
void
component_text_glyph_draw(ComponentText* self, ECS* ecs, Texture* texture, vec3 position)
{
mat4 model;
vec2 size;
component_text_glyph_size_get(self, texture, size);
glm_mat4_identity(model);
glm_translate(model, position);
texture_quad_draw
(
texture,
ecs->renderer,
self->shader,
(f32*)TEXTURE_QUAD_UV_MIN_DEFAULT,
(f32*)TEXTURE_QUAD_UV_MAX_DEFAULT,
model,
size,
self->color,
FLIP_NONE
);
}
void
component_text_rectangle_get(ComponentText* self, Rectangle* rectangle)
{
char glyph;
char nextGlyph;
f32 lineW;
f32 offsetX;
f32 prevY;
GlyphMetrics glyphMetrics;
vec2 origin;
vec2 size;
f32 lineSkip;
f32 kerning;
f32 advance;
lineSkip = font_line_skip_get(self->font) * self->scale[1];
font_glyph_metrics_init(self->font, &glyphMetrics, self->string[0]);
lineW = 0.0f;
size[0] = 0.0f;
size[1] = (f32)glyphMetrics.maxY - glyphMetrics.minY;
for (s32 i = 0; i < (s32)self->length; i++)
{
glyph = self->string[i];
if
(
glyph == '\n' ||
(glyph == ' ' && (lineW > self->wrap) && self->wrap != -1)
)
{
size[1] += lineSkip;
lineW = 0.0f;
if (glyph == '\n')
continue;
}
if (i < (s32)self->length)
{
nextGlyph = self->string[i + 1];
kerning = (f32)font_glyph_kerning_get(self->font, glyph, nextGlyph);
}
else
kerning = 0.0;
font_glyph_metrics_init(self->font, &glyphMetrics, glyph);
advance = glyphMetrics.advance;
offsetX = advance + kerning;
offsetX *= self->scale[0];
lineW += offsetX;
if (lineW > size[0])
size[0] = lineW;
}
rectangle->w = size[0];
rectangle->h = size[1];
rectangle->x = self->position[0] + self->offset[0];
rectangle->y = self->position[1] + self->offset[1];
}
void
component_text_string_set(ComponentText* self, const char* string, u32 length)
{
if (length > COMPONENT_TEXT_STRING_MAX)
return;
self->length = length;
memset(self->string, '\0', sizeof(char) * COMPONENT_TEXT_STRING_MAX);
memcpy(self->string, string, sizeof(char) * self->length);
}
void
component_text_add(ComponentText* self, ECS* ecs)
{
glm_vec4_copy(COMPONENT_TEXT_COLOR_DEFAULT, self->color);
glm_vec2_copy((f32*)COMPONENT_TEXT_SCALE_DEFAULT, self->scale);
}
void
component_text_draw(ComponentText* self, ECS* ecs)
{
char glyph;
char nextGlyph;
f32 advance;
f32 lineW;
f32 offsetX;
f32 kerning;
GlyphMetrics glyphMetrics;
Rectangle rectangle;
vec2 origin;
vec3 position;
f32 lineSkip;
f32 lineBegin;
component_text_rectangle_get(self, &rectangle);
lineSkip = font_line_skip_get(self->font) * self->scale[1];
glm_vec3_zero(position);
position[0] = rectangle.x;
position[1] = rectangle.y;
position[0] += self->offset[0];
position[1] += self->offset[1];
position[2] = self->position[2] + self->offset[2];
offsetX = 0.0f;
lineW = 0.0f;
lineBegin = position[0];
for (s32 i = 0; i < (s32)self->length; i++)
{
glyph = self->string[i];
if
(
glyph == '\n' ||
(glyph == ' ' && (lineW > self->wrap) && self->wrap != -1)
)
{
position[0] = lineBegin;
position[1] += lineSkip;
lineW = 0.0f;
if (glyph == '\n')
continue;
}
if (i < (s32)self->length)
{
nextGlyph = self->string[i + 1];
kerning = (f32)font_glyph_kerning_get(self->font, glyph, nextGlyph);
}
else
kerning = 0.0;
font_glyph_metrics_init(self->font, &glyphMetrics, glyph);
component_text_glyph_draw(self, ecs, &self->font->glyphTextures[(s32)glyph], position);
advance = glyphMetrics.advance;
offsetX = advance + kerning;
offsetX *= self->scale[0];
position[0] += offsetX;
lineW += offsetX;
}
}
void
component_text_init
(
ComponentText* self,
ECS* ecs,
Font* font,
Shader* shader,
RendererBuffer buffer,
const char* string,
const vec2 scale,
const vec3 position,
const vec3 offset,
const vec4 color,
u32 length,
s32 wrap
)
{
self->font = font;
self->wrap = wrap;
self->shader = shader;
self->buffer = buffer;
glm_vec2_copy((f32*)scale, self->scale);
glm_vec3_copy((f32*)position, self->position);
glm_vec3_copy((f32*)offset, self->offset);
glm_vec4_copy((f32*)color, self->color);
component_text_string_set(self, string, length);
}

View File

@@ -0,0 +1,72 @@
#pragma once
#include "../../ecs_entity.h"
#include "../../../../engine/rectangle.h"
#include "../../../../engine/font.h"
#include "../../../render/texture_quad.h"
#include "../../../resource/resource_shader.h"
#define COMPONENT_TEXT_LIMIT 1024
#define COMPONENT_TEXT_STRING_MAX 1024
#define COMPONENT_TEXT_COLOR_DEFAULT (f32*)OPAQUE
static const vec2 COMPONENT_TEXT_SCALE_DEFAULT = {1.0f, 1.0f};
static const vec3 COMPONENT_TEXT_OFFSET_DEFAULT = {0.0f, 0.0f, 0.0f};
typedef struct ComponentText
{
ECSComponent component;
Shader* shader;
RendererBuffer buffer;
vec3 position;
vec4 color;
vec2 scale;
vec3 offset;
Font* font;
char string[COMPONENT_TEXT_STRING_MAX];
u32 length;
s32 wrap;
} ComponentText;
void component_text_glyph_size_get(ComponentText* self, Texture* texture, vec2 size);
void component_text_glyph_draw(ComponentText* self, ECS* ecs, Texture* texture, vec3 position);
void component_text_rectangle_get(ComponentText* self, Rectangle* rectangle);
void component_text_string_set(ComponentText* self, const char* string, u32 length);
void component_text_add(ComponentText* self, ECS* ecs);
void component_text_draw(ComponentText* self, ECS* ecs);
void
component_text_init
(
ComponentText* self,
ECS* ecs,
Font* font,
Shader* shader,
RendererBuffer buffer,
const char* string,
const vec2 scale,
const vec3 position,
const vec3 offset,
const vec4 color,
u32 length,
s32 wrap
);
static const ECSComponentInfo COMPONENT_TEXT_INFO =
{
.system =
{
.functions =
{
(ECSFunction)component_text_add,
NULL,
NULL,
NULL,
(ECSFunction)component_text_draw
}
},
.type = ECS_COMPONENT_TEXT,
.size = sizeof(ComponentText)
};

View File

@@ -0,0 +1,166 @@
#include "component_texture_quad.h"
void
component_texture_quad_size_get(ComponentTextureQuad* self, vec2 size)
{
glm_vec2_copy(self->size, size);
glm_vec2_mul(self->size, self->scale, self->size);
}
void
component_texture_quad_position_get(ComponentTextureQuad* self, vec3 position)
{
vec2 size;
glm_vec3_copy(self->position, position);
glm_vec3_add(self->position, self->offset, position);
switch (self->origin)
{
case ORIGIN_CENTER:
component_texture_quad_size_get(self, size);
position[0] -= size[0] / 2;
position[1] -= size[1] / 2;
case ORIGIN_TOP_LEFT:
default:
break;
}
}
void
component_texture_quad_origin_point_get(ComponentTextureQuad* self, vec3 originPoint)
{
vec2 size;
glm_vec3_zero(originPoint);
switch (self->origin)
{
case ORIGIN_CENTER:
component_texture_quad_size_get(self, size);
originPoint[0] = size[0] / 2;
originPoint[1] = size[1] / 2;
case ORIGIN_TOP_LEFT:
default:
break;
}
}
void
component_texture_quad_model_get(ComponentTextureQuad* self, mat4 model)
{
vec3 position;
vec3 originPoint;
component_texture_quad_position_get(self, position);
component_texture_quad_origin_point_get(self, originPoint);
glm_mat4_identity(model);
glm_translate(model, position);
glm_rotate_at(model, originPoint, self->rotation, (f32*)COMPONENT_TEXTURE_QUAD_ROTATION_AXIS);
}
void
component_texture_quad_rectangle_get(ComponentTextureQuad* self, Rectangle* rectangle)
{
vec2 size;
vec2 difference;
component_texture_quad_size_get(self, size);
rectangle->x = (self->position[0] - (size[0] / 2)) + self->offset[0];
rectangle->y = (self->position[1] - (size[1] / 2)) + self->offset[1];
rectangle->w = size[0];
rectangle->h = size[1];
}
s32
component_texture_quad_sort(ComponentTextureQuad* a, ComponentTextureQuad* b)
{
return a->position[2] > b->position[2] ? -1 : 1;
}
void
component_texture_quad_init
(
ComponentTextureQuad* self,
ECS* ecs,
Texture* texture,
Shader* shader,
Flip flip,
Origin origin,
RendererBuffer buffer,
f32 rotation,
vec2 size,
vec2 scale,
vec2 uvMin,
vec2 uvMax,
vec3 offset,
vec3 position,
vec4 color
)
{
self->texture = texture;
self->shader = shader;
self->flip = flip;
self->origin = origin;
self->buffer = buffer;
self->rotation = rotation;
glm_vec2_copy(size, self->size);
glm_vec2_copy(scale, self->scale);
glm_vec2_copy(uvMin, self->uvMin);
glm_vec2_copy(uvMax, self->uvMax);
glm_vec3_copy(offset, self->offset);
glm_vec3_copy(position, self->position);
glm_vec4_copy(color, self->color);
}
void
component_texture_quad_add(ComponentTextureQuad* self, ECS* ecs)
{
component_texture_quad_init
(
self,
ecs,
&ecs->resources->textures[COMPONENT_TEXTURE_QUAD_TEXTURE_DEFAULT],
&ecs->resources->shaders[COMPONENT_TEXTURE_QUAD_SHADER_DEFAULT],
COMPONENT_TEXTURE_QUAD_FLIP_DEFAULT,
COMPONENT_TEXTURE_QUAD_ORIGIN_DEFAULT,
COMPONENT_TEXTURE_QUAD_BUFFER_DEFAULT,
COMPONENT_TEXTURE_QUAD_ROTATION_DEFAULT,
(f32*)COMPONENT_TEXTURE_QUAD_SIZE_DEFAULT,
(f32*)COMPONENT_TEXTURE_QUAD_SCALE_DEFAULT,
(f32*)COMPONENT_TEXTURE_QUAD_UV_MIN_DEFAULT,
(f32*)COMPONENT_TEXTURE_QUAD_UV_MAX_DEFAULT,
(f32*)COMPONENT_TEXTURE_QUAD_OFFSET_DEFAULT,
(f32*)COMPONENT_TEXTURE_QUAD_POSITION_DEFAULT,
(f32*)COMPONENT_TEXTURE_QUAD_COLOR_DEFAULT
);
}
void
component_texture_quad_draw(ComponentTextureQuad* self, ECS* ecs)
{
mat4 model;
vec2 size;
component_texture_quad_model_get(self, model);
component_texture_quad_size_get(self, size);
renderer_buffer_use(ecs->renderer, self->buffer);
texture_quad_draw
(
self->texture,
ecs->renderer,
self->shader,
self->uvMin,
(f32*)COMPONENT_TEXTURE_QUAD_UV_MAX_DEFAULT,
model,
size,
self->color,
self->flip
);
renderer_buffer_unbind();
}

View File

@@ -0,0 +1,85 @@
#pragma once
#include "../../ecs_entity.h"
#include "../../../../engine/rectangle.h"
#include "../../../render/texture_quad.h"
#include "../../../resource/resource_shader.h"
typedef struct ComponentTextureQuad
{
ECSComponent component;
Texture* texture;
Shader* shader;
Flip flip;
Origin origin;
RendererBuffer buffer;
f32 rotation;
vec2 scale;
vec2 size;
vec2 uvMax;
vec2 uvMin;
vec3 offset;
vec3 position;
vec4 color;
} ComponentTextureQuad;
void component_texture_quad_init
(
ComponentTextureQuad* self,
ECS* ecs,
Texture* texture,
Shader* shader,
Flip flip,
Origin origin,
RendererBuffer buffer,
f32 rotation,
vec2 size,
vec2 scale,
vec2 uvMin,
vec2 uvMax,
vec3 position,
vec3 offset,
vec4 color
);
void component_texture_quad_size_get(ComponentTextureQuad* self, vec2 size);
void component_texture_quad_position_get(ComponentTextureQuad* self, vec3 position);
void component_texture_quad_origin_point_get(ComponentTextureQuad* self, vec3 originPoint);
void component_texture_quad_model_get(ComponentTextureQuad* self, mat4 model);
void component_texture_quad_rectangle_get(ComponentTextureQuad* self, Rectangle* rectangle);
s32 component_texture_quad_sort(ComponentTextureQuad* a, ComponentTextureQuad* b);
void component_texture_quad_draw(ComponentTextureQuad* self, ECS* ecs);
static const ECSComponentInfo COMPONENT_TEXTURE_QUAD_INFO =
{
.system =
{
.functions =
{
NULL,
NULL,
NULL,
NULL,
(ECSFunction)component_texture_quad_draw
}
},
.type = ECS_COMPONENT_TEXTURE_QUAD,
.size = sizeof(ComponentTextureQuad)
};
#define COMPONENT_TEXTURE_QUAD_UV_MIN_DEFAULT TEXTURE_QUAD_UV_MIN_DEFAULT
#define COMPONENT_TEXTURE_QUAD_UV_MAX_DEFAULT TEXTURE_QUAD_UV_MAX_DEFAULT
#define COMPONENT_TEXTURE_QUAD_COLOR_DEFAULT TEXTURE_QUAD_COLOR_DEFAULT
#define COMPONENT_TEXTURE_QUAD_FLIP_DEFAULT TEXTURE_QUAD_FLIP_DEFAULT
#define COMPONENT_TEXTURE_QUAD_ORIGIN_DEFAULT TEXTURE_QUAD_ORIGIN_DEFAULT
static const vec3 COMPONENT_TEXTURE_QUAD_ROTATION_AXIS = {0.0f, 0.0f, 1.0f};
static const TextureType COMPONENT_TEXTURE_QUAD_TEXTURE_DEFAULT = TEXTURE_TEST;
static const ShaderType COMPONENT_TEXTURE_QUAD_SHADER_DEFAULT = SHADER_TEXTURE_QUAD;
static const RendererBuffer COMPONENT_TEXTURE_QUAD_BUFFER_DEFAULT = RENDERER_BUFFER_WORLD;
static const f32 COMPONENT_TEXTURE_QUAD_ROTATION_DEFAULT = 0.0f;
static const vec2 COMPONENT_TEXTURE_QUAD_SIZE_DEFAULT = {32.0f, 32.0f};
static const vec2 COMPONENT_TEXTURE_QUAD_SCALE_DEFAULT = {1.0f, 1.0f};
static const vec3 COMPONENT_TEXTURE_QUAD_OFFSET_DEFAULT = {0.0f, 0.0f, 0.0f};
static const vec3 COMPONENT_TEXTURE_QUAD_POSITION_DEFAULT = {0.0f, 0.0f, 0.0f};

66
src/game/ecs/ecs.c Normal file
View File

@@ -0,0 +1,66 @@
#include "ecs.h"
static void _ecs_function(ECS* self, ECSFunctionType type);
static void
_ecs_function(ECS* self, ECSFunctionType type)
{
for (s32 i = 0; i < ECS_COMPONENT_COUNT; i++)
{
ECSComponentList* list;
list = &self->lists[i];
ecs_component_list_function(list, type);
}
}
void
ecs_tick(ECS* self)
{
_ecs_function(self, ECS_FUNCTION_TICK);
}
void
ecs_update(ECS* self)
{
_ecs_function(self, ECS_FUNCTION_UPDATE);
}
void
ecs_draw(ECS* self)
{
vector_sort(&self->lists[ECS_COMPONENT_TEXTURE_QUAD].components, (SortCompareFunction)component_texture_quad_sort);
_ecs_function(self, ECS_FUNCTION_DRAW);
}
void
ecs_init(ECS* self, Renderer* renderer, Input* input, Resources* resources, Postprocessing* postprocessing)
{
self->renderer = renderer;
self->input = input;
self->resources = resources;
self->postprocessing = postprocessing;
for (s32 i = 0 ; i < ECS_COMPONENT_COUNT; i++)
ecs_component_list_init(&self->lists[i], self, ECS_COMPONENT_INFO[i]);
}
void
ecs_clear(ECS* self)
{
for (s32 i = 0 ; i < ECS_COMPONENT_COUNT; i++)
ecs_component_list_clear(&self->lists[i]);
self->nextID = 0;
}
void
ecs_free(ECS* self)
{
for (s32 i = 0 ; i < ECS_COMPONENT_COUNT; i++)
ecs_component_list_free(&self->lists[i]);
memset(self, '\0', sizeof(ECS));
}

37
src/game/ecs/ecs.h Normal file
View File

@@ -0,0 +1,37 @@
#pragma once
#include "component/game/component_game_object.h"
#include "component/physics/component_copy_mouse_position.h"
#include "component/physics/component_physics.h"
#include "component/utility/component_counter.h"
#include "component/utility/component_timer.h"
#include "component/visual/component_atlas.h"
#include "component/visual/component_outline.h"
#include "component/visual/component_texture_quad.h"
#include "component/visual/component_text.h"
#include "../input/input.h"
#include "../../engine/renderer.h"
#include "../resource/resource_font.h"
#include "../resource/resource_music.h"
#include "../resource/resource_sound.h"
static const struct ECSComponentInfo ECS_COMPONENT_INFO[ECS_COMPONENT_COUNT] =
{
COMPONENT_GAME_OBJECT_INFO,
COMPONENT_COUNTER_INFO,
COMPONENT_TIMER_INFO,
COMPONENT_TEXTURE_QUAD_INFO,
COMPONENT_TEXT_INFO,
COMPONENT_OUTLINE_INFO,
COMPONENT_ATLAS_INFO,
COMPONENT_PHYSICS_INFO,
COMPONENT_COPY_MOUSE_POSITION_INFO
};
void ecs_tick(ECS* self);
void ecs_update(ECS* self);
void ecs_draw(ECS* self);
void ecs_init(ECS* self, Renderer* renderer, Input* input, Resources* resources, Postprocessing* postprocessing);
void ecs_clear(ECS* self);
void ecs_free(ECS* self);

View File

@@ -0,0 +1,76 @@
#include "ecs_component.h"
void*
ecs_component_get(ECS* self, ECSComponentType type, EntityID id)
{
return ecs_component_list_get(&self->lists[type], id);
}
void*
ecs_component_from_index_get(ECS* self, ECSComponentType type, u32 index)
{
return vector_get(&self->lists[type].components, index);
}
void*
ecs_component_add(ECS* self, ECSComponentType type, EntityID id)
{
void* component;
ECSFunction add;
component = ecs_component_get(self, type, id);
if (component)
return component;
component = vector_push(&self->lists[type].components, NULL);
memcpy(component, (void*)&id, sizeof(EntityID));
add = self->lists[type].system.functions[ECS_FUNCTION_ADD];
if (add)
add(component, self);
return component;
}
void
ecs_component_delete(ECS* self, ECSComponentType type, EntityID id)
{
for (s32 i = 0; i < (s32)self->lists[type].components.count; i++)
{
EntityID checkID;
void* component;
component = vector_get(&self->lists[type].components, i);
memcpy(&checkID, component, sizeof(EntityID));
if (checkID == id)
{
ECSFunction delete;
delete = self->lists[type].system.functions[ECS_FUNCTION_DELETE];
if (delete)
delete(component, self);
vector_remove(&self->lists[type].components, i);
}
}
}
void
ecs_components_add(ECS* self, const ECSComponentType* types, u32 count, EntityID id)
{
for (s32 i = 0; i < (s32)count; i++)
ecs_component_add(self, types[i], id);
}
void
ecs_components_delete(ECS* self, const ECSComponentType* types, u32 count, EntityID id)
{
for (s32 i = 0; i < (s32)count; i++)
ecs_component_delete(self, types[i], id);
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "ecs_component_list.h"
void ecs_component_delete(ECS* self, ECSComponentType type, EntityID id);
void* ecs_component_add(ECS* self, ECSComponentType type, EntityID id);
void* ecs_component_get(ECS* self, ECSComponentType type, EntityID id);
void* ecs_component_from_index_get(ECS* self, ECSComponentType type, u32 index);
void ecs_components_add(ECS* self, const ECSComponentType* types, u32 count, EntityID id);
void ecs_components_delete(ECS* self, const ECSComponentType* types, u32 count, EntityID id);

View File

@@ -0,0 +1,73 @@
#include "ecs_component_list.h"
void
ecs_component_list_init(ECSComponentList* self, ECS* ecs, ECSComponentInfo info)
{
self->ecs = ecs;
self->type = info.type;
self->system = info.system;
vector_init(&self->components, info.size);
}
void
ecs_component_list_function(ECSComponentList* self, ECSFunctionType type)
{
ECSFunction function;
function = self->system.functions[type];
if (!function)
return;
for (s32 i = 0; i < (s32)self->components.count; i++)
{
void* component;
ECSComponent ecsComponent;
component = vector_get(&self->components, i);
memcpy(&ecsComponent, component, sizeof(ECSComponent));
if
(
ecsComponent.isDisabled ||
ecsComponent.isFunctionDisabled[type]
)
continue;
function(component, self->ecs);
}
}
void*
ecs_component_list_get(ECSComponentList* self, EntityID id)
{
for (s32 i = 0; i < (s32)self->components.count; i++)
{
u32 checkID;
void* component;
component = vector_get(&self->components, i);
memcpy(&checkID, component, sizeof(u32));
if (checkID == id)
return component;
}
return NULL;
}
void
ecs_component_list_clear(ECSComponentList* self)
{
vector_clear(&self->components);
}
void
ecs_component_list_free(ECSComponentList* self)
{
vector_free(&self->components);
memset(self, '\0', sizeof(ECSComponentList));
}

View File

@@ -0,0 +1,9 @@
#pragma once
#include "ECS_COMMON.h"
void* ecs_component_list_get(ECSComponentList* self, EntityID id);
void ecs_component_list_init(ECSComponentList* self, ECS* ecs, ECSComponentInfo info);
void ecs_component_list_function(ECSComponentList* self, ECSFunctionType type);
void ecs_component_list_clear(ECSComponentList* self);
void ecs_component_list_free(ECSComponentList* self);

20
src/game/ecs/ecs_entity.c Normal file
View File

@@ -0,0 +1,20 @@
#include "ecs_entity.h"
EntityID
ecs_entity_add(ECS* self)
{
EntityID id;
id = self->nextID;
self->nextID++;
return id;
}
void
ecs_entity_delete(ECS* self, EntityID id)
{
for (s32 i = 0; i < ECS_COMPONENT_COUNT; i++)
ecs_component_delete(self, (ECSComponentType)i, id);
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "ecs_component.h"
u32 ecs_entity_add(ECS* ecs);
void ecs_entity_delete(ECS* ecs, EntityID id);

View File

@@ -0,0 +1,23 @@
#include "entity_cursor.h"
EntityID
entity_cursor_add(ECS* ecs)
{
EntityID id;
id = ecs_entity_add(ecs);
ecs_components_add(ecs, ENTITY_CURSOR_DEPENDENCIES, ENTITY_CURSOR_DEPENDENCY_COUNT, id);
component_game_object_init
(
ecs_component_get(ecs, ECS_COMPONENT_TEXTURE_QUAD, id),
ecs,
&ecs->resources->textures[TEXTURE_CURSOR],
ENTITY_CURSOR_BUFFER,
(f32*)ENTITY_CURSOR_SIZE,
(f32*)ENTITY_CURSOR_POSITION
);
return id;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "../../component/game/component_game_object.h"
#include "../../component/physics/component_copy_mouse_position.h"
EntityID entity_cursor_add(ECS* ecs);
#define ENTITY_CURSOR_DEPENDENCY_COUNT 3
static const ECSComponentType ENTITY_CURSOR_DEPENDENCIES[ENTITY_CURSOR_DEPENDENCY_COUNT] =
{
ECS_COMPONENT_GAME_OBJECT,
ECS_COMPONENT_OUTLINE,
ECS_COMPONENT_COPY_MOUSE_POSITION
};
static const RendererBuffer ENTITY_CURSOR_BUFFER = RENDERER_BUFFER_UI;
static const vec2 ENTITY_CURSOR_SIZE = {32.0f, 32.0f};
static const vec3 ENTITY_CURSOR_POSITION = {0.0f, 0.0f, 0.0f};

View File

@@ -0,0 +1,15 @@
#include "entity_counter.h"
EntityID
entity_counter_add(ECS* ecs, s32 value, s32 max)
{
EntityID id;
id = ecs_entity_add(ecs);
ecs_components_add(ecs, ENTITY_COUNTER_DEPENDENCIES, ENTITY_COUNTER_DEPENDENCY_COUNT, id);
component_counter_init(ecs_component_get(ecs, ECS_COMPONENT_COUNTER, id), ecs, value, max);
return id;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "../../component/utility/component_counter.h"
#define ENTITY_COUNTER_DEPENDENCY_COUNT 1
static const ECSComponentType ENTITY_COUNTER_DEPENDENCIES[ENTITY_COUNTER_DEPENDENCY_COUNT] =
{
ECS_COMPONENT_COUNTER
};
EntityID entity_counter_add(ECS* ecs, s32 value, s32 max);

View File

@@ -0,0 +1,15 @@
#include "entity_timer.h"
EntityID
entity_timer_add(ECS* ecs, u32 value)
{
EntityID id;
id = ecs_entity_add(ecs);
ecs_components_add(ecs, ENTITY_TIMER_DEPENDENCIES, ENTITY_TIMER_DEPENDENCY_COUNT, id);
component_timer_init(ecs_component_get(ecs, ECS_COMPONENT_TIMER, id), ecs, value);
return id;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "../../component/utility/component_timer.h"
#define ENTITY_TIMER_DEPENDENCY_COUNT 1
static const ECSComponentType ENTITY_TIMER_DEPENDENCIES[ENTITY_TIMER_DEPENDENCY_COUNT] =
{
ECS_COMPONENT_TIMER
};
EntityID entity_timer_add(ECS* ecs, u32 value);

View File

@@ -0,0 +1,32 @@
#include "entity_sprite.h"
EntityID
entity_sprite_add(ECS* ecs, Texture* texture, RendererBuffer buffer, const vec2 size, const vec3 position)
{
EntityID id;
id = ecs_entity_add(ecs);
ecs_components_add(ecs, ENTITY_SPRITE_DEPENDENCIES, ENTITY_SPRITE_DEPENDENCY_COUNT, id);
component_texture_quad_init
(
ecs_component_get(ecs, ECS_COMPONENT_TEXTURE_QUAD, id),
ecs,
texture,
&ecs->resources->shaders[SHADER_TEXTURE_QUAD],
COMPONENT_TEXTURE_QUAD_FLIP_DEFAULT,
COMPONENT_TEXTURE_QUAD_ORIGIN_DEFAULT,
buffer,
COMPONENT_TEXTURE_QUAD_ROTATION_DEFAULT,
(f32*)size,
(f32*)COMPONENT_TEXTURE_QUAD_SCALE_DEFAULT,
(f32*)COMPONENT_TEXTURE_QUAD_UV_MIN_DEFAULT,
(f32*)COMPONENT_TEXTURE_QUAD_UV_MAX_DEFAULT,
(f32*)COMPONENT_TEXTURE_QUAD_OFFSET_DEFAULT,
(f32*)position,
(f32*)COMPONENT_TEXTURE_QUAD_COLOR_DEFAULT
);
return id;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "../../component/visual/component_texture_quad.h"
#define ENTITY_SPRITE_DEPENDENCY_COUNT 1
static const ECSComponentType ENTITY_SPRITE_DEPENDENCIES[ENTITY_SPRITE_DEPENDENCY_COUNT] =
{
ECS_COMPONENT_TEXTURE_QUAD
};
EntityID entity_sprite_add(ECS* ecs, Texture* texture, RendererBuffer buffer, const vec2 size, const vec3 position);

View File

@@ -0,0 +1,39 @@
#include "entity_text.h"
EntityID
entity_text_add
(
ECS* ecs,
Font* font,
RendererBuffer buffer,
const char* string,
const vec3 position,
const vec4 color,
u32 length,
u32 wrap
)
{
EntityID id;
id = ecs_entity_add(ecs);
ecs_components_add(ecs, ENTITY_TEXT_DEPENDENCIES, ENTITY_TEXT_DEPENDENCY_COUNT, id);
component_text_init
(
ecs_component_get(ecs, ECS_COMPONENT_TEXT, id),
ecs,
font,
&ecs->resources->shaders[SHADER_TEXTURE_QUAD],
buffer,
string,
(f32*)ENTITY_TEXT_SCALE_DEFAULT,
position,
(f32*)ENTITY_TEXT_OFFSET_DEFAULT,
color,
length,
wrap
);
return id;
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include "../../component/visual/component_text.h"
#define ENTITY_TEXT_SCALE_DEFAULT COMPONENT_TEXT_SCALE_DEFAULT
#define ENTITY_TEXT_OFFSET_DEFAULT COMPONENT_TEXT_OFFSET_DEFAULT
#define ENTITY_TEXT_DEPENDENCY_COUNT 1
static const ECSComponentType ENTITY_TEXT_DEPENDENCIES[ENTITY_TEXT_DEPENDENCY_COUNT] =
{
ECS_COMPONENT_TEXT
};
EntityID
entity_text_add
(
ECS* ecs,
Font* font,
RendererBuffer buffer,
const char* string,
const vec3 position,
const vec4 color,
u32 length,
u32 wrap
);

116
src/game/game.c Normal file
View File

@@ -0,0 +1,116 @@
#include "game.h"
Game game;
static void _game_tick(Game* self);
static void _game_update(Game* self);
static void _game_draw(Game* self);
static void _game_quit(Game* self);
static void
_game_quit(Game* self)
{
state_free(&self->state);
ecs_free(&self->ecs);
window_free(&self->window);
sdl_quit();
memset(self, '\0', sizeof(Game));
exit(EXIT_SUCCESS);
}
static void
_game_tick(Game* self)
{
input_tick(&self->input);
state_tick(&self->state);
ecs_tick(&self->ecs);
if (event_press(&self->input.event, EVENT_QUIT))
_game_quit(self);
}
static void
_game_update(Game* self)
{
renderer_update(&self->renderer);
ecs_update(&self->ecs);
}
static void
_game_draw(Game* self)
{
renderer_clear_color_set(&self->renderer, (f32*)RENDERER_CLEAR_COLOR);
renderer_clear(&self->renderer);
for (s32 i = 0; i < RENDERER_BUFFER_COUNT; i++)
{
renderer_buffer_init(&self->renderer, (RendererBuffer)i);
renderer_buffer_use(&self->renderer, (RendererBuffer)i);
renderer_clear_color_set(&self->renderer, (f32*)TRANSPARENT);
renderer_clear(&self->renderer);
renderer_buffer_unbind();
}
ecs_draw(&self->ecs);
for (s32 i = 0; i < RENDERER_BUFFER_COUNT; i++)
{
buffer_draw
(
&self->renderer,
&self->resources.shaders[SHADER_POSTPROCESS_TEXTURE_QUAD],
&self->postprocessing[i],
(RendererBuffer)i
);
renderer_buffer_free(&self->renderer, (RendererBuffer)i);
}
renderer_present(&self->renderer);
}
void
game_init(Game* self)
{
memset(self, '\0', sizeof(Game));
RANDOM_SEED_SET(time(NULL));
resource_shader_read(&self->resources);
sdl_init();
window_init(&self->window, STRING_WINDOW_TITLE, (s32*)WINDOW_SIZE, WINDOW_FLAGS);
renderer_init(&self->renderer, &self->window, CAMERA_ORTHOGRAPHIC, (s32*)WORLD_SIZE);
renderer_clear_color_set(&self->renderer, (f32*)RENDERER_CLEAR_COLOR);
ecs_init(&self->ecs, &self->renderer, &self->input, &self->resources, self->postprocessing);
state_init(&self->state, &self->ecs, STATE_GAMEPLAY);
}
void
game_loop(Game* self)
{
tick_update(&self->tick);
while (self->tick.cumulative > TICK_DELAY)
{
_game_tick(self);
self->tick.cumulative -= TICK_DELAY;
}
_game_update(self);
_game_draw(self);
}

16
src/game/game.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
#include "GAME_COMMON.h"
#define WINDOW_FLAGS SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
#define STRING_WINDOW_TITLE "Game Engine"
#define TICK_DELAY 15
static const ivec2 WINDOW_SIZE = {1280, 720};
static const ivec2 WORLD_SIZE = {1280, 720};
static const vec4 RENDERER_CLEAR_COLOR = {0.700f, 0.700f, 0.700f, 1.0f};
void game_init(Game* game);
void game_loop(Game* game);
extern Game game;

9
src/game/input/input.c Normal file
View File

@@ -0,0 +1,9 @@
#include "input.h"
void
input_tick(Input* self)
{
keyboard_update(&self->keyboard);
mouse_update(&self->mouse);
event_update(&self->event);
}

14
src/game/input/input.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include "../../engine/event.h"
#include "../../engine/keyboard.h"
#include "../../engine/mouse.h"
typedef struct Input
{
Keyboard keyboard;
Mouse mouse;
Event event;
} Input;
void input_tick(Input* self);

View File

@@ -0,0 +1,26 @@
#pragma once
#include "../../engine/renderer.h"
#include "../../engine/texture.h"
typedef enum Flip
{
FLIP_NONE,
FLIP_HORIZONTAL,
FLIP_VERTICAL,
FLIP_HORIZONTAL_VERTICAL
} Flip;
typedef enum Origin
{
ORIGIN_CENTER,
ORIGIN_TOP_LEFT
} Origin;
typedef struct Postprocessing
{
vec4 color;
f32 screenShakeIntensity;
u32 screenShakeTimer;
bool isScreenShake;
} Postprocessing;

44
src/game/render/buffer.c Normal file
View File

@@ -0,0 +1,44 @@
#include "buffer.h"
void
buffer_draw(Renderer* renderer, Shader* shader, Postprocessing* postprocessing, RendererBuffer buffer)
{
mat4 model;
vec2 size;
vec3 position;
glm_vec2_zero(size);
glm_vec3_zero(position);
glm_mat4_identity(model);
size[0] = renderer->size[0];
size[1] = renderer->size[1];
glm_translate(model, position);
renderer_shader_use(renderer, shader);
glDisable(GL_DEPTH_TEST);
/*
postprocessing->color[0] = 0.9f;
postprocessing->color[1] = 0.25f;
postprocessing->color[2] = 0.25f;
postprocessing->color[3] = 1.0f;
*/
texture_quad_draw
(
&renderer->fboTextures[buffer],
renderer,
shader,
(f32*)TEXTURE_QUAD_UV_MIN_DEFAULT,
(f32*)TEXTURE_QUAD_UV_MAX_DEFAULT,
model,
size,
postprocessing->color,
FLIP_HORIZONTAL_VERTICAL
);
glEnable(GL_DEPTH_TEST);
}

5
src/game/render/buffer.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
#include "texture_quad.h"
void buffer_draw(Renderer* renderer, Shader* shader, Postprocessing* postprocessing, RendererBuffer buffer);

View File

@@ -0,0 +1,97 @@
#include "texture_quad.h"
void
texture_quad_draw
(
Texture* texture,
Renderer* renderer,
Shader* shader,
vec2 uvMin,
vec2 uvMax,
mat4 model,
vec2 size,
vec4 color,
Flip flip
)
{
mat4 view;
mat4 projection;
f32 vertices[4][5];
u32 indices[2][3] = {{1, 2, 3}, {0, 1, 3}};
f32 verticiesFlipNone[4][5] =
{
{0.0f, 0.0f, 0.0f, uvMin[0], uvMin[1]},
{0.0f, size[1], 0.0f, uvMin[0], uvMax[1]},
{size[0], size[1], 0.0f, uvMax[0], uvMax[1]},
{size[0], 0.0f, 0.0f, uvMax[0], uvMin[1]}
};
f32 verticiesFlipHorizontal[4][5] =
{
{size[0], 0.0f, 0.0f, uvMin[0], uvMin[1]},
{size[0], size[1], 0.0f, uvMin[0], uvMax[1]},
{0.0f, size[1], 0.0f, uvMax[0], uvMax[1]},
{0.0f, 0.0f, 0.0f, uvMax[0], uvMin[1]}
};
f32 verticiesFlipVertical[4][5] =
{
{size[0], size[1], 0.0f, uvMin[0], uvMin[1]},
{size[0], 0.0f, 0.0f, uvMin[0], uvMax[1]},
{0.0f, 0.0f, 0.0f, uvMax[0], uvMax[1]},
{0.0f, size[1], 0.0f, uvMax[0], uvMin[1]}
};
f32 verticiesFlipHorizontalVertical[4][5] =
{
{0.0f, size[1], 0.0f, uvMin[0], uvMin[1]},
{0.0f, 0.0f, 0.0f, uvMin[0], uvMax[1]},
{size[0], 0.0f, 0.0f, uvMax[0], uvMax[1]},
{size[0], size[1], 0.0f, uvMax[0], uvMin[1]}
};
switch (flip)
{
case FLIP_HORIZONTAL:
memcpy(vertices, verticiesFlipHorizontal, sizeof(vertices));
break;
case FLIP_VERTICAL:
memcpy(vertices, verticiesFlipVertical, sizeof(vertices));
break;
case FLIP_HORIZONTAL_VERTICAL:
memcpy(vertices, verticiesFlipHorizontalVertical, sizeof(vertices));
break;
case FLIP_NONE:
default:
memcpy(vertices, verticiesFlipNone, sizeof(vertices));
break;
}
camera_view_get(&renderer->camera, view);
camera_projection_get(&renderer->camera, projection);
vao_bind(&renderer->vao);
vbo_bind(&renderer->vbo);
vbo_buffer(&renderer->vbo, sizeof(vertices), vertices);
vbo_bind(&renderer->ebo);
vbo_buffer(&renderer->ebo, sizeof(indices), indices);
vertex_attribute_set(0, 3, GL_FLOAT, 5 * sizeof(f32), 0);
vertex_attribute_set(1, 2, GL_FLOAT, 5 * sizeof(f32), 3 * sizeof(f32));
renderer_shader_use(renderer, shader);
shader_uniform_mat4_set(shader, TEXTURE_QUAD_UNIFORM_VIEW, view);
shader_uniform_mat4_set(shader, TEXTURE_QUAD_UNIFORM_PROJECTION, projection);
shader_uniform_mat4_set(shader, TEXTURE_QUAD_UNIFORM_MODEL, model);
shader_uniform_vec2_set(shader, TEXTURE_QUAD_UNIFORM_SIZE, size);
shader_uniform_vec4_set(shader, TEXTURE_QUAD_UNIFORM_COLOR, color);
shader_uniform_texture_set(shader, TEXTURE_QUAD_UNIFORM_TEXTURE, texture, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
vao_unbind();
}

Some files were not shown because too many files have changed in this diff Show More