383 lines
11 KiB
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 //
|