3dtoys/terrain.c

923 lines
35 KiB
C
Raw Permalink Normal View History

2024-09-21 03:54:40 +00:00
#ifdef _EE
#define DIRECTBUILD
#define H3D_VOLATILE_FLOATS
#endif
#ifdef DIRECTBUILD
// clang-format off
#define MATHC_USE_UNIONS
#define MATHC_NO_STRUCT_FUNCTIONS
#include "haloo3d/lib/mathc.c"
#define FNL_IMPL
#include "haloo3d/lib/FastNoiseLite.h"
#include "haloo3d/haloo3d.c"
#include "haloo3d/haloo3dex_easy.c"
#include "haloo3d/haloo3dex_gen.c"
#include "haloo3d/haloo3dex_obj.c"
#include "haloo3d/haloo3dex_print.c"
#include "unigi.platform.sdl2/main.c"
// clang-format on
#else
2024-09-08 22:42:50 +00:00
#include "haloo3d/haloo3d.h"
#include "haloo3d/haloo3dex_easy.h"
#include "haloo3d/haloo3dex_gen.h"
#include "haloo3d/haloo3dex_obj.h"
2024-09-09 06:13:24 +00:00
#include "haloo3d/haloo3dex_print.h"
2024-09-20 01:34:05 +00:00
#include "haloo3d/lib/FastNoiseLite.h"
#include "haloo3d/lib/mathc.h"
2024-09-13 03:41:54 +00:00
#include "unigi/main.h"
2024-09-21 03:54:40 +00:00
#endif
2024-09-08 22:42:50 +00:00
// #include "keys.h"
2024-09-19 09:33:21 +00:00
// #define ECS_MAXENTITIES 30000
2024-09-08 22:42:50 +00:00
#include "terrain_ecstypes.h"
#include <stdlib.h>
2024-09-09 06:13:24 +00:00
#include <time.h>
2024-09-08 22:42:50 +00:00
2024-09-21 04:15:10 +00:00
// #define LIMITEDPRINT
2024-09-24 03:39:34 +00:00
// #define NOPRINT
2024-09-21 04:15:10 +00:00
2024-09-21 03:54:40 +00:00
#ifdef _EE
#define WIDTH 160
#define HEIGHT 120
#define SCREENSCALE 4
2024-09-24 03:39:34 +00:00
#define VIEWDISTANCE 2 // MAX IS AROUND 12
#define MAXTREEPERCELL 4
#define MAXTREEACROSS 2
#define CHUNKINITFACES (H3D_OBJ_MAXFACES / 2)
#define CHUNKINITVERTS (H3D_OBJ_MAXVERTICES / 2)
#define INIT_DITHEREND 999
#define INIT_DITHERSTART 999
2024-09-21 03:54:40 +00:00
#else
2024-09-08 22:42:50 +00:00
#define WIDTH 480
#define HEIGHT 300
#define SCREENSCALE 2
2024-09-24 03:39:34 +00:00
#define VIEWDISTANCE 10 // MAX IS AROUND 12
#define MAXTREEPERCELL 9
#define MAXTREEACROSS 3
#define CHUNKINITFACES H3D_OBJ_MAXFACES
#define CHUNKINITVERTS H3D_OBJ_MAXVERTICES
#define INIT_DITHEREND H3DVF(VIEWDISTANCE - 1.0)
#define INIT_DITHERSTART H3DVF(INIT_DITHEREND * 0.5)
2024-09-21 03:54:40 +00:00
#endif
2024-09-08 22:42:50 +00:00
#define SWIDTH (WIDTH * SCREENSCALE)
#define SHEIGHT (HEIGHT * SCREENSCALE)
2024-09-24 03:39:34 +00:00
#define AVGWEIGHT H3DVF(0.85)
2024-09-09 06:32:02 +00:00
#define DEFAULTUP \
{ .x = 0, .y = 1, .z = 0 }
2024-09-14 05:00:20 +00:00
// Lookvec for objects which all face forward along with the player
#define DEFAULTLOOK \
{ .x = 0, .y = 0, .z = -1 }
2024-09-22 21:27:36 +00:00
2024-09-20 00:27:49 +00:00
// How big each chunk is (x and y, square). MUST BE POWER OF 2 - 1
2024-09-20 01:34:05 +00:00
#define CHUNKSIZE 7 // This is the width in tiles
2024-09-24 03:39:34 +00:00
#define CHUNKSCALE H3DVF(1.0 / CHUNKSIZE)
2024-09-20 01:34:05 +00:00
// This is how many vertices across a chunk is
#define CHUNKVSIZE (CHUNKSIZE + 1)
2024-09-14 08:34:19 +00:00
#define PLBOXEDGE (VIEWDISTANCE * 2 + 1)
#define MAXCHUNKPERFRAME PLBOXEDGE
2024-09-20 01:34:05 +00:00
// Generation consts / things for looks
2024-09-22 21:00:11 +00:00
#define COLOREDTERRAIN // Some cost, not much
2024-09-24 03:39:34 +00:00
#define LANDHEIGHT H3DVF(4.0)
2024-09-23 06:25:46 +00:00
#define LANDCOL 0xF7C3 // 0xF4E1
2024-09-22 21:00:11 +00:00
#define FLANDCOL 0xF260 // 0xF3A0 // 0xF4E1
#define UWLANDCOL 0xF026
2024-09-23 00:41:05 +00:00
#define SEACOL 0xF28D // 0xF26C
#define SKYCOL 0xF96E // 0xF77F
#define SKYCOL2 0xFFAF // 0xF77F
2024-09-23 06:25:46 +00:00
#define CLOUDCOL 0xFFDE
2024-09-20 06:22:27 +00:00
#define TREECOL 0xF070
#define TREETRUNKCOL 0xF950
2024-09-22 01:19:43 +00:00
#define REDFLOWERCOL 0xFF46 // 0xFF9A
#define YELLOWFLOWERCOL 0xFEE0
#define TOWERCOL 0xF111
2024-09-22 03:32:37 +00:00
#define LIGHTCOL 0xFF00
2024-09-23 06:25:46 +00:00
#define SANDCOL 0xFDD8
2024-09-24 03:39:34 +00:00
#define TOWERLOW H3DVF(0.755) // small changes to this make a huge difference
#define TOWERLIGHTMINSIZE H3DVF(CHUNKSCALE * 0.1)
#define TOWERLIGHTMAXSIZE H3DVF(CHUNKSCALE * 0.3)
#define TOWERLIGHTMINTRANS H3DVF(0)
#define TOWERLIGHTMAXTRANS H3DVF(0.4)
#define TOWERLIGHTRATE H3DVF(1.5)
#define SANDSTART H3DVF(0.085)
#define TREEBOTTOM H3DVF(-0.333)
#define TREETRUNKWIDTH H3DVF(0.20)
#define SEATRANS H3DVF(0.5)
#define CLOUDTRANSMIN H3DVF(0.1)
#define CLOUDTRANSMAX H3DVF(0.2)
#define CLOUDHEIGHT H3DVF(1 + VIEWDISTANCE * 0.1)
#define CLOUDSTRETCH H3DVF(2)
#define CLOUDCHANCE H3DVF(0.1)
#define INIT_LIGHTPITCH H3DVF(MPI_2 * 1.65)
#define INIT_LIGHTYAW H3DVF(MPI_2 * 0.65)
#define INIT_MINLIGHT H3DVF(0.2)
#define MAXTREECLOSENESS H3DVF(0.2)
2024-09-20 01:34:05 +00:00
// Player things
2024-09-24 03:39:34 +00:00
#define INIT_FOV H3DVF(90.0)
#define INIT_CAMPITCH H3DVF(MPI_2 * 1.3) // MPI_2 * 1.6 // 1.575
#define INIT_PLAYERHEIGHT H3DVF(0.65)
#define INIT_NEARCLIP H3DVF(0.010)
#define INIT_FARCLIP H3DVF(100.0)
2024-09-09 06:13:24 +00:00
#define INIT_PLAYERSPEED \
2024-09-20 06:22:27 +00:00
{ .x = 0, .y = 0, .z = -1.5 }
2024-09-09 06:13:24 +00:00
2024-09-24 03:39:34 +00:00
#define RANDF() ((float)rand() / H3DVF(RAND_MAX))
2024-09-22 03:32:37 +00:00
#define OFLOOR(v) (floor(fabs(v)) * ((v) < 0 ? -1 : 1))
2024-09-20 00:27:49 +00:00
// Some globals you can mess around with potentially
2024-09-14 08:34:19 +00:00
int fps = 60;
2024-09-14 05:00:20 +00:00
#define PALETTEKEY "palette"
2024-09-20 06:22:27 +00:00
#define TREEKEY "tree"
2024-09-21 03:37:58 +00:00
#define CLOUDKEY "cloud"
2024-09-22 03:32:37 +00:00
#define LIGHTKEY "light"
2024-09-21 12:54:58 +00:00
#define REDFLOWERKEY "redflower"
2024-09-21 13:26:52 +00:00
#define YELLOWFLOWERKEY "yellowflower"
2024-09-22 01:19:43 +00:00
#define TOWERKEY "tower"
2024-09-14 05:00:20 +00:00
#include "commonobj.c"
2024-09-14 07:30:53 +00:00
2024-09-20 01:34:05 +00:00
static int gen_terrain_seed = 0;
2024-09-21 12:54:58 +00:00
static inline mfloat_t calc_barycentric(mfloat_t *point, mfloat_t *values,
struct vec2 *triedge, int count) {
mfloat_t we[3];
for (int i = 0; i < count; i++) {
int ofs = i * 3;
we[0] = haloo3d_edgefunc(triedge[ofs + 1].v, triedge[ofs + 2].v, point);
we[1] = haloo3d_edgefunc(triedge[ofs + 2].v, triedge[ofs + 0].v, point);
we[2] = haloo3d_edgefunc(triedge[ofs + 0].v, triedge[ofs + 1].v, point);
if (we[0] < 0 || we[1] < 0 || we[2] < 0) {
continue;
}
return we[0] * values[ofs] + we[1] * values[ofs + 1] +
we[2] * values[ofs + 2];
}
return 0;
}
2024-09-22 03:32:37 +00:00
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;
2024-09-24 03:39:34 +00:00
pos.x += H3DVF(0.5);
2024-09-22 03:32:37 +00:00
pos.y += scale;
2024-09-24 03:39:34 +00:00
pos.z -= H3DVF(0.5);
2024-09-22 03:32:37 +00:00
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},
2024-09-24 03:39:34 +00:00
.lighting = NULL,
2024-09-22 03:32:37 +00:00
.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){};
2024-09-24 03:39:34 +00:00
ECS_SETCOMPONENT(ecs, cloudid, ecs_placement){
.up = DEFAULTUP,
.lookvec = DEFAULTLOOK,
.pos = {.x = pos.x + RANDF(),
.y = CLOUDHEIGHT + H3DVF(0.5) * RANDF(),
.z = pos.z - 0.9}};
2024-09-22 03:32:37 +00:00
ECS_SETCOMPONENT(ecs, cloudid, ecs_object){
.flatdither = CLOUDTRANSMIN + (CLOUDTRANSMAX - CLOUDTRANSMIN) * RANDF(),
.texture = haloo3d_easystore_gettex(&ecs->storage, PALETTEKEY),
2024-09-24 03:39:34 +00:00
.scale = {.x = H3DVF(1) + RANDF(),
.y = H3DVF(1.0 / CLOUDSTRETCH),
.z = 1},
.lighting = NULL,
2024-09-22 03:32:37 +00:00
.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;
2024-09-14 08:34:19 +00:00
eprintf("Generating terrain at %d,%d\n", pos.x, pos.z);
2024-09-20 06:22:27 +00:00
haloo3d_obj *tree = haloo3d_easystore_getobj(storage, TREEKEY);
2024-09-22 01:19:43 +00:00
haloo3d_obj *tower = haloo3d_easystore_getobj(storage, TOWERKEY);
2024-09-21 13:26:52 +00:00
haloo3d_obj *flowers[2];
flowers[0] = haloo3d_easystore_getobj(storage, REDFLOWERKEY);
flowers[1] = haloo3d_easystore_getobj(storage, YELLOWFLOWERKEY);
2024-09-14 07:30:53 +00:00
// Don't allow the model to have more than some amount of faces/vertices.
2024-09-24 03:39:34 +00:00
haloo3d_obj_resetfixed(model, CHUNKINITFACES, CHUNKINITVERTS);
2024-09-22 21:00:11 +00:00
#define LCOLSTEP 8
2024-09-23 06:00:55 +00:00
// uint16_t sandcol = COMCOL(model, 0xFFF7);
2024-09-22 21:00:11 +00:00
uint16_t landcols[(LCOLSTEP + 1) * 2];
for (int i = 0; i <= LCOLSTEP; i++) {
2024-09-24 03:39:34 +00:00
landcols[i] = COMCOL(
model, haloo3d_col_lerp(LANDCOL, FLANDCOL, (float)i / H3DVF(LCOLSTEP)));
2024-09-22 21:00:11 +00:00
landcols[i + LCOLSTEP + 1] =
2024-09-23 06:00:55 +00:00
// 0xFDE6
2024-09-23 06:25:46 +00:00
COMCOL(model, haloo3d_col_lerp(SANDCOL, UWLANDCOL,
2024-09-24 03:39:34 +00:00
(float)i / H3DVF(LCOLSTEP)));
2024-09-22 21:00:11 +00:00
}
2024-09-20 01:34:05 +00:00
fnl_state ns = fnlCreateState();
ns.noise_type = FNL_NOISE_OPENSIMPLEX2;
ns.seed = gen_terrain_seed;
2024-09-24 03:39:34 +00:00
ns.frequency = H3DVF(0.025);
2024-09-20 01:34:05 +00:00
ns.fractal_type = FNL_FRACTAL_RIDGED;
float noisex = pos.x * CHUNKSIZE;
float noisey = -pos.z * CHUNKSIZE;
for (int z = 0; z < CHUNKVSIZE; z++) {
for (int x = 0; x < CHUNKVSIZE; x++) {
// clang-format off
2024-09-22 21:00:11 +00:00
haloo3d_obj_addvertex(model, (struct vec4){
.x = x, .y = fnlGetNoise2D(&ns, noisex + x, noisey + z), .z = -z, .w = 1 });
2024-09-20 01:34:05 +00:00
// clang-format on
2024-09-20 00:27:49 +00:00
}
}
2024-09-21 13:26:52 +00:00
struct vec2 triedge[6];
mfloat_t heights[6];
uint16_t faces[2];
2024-09-22 01:19:43 +00:00
uint8_t gentower = 0;
2024-09-21 13:26:52 +00:00
// A funny little thing... we're going to add flowers to this alternative
// model, then add them to the end of the real model with a pointer saying
// "don't do lighting past this point"
haloo3d_obj nl_model;
haloo3d_obj_resetfixed(&nl_model, H3D_OBJ_MAXFACES, H3D_OBJ_MAXVERTICES);
2024-09-20 01:34:05 +00:00
for (int i = 0; i < CHUNKVSIZE * (CHUNKVSIZE - 1); i++) {
2024-09-20 00:27:49 +00:00
if ((i & CHUNKSIZE) == CHUNKSIZE) {
continue;
}
2024-09-22 21:00:11 +00:00
// Change frequency for subthings
// ns.seed = 0;
ns.frequency = 0.01; // 0.02;
ns.fractal_type = FNL_FRACTAL_NONE;
2024-09-20 00:27:49 +00:00
uint16_t bl = i;
uint16_t br = i + 1;
2024-09-20 01:34:05 +00:00
uint16_t tl = i + CHUNKVSIZE;
uint16_t tr = i + CHUNKVSIZE + 1;
2024-09-22 21:00:11 +00:00
faces[0] = fastface2(model, landcols[0], bl, br, tl);
faces[1] = fastface2(model, landcols[0], br, tr, tl);
float lowys[2];
float highys[2];
for (int t = 0; t < 2; t++) {
2024-09-24 03:39:34 +00:00
lowys[t] = H3DVF(999);
highys[t] = H3DVF(-999);
for (int v = 0; v < 3; v++) {
2024-09-21 12:54:58 +00:00
int ofs = t * 3;
// NOTE: WE SWTICH Y AND Z TO MAKE THE EDGE FUNCTION WORK
2024-09-21 12:54:58 +00:00
triedge[ofs + v].x = model->vertices[model->faces[faces[t]][v].posi].x;
triedge[ofs + v].y = model->vertices[model->faces[faces[t]][v].posi].z;
heights[ofs + v] = model->vertices[model->faces[faces[t]][v].posi].y;
2024-09-22 21:00:11 +00:00
if (heights[ofs + v] < lowys[t])
lowys[t] = heights[ofs + v];
if (heights[ofs + v] > highys[t])
highys[t] = heights[ofs + v];
}
#ifdef COLOREDTERRAIN
uint16_t tfvi = model->faces[faces[t]][0].posi;
float nlayer = fnlGetNoise2D(&ns, noisex + model->vertices[tfvi].x,
noisey + model->vertices[tfvi].z);
int landcol;
2024-09-23 06:25:46 +00:00
if (highys[t] < SANDSTART) {
2024-09-22 21:00:11 +00:00
landcol = LCOLSTEP + 1 + LCOLSTEP * fabs(highys[t]);
} else {
2024-09-24 03:39:34 +00:00
landcol = LCOLSTEP * fabs(lowys[t]) * (H3DVF(1) + nlayer) * H3DVF(0.5);
}
2024-09-22 21:00:11 +00:00
for (int v = 0; v < 3; v++) {
model->faces[faces[t]][v].texi = landcols[landcol];
}
#endif
}
2024-09-22 21:00:11 +00:00
float lowy = MIN(lowys[0], lowys[1]);
2024-09-22 01:19:43 +00:00
int treecount = 0;
2024-09-21 03:37:58 +00:00
for (int t = 0; t < MAXTREEPERCELL; t++) {
// We know that the first vec in the first triangle is bl, which is our
// base to start generating trees
struct vec2 treepos = {
2024-09-24 03:39:34 +00:00
.x = triedge[0].x + H3DVF(1.0 / MAXTREEACROSS) *
((t % MAXTREEACROSS) +
(H3DVF(1.0) - MAXTREECLOSENESS) * RANDF()),
.y = triedge[0].y - (H3DVF(1.0 / MAXTREEACROSS) *
((int)(t / MAXTREEACROSS) +
(H3DVF(1.0) - MAXTREECLOSENESS) * RANDF()))};
2024-09-21 12:54:58 +00:00
float y = calc_barycentric(treepos.v, heights, triedge, 2);
float pick = RANDF(); // pow(RANDF(), 2);
float nlayer = fnlGetNoise2D(&ns, noisex + treepos.x, noisey + treepos.y);
2024-09-24 03:39:34 +00:00
if (pick < y * (H3DVF(1) + nlayer) * H3DVF(0.5)) {
2024-09-22 21:38:19 +00:00
// Generate tree
2024-09-24 03:39:34 +00:00
float scale = H3DVF(0.1) + RANDF() * H3DVF(0.05);
float height = H3DVF(0.5) + RANDF() * H3DVF(0.5);
2024-09-21 12:54:58 +00:00
haloo3d_obj_addobj(
model, tree,
(struct vec3){
.x = treepos.x, .y = y + scale * height, .z = treepos.y},
(struct vec3)DEFAULTLOOK, (struct vec3)DEFAULTUP,
(struct vec3){.x = scale, .y = scale * height, .z = scale});
2024-09-22 01:19:43 +00:00
treecount++;
2024-09-24 03:39:34 +00:00
} else if ((rand() & 3) == 0 && y < H3DVF(0.4) && y > H3DVF(0) &&
RANDF() < -nlayer) {
2024-09-22 21:38:19 +00:00
// Generate flower of random-ish color
2024-09-24 03:39:34 +00:00
float scale = H3DVF(0.04);
float vertscale = scale * (H3DVF(1) - H3DVF(0.5) * RANDF());
2024-09-21 13:26:52 +00:00
haloo3d_obj_addobj(
2024-09-24 03:39:34 +00:00
&nl_model, flowers[nlayer > H3DVF(-0.9)],
(struct vec3){.x = treepos.x,
.y = y + vertscale * H3DVF(0.5),
.z = treepos.y},
2024-09-22 21:38:19 +00:00
(struct vec3)DEFAULTLOOK, (struct vec3)DEFAULTUP,
2024-09-21 13:26:52 +00:00
(struct vec3){.x = scale, .y = vertscale, .z = scale});
}
2024-09-20 07:05:45 +00:00
}
2024-09-22 21:38:19 +00:00
// You can put towers in cells with no trees that are high enough, as long
// as this chunk doesn't already have one
2024-09-22 18:20:36 +00:00
if (treecount == 0 && lowy > TOWERLOW && !gentower) {
2024-09-22 01:19:43 +00:00
gentower = 1;
2024-09-22 03:32:37 +00:00
gen_tower(&nl_model, tower, ecs, ctx, pos,
(struct vec3){.x = triedge[0].x, .y = lowy, .z = triedge[0].y});
2024-09-22 01:19:43 +00:00
}
2024-09-20 00:27:49 +00:00
}
2024-09-22 21:38:19 +00:00
// A silly hack to get a single model to render in multiple ways. Not good!
2024-09-21 13:26:52 +00:00
uint16_t stoplighting = model->numfaces;
haloo3d_obj_addobj(model, &nl_model, (struct vec3){.x = 0, .y = 0, .z = 0},
(struct vec3)DEFAULTLOOK, (struct vec3)DEFAULTUP,
(struct vec3){.x = 1, .y = 1, .z = 1});
haloo3d_obj_free(&nl_model);
2024-09-22 21:38:19 +00:00
// Generate a cloud maybe
2024-09-22 03:32:37 +00:00
if (RANDF() < CLOUDCHANCE)
gen_cloud(ctx, ecs, pos);
2024-09-21 13:26:52 +00:00
return stoplighting;
2024-09-14 07:30:53 +00:00
}
// Generate the entity/components/terrain for the chunk at the given
// coordinates.
// NOTE: chunks are per x/y tile (terrain inside is just scaled
// down to fit inside the 1x1 box)
2024-09-14 08:34:19 +00:00
void gen_chunk(render_context *ctx, tecs *ecs, struct vec3i pos) {
2024-09-14 07:30:53 +00:00
// eprintf("Generating chunk at %d,%d\n", pos.x, pos.y);
ecs_eid id = tecs_newentity(ecs, 0);
ecs_playergarbage garbage;
sprintf(garbage.dynmodel, "e%d", id);
haloo3d_obj *model =
haloo3d_easystore_addobj(&ecs->storage, garbage.dynmodel);
2024-09-22 03:32:37 +00:00
uint16_t stoplighting = gen_terrain(pos, model, ecs, ctx);
2024-09-14 07:30:53 +00:00
ECS_SETCOMPONENT(ecs, id, ecs_playergarbage) garbage;
ECS_SETCOMPONENT(ecs, id, ecs_chunk){.pos = pos};
ECS_SETCOMPONENT(ecs, id,
ecs_placement){.up = DEFAULTUP,
.lookvec = DEFAULTLOOK,
2024-09-14 08:34:19 +00:00
.pos = {.x = pos.x, .y = pos.y, .z = pos.z}};
2024-09-14 07:30:53 +00:00
// TODO: an easy place for optimization (if it's even needed)
// eprintf("TEX: %p\n", haloo3d_easystore_gettex(&ecs->storage, PALETTEKEY));
ECS_SETCOMPONENT(ecs, id, ecs_object){
2024-09-20 02:33:53 +00:00
.flatdither = 0,
2024-09-14 07:30:53 +00:00
.texture = haloo3d_easystore_gettex(&ecs->storage, PALETTEKEY),
2024-09-20 01:34:05 +00:00
.scale = {.x = CHUNKSCALE, .y = CHUNKSCALE * LANDHEIGHT, .z = CHUNKSCALE},
2024-09-14 08:34:19 +00:00
.lighting = &ecs->chunklight,
2024-09-21 13:26:52 +00:00
.stoplighting = stoplighting,
2024-09-14 07:30:53 +00:00
.model = model,
2024-09-14 07:42:59 +00:00
.cullbackface = 1,
2024-09-14 07:30:53 +00:00
.context = {ctx},
.contextcount = 1};
}
void player_chunkload(ecs_placement *ppos, render_context *ctx, tecs *ecs) {
2024-09-22 03:32:37 +00:00
struct vec3i pchunk = {.x = OFLOOR(ppos->pos.x),
.y = OFLOOR(ppos->pos.y),
.z = OFLOOR(ppos->pos.z)};
2024-09-14 07:30:53 +00:00
// 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};
// Need to pull all existing objects that are killable
ecs_eid matches[ECS_MAXENTITIES];
// Find + iterate over killable objects placed in world
int mcount = tecs_query(
ecs, ecs_playergarbage_fl | ecs_placement_fl | ecs_object_fl, matches);
2024-09-21 06:54:24 +00:00
int lostobjects = 0;
2024-09-14 07:30:53 +00:00
for (int i = 0; i < mcount; i++) {
ecs_placement *placement =
&ECS_GETCOMPONENT(ecs, matches[i], ecs_placement);
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
2024-09-22 03:32:37 +00:00
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
2024-09-14 07:30:53 +00:00
obj->contextcount--;
2024-09-21 06:54:24 +00:00
lostobjects++;
2024-09-14 07:30:53 +00:00
}
// This is specifically a chunk, it might be within our view radius.
if (ECS_HASCOMPONENT(ecs, matches[i], ecs_chunk)) {
ecs_chunk *chunk = &ECS_GETCOMPONENT(ecs, matches[i], ecs_chunk);
int surx = chunk->pos.x - pchunk.x + VIEWDISTANCE;
2024-09-14 08:34:19 +00:00
int surz = chunk->pos.z - pchunk.z + VIEWDISTANCE;
if (surx >= 0 && surz >= 0 && surx < PLBOXEDGE && surz < PLBOXEDGE) {
2024-09-14 07:30:53 +00:00
// eprintf("SUR: %d %d\n", surx, sury);
2024-09-14 08:34:19 +00:00
surround[surz][surx] = 1; // matches[i];
2024-09-14 07:30:53 +00:00
}
}
}
2024-09-21 06:54:24 +00:00
if (lostobjects) {
eprintf("KILLABLE OBJS: %d PCHUNK: %d,%d\n", mcount, pchunk.x, pchunk.y);
}
2024-09-14 07:30:53 +00:00
int chunkgen = 0;
// We now have our view radius box and which chunks are not loaded. Up to
// some amount, let's load them
2024-09-14 08:34:19 +00:00
for (int z = pchunk.z - VIEWDISTANCE; z <= pchunk.z + VIEWDISTANCE; z++) {
for (int x = pchunk.x - VIEWDISTANCE; x <= pchunk.x + VIEWDISTANCE; x++) {
2024-09-14 07:30:53 +00:00
int surx = x - pchunk.x + VIEWDISTANCE;
2024-09-14 08:34:19 +00:00
int surz = z - pchunk.z + VIEWDISTANCE;
if (!surround[surz][surx]) {
gen_chunk(ctx, ecs, (struct vec3i){.x = x, .y = 0, .z = z});
2024-09-14 07:30:53 +00:00
if (++chunkgen >= MAXCHUNKPERFRAME) {
break;
}
}
}
}
}
2024-09-09 06:13:24 +00:00
// ---------------------------------------------------
// The terrain ecs systems
2024-09-09 06:13:24 +00:00
// ---------------------------------------------------
// All initialization for a specific render context
2024-09-14 07:30:53 +00:00
void sys_rendercontext(ecs_rendercontext *erc, ecs_placement *p, tecs **ecs) {
render_context *rc = *erc;
2024-09-09 06:13:24 +00:00
struct vec3 lookat;
mfloat_t cammatrix[MAT4_SIZE];
mfloat_t perspective[MAT4_SIZE];
// Some initial clearing
haloo3d_fb_cleardepth(&rc->window);
if (rc->windowclear & 0xF000) {
haloo3d_fb_clear(&rc->window, rc->windowclear);
}
2024-09-23 00:41:05 +00:00
if (rc->backtex) {
haloo3d_fb_fill_raw(&rc->window, rc->backtex, 0);
}
2024-09-09 06:13:24 +00:00
// Precalc stuff for later object rendering
rc->precalc_halfwidth = rc->window.width * H3DVF(0.5);
rc->precalc_halfheight = rc->window.height * H3DVF(0.5);
haloo3d_perspective(perspective, rc->fov,
(mfloat_t)rc->window.width / rc->window.height,
rc->nearclip, rc->farclip);
vec3_add(lookat.v, p->pos.v, p->lookvec.v);
haloo3d_my_lookat(cammatrix, p->pos.v, lookat.v, p->up.v);
mat4_inverse(cammatrix, cammatrix);
mat4_multiply(rc->precalc_screen, perspective, cammatrix);
2024-09-14 07:30:53 +00:00
// Well, since we're here... might as well do the player-related stuff.
// After all, we can be sure this is a player... right?
player_chunkload(p, rc, *ecs);
}
2024-09-22 03:32:37 +00:00
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;
}
}
2024-09-09 06:13:24 +00:00
// 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);
}
2024-09-09 06:13:24 +00:00
void sys_movement(ecs_placement *p, ecs_movement *m, tecs **ecs) {
mfloat_t temp[VEC3_SIZE];
vec3_multiply_f(temp, m->lookvec.v, (*ecs)->delta_s);
vec3_add(p->lookvec.v, p->lookvec.v, temp);
vec3_multiply_f(temp, m->up.v, (*ecs)->delta_s);
vec3_add(p->up.v, p->up.v, temp);
vec3_multiply_f(temp, m->pos.v, (*ecs)->delta_s);
vec3_add(p->pos.v, p->pos.v, temp);
2024-09-19 09:33:21 +00:00
// vec3_multiply(p->pos.v, p->pos.v, p->pos.v);
}
// Perform the entire rendering of an object
2024-09-09 06:32:02 +00:00
void sys_renderobject(ecs_placement *p, ecs_object *o, tecs **ecs) {
2024-09-12 06:59:28 +00:00
// --**-- First, precalc all the vertices in the object --**--
mfloat_t tmp[VEC4_SIZE];
mfloat_t modelm[MAT4_SIZE];
mfloat_t finalmatrix[MAT4_SIZE];
2024-09-12 06:59:28 +00:00
struct vec4 precalc_verts[H3D_OBJ_MAXVERTICES];
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);
2024-09-20 02:33:53 +00:00
haloo3d_trirender rsettings;
2024-09-14 05:00:20 +00:00
// We might be rendering into multiple contexts in a multiplayer game (or
// just different angles or something)
for (int ctx = 0; ctx < o->contextcount; ctx++) {
2024-09-20 02:33:53 +00:00
memcpy(&rsettings, &o->context[ctx]->rendersettings,
sizeof(haloo3d_trirender));
rsettings.texture = o->texture;
if (o->flatdither > 0) {
rsettings.ditherflat = o->flatdither;
}
2024-09-14 05:00:20 +00:00
mat4_multiply(finalmatrix, o->context[ctx]->precalc_screen, modelm);
haloo3d_precalc_verts(o->model, finalmatrix, precalc_verts);
// --**-- Next, setup some rendering invariants --**--
struct vec3 lighting;
// The compiler is complaining about lighting being used unitialized, even
// though it's not. Just shut it up
vec3(lighting.v, 0, 0, 0);
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
2024-09-20 02:33:53 +00:00
// transpose works for rotation matrices(?) but I don't trust that
// this lookat does that mat4_inverse(modelm, modelm);
2024-09-14 05:00:20 +00:00
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);
2024-09-20 02:33:53 +00:00
// No need to fix W, should all be good (no perspective divide). But
// we DO need to pull out that result
2024-09-14 05:00:20 +00:00
vec3(lighting.v, lout.x, lout.y, lout.z);
vec3_normalize(lighting.v, lighting.v);
} else {
2024-09-14 05:00:20 +00:00
vec3_assign(lighting.v, o->lighting->dir.v);
}
2024-09-14 05:00:20 +00:00
}
// --**-- Finally, actually render faces --**--
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) {
2024-09-20 02:33:53 +00:00
uint8_t oflags = rsettings.flags;
2024-09-21 13:26:52 +00:00
if (o->lighting && facei < o->stoplighting) {
2024-09-14 05:00:20 +00:00
haloo3d_obj_facef(o->model, o->model->faces[facei], baseface);
2024-09-20 02:33:53 +00:00
rsettings.intensity =
2024-09-14 05:00:20 +00:00
haloo3d_calc_light(lighting.v, o->lighting->minlight, baseface);
} else {
2024-09-20 02:33:53 +00:00
rsettings.intensity = H3DVF(1.0);
}
2024-09-20 02:33:53 +00:00
// if ((r->_objstate[object - r->objects] & H3D_EASYOBJSTATE_NOTRANS))
// {
2024-09-14 05:00:20 +00:00
// r->rendersettings.flags &= ~H3DR_TRANSPARENCY;
// }
for (int ti = 0; ti < tris; ti++) {
int backface = !haloo3d_facef_finalize(outfaces[ti]);
2024-09-21 18:21:42 +00:00
if (o->cullbackface && facei < o->stoplighting && backface) {
2024-09-14 05:00:20 +00:00
continue;
}
(*ecs)->totaldrawn++;
// We still have to convert the points into the view
haloo3d_facef_viewport_into_fast(outfaces[ti],
o->context[ctx]->precalc_halfwidth,
o->context[ctx]->precalc_halfheight);
2024-09-20 02:33:53 +00:00
haloo3d_triangle(&o->context[ctx]->window, &rsettings, outfaces[ti]);
2024-09-14 05:00:20 +00:00
}
2024-09-20 02:33:53 +00:00
rsettings.flags = oflags;
}
}
}
}
2024-09-08 22:42:50 +00:00
2024-09-09 06:32:02 +00:00
void sys_playerinput(ecs_input *in) {
in->numevents = 0;
unigi_type_event event;
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;
}
in->numevents++;
} while (event.type != unigi_enum_event_none);
}
2024-09-14 05:00:20 +00:00
void sys_playergarbage(ecs_playergarbage *pg, ecs_object *ob, tecs **ecs) {
ecs_eid id = tecs_eid(ecs);
if (ob->contextcount <= 0) {
eprintf("Deleting object %d\n", id);
if (pg->dynmodel[0]) {
haloo3d_easystore_deleteobj(&(*ecs)->storage, pg->dynmodel,
haloo3d_obj_free);
}
tecs_deleteentity(*ecs, id);
}
}
2024-09-19 08:13:39 +00:00
void sys_placement_lock(ecs_placement_lock *lock, ecs_placement *pl) {
if (lock->options & TECS_PLOCK_LOCKUP) {
pl->up = lock->link->up;
}
if (lock->options & TECS_PLOCK_LOCKPOSX) {
pl->pos.x = lock->link->pos.x;
}
if (lock->options & TECS_PLOCK_LOCKPOSY) {
pl->pos.y = lock->link->pos.y;
}
if (lock->options & TECS_PLOCK_LOCKPOSZ) {
pl->pos.z = lock->link->pos.z;
}
if (lock->options & TECS_PLOCK_LOCKLOOKX) {
pl->lookvec.x = lock->link->lookvec.x;
}
if (lock->options & TECS_PLOCK_LOCKLOOKY) {
pl->lookvec.y = lock->link->lookvec.y;
}
if (lock->options & TECS_PLOCK_LOCKLOOKZ) {
pl->lookvec.z = lock->link->lookvec.z;
}
}
// ---------------------------------------------------
// Setup functions
// ---------------------------------------------------
ecs_eid setup_player(tecs *ecs, render_context *context) {
ecs_eid playerid = tecs_newentity(ecs, 0);
ECS_SETCOMPONENT(ecs, playerid, ecs_placement){
2024-09-19 09:33:21 +00:00
.pos = {.x = 0, .y = INIT_PLAYERHEIGHT, .z = 0}, .up = DEFAULTUP};
2024-09-19 08:13:39 +00:00
ECS_SETCOMPONENT(ecs, playerid, ecs_movement){.pos = INIT_PLAYERSPEED};
ECS_SETCOMPONENT(ecs, playerid, ecs_rotation){.yaw = 0,
2024-09-19 09:33:21 +00:00
.pitch = INIT_CAMPITCH};
2024-09-19 08:13:39 +00:00
ECS_SETCOMPONENT(ecs, playerid, ecs_rendercontext) context;
ECS_SETCOMPONENT(ecs, playerid, ecs_input){};
return playerid;
}
ecs_eid setup_sea(tecs *ecs, render_context *ctx, ecs_placement *playerpos,
haloo3d_easystore *storage) {
ecs_eid seaid = tecs_newentity(ecs, 0);
ECS_SETCOMPONENT(ecs, seaid, ecs_placement){
.pos = {.x = 0, .y = 0, .z = 0}, .lookvec = DEFAULTLOOK, .up = DEFAULTUP};
ECS_SETCOMPONENT(ecs, seaid, ecs_placement_lock){
.options = TECS_PLOCK_LOCKPOSX | TECS_PLOCK_LOCKPOSZ | TECS_PLOCK_LOCKUP,
.link = playerpos,
};
haloo3d_obj *model = haloo3d_easystore_addobj(storage, "sea");
haloo3d_obj_resetfixed(model, 2, 4);
2024-09-20 01:34:05 +00:00
struct vec3 seacol = haloo3d_gen_paletteuv(SEACOL); // 0xF26F);
2024-09-19 08:13:39 +00:00
int seauv = haloo3d_obj_addvtexture(model, seacol);
// clang-format off
// REMEMBER: NEGATIVE Z IS FORWARD
int tl = haloo3d_obj_addvertex(model, (struct vec4){.x = -1, .y = 0, .z = -1, .w = 1});
int tr = haloo3d_obj_addvertex(model, (struct vec4){.x = 1, .y = 0, .z = -1, .w = 1});
int bl = haloo3d_obj_addvertex(model, (struct vec4){.x = -1, .y = 0, .z = 1, .w = 1});
int br = haloo3d_obj_addvertex(model, (struct vec4){.x = 1, .y = 0, .z = 1, .w = 1});
// clang-format on
haloo3d_facei face;
fastface(face, seauv, bl, br, tl);
haloo3d_obj_addface(model, face);
fastface(face, seauv, br, tr, tl);
haloo3d_obj_addface(model, face);
ECS_SETCOMPONENT(ecs, seaid, ecs_object){
2024-09-20 02:33:53 +00:00
.flatdither = SEATRANS,
2024-09-19 08:13:39 +00:00
.texture = haloo3d_easystore_gettex(&ecs->storage, PALETTEKEY),
2024-09-20 02:33:53 +00:00
.scale = {.x = VIEWDISTANCE * 1.5,
.y = VIEWDISTANCE * 1.5,
.z = VIEWDISTANCE * 1.5},
2024-09-19 08:13:39 +00:00
.lighting = NULL,
.model = model,
.cullbackface = 1,
.context = {ctx},
.contextcount = 1};
return seaid;
}
2024-09-23 00:41:05 +00:00
void draw_gradient(haloo3d_fb *buf, uint16_t topcol, uint16_t botcol,
int height) {
// Precalc an array indicating the bands of color.
int row[64]; // not sure how many bands there can be but...
uint16_t col[64];
int bandscount = 1;
row[0] = 0;
col[0] = topcol;
uint8_t dither[4];
for (int y = 1; y < height; y++) {
uint16_t thiscol =
haloo3d_col_lerp(topcol, botcol, (float)y / (height - 1));
if (thiscol != col[bandscount - 1]) {
row[bandscount] = y;
col[bandscount] = thiscol;
bandscount++;
}
}
for (int band = 0; band < bandscount - 1; band++) {
for (int r = row[band]; r < row[band + 1]; r++) {
haloo3d_getdither4x4((float)(r - row[band]) / (row[band + 1] - row[band]),
dither);
uint8_t df = dither[r & 3];
for (int b = 0; b < 8; b++) {
haloo3d_fb_set(buf, b, r, (df & 1) ? col[band + 1] : col[band]);
df >>= 1;
}
uint16_t *bufstart = buf->buffer + r * buf->width;
// Then, a repeated growing copy to minimize copies? IDK
for (int size = 8; size < buf->width; size <<= 1) {
memcpy(bufstart + size, bufstart,
sizeof(uint16_t) * MIN(size, buf->width - size));
}
}
}
}
2024-09-12 06:59:28 +00:00
// ---------------------------------------------------
// MAIN FUNCTION
// ---------------------------------------------------
2024-09-08 22:42:50 +00:00
int main() { // int argc, char **argv) {
srand(clock());
2024-09-20 01:34:05 +00:00
gen_terrain_seed = rand();
2024-09-08 22:42:50 +00:00
// Init unigi system. Can use anything here that can render to screen
unigi_type_resolution res;
res.width = SWIDTH;
res.height = SHEIGHT;
res.depth = 0;
unigi_graphics_init();
unigi_window_create(res, "terrain.exe"); // render.printbuf);
eprintf("Initialized unigi system\n");
haloo3d_fb screen;
haloo3d_fb_init(&screen, SWIDTH, SHEIGHT);
2024-09-09 06:13:24 +00:00
haloo3d_print_tracker pt;
char printbuf[8192];
haloo3d_print_initdefault(&pt, printbuf, sizeof(printbuf));
pt.fb = &screen;
2024-09-14 05:00:20 +00:00
pt.scale = 1;
2024-09-08 22:42:50 +00:00
2024-09-12 06:59:28 +00:00
haloo3d_easytimer frametimer, drawtimer, sdltimer;
2024-09-08 22:42:50 +00:00
haloo3d_easytimer_init(&frametimer, AVGWEIGHT);
haloo3d_easytimer_init(&drawtimer, AVGWEIGHT);
haloo3d_easytimer_init(&sdltimer, AVGWEIGHT);
2024-09-23 00:41:05 +00:00
haloo3d_fb skygrad;
haloo3d_fb_init_tex(&skygrad, 1 << (int)ceil(log2(WIDTH)),
1 << (int)ceil(log2(HEIGHT)));
haloo3d_fb_clear(&skygrad, SKYCOL2);
draw_gradient(&skygrad, SKYCOL, SKYCOL2, HEIGHT / 2);
eprintf("Sky texture size: %dx%d\n", skygrad.width, skygrad.height);
2024-09-09 06:13:24 +00:00
render_context context;
2024-09-23 00:41:05 +00:00
context.backtex = &skygrad;
context.windowclear = 0; // SKYCOL;
2024-09-09 06:13:24 +00:00
context.nearclip = INIT_NEARCLIP;
context.farclip = INIT_FARCLIP;
context.fov = INIT_FOV;
2024-09-19 09:33:21 +00:00
haloo3d_trirender_init(&context.rendersettings);
2024-09-20 06:22:27 +00:00
// context.rendersettings.flags &= ~H3DR_PCT;
2024-09-20 02:33:53 +00:00
// context.rendersettings.flags &= ~H3DR_DITHERPIX;
// context.rendersettings.flags |= H3DR_DITHERTRI;
2024-09-19 09:33:21 +00:00
context.rendersettings.ditherclose = INIT_DITHERSTART;
context.rendersettings.ditherfar = INIT_DITHEREND;
2024-09-22 18:20:36 +00:00
// context.rendersettings.pctminsize = 500;
2024-09-09 06:13:24 +00:00
haloo3d_fb_init(&context.window, WIDTH, HEIGHT);
eprintf("Initialized screen buffers, context, and timers\n");
tecs ecs;
2024-09-09 06:13:24 +00:00
ecs.delta_s = 0;
tecs_init(&ecs);
2024-09-09 06:13:24 +00:00
int tecs_size = sizeof(tecs);
2024-09-14 05:00:20 +00:00
YAWP2VEC(INIT_LIGHTYAW, INIT_LIGHTPITCH, ecs.globallighting.v);
// An issue? Not a pointer? Eeehhh....
ecs.chunklight.dir = ecs.globallighting;
ecs.chunklight.minlight = INIT_MINLIGHT;
ecs.chunklight.autolightfix = 0;
haloo3d_easystore_init(&ecs.storage);
haloo3d_fb *palettetex = haloo3d_easystore_addtex(&ecs.storage, PALETTEKEY);
haloo3d_gen_palettetex(palettetex);
2024-09-20 06:22:27 +00:00
haloo3d_obj *treemodel = haloo3d_easystore_addobj(&ecs.storage, TREEKEY);
gen_tree_model(treemodel);
2024-09-21 03:37:58 +00:00
haloo3d_obj *cloudmodel = haloo3d_easystore_addobj(&ecs.storage, CLOUDKEY);
gen_circle_model(cloudmodel, CLOUDCOL, 32);
2024-09-22 03:32:37 +00:00
haloo3d_obj *lightmodel = haloo3d_easystore_addobj(&ecs.storage, LIGHTKEY);
gen_circle_model(lightmodel, LIGHTCOL, 16);
2024-09-21 12:54:58 +00:00
haloo3d_obj *redflower = haloo3d_easystore_addobj(&ecs.storage, REDFLOWERKEY);
2024-09-22 03:32:37 +00:00
gen_flower_model(redflower, REDFLOWERCOL);
2024-09-21 13:26:52 +00:00
haloo3d_obj *yellowflower =
haloo3d_easystore_addobj(&ecs.storage, YELLOWFLOWERKEY);
2024-09-22 03:32:37 +00:00
gen_flower_model(yellowflower, YELLOWFLOWERCOL);
2024-09-22 01:19:43 +00:00
haloo3d_obj *tower = haloo3d_easystore_addobj(&ecs.storage, TOWERKEY);
2024-09-22 03:32:37 +00:00
gen_tower_model(tower, TOWERCOL);
2024-09-14 05:00:20 +00:00
eprintf("Setup ECS system + obj/tex storage (%d bytes)\n", tecs_size);
2024-09-09 06:13:24 +00:00
2024-09-19 08:13:39 +00:00
ecs_eid playerid = setup_player(&ecs, &context);
2024-09-09 06:13:24 +00:00
ecs_placement *playerpos = &ECS_GETCOMPONENT(&ecs, playerid, ecs_placement);
2024-09-19 08:13:39 +00:00
ecs_eid seaid = setup_sea(&ecs, &context, playerpos, &ecs.storage);
2024-09-09 06:13:24 +00:00
2024-09-19 08:13:39 +00:00
eprintf("Setup player(%d) + sea(%d)\n", playerid, seaid);
2024-09-09 06:13:24 +00:00
// MAIN LOOP
while (1) {
haloo3d_easytimer_start(&frametimer);
2024-09-09 06:13:24 +00:00
haloo3d_print_refresh(&pt);
2024-09-09 06:32:02 +00:00
ecs.totaldrawn = 0;
2024-09-09 06:13:24 +00:00
// ECS logic (which includes rendering)
2024-09-09 06:13:24 +00:00
if (ecs.delta_s) {
2024-09-09 06:32:02 +00:00
ECS_RUNSYSTEM1(&ecs, sys_playerinput, ecs_input);
2024-09-09 06:13:24 +00:00
ECS_RUNSYSTEM2(&ecs, sys_rotation, ecs_placement, ecs_rotation);
2024-09-19 09:33:21 +00:00
ECS_RUNSYSTEM3(&ecs, sys_movement, ecs_placement, ecs_movement, tecs);
2024-09-19 08:13:39 +00:00
ECS_RUNSYSTEM2(&ecs, sys_placement_lock, ecs_placement_lock,
ecs_placement);
2024-09-14 07:30:53 +00:00
ECS_RUNSYSTEM3(&ecs, sys_rendercontext, ecs_rendercontext, ecs_placement,
tecs);
2024-09-14 05:00:20 +00:00
ECS_RUNSYSTEM3(&ecs, sys_playergarbage, ecs_playergarbage, ecs_object,
tecs);
2024-09-22 03:32:37 +00:00
ECS_RUNSYSTEM3(&ecs, sys_towerlight, ecs_towerlight, tecs, ecs_object);
2024-09-09 06:32:02 +00:00
haloo3d_easytimer_start(&drawtimer);
ECS_RUNSYSTEM3(&ecs, sys_renderobject, ecs_placement, ecs_object, tecs);
haloo3d_easytimer_end(&drawtimer);
2024-09-09 06:13:24 +00:00
}
// Scale 3D into final buffer
2024-09-09 06:13:24 +00:00
haloo3d_fb_fill(&screen, &context.window);
2024-09-24 03:39:34 +00:00
#ifndef NOPRINT
2024-09-09 06:13:24 +00:00
// clang-format off
haloo3d_print(&pt,
"Pframe: %05.2f (%05.2f) DT: %0.3f\n"
2024-09-21 04:15:10 +00:00
#ifndef LIMITEDPRINT
2024-09-09 06:13:24 +00:00
"PSDLFl: %05.2f (%05.2f)\n"
2024-09-09 06:32:02 +00:00
"Render: %05.2f (%05.2f)\n"
"PlPos: %05.2f (%05.2f)\n"
2024-09-21 04:15:10 +00:00
#endif
2024-09-09 06:32:02 +00:00
"Tris: %d\n",
2024-09-09 06:13:24 +00:00
frametimer.last * 1000, frametimer.sum * 1000, ecs.delta_s,
2024-09-21 04:15:10 +00:00
#ifndef LIMITEDPRINT
sdltimer.last * 1000, sdltimer.sum * 1000,
2024-09-09 06:32:02 +00:00
drawtimer.last * 1000, drawtimer.sum * 1000,
playerpos->pos.x, playerpos->pos.z,
2024-09-21 04:15:10 +00:00
#endif
2024-09-09 06:32:02 +00:00
ecs.totaldrawn);
2024-09-24 03:39:34 +00:00
// clang-format on
#endif
// 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);
}
2024-09-09 06:32:02 +00:00
ecs.delta_s = frametimer.last + MAX(waittime, 0);
}
haloo3d_fb_free(&screen);
2024-09-09 06:13:24 +00:00
haloo3d_fb_free(&context.window);
2024-09-14 05:00:20 +00:00
haloo3d_easystore_deleteallobj(&ecs.storage, haloo3d_obj_free);
haloo3d_easystore_deletealltex(&ecs.storage, haloo3d_fb_free);
2024-09-08 22:42:50 +00:00
}