mr4th/src/main.c

383 lines
11 KiB
C

/* TODO(allen) - main.c
**
** Functions that need to do log output end up with complicated
** signatures or bad coupling of the arena usage and the log output.
** The user is forced to manually manage the log in-out parameters.
** Build a better logging system and update the functions labeled
** with "Better logging here" TODOs.
**
** Unicode conversions should take string lists.
** Find "Better unicode conversions here"
**
** EXPERIMENT IDEAS
** Roll a codebase-wide custodian system
** Arena header for dynamically interfacing arenas between
** fully separated layers
**
** RESEARCH
** Is there any way to do OffsetOfMember without
** relying on undefined behavior?
**
*/
// TODO(allen):
//
// [ ] "render" should give a prescribed way for a user to
// down shift into lower level APIs (i.e. writing opengl
// or d3d11 directly).
// Each backend would have a concrete 'downshift' API that
// lets you seamlessly extract the parts of the system you
// need. --- This would *HAVE* to be per-backend. There is
// no way to describe downshifting into a lower level API
// that does not involve coupling to the lower level API.
// `` "glBlendFunc" statefulness compositional problems. ``
// ^^ This problem is actually a specific case of what I
// just described as a downshifting problem above.
// Someone mixing their own features in with render
// would need a prescribed way to restore *render*'s
// chose defaults.
//
// [ ] optimization pass over opengl render backend
//
// [ ] UTF-8 decoding version of "draw_string"
//
// [ ] A way to check equipment
// [ ] "Check equipment here" (tagged in several locations)
// [ ] optimized (HWND -> GFX_Window) mapping
//
// [ ] How should the resize handler be written?
// [ ] Make it look good when we resize
// [ ] Does it need to know about the equipped renderer?
#include "base/base_inc.h"
#include "wave/riff_format.h"
#include "wave/wave_format.h"
#include "wave/wave_parser.h"
#include "temp_wave.h"
#include "audio_gen.h"
#include "art/color.h"
#include "font/font_types.h"
#include "font/font_parse_by_freetype.h"
#include "icon_codes.h"
#include "os/os_inc.h"
#include "gfx/gfx_inc.h"
#include "render/render_inc.h"
#include "d3d11/d3d11_inc.h"
#include "base/base_inc.c"
#include "base/base_big_functions.c"
#include "wave/wave_parser.c"
#include "temp_wave.c"
#include "audio_gen.c"
#include "art/color.c"
#include "font/font_types.c"
#include "font/font_parse_by_freetype.c"
#include "os/os_inc.c"
#include "gfx/gfx_inc.c"
#include "render/render_inc.c"
////////////////////////////////
// NOTE(allen): Main
function void
window_resize_handler(GFX_Window *window, U32 width, U32 height){
ogl_begin(window);
r_canvas_init(v2s32(width, height));
r_show_canvas_on_activated_window();
ogl_end();
}
#define color_linu32_from_srgba(r,g,b,a) \
color_linear_from_srgb_u32(color_u32_from_4f32(r,g,b,a))
#define color_linu32_from_srgba_v(v) \
color_linear_from_srgb_u32(color_u32_from_4f32(V4_EXPANDED(v)))
int
WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd){
ProfOpen("profile.spall");
ProfThreadBegin();
ProfBegin("program-init");
w32_WinMain_init(hInstance, hPrevInstance, lpCmdLine, nShowCmd);
er_accum_begin();
Arena *arena = arena_alloc();
Arena *frame_arena = arena_alloc();
// initialize graphics and rendering
gfx_init();
gfx_set_resizing_hook(window_resize_handler);
r_init();
// initialize font
#define FONT_COUNT 3
R_Font *font[FONT_COUNT] = {0};
{
String8 font_names[FONT_COUNT] = {
str8_lit("liberation-mono.ttf"),
str8_lit("Exo-Regular.ttf"),
str8_lit("icon_font.ttf"),
};
FONT_PackParams pack_params = {0};
pack_params.max_glyph_side = 64;
pack_params.initial_atlas_side = 64;
pack_params.max_grow_count = 10;
r_backend_begin(0);
for (U64 i = 0; i < FONT_COUNT; i += 1){
ArenaTemp scratch = arena_get_scratch(0, 0);
String8 name = font_names[i];
String8 data = os_file_read(scratch.arena, name);
log_accum_begin();
FONT_Loose *loose = font_parse_by_freetype(scratch.arena, data);
font[i] = r_font_bake_and_build_texture(arena, loose, &pack_params);
String8 log = log_accum_end(scratch.arena);
if (log.size != 0){
gfx_message_box(str8_lit("FreeType Log"), log);
}
arena_release_scratch(&scratch);
}
r_backend_end();
}
// setup a window
GFX_Window *window = gfx_window_create();
r_backend_equip_window(window);
gfx_window_set_title(window, str8_lit("Render Window"));
// calculate frame rate control factors
U64 ratio_usecs = 0;
U64 ratio_ticks = 0;
os_microseconds_over_ticks(&ratio_usecs, &ratio_ticks);
U64 frame_per_second = gfx_window_refresh_rate(window);
U64 usec_per_frame = Million(1)/frame_per_second;
U64 tick_per_frame = usec_per_frame*ratio_ticks/ratio_usecs;
// convert to string
String8 usec_per_frame_string = str8_pushf(arena, "%8llu", usec_per_frame);
// previous frame length
U64 frame_index = 0;
// check for any errors during initialization
{
ArenaTemp scratch = arena_get_scratch(0, 0);
String8 error = er_accum_end(scratch.arena);
if (error.size != 0){
gfx_message_box(str8_lit("Initialization Error"), error);
os_exit_process(1);
}
arena_release_scratch(&scratch);
}
ProfEnd();
// begin UI loop
B32 loop_good = 1;
U64 frame_begin_t = os_now_ticks();
gfx_window_set_visible(window, 1);
for (;loop_good;){
// frame begin
ProfBegin("frame-loop");
er_accum_begin();
arena_pop_to(frame_arena, 0);
// calculate target end
U64 frame_target_end_t = frame_begin_t + tick_per_frame;
// wait for input
if (!gfx_peek_input()){
loop_good = 0;
goto frame_end;
}
// draw gl window
if (gfx_window_is_valid(window)){
V2S32 window_dim = {0};
{
RectS32 rect = {0};
if (gfx_window_get_inner_rect(window, &rect)){
window_dim = dim_from_rects32(rect);
}
}
r_backend_begin(window);
r_canvas_init(window_dim);
R_List rlist = {0};
{
U32 c0 = color_linu32_from_srgba(0.9f, 0.1f, 0.0f, 0.3f);
U32 c1 = color_linu32_from_srgba(0.8f, 0.0f, 0.0f, 0.3f);
U32 c2 = color_linu32_from_srgba(0.1f, 0.9f, 0.0f, 0.3f);
U32 c3 = color_linu32_from_srgba(0.0f, 0.9f, 0.1f, 0.3f);
U32 c4 = color_linu32_from_srgba(1.0f, 1.0f, 0.5f, 0.3f);
U32 c5 = color_linu32_from_srgba(0.4f, 0.8f, 1.0f, 0.3f);
R_Ctx rctx = r_ctx_make(frame_arena, &rlist);
if (frame_index < 95){
F32 clip_amt = frame_index*(1920.f/95.f);
r_ctx_clip(&rctx, 1, rectf32(0, 0, clip_amt, clip_amt));
}
{
R_Quad quad = {0};
quad.xy = rectf32(400.f, 200.f, 430.f, 230.f);
quad.radius = 500.f;
quad.theta = tau_F32*0.125f;
quad.c[0] = 0xFFFFFFFF;
quad.c[1] = 0xFFFFFFFF;
quad.flags = R_QuadFlag_SharpCornerBL;
r_ctx_apply_clip(&rctx, &quad);
r_quad(&rctx, &quad, 0);
}
r_rect(&rctx, rectf32(5.f, 5.f, 45.f, 45.f), 5.f, c0);
r_rect(&rctx, rectf32(55.f, 5.f, 95.f, 45.f), 5.f, c0);
r_rect(&rctx, rectf32(5.f, 50.f, 45.f, 70.f), 0.f, c2);
r_rect(&rctx, rectf32(55.f, 50.f, 95.f, 70.f), 0.f, c3);
r_ctx_font(&rctx, font[0]);
//r_string(&rctx, str8_lit("Hello, World!!!"), v2f32(25.f, 50.f), c4);
r_rect(&rctx, rectf32(5.f, 105.f, 45.f, 145.f), 5.f, c0);
r_rect(&rctx, rectf32(55.f, 105.f, 95.f, 145.f), 5.f, c0);
r_rect(&rctx, rectf32(5.f, 150.f, 45.f, 170.f), 0.f, c2);
r_rect(&rctx, rectf32(55.f, 150.f, 95.f, 170.f), 0.f, c1);
r_ctx_font(&rctx, font[1]);
r_string(&rctx, str8_lit("Font Change!"), v2f32(25.f, 150.f), c4);
r_ctx_font(&rctx, font[2]);
r_char(&rctx, ICON_LOCK, v2f32(25.f, 250.f), c5);
r_char(&rctx, ICON_LOCK_OPEN_ALT, v2f32(50.f, 250.f), c5);
// gradient test
{
R_Quad quad = {0};
quad.xy = rectf32(100.f, 400.f, 250.f, 415.f);
quad.c[0] = color_linu32_from_srgba(0.f, 0.f, 0.f, 1.f);
quad.c[1] = color_linu32_from_srgba(1.f, 1.f, 1.f, 1.f);
quad.flags |= R_QuadFlag_HzGradient;
r_ctx_apply_clip(&rctx, &quad);
r_quad(&rctx, &quad, 0);
}
// text srgb test
{
r_ctx_font(&rctx, font[0]);
r_string(&rctx, str8_lit("[ ABC, abc; 0123: XYZ | xyz ]"),
v2f32(400.f, 400.f), 0x8000FF80);
}
// segment test
{
U32 c = color_linu32_from_srgba(0.4f, 0.9f, 0.1f, 1.f);
V2F32 p[5] = {
v2f32(400.f, 450.f),
v2f32(450.f, 500.f),
v2f32(550.f, 450.f),
v2f32(500.f, 650.f),
v2f32(400.f, 550.f),
};
for (U32 i = 1; i < ArrayCount(p); i += 1){
r_segment(&rctx, p[i - 1], p[i], 2.f, c);
}
}
}
r_flush(&rlist);
r_show_canvas_on_activated_window();
r_backend_end();
}
ProfEnd();
ProfThreadFlush();
// frame time controls
{
U64 now_t = os_now_ticks();
// save frame length in microseconds
{
U64 frame_length_t = 0;
if (now_t > frame_begin_t){
frame_length_t = now_t - frame_begin_t;
}
U64 frame_length_usec = frame_length_t*ratio_usecs/ratio_ticks;
}
// rest away time
if (now_t < frame_target_end_t){
U64 left_over_t = frame_target_end_t - now_t;
U64 left_over_usec = left_over_t*ratio_usecs/ratio_ticks;
U64 left_over_msec = left_over_usec/1000;
Sleep(left_over_msec);
now_t = os_now_ticks();
}
// shift frame begin t up
B32 bad_t = 0;
{
if (now_t < frame_target_end_t ||
now_t - frame_target_end_t < tick_per_frame/16){
frame_begin_t = frame_target_end_t;
}
else{
frame_begin_t = now_t;
bad_t = 1;
}
}
}
// increment frame index
frame_index += 1;
// frame end
frame_end:
{
ArenaTemp scratch = arena_get_scratch(0, 0);
String8 error = er_accum_end(scratch.arena);
if (error.size != 0){
gfx_message_box(str8_lit("Frame Error"), error);
os_exit_process(1);
}
arena_release_scratch(&scratch);
}
}
ProfThreadEnd();
ProfClose();
return(0);
}
//$ graphical freetype //