Paintings ALMOST worked

This commit is contained in:
Carlos Sanchez 2024-08-21 23:52:01 -04:00
parent 29c5ece6da
commit aa0c785a49
6 changed files with 398 additions and 1465 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@ ignore/
*.obj
*.cam
*.tar.gz
*.Identifier
callgrind.*
# Images

53
ecs2.h
View File

@ -11,41 +11,64 @@
#define ECS_MAXENTITIES 1024
#endif
#define ECS_MAXCTYPES 63 // uint64 bits minus one
// We reserve one slot to automatically point back to the ecs system.
// This is the unusable 64th ID = 63 (your ids should start from 0)
#define ECS_MAXCTYPES 63
// The self flag is an ID that will get you back a component that is
// the ecs system itself. It is ALSO used to identify is an entity is
// valid, as ALL entities will implicitly have the ECS component
#define ECS_SELFFLAG (1ULL << ECS_MAXCTYPES)
typedef unsigned long long ecs_cid;
typedef int ecs_eid;
#define ECS_START(name) \
typedef struct { \
typedef struct name name; \
struct name { \
ecs_cid entities[ECS_MAXENTITIES]; \
ecs_eid entitytop;
ecs_eid entitytop; \
name *c_##name[ECS_MAXENTITIES];
#define ECS_END(name) \
} \
name; \
; \
/* Always initialize the ecs system when you create a new one! */ \
static void name##_init(name *_ecs) { memset(_ecs, 0, sizeof(name)); } \
/* Create an entity with the given base components (usually 0) */ \
static ecs_eid name##_newentity(name *_ecs, ecs_cid basecomponents) { \
for (int i = 0; i < ECS_MAXENTITIES; i++) { \
ecs_eid id = _ecs->entitytop++; \
ecs_eid id = _ecs->entitytop; \
_ecs->entitytop = (_ecs->entitytop + 1) % ECS_MAXENTITIES; \
if (_ecs->entities[id] == 0) { \
_ecs->entities[id] = (1ULL << ECS_MAXCTYPES) | basecomponents; \
_ecs->entities[id] = ECS_SELFFLAG | basecomponents; \
_ecs->c_##name[id] = _ecs; \
return id; \
} \
} \
return -1; \
} \
/* Delete an entity by eid from the given ecs sys */ \
static void name##_deleteentity(name *_ecs, ecs_eid eid) { \
if (eid >= 0 && eid < ECS_MAXENTITIES) \
_ecs->entities[eid] = 0; \
} \
/* Whether an entity matches a given list of components by flag */ \
static int name##_match(name *_ecs, ecs_eid _eid, ecs_cid _comps) { \
ecs_cid _realcomps = (1ULL << ECS_MAXCTYPES) | _comps; \
ecs_cid _realcomps = ECS_SELFFLAG | _comps; \
return (_ecs->entities[_eid] & _realcomps) == _realcomps; \
}
} \
/* Calculate the eid from a double ecs pointer. Useful to get eid in sys */ \
static ecs_eid name##_eid(name **_ecs) { \
return (ecs_eid)(_ecs - (*_ecs)->c_##name); \
} \
const ecs_cid name##_fl = ECS_SELFFLAG;
// Create an ECS component within an ECS struct
#define ECS_COMPONENT(type) type c_##type[ECS_MAXENTITIES];
// Define the CIDs necessary to access a component (each component MUST
// have a unique id and I can't do that inside a macro without requiring
// extensions)
#define ECS_CID(type, id) \
const int type##_id = id; \
const ecs_cid type##_fl = (1ULL << id);
@ -116,4 +139,18 @@ typedef int ecs_eid;
} \
}
// Add a system function which automatically calls your given function with
// pre-pulled items from the entity component arrays. The new function is
// named the same as the old one, just with _run appeneded
#define ECS_SYSTEM6(ecsname, fname, type1, type2, type3, type4, type5, type6) \
void fname##_run(ecsname *_ecs, ecs_eid eid) { \
ecs_cid _ecsflags = type1##_fl | type2##_fl | type3##_fl | type4##_fl | \
type5##_fl | type6##_fl; \
if (ecsname##_match(_ecs, eid, _ecsflags)) { \
fname(_ecs->c_##type1 + eid, _ecs->c_##type2 + eid, \
_ecs->c_##type3 + eid, _ecs->c_##type4 + eid, \
_ecs->c_##type5 + eid, _ecs->c_##type6 + eid); \
} \
}
#endif

@ -1 +1 @@
Subproject commit 8d814bd4abae2fb0113e5675f838ed2caa4e938f
Subproject commit 96dbee2942ae8b3d09302a24b075024c8134bb55

347
maze.c
View File

@ -9,8 +9,11 @@
#include "unigi/unigi.headers/src/main.h"
#include "unigi/unigi.platform.sdl1/src/main.c"
#define ECS_MAXENTITIES 100
#include "ecs2.h"
#include "keys.h"
#include "maze_ecstypes.h"
#include <stdlib.h>
@ -20,7 +23,7 @@
#define WIDTH 320
#define HEIGHT 200
#define ASPECT ((float)WIDTH / HEIGHT)
#define SCREENSCALE 2
#define SCREENSCALE 1
#define SWIDTH (WIDTH * SCREENSCALE)
#define SHEIGHT (HEIGHT * SCREENSCALE)
#define NEARCLIP 0.01
@ -29,8 +32,9 @@
#define AVGWEIGHT 0.85
// Game options
#define MAZESIZE 15
#define MAZESIZE 5
#define HSCALE 1.5
#define PAINTINGODDS 2
// Maze grows in the positive direction
#define MAZENORTH 1
@ -51,6 +55,8 @@
#define STACKPUSH(s, t, v) s[t++] = v;
#define ENDTEXTURE "resources/mazeend.ppm"
#define PAINTINGTEXTURE "resources/specwall.ppm"
#define PAINTINGNAME "painting"
// Store all the values users can change at the beginning
float ditherstart = -1;
@ -229,18 +235,63 @@ void maze_generate(uint8_t *maze, int size, struct vec2i *start,
free(mazestack);
}
void maze_wall_generate(uint8_t *maze, int size, haloo3d_obj *obj) {
// int rand_painting(int size) {
// return (rand() % ()) == 0;
// }
void create_painting(struct vec2i mazepos, uint8_t dir,
haloo3d_easyinstancer *ins, mecs *ecs, ecs_world *world) {
// Create the painting render instance, set up the ecs instance, etc.
haloo3d_obj_instance *painting = haloo3d_easyinstantiate(ins, PAINTINGNAME);
ecs_eid id = mecs_newentity(ecs, 0);
ECS_SETCOMPONENT(ecs, id, ecs_syncgrow){.obj = painting,
.scale = &world->scaleto,
.basescale = 1,
.timer = &world->scaletimer};
ECS_SETCOMPONENT(ecs, id, ecs_dieoninit){
.obj = painting, .render = ins->render, .ws = world->state};
// Fix up some things based on dir.
switch (dir) {
case DIRNORTH:
mazepos.y++;
break;
case DIREAST: // East also needs the rotation from west
mazepos.x++;
// fall through
case DIRWEST:
vec3(painting->lookvec.v, 1, 0, 0);
break;
}
// OK now that it's setup, we need to put it in the right spot and scale it
vec3(painting->pos.v, mazepos.x * world->state->cellsize, 0,
mazepos.y * world->state->cellsize);
vec3(painting->scale.v, HSCALE, world->scaleto, HSCALE);
// rotation is around the left edge. That's both where we put it AND
// where the painting rotates around.
}
// Generate walls AND create paintings. Kind of doing too much
void maze_wall_generate(uint8_t *maze, int size, haloo3d_obj *obj,
haloo3d_easyinstancer *ins, mecs *ecs,
ecs_world *world) {
// Reset ALL walls
obj->numfaces = 0;
// Simple: for each cell, we check if north or east is a wall. If so,
// generate it. Also, generate walls for the south and west global wall
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
struct vec2i mazepos = {.x = x, .y = y};
if (!maze_connected(maze, x, y, size, DIREAST)) {
haloo3d_gen_grid_quad(obj, x, y, dirtovec(DIREAST));
if ((rand() % PAINTINGODDS) == 0) {
create_painting(mazepos, DIREAST, ins, ecs, world);
}
}
if (!maze_connected(maze, x, y, size, DIRNORTH)) {
haloo3d_gen_grid_quad(obj, x, y, dirtovec(DIRNORTH));
if ((rand() % PAINTINGODDS) == 0) {
create_painting(mazepos, DIRNORTH, ins, ecs, world);
}
}
}
}
@ -250,21 +301,33 @@ void maze_wall_generate(uint8_t *maze, int size, haloo3d_obj *obj) {
}
}
// Turning into a blob? IDK. Maybe certain things should be
// global state, which is this.
typedef struct {
// float timedelta;
int fps;
uint8_t state;
uint8_t maze[MAZESIZE * MAZESIZE];
// int size;
// A suggested start and end. The end is the actual
// end, where we put the ending indicator
struct vec2i start;
struct vec2i end;
// Some simple calcs for you to use
mfloat_t cellsize;
} worldstate;
// // A simple linked list of objects
// struct objlist {
// haloo3d_obj_instance *obj;
// struct objlist *next;
// };
//
// // Add a new link at the given elem
// struct objlist *objlist_add(struct objlist *elem, haloo3d_obj_instance *obj)
// {
// mallocordie(elem->next, sizeof(struct objlist *));
// elem->next->obj = obj;
// elem->next->next = NULL;
// return elem->next;
// }
//
// // Free every single element starting at head
// void objlist_free(struct objlist *head, haloo3d_easyrender *r) {
// // void (*freefunc)(haloo3d_obj_instance *obj)) {
// if (head) {
// objlist_free(head->next, r);
// haloo3d_easyrender_deleteinstance(r, head->obj);
// // if (freefunc) {
// // freefunc(head->obj);
// //}
// free(head);
// }
// }
enum {
WSTATE_INIT = 0,
@ -274,61 +337,6 @@ enum {
WSTATE_SPINDOWN = 4
};
// A component that stores a position and a facing direction
// as an angle
typedef struct {
struct vec3 pos;
struct vec2 rot; // x is yaw, y is pitch
} ecs_placement;
// A component which links back to a camera
typedef struct {
haloo3d_camera *camera;
} ecs_camera;
// A component which allows automatic navigation
// of position through the use of timers.
typedef struct {
struct vec3 dest;
int timer;
} ecs_autonav;
// A component which allows automatic rotation
// through the use of timers.
typedef struct {
struct vec2 dest; // x is yaw, y is pitch
int timer;
} ecs_autorotate;
// Component which enables synchronized scale y from 0 to 1 or 1 to 0. It is
// expected that an external source is modifying the value
typedef struct {
haloo3d_obj_instance *obj;
mfloat_t *scale;
// When scales are set, they're multiplied by this
mfloat_t basescale;
int *timer;
} ecs_syncgrow;
// A billboard for OUR system, which does not look up or down at the target. As
// such, no matter what the lookat is set to, y is always going to be equal to
// the y of the instance, so it appears to be looking "straight"
typedef struct {
haloo3d_obj_instance *obj;
struct vec3 *lookat;
} ecs_billboard;
// A component which holds onto data specifically for world
// entities. You can think of it as private data so people
// can't poke at the worldstate data
typedef struct {
worldstate *state;
haloo3d_obj *wallmodel;
haloo3d_obj_instance *endobj;
int scaletimer;
mfloat_t scaleto;
} ecs_world;
void sys_billboard(ecs_billboard *bb) {
// In our current system, the lookvec is the direction it wants to face, not a
// "lookat" point. To lookat something, you simply get the vector pointing
@ -397,12 +405,27 @@ void sys_camera(ecs_camera *cam, ecs_placement *p) {
cam->camera->pitch = p->rot.y;
}
void sys_world(ecs_world *w) {
void sys_dieoninit(ecs_dieoninit *die, mecs **ecs) {
if (die->ws->state == WSTATE_INIT) {
ecs_eid id = mecs_eid(ecs);
eprintf("DELETING SELF: %d\n", id);
// Trivially delete the entity from the renderer
haloo3d_easyrender_deleteinstance(die->render, die->obj);
// Delete ourselves from existence
mecs_deleteentity(*ecs, id);
}
}
void sys_world(ecs_world *w, mecs **ecs) {
const int spinspeed = w->state->fps * 4.0 / (5 * speed);
switch (w->state->state) {
case WSTATE_INIT:
maze_generate(w->state->maze, MAZESIZE, &w->state->start, &w->state->end);
maze_wall_generate(w->state->maze, MAZESIZE, w->wallmodel);
// We don't need to free anything created from previous runs; they delete
// themselves
maze_generate(w->state->maze, w->state->size, &w->state->start,
&w->state->end);
maze_wall_generate(w->state->maze, w->state->size, w->wallmodel,
w->instancer, *ecs, w);
eprintf("INIT MAZE COMPLETE, spinning up walls\n");
maze_to_pos(&w->state->end, w->endobj->pos.v, w->state->cellsize);
w->state->state = WSTATE_SPINUP;
@ -441,18 +464,6 @@ enum {
SAI_GAMEPLAY,
};
// State for tracking a smart ai moving through the maze.
typedef struct {
uint8_t state;
// uint8_t rotstate;
uint8_t dir;
uint32_t timer;
mfloat_t rotchange;
struct vec2i mpos;
worldstate *ws;
haloo3d_obj_instance *startmarker;
} ecs_smartai;
int smartai_mazeend(ecs_smartai *smartai) {
if (smartai->mpos.x == smartai->ws->end.x &&
smartai->mpos.y == smartai->ws->end.y) {
@ -464,8 +475,8 @@ int smartai_mazeend(ecs_smartai *smartai) {
return 0;
}
static void sys_smartai(ecs_smartai *smartai, ecs_placement *p,
ecs_autonav *anav, ecs_autorotate *arot) {
void sys_smartai(ecs_smartai *smartai, ecs_placement *p, ecs_autonav *anav,
ecs_autorotate *arot) {
const int actiontime = smartai->ws->fps / (2 * speed);
const int rotdelaytime = actiontime / 2; // 2 * actiontime / 5;
switch (smartai->state) {
@ -475,8 +486,8 @@ static void sys_smartai(ecs_smartai *smartai, ecs_placement *p,
if (smartai->ws->state == WSTATE_SPINUP) {
smartai->mpos = smartai->ws->start;
smartai->dir =
maze_longesthallway(smartai->ws->maze, MAZESIZE, smartai->ws->start.x,
smartai->ws->start.y);
maze_longesthallway(smartai->ws->maze, smartai->ws->size,
smartai->ws->start.x, smartai->ws->start.y);
maze_to_pos(&smartai->ws->start, p->pos.v, smartai->ws->cellsize);
p->rot.x = dirtoyaw(smartai->dir);
// Move startmarker to in front of player.
@ -527,7 +538,7 @@ static void sys_smartai(ecs_smartai *smartai, ecs_placement *p,
}
// Player can only move forward if there's nothing in front of them
if (maze_connected(smartai->ws->maze, smartai->mpos.x, smartai->mpos.y,
MAZESIZE, smartai->dir)) {
smartai->ws->size, smartai->dir)) {
struct vec2i movement = dirtovec(smartai->dir);
smartai->mpos.x += movement.x;
smartai->mpos.y += movement.y;
@ -538,12 +549,12 @@ static void sys_smartai(ecs_smartai *smartai, ecs_placement *p,
// Figure out if a rotation should be scheduled
if (!(smartai->mpos.x == smartai->ws->end.x &&
smartai->mpos.y == smartai->ws->end.y)) {
// Ok we might be moving, we might not be. Let's go ahead and calculate
// rotation based on the FUTURE direction we want to turn.
// Ok we might be moving, we might not be. Let's go ahead and
// calculate rotation based on the FUTURE direction we want to turn.
uint8_t rightdir = TURNRIGHT(smartai->dir);
uint8_t leftdir = TURNLEFT(smartai->dir);
if (maze_connected(smartai->ws->maze, smartai->mpos.x, smartai->mpos.y,
MAZESIZE, rightdir)) {
smartai->ws->size, rightdir)) {
// Always choose right over left
smartai->rotchange += MPI_2;
smartai->timer = rotdelaytime;
@ -553,7 +564,8 @@ static void sys_smartai(ecs_smartai *smartai, ecs_placement *p,
// This while loop lets us turn around if necessary, so reaching a
// dead end isn't super painful waiting for two rotations
while (!maze_connected(smartai->ws->maze, smartai->mpos.x,
smartai->mpos.y, MAZESIZE, smartai->dir)) {
smartai->mpos.y, smartai->ws->size,
smartai->dir)) {
// We seem to have reached a wall. Do we need to turn ALL the way
// around? We only move left if the player can't move forward or
// right
@ -570,30 +582,8 @@ static void sys_smartai(ecs_smartai *smartai, ecs_placement *p,
}
}
// Setup ECS system for our game
ECS_START(mecs)
ECS_COMPONENT(ecs_world);
ECS_COMPONENT(ecs_autonav);
ECS_COMPONENT(ecs_autorotate);
ECS_COMPONENT(ecs_placement);
ECS_COMPONENT(ecs_camera);
ECS_COMPONENT(ecs_smartai);
ECS_COMPONENT(ecs_syncgrow);
ECS_COMPONENT(ecs_billboard);
ECS_END(mecs)
// And then a copy of the components here... that sucksssss
ECS_CID(ecs_worldstate, 0);
ECS_CID(ecs_world, 1);
ECS_CID(ecs_autonav, 2);
ECS_CID(ecs_autorotate, 3);
ECS_CID(ecs_placement, 4);
ECS_CID(ecs_camera, 5);
ECS_CID(ecs_smartai, 6);
ECS_CID(ecs_syncgrow, 7);
ECS_CID(ecs_billboard, 8);
ECS_SYSTEM1(mecs, sys_world, ecs_world);
ECS_SYSTEM2(mecs, sys_world, ecs_world, mecs);
ECS_SYSTEM2(mecs, sys_dieoninit, ecs_dieoninit, mecs);
ECS_SYSTEM1(mecs, sys_syncgrow, ecs_syncgrow);
ECS_SYSTEM1(mecs, sys_billboard, ecs_billboard);
ECS_SYSTEM2(mecs, sys_autonav, ecs_autonav, ecs_placement);
@ -602,6 +592,41 @@ ECS_SYSTEM2(mecs, sys_camera, ecs_camera, ecs_placement);
ECS_SYSTEM4(mecs, sys_smartai, ecs_smartai, ecs_placement, ecs_autonav,
ecs_autorotate);
// typedef struct {
// haloo3d_easyrender *render;
// haloo3d_obj_instance *paintings[MAXPAINTINGS];
// ecs_eid paintingecs[MAXPAINTINGS];
// haloo3d_fb *texture;
// haloo3d_obj *model;
// mecs *ecs;
// mfloat_t *scaleto;
// int *scaletimer;
// int numpaintings;
// } paintingmanager;
//
// void pm_add_painting(paintingmanager *pm) {
// if (pm->numpaintings < MAXPAINTINGS) {
// pm->paintings[pm->numpaintings] =
// haloo3d_easyrender_addinstance(pm->render, pm->model, pm->texture);
// ecs_eid id = mecs_newentity(pm->ecs, 0);
// ECS_SETCOMPONENT(pm->ecs, id,
// ecs_syncgrow){.obj = pm->paintings[pm->numpaintings],
// .scale = pm->scaleto,
// .basescale = 1,
// .timer = pm->scaletimer};
// pm->paintingecs[pm->numpaintings] = id;
// pm->numpaintings++;
// }
// }
//
// void pm_clear_all(paintingmanager * pm) {
// for(int i = 0; i < pm->numpaintings; i++) {
// mecs_deleteentity(pm->ecs, pm->paintingecs[i]);
// haloo3d_easyrender_deleteinstance(pm->render, pm->paintings[i]);
// }
// pm->numpaintings = 0;
// }
void init_floortexture(haloo3d_fb *floort) {
uint16_t cols[1] = {0xFD93};
haloo3d_fb_init_tex(floort, 64, 64);
@ -679,6 +704,10 @@ void init_endtexture(haloo3d_fb *endt) {
haloo3d_img_totransparent(endt, haloo3d_fb_get(endt, 0, 0));
}
void init_paintingtexture(haloo3d_fb *endt) {
haloo3d_img_loadppmfile(endt, PAINTINGTEXTURE);
}
void init_billboard(haloo3d_obj_instance *bb, mfloat_t scale) {
// Haven't actually generated the object yet, oops. We don't let billboards
// all share the same model, as they might require slightly different
@ -711,6 +740,56 @@ void init_mazeinstances(haloo3d_obj_instance *floori,
ceili->pos.y = 1;
}
// Given a pointer into an obj, fill it with everything required to make
// the painting that clips with the wall (it's a cube)
void create_paintingobj(haloo3d_obj *obj) {
// 2 for each face; we have 4 faces (top and bottom don't need anything)
haloo3d_gen_obj_prealloc(obj, 8, 8, 8);
// ppm is 128x128 but 1 pixel along the top is the wall side
const mfloat_t ptextop = 1.0 / 128.0;
const mfloat_t thickness = 1.0 / 64.0;
// box will be aligned along x/y axis, so it will be "facing" the negative z
// dir like most other models. Box is topleft, topright, bottomleft,
// bottomright, then same on other side. Box is not centered around 0,
// intstead it is the same as a wall where iti starts from y=0 and goes to
// y=1
vec4(obj->vertices[0].v, 0, 1, thickness, 1);
vec4(obj->vertices[1].v, 1, 1, thickness, 1);
vec4(obj->vertices[2].v, 0, 0, thickness, 1);
vec4(obj->vertices[3].v, 1, 0, thickness, 1);
vec4(obj->vertices[4].v, 0, 1, -thickness, 1);
vec4(obj->vertices[5].v, 1, 1, -thickness, 1);
vec4(obj->vertices[6].v, 0, 0, -thickness, 1);
vec4(obj->vertices[7].v, 1, 0, -thickness, 1);
// Now, the vtexture points. Some might be dupes, I don't care. First 4 are
// the painting texture, next 4 are the wall texture
vec3(obj->vtexture[0].v, 0.001, 0.999 - ptextop, 0);
vec3(obj->vtexture[1].v, 0.999, 0.999 - ptextop, 0);
vec3(obj->vtexture[2].v, 0.001, 0.001, 0);
vec3(obj->vtexture[3].v, 0.999, 0.001, 0);
vec3(obj->vtexture[4].v, 0.001, 0.999, 0);
vec3(obj->vtexture[5].v, 0.999, 0.999, 0);
vec3(obj->vtexture[6].v, 0.001, 1.0 - ptextop, 0);
vec3(obj->vtexture[7].v, 0.999, 1.0 - ptextop, 0);
// Preconstruct the simplified format of the face vertices and vtexture.
// First 3 are vertices, next are vtexture
// clang-format: off
const uint8_t f[8][6] = {
{0, 2, 3, 0, 2, 3}, // front face
{0, 3, 1, 0, 3, 1}, {5, 7, 6, 0, 2, 3}, // back face
{5, 6, 4, 0, 3, 1}, {1, 3, 7, 4, 6, 7}, // front side
{1, 7, 5, 4, 7, 5}, {4, 6, 2, 4, 6, 7}, // back side
{4, 2, 0, 4, 7, 5},
};
// clang-format: on
for (int fi = 0; fi < obj->numfaces; fi++) {
for (int v = 0; v < 3; v++) {
obj->faces[fi][v].posi = f[fi][v];
obj->faces[fi][v].texi = f[fi][v + 3];
}
}
}
int main() { // int argc, char **argv) {
haloo3d_easystore storage;
@ -725,6 +804,8 @@ int main() { // int argc, char **argv) {
render.tprint.fb = &screen;
eprintf("Initialized renderer\n");
haloo3d_easyinstancer instancer = {.storage = &storage, .render = &render};
haloo3d_easytimer frametimer, sdltimer, filltimer, logictimer;
haloo3d_easytimer_init(&frametimer, AVGWEIGHT);
haloo3d_easytimer_init(&sdltimer, AVGWEIGHT);
@ -736,31 +817,40 @@ int main() { // int argc, char **argv) {
haloo3d_obj *wallo = haloo3d_easystore_addobj(&storage, "walls");
haloo3d_obj *starto = haloo3d_easystore_addobj(&storage, "start");
haloo3d_obj *endo = haloo3d_easystore_addobj(&storage, "end");
haloo3d_obj *paintingo = haloo3d_easystore_addobj(&storage, PAINTINGNAME);
haloo3d_fb *floort = haloo3d_easystore_addtex(&storage, "floor");
haloo3d_fb *ceilt = haloo3d_easystore_addtex(&storage, "ceiling");
haloo3d_fb *wallt = haloo3d_easystore_addtex(&storage, "walls");
haloo3d_fb *startt = haloo3d_easystore_addtex(&storage, "start");
haloo3d_fb *endt = haloo3d_easystore_addtex(&storage, "end");
haloo3d_fb *paintingt = haloo3d_easystore_addtex(&storage, PAINTINGNAME);
haloo3d_gen_plane(planeo, MAZESIZE);
haloo3d_gen_grid(wallo, MAZESIZE, 0);
create_paintingobj(paintingo);
init_floortexture(floort);
init_ceilingtexture(ceilt);
init_walltexture(wallt);
init_starttexture(startt);
init_endtexture(endt);
init_paintingtexture(paintingt);
eprintf("Initialized models and textures\n");
worldstate wstate;
memset(&wstate, 0, sizeof(worldstate));
// The maze won't change size (for now), so we can set it here to some
// constant array
uint8_t maze[MAZESIZE * MAZESIZE];
wstate.size = MAZESIZE;
wstate.maze = maze;
wstate.fps = fps;
wstate.state = WSTATE_INIT;
wstate.cellsize = HSCALE;
// Lighting. Note that for performance, the lighting is always calculated
// against the base model, and is thus not realistic if the object rotates in
// the world. This can be fixed easily, since each object gets its own
// against the base model, and is thus not realistic if the object rotates
// in the world. This can be fixed easily, since each object gets its own
// lighting vector, which can easily be rotated in the opposite direction of
// the model
struct vec3 light;
@ -779,7 +869,7 @@ int main() { // int argc, char **argv) {
init_mazeinstances(floori, ceili, walli);
init_billboard(starti, 1.0);
init_billboard(endi, 0.25);
eprintf("Setup all object instances\n");
eprintf("Setup all static object instances\n");
unigi_type_event event;
unigi_type_resolution res;
@ -817,11 +907,15 @@ int main() { // int argc, char **argv) {
// Set up ECS entities. For this game, we mostly have global entities.
mecs ecs;
mecs_init(&ecs);
eprintf("ECS sys size: %zu\n", sizeof(mecs));
ecs_eid worldid = mecs_newentity(&ecs, 0);
eprintf("World eid: %d\n", worldid);
ECS_SETCOMPONENT(&ecs, worldid, ecs_world){
.state = &wstate, .wallmodel = wallo, .endobj = endi, .scaletimer = 0};
ECS_SETCOMPONENT(&ecs, worldid, ecs_world){.state = &wstate,
.wallmodel = wallo,
.endobj = endi,
.scaletimer = 0,
.instancer = &instancer};
ecs_world *eworld = ecs.c_ecs_world + worldid;
// Setup some dynamic objects
@ -909,6 +1003,7 @@ int main() { // int argc, char **argv) {
sys_autorotate_run(&ecs, i);
sys_camera_run(&ecs, i);
sys_billboard_run(&ecs, i);
sys_dieoninit_run(&ecs, i);
}
haloo3d_easytimer_end(&logictimer);

125
maze_ecstypes.h Normal file
View File

@ -0,0 +1,125 @@
#ifndef __MAZE_ECSTYPES
#define __MAZE_ECSTYPES
#include "ecs2.h"
#include "haloo3d/haloo3d.h"
#include "haloo3d/haloo3dex_easy.h"
// Turning into a blob? IDK. Maybe certain things should be
// global state, which is this.
typedef struct {
// float timedelta;
int fps;
uint8_t state;
uint8_t *maze; //[MAZESIZE * MAZESIZE];
int size; // The length of an edge, guaranteed to be a square
// A suggested start and end. The end is the actual
// end, where we put the ending indicator
struct vec2i start;
struct vec2i end;
// Some simple calcs for you to use
mfloat_t cellsize;
} worldstate;
// A component that stores a position and a facing direction
// as an angle
typedef struct {
struct vec3 pos;
struct vec2 rot; // x is yaw, y is pitch
} ecs_placement;
// A component which links back to a camera
typedef struct {
haloo3d_camera *camera;
} ecs_camera;
// A component which allows automatic navigation
// of position through the use of timers.
typedef struct {
struct vec3 dest;
int timer;
} ecs_autonav;
// A component which allows automatic rotation
// through the use of timers.
typedef struct {
struct vec2 dest; // x is yaw, y is pitch
int timer;
} ecs_autorotate;
// Component which enables synchronized scale y from 0 to 1 or 1 to 0. It is
// expected that an external source is modifying the value
typedef struct {
haloo3d_obj_instance *obj;
mfloat_t *scale;
// When scales are set, they're multiplied by this
mfloat_t basescale;
int *timer;
} ecs_syncgrow;
// A billboard for OUR system, which does not look up or down at the target. As
// such, no matter what the lookat is set to, y is always going to be equal to
// the y of the instance, so it appears to be looking "straight"
typedef struct {
haloo3d_obj_instance *obj;
struct vec3 *lookat;
} ecs_billboard;
// A component which holds onto data specifically for world
// entities. You can think of it as private data so people
// can't poke at the worldstate data
typedef struct {
worldstate *state;
haloo3d_obj *wallmodel;
haloo3d_obj_instance *endobj;
haloo3d_easyinstancer *instancer;
// paintingmanager * pm;
int scaletimer;
mfloat_t scaleto;
} ecs_world;
// State for tracking a smart ai moving through the maze.
typedef struct {
uint8_t state;
uint8_t dir;
uint32_t timer;
mfloat_t rotchange;
struct vec2i mpos;
worldstate *ws;
haloo3d_obj_instance *startmarker;
} ecs_smartai;
// A component which allows an object instance to die
// when the maze is initiailized.
typedef struct {
haloo3d_obj_instance *obj;
haloo3d_easyrender *render;
worldstate *ws;
} ecs_dieoninit;
// Setup ECS system for our game
ECS_START(mecs)
ECS_COMPONENT(ecs_world);
ECS_COMPONENT(ecs_autonav);
ECS_COMPONENT(ecs_autorotate);
ECS_COMPONENT(ecs_placement);
ECS_COMPONENT(ecs_camera);
ECS_COMPONENT(ecs_smartai);
ECS_COMPONENT(ecs_syncgrow);
ECS_COMPONENT(ecs_billboard);
ECS_COMPONENT(ecs_dieoninit);
ECS_END(mecs)
// And then a copy of the components here... that sucksssss
ECS_CID(ecs_worldstate, 0);
ECS_CID(ecs_world, 1);
ECS_CID(ecs_autonav, 2);
ECS_CID(ecs_autorotate, 3);
ECS_CID(ecs_placement, 4);
ECS_CID(ecs_camera, 5);
ECS_CID(ecs_smartai, 6);
ECS_CID(ecs_syncgrow, 7);
ECS_CID(ecs_billboard, 8);
ECS_CID(ecs_dieoninit, 9);
#endif

File diff suppressed because one or more lines are too long