From e4789d615684bc7ed07030f2e6a72b0180900455 Mon Sep 17 00:00:00 2001 From: Carlos Sanchez Date: Sat, 21 Sep 2024 23:32:37 -0400 Subject: [PATCH] Towers with lights --- commonobj.c | 4 +- terrain.c | 141 +++++++++++++++++++++++++++++++-------------- terrain_ecstypes.h | 7 +++ 3 files changed, 106 insertions(+), 46 deletions(-) diff --git a/commonobj.c b/commonobj.c index c501516..a357d61 100644 --- a/commonobj.c +++ b/commonobj.c @@ -86,7 +86,7 @@ void gen_circle_model(haloo3d_obj *model, uint16_t color, int vertices) { fastface2(model, circleuv, middle, lastv, firstv); } -void gen_flower(haloo3d_obj *model, uint16_t color) { +void gen_flower_model(haloo3d_obj *model, uint16_t color) { haloo3d_obj_resetfixed(model, 2, 5); uint16_t vs[5]; uint16_t col = COMCOL(model, color); @@ -116,7 +116,7 @@ void gen_horibox(haloo3d_obj *model, uint16_t col, mfloat_t wid, mfloat_t bot, } } -void gen_tower(haloo3d_obj *model, uint16_t color) { +void gen_tower_model(haloo3d_obj *model, uint16_t color) { haloo3d_obj_resetfixed(model, 100, 100); uint16_t col = COMCOL(model, color); uint16_t top = COMVERT(model, 0, 1, 0); diff --git a/terrain.c b/terrain.c index cf89bc6..63d5d34 100644 --- a/terrain.c +++ b/terrain.c @@ -77,6 +77,12 @@ #define REDFLOWERCOL 0xFF46 // 0xFF9A #define YELLOWFLOWERCOL 0xFEE0 #define TOWERCOL 0xF111 +#define LIGHTCOL 0xFF00 +#define TOWERLIGHTMINSIZE (CHUNKSCALE * 0.1) +#define TOWERLIGHTMAXSIZE (CHUNKSCALE * 0.5) +#define TOWERLIGHTMINTRANS 0 +#define TOWERLIGHTMAXTRANS 0.4 +#define TOWERLIGHTRATE 1.5 #define TREEBOTTOM -0.333 #define TREETRUNKWIDTH 0.2 #define SEATRANS 0.75 @@ -102,6 +108,7 @@ { .x = 0, .y = 0, .z = -1.5 } #define RANDF() ((float)rand() / RAND_MAX) +#define OFLOOR(v) (floor(fabs(v)) * ((v) < 0 ? -1 : 1)) // Some globals you can mess around with potentially int fps = 60; @@ -109,6 +116,7 @@ int fps = 60; #define PALETTEKEY "palette" #define TREEKEY "tree" #define CLOUDKEY "cloud" +#define LIGHTKEY "light" #define REDFLOWERKEY "redflower" #define YELLOWFLOWERKEY "yellowflower" #define TOWERKEY "tower" @@ -134,8 +142,65 @@ static inline mfloat_t calc_barycentric(mfloat_t *point, mfloat_t *values, return 0; } -uint16_t gen_terrain(struct vec3i pos, haloo3d_obj *model, - haloo3d_easystore *storage) { +void gen_tower(haloo3d_obj *model, haloo3d_obj *tower, tecs *ecs, + render_context *ctx, struct vec3i chunk, struct vec3 pos) { + const float scale = 0.5; + pos.x += 0.5; + pos.y += scale; + pos.z -= 0.5; + haloo3d_obj_addobj(model, tower, pos, (struct vec3)DEFAULTLOOK, + (struct vec3)DEFAULTUP, + (struct vec3){.x = scale, .y = scale, .z = scale}); + // Put a nice little light on top + pos.y += scale; + haloo3d_obj *light = haloo3d_easystore_getobj(&ecs->storage, LIGHTKEY); + ecs_eid lightid = tecs_newentity(ecs, 0); + eprintf("LIGHTING SPAWN: %d (%d,%d)\n", lightid, chunk.x, chunk.z); + ECS_SETCOMPONENT(ecs, lightid, ecs_playergarbage){}; + ECS_SETCOMPONENT(ecs, lightid, ecs_towerlight){.timer = 0}; + ECS_SETCOMPONENT(ecs, lightid, ecs_placement){ + .up = DEFAULTUP, + .lookvec = DEFAULTLOOK, + .pos = (struct vec3){.x = chunk.x + pos.x * CHUNKSCALE, + .y = pos.y * CHUNKSCALE * LANDHEIGHT, + .z = chunk.z + pos.z * CHUNKSCALE}}; + ECS_SETCOMPONENT(ecs, lightid, ecs_object){ + .flatdither = 0.2, + .texture = haloo3d_easystore_gettex(&ecs->storage, PALETTEKEY), + .scale = {.x = CHUNKSCALE, .y = CHUNKSCALE, .z = CHUNKSCALE}, + .lighting = NULL, //&ecs->chunklight, + .stoplighting = 0, + .model = light, + .cullbackface = 0, + .context = {ctx}, + .contextcount = 1}; +} + +void gen_cloud(render_context *ctx, tecs *ecs, struct vec3i pos) { + haloo3d_obj *cloud = haloo3d_easystore_getobj(&ecs->storage, CLOUDKEY); + ecs_eid cloudid = tecs_newentity(ecs, 0); + ECS_SETCOMPONENT(ecs, cloudid, ecs_playergarbage){}; + ECS_SETCOMPONENT(ecs, cloudid, + ecs_placement){.up = DEFAULTUP, + .lookvec = DEFAULTLOOK, + .pos = {.x = pos.x + RANDF(), + .y = CLOUDHEIGHT + 0.5 * RANDF(), + .z = pos.z - 0.9}}; + ECS_SETCOMPONENT(ecs, cloudid, ecs_object){ + .flatdither = CLOUDTRANSMIN + (CLOUDTRANSMAX - CLOUDTRANSMIN) * RANDF(), + .texture = haloo3d_easystore_gettex(&ecs->storage, PALETTEKEY), + .scale = {.x = 1 + RANDF(), .y = 1.0 / CLOUDSTRETCH, .z = 1}, + .lighting = NULL, //&ecs->chunklight, + .stoplighting = 0, + .model = cloud, + .cullbackface = 0, + .context = {ctx}, + .contextcount = 1}; +} + +uint16_t gen_terrain(struct vec3i pos, haloo3d_obj *model, tecs *ecs, + render_context *ctx) { + haloo3d_easystore *storage = &ecs->storage; eprintf("Generating terrain at %d,%d\n", pos.x, pos.z); haloo3d_obj *tree = haloo3d_easystore_getobj(storage, TREEKEY); haloo3d_obj *tower = haloo3d_easystore_getobj(storage, TOWERKEY); @@ -234,15 +299,10 @@ uint16_t gen_terrain(struct vec3i pos, haloo3d_obj *model, (struct vec3){.x = scale, .y = vertscale, .z = scale}); } } - // 0..65 - if (treecount == 0 && lowy > 0.15 && !gentower) { + if (treecount == 0 && lowy > 0.75 && !gentower) { gentower = 1; - haloo3d_obj_addobj(&nl_model, tower, - (struct vec3){.x = triedge[0].x + 0.5, - .y = lowy + 0.5, - .z = triedge[0].y - 0.5}, - (struct vec3)DEFAULTLOOK, (struct vec3)DEFAULTUP, - (struct vec3){.x = 0.5, .y = 0.5, .z = 0.5}); + gen_tower(&nl_model, tower, ecs, ctx, pos, + (struct vec3){.x = triedge[0].x, .y = lowy, .z = triedge[0].y}); } } uint16_t stoplighting = model->numfaces; @@ -250,30 +310,12 @@ uint16_t gen_terrain(struct vec3i pos, haloo3d_obj *model, (struct vec3)DEFAULTLOOK, (struct vec3)DEFAULTUP, (struct vec3){.x = 1, .y = 1, .z = 1}); haloo3d_obj_free(&nl_model); + // Generate a cloud + if (RANDF() < CLOUDCHANCE) + gen_cloud(ctx, ecs, pos); return stoplighting; } -void gen_cloud(render_context *ctx, tecs *ecs, struct vec3i pos) { - haloo3d_obj *cloud = haloo3d_easystore_getobj(&ecs->storage, CLOUDKEY); - ecs_eid cloudid = tecs_newentity(ecs, 0); - ECS_SETCOMPONENT(ecs, cloudid, ecs_playergarbage){}; - ECS_SETCOMPONENT(ecs, cloudid, ecs_placement){ - .up = DEFAULTUP, - .lookvec = DEFAULTLOOK, - .pos = { - .x = pos.x + RANDF(), .y = CLOUDHEIGHT + 0.5 * RANDF(), .z = pos.z}}; - ECS_SETCOMPONENT(ecs, cloudid, ecs_object){ - .flatdither = CLOUDTRANSMIN + (CLOUDTRANSMAX - CLOUDTRANSMIN) * RANDF(), - .texture = haloo3d_easystore_gettex(&ecs->storage, PALETTEKEY), - .scale = {.x = 1 + RANDF(), .y = 1.0 / CLOUDSTRETCH, .z = 1}, - .lighting = NULL, //&ecs->chunklight, - .stoplighting = 0, - .model = cloud, - .cullbackface = 1, - .context = {ctx}, - .contextcount = 1}; -} - // Generate the entity/components/terrain for the chunk at the given // coordinates. // NOTE: chunks are per x/y tile (terrain inside is just scaled @@ -285,7 +327,7 @@ void gen_chunk(render_context *ctx, tecs *ecs, struct vec3i pos) { sprintf(garbage.dynmodel, "e%d", id); haloo3d_obj *model = haloo3d_easystore_addobj(&ecs->storage, garbage.dynmodel); - uint16_t stoplighting = gen_terrain(pos, model, &ecs->storage); + uint16_t stoplighting = gen_terrain(pos, model, ecs, ctx); ECS_SETCOMPONENT(ecs, id, ecs_playergarbage) garbage; ECS_SETCOMPONENT(ecs, id, ecs_chunk){.pos = pos}; ECS_SETCOMPONENT(ecs, id, @@ -304,15 +346,12 @@ void gen_chunk(render_context *ctx, tecs *ecs, struct vec3i pos) { .cullbackface = 1, .context = {ctx}, .contextcount = 1}; - // Generate a cloud - if (RANDF() < CLOUDCHANCE) - gen_cloud(ctx, ecs, pos); } void player_chunkload(ecs_placement *ppos, render_context *ctx, tecs *ecs) { - struct vec3i pchunk = {.x = floor(ppos->pos.x), - .y = floor(ppos->pos.y), - .z = floor(ppos->pos.z)}; + struct vec3i pchunk = {.x = OFLOOR(ppos->pos.x), + .y = OFLOOR(ppos->pos.y), + .z = OFLOOR(ppos->pos.z)}; // This is our little array of "filled chunks" around the player. We // use this to figure out what to generate ecs_eid surround[PLBOXEDGE][PLBOXEDGE] = {0}; @@ -328,9 +367,9 @@ void player_chunkload(ecs_placement *ppos, render_context *ctx, tecs *ecs) { ecs_object *obj = &ECS_GETCOMPONENT(ecs, matches[i], ecs_object); // If this object is outside the view distance, we no longer have access to // it - if (fabs(floor(placement->pos.x) - pchunk.x) > VIEWDISTANCE || - fabs(floor(placement->pos.z) - pchunk.z) > VIEWDISTANCE) { - // OK, reduce the chunk refcount, since we're no longer close to it + if (fabs(OFLOOR(placement->pos.x) - pchunk.x) > VIEWDISTANCE || + fabs(OFLOOR(placement->pos.z) - pchunk.z) > VIEWDISTANCE) { + // OK, reduce the item refcount, since we're no longer close to it obj->contextcount--; lostobjects++; } @@ -396,6 +435,17 @@ void sys_rendercontext(ecs_rendercontext *erc, ecs_placement *p, tecs **ecs) { player_chunkload(p, rc, *ecs); } +void sys_towerlight(ecs_towerlight *tl, tecs **ecs, ecs_object *o) { + tl->timer += (*ecs)->delta_s; + float ang = fabs(sin(tl->timer * TOWERLIGHTRATE)); + o->flatdither = + TOWERLIGHTMINTRANS + (TOWERLIGHTMAXTRANS - TOWERLIGHTMINTRANS) * ang; + for (int i = 0; i < 3; i++) { + o->scale.v[i] = + TOWERLIGHTMINSIZE + (TOWERLIGHTMAXSIZE - TOWERLIGHTMINSIZE) * ang; + } +} + // Apply rotation to lookvec of placement, overrides lookvec void sys_rotation(ecs_placement *p, ecs_rotation *r) { YAWP2VEC(r->yaw, r->pitch, p->lookvec.v); @@ -692,13 +742,15 @@ int main() { // int argc, char **argv) { gen_tree_model(treemodel); haloo3d_obj *cloudmodel = haloo3d_easystore_addobj(&ecs.storage, CLOUDKEY); gen_circle_model(cloudmodel, CLOUDCOL, 32); + haloo3d_obj *lightmodel = haloo3d_easystore_addobj(&ecs.storage, LIGHTKEY); + gen_circle_model(lightmodel, LIGHTCOL, 16); haloo3d_obj *redflower = haloo3d_easystore_addobj(&ecs.storage, REDFLOWERKEY); - gen_flower(redflower, REDFLOWERCOL); + gen_flower_model(redflower, REDFLOWERCOL); haloo3d_obj *yellowflower = haloo3d_easystore_addobj(&ecs.storage, YELLOWFLOWERKEY); - gen_flower(yellowflower, YELLOWFLOWERCOL); + gen_flower_model(yellowflower, YELLOWFLOWERCOL); haloo3d_obj *tower = haloo3d_easystore_addobj(&ecs.storage, TOWERKEY); - gen_tower(tower, TOWERCOL); + gen_tower_model(tower, TOWERCOL); eprintf("Setup ECS system + obj/tex storage (%d bytes)\n", tecs_size); @@ -725,6 +777,7 @@ int main() { // int argc, char **argv) { tecs); ECS_RUNSYSTEM3(&ecs, sys_playergarbage, ecs_playergarbage, ecs_object, tecs); + ECS_RUNSYSTEM3(&ecs, sys_towerlight, ecs_towerlight, tecs, ecs_object); haloo3d_easytimer_start(&drawtimer); ECS_RUNSYSTEM3(&ecs, sys_renderobject, ecs_placement, ecs_object, tecs); haloo3d_easytimer_end(&drawtimer); diff --git a/terrain_ecstypes.h b/terrain_ecstypes.h index 6fa7880..e2e2b29 100644 --- a/terrain_ecstypes.h +++ b/terrain_ecstypes.h @@ -82,6 +82,11 @@ typedef struct { // typedef ecs_placement *ecs_placement_lock; +typedef struct { + // The data required to animate the tower light + float timer; +} ecs_towerlight; + // Movement is applied to placement and may also be used to check for // collisions and whatever typedef struct { @@ -144,6 +149,7 @@ ECS_COMPONENT(ecs_input) ECS_COMPONENT(ecs_playergarbage) ECS_COMPONENT(ecs_chunk) ECS_COMPONENT(ecs_placement_lock) +ECS_COMPONENT(ecs_towerlight) ECS_END(tecs) ECS_FN_INIT(tecs) @@ -162,5 +168,6 @@ ECS_CID(ecs_input, 5) ECS_CID(ecs_playergarbage, 6) ECS_CID(ecs_chunk, 7) ECS_CID(ecs_placement_lock, 8) +ECS_CID(ecs_towerlight, 9) #endif