Setting up basic components and systems

This commit is contained in:
Carlos Sanchez 2024-09-08 23:04:57 -04:00
parent 1fddf39939
commit 8b227bf993
3 changed files with 303 additions and 24 deletions

74
ecs2.h
View File

@ -93,19 +93,77 @@ typedef int ecs_eid;
(_ecs)->entities[eid] |= type##_fl; \ (_ecs)->entities[eid] |= type##_fl; \
(_ecs)->c_##type[eid] = (type) (_ecs)->c_##type[eid] = (type)
// Internal-use loop for ECS_RUNSYSTEM
#define _ECS_RSLOOP(_i, _ecs, _comps) \
for (int _i = 0; _i < ECS_MAXENTITIES; _i++) \
if (((_ecs)->entities[_i] & _comps) == _comps)
// A shortcut to run a system against all matching components. You could also // A shortcut to run a system against all matching components. You could also
// use the query function for your ecs type if you don't want to use this macro. // define systems using ECS_SYSTEM1 etc. and call them per entity.
// Make sure you pass int the name of YOUR system, not the "run" function. This // Make sure you pass int the name of YOUR system, not the "run" function (you
// function bypasses // don't need the run function when using these macros)
#define ECS_RUNSYSTEM(_ecs, _comps, _system) \ #define ECS_RUNSYSTEM1(_ecs, _system, type1) \
{ \ { \
ecs_cid _realcomps = ECS_SELFFLAG | _comps; \ ecs_cid _ecsflags = ECS_SELFFLAG | type1##_fl; \
for (int __i = 0; __i < ECS_MAXENTITIES; __i++) { \ _ECS_RSLOOP(eid, _ecs, _ecsflags) { _system((_ecs)->c_##type1 + eid); } \
if ((_ecs->entities[__i] & _realcomps) == _realcomps) \ }
_system##_run(_ecs, __i); \
// A shortcut to run a system against all matching components. You could also
// define systems using ECS_SYSTEM2 etc. and call them per entity.
// Make sure you pass int the name of YOUR system, not the "run" function (you
// don't need the run function when using these macros)
#define ECS_RUNSYSTEM2(_ecs, _system, t1, t2) \
{ \
ecs_cid _ecsflags = ECS_SELFFLAG | t1##_fl | t2##_fl; \
_ECS_RSLOOP(eid, _ecs, _ecsflags) { \
_system((_ecs)->c_##t1 + eid, (_ecs)->c_##t2 + eid); \
} \ } \
} }
// A shortcut to run a system against all matching components. You could also
// define systems using ECS_SYSTEM3 etc. and call them per entity.
// Make sure you pass int the name of YOUR system, not the "run" function (you
// don't need the run function when using these macros)
#define ECS_RUNSYSTEM3(_ecs, _system, t1, t2, t3) \
{ \
ecs_cid _ecsflags = ECS_SELFFLAG | t1##_fl | t2##_fl | t3##_fl; \
_ECS_RSLOOP(eid, _ecs, _ecsflags) { \
_system((_ecs)->c_##t1 + eid, (_ecs)->c_##t2 + eid, \
(_ecs)->c_##t3 + eid); \
} \
}
// A shortcut to run a system against all matching components. You could also
// define systems using ECS_SYSTEM4 etc. and call them per entity.
// Make sure you pass int the name of YOUR system, not the "run" function (you
// don't need the run function when using these macros)
#define ECS_RUNSYSTEM4(_ecs, _system, t1, t2, t3, t4) \
{ \
ecs_cid _ecsflags = ECS_SELFFLAG | t1##_fl | t2##_fl | t3##_fl | t4##_fl; \
_ECS_RSLOOP(eid, _ecs, _ecsflags) { \
_system((_ecs)->c_##t1 + eid, (_ecs)->c_##t2 + eid, \
(_ecs)->c_##t3 + eid, (_ecs)->c_##t4 + eid); \
} \
}
// A shortcut to run a system against all matching components. You could also
// define systems using ECS_SYSTEM5 etc. and call them per entity.
// Make sure you pass int the name of YOUR system, not the "run" function (you
// don't need the run function when using these macros)
#define ECS_RUNSYSTEM5(_ecs, _system, t1, t2, t3, t4, t5) \
{ \
ecs_cid _ecsflags = \
ECS_SELFFLAG | t1##_fl | t2##_fl | t3##_fl | t4##_fl | t5##_fl; \
_ECS_RSLOOP(eid, _ecs, _ecsflags) { \
_system(_ecs->c_##t1 + eid, _ecs->c_##t2 + eid, _ecs->c_##t3 + eid, \
_ecs->c_##t4 + eid, _ecs->c_##t5 + eid); \
} \
}
// ---------------------------------------------------------
// YOU DON'T NEED THIS STUFF IF YOU USE ECS_RUNSYSTEM
// ---------------------------------------------------------
// Add a system function which automatically calls your given function with // Add a system function which automatically calls your given function with
// pre-pulled items from the entity component arrays. The new function is // pre-pulled items from the entity component arrays. The new function is
// named the same as the old one, just with _run appeneded // named the same as the old one, just with _run appeneded

199
terrain.c
View File

@ -3,29 +3,146 @@
#include "haloo3d/haloo3dex_gen.h" #include "haloo3d/haloo3dex_gen.h"
#include "haloo3d/haloo3dex_obj.h" #include "haloo3d/haloo3dex_obj.h"
#include "haloo3d/lib/mathc.h"
#include "unigi/unigi.headers/src/main.h" #include "unigi/unigi.headers/src/main.h"
#include "unigi/unigi.platform.sdl1/src/main.c" #include "unigi/unigi.platform.sdl1/src/main.c"
#include "ecs2.h" #include "ecs2.h"
// #include "keys.h"
#include "terrain_ecstypes.h" #include "terrain_ecstypes.h"
#include <stdlib.h> #include <stdlib.h>
#define WIDTH 480 #define WIDTH 480
#define HEIGHT 300 #define HEIGHT 300
#define ASPECT ((float)WIDTH / HEIGHT)
#define SCREENSCALE 2 #define SCREENSCALE 2
#define SWIDTH (WIDTH * SCREENSCALE) #define SWIDTH (WIDTH * SCREENSCALE)
#define SHEIGHT (HEIGHT * SCREENSCALE) #define SHEIGHT (HEIGHT * SCREENSCALE)
#define NEARCLIP 0.01
#define FARCLIP 100.0
#define AVGWEIGHT 0.85 #define AVGWEIGHT 0.85
// These are initial values but there may be ways to change it
#define CAM_INITPITCH MPI_2 #define CAM_INITPITCH MPI_2
#define INIT_NEARCLIP 0.01
#define INIT_FARCLIP 100.0
#define INIT_DITHERSTART 10000
#define INIT_DITHEREND 10000
// Try 0.5 and 3.5 or something // Some globals you can mess around with potentially
#define DITHERSTART 10000 int fps = 30;
#define DITHEREND 10000
// The terrain ecs systems
// All initialization for a specific render context
void sys_rendercontext(ecs_rendercontext *erc, ecs_placement *p) {
render_context *rc = *erc;
rc->precalc_halfwidth = rc->window.width * H3DVF(0.5);
rc->precalc_halfheight = rc->window.height * H3DVF(0.5);
haloo3d_perspective(rc->precalc_perspective, rc->fov,
(mfloat_t)rc->window.width / rc->window.height,
rc->nearclip, rc->farclip);
haloo3d_fb_cleardepth(&rc->window);
if (rc->windowclear & 0xF000) {
haloo3d_fb_clear(&rc->window, rc->windowclear);
}
}
// Apply rotation to lookvec of placement
void sys_rotation(ecs_placement *p, ecs_rotation *r) {
YAWP2VEC(r->yaw, r->pitch, p->lookvec.v);
}
void sys_movement(ecs_placement *p, ecs_movement *m) {
vec3_add(p->lookvec.v, p->lookvec.v, m->lookvec.v);
vec3_add(p->up.v, p->up.v, m->up.v);
vec3_add(p->pos.v, p->pos.v, m->pos.v);
}
// Perform the entire rendering of an object
void sys_renderobject(ecs_placement *p, ecs_object *o) {
struct vec3 lighting;
struct vec4 precalc_verts[H3D_OBJ_MAXVERTICES];
// First, precalc all the vertices in the object
// ------------------------------------------------------------------
mfloat_t tmp[VEC4_SIZE];
mfloat_t modelm[MAT4_SIZE];
mfloat_t finalmatrix[MAT4_SIZE];
vec3_add(tmp, p->pos.v, p->lookvec.v);
haloo3d_my_lookat(modelm, p->pos.v, tmp, p->up.v);
// Apply scale such that it looks like it was applied first (this prevents
// scaling applying skew to a rotated object)
haloo3d_mat4_prescalev(modelm, o->scale.v);
mat4_multiply(finalmatrix, o->context->precalc_screen, modelm);
haloo3d_precalc_verts(o->model, finalmatrix, precalc_verts);
// Next, setup some rendering invariants
// ------------------------------------------------------------------
o->context->rendersettings.texture = o->texture;
if (o->lighting) {
if (o->lighting->autolightfix) {
// Lighting doesn't rotate with the model unless you do it yourself.
// In the easy system, you can request the renderer to do it for you
struct vec4 ltmp, lout;
// Lighting is centered at 0
vec4(ltmp.v, 0, 0, 0, 1);
// Calc the same lookat just without translation. THis should be the same
// rotation matrix used on the model
haloo3d_my_lookat(modelm, ltmp.v, p->lookvec.v, p->up.v);
// We actually want the inverse. Apparently to speed things up, the
// transpose works for rotation matrices(?) but I don't trust that this
// lookat does that
// mat4_inverse(modelm, modelm);
mat4_transpose(modelm, modelm);
// We HAVE to have a vec4 (oof)
vec4(ltmp.v, o->lighting->dir.x, o->lighting->dir.y, o->lighting->dir.z,
1);
haloo3d_vec4_multmat_into(&ltmp, modelm, &lout);
// No need to fix W, should all be good (no perspective divide). But we DO
// need to pull out that result
vec3(lighting.v, lout.x, lout.y, lout.z);
vec3_normalize(lighting.v, lighting.v);
} else {
vec3_assign(lighting.v, o->lighting->dir.v);
}
}
// Finally, actually render faces
// ------------------------------------------------------------------
int totaldrawn = 0;
haloo3d_facef face, baseface;
haloo3d_facef outfaces[H3D_FACEF_MAXCLIP];
for (int facei = 0; facei < o->model->numfaces; facei++) {
// Copy face values out of precalc array and clip them
haloo3d_make_facef(o->model->faces[facei], precalc_verts,
o->model->vtexture, face);
int tris = haloo3d_facef_clip(face, outfaces);
if (tris > 0) {
uint8_t oflags = o->context->rendersettings.flags;
if (o->lighting) {
haloo3d_obj_facef(o->model, o->model->faces[facei], baseface);
o->context->rendersettings.intensity =
haloo3d_calc_light(lighting.v, o->lighting->minlight, baseface);
} else {
o->context->rendersettings.intensity = H3DVF(1.0);
}
// if ((r->_objstate[object - r->objects] & H3D_EASYOBJSTATE_NOTRANS)) {
// r->rendersettings.flags &= ~H3DR_TRANSPARENCY;
// }
for (int ti = 0; ti < tris; ti++) {
int backface = !haloo3d_facef_finalize(outfaces[ti]);
if (o->cullbackface && backface) {
continue;
}
totaldrawn++;
// We still have to convert the points into the view
haloo3d_facef_viewport_into_fast(outfaces[ti],
o->context->precalc_halfwidth,
o->context->precalc_halfheight);
haloo3d_triangle(&o->context->window, &o->context->rendersettings,
outfaces[ti]);
}
o->context->rendersettings.flags = oflags;
}
}
// return totaldrawn;
}
int main() { // int argc, char **argv) { int main() { // int argc, char **argv) {
srand(clock()); srand(clock());
@ -49,6 +166,8 @@ int main() { // int argc, char **argv) {
eprintf("Initialized storage and default textures/etc\n"); eprintf("Initialized storage and default textures/etc\n");
haloo3d_fb screen3d;
haloo3d_fb_init(&screen3d, WIDTH, HEIGHT);
haloo3d_fb screen; haloo3d_fb screen;
haloo3d_fb_init(&screen, SWIDTH, SHEIGHT); haloo3d_fb_init(&screen, SWIDTH, SHEIGHT);
@ -59,6 +178,74 @@ int main() { // int argc, char **argv) {
haloo3d_easytimer_init(&filltimer, AVGWEIGHT); haloo3d_easytimer_init(&filltimer, AVGWEIGHT);
haloo3d_easytimer_init(&logictimer, AVGWEIGHT); haloo3d_easytimer_init(&logictimer, AVGWEIGHT);
eprintf("Initialized screen buffers and timers\n");
tecs ecs;
tecs_init(&ecs);
// MAIN LOOP
while (1) {
haloo3d_easytimer_start(&frametimer);
do {
unigi_event_get(&event);
switch (event.type) {
case unigi_enum_event_input_keyboard:
if (event.data.input_keyboard.down) {
switch (event.data.input_keyboard.button) {
// case KEY_SPACE:
// haloo3d_debugconsole_beginprompt(&dc);
// break;
default:
exit(0);
}
}
break;
}
} while (event.type != unigi_enum_event_none);
// ECS logic (which includes rendering)
ECS_RUNSYSTEM2(&ecs, sys_rotation, ecs_placement, ecs_rotation);
ECS_RUNSYSTEM2(&ecs, sys_movement, ecs_placement, ecs_movement);
ECS_RUNSYSTEM2(&ecs, sys_rendercontext, ecs_rendercontext, ecs_placement);
ECS_RUNSYSTEM2(&ecs, sys_renderobject, ecs_placement, ecs_object);
// Scale 3D into final buffer
haloo3d_easytimer_start(&filltimer);
haloo3d_fb_fill(&screen, &screen3d);
haloo3d_easytimer_end(&filltimer);
/*
haloo3d_print(&render.tprint,
"Pframe: %05.2f (%05.2f)\nPSDLFl: %05.2f "
"(%05.2f)\nFill: %05.2f "
"(%05.2f)\nLogic: %05.2f (%05.2f)\nTris: %d / %d\nVerts: "
"%d\nWState: %d",
frametimer.last * 1000, frametimer.sum * 1000,
sdltimer.last * 1000, sdltimer.sum * 1000,
filltimer.last * 1000, filltimer.sum * 1000,
logictimer.last * 1000, logictimer.sum * 1000, totaldrawn,
render.totalfaces, render.totalverts, wstate.state);
*/
// Finally, actually put buffer onto screen
haloo3d_easytimer_start(&sdltimer);
unigi_graphics_blit(0, (unigi_type_color *)screen.buffer,
res.width * res.height);
unigi_graphics_flush();
haloo3d_easytimer_end(&sdltimer);
haloo3d_easytimer_end(&frametimer);
// Wait for next frame based on fps
float waittime = (1.0 / fps) - frametimer.last;
if (waittime > 0) {
unigi_time_sleep(waittime * unigi_time_clocks_per_s);
}
}
haloo3d_fb_free(&screen);
haloo3d_fb_free(&screen3d);
haloo3d_easystore_deleteallobj(&storage, haloo3d_obj_free); haloo3d_easystore_deleteallobj(&storage, haloo3d_obj_free);
haloo3d_easystore_deletealltex(&storage, haloo3d_fb_free); haloo3d_easystore_deletealltex(&storage, haloo3d_fb_free);
} }

View File

@ -11,31 +11,47 @@
typedef struct { typedef struct {
// struct vec4 precalcs[H3D_OBJ_MAXVERTICES]; // struct vec4 precalcs[H3D_OBJ_MAXVERTICES];
// haloo3d_facef outfaces[H3D_FACEF_MAXCLIP]; // haloo3d_facef outfaces[H3D_FACEF_MAXCLIP];
mfloat_t perspective[MAT4_SIZE]; // haloo3d_perspective(render.perspective, fov, ASPECT, NEARCLIP, FARCLIP);
mfloat_t precalc_perspective[MAT4_SIZE];
mfloat_t precalc_screen[MAT4_SIZE]; mfloat_t precalc_screen[MAT4_SIZE];
mfloat_t precalc_halfwidth; // Optimization for reducing calcs per tri
mfloat_t precalc_halfheight; // Optimization for reducing calcs per tri
mfloat_t fov;
mfloat_t nearclip;
mfloat_t farclip;
// NOTE: aspect ratio calculated from window
haloo3d_fb window; haloo3d_fb window;
// Baseline render settings. Some of these settings will be applied to // Baseline render settings. Some of these settings will be applied to
// each object associated with this context // each object associated with this context
haloo3d_trirender rendersettings; haloo3d_trirender rendersettings;
mfloat_t precalc_halfwidth; // Optimization for reducing calcs per tri // If alpha is 0, screen is not cleared
mfloat_t precalc_halfheight; // Optimization for reducing calcs per tri uint16_t windowclear;
} render_context; } render_context;
// Associate this to some entity along with a placement and it will be the // Associate this to some entity along with a placement and it will be the
// main "renderer" for a viewpoint // main "renderer" for a viewpoint
typedef render_context *ecs_rendercontext; typedef render_context *ecs_rendercontext;
// All values which allow rendering of a 3d object // Associate lighting with some object. Since this is part of the renderer,
// this isn't a component you can assign (it also doesn't mean anything on its
// own)
typedef struct { typedef struct {
struct vec3 scale; // how big the thing should be in world struct vec3 dir;
struct vec3 *lighting; // a pointer to lighting, null for none mfloat_t minlight;
render_context *context; // What to render into
haloo3d_obj *model;
haloo3d_fb *texture;
uint8_t cullbackface; // Whether to cull backfaces (you probably should)
// Whether to automatically move lighting when models have a // Whether to automatically move lighting when models have a
// lookvec. This also normalizes the light // lookvec. This also normalizes the light
uint8_t autolightfix; uint8_t autolightfix;
} object_lighting;
// All values which allow rendering of a 3d object
typedef struct {
// haloo3d_trirender rendersettings; // baseline settings for THIS object.
struct vec3 scale; // how big the thing should be in world
object_lighting *lighting; // a pointer to lighting, null for none
render_context *context; // What to render into
haloo3d_obj *model;
haloo3d_fb *texture;
uint8_t cullbackface; // Whether to cull backfaces (you probably should)
} ecs_object; } ecs_object;
// Some placement within the world. Doesn't imply anything other than a // Some placement within the world. Doesn't imply anything other than a
@ -46,6 +62,20 @@ typedef struct {
struct vec3 lookvec; struct vec3 lookvec;
} ecs_placement; } ecs_placement;
// Movement is applied to placement and may also be used to check for
// collisions and whatever
typedef struct {
struct vec3 pos;
struct vec3 up;
struct vec3 lookvec;
} ecs_movement;
// Use rotation to override the lookvec of an ecs_placement
typedef struct {
mfloat_t yaw;
mfloat_t pitch;
} ecs_rotation;
// typedef haloo3d_camera *ecs_camera; // typedef haloo3d_camera *ecs_camera;
// typedef haloo3d_obj_instance *ecs_object; // typedef haloo3d_obj_instance *ecs_object;
@ -73,11 +103,15 @@ ECS_START(tecs)
ECS_COMPONENT(ecs_rendercontext); ECS_COMPONENT(ecs_rendercontext);
ECS_COMPONENT(ecs_object); ECS_COMPONENT(ecs_object);
ECS_COMPONENT(ecs_placement); ECS_COMPONENT(ecs_placement);
ECS_COMPONENT(ecs_rotation);
ECS_COMPONENT(ecs_movement);
ECS_END(tecs) ECS_END(tecs)
// And then a copy of the components here... that sucksssss // And then a copy of the components here... that sucksssss
ECS_CID(ecs_rendercontext, 0); ECS_CID(ecs_rendercontext, 0);
ECS_CID(ecs_object, 1); ECS_CID(ecs_object, 1);
ECS_CID(ecs_placement, 2); ECS_CID(ecs_placement, 2);
ECS_CID(ecs_rotation, 3);
ECS_CID(ecs_movement, 4);
#endif #endif