#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/mathc.h" #include "unigi/main.h" #include "ecs2.h" // #include "keys.h" #include "terrain_ecstypes.h" #include #include #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 } // These are initial values but there may be ways to change it #define CAM_INITPITCH MPI_2 #define INIT_NEARCLIP 0.01 #define INIT_FARCLIP 100.0 #define INIT_FOV 90.0 #define INIT_DITHERSTART 10000 #define INIT_DITHEREND 10000 #define INIT_PLAYERSPEED \ { .x = 0, .y = 0, .z = -0.5 } // Some globals you can mess around with potentially int fps = 30; // --------------------------------------------------- // The terrain ecs systems // --------------------------------------------------- // All initialization for a specific render context void sys_rendercontext(ecs_rendercontext *erc, ecs_placement *p) { 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); } // 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); } // 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); mat4_multiply(finalmatrix, o->context->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->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->rendersettings.flags; if (o->lighting) { haloo3d_obj_facef(o->model, o->model->faces[facei], baseface); o->context->rendersettings.intensity = haloo3d_calc_light(lighting.v, o->lighting->minlight, baseface); } else { o->context->rendersettings.intensity = H3DVF(1.0); } // if ((r->_objstate[object - r->objects] & H3D_EASYOBJSTATE_NOTRANS)) { // r->rendersettings.flags &= ~H3DR_TRANSPARENCY; // } for (int ti = 0; ti < tris; ti++) { int backface = !haloo3d_facef_finalize(outfaces[ti]); if (o->cullbackface && backface) { continue; } (*ecs)->totaldrawn++; // We still have to convert the points into the view haloo3d_facef_viewport_into_fast(outfaces[ti], o->context->precalc_halfwidth, o->context->precalc_halfheight); haloo3d_triangle(&o->context->window, &o->context->rendersettings, outfaces[ti]); } o->context->rendersettings.flags = oflags; } } } 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); } // --------------------------------------------------- // MAIN FUNCTION // --------------------------------------------------- int main() { // int argc, char **argv) { srand(clock()); // 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_easystore storage; haloo3d_easystore_init(&storage); haloo3d_fb *palettetex = haloo3d_easystore_addtex(&storage, "palette"); haloo3d_gen_palettetex(palettetex); eprintf("Initialized storage and default textures/etc\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; 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 = 0xF000; context.nearclip = INIT_NEARCLIP; context.farclip = INIT_FARCLIP; context.fov = INIT_FOV; 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); ecs_eid playerid = tecs_newentity(&ecs, 0); ECS_SETCOMPONENT(&ecs, playerid, ecs_placement){ .pos = {.x = 0, .y = 10, .z = 0}, .up = DEFAULTUP}; ECS_SETCOMPONENT(&ecs, playerid, ecs_movement){.pos = INIT_PLAYERSPEED}; ECS_SETCOMPONENT(&ecs, playerid, ecs_rotation){.yaw = 0, .pitch = CAM_INITPITCH}; ECS_SETCOMPONENT(&ecs, playerid, ecs_rendercontext) & context; ECS_SETCOMPONENT(&ecs, playerid, ecs_input){}; ecs_placement *playerpos = &ECS_GETCOMPONENT(&ecs, playerid, ecs_placement); eprintf("Setup ECS system (%d bytes)\n", tecs_size); // 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_rendercontext, ecs_rendercontext, ecs_placement); 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(&storage, haloo3d_obj_free); haloo3d_easystore_deletealltex(&storage, haloo3d_fb_free); }