commit 2a8375d22d528395a453ae71cc86ce27c36cf558
parent 312eb70506a9e8f21cc8ea076ec949ff9feff3e9
Author: evenfri <evenfri@4plt.ch>
Date: Fri, 6 Nov 2026 00:02:00 +0800
add mini ecs
Diffstat:
| M | README | | | 2 | +- |
| A | array.c | | | 53 | +++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | camera.c | | | 170 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
| M | dat.h | | | 117 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
| M | fns.h | | | 68 | ++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- |
| M | main.c | | | 2 | ++ |
| M | mat4.c | | | 36 | ++++++++++++++++++++++++++++++++++++ |
| M | mesh.c | | | 91 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
| M | mkfile | | | 6 | +++--- |
| M | render.c | | | 10 | +++++----- |
| M | scene.c | | | 113 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------- |
| M | shader.c | | | 6 | +++--- |
| M | stb_image.h | | | 60 | ++++++++++++++++++++++++++++++------------------------------ |
| M | test.c | | | 20 | ++++++++++++++------ |
| M | texture.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);