/* 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 //