585 lines
22 KiB
C
585 lines
22 KiB
C
#include "haloo3d/haloo3d.h"
|
|
#include "haloo3d/haloo3dex_easy.h"
|
|
#include "haloo3d/haloo3dex_gen.h"
|
|
#include "haloo3d/haloo3dex_obj.h"
|
|
|
|
#include "haloo3d/haloo3dex_print.h"
|
|
#include "haloo3d/lib/FastNoiseLite.h"
|
|
#include "haloo3d/lib/mathc.h"
|
|
#include "unigi/main.h"
|
|
|
|
// #include "keys.h"
|
|
// #define ECS_MAXENTITIES 30000
|
|
#include "terrain_ecstypes.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
|
|
#define WIDTH 480
|
|
#define HEIGHT 300
|
|
#define SCREENSCALE 2
|
|
#define SWIDTH (WIDTH * SCREENSCALE)
|
|
#define SHEIGHT (HEIGHT * SCREENSCALE)
|
|
#define AVGWEIGHT 0.85
|
|
#define DEFAULTUP \
|
|
{ .x = 0, .y = 1, .z = 0 }
|
|
// Lookvec for objects which all face forward along with the player
|
|
#define DEFAULTLOOK \
|
|
{ .x = 0, .y = 0, .z = -1 }
|
|
// How big each chunk is (x and y, square). MUST BE POWER OF 2 - 1
|
|
#define CHUNKSIZE 7 // This is the width in tiles
|
|
#define CHUNKSCALE 1.0 / CHUNKSIZE
|
|
// This is how many vertices across a chunk is
|
|
#define CHUNKVSIZE (CHUNKSIZE + 1)
|
|
#define VIEWDISTANCE 10
|
|
#define PLBOXEDGE (VIEWDISTANCE * 2 + 1)
|
|
#define INIT_NEARCLIP 0.01
|
|
#define INIT_FARCLIP 100.0
|
|
|
|
#define MAXCHUNKPERFRAME 1
|
|
|
|
// Generation consts / things for looks
|
|
#define LANDCOL 0xF4E1
|
|
#define SEACOL 0xF26C
|
|
#define LANDHEIGHT 4.0
|
|
#define SKYCOL 0xF77F
|
|
#define INIT_LIGHTPITCH MPI_2 * 1.65
|
|
#define INIT_LIGHTYAW MPI_2 * 0.65
|
|
#define INIT_MINLIGHT 0.2
|
|
#define INIT_DITHERSTART 3
|
|
#define INIT_DITHEREND 10
|
|
|
|
// Player things
|
|
#define INIT_FOV 90.0
|
|
#define INIT_CAMPITCH MPI_2 * 1.2 // MPI_2 * 1.6 // 1.575
|
|
#define INIT_PLAYERHEIGHT 0.65
|
|
#define INIT_PLAYERSPEED \
|
|
{ .x = 0, .y = 0, .z = -9.5 }
|
|
|
|
#define RANDF() ((float)rand() / RAND_MAX)
|
|
|
|
// Some globals you can mess around with potentially
|
|
int fps = 60;
|
|
|
|
#define PALETTEKEY "palette"
|
|
|
|
void fastface(haloo3d_facei face, uint16_t tex, uint16_t v0, uint16_t v1,
|
|
uint16_t v2) {
|
|
face[0].texi = tex;
|
|
face[1].texi = tex;
|
|
face[2].texi = tex;
|
|
face[0].posi = v0;
|
|
face[1].posi = v1;
|
|
face[2].posi = v2;
|
|
}
|
|
|
|
static int gen_terrain_seed = 0;
|
|
|
|
void gen_terrain(struct vec3i pos, haloo3d_obj *model) {
|
|
eprintf("Generating terrain at %d,%d\n", pos.x, pos.z);
|
|
// Don't allow the model to have more than some amount of faces/vertices.
|
|
haloo3d_obj_resetfixed(model, CHUNKVSIZE * CHUNKVSIZE * 4,
|
|
CHUNKVSIZE * CHUNKVSIZE * 4);
|
|
struct vec3 landcol = haloo3d_gen_paletteuv(LANDCOL); // 0xF2C0);
|
|
int landuv = haloo3d_obj_addvtexture(model, landcol);
|
|
fnl_state ns = fnlCreateState();
|
|
ns.noise_type = FNL_NOISE_OPENSIMPLEX2;
|
|
ns.seed = gen_terrain_seed;
|
|
ns.frequency = 0.025;
|
|
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
|
|
haloo3d_obj_addvertex(model,
|
|
(struct vec4){.x = x, .y = fnlGetNoise2D(&ns, noisex + x, noisey + z), .z = -z });
|
|
//(struct vec4){.x = x, .y = 2 * RANDF() - 1, .z = -z});
|
|
// clang-format on
|
|
}
|
|
}
|
|
for (int i = 0; i < CHUNKVSIZE * (CHUNKVSIZE - 1); i++) {
|
|
if ((i & CHUNKSIZE) == CHUNKSIZE) {
|
|
continue;
|
|
}
|
|
uint16_t bl = i;
|
|
uint16_t br = i + 1;
|
|
uint16_t tl = i + CHUNKVSIZE;
|
|
uint16_t tr = i + CHUNKVSIZE + 1;
|
|
haloo3d_facei face;
|
|
fastface(face, landuv, bl, br, tl);
|
|
haloo3d_obj_addface(model, face);
|
|
fastface(face, landuv, br, tr, tl);
|
|
haloo3d_obj_addface(model, face);
|
|
}
|
|
haloo3d_obj_shrinktofit(model);
|
|
}
|
|
|
|
// 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)
|
|
void gen_chunk(render_context *ctx, tecs *ecs, struct vec3i pos) {
|
|
// 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);
|
|
gen_terrain(pos, model);
|
|
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,
|
|
.pos = {.x = pos.x, .y = pos.y, .z = pos.z}};
|
|
// 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){
|
|
.texture = haloo3d_easystore_gettex(&ecs->storage, PALETTEKEY),
|
|
.scale = {.x = CHUNKSCALE, .y = CHUNKSCALE * LANDHEIGHT, .z = CHUNKSCALE},
|
|
.lighting = &ecs->chunklight,
|
|
.model = model,
|
|
.cullbackface = 1,
|
|
.context = {ctx},
|
|
.contextcount = 1};
|
|
}
|
|
|
|
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)};
|
|
// 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);
|
|
// eprintf("KILLABLE OBJS: %d PCHUNK: %d,%d\n", mcount, pchunk.x, pchunk.y);
|
|
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
|
|
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
|
|
obj->contextcount--;
|
|
}
|
|
// 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;
|
|
int surz = chunk->pos.z - pchunk.z + VIEWDISTANCE;
|
|
if (surx >= 0 && surz >= 0 && surx < PLBOXEDGE && surz < PLBOXEDGE) {
|
|
// eprintf("SUR: %d %d\n", surx, sury);
|
|
surround[surz][surx] = 1; // matches[i];
|
|
}
|
|
}
|
|
}
|
|
int chunkgen = 0;
|
|
// We now have our view radius box and which chunks are not loaded. Up to
|
|
// some amount, let's load them
|
|
for (int z = pchunk.z - VIEWDISTANCE; z <= pchunk.z + VIEWDISTANCE; z++) {
|
|
for (int x = pchunk.x - VIEWDISTANCE; x <= pchunk.x + VIEWDISTANCE; x++) {
|
|
int surx = x - pchunk.x + VIEWDISTANCE;
|
|
int surz = z - pchunk.z + VIEWDISTANCE;
|
|
if (!surround[surz][surx]) {
|
|
gen_chunk(ctx, ecs, (struct vec3i){.x = x, .y = 0, .z = z});
|
|
//.y = pchunk.y - VIEWDISTANCE + y});
|
|
if (++chunkgen >= MAXCHUNKPERFRAME) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------
|
|
// The terrain ecs systems
|
|
// ---------------------------------------------------
|
|
|
|
// All initialization for a specific render context
|
|
void sys_rendercontext(ecs_rendercontext *erc, ecs_placement *p, tecs **ecs) {
|
|
render_context *rc = *erc;
|
|
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);
|
|
}
|
|
// 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);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
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);
|
|
// vec3_multiply(p->pos.v, p->pos.v, p->pos.v);
|
|
}
|
|
|
|
// Perform the entire rendering of an object
|
|
void sys_renderobject(ecs_placement *p, ecs_object *o, tecs **ecs) {
|
|
// --**-- First, precalc all the vertices in the object --**--
|
|
mfloat_t tmp[VEC4_SIZE];
|
|
mfloat_t modelm[MAT4_SIZE];
|
|
mfloat_t finalmatrix[MAT4_SIZE];
|
|
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);
|
|
// 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++) {
|
|
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);
|
|
o->context[ctx]->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(<mp, 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 --**--
|
|
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[ctx]->rendersettings.flags;
|
|
if (o->lighting) {
|
|
haloo3d_obj_facef(o->model, o->model->faces[facei], baseface);
|
|
o->context[ctx]->rendersettings.intensity =
|
|
haloo3d_calc_light(lighting.v, o->lighting->minlight, baseface);
|
|
} else {
|
|
o->context[ctx]->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;
|
|
}
|
|
(*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);
|
|
haloo3d_triangle(&o->context[ctx]->window,
|
|
&o->context[ctx]->rendersettings, outfaces[ti]);
|
|
}
|
|
o->context[ctx]->rendersettings.flags = oflags;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
// void sys_chunk(ecs_chunk *ch, ecs_object *o, tecs **ecs) {
|
|
// // Is it really ok to have this check every single time? Seems kinda
|
|
// wasteful if (ch->generation == 1) {
|
|
// }
|
|
// }
|
|
|
|
// ---------------------------------------------------
|
|
// Setup functions
|
|
// ---------------------------------------------------
|
|
|
|
ecs_eid setup_player(tecs *ecs, render_context *context) {
|
|
ecs_eid playerid = tecs_newentity(ecs, 0);
|
|
ECS_SETCOMPONENT(ecs, playerid, ecs_placement){
|
|
.pos = {.x = 0, .y = INIT_PLAYERHEIGHT, .z = 0}, .up = DEFAULTUP};
|
|
ECS_SETCOMPONENT(ecs, playerid, ecs_movement){.pos = INIT_PLAYERSPEED};
|
|
ECS_SETCOMPONENT(ecs, playerid, ecs_rotation){.yaw = 0,
|
|
.pitch = INIT_CAMPITCH};
|
|
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);
|
|
struct vec3 seacol = haloo3d_gen_paletteuv(SEACOL); // 0xF26F);
|
|
int seauv = haloo3d_obj_addvtexture(model, seacol);
|
|
// struct vec3 seacol2 = haloo3d_gen_paletteuv(0xF008);
|
|
// haloo3d_obj_addvtexture(model, seacol2);
|
|
// 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);
|
|
// model->faces[0][0].texi++;
|
|
fastface(face, seauv, br, tr, tl);
|
|
haloo3d_obj_addface(model, face);
|
|
ECS_SETCOMPONENT(ecs, seaid, ecs_object){
|
|
.texture = haloo3d_easystore_gettex(&ecs->storage, PALETTEKEY),
|
|
.scale = {.x = VIEWDISTANCE * 0.5,
|
|
.y = VIEWDISTANCE * 0.5,
|
|
.z = VIEWDISTANCE * 0.5},
|
|
.lighting = NULL,
|
|
.model = model,
|
|
.cullbackface = 1,
|
|
.context = {ctx},
|
|
.contextcount = 1};
|
|
return seaid;
|
|
}
|
|
|
|
// ---------------------------------------------------
|
|
// MAIN FUNCTION
|
|
// ---------------------------------------------------
|
|
|
|
int main() { // int argc, char **argv) {
|
|
srand(clock());
|
|
gen_terrain_seed = rand();
|
|
|
|
// 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);
|
|
haloo3d_print_tracker pt;
|
|
char printbuf[8192];
|
|
haloo3d_print_initdefault(&pt, printbuf, sizeof(printbuf));
|
|
pt.fb = &screen;
|
|
pt.scale = 1;
|
|
|
|
haloo3d_easytimer frametimer, drawtimer, sdltimer;
|
|
haloo3d_easytimer_init(&frametimer, AVGWEIGHT);
|
|
haloo3d_easytimer_init(&drawtimer, AVGWEIGHT);
|
|
haloo3d_easytimer_init(&sdltimer, AVGWEIGHT);
|
|
|
|
render_context context;
|
|
context.windowclear = SKYCOL;
|
|
context.nearclip = INIT_NEARCLIP;
|
|
context.farclip = INIT_FARCLIP;
|
|
context.fov = INIT_FOV;
|
|
haloo3d_trirender_init(&context.rendersettings);
|
|
context.rendersettings.ditherclose = INIT_DITHERSTART;
|
|
context.rendersettings.ditherfar = INIT_DITHEREND;
|
|
haloo3d_fb_init(&context.window, WIDTH, HEIGHT);
|
|
|
|
eprintf("Initialized screen buffers, context, and timers\n");
|
|
|
|
tecs ecs;
|
|
ecs.delta_s = 0;
|
|
tecs_init(&ecs);
|
|
int tecs_size = sizeof(tecs);
|
|
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);
|
|
|
|
eprintf("Setup ECS system + obj/tex storage (%d bytes)\n", tecs_size);
|
|
|
|
ecs_eid playerid = setup_player(&ecs, &context);
|
|
ecs_placement *playerpos = &ECS_GETCOMPONENT(&ecs, playerid, ecs_placement);
|
|
ecs_eid seaid = setup_sea(&ecs, &context, playerpos, &ecs.storage);
|
|
|
|
eprintf("Setup player(%d) + sea(%d)\n", playerid, seaid);
|
|
|
|
// MAIN LOOP
|
|
while (1) {
|
|
haloo3d_easytimer_start(&frametimer);
|
|
haloo3d_print_refresh(&pt);
|
|
ecs.totaldrawn = 0;
|
|
|
|
// ECS logic (which includes rendering)
|
|
if (ecs.delta_s) {
|
|
ECS_RUNSYSTEM1(&ecs, sys_playerinput, ecs_input);
|
|
ECS_RUNSYSTEM2(&ecs, sys_rotation, ecs_placement, ecs_rotation);
|
|
ECS_RUNSYSTEM3(&ecs, sys_movement, ecs_placement, ecs_movement, tecs);
|
|
ECS_RUNSYSTEM2(&ecs, sys_placement_lock, ecs_placement_lock,
|
|
ecs_placement);
|
|
ECS_RUNSYSTEM3(&ecs, sys_rendercontext, ecs_rendercontext, ecs_placement,
|
|
tecs);
|
|
ECS_RUNSYSTEM3(&ecs, sys_playergarbage, ecs_playergarbage, ecs_object,
|
|
tecs);
|
|
haloo3d_easytimer_start(&drawtimer);
|
|
ECS_RUNSYSTEM3(&ecs, sys_renderobject, ecs_placement, ecs_object, tecs);
|
|
haloo3d_easytimer_end(&drawtimer);
|
|
}
|
|
|
|
// Scale 3D into final buffer
|
|
haloo3d_fb_fill(&screen, &context.window);
|
|
|
|
// clang-format off
|
|
haloo3d_print(&pt,
|
|
"Pframe: %05.2f (%05.2f) DT: %0.3f\n"
|
|
"PSDLFl: %05.2f (%05.2f)\n"
|
|
"Render: %05.2f (%05.2f)\n"
|
|
"PlPos: %05.2f (%05.2f)\n"
|
|
"Tris: %d\n",
|
|
frametimer.last * 1000, frametimer.sum * 1000, ecs.delta_s,
|
|
sdltimer.last * 1000, sdltimer.sum * 1000,
|
|
drawtimer.last * 1000, drawtimer.sum * 1000,
|
|
playerpos->pos.x, playerpos->pos.z,
|
|
ecs.totaldrawn);
|
|
// clang-format on
|
|
|
|
// 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);
|
|
}
|
|
ecs.delta_s = frametimer.last + MAX(waittime, 0);
|
|
}
|
|
|
|
haloo3d_fb_free(&screen);
|
|
haloo3d_fb_free(&context.window);
|
|
haloo3d_easystore_deleteallobj(&ecs.storage, haloo3d_obj_free);
|
|
haloo3d_easystore_deletealltex(&ecs.storage, haloo3d_fb_free);
|
|
}
|