engine

game
git clone git://git.evenfri.pw/engine.git
Log | Files | Refs | README

commit 2a8375d22d528395a453ae71cc86ce27c36cf558
parent 312eb70506a9e8f21cc8ea076ec949ff9feff3e9
Author: evenfri <evenfri@4plt.ch>
Date:   Fri,  6 Nov 2026 00:02:00 +0800

add mini ecs

Diffstat:
MREADME | 2+-
Aarray.c | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcamera.c | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mdat.h | 117++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mfns.h | 68++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Mmain.c | 2++
Mmat4.c | 36++++++++++++++++++++++++++++++++++++
Mmesh.c | 91++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mmkfile | 6+++---
Mrender.c | 10+++++-----
Mscene.c | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Mshader.c | 6+++---
Mstb_image.h | 60++++++++++++++++++++++++++++++------------------------------
Mtest.c | 20++++++++++++++------
Mtexture.c | 4++--
15 files changed, 527 insertions(+), 231 deletions(-)

diff --git a/README b/README @@ -8,4 +8,4 @@ realized * render * textures * camera input - * generation world + * generation scene diff --git a/array.c b/array.c @@ -0,0 +1,53 @@ +#include <string.h> +#include "engine.h" + +void array_init(Array_t *a, size_t elem_size) { + a->data = NULL; + a->elem_size = elem_size; + a->count = 0; + a->capacity = 0; +} + +void array_free(Array_t *a) { + free(a->data); + a->data = NULL; + a->count = 0; + a->capacity = 0; +} + +static void array_grow(Array_t *a) { + size_t new_cap = a->capacity ? a->capacity * 2 : 8; + void *new_data = realloc(a->data, new_cap * a->elem_size); + if (!new_data) { + fprintf(stderr, "err: array_grow out of memory\n"); + exit(EXIT_FAILURE); + } + a->data = new_data; + a->capacity = new_cap; +} + +void *array_push(Array_t *a) { + if (a->count >= a->capacity) array_grow(a); + void *slot = (char*)a->data + a->count * a->elem_size; + a->count++; + return slot; +} + +void *array_pop(Array_t *a, size_t i) { + if (i >= a->count) return NULL; + return (char*)a->data + i * a->elem_size; +} + +void array_remove_swap(Array_t *a, size_t i) { + if (i >= a->count) return; + if (i != a->count - 1) { + void *dst = (char*)a->data + i * a->elem_size; + void *src = (char*)a->data + (a->count - 1) * a->elem_size; + memcpy(dst, src, a->elem_size); + } + a->count--; +} + +void array_clear(Array_t *a) { + a->count = 0; +} diff --git a/camera.c b/camera.c @@ -1,80 +1,148 @@ #include <math.h> #include "engine.h" -Camera_t camera; +static editor_camera_t editor_storage; -void camera_update_vectors(void) { - float yr = camera.yaw * PI / 180.0f; - float pr = camera.pitch * PI / 180.0f; - - vec3 front; front.x = cosf(yr) * cosf(pr); front.y = sinf(pr); +/* editor backend */ +static void editor_update_vectors(editor_camera_t *c) { + float yr = c->yaw * PI / 180.0f; + float pr = c->pitch * PI / 180.0f; + vec3 front; + front.x = cosf(yr) * cosf(pr); + front.y = sinf(pr); front.z = sinf(yr) * cosf(pr); + c->front = vec3_norm(front); + c->right = vec3_norm(vec3_cross(c->front, c->scene_up)); + c->up = vec3_norm(vec3_cross(c->right, c->front)); +} - camera.front = vec3_norm(front); - camera.right = vec3_norm(vec3_cross(camera.front, camera.world_up)); - camera.up = vec3_norm(vec3_cross(camera.right, camera.front)); +static mat4 editor_view(editor_camera_t *c) { + vec3 f = vec3_norm(c->front); + vec3 s = vec3_norm(vec3_cross(f, c->up)); + vec3 u = vec3_cross(s, f); + vec3 e = c->position; + mat4 v; + v.m[0] = s.x; v.m[4] = s.y; v.m[8] = s.z; v.m[12] = -vec3_dot(s, e); + v.m[1] = u.x; v.m[5] = u.y; v.m[9] = u.z; v.m[13] = -vec3_dot(u, e); + v.m[2] = -f.x; v.m[6] = -f.y; v.m[10] = -f.z; v.m[14] = vec3_dot(f, e); + v.m[3] = 0.0f; v.m[7] = 0.0f; v.m[11] = 0.0f; v.m[15] = 1.0f; + return v; } +/* game backend */ +static mat4 game_view(game_obj_t *obj) { + transform_t *t = game_obj_get_component(obj, COMP_TRANSFORM); + if (!t) return mat4_identity(); + mat4 R = mat4_mul( + mat4_rotate_y(t->rot.y * PI / 180.0f), + mat4_rotate_x(t->rot.x * PI / 180.0f)); + mat4 Rt; + Rt.m[0] = R.m[0]; Rt.m[1] = R.m[4]; Rt.m[2] = R.m[8]; Rt.m[3] = 0; + Rt.m[4] = R.m[1]; Rt.m[5] = R.m[5]; Rt.m[6] = R.m[9]; Rt.m[7] = 0; + Rt.m[8] = R.m[2]; Rt.m[9] = R.m[6]; Rt.m[10] = R.m[10]; Rt.m[11] = 0; + Rt.m[12] = 0; Rt.m[13] = 0; Rt.m[14] = 0; Rt.m[15] = 1; + mat4 T = mat4_translate(-t->pos.x, -t->pos.y, -t->pos.z); + return mat4_mul(Rt, T); +} + +/* unified interface */ + void camera_init(vec3 position) { - camera.position = position; - camera.world_up = vec3_make(0.0f, 1.0f, 0.0f); - camera.yaw = 0.0f; - camera.pitch = 0.0f; - camera.speed = CAMERA_SPEED; - camera.sensitivity = CAMERA_SENSITIVITY; - camera.fov = CAMERA_FOV; - camera_update_vectors(); + editor_camera_t *c = &editor_storage; + c->position = position; + c->scene_up = vec3_make(0.0f, 1.0f, 0.0f); + c->yaw = c->pitch = 0.0f; + c->speed = CAMERA_SPEED; + c->sensitivity = CAMERA_SENSITIVITY; + c->fov = CAMERA_FOV; + c->near_plane = 0.1f; + c->far_plane = 100.0f; + editor_update_vectors(c); + + active_camera.kind = CAMERA_EDITOR; + active_camera.impl.editor = c; +} + +void camera_set_editor(void) { + active_camera.kind = CAMERA_EDITOR; + active_camera.impl.editor = &editor_storage; +} + +void camera_set_game(game_obj_t *obj, camera_comp_t *comp) { + active_camera.kind = CAMERA_GAME; + active_camera.impl.game.obj = obj; + active_camera.impl.game.comp = comp; +} + +editor_camera_t *camera_editor(void) { + return active_camera.kind == CAMERA_EDITOR ? active_camera.impl.editor : NULL; } mat4 camera_get_view(void) { - vec3 f = vec3_norm(camera.front); - vec3 s = vec3_norm(vec3_cross(f, camera.up)); - vec3 u = vec3_cross(s, f); - vec3 e = camera.position; + switch (active_camera.kind) { + case CAMERA_EDITOR: return editor_view(active_camera.impl.editor); + case CAMERA_GAME: return game_view(active_camera.impl.game.obj); + } + return mat4_identity(); +} - mat4 v; - v.m[0] = s.x; v.m[4] = s.y; v.m[8] = s.z; v.m[12] = -vec3_dot(s, e); - v.m[1] = u.x; v.m[5] = u.y; v.m[9] = u.z; v.m[13] = -vec3_dot(u, e); - v.m[2] = -f.x; v.m[6] = -f.y; v.m[10] = -f.z; v.m[14] = vec3_dot(f, e); - v.m[3] = 0.0f; v.m[7] = 0.0f; v.m[11] = 0.0f; v.m[15] = 1.0f; - return v; +float camera_get_fov(void) { + if (active_camera.kind == CAMERA_EDITOR) + return active_camera.impl.editor->fov; + return active_camera.impl.game.comp->fov; } -void camera_process_keyboard(float dt) { - float v = camera.speed * dt; +float camera_get_near(void) { + if (active_camera.kind == CAMERA_EDITOR) + return active_camera.impl.editor->near_plane; + return active_camera.impl.game.comp->near_plane; +} + +float camera_get_far(void) { + if (active_camera.kind == CAMERA_EDITOR) + return active_camera.impl.editor->far_plane; + return active_camera.impl.game.comp->far_plane; +} +void camera_process_keyboard(float dt) { + editor_camera_t *c = camera_editor(); + if (!c) return; + float v = c->speed * dt; if (glfwGetKey(Window, GLFW_KEY_E) == GLFW_PRESS) { - camera.position.x += camera.front.x * v; - camera.position.y += camera.front.y * v; - camera.position.z += camera.front.z * v; + c->position.x += c->front.x * v; + c->position.y += c->front.y * v; + c->position.z += c->front.z * v; } if (glfwGetKey(Window, GLFW_KEY_D) == GLFW_PRESS) { - camera.position.x -= camera.front.x * v; - camera.position.y -= camera.front.y * v; - camera.position.z -= camera.front.z * v; + c->position.x -= c->front.x * v; + c->position.y -= c->front.y * v; + c->position.z -= c->front.z * v; } if (glfwGetKey(Window, GLFW_KEY_S) == GLFW_PRESS) { - camera.position.x -= camera.right.x * v; - camera.position.y -= camera.right.y * v; - camera.position.z -= camera.right.z * v; + c->position.x -= c->right.x * v; + c->position.y -= c->right.y * v; + c->position.z -= c->right.z * v; } if (glfwGetKey(Window, GLFW_KEY_F) == GLFW_PRESS) { - camera.position.x += camera.right.x * v; - camera.position.y += camera.right.y * v; - camera.position.z += camera.right.z * v; + c->position.x += c->right.x * v; + c->position.y += c->right.y * v; + c->position.z += c->right.z * v; } - if (glfwGetKey(Window, GLFW_KEY_SPACE) == GLFW_PRESS) - camera.position.y += v; - if (glfwGetKey(Window, GLFW_KEY_Z) == GLFW_PRESS) - camera.position.y -= v; + if (glfwGetKey(Window, GLFW_KEY_SPACE) == GLFW_PRESS) c->position.y += v; + if (glfwGetKey(Window, GLFW_KEY_Z) == GLFW_PRESS) c->position.y -= v; } void camera_process_mouse(float dx, float dy) { - camera.yaw += dx * camera.sensitivity; - camera.pitch += dy * camera.sensitivity; - - if (camera.pitch > 89.0f) camera.pitch = 89.0f; - if (camera.pitch < -89.0f) camera.pitch = -89.0f; + editor_camera_t *c = camera_editor(); + if (!c) return; + c->yaw += dx * c->sensitivity; + c->pitch += dy * c->sensitivity; + if (c->pitch > 89.0f) c->pitch = 89.0f; + if (c->pitch < -89.0f) c->pitch = -89.0f; + editor_update_vectors(c); +} - camera_update_vectors(); +void camera_update_vectors(void) { + editor_camera_t *c = camera_editor(); + if (c) editor_update_vectors(c); } diff --git a/dat.h b/dat.h @@ -3,83 +3,102 @@ #include "engine.h" +typedef unsigned int uint; + #define PI 3.14159265358979323846f typedef struct { float x, y, z; } vec3; typedef struct { float m[16]; } mat4; +/* dynamic array */ typedef struct { - vec3 position; - vec3 front; - vec3 up; - vec3 right; - vec3 world_up; - float yaw; - float pitch; - float speed; - float sensitivity; - float fov; -} Camera_t; + void *data; + size_t elem_size; + size_t count; + size_t capacity; +} Array_t; typedef struct { - unsigned int vao, vbo, ebo; + uint vao, vbo, ebo; int vertex_count; - unsigned int texture; + uint texture; } Mesh_t; +typedef struct { float x, y, z; } TempVec3_t; +typedef struct { float x, y; } TempVec2_t; + +/* components */ typedef struct { - vec3 position; - vec3 rotation; - vec3 scale; - Mesh_t *mesh; - unsigned int texture; -} Entity_t; + uint32_t type_id; + void *data; + size_t size; +} component_t; typedef struct { - Entity_t entities[64]; - int count; -} Scene_t; + vec3 pos; + vec3 rot; + vec3 scl; +} transform_t; typedef struct { - float x, y, z; -} TempVec3_t; + float fov; + float near_plane; + float far_plane; +} camera_comp_t; typedef struct { - float x, y; -} TempVec2_t; + Mesh_t *mesh; + uint texture; +} mesh_comp_t; typedef struct { - int v_idx; - int vt_idx; - int vn_idx; -} VertexKey_t; + vec3 position; + vec3 front; + vec3 up; + vec3 right; + vec3 scene_up; + float yaw; + float pitch; + float speed; + float sensitivity; + float fov; + float near_plane; + float far_plane; +} editor_camera_t; -#define MAX_VERTICES 65536 +typedef enum { + CAMERA_EDITOR, + CAMERA_GAME, +} camera_kind_t; -extern GLFWwindow *Window; -extern unsigned int Shader; -extern Camera_t camera; +/* component type ids */ +#define COMP_TRANSFORM 0x01u +#define COMP_CAMERA 0x02u +#define COMP_MESH 0x03u typedef struct { - uint32_t type_id; - void *data; - size_t size; -} component_t; + Array_t components; + int active; +} game_obj_t; typedef struct { - component_t component; - - float fov; - float near_plane; - float far_plane; -} camera_t; + Array_t objects; +} scene_t; typedef struct { - component_t component; + camera_kind_t kind; + union { + editor_camera_t *editor; + struct { + game_obj_t *obj; + camera_comp_t *comp; + } game; + } impl; +} active_camera_t; - vec3 pos; - vec3 rot; - vec3 scl; -} transform_t; + +extern GLFWwindow *Window; +extern uint Shader; +extern active_camera_t active_camera; #endif /* DAT_H */ diff --git a/fns.h b/fns.h @@ -1,17 +1,15 @@ #ifndef FNS_H #define FNS_H -void window_init(); - -void process_input(float dt); - -void render_init(); -void render_begin(); -void render_end(); - -void shader_init(); -void shader_end(); +/* array */ +void array_init(Array_t *a, size_t elem_size); +void array_free(Array_t *a); +void *array_push(Array_t *a); +void *array_pop(Array_t *a, size_t i); +void array_remove_swap(Array_t *a, size_t i); +void array_clear(Array_t *a); +/* math */ vec3 vec3_make(float x, float y, float z); vec3 vec3_sub(vec3 a, vec3 b); vec3 vec3_scale(vec3 a, float s); @@ -19,27 +17,65 @@ float vec3_dot(vec3 a, vec3 b); vec3 vec3_cross(vec3 a, vec3 b); vec3 vec3_norm(vec3 a); +mat4 mat4_mul(mat4 a, mat4 b); +mat4 mat4_rotate_x(float radians); +mat4 mat4_rotate_y(float radians); +mat4 mat4_rotate_z(float radians); mat4 mat4_identity(void); mat4 mat4_perspective(float fovy, float aspect, float znear, float zfar); mat4 mat4_translate(float x, float y, float z); +/* window */ +void window_init(); +void process_input(float dt); + +/* render */ +void render_init(); +void render_begin(); +void render_end(); + +/* shader */ +void shader_init(); +void shader_end(); + +/* camera */ void camera_init(vec3 position); -void camera_update_vectors(void); -mat4 camera_get_view(void); +void camera_set_editor(void); +void camera_set_game(game_obj_t *obj, camera_comp_t *comp); +editor_camera_t *camera_editor(void); +mat4 camera_get_view(void); +float camera_get_fov(void); +float camera_get_near(void); +float camera_get_far(void); void camera_process_keyboard(float dt); void camera_process_mouse(float dx, float dy); +void camera_update_vectors(void); +/* mesh */ Mesh_t mesh_load_obj(const char *path); void mesh_draw(Mesh_t *mesh); void mesh_destroy(Mesh_t *mesh); -unsigned int texture_load(const char *path); +/* texture */ +uint texture_load(const char *path); + +/* scene / components */ +void scene_init(scene_t *w); +void scene_end(scene_t *w); +game_obj_t *scene_add_object(scene_t *w); +void scene_render(scene_t *w, uint shader_program); + +void *game_obj_add_component(game_obj_t *obj, uint32_t type_id, size_t size); +void *game_obj_get_component(game_obj_t *obj, uint32_t type_id); -void scene_init(Scene_t *scene); -Entity_t* scene_add_entity(Scene_t *scene, Mesh_t *mesh, unsigned int texture); -void scene_render(Scene_t *scene, unsigned int shader_program); +/* typed component helpers */ +transform_t *game_obj_add_transform(game_obj_t *obj); +camera_comp_t *game_obj_add_camera(game_obj_t *obj); +mesh_comp_t *game_obj_add_mesh(game_obj_t *obj, Mesh_t *mesh, uint texture); +void game_obj_activate_camera(game_obj_t *obj); +/* test*/ int test_start(); int test_update(float dt); int test_end(); diff --git a/main.c b/main.c @@ -1,5 +1,7 @@ #include "engine.h" +active_camera_t active_camera; + int main() { window_init(); shader_init(); diff --git a/mat4.c b/mat4.c @@ -1,6 +1,42 @@ #include <math.h> #include "engine.h" +mat4 mat4_mul(mat4 a, mat4 b) { + mat4 r = {{0}}; + for (int c = 0; c < 4; c++) + for (int row = 0; row < 4; row++) { + float s = 0.0f; + for (int k = 0; k < 4; k++) + s += a.m[k*4 + row] * b.m[c*4 + k]; + r.m[c*4 + row] = s; + } + return r; +} + +mat4 mat4_rotate_x(float a) { + mat4 r = mat4_identity(); + float c = cosf(a), s = sinf(a); + r.m[5] = c; r.m[6] = s; + r.m[9] = -s; r.m[10] = c; + return r; +} + +mat4 mat4_rotate_y(float a) { + mat4 r = mat4_identity(); + float c = cosf(a), s = sinf(a); + r.m[0] = c; r.m[2] = -s; + r.m[8] = s; r.m[10] = c; + return r; +} + +mat4 mat4_rotate_z(float a) { + mat4 r = mat4_identity(); + float c = cosf(a), s = sinf(a); + r.m[0] = c; r.m[1] = s; + r.m[4] = -s; r.m[5] = c; + return r; +} + mat4 mat4_identity(void) { mat4 r = {{0}}; r.m[0] = r.m[5] = r.m[10] = r.m[15] = 1.0f; diff --git a/mesh.c b/mesh.c @@ -7,43 +7,33 @@ Mesh_t mesh_load_obj(const char *path) { return (Mesh_t){0}; } - TempVec3_t temp_positions[MAX_VERTICES]; - TempVec2_t temp_texcoords[MAX_VERTICES]; - TempVec3_t temp_normals[MAX_VERTICES]; - int pos_count = 0, tex_count = 0, norm_count = 0; - - float final_vertices[MAX_VERTICES * 5]; - unsigned int final_indices[MAX_VERTICES]; - int vertex_count = 0; - int index_count = 0; + Array_t positions, texcoords, final_vertices, final_indices; + array_init(&positions, sizeof(vec3)); + array_init(&texcoords, sizeof(TempVec2_t)); + array_init(&final_vertices, sizeof(float)); + array_init(&final_indices, sizeof(unsigned int)); char line[256]; while (fgets(line, sizeof(line), f)) { if (line[0] == 'v' && line[1] == ' ') { - TempVec3_t v; - sscanf(line, "v %f %f %f", &v.x, &v.y, &v.z); - temp_positions[pos_count++] = v; + vec3 *v = array_push(&positions); + sscanf(line, "v %f %f %f", &v->x, &v->y, &v->z); } else if (line[0] == 'v' && line[1] == 't') { - TempVec2_t vt; - sscanf(line, "vt %f %f", &vt.x, &vt.y); - temp_texcoords[tex_count++] = vt; + TempVec2_t *vt = array_push(&texcoords); + sscanf(line, "vt %f %f", &vt->x, &vt->y); } else if (line[0] == 'v' && line[1] == 'n') { - TempVec3_t vn; - sscanf(line, "vn %f %f %f", &vn.x, &vn.y, &vn.z); - temp_normals[norm_count++] = vn; + /* normals: parsed only to skip them cleanly */ + float dummy[3]; + sscanf(line, "vn %f %f %f", &dummy[0], &dummy[1], &dummy[2]); } else if (line[0] == 'f' && line[1] == ' ') { int v[3] = {0}, vt[3] = {0}, vn[3] = {0}; int matches = sscanf(line, "f %d/%d/%d %d/%d/%d %d/%d/%d", &v[0], &vt[0], &vn[0], &v[1], &vt[1], &vn[1], &v[2], &vt[2], &vn[2]); - (void)matches; - if (matches < 6) { matches = sscanf(line, "f %d/%d %d/%d %d/%d", - &v[0], &vt[0], - &v[1], &vt[1], - &v[2], &vt[2]); + &v[0], &vt[0], &v[1], &vt[1], &v[2], &vt[2]); } if (matches < 3) { sscanf(line, "f %d %d %d", &v[0], &v[1], &v[2]); @@ -53,52 +43,63 @@ Mesh_t mesh_load_obj(const char *path) { int p_idx = v[i] - 1; int t_idx = vt[i] - 1; - TempVec3_t pos = temp_positions[p_idx]; - TempVec2_t uv = (tex_count > 0 && t_idx >= 0) ? - temp_texcoords[t_idx] : (TempVec2_t){0.0f, 0.0f}; + vec3 *pos = array_pop(&positions, (size_t)p_idx); + if (!pos) continue; + + TempVec2_t uv_zero = {0.0f, 0.0f}; + TempVec2_t *uv = &uv_zero; + if (texcoords.count > 0 && t_idx >= 0) { + TempVec2_t *p = array_pop(&texcoords, (size_t)t_idx); + if (p) uv = p; + } - /* read vertex */ - int cur_v_idx = vertex_count / 5; - final_vertices[vertex_count++] = pos.x; - final_vertices[vertex_count++] = pos.y; - final_vertices[vertex_count++] = pos.z; - final_vertices[vertex_count++] = uv.x; - final_vertices[vertex_count++] = uv.y; + unsigned int cur_v_idx = (unsigned int)(final_vertices.count / 5); - final_indices[index_count++] = cur_v_idx; + *(float*)array_push(&final_vertices) = pos->x; + *(float*)array_push(&final_vertices) = pos->y; + *(float*)array_push(&final_vertices) = pos->z; + *(float*)array_push(&final_vertices) = uv->x; + *(float*)array_push(&final_vertices) = uv->y; + + *(unsigned int*)array_push(&final_indices) = cur_v_idx; } } } fclose(f); - (void)temp_normals; Mesh_t m = {0}; - m.vertex_count = index_count; + m.vertex_count = (int)final_indices.count; glGenVertexArrays(1, &m.vao); glGenBuffers(1, &m.vbo); glGenBuffers(1, &m.ebo); - glBindVertexArray(m.vao); glBindBuffer(GL_ARRAY_BUFFER, m.vbo); - glBufferData(GL_ARRAY_BUFFER, vertex_count * sizeof(float), final_vertices, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, + (GLsizeiptr)(final_vertices.count * sizeof(float)), + final_vertices.data, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m.ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_count * sizeof(unsigned int), final_indices, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + (GLsizeiptr)(final_indices.count * sizeof(unsigned int)), + final_indices.data, GL_STATIC_DRAW); - /* position attribute */ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); - - /* texture coord attribute */ - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); - + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), + (void*)(3 * sizeof(float))); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glBindVertexArray(0); - printf("loaded obj: %s (indices: %d)\n", path, index_count); + printf("loaded obj: %s (indices: %d)\n", path, m.vertex_count); + + array_free(&positions); + array_free(&texcoords); + array_free(&final_vertices); + array_free(&final_indices); + return m; } diff --git a/mkfile b/mkfile @@ -1,10 +1,11 @@ <$PLAN9/src/mkhdr ld = gcc - ldflags = -lglfw -lGL -lm ofiles = \ + stb_image.$o \ + array.$o \ vec3.$o \ mat4.$o \ window.$o \ @@ -13,7 +14,6 @@ ofiles = \ shader.$o \ camera.$o \ mesh.$o \ - stb_image.$o \ texture.$o \ scene.$o \ test.$o \ @@ -25,6 +25,6 @@ hfiles = \ dat.h \ config.h -targ = engine +targ = engine <$PLAN9/src/mkone diff --git a/render.c b/render.c @@ -6,8 +6,8 @@ void render_init() { glUseProgram(Shader); glUniform1i(glGetUniformLocation(Shader, "texture1"), 0); u_model = glGetUniformLocation(Shader, "model"); - u_view = glGetUniformLocation(Shader, "view"); - u_proj = glGetUniformLocation(Shader, "projection"); + u_view = glGetUniformLocation(Shader, "view"); + u_proj = glGetUniformLocation(Shader, "projection"); } void render_begin() { @@ -18,10 +18,10 @@ void render_begin() { mat4 view = camera_get_view(); mat4 projection = mat4_perspective( - camera.fov, + camera_get_fov(), (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, - 0.1f, 100.0f - ); + camera_get_near(), + camera_get_far()); glUniformMatrix4fv(u_view, 1, GL_FALSE, view.m); glUniformMatrix4fv(u_proj, 1, GL_FALSE, projection.m); diff --git a/scene.c b/scene.c @@ -1,33 +1,106 @@ +#include <string.h> #include "engine.h" -void scene_init(Scene_t *scene) { - scene->count = 0; +void scene_init(scene_t *w) { + array_init(&w->objects, sizeof(game_obj_t*)); } -Entity_t* scene_add_entity(Scene_t *scene, Mesh_t *mesh, unsigned int texture) { - if (scene->count >= 64) return NULL; - Entity_t *e = &scene->entities[scene->count++]; - e->position = vec3_make(0, 0, 0); - e->rotation = vec3_make(0, 0, 0); - e->scale = vec3_make(1, 1, 1); - e->mesh = mesh; - e->texture = texture; - return e; +void scene_end(scene_t *w) { + for (size_t i = 0; i < w->objects.count; i++) { + game_obj_t *obj = *(game_obj_t**)array_pop(&w->objects, i); + for (size_t j = 0; j < obj->components.count; j++) { + component_t *c = array_pop(&obj->components, j); + free(c->data); + } + array_free(&obj->components); + free(obj); + } + array_free(&w->objects); +} + +game_obj_t *scene_add_object(scene_t *w) { + game_obj_t *obj = calloc(1, sizeof(game_obj_t)); + if (!obj) { + fprintf(stderr, "err: failed to allocate game_obj_t\n"); + exit(EXIT_FAILURE); + } + array_init(&obj->components, sizeof(component_t)); + obj->active = 1; + *(game_obj_t**)array_push(&w->objects) = obj; + return obj; +} + +/* generic component api */ +void *game_obj_add_component(game_obj_t *obj, uint32_t type_id, size_t size) { + /* replace existing component if present */ + for (size_t i = 0; i < obj->components.count; i++) { + component_t *c = array_pop(&obj->components, i); + if (c->type_id == type_id) { + free(c->data); + c->size = size; + c->data = calloc(1, size); + return c->data; + } + } + component_t *c = array_push(&obj->components); + c->type_id = type_id; + c->size = size; + c->data = calloc(1, size); + return c->data; } -void scene_render(Scene_t *scene, unsigned int shader_program) { - for (int i = 0; i < scene->count; i++) { - Entity_t *e = &scene->entities[i]; +void *game_obj_get_component(game_obj_t *obj, uint32_t type_id) { + for (size_t i = 0; i < obj->components.count; i++) { + component_t *c = array_pop(&obj->components, i); + if (c->type_id == type_id) return c->data; + } + return NULL; +} - mat4 model = mat4_identity(); - model = mat4_translate(e->position.x, e->position.y, e->position.z); +/* typed helpers */ +transform_t *game_obj_add_transform(game_obj_t *obj) { + transform_t *t = game_obj_add_component(obj, COMP_TRANSFORM, sizeof(transform_t)); + t->scl = vec3_make(1.0f, 1.0f, 1.0f); + return t; +} - int u_model = glGetUniformLocation(shader_program, "model"); +camera_comp_t *game_obj_add_camera(game_obj_t *obj) { + camera_comp_t *c = game_obj_add_component(obj, COMP_CAMERA, + sizeof(camera_comp_t)); + c->fov = 60.0f; + c->near_plane = 0.1f; + c->far_plane = 100.0f; + return c; +} + +mesh_comp_t *game_obj_add_mesh(game_obj_t *obj, Mesh_t *mesh, unsigned int texture) { + mesh_comp_t *mc = game_obj_add_component(obj, COMP_MESH, sizeof(mesh_comp_t)); + mc->mesh = mesh; + mc->texture = texture; + return mc; +} + +/* render system */ +void scene_render(scene_t *w, unsigned int shader_program) { + int u_model = glGetUniformLocation(shader_program, "model"); + for (size_t i = 0; i < w->objects.count; i++) { + game_obj_t *obj = *(game_obj_t**)array_pop(&w->objects, i); + if (!obj->active) continue; + + transform_t *t = game_obj_get_component(obj, COMP_TRANSFORM); + mesh_comp_t *mc = game_obj_get_component(obj, COMP_MESH); + if (!t || !mc) continue; + + mat4 model = mat4_translate(t->pos.x, t->pos.y, t->pos.z); glUniformMatrix4fv(u_model, 1, GL_FALSE, model.m); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, e->texture); - - mesh_draw(e->mesh); + glBindTexture(GL_TEXTURE_2D, mc->texture); + mesh_draw(mc->mesh); } } + +void game_obj_activate_camera(game_obj_t *obj) { + camera_comp_t *c = game_obj_get_component(obj, COMP_CAMERA); + if (c) camera_set_game(obj, c); +} diff --git a/shader.c b/shader.c @@ -1,6 +1,6 @@ #include "engine.h" -unsigned int Shader; +uint Shader; static char *read_file(const char *path) { FILE *f = fopen(path, "rb"); @@ -31,7 +31,7 @@ static void load_shaders() { void shader_init() { load_shaders(); - unsigned int vert_shader = glCreateShader(GL_VERTEX_SHADER); + uint vert_shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vert_shader, 1, &vert_shader_src, NULL); glCompileShader(vert_shader); @@ -44,7 +44,7 @@ void shader_init() { printf("err: vertex shader failed: %s\n", info); } /* fragment shader */ - unsigned int frag_shader = glCreateShader(GL_FRAGMENT_SHADER); + uint frag_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(frag_shader, 1, &frag_shader_src, NULL); glCompileShader(frag_shader); diff --git a/stb_image.h b/stb_image.h @@ -641,7 +641,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #if defined(_MSC_VER) || defined(__SYMBIAN32__) typedef unsigned short stbi__uint16; typedef signed short stbi__int16; -typedef unsigned int stbi__uint32; +typedef uint stbi__uint32; typedef signed int stbi__int32; #else #include <stdint.h> @@ -1323,8 +1323,8 @@ static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, in #ifndef STBI_NO_STDIO #if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) -STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); -STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(uint cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(uint cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); #endif #if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) @@ -1752,7 +1752,7 @@ static stbi_uc stbi__compute_y(int r, int g, int b) #if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) // nothing #else -static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, uint x, uint y) { int i,j; unsigned char *good; @@ -1809,7 +1809,7 @@ static stbi__uint16 stbi__compute_y_16(int r, int g, int b) #if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) // nothing #else -static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, uint x, uint y) { int i,j; stbi__uint16 *good; @@ -1942,7 +1942,7 @@ typedef struct stbi__uint16 code[256]; stbi_uc values[256]; stbi_uc size[257]; - unsigned int maxcode[18]; + uint maxcode[18]; int delta[17]; // old 'firstsymbol' - old 'firstcode' } stbi__huffman; @@ -2003,7 +2003,7 @@ typedef struct static int stbi__build_huffman(stbi__huffman *h, int *count) { int i,j,k=0; - unsigned int code; + uint code; // build size list for each symbol (from JPEG spec) for (i=0; i < 16; ++i) { for (j=0; j < count[i]; ++j) { @@ -2075,7 +2075,7 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) static void stbi__grow_buffer_unsafe(stbi__jpeg *j) { do { - unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + uint b = j->nomore ? 0 : stbi__get8(j->s); if (b == 0xff) { int c = stbi__get8(j->s); while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes @@ -2096,7 +2096,7 @@ static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,204 // decode a jpeg huffman value from the bitstream stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) { - unsigned int temp; + uint temp; int c,k; if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); @@ -2152,7 +2152,7 @@ static const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023, // always extends everything it receives. stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) { - unsigned int k; + uint k; int sgn; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing @@ -2168,7 +2168,7 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) // get some unsigned bits stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) { - unsigned int k; + uint k; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing k = stbi_lrot(j->code_buffer, n); @@ -2180,7 +2180,7 @@ stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) { - unsigned int k; + uint k; if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing k = j->code_buffer; @@ -2229,7 +2229,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman // decode AC components, see JPEG spec k = 1; do { - unsigned int zig; + uint zig; int c,r,s; if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); @@ -2307,7 +2307,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ k = j->spec_start; do { - unsigned int zig; + uint zig; int c,r,s; if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); @@ -2416,7 +2416,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ stbi_inline static stbi_uc stbi__clamp(int x) { // trick to use a single test to catch both cases - if ((unsigned int) x > 255) { + if ((uint) x > 255) { if (x < 0) return 0; if (x > 255) return 255; } @@ -3858,7 +3858,7 @@ typedef struct // fast 0..255 * 0..255 => 0..255 rounded multiplication static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) { - unsigned int t = x*y + 128; + uint t = x*y + 128; return (stbi_uc) ((t + (t >>8)) >> 8); } @@ -3890,7 +3890,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp // resample and color-convert { int k; - unsigned int i,j; + uint i,j; stbi_uc *output; stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; @@ -4206,14 +4206,14 @@ static void stbi__fill_bits(stbi__zbuf *z) z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ return; } - z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->code_buffer |= (uint) stbi__zget8(z) << z->num_bits; z->num_bits += 8; } while (z->num_bits <= 24); } -stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +stbi_inline static uint stbi__zreceive(stbi__zbuf *z, int n) { - unsigned int k; + uint k; if (z->num_bits < n) stbi__fill_bits(z); k = z->code_buffer & ((1 << n) - 1); z->code_buffer >>= n; @@ -4273,10 +4273,10 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes { char *q; - unsigned int cur, limit, old_limit; + uint cur, limit, old_limit; z->zout = zout; if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); - cur = (unsigned int) (z->zout - z->zout_start); + cur = (uint) (z->zout - z->zout_start); limit = old_limit = (unsigned) (z->zout_end - z->zout_start); if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); while (cur + n > limit) { @@ -5367,7 +5367,7 @@ static int stbi__bmp_test(stbi__context *s) // returns 0..31 for the highest set bit -static int stbi__high_bit(unsigned int z) +static int stbi__high_bit(uint z) { int n=0; if (z == 0) return -1; @@ -5379,7 +5379,7 @@ static int stbi__high_bit(unsigned int z) return n; } -static int stbi__bitcount(unsigned int a) +static int stbi__bitcount(uint a) { a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 @@ -5392,14 +5392,14 @@ static int stbi__bitcount(unsigned int a) // extract an arbitrarily-aligned N-bit value (N=bits) // from v, and then make it 8-bits long and fractionally // extend it to full full range. -static int stbi__shiftsigned(unsigned int v, int shift, int bits) +static int stbi__shiftsigned(uint v, int shift, int bits) { - static unsigned int mul_table[9] = { + static uint mul_table[9] = { 0, 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, }; - static unsigned int shift_table[9] = { + static uint shift_table[9] = { 0, 0,0,1,0,2,4,6,0, }; if (shift < 0) @@ -5415,7 +5415,7 @@ static int stbi__shiftsigned(unsigned int v, int shift, int bits) typedef struct { int bpp, offset, hsz; - unsigned int mr,mg,mb,ma, all_a; + uint mr,mg,mb,ma, all_a; int extra_read; } stbi__bmp_data; @@ -5531,7 +5531,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi_uc *out; - unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + uint mr=0,mg=0,mb=0,ma=0, all_a; stbi_uc pal[256][4]; int psize=0,i,j,width; int flip_vertically, pad, target; @@ -5691,7 +5691,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req int bpp = info.bpp; for (i=0; i < (int) s->img_x; ++i) { stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); - unsigned int a; + uint a; out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); diff --git a/test.c b/test.c @@ -2,19 +2,26 @@ static Mesh_t mesh; static unsigned int texture; -static Scene_t main_scene; +static scene_t main_scene; int test_start() { + scene_init(&main_scene); + camera_init(vec3_make(0, 0, 0)); - camera.yaw = -90.0f; - camera.fov = 60.0f; + editor_camera_t *ed = camera_editor(); + ed->yaw = -90.0f; + ed->fov = 60.0f; camera_update_vectors(); - scene_init(&main_scene); mesh = mesh_load_obj("assets/cube.obj"); texture = texture_load("assets/cube.png"); - Entity_t *e = scene_add_entity(&main_scene, &mesh, texture); - e->position = vec3_make(0.0f, 0.0f, -2.0f); + + game_obj_t *e = scene_add_object(&main_scene); + transform_t *t = game_obj_add_transform(e); + + t->pos = vec3_make(0.0f, 0.0f, -2.0f); + game_obj_add_mesh(e, &mesh, texture); + return 0; } @@ -25,6 +32,7 @@ int test_update(float dt) { } int test_end() { + scene_end(&main_scene); mesh_destroy(&mesh); /* TODO: texture_delete() */ return 0; diff --git a/texture.c b/texture.c @@ -1,8 +1,8 @@ #include "engine.h" #include "stb_image.h" -unsigned int texture_load(const char *path) { - unsigned int texture_id; +uint texture_load(const char *path) { + uint texture_id; glGenTextures(1, &texture_id); glBindTexture(GL_TEXTURE_2D, texture_id);