Paged memory allocator, and async file system
This commit is contained in:
parent
6775ea26d3
commit
6e80c811cf
18
admin.txt
18
admin.txt
|
@ -7,14 +7,20 @@
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
1. Upgrade Lumenarium's plubming
|
1. Upgrade Lumenarium's plumbing
|
||||||
1. switch over to compiling with clang & bash based build scripts
|
x. switch over to compiling with clang & bash based build scripts
|
||||||
2. better platform layer separation
|
x. better platform layer separation
|
||||||
3. osx and webgl layers, possibly linux?
|
3. osx and webgl layers, possibly linux?
|
||||||
4. remove dll compiling, just build all in one go
|
x. remove dll compiling, just build all in one go
|
||||||
5. improve ui
|
5. improve ui
|
||||||
1. default to using a basic layout object
|
[ ] get widgets and widget ids working
|
||||||
2. improve widget handling (see a_trick_of_fate)
|
- see a trick of fate
|
||||||
|
[ ] clip widgets to regions
|
||||||
|
[ ] text rendering
|
||||||
|
[ ] interaction
|
||||||
|
[ ] layout manager
|
||||||
|
- do layout the way youre doing styling - optional pointer to a struct
|
||||||
|
and fallback on some global default
|
||||||
|
|
||||||
2. Incenter
|
2. Incenter
|
||||||
1. Sculpture generation from list of lat-long coordinates
|
1. Sculpture generation from list of lat-long coordinates
|
||||||
|
|
|
@ -144,7 +144,7 @@ CompilerFlags_DEBUG_win32=""
|
||||||
add_flag CompilerFlags_DEBUG_win32 "-Od" #
|
add_flag CompilerFlags_DEBUG_win32 "-Od" #
|
||||||
add_flag CompilerFlags_DEBUG_win32 "-Zi" #
|
add_flag CompilerFlags_DEBUG_win32 "-Zi" #
|
||||||
add_flag CompilerFlags_DEBUG_win32 "-DDEBUG" #
|
add_flag CompilerFlags_DEBUG_win32 "-DDEBUG" #
|
||||||
add_flag CompilerFlags_DEBUG_win32 "-DPRINT_ASSERTS"
|
# add_flag CompilerFlags_DEBUG_win32 "-DPRINT_ASSERTS"
|
||||||
|
|
||||||
CompilerFlags_DEBUG="-O0"
|
CompilerFlags_DEBUG="-O0"
|
||||||
add_flag CompilerFlags_DEBUG "-g" #
|
add_flag CompilerFlags_DEBUG "-g" #
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -81,7 +81,7 @@ void make_quad(Platform_Geometry_Buffer* geo, Platform_Shader* shd, Platform_Tex
|
||||||
lit_str("uv"),
|
lit_str("uv"),
|
||||||
};
|
};
|
||||||
*shd = platform_shader_create(
|
*shd = platform_shader_create(
|
||||||
shader_code_vert, shader_code_frag, attribs, 2
|
shader_code_vert, shader_code_frag, attribs, 2, 0, 0
|
||||||
);
|
);
|
||||||
|
|
||||||
platform_vertex_attrib_pointer(*geo, *shd, 4, shd->attrs[0], 6, 0);
|
platform_vertex_attrib_pointer(*geo, *shd, 4, shd->attrs[0], 6, 0);
|
||||||
|
@ -90,30 +90,38 @@ void make_quad(Platform_Geometry_Buffer* geo, Platform_Shader* shd, Platform_Tex
|
||||||
*tex = platform_texture_create((u8*)pix, 4, 4, 4);
|
*tex = platform_texture_create((u8*)pix, 4, 4, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ed_load_font_cb(Platform_File_Async_Job_Args result)
|
||||||
|
{
|
||||||
|
s32 x = 5;
|
||||||
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
ed_init(App_State* state)
|
ed_init(App_State* state)
|
||||||
{
|
{
|
||||||
Editor* editor = allocator_alloc_struct(permanent, Editor);
|
Editor* editor = allocator_alloc_struct(permanent, Editor);
|
||||||
state->editor = editor;
|
state->editor = editor;
|
||||||
|
state->editor->ui = ui_create(4096, 4096, state->input_state, permanent);
|
||||||
|
|
||||||
|
// make the default quad for us to draw with
|
||||||
|
// TODO(PS): this might be unnecessary with the per-frame buffer we use now
|
||||||
make_quad(&editor->renderer.geo, &editor->renderer.shd, &editor->renderer.tex);
|
make_quad(&editor->renderer.geo, &editor->renderer.shd, &editor->renderer.tex);
|
||||||
|
|
||||||
|
platform_file_async_read(lit_str("data/font.ttf"), ed_load_font_cb);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
ed_frame_prepare(App_State* state)
|
ed_frame_prepare(App_State* state)
|
||||||
{
|
{
|
||||||
|
ui_frame_prepare(&state->editor->ui, state->editor->window_dim);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
ed_frame(App_State* state)
|
ed_frame(App_State* state)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < 16; i++)
|
edr_render_begin(state);
|
||||||
{
|
ui_draw(&state->editor->ui);
|
||||||
if (i % 2 == 1) continue;
|
|
||||||
pix[i] += 1;
|
|
||||||
}
|
|
||||||
platform_texture_update(state->editor->renderer.tex, (u8*)pix, 4, 4, 4);
|
|
||||||
|
|
||||||
edr_render(state);
|
edr_render(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ struct Editor
|
||||||
{
|
{
|
||||||
v2 window_dim;
|
v2 window_dim;
|
||||||
Editor_Renderer renderer;
|
Editor_Renderer renderer;
|
||||||
|
UI ui;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //LUMENARIUM_EDITOR_H
|
#endif //LUMENARIUM_EDITOR_H
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
edr_render(App_State* state)
|
edr_render_begin(App_State* state)
|
||||||
{
|
{
|
||||||
Platform_Graphics_Frame_Desc desc = {};
|
Platform_Graphics_Frame_Desc desc = {};
|
||||||
desc.clear_color = { 0.1f, 0.1f, 0.1f, 1 };
|
desc.clear_color = { 0.1f, 0.1f, 0.1f, 1 };
|
||||||
|
@ -9,9 +8,15 @@ edr_render(App_State* state)
|
||||||
desc.viewport_max = state->editor->window_dim;
|
desc.viewport_max = state->editor->window_dim;
|
||||||
platform_frame_begin(desc);
|
platform_frame_begin(desc);
|
||||||
platform_frame_clear();
|
platform_frame_clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
edr_render(App_State* state)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
platform_geometry_bind(state->editor->renderer.geo);
|
platform_geometry_bind(state->editor->renderer.geo);
|
||||||
platform_texture_bind(state->editor->renderer.tex);
|
platform_texture_bind(state->editor->ui.atlas_texture);
|
||||||
platform_shader_bind(state->editor->renderer.shd);
|
platform_shader_bind(state->editor->renderer.shd);
|
||||||
platform_geometry_draw(state->editor->renderer.geo);
|
platform_geometry_draw(state->editor->renderer.geo);
|
||||||
|
#endif
|
||||||
}
|
}
|
|
@ -0,0 +1,452 @@
|
||||||
|
#define WHITE_SPRITE_ID 511
|
||||||
|
|
||||||
|
static String ui_shader_vert_win32 = lit_str(
|
||||||
|
"#version 330 core\n"
|
||||||
|
"layout (location = 0) in vec4 a_pos;\n"
|
||||||
|
"layout (location = 1) in vec2 a_uv;\n"
|
||||||
|
"layout (location = 2) in vec4 a_color;\n"
|
||||||
|
"out vec2 uv;\n"
|
||||||
|
"out vec4 color;\n"
|
||||||
|
"uniform mat4 proj;\n"
|
||||||
|
"void main(void) {\n"
|
||||||
|
" gl_Position = proj * a_pos;\n"
|
||||||
|
" uv = a_uv;\n"
|
||||||
|
" color = a_color;\n"
|
||||||
|
"}"
|
||||||
|
);
|
||||||
|
|
||||||
|
static String ui_shader_frag_win32 = lit_str(
|
||||||
|
"#version 330 core\n"
|
||||||
|
"in vec2 uv;\n"
|
||||||
|
"in vec4 color;\n"
|
||||||
|
"out vec4 FragColor;\n"
|
||||||
|
"uniform sampler2D texture;\n"
|
||||||
|
"void main(void) {\n"
|
||||||
|
" FragColor = texture(texture, uv) * color;\n"
|
||||||
|
" if (FragColor.w <= 0.01f) discard;\n"
|
||||||
|
"}"
|
||||||
|
);
|
||||||
|
|
||||||
|
internal UI
|
||||||
|
ui_create(u32 widget_pool_cap, u32 verts_cap, Input_State* input, Allocator* a)
|
||||||
|
{
|
||||||
|
UI result = {};
|
||||||
|
result.input = input;
|
||||||
|
|
||||||
|
// Widgets
|
||||||
|
result.widgets.free = allocator_alloc_array(a, UI_Widget, widget_pool_cap);
|
||||||
|
result.widgets.free_cap = widget_pool_cap;
|
||||||
|
|
||||||
|
// Per Frame Vertex Buffer
|
||||||
|
result.verts_cap = verts_cap;
|
||||||
|
result.verts = allocator_alloc_array(a, UI_Vertex, verts_cap);
|
||||||
|
result.indices_cap = verts_cap * 2;
|
||||||
|
result.indices = allocator_alloc_array(a, u32, result.indices_cap);
|
||||||
|
|
||||||
|
result.per_frame_buffer = platform_geometry_buffer_create(
|
||||||
|
(r32*)result.verts,
|
||||||
|
result.verts_cap,
|
||||||
|
result.indices,
|
||||||
|
result.indices_cap
|
||||||
|
);
|
||||||
|
|
||||||
|
String attrs[] = { lit_str("a_pos"), lit_str("a_uv"), lit_str("a_color") };
|
||||||
|
String uniforms[] = { lit_str("proj") };
|
||||||
|
result.shader = platform_shader_create(
|
||||||
|
ui_shader_vert_win32,
|
||||||
|
ui_shader_frag_win32,
|
||||||
|
attrs, 3,
|
||||||
|
uniforms, 1
|
||||||
|
);
|
||||||
|
|
||||||
|
platform_vertex_attrib_pointer(
|
||||||
|
result.per_frame_buffer, result.shader, 4, result.shader.attrs[0], 10, 0
|
||||||
|
);
|
||||||
|
platform_vertex_attrib_pointer(
|
||||||
|
result.per_frame_buffer, result.shader, 2, result.shader.attrs[1], 10, 4
|
||||||
|
);
|
||||||
|
platform_vertex_attrib_pointer(
|
||||||
|
result.per_frame_buffer, result.shader, 4, result.shader.attrs[2], 10, 6
|
||||||
|
);
|
||||||
|
|
||||||
|
// Texture Atlas
|
||||||
|
result.atlas = texture_atlas_create(1024, 1024, 512, permanent);
|
||||||
|
result.atlas_texture = platform_texture_create(result.atlas.pixels, 1024, 1024, 1024);
|
||||||
|
|
||||||
|
u32 white_sprite[] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
|
||||||
|
ui_sprite_register(&result, (u8*)white_sprite, 2, 2, WHITE_SPRITE_ID);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal u32
|
||||||
|
ui_vert_push(UI* ui, v3 p, v2 t, v4 c)
|
||||||
|
{
|
||||||
|
assert(ui->verts_len < ui->verts_cap);
|
||||||
|
u32 index = ui->verts_len++;
|
||||||
|
|
||||||
|
ui->verts[index].pos = {p.x, p.y, p.z, 1};
|
||||||
|
ui->verts[index].uv = t;
|
||||||
|
ui->verts[index].color = c;
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_index_push(UI* ui, u32 i)
|
||||||
|
{
|
||||||
|
assert(ui->indices_len < ui->indices_cap);
|
||||||
|
ui->indices[ui->indices_len++] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_quad_push(UI* ui, v3 pmin, v3 pmax, v2 tmin, v2 tmax, v4 c)
|
||||||
|
{
|
||||||
|
u32 bl = ui_vert_push(ui, pmin, tmin, c);
|
||||||
|
u32 br = ui_vert_push(ui, v3{pmax.x, pmin.y, pmin.z}, v2{tmax.x,tmin.y}, c);
|
||||||
|
u32 tr = ui_vert_push(ui, pmax, tmax, c);
|
||||||
|
u32 tl = ui_vert_push(ui, v3{pmin.x, pmax.y, pmin.z}, v2{tmin.x,tmax.y}, c);
|
||||||
|
|
||||||
|
ui_index_push(ui, bl);
|
||||||
|
ui_index_push(ui, br);
|
||||||
|
ui_index_push(ui, tr);
|
||||||
|
|
||||||
|
ui_index_push(ui, bl);
|
||||||
|
ui_index_push(ui, tr);
|
||||||
|
ui_index_push(ui, tl);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_sprite_register(UI* ui, u8* pixels, u32 w, u32 h, u32 id)
|
||||||
|
{
|
||||||
|
texture_atlas_register(&ui->atlas, pixels, w, h, id);
|
||||||
|
platform_texture_update(ui->atlas_texture, ui->atlas.pixels, ui->atlas.width, ui->atlas.height, ui->atlas.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_sprite_push(UI* ui, v3 pmin, v3 pmax, u32 id, v4 color)
|
||||||
|
{
|
||||||
|
v4 uv = texture_atlas_sprite_get_uvs(&ui->atlas, id);
|
||||||
|
ui_quad_push(ui, pmin, pmax, uv.xy, uv.zw, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_sprite_push(UI* ui, v3 pmin, v3 pmax, u32 id)
|
||||||
|
{
|
||||||
|
ui_sprite_push(ui, pmin, pmax, id, v4{1,1,1,1});
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_frame_prepare(UI* ui, v2 window_dim)
|
||||||
|
{
|
||||||
|
ui->verts_len = 0;
|
||||||
|
ui->indices_len = 0;
|
||||||
|
|
||||||
|
ui->widgets.free_len = 0;
|
||||||
|
ui->widgets.active_parent = 0;
|
||||||
|
ui->widgets.root = ui_widget_pool_push(&ui->widgets, lit_str("root"));
|
||||||
|
ui->widgets.active_parent = ui->widgets.root;
|
||||||
|
|
||||||
|
v2 half_d = window_dim * 0.5f;
|
||||||
|
ui->proj = HMM_Orthographic(0, window_dim.x, window_dim.y, 0, 0.01f, 100);
|
||||||
|
|
||||||
|
if (ui->widget_next_hot.value != 0)
|
||||||
|
{
|
||||||
|
ui->widget_next_hot_frames += 1;
|
||||||
|
if (ui->widget_hot_frames > 1)
|
||||||
|
{
|
||||||
|
ui->widget_next_hot = UI_Widget_Id{0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ui->widget_hot.value != 0)
|
||||||
|
{
|
||||||
|
ui->widget_hot_frames += 1;
|
||||||
|
if (ui->widget_hot_frames > 1) ui->widget_hot = UI_Widget_Id{0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global bool show = false;
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_draw(UI* ui)
|
||||||
|
{
|
||||||
|
UI_Widget_Desc d0 = {
|
||||||
|
{
|
||||||
|
(UIWidgetStyle_Bg),
|
||||||
|
WHITE_V4,
|
||||||
|
BLACK_V4,
|
||||||
|
WHITE_SPRITE_ID,
|
||||||
|
},
|
||||||
|
lit_str("Hi there!"),
|
||||||
|
v2{ 32.0f, 32.0f },
|
||||||
|
v2{ 128.0f, 64.0f },
|
||||||
|
};
|
||||||
|
UI_Widget_Result r0 = ui_widget_push(ui, d0);
|
||||||
|
|
||||||
|
UI_Widget_Desc d1 = d0;
|
||||||
|
d1.style.flags |= UIWidgetStyle_Outline | UIWidgetStyle_MouseClick;
|
||||||
|
d1.style.color_bg = PINK_V4;
|
||||||
|
d1.style.color_fg = GREEN_V4;
|
||||||
|
d1.p_min = v2{ 512, 32 };
|
||||||
|
d1.p_max = v2{ 640, 128 };
|
||||||
|
d1.string = lit_str("Hello");
|
||||||
|
UI_Widget_Result r1 = ui_widget_push(ui, d1);
|
||||||
|
bool clicked_r1 = has_flag(r1.flags, UIWidgetResult_MouseLeft_WentUp);
|
||||||
|
if (clicked_r1) show = !show;
|
||||||
|
|
||||||
|
UI_Widget_Result r2 = {};
|
||||||
|
if (show)
|
||||||
|
{
|
||||||
|
UI_Widget_Desc d2 = d1;
|
||||||
|
d1.string = lit_str("Hello There");
|
||||||
|
d1.p_min = v2{ 560, 64 };
|
||||||
|
d1.p_max = v2{ 700, 256 };
|
||||||
|
r2 = ui_widget_push(ui, d1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool clicked_r2 = has_flag(r2.flags, UIWidgetResult_MouseLeft_WentUp);
|
||||||
|
assert(
|
||||||
|
(!clicked_r1 && !clicked_r2) ||
|
||||||
|
(clicked_r1 && !clicked_r2) ||
|
||||||
|
(!clicked_r1 && clicked_r2)
|
||||||
|
);
|
||||||
|
|
||||||
|
u32 widget_count = ui->widgets.free_len;
|
||||||
|
r32 range_min = -10;
|
||||||
|
r32 range_max = -1;
|
||||||
|
r32 range_step = (range_max - range_min) / (r32)widget_count;
|
||||||
|
ui_widgets_to_geometry_recursive(ui, ui->widgets.root, -10, range_step);
|
||||||
|
|
||||||
|
platform_geometry_buffer_update(
|
||||||
|
&ui->per_frame_buffer,
|
||||||
|
(r32*)ui->verts,
|
||||||
|
0,
|
||||||
|
ui->verts_len * 10,
|
||||||
|
ui->indices,
|
||||||
|
0,
|
||||||
|
ui->indices_len
|
||||||
|
);
|
||||||
|
platform_shader_bind(ui->shader);
|
||||||
|
platform_set_uniform(ui->shader, 0, ui->proj);
|
||||||
|
platform_texture_bind(ui->atlas_texture);
|
||||||
|
platform_geometry_bind(ui->per_frame_buffer);
|
||||||
|
platform_geometry_draw(ui->per_frame_buffer, ui->indices_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////
|
||||||
|
// Widgets
|
||||||
|
|
||||||
|
internal UI_Widget_Id
|
||||||
|
ui_widget_id_create(String string, u32 index)
|
||||||
|
{
|
||||||
|
assert(string.len != 0 && string.str != 0);
|
||||||
|
UI_Widget_Id result = {};
|
||||||
|
result.value = hash_djb2_to_u32(string);
|
||||||
|
result.index = index;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal UI_Widget*
|
||||||
|
ui_widget_pool_push(UI_Widget_Pool* pool, String string)
|
||||||
|
{
|
||||||
|
assert(pool->free_len < pool->free_cap);
|
||||||
|
UI_Widget* result = pool->free + pool->free_len++;
|
||||||
|
|
||||||
|
result->id = ui_widget_id_create(string, pool->free_len);
|
||||||
|
result->parent = 0;
|
||||||
|
result->next = 0;
|
||||||
|
result->child_first = 0;
|
||||||
|
result->child_last = 0;
|
||||||
|
|
||||||
|
if (pool->active_parent)
|
||||||
|
{
|
||||||
|
result->parent = pool->active_parent;
|
||||||
|
sll_push(
|
||||||
|
pool->active_parent->child_first,
|
||||||
|
pool->active_parent->child_last,
|
||||||
|
result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_widget_pool_pop(UI_Widget_Pool* pool)
|
||||||
|
{
|
||||||
|
if (pool->active_parent->parent)
|
||||||
|
{
|
||||||
|
pool->active_parent = pool->active_parent->parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool
|
||||||
|
ui_widget_id_equals(UI_Widget_Id a, UI_Widget_Id b)
|
||||||
|
{
|
||||||
|
return (a.value == b.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool
|
||||||
|
ui_widget_id_is_valid(UI_Widget_Id h)
|
||||||
|
{
|
||||||
|
return h.value != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_widget_next_hot_set(UI* ui, UI_Widget* w)
|
||||||
|
{
|
||||||
|
ui->widget_next_hot = w->id;
|
||||||
|
ui->widget_next_hot_frames = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_widget_hot_set(UI* ui, UI_Widget* w)
|
||||||
|
{
|
||||||
|
ui->widget_hot = w->id;
|
||||||
|
ui->widget_hot_frames = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal UI_Widget_Result
|
||||||
|
ui_widget_push(UI* ui, UI_Widget_Desc desc)
|
||||||
|
{
|
||||||
|
UI_Widget_Result result = {};
|
||||||
|
|
||||||
|
UI_Widget* w = ui_widget_pool_push(&ui->widgets, desc.string);
|
||||||
|
w->desc = desc;
|
||||||
|
|
||||||
|
if (has_flag(desc.style.flags, UIWidgetStyle_MouseClick))
|
||||||
|
{
|
||||||
|
// CASES:
|
||||||
|
// Mouse Over | Mouse Clicked | Is Next Hot | Response
|
||||||
|
// f | f | t | clear next hot
|
||||||
|
// f | f | f | do nothing
|
||||||
|
// f | t | f | do nothing
|
||||||
|
// t | f | f | beome next hot
|
||||||
|
// t | t | f | become next hot
|
||||||
|
// t | t | t | become hot
|
||||||
|
|
||||||
|
v2 mouse_p = ui->input->frame_hot->mouse_pos;
|
||||||
|
bool mouse_over = (
|
||||||
|
mouse_p.x >= desc.p_min.x && mouse_p.x <= desc.p_max.x &&
|
||||||
|
mouse_p.y >= desc.p_min.y && mouse_p.y <= desc.p_max.y
|
||||||
|
);
|
||||||
|
|
||||||
|
if (mouse_over)
|
||||||
|
{
|
||||||
|
if (ui_widget_id_equals(w->id, ui->widget_next_hot))
|
||||||
|
{
|
||||||
|
if (input_key_is_down(ui->input, KeyCode_MouseLeftButton))
|
||||||
|
{
|
||||||
|
ui_widget_hot_set(ui, w);
|
||||||
|
result.flags |= UIWidgetResult_MouseLeft_IsDown;
|
||||||
|
}
|
||||||
|
if (input_key_went_up(ui->input, KeyCode_MouseLeftButton))
|
||||||
|
{
|
||||||
|
result.flags |= UIWidgetResult_MouseLeft_WentUp;
|
||||||
|
ui->widget_hot = UI_Widget_Id{0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((w->id.index >= ui->widget_next_hot.index) && ui->widget_hot.value == 0)
|
||||||
|
{
|
||||||
|
ui_widget_next_hot_set(ui, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ui_widget_id_equals(w->id, ui->widget_next_hot))
|
||||||
|
{
|
||||||
|
ui->widget_next_hot = UI_Widget_Id{0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_widget_pop(UI* ui, UI_Widget* widget)
|
||||||
|
{
|
||||||
|
assert(ui_widget_id_equals(widget->id, ui->widgets.active_parent->id));
|
||||||
|
ui_widget_pool_pop(&ui->widgets);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal r32
|
||||||
|
ui_widgets_to_geometry_recursive(UI* ui, UI_Widget* widget, r32 z_start, r32 z_step)
|
||||||
|
{
|
||||||
|
r32 z_at = z_start;
|
||||||
|
for (UI_Widget* child = widget->child_first; child != 0; child = child->next)
|
||||||
|
{
|
||||||
|
UI_Widget_Desc desc = child->desc;
|
||||||
|
v3 bg_min = v2_to_v3(desc.p_min, z_at);
|
||||||
|
v3 bg_max = v2_to_v3(desc.p_max, z_at);
|
||||||
|
|
||||||
|
v4 color_fg = desc.style.color_fg;
|
||||||
|
v4 color_bg = desc.style.color_bg;
|
||||||
|
if (ui_widget_id_equals(ui->widget_next_hot, child->id))
|
||||||
|
{
|
||||||
|
color_fg = desc.style.color_bg;
|
||||||
|
color_bg = desc.style.color_fg;
|
||||||
|
}
|
||||||
|
if (ui_widget_id_equals(ui->widget_hot, child->id))
|
||||||
|
{
|
||||||
|
color_fg = desc.style.color_fg;
|
||||||
|
color_bg = desc.style.color_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_flag(child->desc.style.flags, UIWidgetStyle_Outline))
|
||||||
|
{
|
||||||
|
ui_sprite_push(ui, bg_min, bg_max, WHITE_SPRITE_ID, color_fg);
|
||||||
|
bg_min += v3{ 3, 3, 0};
|
||||||
|
bg_max -= v3{ 3, 3, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_flag(child->desc.style.flags, UIWidgetStyle_Bg))
|
||||||
|
{
|
||||||
|
bg_min.z += z_step;
|
||||||
|
bg_max.z += z_step;
|
||||||
|
ui_sprite_push(ui, bg_min, bg_max, desc.style.sprite, color_bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_flag(child->desc.style.flags, UIWidgetStyle_Text))
|
||||||
|
{
|
||||||
|
// TODO(PS):
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child->child_first)
|
||||||
|
{
|
||||||
|
z_at = ui_widgets_to_geometry_recursive(ui, child, z_at + z_step, z_step);
|
||||||
|
}
|
||||||
|
|
||||||
|
z_at += z_step;
|
||||||
|
}
|
||||||
|
return z_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////
|
||||||
|
// Specific Widget Implementations
|
||||||
|
|
||||||
|
global UI_Style_Sheet ui_default_style_sheet = {
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
internal UI_Widget_Style
|
||||||
|
ui_get_style(UI* ui, UI_Widget_Kind kind)
|
||||||
|
{
|
||||||
|
if (ui->style_sheet) return ui->style_sheet->styles[kind];
|
||||||
|
return ui_default_style_sheet.styles[kind];
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_text(UI* ui, String string)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool
|
||||||
|
ui_button(UI* ui, String string)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
/* date = March 28th 2022 10:52 pm */
|
||||||
|
|
||||||
|
#ifndef LUMENARIUM_UI_H
|
||||||
|
#define LUMENARIUM_UI_H
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
// Interface
|
||||||
|
|
||||||
|
struct UI_Vertex
|
||||||
|
{
|
||||||
|
v4 pos;
|
||||||
|
v2 uv;
|
||||||
|
v4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define UI_WIDGET_ID_VALID_BIT 1 << 31
|
||||||
|
|
||||||
|
union UI_Widget_Id
|
||||||
|
{
|
||||||
|
// equality of widget id's only relies on the value field
|
||||||
|
// which is a hash of the widget's string
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
// this struct tracks the index of the widget only to be able
|
||||||
|
// to override next hot in cases where an earlier element became
|
||||||
|
// next hot that is in the same location as the current one
|
||||||
|
u32 index;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef u32 UI_Widget_Style_Flags;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
UIWidgetStyle_None = 0,
|
||||||
|
UIWidgetStyle_Bg = 1,
|
||||||
|
UIWidgetStyle_Text = 2,
|
||||||
|
UIWidgetStyle_Outline = 4,
|
||||||
|
UIWidgetStyle_MouseClick = 8,
|
||||||
|
UIWidgetStyle_MouseDrag = 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
// akin to a css class, could be used to style multiple
|
||||||
|
// elements
|
||||||
|
struct UI_Widget_Style
|
||||||
|
{
|
||||||
|
UI_Widget_Style_Flags flags;
|
||||||
|
v4 color_bg;
|
||||||
|
v4 color_fg;
|
||||||
|
|
||||||
|
u32 sprite;
|
||||||
|
};
|
||||||
|
|
||||||
|
// combination of style info and per-instance data
|
||||||
|
struct UI_Widget_Desc
|
||||||
|
{
|
||||||
|
UI_Widget_Style style;
|
||||||
|
String string;
|
||||||
|
v2 p_min;
|
||||||
|
v2 p_max;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UI_Widget
|
||||||
|
{
|
||||||
|
UI_Widget_Id id;
|
||||||
|
UI_Widget_Desc desc;
|
||||||
|
|
||||||
|
UI_Widget* parent;
|
||||||
|
UI_Widget* next;
|
||||||
|
UI_Widget* child_first;
|
||||||
|
UI_Widget* child_last;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef u32 UI_Widget_Result_Flags;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
UIWidgetResult_None = 0,
|
||||||
|
UIWidgetResult_MouseLeft_IsDown = 1,
|
||||||
|
UIWidgetResult_MouseLeft_WentUp = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UI_Widget_Result
|
||||||
|
{
|
||||||
|
UI_Widget_Result_Flags flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum UI_Widget_Kind
|
||||||
|
{
|
||||||
|
UIWidget_Text,
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
UIWidget_Button,
|
||||||
|
UIWidget_Toggle,
|
||||||
|
UIWidget_Menu,
|
||||||
|
UIWidget_Dropdown,
|
||||||
|
|
||||||
|
// Sliders
|
||||||
|
UIWidget_HSlider,
|
||||||
|
UIWidget_VSlider,
|
||||||
|
UIWidget_HScroll,
|
||||||
|
UIWidget_VScroll,
|
||||||
|
|
||||||
|
// Panels
|
||||||
|
UIWidget_Window,
|
||||||
|
|
||||||
|
UIWidget_Count,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UI_Style_Sheet
|
||||||
|
{
|
||||||
|
UI_Widget_Style styles[UIWidget_Count];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UI_Widget_Pool
|
||||||
|
{
|
||||||
|
UI_Widget* free;
|
||||||
|
u32 free_cap;
|
||||||
|
u32 free_len;
|
||||||
|
|
||||||
|
UI_Widget* root;
|
||||||
|
UI_Widget* active_parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UI
|
||||||
|
{
|
||||||
|
UI_Vertex* verts;
|
||||||
|
u32 verts_len;
|
||||||
|
u32 verts_cap;
|
||||||
|
|
||||||
|
u32* indices;
|
||||||
|
u32 indices_len;
|
||||||
|
u32 indices_cap;
|
||||||
|
|
||||||
|
Texture_Atlas atlas;
|
||||||
|
|
||||||
|
UI_Widget_Pool widgets;
|
||||||
|
UI_Style_Sheet* style_sheet;
|
||||||
|
|
||||||
|
UI_Widget_Id widget_next_hot;
|
||||||
|
UI_Widget_Id widget_hot;
|
||||||
|
|
||||||
|
// frames since these values were set
|
||||||
|
u16 widget_next_hot_frames;
|
||||||
|
u16 widget_hot_frames;
|
||||||
|
|
||||||
|
Input_State* input;
|
||||||
|
|
||||||
|
m44 proj;
|
||||||
|
Platform_Shader shader;
|
||||||
|
Platform_Texture atlas_texture;
|
||||||
|
Platform_Geometry_Buffer per_frame_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Interface
|
||||||
|
|
||||||
|
internal UI ui_create();
|
||||||
|
internal void ui_quad_push(UI* ui, v3 pmin, v3 pmax, v2 tmin, v2 tmax, v4 c);
|
||||||
|
internal void ui_sprite_register(UI* ui, u8* pixels, u32 w, u32 h, u32 id);
|
||||||
|
internal void ui_sprite_push(UI* ui, v3 pmin, v3 pmax, u32 id, v4 color);
|
||||||
|
internal void ui_sprite_push(UI* ui, v3 pmin, v3 pmax, u32 id);
|
||||||
|
internal void ui_draw(UI* ui);
|
||||||
|
|
||||||
|
// Widgets
|
||||||
|
|
||||||
|
internal UI_Widget_Id ui_widget_id_create(u32 index_in_parent, String string);
|
||||||
|
internal bool ui_widget_id_equals(UI_Widget_Id a, UI_Widget_Id b);
|
||||||
|
internal bool ui_widget_id_is_valid(UI_Widget_Id h);
|
||||||
|
|
||||||
|
internal UI_Widget* ui_widget_pool_push(UI_Widget_Pool* pool, String string);
|
||||||
|
internal void ui_widget_pool_pop(UI_Widget_Pool* pool);
|
||||||
|
|
||||||
|
internal UI_Widget_Result ui_widget_push(UI* ui, UI_Widget_Desc desc);
|
||||||
|
internal void ui_widget_pop(UI* ui, UI_Widget* widget);
|
||||||
|
|
||||||
|
internal r32 ui_widgets_to_geometry_recursive(UI* ui, UI_Widget* widget, r32 z_start, r32 z_step);
|
||||||
|
|
||||||
|
#endif //LUMENARIUM_UI_H
|
|
@ -1 +0,0 @@
|
||||||
//
|
|
|
@ -1,36 +0,0 @@
|
||||||
/* date = March 28th 2022 10:52 pm */
|
|
||||||
|
|
||||||
#ifndef LUMENARIUM_UI_H
|
|
||||||
#define LUMENARIUM_UI_H
|
|
||||||
|
|
||||||
struct Font_Glyph
|
|
||||||
{
|
|
||||||
u32 code_point;
|
|
||||||
v2 uv_min;
|
|
||||||
v2 uv_max;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Font_Glyph_Table
|
|
||||||
{
|
|
||||||
Font_Glyph* values;
|
|
||||||
u32 cap;
|
|
||||||
u32 len;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Font_Bitmap
|
|
||||||
{
|
|
||||||
u8* pixels;
|
|
||||||
u32 width;
|
|
||||||
u32 height;
|
|
||||||
u32 stride;
|
|
||||||
|
|
||||||
Platform_Texture texture;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Font
|
|
||||||
{
|
|
||||||
Font_Glyph_Table glyphs;
|
|
||||||
Font_Bitmap bitmap;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //LUMENARIUM_UI_H
|
|
|
@ -3,6 +3,10 @@ internal void
|
||||||
en_init(App_State* state, App_Init_Desc desc)
|
en_init(App_State* state, App_Init_Desc desc)
|
||||||
{
|
{
|
||||||
state->assemblies = assembly_array_create(permanent, desc.assembly_cap);
|
state->assemblies = assembly_array_create(permanent, desc.assembly_cap);
|
||||||
|
|
||||||
|
Output* o = &state->output;
|
||||||
|
register_output_method(o, OutputData_NetworkSACN, output_network_sacn_build, output_network_sacn_init());
|
||||||
|
register_output_method(o, OutputData_ComUART, output_network_sacn_build, output_com_uart_init());
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
@ -15,6 +19,52 @@ internal void
|
||||||
en_frame(App_State* state)
|
en_frame(App_State* state)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Output Data
|
||||||
|
|
||||||
|
Output_Data_Queue output_queue = {};
|
||||||
|
output_queue.a = scratch;
|
||||||
|
|
||||||
|
// build output data buffers
|
||||||
|
Output_Methods methods;
|
||||||
|
Assembly_Array assemblies = state->assemblies;
|
||||||
|
for (u32 i = 0; i < assemblies.len; i++)
|
||||||
|
{
|
||||||
|
Assembly_Strip_Array strips = assemblies.strip_arrays[i];
|
||||||
|
for (u32 j = 0; j < strips.len; j++)
|
||||||
|
{
|
||||||
|
Assembly_Strip* strip = strips.strips + j;
|
||||||
|
Build_Output_Data_Buffer* method_proc = methods.procs[strip->output_kind];
|
||||||
|
u8* method_data = methods.method_data[strip->output_kind];
|
||||||
|
if (method_proc == 0) continue;
|
||||||
|
method_proc(state, i, strip, method_data, &output_queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// output the buffers
|
||||||
|
// TODO(PS): we could sort these first if switchig between output
|
||||||
|
// types is time consuming
|
||||||
|
for (Output_Data* at = output_queue.first; at != 0; at = at->next)
|
||||||
|
{
|
||||||
|
// NOTE(PS): we can overload each switch case as more methods come in
|
||||||
|
// ie. OutputData_NetworkSACN and OutputData_NetworkArtNet could use
|
||||||
|
// the same case since at this point they just need to push data out
|
||||||
|
// over a socket
|
||||||
|
switch (at->kind)
|
||||||
|
{
|
||||||
|
case OutputData_NetworkSACN:
|
||||||
|
{
|
||||||
|
// TODO(PS): platform network io
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OutputData_ComUART:
|
||||||
|
{
|
||||||
|
// TODO(PS): platform com io
|
||||||
|
} break;
|
||||||
|
|
||||||
|
invalid_code_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
|
|
@ -42,6 +42,9 @@ struct Assembly_Strip
|
||||||
u32 pixels_len;
|
u32 pixels_len;
|
||||||
// array of indices into the Assembly_Pixel_Buffer for the same assembly
|
// array of indices into the Assembly_Pixel_Buffer for the same assembly
|
||||||
u32* pixels;
|
u32* pixels;
|
||||||
|
|
||||||
|
Output_Data_Kind output_kind;
|
||||||
|
u32 sacn_universe;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Assembly_Strip_Array
|
struct Assembly_Strip_Array
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
internal void
|
||||||
|
register_output_method(Output* output, Output_Data_Kind kind, Build_Output_Data_Buffer* proc, u8* method_data)
|
||||||
|
{
|
||||||
|
output->methods.procs[kind] = proc;
|
||||||
|
output->methods.method_data[kind] = method_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Output_Data*
|
||||||
|
output_data_queue_push(Output_Data_Queue* q, u32 size, Output_Data_Kind kind)
|
||||||
|
{
|
||||||
|
Output_Data* d = allocator_alloc_struct(q->a, Output_Data);
|
||||||
|
d->kind = kind;
|
||||||
|
d->data.size = size;
|
||||||
|
d->data.base = allocator_alloc(q->a, size);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
output_data_set_network_addr(Output_Data* d, u32 send_addr, u32 port)
|
||||||
|
{
|
||||||
|
d->network.v4_addr = send_addr;
|
||||||
|
d->network.port = port;
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* date = March 30th 2022 9:23 am */
|
||||||
|
|
||||||
|
#ifndef LUMENARIUM_ENGINE_OUTPUT_H
|
||||||
|
#define LUMENARIUM_ENGINE_OUTPUT_H
|
||||||
|
|
||||||
|
typedef u8 Output_Data_Kind;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
OutputData_Invalid = 0,
|
||||||
|
OutputData_NetworkSACN,
|
||||||
|
OutputData_ComUART,
|
||||||
|
OutputData_Count,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Output_Data_Network
|
||||||
|
{
|
||||||
|
// Platform_Socket_Handle socket;
|
||||||
|
u32 v4_addr;
|
||||||
|
u32 port;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Output_Data_Com
|
||||||
|
{
|
||||||
|
String port;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Output_Data
|
||||||
|
{
|
||||||
|
Output_Data_Kind kind;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
Output_Data_Network network;
|
||||||
|
Output_Data_Com com;
|
||||||
|
};
|
||||||
|
Data data;
|
||||||
|
|
||||||
|
Output_Data* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Output_Data_Queue
|
||||||
|
{
|
||||||
|
Output_Data* first;
|
||||||
|
Output_Data* last;
|
||||||
|
u32 len;
|
||||||
|
Allocator* a;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void Build_Output_Data_Buffer(App_State* state, u32 assembly_id, Assembly_Strip* strip, u8* method_data, Output_Data_Queue* queue);
|
||||||
|
|
||||||
|
struct Output_Methods
|
||||||
|
{
|
||||||
|
Build_Output_Data_Buffer* procs[OutputData_Count];
|
||||||
|
u8* method_data[OutputData_Count];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Output
|
||||||
|
{
|
||||||
|
Output_Methods methods;
|
||||||
|
};
|
||||||
|
|
||||||
|
internal void register_output_method(Output* output, Output_Data_Kind kind, Build_Output_Data_Buffer* proc, u8* method_data);
|
||||||
|
|
||||||
|
internal Output_Data* output_data_queue_push(Output_Data_Queue* q, u32 size, Output_Data_Kind kind);
|
||||||
|
|
||||||
|
internal void output_data_set_network_addr(Output_Data* d, u32 send_addr, u32 port);
|
||||||
|
|
||||||
|
#endif //LUMENARIUM_ENGINE_OUTPUT_H
|
|
@ -0,0 +1,207 @@
|
||||||
|
#define SACN_DEFAULT_PORT 5568
|
||||||
|
|
||||||
|
|
||||||
|
// a description of the address space being used
|
||||||
|
#define SACN_PREAMBLE_SIZE_ADDR 0
|
||||||
|
#define SACN_POSTAMBLE_SIZE_ADDR 2
|
||||||
|
#define SACN_ACN_IDENTIFIER_ADDR 4
|
||||||
|
#define SACN_ROOT_FLAGS_AND_LEN_ADDR 16
|
||||||
|
#define SACN_ROOT_VECTOR_ADDR 18
|
||||||
|
#define SACN_CID_ADDR 22
|
||||||
|
#define SACN_FRAMING_FLAGS_AND_LEN_ADDR 38
|
||||||
|
#define SACN_FRAMING_VECTOR_ADDR 40
|
||||||
|
#define SACN_SOURCE_NAME_ADDR 44
|
||||||
|
#define SACN_PRIORITY_ADDR 108
|
||||||
|
#define SACN_RESERVED_ADDR 109
|
||||||
|
#define SACN_SEQ_NUM_ADDR 111
|
||||||
|
#define SACN_OPTIONS_ADDR 112
|
||||||
|
#define SACN_UNIVERSE_ADDR 113
|
||||||
|
#define SACN_DMP_FLAGS_AND_LEN_ADDR 115
|
||||||
|
#define SACN_DMP_VECTOR_ADDR 117
|
||||||
|
#define SACN_DMP_ADDRESS_AND_DATA_ADDR 118
|
||||||
|
#define SACN_FIRST_PROPERTY_ADDRESS_ADDR 119
|
||||||
|
#define SACN_ADDRESS_INC_ADDR 121
|
||||||
|
#define SACN_PROP_COUNT_ADDR 123
|
||||||
|
#define SACN_START_CODE_ADDR 125
|
||||||
|
#define SACN_PROP_VALUES_ADDR (SACN_START_CODE_ADDR + 1)
|
||||||
|
|
||||||
|
// Common Sizes
|
||||||
|
#define SACN_BUFFER_HEADER_SIZE 126
|
||||||
|
#define SACN_BUFFER_BODY_SIZE 512
|
||||||
|
#define SACN_BUFFER_SIZE (SACN_BUFFER_HEADER_SIZE + SACN_BUFFER_BODY_SIZE)
|
||||||
|
|
||||||
|
#define SACN_SOURCE_NAME_SIZE 64
|
||||||
|
#define SACN_ACN_IDENTIFIER_SIZE 12
|
||||||
|
#define SACN_RLP_PREAMBLE_SIZE 16
|
||||||
|
#define SACN_RLP_POSTAMBLE_SIZE 0
|
||||||
|
|
||||||
|
// Data Definitions
|
||||||
|
#define SACN_ACN_IDENTIFIER lit_str("ASC-E1.17\0\0\0")
|
||||||
|
#define SACN_ROOT_VECTOR 4
|
||||||
|
#define SACN_FRAMING_VECTOR 2
|
||||||
|
#define SACN_DMP_VECTOR 2
|
||||||
|
#define SACN_ADDRESS_AND_DATA_FORMAT 0xa1
|
||||||
|
#define SACN_ADDR_INC 1
|
||||||
|
#define SACN_DMP_FIRST_PROPERTY_ADDRESS_FORCE 0
|
||||||
|
#define SACN_RESERVED_VALUE 0
|
||||||
|
|
||||||
|
#define SACN_VHD_L_FLAG 0x80
|
||||||
|
#define SACN_VHD_V_FLAG 0x40
|
||||||
|
#define SACN_VHD_H_FLAG 0x20
|
||||||
|
#define SACN_VHD_D_FLAG 0x10
|
||||||
|
|
||||||
|
#define SACN_VHD_MAXFLAGBYTES 7 //The maximum amount of bytes used to pack the flags, len, and vector
|
||||||
|
#define SACN_VHD_MAXLEN 0x0fffff //The maximum packet length is 20 bytes long
|
||||||
|
#define SACN_VHD_MAXMINLENGTH 4095 //The highest length that will fit in the "smallest" length pack
|
||||||
|
|
||||||
|
|
||||||
|
internal void
|
||||||
|
sacn_vhd_pack_flags(Data_Writer* w, b8 inherit_vec, b8 inherit_head, b8 inherit_data)
|
||||||
|
{
|
||||||
|
u8 last_byte = dw_get_u8(w) & 0x8F;
|
||||||
|
w->at -= 1;
|
||||||
|
|
||||||
|
if (!inherit_vec) { last_byte |= SACN_VHD_V_FLAG; }
|
||||||
|
if (!inherit_head) { last_byte |= SACN_VHD_H_FLAG; }
|
||||||
|
if (!inherit_data) { last_byte |= SACN_VHD_D_FLAG; }
|
||||||
|
|
||||||
|
dw_put_u8(w, last_byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
sacn_vhd_pack_len(Data_Writer* w, u32 len, b8 include_len)
|
||||||
|
{
|
||||||
|
u32 len_adjusted = len;
|
||||||
|
if (include_len)
|
||||||
|
{
|
||||||
|
if (len + 1 > SACN_VHD_MAXMINLENGTH)
|
||||||
|
{
|
||||||
|
len_adjusted += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
len_adjusted += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mask out the length bits to keep flags intact
|
||||||
|
u8 last_byte = dw_get_u8(w) & 0x70;
|
||||||
|
w->at -= 1;
|
||||||
|
|
||||||
|
if (len_adjusted > SACN_VHD_MAXMINLENGTH) last_byte |= SACN_VHD_L_FLAG;
|
||||||
|
|
||||||
|
u8* pack_buffer = (u8*)&len_adjusted;
|
||||||
|
if (len_adjusted <= SACN_VHD_MAXMINLENGTH)
|
||||||
|
{
|
||||||
|
last_byte |= (pack_buffer[1] & 0x0f);
|
||||||
|
dw_put_u8(w, last_byte);
|
||||||
|
dw_put_u8(w, pack_buffer[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last_byte |= (pack_buffer[2] & 0x0f);
|
||||||
|
dw_put_u8(w, pack_buffer[1]);
|
||||||
|
dw_put_u8(w, pack_buffer[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
sacn_fill_buffer_header(Output_Data* d, u16 universe, Sacn* sacn)
|
||||||
|
{
|
||||||
|
assert(d && d->data.size > 0);
|
||||||
|
|
||||||
|
// TODO(PS): these should be passed in?
|
||||||
|
u16 slot_count = 0;
|
||||||
|
u8 start_code = 0;
|
||||||
|
u8 priority = 0;
|
||||||
|
u16 reserved = 0;
|
||||||
|
u8 options = 0;
|
||||||
|
|
||||||
|
Data_Writer w = {};
|
||||||
|
w.data = d->data;
|
||||||
|
|
||||||
|
dw_put_u16_b(&w, SACN_RLP_PREAMBLE_SIZE);
|
||||||
|
dw_put_u16_b(&w, SACN_RLP_POSTAMBLE_SIZE);
|
||||||
|
dw_put_str(&w, SACN_ACN_IDENTIFIER);
|
||||||
|
|
||||||
|
sacn_vhd_pack_flags(&w, false, false, false);
|
||||||
|
sacn_vhd_pack_len(&w, SACN_BUFFER_HEADER_SIZE - SACN_RLP_PREAMBLE_SIZE + slot_count, false);
|
||||||
|
|
||||||
|
dw_put_u32_b(&w, SACN_ROOT_VECTOR);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < SACN_CID_BYTES; i++) dw_put_u8(&w, sacn->cid.bytes[i]);
|
||||||
|
|
||||||
|
sacn_vhd_pack_flags(&w, false, false, false);
|
||||||
|
sacn_vhd_pack_len(&w, SACN_BUFFER_HEADER_SIZE - SACN_FRAMING_FLAGS_AND_LEN_ADDR + slot_count, false);
|
||||||
|
|
||||||
|
dw_put_u32_b(&w, SACN_FRAMING_VECTOR);
|
||||||
|
dw_put_str(&w, sacn->source_name);
|
||||||
|
|
||||||
|
dw_put_u8(&w, priority);
|
||||||
|
dw_put_u16_b(&w, reserved);
|
||||||
|
dw_put_u8(&w, 0); // Sequence Number starts at 0, gets updated
|
||||||
|
dw_put_u8(&w, options);
|
||||||
|
dw_put_u16_b(&w, universe);
|
||||||
|
|
||||||
|
sacn_vhd_pack_flags(&w, false, false, false);
|
||||||
|
sacn_vhd_pack_len(&w, SACN_BUFFER_HEADER_SIZE - SACN_DMP_FLAGS_AND_LEN_ADDR + slot_count, false);
|
||||||
|
|
||||||
|
dw_put_u8(&w, SACN_DMP_VECTOR);
|
||||||
|
dw_put_u8(&w, SACN_ADDRESS_AND_DATA_FORMAT);
|
||||||
|
dw_put_u8(&w, 0); // dmp first priority addr
|
||||||
|
dw_put_u8(&w, SACN_ADDR_INC); // dmp address increment
|
||||||
|
dw_put_u16_b(&w, slot_count + 1);
|
||||||
|
dw_put_u8(&w, start_code);
|
||||||
|
|
||||||
|
assert(w.at == SACN_BUFFER_HEADER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
sacn_fill_buffer_body(Output_Data* d, u32* leds_placed)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Sacn_Cid
|
||||||
|
sacn_string_to_cid(String str)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
internal u32
|
||||||
|
sacn_universe_to_send_addr(u32 universe)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal u8*
|
||||||
|
output_network_sacn_init()
|
||||||
|
{
|
||||||
|
Sacn* result = allocator_alloc_struct(permanent, Sacn);
|
||||||
|
// TODO(PS): get platform send socket
|
||||||
|
|
||||||
|
String cid_str = lit_str("{67F9D986-544E-4abb-8986-D5F79382586C}");
|
||||||
|
result->cid = sacn_string_to_cid(cid_str);
|
||||||
|
|
||||||
|
return (u8*)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
output_network_sacn_build(App_State* state, u32 assembly_id, Assembly_Strip* strip, u8* method_data, Output_Data_Queue* queue)
|
||||||
|
{
|
||||||
|
Sacn* sacn = (Sacn*)method_data;
|
||||||
|
|
||||||
|
u16 universe = (u16)strip->sacn_universe;
|
||||||
|
u32 send_port = SACN_DEFAULT_PORT;
|
||||||
|
for (u32 leds_placed = 0; leds_placed < strip->pixels_len;)
|
||||||
|
{
|
||||||
|
u32 v4_send_addr = sacn_universe_to_send_addr(universe);
|
||||||
|
|
||||||
|
Output_Data* d = output_data_queue_push(queue, SACN_BUFFER_SIZE, OutputData_NetworkSACN);
|
||||||
|
output_data_set_network_addr(d, v4_send_addr, send_port);
|
||||||
|
|
||||||
|
sacn_fill_buffer_header(d, universe, sacn);
|
||||||
|
sacn_fill_buffer_body(d, &leds_placed);
|
||||||
|
universe += 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* date = March 30th 2022 9:55 am */
|
||||||
|
|
||||||
|
#ifndef LUMENARIUM_OUTPUT_SACN_H
|
||||||
|
#define LUMENARIUM_OUTPUT_SACN_H
|
||||||
|
|
||||||
|
#define SACN_CID_BYTES 16
|
||||||
|
struct Sacn_Cid
|
||||||
|
{
|
||||||
|
u8 bytes[SACN_CID_BYTES];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sacn
|
||||||
|
{
|
||||||
|
Sacn_Cid cid;
|
||||||
|
s32 sequence_iter;
|
||||||
|
String source_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
internal u8* output_network_sacn_init();
|
||||||
|
internal void output_network_sacn_build(App_State* state, u32 assembly_id, Assembly_Strip* strip, u8* method_data, Output_Data_Queue* queue);
|
||||||
|
|
||||||
|
#endif //LUMENARIUM_OUTPUT_SACN_H
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
internal u8*
|
||||||
|
output_com_uart_init()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
output_com_uart_build(App_State* state, u32 assembly_id, Assembly_Strip* strip, u8* method_data, Output_Data_Queue* queue)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
/* date = March 30th 2022 9:57 am */
|
||||||
|
|
||||||
|
#ifndef LUMENARIUM_OUTPUT_UART_H
|
||||||
|
#define LUMENARIUM_OUTPUT_UART_H
|
||||||
|
|
||||||
|
internal u8* output_com_uart_init();
|
||||||
|
internal void output_com_uart_build(App_State* state, u32 assembly_id, Assembly_Strip* strip, u8* method_data, Output_Data_Queue* queue);
|
||||||
|
|
||||||
|
#endif //LUMENARIUM_OUTPUT_UART_H
|
|
@ -462,6 +462,12 @@ extern "C"
|
||||||
float Ignored0_;
|
float Ignored0_;
|
||||||
float Ignored1_;
|
float Ignored1_;
|
||||||
};
|
};
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
hmm_vec2 xy;
|
||||||
|
float Ignored0b_;
|
||||||
|
float Ignored1b_;
|
||||||
|
};
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -469,6 +475,12 @@ extern "C"
|
||||||
hmm_vec2 YZ;
|
hmm_vec2 YZ;
|
||||||
float Ignored3_;
|
float Ignored3_;
|
||||||
};
|
};
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
float Ignored2b_;
|
||||||
|
hmm_vec2 yz;
|
||||||
|
float Ignored3b_;
|
||||||
|
};
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -477,6 +489,13 @@ extern "C"
|
||||||
hmm_vec2 ZW;
|
hmm_vec2 ZW;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
float Ignored4b_;
|
||||||
|
float Ignored5b_;
|
||||||
|
hmm_vec2 zw;
|
||||||
|
};
|
||||||
|
|
||||||
float Elements[4];
|
float Elements[4];
|
||||||
} hmm_vec4;
|
} hmm_vec4;
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,9 @@ lumenarium_init()
|
||||||
{
|
{
|
||||||
App_State* state = 0;
|
App_State* state = 0;
|
||||||
|
|
||||||
permanent = bump_allocator_create_reserve(MB(4));
|
permanent = bump_allocator_create_reserve(GB(1));
|
||||||
scratch = bump_allocator_create_reserve(KB(64));
|
scratch = bump_allocator_create_reserve(KB(64));
|
||||||
|
platform_file_jobs_init();
|
||||||
|
|
||||||
run_tests();
|
run_tests();
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ lumenarium_init()
|
||||||
add_flag(state->flags, AppState_IsRunning);
|
add_flag(state->flags, AppState_IsRunning);
|
||||||
add_flag(state->flags, AppState_RunEditor);
|
add_flag(state->flags, AppState_RunEditor);
|
||||||
|
|
||||||
state->input_state = input_state_create();
|
state->input_state = input_state_create(permanent);
|
||||||
|
|
||||||
en_init(state, desc);
|
en_init(state, desc);
|
||||||
if (has_flag(state->flags, AppState_RunEditor))
|
if (has_flag(state->flags, AppState_RunEditor))
|
||||||
|
@ -34,7 +35,7 @@ lumenarium_frame_prepare(App_State* state)
|
||||||
{
|
{
|
||||||
allocator_clear(scratch);
|
allocator_clear(scratch);
|
||||||
|
|
||||||
input_state_swap_frames(&state->input_state);
|
input_state_swap_frames(state->input_state);
|
||||||
|
|
||||||
en_frame_prepare(state);
|
en_frame_prepare(state);
|
||||||
if (has_flag(state->flags, AppState_RunEditor))
|
if (has_flag(state->flags, AppState_RunEditor))
|
||||||
|
@ -42,12 +43,14 @@ lumenarium_frame_prepare(App_State* state)
|
||||||
ed_frame_prepare(state);
|
ed_frame_prepare(state);
|
||||||
}
|
}
|
||||||
incenter_frame_prepare(state);
|
incenter_frame_prepare(state);
|
||||||
|
|
||||||
|
platform_file_async_jobs_do_work(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
lumenarium_frame(App_State* state)
|
lumenarium_frame(App_State* state)
|
||||||
{
|
{
|
||||||
en_frame(state);
|
//en_frame(state);
|
||||||
if (has_flag(state->flags, AppState_RunEditor))
|
if (has_flag(state->flags, AppState_RunEditor))
|
||||||
{
|
{
|
||||||
ed_frame(state);
|
ed_frame(state);
|
||||||
|
@ -58,7 +61,7 @@ lumenarium_frame(App_State* state)
|
||||||
internal void
|
internal void
|
||||||
lumenarium_event(Platform_Window_Event evt, App_State* state)
|
lumenarium_event(Platform_Window_Event evt, App_State* state)
|
||||||
{
|
{
|
||||||
Input_Frame* frame = state->input_state.frame_hot;
|
Input_Frame* frame = state->input_state->frame_hot;
|
||||||
switch (evt.kind)
|
switch (evt.kind)
|
||||||
{
|
{
|
||||||
case WindowEvent_MouseScroll:
|
case WindowEvent_MouseScroll:
|
||||||
|
@ -66,6 +69,13 @@ lumenarium_event(Platform_Window_Event evt, App_State* state)
|
||||||
frame->mouse_scroll = evt.scroll_amt;
|
frame->mouse_scroll = evt.scroll_amt;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case WindowEvent_MouseMoved:
|
||||||
|
{
|
||||||
|
v2 mouse_pos_old = frame->mouse_pos;
|
||||||
|
frame->mouse_pos = v2{ (r32)evt.mouse_x, (r32)evt.mouse_y };
|
||||||
|
state->input_state->mouse_pos_delta = frame->mouse_pos - mouse_pos_old;
|
||||||
|
} break;
|
||||||
|
|
||||||
case WindowEvent_ButtonDown:
|
case WindowEvent_ButtonDown:
|
||||||
case WindowEvent_ButtonUp:
|
case WindowEvent_ButtonUp:
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,11 +9,18 @@ typedef struct App_State App_State;
|
||||||
#include "lumenarium_memory.cpp"
|
#include "lumenarium_memory.cpp"
|
||||||
#include "lumenarium_string.cpp"
|
#include "lumenarium_string.cpp"
|
||||||
#include "lumenarium_input.cpp"
|
#include "lumenarium_input.cpp"
|
||||||
|
#include "lumenarium_texture_atlas.cpp"
|
||||||
|
#include "lumenarium_hash.cpp"
|
||||||
|
|
||||||
// Engine
|
// Engine
|
||||||
|
typedef struct Assembly_Strip Assembly_Strip;
|
||||||
|
#include "engine/lumenarium_engine_output.h"
|
||||||
#include "engine/lumenarium_engine_assembly.h"
|
#include "engine/lumenarium_engine_assembly.h"
|
||||||
|
#include "engine/output/lumenarium_output_uart.h"
|
||||||
|
#include "engine/output/lumenarium_output_sacn.h"
|
||||||
|
|
||||||
// Editor
|
// Editor
|
||||||
|
#include "editor/lumenarium_editor_ui.h"
|
||||||
#include "editor/lumenarium_editor_renderer.h"
|
#include "editor/lumenarium_editor_renderer.h"
|
||||||
#include "editor/lumenarium_editor.h"
|
#include "editor/lumenarium_editor.h"
|
||||||
|
|
||||||
|
@ -49,15 +56,21 @@ struct App_State
|
||||||
{
|
{
|
||||||
App_State_Flags flags;
|
App_State_Flags flags;
|
||||||
|
|
||||||
Input_State input_state;
|
Input_State* input_state;
|
||||||
|
|
||||||
Assembly_Array assemblies;
|
Assembly_Array assemblies;
|
||||||
|
Output output;
|
||||||
|
|
||||||
Editor* editor;
|
Editor* editor;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "engine/lumenarium_engine_assembly.cpp"
|
#include "engine/lumenarium_engine_assembly.cpp"
|
||||||
#include "engine/lumenarium_engine.cpp"
|
#include "engine/lumenarium_engine.cpp"
|
||||||
|
#include "engine/lumenarium_engine_output.cpp"
|
||||||
|
#include "engine/output/lumenarium_output_uart.cpp"
|
||||||
|
#include "engine/output/lumenarium_output_sacn.cpp"
|
||||||
|
|
||||||
|
#include "editor/lumenarium_editor_ui.cpp"
|
||||||
#include "editor/lumenarium_editor_renderer.cpp"
|
#include "editor/lumenarium_editor_renderer.cpp"
|
||||||
#include "editor/lumenarium_editor.cpp"
|
#include "editor/lumenarium_editor.cpp"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/* date = April 1st 2022 7:29 pm */
|
||||||
|
|
||||||
|
#ifndef LUMENARIUM_HASH_CPP
|
||||||
|
#define LUMENARIUM_HASH_CPP
|
||||||
|
|
||||||
|
//
|
||||||
|
// DJB2
|
||||||
|
// Source: http://www.cse.yorku.ca/~oz/hash.html
|
||||||
|
|
||||||
|
internal u32
|
||||||
|
hash_djb2_to_u32(char* str, u64 len)
|
||||||
|
{
|
||||||
|
u32 result = 5381;
|
||||||
|
for (u64 i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
result = ((result << 5) + result) + (u8)str[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal u32
|
||||||
|
hash_djb2_to_u32(char* str)
|
||||||
|
{
|
||||||
|
u64 len = c_str_len(str);
|
||||||
|
return hash_djb2_to_u32(str, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal u32
|
||||||
|
hash_djb2_to_u32(String str)
|
||||||
|
{
|
||||||
|
return hash_djb2_to_u32((char*)str.str, str.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal u64
|
||||||
|
hash_djb2_to_u64(char* str, u64 len)
|
||||||
|
{
|
||||||
|
u64 result = 5381;
|
||||||
|
for (u64 i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
result = ((result << 5) + result) + (u8)str[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal u64
|
||||||
|
hash_djb2_to_u64(char* str)
|
||||||
|
{
|
||||||
|
u64 len = c_str_len(str);
|
||||||
|
return hash_djb2_to_u64(str, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal u64
|
||||||
|
hash_djb2_to_u64(String str)
|
||||||
|
{
|
||||||
|
return hash_djb2_to_u64((char*)str.str, str.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //LUMENARIUM_HASH_CPP
|
|
@ -24,15 +24,30 @@ struct Input_State
|
||||||
|
|
||||||
#define key_was_down(key_flags) has_flag((key_flags), KeyFlag_State_WasDown)
|
#define key_was_down(key_flags) has_flag((key_flags), KeyFlag_State_WasDown)
|
||||||
#define key_is_down(key_flags) has_flag((key_flags), KeyFlag_State_IsDown)
|
#define key_is_down(key_flags) has_flag((key_flags), KeyFlag_State_IsDown)
|
||||||
#define key_was_up(key_flags) (!has_flag((key_flags), KeyFlag_State_WasDown)
|
#define key_was_up(key_flags) (!has_flag((key_flags), KeyFlag_State_WasDown))
|
||||||
#define key_is_up(key_flags) (!has_flag((key_flags), KeyFlag_State_IsDown)
|
#define key_is_up(key_flags) (!has_flag((key_flags), KeyFlag_State_IsDown))
|
||||||
|
|
||||||
internal Input_State
|
internal Input_State*
|
||||||
input_state_create()
|
input_state_create(Allocator* a)
|
||||||
{
|
{
|
||||||
Input_State result = {};
|
Input_State* result = allocator_alloc_struct(a, Input_State);
|
||||||
result.frame_hot = result.frames + 0;
|
result->frame_hot = result->frames + 0;
|
||||||
result.frame_cold = result.frames + 1;
|
result->frame_cold = result->frames + 1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Platform_Key_Flags
|
||||||
|
input_key_advance(Platform_Key_Flags flag)
|
||||||
|
{
|
||||||
|
Platform_Key_Flags result = flag;
|
||||||
|
if (key_is_down(flag))
|
||||||
|
{
|
||||||
|
add_flag(result, KeyFlag_State_WasDown);
|
||||||
|
}
|
||||||
|
if (key_is_up(flag))
|
||||||
|
{
|
||||||
|
rem_flag(result, KeyFlag_State_WasDown);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +61,10 @@ input_state_swap_frames(Input_State* input_state)
|
||||||
// Clear the new hot input frame
|
// Clear the new hot input frame
|
||||||
Platform_Key_Flags* hot_key_flags = input_state->frame_hot->key_flags;
|
Platform_Key_Flags* hot_key_flags = input_state->frame_hot->key_flags;
|
||||||
Platform_Key_Flags* cold_key_flags = input_state->frame_cold->key_flags;
|
Platform_Key_Flags* cold_key_flags = input_state->frame_cold->key_flags;
|
||||||
for (u32 i = 0; i < KeyCode_Count; i++) hot_key_flags[i] = cold_key_flags[i];
|
for (u32 i = 0; i < KeyCode_Count; i++)
|
||||||
|
{
|
||||||
|
hot_key_flags[i] = input_key_advance(cold_key_flags[i]);
|
||||||
|
}
|
||||||
input_state->frame_hot->string_input_len = 0;
|
input_state->frame_hot->string_input_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,21 +32,25 @@ memory_copy_simd(u8* from, u8* to, u64 size)
|
||||||
memory_copy_no_simd(from, to, size);
|
memory_copy_no_simd(from, to, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
# define memory_zero(b,s) memory_zero_simd((b),(s))
|
# define memory_zero_(b,s) memory_zero_simd((b),(s))
|
||||||
# define memory_copy(f,t,s) memory_copy_simd((f),(t),(s))
|
# define memory_copy_(f,t,s) memory_copy_simd((f),(t),(s))
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# define memory_zero(b,s) memory_zero_no_simd((b),(s))
|
# define memory_zero_(b,s) memory_zero_no_simd((b),(s))
|
||||||
# define memory_copy(f,t,s) memory_copy_no_simd((f),(t),(s))
|
# define memory_copy_(f,t,s) memory_copy_no_simd((f),(t),(s))
|
||||||
|
|
||||||
#endif // defined(PLATFORM_HAS_SIMD)
|
#endif // defined(PLATFORM_HAS_SIMD)
|
||||||
|
|
||||||
#define zero_struct(s) memory_zero((u8*)(&s), sizeof(s))
|
#define zero_struct(s) memory_zero((u8*)(&s), sizeof(s))
|
||||||
|
|
||||||
|
internal void memory_zero(u8* base, u64 size) { memory_zero_(base, size); }
|
||||||
|
internal void memory_copy(u8* from, u8* to, u64 size) {
|
||||||
|
memory_copy_(from, to, size);
|
||||||
|
}
|
||||||
|
|
||||||
u64
|
u64
|
||||||
size_to_pages(u64 size)
|
round_size_to_page_multiple(u64 size, u64 page_size)
|
||||||
{
|
{
|
||||||
u64 page_size = platform_page_size();
|
|
||||||
u64 rem = size % page_size;
|
u64 rem = size % page_size;
|
||||||
if (rem != 0 || size < page_size)
|
if (rem != 0 || size < page_size)
|
||||||
{
|
{
|
||||||
|
@ -56,6 +60,13 @@ size_to_pages(u64 size)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64
|
||||||
|
round_size_to_page_multiple(u64 size)
|
||||||
|
{
|
||||||
|
u64 page_size = platform_page_size();
|
||||||
|
return round_size_to_page_multiple(size, page_size);
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
// Allocator
|
// Allocator
|
||||||
//
|
//
|
||||||
|
@ -64,37 +75,14 @@ size_to_pages(u64 size)
|
||||||
// To implement a complete allocator, all that is really required
|
// To implement a complete allocator, all that is really required
|
||||||
// is to create its Allocator_Alloc function
|
// is to create its Allocator_Alloc function
|
||||||
|
|
||||||
typedef struct Allocator Allocator;
|
internal void
|
||||||
|
allocator_destroy_(Allocator* allocator, u64 custom_data_size)
|
||||||
typedef u8* Allocator_Alloc(Allocator* allocator, u64 size);
|
|
||||||
typedef void Allocator_Free(Allocator* allocator, u8* base, u64 size);
|
|
||||||
typedef u8* Allocator_Realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size);
|
|
||||||
typedef void Allocator_Clear(Allocator* allocator);
|
|
||||||
|
|
||||||
struct Allocator
|
|
||||||
{
|
{
|
||||||
Allocator_Alloc* alloc;
|
zero_struct(*allocator);
|
||||||
Allocator_Free* free;
|
u64 size = sizeof(Allocator) + custom_data_size;
|
||||||
Allocator_Realloc* realloc;
|
platform_mem_decommit((u8*)allocator, size);
|
||||||
Allocator_Clear* clear;
|
platform_mem_release((u8*)allocator, size);
|
||||||
|
}
|
||||||
Allocator* parent;
|
|
||||||
|
|
||||||
u8* allocator_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define allocator_alloc(a,s) (a)->alloc((a),(s))
|
|
||||||
#define allocator_alloc_struct(a,t) (t*)(a)->alloc((a),sizeof(t))
|
|
||||||
#define allocator_alloc_array(a,t,c) (t*)(a)->alloc((a),sizeof(t)*(c))
|
|
||||||
|
|
||||||
#define allocator_free(a,b,s) (a)->free((a),(b),(s))
|
|
||||||
#define allocator_free_struct(a,b,t) (a)->free((a),(b),sizeof(t))
|
|
||||||
#define allocator_free_array(a,b,t,c) (a)->free((a),(b),sizeof(t)*(c))
|
|
||||||
|
|
||||||
#define allocator_realloc(a,b,os,ns) (a)->realloc((a),(b),(os),(ns))
|
|
||||||
#define allocator_realloc_array(a,b,t,oc,nc) (t*)(a)->realloc((a),(b),sizeof(t)*(oc),sizeof(t)*(nc))
|
|
||||||
|
|
||||||
#define allocator_clear(a) (a)->clear(a)
|
|
||||||
|
|
||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
// Bump Allocator
|
// Bump Allocator
|
||||||
|
@ -105,13 +93,12 @@ struct Allocator_Bump
|
||||||
u64 at;
|
u64 at;
|
||||||
u64 size_committed;
|
u64 size_committed;
|
||||||
u64 size_reserved;
|
u64 size_reserved;
|
||||||
|
u64 page_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
internal u8*
|
internal u8*
|
||||||
bump_allocator_alloc(Allocator* allocator, u64 size)
|
bump_allocator_alloc_inner(Allocator* allocator, Allocator_Bump* bump, u64 size)
|
||||||
{
|
{
|
||||||
Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data;
|
|
||||||
|
|
||||||
u64 at_after = bump->at + size;
|
u64 at_after = bump->at + size;
|
||||||
// TODO(PS): align up to 8 bytes
|
// TODO(PS): align up to 8 bytes
|
||||||
|
|
||||||
|
@ -119,8 +106,15 @@ bump_allocator_alloc(Allocator* allocator, u64 size)
|
||||||
{
|
{
|
||||||
// determine new size of the arena
|
// determine new size of the arena
|
||||||
u64 new_size = bump->size_committed * 2;
|
u64 new_size = bump->size_committed * 2;
|
||||||
if (new_size == 0) new_size = platform_page_size();
|
if (new_size == 0)
|
||||||
if (new_size < at_after) new_size = size_to_pages(at_after);
|
{
|
||||||
|
if (bump->page_size == 0) bump->page_size = platform_page_size();
|
||||||
|
new_size = bump->page_size;
|
||||||
|
}
|
||||||
|
if (new_size < at_after)
|
||||||
|
{
|
||||||
|
new_size = round_size_to_page_multiple(at_after, bump->page_size);
|
||||||
|
}
|
||||||
|
|
||||||
if (allocator->parent)
|
if (allocator->parent)
|
||||||
{
|
{
|
||||||
|
@ -140,7 +134,7 @@ bump_allocator_alloc(Allocator* allocator, u64 size)
|
||||||
{
|
{
|
||||||
if (new_size <= bump->size_reserved)
|
if (new_size <= bump->size_reserved)
|
||||||
{
|
{
|
||||||
u64 next_page = size_to_pages(bump->at);
|
u64 next_page = round_size_to_page_multiple(bump->at);
|
||||||
if (bump->at == 0 && bump->size_committed == 0) next_page = 0;
|
if (bump->at == 0 && bump->size_committed == 0) next_page = 0;
|
||||||
u64 commit_amt = new_size - next_page;
|
u64 commit_amt = new_size - next_page;
|
||||||
u8* new_page = platform_mem_commit(bump->base + next_page, commit_amt);
|
u8* new_page = platform_mem_commit(bump->base + next_page, commit_amt);
|
||||||
|
@ -162,6 +156,14 @@ bump_allocator_alloc(Allocator* allocator, u64 size)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal u8*
|
||||||
|
bump_allocator_alloc(Allocator* allocator, u64 size)
|
||||||
|
{
|
||||||
|
Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data;
|
||||||
|
u8* result = bump_allocator_alloc_inner(allocator, bump, size);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
internal u8*
|
internal u8*
|
||||||
bump_allocator_realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size)
|
bump_allocator_realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size)
|
||||||
{
|
{
|
||||||
|
@ -178,6 +180,21 @@ bump_allocator_clear(Allocator* allocator)
|
||||||
bump->at = 0;
|
bump->at = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
bump_allocator_destroy_(Allocator_Bump* bump)
|
||||||
|
{
|
||||||
|
platform_mem_decommit(bump->base, bump->size_committed);
|
||||||
|
platform_mem_release(bump->base, bump->size_reserved);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
bump_allocator_destroy(Allocator* allocator)
|
||||||
|
{
|
||||||
|
Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data;
|
||||||
|
bump_allocator_destroy_(bump);
|
||||||
|
allocator_destroy_(allocator, sizeof(Allocator_Bump));
|
||||||
|
}
|
||||||
|
|
||||||
internal Allocator*
|
internal Allocator*
|
||||||
bump_allocator_create_()
|
bump_allocator_create_()
|
||||||
{
|
{
|
||||||
|
@ -195,6 +212,7 @@ bump_allocator_create_()
|
||||||
result->alloc = bump_allocator_alloc;
|
result->alloc = bump_allocator_alloc;
|
||||||
result->realloc = bump_allocator_realloc;
|
result->realloc = bump_allocator_realloc;
|
||||||
result->clear = bump_allocator_clear;
|
result->clear = bump_allocator_clear;
|
||||||
|
result->destroy = bump_allocator_destroy;
|
||||||
result->allocator_data = (u8*)bump;
|
result->allocator_data = (u8*)bump;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -206,7 +224,7 @@ bump_allocator_create_reserve(u64 reserve_size)
|
||||||
Allocator* result = bump_allocator_create_();
|
Allocator* result = bump_allocator_create_();
|
||||||
Allocator_Bump* bump = (Allocator_Bump*)result->allocator_data;
|
Allocator_Bump* bump = (Allocator_Bump*)result->allocator_data;
|
||||||
|
|
||||||
u64 reserve_pages = size_to_pages(reserve_size);
|
u64 reserve_pages = round_size_to_page_multiple(reserve_size);
|
||||||
bump->base = platform_mem_reserve(reserve_pages);
|
bump->base = platform_mem_reserve(reserve_pages);
|
||||||
if (bump->base != 0) bump->size_reserved = reserve_pages;
|
if (bump->base != 0) bump->size_reserved = reserve_pages;
|
||||||
|
|
||||||
|
@ -229,3 +247,286 @@ bump_allocator_create_child(Allocator* parent, u64 init_size)
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////
|
||||||
|
// Paged Allocator
|
||||||
|
|
||||||
|
struct Allocator_Paged_Free_Region
|
||||||
|
{
|
||||||
|
u64 pages;
|
||||||
|
Allocator_Paged_Free_Region* prev;
|
||||||
|
Allocator_Paged_Free_Region* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Allocator_Paged
|
||||||
|
{
|
||||||
|
Allocator_Bump bump;
|
||||||
|
Allocator_Paged_Free_Region* free_first;
|
||||||
|
};
|
||||||
|
|
||||||
|
internal u8*
|
||||||
|
paged_allocator_alloc(Allocator* allocator, u64 size)
|
||||||
|
{
|
||||||
|
// 1. Find the number of pages we need
|
||||||
|
// 2. Find a run of free pages that we can use
|
||||||
|
// If found,
|
||||||
|
// remove those pages from the run they are in
|
||||||
|
// return those pages of memory
|
||||||
|
// 3. Commit pages on the end
|
||||||
|
|
||||||
|
Allocator_Paged* paged = (Allocator_Paged*)allocator->allocator_data;
|
||||||
|
if (paged->bump.page_size == 0) paged->bump.page_size = platform_page_size();
|
||||||
|
|
||||||
|
u64 rounded_size = round_size_to_page_multiple(size, paged->bump.page_size);
|
||||||
|
u64 pages_needed = rounded_size / paged->bump.page_size;
|
||||||
|
|
||||||
|
u8* result = 0;
|
||||||
|
|
||||||
|
// Find free pages
|
||||||
|
if (paged->free_first)
|
||||||
|
{
|
||||||
|
Allocator_Paged_Free_Region* found = 0;
|
||||||
|
for (Allocator_Paged_Free_Region* at = paged->free_first; at != 0; at = at->next)
|
||||||
|
{
|
||||||
|
// NOTE(PS): this set of conditions checks to see if is bigger than what
|
||||||
|
// we need. If it is, we also check to see if this is smaller than any
|
||||||
|
// region we've found before. And we abort the search if this region
|
||||||
|
// perfectly fits the size needed.
|
||||||
|
//
|
||||||
|
// This should make sure that we are always choosing the closest fit we
|
||||||
|
// can. I'm not sure this is the best strategy for dealing with fragmentation
|
||||||
|
// but its a decent first pass
|
||||||
|
if (at->pages >= pages_needed)
|
||||||
|
{
|
||||||
|
if (!found || (found->pages > at->pages))
|
||||||
|
{
|
||||||
|
found = at;
|
||||||
|
if (found->pages == pages_needed) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
result = (u8*)found;
|
||||||
|
if (found->pages > pages_needed)
|
||||||
|
{
|
||||||
|
Allocator_Paged_Free_Region* region_after = (Allocator_Paged_Free_Region*)(result + rounded_size);
|
||||||
|
if (found->prev != 0) found->prev->next = region_after;
|
||||||
|
region_after = found->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (found->prev != 0) found->prev->next = found->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
result = bump_allocator_alloc_inner(allocator, &paged->bump, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define region_end(r,page_size) ((u8*)(r) + ((r)->pages * page_size))
|
||||||
|
|
||||||
|
internal void
|
||||||
|
paged_region_insert(
|
||||||
|
Allocator_Paged_Free_Region* before,
|
||||||
|
Allocator_Paged_Free_Region* new_region,
|
||||||
|
Allocator_Paged_Free_Region* after,
|
||||||
|
u64 page_size
|
||||||
|
){
|
||||||
|
assert(after == 0 || before < after);
|
||||||
|
assert(before < new_region);
|
||||||
|
assert(after == 0 || new_region < after);
|
||||||
|
assert(new_region->prev == 0 && new_region->next == 0);
|
||||||
|
|
||||||
|
u8* before_end = region_end(before, page_size);
|
||||||
|
u8* new_region_end = region_end(new_region, page_size);
|
||||||
|
|
||||||
|
// Before
|
||||||
|
if (before_end == (u8*)new_region)
|
||||||
|
{
|
||||||
|
// merge the regions
|
||||||
|
before->pages += new_region->pages;
|
||||||
|
new_region = before;
|
||||||
|
assert(new_region_end == region_end(new_region, page_size));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(before_end < (u8*)new_region);
|
||||||
|
before->next = new_region;
|
||||||
|
new_region->prev = before;
|
||||||
|
}
|
||||||
|
|
||||||
|
// After
|
||||||
|
if (after != 0)
|
||||||
|
{
|
||||||
|
if (new_region_end == (u8*)after)
|
||||||
|
{
|
||||||
|
// merge the regions
|
||||||
|
new_region->pages += after->pages;
|
||||||
|
u8* a = region_end(after, page_size);
|
||||||
|
u8* b = region_end(new_region, page_size);
|
||||||
|
assert(a == b);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(new_region_end < (u8*)after);
|
||||||
|
new_region->next = after;
|
||||||
|
after->prev = new_region;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
paged_allocator_free(Allocator* allocator, u8* base, u64 size)
|
||||||
|
{
|
||||||
|
// Figure out which page base is the base of, assert its the base
|
||||||
|
// figure out how many pages size represents.
|
||||||
|
// create a free range
|
||||||
|
// stick it in between contiguous free ranges
|
||||||
|
// if the ranges before or after meet this new one, merge them all
|
||||||
|
|
||||||
|
Allocator_Paged* paged = (Allocator_Paged*)allocator->allocator_data;
|
||||||
|
|
||||||
|
u64 page_base_rel = (base - paged->bump.base);
|
||||||
|
assert((page_base_rel % paged->bump.page_size) == 0);
|
||||||
|
u64 page_index = page_base_rel / paged->bump.page_size;
|
||||||
|
u64 size_pages_mult = round_size_to_page_multiple(size, paged->bump.page_size);
|
||||||
|
assert((size_pages_mult % paged->bump.page_size) == 0);
|
||||||
|
u64 page_count = size_pages_mult / paged->bump.page_size;
|
||||||
|
|
||||||
|
Allocator_Paged_Free_Region* region = (Allocator_Paged_Free_Region*)base;
|
||||||
|
zero_struct(*region);
|
||||||
|
region->pages = page_count;
|
||||||
|
|
||||||
|
Allocator_Paged_Free_Region* prev = 0;
|
||||||
|
Allocator_Paged_Free_Region* next = 0;
|
||||||
|
for (Allocator_Paged_Free_Region* at = paged->free_first; at != 0; at = at->next)
|
||||||
|
{
|
||||||
|
if (at < region)
|
||||||
|
{
|
||||||
|
prev = at;
|
||||||
|
next = at->next;
|
||||||
|
if (next != 0)
|
||||||
|
{
|
||||||
|
assert(next > region);
|
||||||
|
assert((u8*)next >= ((u8*)region + size_pages_mult));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prev && next)
|
||||||
|
{
|
||||||
|
// found a region to insert into
|
||||||
|
paged_region_insert(prev, region, next, paged->bump.page_size);
|
||||||
|
}
|
||||||
|
else if (prev)
|
||||||
|
{
|
||||||
|
// got to the end and all were before the free region in memory
|
||||||
|
paged_region_insert(prev, region, 0, paged->bump.page_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// free list is empty
|
||||||
|
paged->free_first = region;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal u8*
|
||||||
|
paged_allocator_realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size)
|
||||||
|
{
|
||||||
|
// TODO(PS):
|
||||||
|
// Process:
|
||||||
|
// 1. Figure out which page base starts on
|
||||||
|
// 2. Find if there is a free region after base that is big enough to house
|
||||||
|
// the new size
|
||||||
|
// 3. If there is a free region, pull the needed memory out of it
|
||||||
|
// 4. Otherwise, alloc new_size, copy base into it, and free base
|
||||||
|
|
||||||
|
// TODO(PS): you could do a simple version where you just always alloc, copy, free
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
paged_allocator_clear(Allocator* allocator)
|
||||||
|
{
|
||||||
|
if (!allocator->allocator_data) return;
|
||||||
|
Allocator_Paged* paged = (Allocator_Paged*)allocator->allocator_data;
|
||||||
|
paged->bump.at = 0;
|
||||||
|
paged->free_first = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
paged_allocator_destroy(Allocator* allocator)
|
||||||
|
{
|
||||||
|
Allocator_Paged* paged = (Allocator_Paged*)allocator->allocator_data;
|
||||||
|
bump_allocator_destroy_(&paged->bump);
|
||||||
|
allocator_destroy_(allocator, sizeof(Allocator_Paged));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Allocator*
|
||||||
|
paged_allocator_create_()
|
||||||
|
{
|
||||||
|
u64 size_needed = sizeof(Allocator) + sizeof(Allocator_Bump);
|
||||||
|
|
||||||
|
u8* base = platform_mem_reserve(size_needed);
|
||||||
|
base = platform_mem_commit(base, size_needed);
|
||||||
|
|
||||||
|
Allocator* result = (Allocator*)base;
|
||||||
|
zero_struct(*result);
|
||||||
|
|
||||||
|
Allocator_Bump* bump = (Allocator_Bump*)base + sizeof(Allocator);
|
||||||
|
zero_struct(*bump);
|
||||||
|
|
||||||
|
result->alloc = paged_allocator_alloc;
|
||||||
|
result->free = paged_allocator_free;
|
||||||
|
result->realloc = paged_allocator_realloc;
|
||||||
|
result->clear = paged_allocator_clear;
|
||||||
|
result->destroy = paged_allocator_destroy;
|
||||||
|
result->allocator_data = (u8*)bump;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Allocator*
|
||||||
|
paged_allocator_create_reserve(u64 reserve_size, u64 page_size)
|
||||||
|
{
|
||||||
|
Allocator* result = paged_allocator_create_();
|
||||||
|
Allocator_Paged* paged = (Allocator_Paged*)result->allocator_data;
|
||||||
|
|
||||||
|
u64 reserve_pages = round_size_to_page_multiple(reserve_size);
|
||||||
|
paged->bump.page_size = page_size;
|
||||||
|
paged->bump.base = platform_mem_reserve(reserve_pages);
|
||||||
|
if (paged->bump.base != 0) paged->bump.size_reserved = reserve_pages;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Allocator*
|
||||||
|
paged_allocator_create_reserve(u64 reserve_size)
|
||||||
|
{
|
||||||
|
u64 page_size = platform_page_size();
|
||||||
|
return paged_allocator_create_reserve(reserve_size, page_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Allocator*
|
||||||
|
paged_allocator_create_child(Allocator* parent, u64 init_size)
|
||||||
|
{
|
||||||
|
Allocator* result = bump_allocator_create_();
|
||||||
|
result->parent = parent;
|
||||||
|
|
||||||
|
Allocator_Paged* paged = (Allocator_Paged*)result->allocator_data;
|
||||||
|
paged->bump.base = allocator_alloc(result->parent, init_size);
|
||||||
|
if (paged->bump.base != 0)
|
||||||
|
{
|
||||||
|
paged->bump.size_reserved = init_size;
|
||||||
|
paged->bump.size_committed = init_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/* date = April 6th 2022 7:55 pm */
|
||||||
|
|
||||||
|
#ifndef LUMENARIUM_MEMORY_H
|
||||||
|
#define LUMENARIUM_MEMORY_H
|
||||||
|
|
||||||
|
/////////////////////////////////////////
|
||||||
|
// Allocator
|
||||||
|
|
||||||
|
typedef struct Allocator Allocator;
|
||||||
|
|
||||||
|
typedef u8* Allocator_Alloc(Allocator* allocator, u64 size);
|
||||||
|
typedef void Allocator_Free(Allocator* allocator, u8* base, u64 size);
|
||||||
|
typedef u8* Allocator_Realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size);
|
||||||
|
typedef void Allocator_Clear(Allocator* allocator);
|
||||||
|
typedef void Allocator_Destroy(Allocator* allocator);
|
||||||
|
|
||||||
|
struct Allocator
|
||||||
|
{
|
||||||
|
Allocator_Alloc* alloc;
|
||||||
|
Allocator_Free* free;
|
||||||
|
Allocator_Realloc* realloc;
|
||||||
|
Allocator_Clear* clear;
|
||||||
|
Allocator_Destroy* destroy;
|
||||||
|
|
||||||
|
Allocator* parent;
|
||||||
|
|
||||||
|
u8* allocator_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define allocator_alloc(a,s) (a)->alloc((a),(s))
|
||||||
|
#define allocator_alloc_struct(a,t) (t*)(a)->alloc((a),sizeof(t))
|
||||||
|
#define allocator_alloc_array(a,t,c) (t*)(a)->alloc((a),sizeof(t)*(c))
|
||||||
|
|
||||||
|
#define allocator_free(a,b,s) (a)->free((a),(b),(s))
|
||||||
|
#define allocator_free_struct(a,b,t) (a)->free((a),(b),sizeof(t))
|
||||||
|
#define allocator_free_array(a,b,t,c) (a)->free((a),(b),sizeof(t)*(c))
|
||||||
|
|
||||||
|
#define allocator_realloc(a,b,os,ns) (a)->realloc((a),(b),(os),(ns))
|
||||||
|
#define allocator_realloc_array(a,b,t,oc,nc) (t*)(a)->realloc((a),(b),sizeof(t)*(oc),sizeof(t)*(nc))
|
||||||
|
|
||||||
|
#define allocator_clear(a) (a)->clear(a)
|
||||||
|
#define allocator_destroy(a) (a)->destroy(a)
|
||||||
|
|
||||||
|
internal Allocator* paged_allocator_create_reserve(u64 reserve_size, u64 page_size);
|
||||||
|
#endif //LUMENARIUM_MEMORY_H
|
|
@ -54,6 +54,16 @@ char_to_forward_slash(u8 c)
|
||||||
// Note that these don't actually modify any memory
|
// Note that these don't actually modify any memory
|
||||||
// just return structures that let you view it differently
|
// just return structures that let you view it differently
|
||||||
|
|
||||||
|
internal String
|
||||||
|
string_create(u8* str, u64 len, u64 cap)
|
||||||
|
{
|
||||||
|
String result = {};
|
||||||
|
result.str = str;
|
||||||
|
result.len = len;
|
||||||
|
result.cap = cap;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
internal String
|
internal String
|
||||||
string_substring(String s, u64 min, u64 max)
|
string_substring(String s, u64 min, u64 max)
|
||||||
{
|
{
|
||||||
|
@ -213,15 +223,25 @@ string_chop_last_slash(String s)
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
// String Modifications
|
// String Modifications
|
||||||
|
|
||||||
|
internal u64
|
||||||
|
string_copy_to(String* dest, String src)
|
||||||
|
{
|
||||||
|
u64 len_to_copy = dest->cap < src.len ? dest->cap : src.len;
|
||||||
|
memory_copy(src.str, dest->str, len_to_copy);
|
||||||
|
u64 null_term_index = len_to_copy;
|
||||||
|
if (null_term_index >= dest->cap) null_term_index -= 1;
|
||||||
|
dest->str[null_term_index] = 0;
|
||||||
|
dest->len = null_term_index;
|
||||||
|
return null_term_index;
|
||||||
|
}
|
||||||
|
|
||||||
internal String
|
internal String
|
||||||
string_copy(String s, Allocator* a)
|
string_copy(String s, Allocator* a)
|
||||||
{
|
{
|
||||||
u64 size = s.cap;
|
u64 size = s.cap;
|
||||||
if (s.str[s.cap] != 0) size += 1;
|
if (s.str[s.cap] != 0) size += 1;
|
||||||
String result = allocator_alloc_string(a, size);
|
String result = allocator_alloc_string(a, size);
|
||||||
memory_copy(s.str, result.str, s.cap);
|
string_copy_to(&result, s);
|
||||||
result.str[size] = 0;
|
|
||||||
result.len = size;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,90 @@ thread_proc(Platform_Thread_Data* td)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
memory_allocator_tests(Allocator* a, bool run_free_tests)
|
||||||
|
{
|
||||||
|
// TestGroup("Allocator Push")
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
u8* buf0 = allocator_alloc(a, 256);
|
||||||
|
buf0[0] = 200;
|
||||||
|
buf0[255] = 199;
|
||||||
|
assert(buf0[0] == 200);
|
||||||
|
assert(buf0[255] == 199);
|
||||||
|
|
||||||
|
u8* buf1 = allocator_alloc(a, 256);
|
||||||
|
buf1[0] = 201;
|
||||||
|
buf1[255] = 202;
|
||||||
|
assert(buf1 >= (buf0 + 256));
|
||||||
|
assert(buf0[0] == 200);
|
||||||
|
assert(buf0[255] == 199);
|
||||||
|
assert(buf1[0] == 201);
|
||||||
|
assert(buf1[255] == 202);
|
||||||
|
|
||||||
|
allocator_clear(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGroup("Allocator Free")
|
||||||
|
if (run_free_tests)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
u8* buf0 = allocator_alloc(a, KB(4));
|
||||||
|
u8* buf1 = allocator_alloc(a, KB(4));
|
||||||
|
u8* buf2 = allocator_alloc(a, KB(4));
|
||||||
|
u8* buf3 = allocator_alloc(a, KB(4));
|
||||||
|
u8* buf4 = allocator_alloc(a, KB(4));
|
||||||
|
assert((buf1 - buf0) >= KB(4));
|
||||||
|
assert((buf2 - buf0) >= KB(8));
|
||||||
|
assert((buf3 - buf0) >= KB(12));
|
||||||
|
assert((buf4 - buf0) >= KB(16));
|
||||||
|
|
||||||
|
allocator_free(a, buf1, KB(4));
|
||||||
|
allocator_free(a, buf2, KB(4));
|
||||||
|
u8* buf5 = allocator_alloc(a, KB(7));
|
||||||
|
// buf5 should get put in the place of buf1 since buf1 and 2 get
|
||||||
|
// merged
|
||||||
|
assert(buf5 == buf1);
|
||||||
|
|
||||||
|
allocator_free(a, buf4, KB(4));
|
||||||
|
allocator_free(a, buf3, KB(4));
|
||||||
|
allocator_free(a, buf0, KB(4));
|
||||||
|
u8* buf6 = allocator_alloc(a, KB(4));
|
||||||
|
assert(buf0 == buf6);
|
||||||
|
|
||||||
|
allocator_clear(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
memory_tests()
|
||||||
|
{
|
||||||
|
// TestGroup("Platform Allocation")
|
||||||
|
{
|
||||||
|
u8* base = platform_mem_reserve(GB(32));
|
||||||
|
platform_mem_commit(base, KB(4));
|
||||||
|
base[4095] = 200;
|
||||||
|
assert(base[4095] == 200);
|
||||||
|
platform_mem_commit(base + KB(4), KB(4));
|
||||||
|
base[5000] = 200;
|
||||||
|
assert(base[5000] == 200);
|
||||||
|
platform_mem_decommit(base, KB(8));
|
||||||
|
platform_mem_release(base, GB(32));
|
||||||
|
}
|
||||||
|
|
||||||
|
Allocator* bump = bump_allocator_create_reserve(KB(32));
|
||||||
|
memory_allocator_tests(bump, false);
|
||||||
|
allocator_destroy(bump);
|
||||||
|
|
||||||
|
Allocator* paged = paged_allocator_create_reserve(KB(32));
|
||||||
|
memory_allocator_tests(paged, true);
|
||||||
|
allocator_destroy(paged);
|
||||||
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
run_tests()
|
run_tests()
|
||||||
{
|
{
|
||||||
|
@ -29,6 +113,8 @@ run_tests()
|
||||||
assert(a1[i] == (100 + i));
|
assert(a1[i] == (100 + i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memory_tests();
|
||||||
|
|
||||||
#if defined(PLATFORM_wasm)
|
#if defined(PLATFORM_wasm)
|
||||||
// NOTE(PS): the tests below this point don't make sense on a web assembly
|
// NOTE(PS): the tests below this point don't make sense on a web assembly
|
||||||
// platform
|
// platform
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
/* date = March 31st 2022 8:30 pm */
|
||||||
|
|
||||||
|
#ifndef LUMENARIUM_TEXTURE_ATLAS_CPP
|
||||||
|
#define LUMENARIUM_TEXTURE_ATLAS_CPP
|
||||||
|
|
||||||
|
struct Texture_Atlas_Sprite
|
||||||
|
{
|
||||||
|
u16 min_x;
|
||||||
|
u16 min_y;
|
||||||
|
u16 max_x;
|
||||||
|
u16 max_y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Texture_Atlas
|
||||||
|
{
|
||||||
|
u8* pixels;
|
||||||
|
u16 width;
|
||||||
|
u16 height;
|
||||||
|
|
||||||
|
u16 next_x;
|
||||||
|
u16 next_y;
|
||||||
|
u16 y_used;
|
||||||
|
|
||||||
|
u32* ids;
|
||||||
|
Texture_Atlas_Sprite* sprites;
|
||||||
|
u32 cap;
|
||||||
|
u32 used;
|
||||||
|
};
|
||||||
|
|
||||||
|
internal Texture_Atlas
|
||||||
|
texture_atlas_create(u32 width, u32 height, u32 cap, Allocator* allocator)
|
||||||
|
{
|
||||||
|
Texture_Atlas result = {};
|
||||||
|
result.pixels = allocator_alloc_array(allocator, u8, width * height * 4);
|
||||||
|
result.width = (u16)width;
|
||||||
|
result.height = (u16)height;
|
||||||
|
for (u32 i = 0; i < width * height; i++) {
|
||||||
|
u8* base = result.pixels + (i * 4);
|
||||||
|
*(u32*)base = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.ids = allocator_alloc_array(allocator, u32, cap);
|
||||||
|
result.sprites = allocator_alloc_array(allocator, Texture_Atlas_Sprite, cap);
|
||||||
|
result.cap = cap;
|
||||||
|
hash_table_init(result.ids, cap);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
texture_atlas_register(Texture_Atlas* ta, u8* pixels, u32 width, u32 height, u32 id)
|
||||||
|
{
|
||||||
|
u16 min_x = ta->next_x;
|
||||||
|
u16 min_y = ta->next_y;
|
||||||
|
u16 max_x = min_x + (u16)width;
|
||||||
|
u16 max_y = min_y + (u16)height;
|
||||||
|
|
||||||
|
// TODO(PS): if the sprite won't fit in this row, then we need to shift it to
|
||||||
|
// the next one
|
||||||
|
|
||||||
|
// copy the data
|
||||||
|
for (u16 y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
u16 src_row = (y * (u16)width) * 4;
|
||||||
|
u16 dst_row = (((y + min_y) * ta->width) + min_x) * 4;
|
||||||
|
for (u16 x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
ta->pixels[dst_row++] = pixels[src_row++];
|
||||||
|
ta->pixels[dst_row++] = pixels[src_row++];
|
||||||
|
ta->pixels[dst_row++] = pixels[src_row++];
|
||||||
|
ta->pixels[dst_row++] = pixels[src_row++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// register a new slot
|
||||||
|
u32 index = hash_table_register(ta->ids, ta->cap, id);
|
||||||
|
|
||||||
|
Texture_Atlas_Sprite* sprite = ta->sprites + index;
|
||||||
|
sprite->min_x = min_x;
|
||||||
|
sprite->min_y = min_y;
|
||||||
|
sprite->max_x = max_x;
|
||||||
|
sprite->max_y = max_y;
|
||||||
|
|
||||||
|
// Prepare for next registration
|
||||||
|
if (max_y > ta->y_used)
|
||||||
|
{
|
||||||
|
ta->y_used = max_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
ta->next_x = max_x + 1;
|
||||||
|
if (ta->next_x > ta->width)
|
||||||
|
{
|
||||||
|
ta->next_x = 0;
|
||||||
|
ta->next_y = ta->y_used;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Texture_Atlas_Sprite
|
||||||
|
texture_atlas_sprite_get(Texture_Atlas* ta, u32 id)
|
||||||
|
{
|
||||||
|
Texture_Atlas_Sprite result = {};
|
||||||
|
u32 index = hash_table_find(ta->ids, ta->cap, id);
|
||||||
|
if (index == ta->cap) return result;
|
||||||
|
result = ta->sprites[index];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal v4
|
||||||
|
texture_atlas_sprite_get_uvs(Texture_Atlas* ta, u32 id)
|
||||||
|
{
|
||||||
|
Texture_Atlas_Sprite sprite = texture_atlas_sprite_get(ta, id);
|
||||||
|
v4 result = {};
|
||||||
|
|
||||||
|
// uv min
|
||||||
|
result.x = (r32)sprite.min_x / (r32)ta->width;
|
||||||
|
result.y = (r32)sprite.min_y / (r32)ta->height;
|
||||||
|
|
||||||
|
// uv max
|
||||||
|
result.z = (r32)sprite.max_x / (r32)ta->width;
|
||||||
|
result.w = (r32)sprite.max_y / (r32)ta->height;
|
||||||
|
|
||||||
|
// inset
|
||||||
|
v2 half_texel = v2{1.0f / ta->width, 1.0f / ta->height};
|
||||||
|
result.xy += half_texel;
|
||||||
|
result.zw -= half_texel;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif //LUMENARIUM_TEXTURE_ATLAS_CPP
|
|
@ -37,16 +37,149 @@ typedef s64 b64;
|
||||||
typedef float r32;
|
typedef float r32;
|
||||||
typedef double r64;
|
typedef double r64;
|
||||||
|
|
||||||
|
#define get_byte(value, byte_index) ((value >> (8 * byte_index)) & 0xFF)
|
||||||
|
|
||||||
struct Data
|
struct Data
|
||||||
{
|
{
|
||||||
u8* base;
|
u8* base;
|
||||||
u64 size;
|
u64 size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
internal Data
|
||||||
|
data_create(u8* base, u64 size)
|
||||||
|
{
|
||||||
|
Data result = {};
|
||||||
|
result.base = base;
|
||||||
|
result.size = size;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void memory_zero(u8* base, u64 size);
|
||||||
|
internal void memory_copy(u8* from, u8* to, u64 size);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////
|
||||||
|
// String
|
||||||
|
|
||||||
|
// NOTE(PS): even though this has a len and cap, it should always be
|
||||||
|
// null terminated
|
||||||
|
struct String
|
||||||
|
{
|
||||||
|
u8* str;
|
||||||
|
u64 len;
|
||||||
|
u64 cap;
|
||||||
|
};
|
||||||
|
|
||||||
|
internal String string_create(u8* str, u64 len, u64 cap);
|
||||||
|
internal u64 string_copy_to(String* dest, String src);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////
|
||||||
|
// Data Writer
|
||||||
|
|
||||||
|
struct Data_Writer
|
||||||
|
{
|
||||||
|
Data data;
|
||||||
|
u64 at;
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE(PS): functions ending in _b treat data in the Data_Writer as big endian
|
||||||
|
// order (network ordering) where functions ending in _l treat data into little
|
||||||
|
// endian order
|
||||||
|
// It is always assumed that values not in the Data_Writer (ie the other args
|
||||||
|
// to the function or the functions return value) are in little endian order
|
||||||
|
|
||||||
|
internal void
|
||||||
|
dw_put_u8(Data_Writer* w, u8 b)
|
||||||
|
{
|
||||||
|
if (w->at < w->data.size)
|
||||||
|
{
|
||||||
|
w->data.base[w->at++] = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal u8
|
||||||
|
dw_get_u8(Data_Writer* w)
|
||||||
|
{
|
||||||
|
u8 result = 0;
|
||||||
|
if (w->at < w->data.size)
|
||||||
|
{
|
||||||
|
result = w->data.base[w->at++];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
dw_put_u16_b(Data_Writer* w, u16 b)
|
||||||
|
{
|
||||||
|
dw_put_u8(w, get_byte(b, 1));
|
||||||
|
dw_put_u8(w, get_byte(b, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
dw_put_u16_l(Data_Writer* w, u16 b)
|
||||||
|
{
|
||||||
|
dw_put_u8(w, get_byte(b, 0));
|
||||||
|
dw_put_u8(w, get_byte(b, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
dw_put_u32_b(Data_Writer* w, u32 b)
|
||||||
|
{
|
||||||
|
dw_put_u8(w, get_byte(b, 3));
|
||||||
|
dw_put_u8(w, get_byte(b, 2));
|
||||||
|
dw_put_u8(w, get_byte(b, 1));
|
||||||
|
dw_put_u8(w, get_byte(b, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
dw_put_u32_l(Data_Writer* w, u32 b)
|
||||||
|
{
|
||||||
|
dw_put_u8(w, get_byte(b, 0));
|
||||||
|
dw_put_u8(w, get_byte(b, 1));
|
||||||
|
dw_put_u8(w, get_byte(b, 2));
|
||||||
|
dw_put_u8(w, get_byte(b, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
dw_put_u64_b(Data_Writer* w, u64 b)
|
||||||
|
{
|
||||||
|
dw_put_u8(w, get_byte(b, 7));
|
||||||
|
dw_put_u8(w, get_byte(b, 6));
|
||||||
|
dw_put_u8(w, get_byte(b, 5));
|
||||||
|
dw_put_u8(w, get_byte(b, 4));
|
||||||
|
dw_put_u8(w, get_byte(b, 3));
|
||||||
|
dw_put_u8(w, get_byte(b, 2));
|
||||||
|
dw_put_u8(w, get_byte(b, 1));
|
||||||
|
dw_put_u8(w, get_byte(b, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
dw_put_u64_l(Data_Writer* w, u64 b)
|
||||||
|
{
|
||||||
|
dw_put_u8(w, get_byte(b, 0));
|
||||||
|
dw_put_u8(w, get_byte(b, 1));
|
||||||
|
dw_put_u8(w, get_byte(b, 2));
|
||||||
|
dw_put_u8(w, get_byte(b, 3));
|
||||||
|
dw_put_u8(w, get_byte(b, 4));
|
||||||
|
dw_put_u8(w, get_byte(b, 5));
|
||||||
|
dw_put_u8(w, get_byte(b, 6));
|
||||||
|
dw_put_u8(w, get_byte(b, 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
dw_put_str(Data_Writer* w, String str)
|
||||||
|
{
|
||||||
|
for (u64 i = 0; i < str.len; i++)
|
||||||
|
{
|
||||||
|
dw_put_u8(w, str.str[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(PS): get functions
|
||||||
|
|
||||||
#define Bytes(x) (x)
|
#define Bytes(x) (x)
|
||||||
#define KB(x) ((x) << 10)
|
#define KB(x) ((x) << 10)
|
||||||
#define MB(x) ((x) << 20)
|
#define MB(x) ((x) << 20)
|
||||||
#define GB(x) ((x) << 30)
|
#define GB(x) (((u64)x) << 30)
|
||||||
#define TB(x) (((u64)x) << 40)
|
#define TB(x) (((u64)x) << 40)
|
||||||
|
|
||||||
#define has_flag(data, flag) (((data) & (flag)) != 0)
|
#define has_flag(data, flag) (((data) & (flag)) != 0)
|
||||||
|
@ -65,17 +198,66 @@ else { (last)->next = (ele); } \
|
||||||
// TODO(PS): Stack, Queue, DLL ops
|
// TODO(PS): Stack, Queue, DLL ops
|
||||||
|
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
// String
|
// Hash Table
|
||||||
|
//
|
||||||
|
// Rather than define a data structure, to allow the most flexibility,
|
||||||
|
// this is just a set of functions that can be integrated into other
|
||||||
|
// routines.
|
||||||
|
// In general, they expect you to track a u32* of ids and a u32 capacity
|
||||||
|
|
||||||
// NOTE(PS): even though this has a len and cap, it should always be
|
internal void
|
||||||
// null terminated
|
hash_table_init(u32* ids, u32 cap)
|
||||||
struct String
|
|
||||||
{
|
{
|
||||||
u8* str;
|
for (u32 i = 0; i < cap; i++) ids[i] = 0;
|
||||||
u64 len;
|
}
|
||||||
u64 cap;
|
|
||||||
};
|
internal u32
|
||||||
|
hash_table_find_(u32* ids, u32 cap, u32 start_id, u32 target_value)
|
||||||
|
{
|
||||||
|
u32 index = start_id % cap;
|
||||||
|
u32 start = index;
|
||||||
|
do {
|
||||||
|
if (ids[index] == target_value) break;
|
||||||
|
index = (index + 1) % cap;
|
||||||
|
} while (index != start);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal u32
|
||||||
|
hash_table_register(u32* ids, u32 cap, u32 new_id)
|
||||||
|
{
|
||||||
|
u32 index = hash_table_find_(ids, cap, new_id, 0);
|
||||||
|
if (ids[index] != 0) return cap;
|
||||||
|
ids[index] = new_id;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal u32
|
||||||
|
hash_table_find(u32* ids, u32 cap, u32 value)
|
||||||
|
{
|
||||||
|
u32 result = hash_table_find_(ids, cap, value, value);
|
||||||
|
if (ids[result] != value) return cap;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////
|
||||||
|
// Vector Extensions
|
||||||
|
|
||||||
|
#define v2_to_v3(xy,z) v3{(xy).x, (xy).y, (z)}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////
|
||||||
|
// Color Constants
|
||||||
|
|
||||||
|
#define WHITE_V4 v4{1,1,1,1}
|
||||||
|
#define BLACK_V4 v4{0,0,0,1}
|
||||||
|
#define RED_V4 v4{1,0,0,1}
|
||||||
|
#define GREEN_V4 v4{0,1,0,1}
|
||||||
|
#define BLUE_V4 v4{0,0,1,1}
|
||||||
|
#define YELLOW_V4 v4{1,1,0,1}
|
||||||
|
#define TEAL_V4 v4{0,1,1,1}
|
||||||
|
#define PINK_V4 v4{1,0,1,1}
|
||||||
|
|
||||||
typedef struct Allocator Allocator;
|
typedef struct Allocator Allocator;
|
||||||
|
|
||||||
|
|
||||||
#endif //LUMENARIUM_TYPES_H
|
#endif //LUMENARIUM_TYPES_H
|
||||||
|
|
|
@ -34,7 +34,12 @@ WASM_EXTERN void wasm_assert_always(char* file, unsigned int file_len, unsigned
|
||||||
#endif // defined(PLATFORM_WASM)
|
#endif // defined(PLATFORM_WASM)
|
||||||
|
|
||||||
#ifdef USE_ASSERTS
|
#ifdef USE_ASSERTS
|
||||||
# define assert(c) if (!(c)) { err_write("Assert Hit: %s:%d\n", __FILE__, (u32)__LINE__); close_err_file(); assert_always; }
|
# define assert(c) \
|
||||||
|
if (!(c)) { \
|
||||||
|
err_write("Assert Hit: %s:%d\n", __FILE__, (u32)__LINE__); \
|
||||||
|
close_err_file(); \
|
||||||
|
assert_always; \
|
||||||
|
}
|
||||||
|
|
||||||
// useful for catching cases that you aren't sure you'll hit, but
|
// useful for catching cases that you aren't sure you'll hit, but
|
||||||
// want to be alerted when they happen
|
// want to be alerted when they happen
|
||||||
|
|
|
@ -80,6 +80,148 @@ bool platform_file_write_all(Platform_File_Handle file_handle, Data file_data);
|
||||||
String platform_get_exe_path(Allocator* allocator);
|
String platform_get_exe_path(Allocator* allocator);
|
||||||
bool platform_pwd_set(String path);
|
bool platform_pwd_set(String path);
|
||||||
|
|
||||||
|
// For Cross Platform File Operations use these:
|
||||||
|
|
||||||
|
typedef u32 Platform_File_Async_Job_Flags;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PlatformFileAsyncJob_Invalid = 0,
|
||||||
|
PlatformFileAsyncJob_Read = 1,
|
||||||
|
PlatformFileAsyncJob_Write = 2,
|
||||||
|
PlatformFileAsyncJob_InFlight = 4,
|
||||||
|
PlatformFileAsyncJob_Success = 8,
|
||||||
|
PlatformFileAsyncJob_Failed = 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Platform_File_Async_Job_Args
|
||||||
|
{
|
||||||
|
String path;
|
||||||
|
Data data;
|
||||||
|
Platform_File_Async_Job_Flags flags;
|
||||||
|
u32 error;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void Platform_File_Async_Cb(Platform_File_Async_Job_Args args);
|
||||||
|
|
||||||
|
struct Platform_File_Async_Job
|
||||||
|
{
|
||||||
|
Data job_memory;
|
||||||
|
Platform_File_Async_Job_Args args;
|
||||||
|
Platform_File_Async_Cb* cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
global Allocator* platform_file_jobs_arena = 0;
|
||||||
|
#define PLATFORM_FILE_ASYNC_MAX_JOBS 32
|
||||||
|
global Platform_File_Async_Job platform_file_async_jobs[PLATFORM_FILE_ASYNC_MAX_JOBS];
|
||||||
|
global u32 platform_file_async_jobs_len = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_file_jobs_init()
|
||||||
|
{
|
||||||
|
platform_file_jobs_arena = paged_allocator_create_reserve(MB(4), 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
platform_file_async_job_add(Platform_File_Async_Job job)
|
||||||
|
{
|
||||||
|
if (platform_file_async_jobs_len >= PLATFORM_FILE_ASYNC_MAX_JOBS) return false;
|
||||||
|
|
||||||
|
// Copy data to job local memory
|
||||||
|
u64 size_needed = job.args.path.len + job.args.data.size + 1;
|
||||||
|
u8* job_mem = allocator_alloc(platform_file_jobs_arena, size_needed);
|
||||||
|
String job_path = string_create(job_mem, 0, job.args.path.len + 1);
|
||||||
|
u64 copied = string_copy_to(&job_path, job.args.path);
|
||||||
|
Data job_data = data_create(job_mem + job_path.cap + 1, size_needed - (job_path.cap + 1));
|
||||||
|
memory_copy(job.args.data.base, job_data.base, job.args.data.size);
|
||||||
|
job.args.path = job_path;
|
||||||
|
job.args.data = job_data;
|
||||||
|
job.job_memory = data_create(job_mem, size_needed);
|
||||||
|
|
||||||
|
platform_file_async_jobs[platform_file_async_jobs_len++] = job;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform_File_Async_Job
|
||||||
|
platform_file_async_job_rem(u64 index)
|
||||||
|
{
|
||||||
|
assert(index < platform_file_async_jobs_len);
|
||||||
|
Platform_File_Async_Job result = platform_file_async_jobs[index];
|
||||||
|
|
||||||
|
platform_file_async_jobs_len -= 1;
|
||||||
|
if (platform_file_async_jobs_len > 0)
|
||||||
|
{
|
||||||
|
u32 last_job = platform_file_async_jobs_len;
|
||||||
|
platform_file_async_jobs[index] = platform_file_async_jobs[last_job];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
platform_file_async_read(String path, Platform_File_Async_Cb* cb)
|
||||||
|
{
|
||||||
|
Platform_File_Async_Job job = {};
|
||||||
|
job.args.path = path;
|
||||||
|
job.args.flags = (
|
||||||
|
PlatformFileAsyncJob_Read |
|
||||||
|
PlatformFileAsyncJob_InFlight
|
||||||
|
);
|
||||||
|
job.cb = cb;
|
||||||
|
bool result = platform_file_async_job_add(job);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
platform_file_async_write(String path, Data data, Platform_File_Async_Cb* cb)
|
||||||
|
{
|
||||||
|
Platform_File_Async_Job job = {};
|
||||||
|
job.args.path = path;
|
||||||
|
job.args.data = data;
|
||||||
|
job.args.flags = (
|
||||||
|
PlatformFileAsyncJob_Write |
|
||||||
|
PlatformFileAsyncJob_InFlight
|
||||||
|
);
|
||||||
|
job.cb = cb;
|
||||||
|
bool result = platform_file_async_job_add(job);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_file_async_job_complete(Platform_File_Async_Job* job)
|
||||||
|
{
|
||||||
|
job->cb(job->args);
|
||||||
|
allocator_free(platform_file_jobs_arena, job->job_memory.base, job->job_memory.size);
|
||||||
|
if (has_flag(job->args.flags, PlatformFileAsyncJob_Write))
|
||||||
|
{
|
||||||
|
allocator_free(platform_file_jobs_arena, job->args.data.base, job->args.data.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void platform_file_async_work_on_job(Platform_File_Async_Job* job);
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_file_async_jobs_do_work(u64 max_jobs)
|
||||||
|
{
|
||||||
|
u64 to_do = max_jobs;
|
||||||
|
if (max_jobs > platform_file_async_jobs_len) to_do = platform_file_async_jobs_len;
|
||||||
|
|
||||||
|
Platform_File_Async_Job_Flags completed = (
|
||||||
|
PlatformFileAsyncJob_Success |
|
||||||
|
PlatformFileAsyncJob_Failed
|
||||||
|
);
|
||||||
|
|
||||||
|
for (u64 i = to_do - 1; i < to_do; i--)
|
||||||
|
{
|
||||||
|
Platform_File_Async_Job* job = platform_file_async_jobs + i;
|
||||||
|
platform_file_async_work_on_job(job);
|
||||||
|
if (has_flag(job->args.flags, completed))
|
||||||
|
{
|
||||||
|
platform_file_async_job_complete(job);
|
||||||
|
platform_file_async_job_rem(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
typedef u32 Platform_Enum_Dir_Flags;
|
typedef u32 Platform_Enum_Dir_Flags;
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -100,6 +242,7 @@ enum Platform_Window_Event_Kind
|
||||||
WindowEvent_Invalid = 0,
|
WindowEvent_Invalid = 0,
|
||||||
|
|
||||||
WindowEvent_MouseScroll,
|
WindowEvent_MouseScroll,
|
||||||
|
WindowEvent_MouseMoved,
|
||||||
WindowEvent_ButtonDown,
|
WindowEvent_ButtonDown,
|
||||||
WindowEvent_ButtonUp,
|
WindowEvent_ButtonUp,
|
||||||
WindowEvent_Char,
|
WindowEvent_Char,
|
||||||
|
@ -299,6 +442,7 @@ struct Platform_Shader
|
||||||
{
|
{
|
||||||
u32 id;
|
u32 id;
|
||||||
u32 attrs[PLATFORM_SHADER_MAX_ATTRS];
|
u32 attrs[PLATFORM_SHADER_MAX_ATTRS];
|
||||||
|
u32 uniforms[PLATFORM_SHADER_MAX_ATTRS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Platform_Geometry_Buffer
|
struct Platform_Geometry_Buffer
|
||||||
|
@ -306,6 +450,7 @@ struct Platform_Geometry_Buffer
|
||||||
u32 buffer_id_vao;
|
u32 buffer_id_vao;
|
||||||
u32 buffer_id_vertices;
|
u32 buffer_id_vertices;
|
||||||
u32 buffer_id_indices;
|
u32 buffer_id_indices;
|
||||||
|
u32 vertices_len;
|
||||||
u32 indices_len;
|
u32 indices_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -329,16 +474,19 @@ void platform_frame_clear();
|
||||||
// Geometry
|
// Geometry
|
||||||
Platform_Geometry_Buffer platform_geometry_buffer_create(r32* vertices, u32 vertices_len, u32* indices, u32 indices_len);
|
Platform_Geometry_Buffer platform_geometry_buffer_create(r32* vertices, u32 vertices_len, u32* indices, u32 indices_len);
|
||||||
Platform_Shader platform_shader_create(
|
Platform_Shader platform_shader_create(
|
||||||
String code_vert, String code_frag, String* attribs, u32 attribs_len
|
String code_vert, String code_frag, String* attribs, u32 attribs_len, String* uniforms, u32 uniforms_len
|
||||||
);
|
);
|
||||||
|
void platform_geometry_buffer_update(Platform_Geometry_Buffer* buffer, r32* verts, u32 verts_offset, u32 verts_len, u32* indices, u32 indices_offset, u32 indices_len);
|
||||||
|
|
||||||
// Shaders
|
// Shaders
|
||||||
void platform_geometry_bind(Platform_Geometry_Buffer geo);
|
void platform_geometry_bind(Platform_Geometry_Buffer geo);
|
||||||
void platform_shader_bind(Platform_Shader shader);
|
void platform_shader_bind(Platform_Shader shader);
|
||||||
|
void platform_geometry_draw(Platform_Geometry_Buffer geo, u32 indices);
|
||||||
void platform_geometry_draw(Platform_Geometry_Buffer geo);
|
void platform_geometry_draw(Platform_Geometry_Buffer geo);
|
||||||
void platform_vertex_attrib_pointer(
|
void platform_vertex_attrib_pointer(
|
||||||
Platform_Geometry_Buffer geo, Platform_Shader shader, u32 count, u32 attr_index, u32 stride, u32 offset
|
Platform_Geometry_Buffer geo, Platform_Shader shader, u32 count, u32 attr_index, u32 stride, u32 offset
|
||||||
);
|
);
|
||||||
|
void platform_set_uniform(Platform_Shader shader, u32 index, m44 u);
|
||||||
|
|
||||||
// Textures
|
// Textures
|
||||||
Platform_Texture platform_texture_create(u8* pixels, u32 width, u32 height, u32 stride);
|
Platform_Texture platform_texture_create(u8* pixels, u32 width, u32 height, u32 stride);
|
||||||
|
|
|
@ -20,8 +20,9 @@ typedef unsigned int GLsizei;
|
||||||
// I resorted to hard coding these rather than passing them in because
|
// I resorted to hard coding these rather than passing them in because
|
||||||
// passing them in didn't seem to be working.
|
// passing them in didn't seem to be working.
|
||||||
|
|
||||||
|
#define GL_FALSE 0
|
||||||
|
#define GL_TRUE 1
|
||||||
#define GL_TEXTURE_2D 0x0DE1
|
#define GL_TEXTURE_2D 0x0DE1
|
||||||
|
|
||||||
#define GL_DEPTH_BUFFER_BIT 0x00000100
|
#define GL_DEPTH_BUFFER_BIT 0x00000100
|
||||||
#define GL_STENCIL_BUFFER_BIT 0x00000400
|
#define GL_STENCIL_BUFFER_BIT 0x00000400
|
||||||
#define GL_COLOR_BUFFER_BIT 0x00004000
|
#define GL_COLOR_BUFFER_BIT 0x00004000
|
||||||
|
@ -68,6 +69,7 @@ WASM_EXTERN void glAttachShader(GLuint program, GLuint shader);
|
||||||
WASM_EXTERN void glLinkProgram(GLuint program);
|
WASM_EXTERN void glLinkProgram(GLuint program);
|
||||||
WASM_EXTERN void glUseProgram(GLuint program);
|
WASM_EXTERN void glUseProgram(GLuint program);
|
||||||
WASM_EXTERN GLuint glGetAttribLocation(GLuint program, const char* name, GLuint name_len);
|
WASM_EXTERN GLuint glGetAttribLocation(GLuint program, const char* name, GLuint name_len);
|
||||||
|
WASM_EXTERN GLuint glGetUniformLocation(GLuint program, const char* name, u32 len);
|
||||||
WASM_EXTERN void glVertexAttribPointer(GLuint attr, GLuint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
|
WASM_EXTERN void glVertexAttribPointer(GLuint attr, GLuint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
|
||||||
WASM_EXTERN void glEnableVertexAttribArray(GLuint index);
|
WASM_EXTERN void glEnableVertexAttribArray(GLuint index);
|
||||||
WASM_EXTERN void glDrawElements(GLenum type, GLuint count, GLenum ele_type, void* indices);
|
WASM_EXTERN void glDrawElements(GLenum type, GLuint count, GLenum ele_type, void* indices);
|
||||||
|
@ -109,7 +111,7 @@ platform_geometry_buffer_create(
|
||||||
|
|
||||||
Platform_Shader
|
Platform_Shader
|
||||||
platform_shader_create(
|
platform_shader_create(
|
||||||
String code_vert, String code_frag, String* attrs, GLuint attrs_len
|
String code_vert, String code_frag, String* attrs, GLuint attrs_len, String* uniforms, GLuint uniforms_len
|
||||||
){
|
){
|
||||||
Platform_Shader result = {};
|
Platform_Shader result = {};
|
||||||
|
|
||||||
|
@ -139,6 +141,16 @@ platform_shader_create(
|
||||||
}
|
}
|
||||||
result.attrs[attrs_len] = PLATFORM_SHADER_ATTR_LAST;
|
result.attrs[attrs_len] = PLATFORM_SHADER_ATTR_LAST;
|
||||||
|
|
||||||
|
assert(uniforms_len < PLATFORM_SHADER_MAX_ATTRS);
|
||||||
|
for (GLuint i = 0; i < uniforms_len; i++)
|
||||||
|
{
|
||||||
|
s32 len = (s32)uniforms[i].len;
|
||||||
|
result.uniforms[i] = glGetUniformLocation(
|
||||||
|
result.id, (char*)uniforms[i].str, uniforms[i].len
|
||||||
|
);
|
||||||
|
}
|
||||||
|
result.uniforms[uniforms_len] = PLATFORM_SHADER_ATTR_LAST;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +171,19 @@ platform_shader_bind(Platform_Shader shader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_set_uniform(Platform_Shader shader, u32 index, m44 u)
|
||||||
|
{
|
||||||
|
glUniformMatrix4fv(shader.uniforms[index], 1, GL_FALSE, &u.Elements[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_geometry_draw(
|
||||||
|
Platform_Geometry_Buffer geo, u32 indices
|
||||||
|
){
|
||||||
|
glDrawElements(GL_TRIANGLES, indices, GL_UNSIGNED_INT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
platform_geometry_draw(
|
platform_geometry_draw(
|
||||||
Platform_Geometry_Buffer geo
|
Platform_Geometry_Buffer geo
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "../../lumenarium_types.h"
|
#include "../../lumenarium_types.h"
|
||||||
|
#include "../../lumenarium_memory.h"
|
||||||
#include "../lumenarium_platform.h"
|
#include "../lumenarium_platform.h"
|
||||||
#include "../../lumenarium_first.cpp"
|
#include "../../lumenarium_first.cpp"
|
||||||
|
|
||||||
|
@ -215,6 +216,20 @@ WinMain(
|
||||||
lumenarium_event(evt, state);
|
lumenarium_event(evt, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the position of the mouse every frame
|
||||||
|
{
|
||||||
|
POINT mouse_p;
|
||||||
|
GetCursorPos(&mouse_p);
|
||||||
|
ScreenToClient(win32_main_window.window_handle, &mouse_p);
|
||||||
|
|
||||||
|
Platform_Window_Event evt = {};
|
||||||
|
evt.kind = WindowEvent_MouseMoved;
|
||||||
|
evt.mouse_x = mouse_p.x;
|
||||||
|
evt.mouse_y = mouse_p.y;
|
||||||
|
|
||||||
|
lumenarium_event(evt, state);
|
||||||
|
}
|
||||||
|
|
||||||
// Pass Window Events to the runtime
|
// Pass Window Events to the runtime
|
||||||
MSG window_msg;
|
MSG window_msg;
|
||||||
while (PeekMessageA(
|
while (PeekMessageA(
|
||||||
|
|
|
@ -256,3 +256,36 @@ platform_pwd_set(String path)
|
||||||
if (!result) win32_get_last_error();
|
if (!result) win32_get_last_error();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_file_async_work_on_job(Platform_File_Async_Job* job)
|
||||||
|
{
|
||||||
|
Platform_File_Handle file = {};
|
||||||
|
if (has_flag(job->args.flags, PlatformFileAsyncJob_Read))
|
||||||
|
{
|
||||||
|
file = platform_file_open(job->args.path, FileAccess_Read, FileCreate_OpenExisting);
|
||||||
|
Data result = platform_file_read_all(file, platform_file_jobs_arena);
|
||||||
|
if (result.base != 0)
|
||||||
|
{
|
||||||
|
job->args.data = result;
|
||||||
|
add_flag(job->args.flags, PlatformFileAsyncJob_Success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
add_flag(job->args.flags, PlatformFileAsyncJob_Failed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (has_flag(job->args.flags, PlatformFileAsyncJob_Write))
|
||||||
|
{
|
||||||
|
file = platform_file_open(job->args.path, FileAccess_Write, FileCreate_OpenAlways);
|
||||||
|
if (platform_file_write_all(file, job->args.data))
|
||||||
|
{
|
||||||
|
add_flag(job->args.flags, PlatformFileAsyncJob_Success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
add_flag(job->args.flags, PlatformFileAsyncJob_Failed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
platform_file_close(file);
|
||||||
|
}
|
|
@ -39,6 +39,7 @@ platform_geometry_buffer_create(
|
||||||
GL_ARRAY_BUFFER, sizeof(r32) * vertices_len, vertices, GL_STATIC_DRAW
|
GL_ARRAY_BUFFER, sizeof(r32) * vertices_len, vertices, GL_STATIC_DRAW
|
||||||
);
|
);
|
||||||
win32_gl_no_error();
|
win32_gl_no_error();
|
||||||
|
result.vertices_len = vertices_len;
|
||||||
|
|
||||||
// Indices
|
// Indices
|
||||||
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, result.buffer_id_indices);
|
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, result.buffer_id_indices);
|
||||||
|
@ -56,9 +57,61 @@ platform_geometry_buffer_create(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void platform_geometry_buffer_update(
|
||||||
|
Platform_Geometry_Buffer* buffer,
|
||||||
|
r32* verts,
|
||||||
|
u32 verts_offset,
|
||||||
|
u32 verts_len,
|
||||||
|
u32* indices,
|
||||||
|
u32 indices_offset,
|
||||||
|
u32 indices_len
|
||||||
|
){
|
||||||
|
gl.glBindVertexArray(buffer->buffer_id_vao);
|
||||||
|
gl.glBindBuffer(GL_ARRAY_BUFFER, buffer->buffer_id_vertices);
|
||||||
|
win32_gl_no_error();
|
||||||
|
|
||||||
|
if (verts_len > buffer->vertices_len)
|
||||||
|
{
|
||||||
|
// NOTE(PS): this is because we're going to delete the old buffer and
|
||||||
|
// create a new one. In order to do that and not lose data, the update
|
||||||
|
// function needs to have been passed all the buffer's data
|
||||||
|
assert(verts_offset == 0);
|
||||||
|
gl.glBufferData(
|
||||||
|
GL_ARRAY_BUFFER, verts_len * sizeof(r32), (void*)verts, GL_STATIC_DRAW
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gl.glBufferSubData(
|
||||||
|
GL_ARRAY_BUFFER, verts_offset * sizeof(r32), verts_len * sizeof(r32), (void*)verts
|
||||||
|
);
|
||||||
|
}
|
||||||
|
win32_gl_no_error();
|
||||||
|
|
||||||
|
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->buffer_id_indices);
|
||||||
|
win32_gl_no_error();
|
||||||
|
if (indices_len > buffer->indices_len)
|
||||||
|
{
|
||||||
|
// NOTE(PS): this is because we're going to delete the old buffer and
|
||||||
|
// create a new one. In order to do that and not lose data, the update
|
||||||
|
// function needs to have been passed all the buffer's data
|
||||||
|
assert(indices_offset == 0);
|
||||||
|
gl.glBufferData(
|
||||||
|
GL_ELEMENT_ARRAY_BUFFER, indices_len * sizeof(u32), (void*)indices, GL_STATIC_DRAW
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gl.glBufferSubData(
|
||||||
|
GL_ELEMENT_ARRAY_BUFFER, indices_offset * sizeof(u32), indices_len * sizeof(u32), (void*)indices
|
||||||
|
);
|
||||||
|
}
|
||||||
|
win32_gl_no_error();
|
||||||
|
}
|
||||||
|
|
||||||
Platform_Shader
|
Platform_Shader
|
||||||
platform_shader_create(
|
platform_shader_create(
|
||||||
String code_vert, String code_frag, String* attrs, u32 attrs_len
|
String code_vert, String code_frag, String* attrs, u32 attrs_len, String* uniforms, u32 uniforms_len
|
||||||
){
|
){
|
||||||
Platform_Shader result = {};
|
Platform_Shader result = {};
|
||||||
|
|
||||||
|
@ -117,12 +170,29 @@ platform_shader_create(
|
||||||
result.attrs[i] = gl.glGetAttribLocation(
|
result.attrs[i] = gl.glGetAttribLocation(
|
||||||
result.id, (char*)attrs[i].str
|
result.id, (char*)attrs[i].str
|
||||||
);
|
);
|
||||||
|
win32_gl_no_error();
|
||||||
}
|
}
|
||||||
result.attrs[attrs_len] = PLATFORM_SHADER_ATTR_LAST;
|
result.attrs[attrs_len] = PLATFORM_SHADER_ATTR_LAST;
|
||||||
|
|
||||||
|
assert(uniforms_len < PLATFORM_SHADER_MAX_ATTRS);
|
||||||
|
for (GLuint i = 0; i < uniforms_len; i++)
|
||||||
|
{
|
||||||
|
s32 len = (s32)uniforms[i].len;
|
||||||
|
result.uniforms[i] = gl.glGetUniformLocation(
|
||||||
|
result.id, (char*)uniforms[i].str
|
||||||
|
);
|
||||||
|
}
|
||||||
|
result.uniforms[uniforms_len] = PLATFORM_SHADER_ATTR_LAST;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_set_uniform(Platform_Shader shader, u32 index, m44 u)
|
||||||
|
{
|
||||||
|
gl.glUniformMatrix4fv(shader.uniforms[index], 1, GL_FALSE, (r32*)u.Elements);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
platform_geometry_bind(Platform_Geometry_Buffer geo)
|
platform_geometry_bind(Platform_Geometry_Buffer geo)
|
||||||
{
|
{
|
||||||
|
@ -150,12 +220,19 @@ platform_shader_bind(Platform_Shader shader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
platform_geometry_draw(
|
||||||
|
Platform_Geometry_Buffer geo, u32 indices
|
||||||
|
){
|
||||||
|
glDrawElements(GL_TRIANGLES, indices, GL_UNSIGNED_INT, 0);
|
||||||
|
win32_gl_no_error();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
platform_geometry_draw(
|
platform_geometry_draw(
|
||||||
Platform_Geometry_Buffer geo
|
Platform_Geometry_Buffer geo
|
||||||
){
|
){
|
||||||
glDrawElements(GL_TRIANGLES, geo.indices_len, GL_UNSIGNED_INT, 0);
|
platform_geometry_draw(geo, geo.indices_len);
|
||||||
win32_gl_no_error();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void platform_vertex_attrib_pointer(
|
void platform_vertex_attrib_pointer(
|
||||||
|
|
|
@ -5,7 +5,7 @@ u64 platform_page_size() { return WIN32_PAGE_SIZE; }
|
||||||
u8*
|
u8*
|
||||||
platform_mem_reserve(u64 size)
|
platform_mem_reserve(u64 size)
|
||||||
{
|
{
|
||||||
size_t size_cvt = (size_t)size_to_pages(size);
|
size_t size_cvt = (size_t)round_size_to_page_multiple(size);
|
||||||
DWORD alloc_type = MEM_RESERVE;
|
DWORD alloc_type = MEM_RESERVE;
|
||||||
DWORD protection = PAGE_READWRITE;
|
DWORD protection = PAGE_READWRITE;
|
||||||
u8* result = (u8*)VirtualAlloc(0, size_cvt, alloc_type, protection);
|
u8* result = (u8*)VirtualAlloc(0, size_cvt, alloc_type, protection);
|
||||||
|
@ -16,7 +16,7 @@ platform_mem_reserve(u64 size)
|
||||||
u8*
|
u8*
|
||||||
platform_mem_commit(u8* base, u64 size)
|
platform_mem_commit(u8* base, u64 size)
|
||||||
{
|
{
|
||||||
size_t size_cvt = (size_t)size_to_pages(size);
|
size_t size_cvt = (size_t)round_size_to_page_multiple(size);
|
||||||
DWORD alloc_type = MEM_COMMIT;
|
DWORD alloc_type = MEM_COMMIT;
|
||||||
DWORD protection = PAGE_READWRITE;
|
DWORD protection = PAGE_READWRITE;
|
||||||
u8* result = (u8*)VirtualAlloc(base, size_cvt, alloc_type, protection);
|
u8* result = (u8*)VirtualAlloc(base, size_cvt, alloc_type, protection);
|
||||||
|
@ -37,7 +37,9 @@ bool
|
||||||
platform_mem_release(u8* base, u64 size)
|
platform_mem_release(u8* base, u64 size)
|
||||||
{
|
{
|
||||||
DWORD free_type = MEM_RELEASE;
|
DWORD free_type = MEM_RELEASE;
|
||||||
bool result = VirtualFree(base, size, free_type);
|
// according to the docs, if we're releasing memory, the size must be
|
||||||
|
// zero as its implied VirtualFree will free the entire region
|
||||||
|
bool result = VirtualFree(base, 0, free_type);
|
||||||
if (!result) win32_get_last_error();
|
if (!result) win32_get_last_error();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ typedef void proc_glBindVertexArray(GLuint array);
|
||||||
typedef void proc_glGenBuffers (GLsizei n, GLuint *buffers);
|
typedef void proc_glGenBuffers (GLsizei n, GLuint *buffers);
|
||||||
typedef void proc_glBindBuffer(GLenum target, GLuint buffer);
|
typedef void proc_glBindBuffer(GLenum target, GLuint buffer);
|
||||||
typedef void proc_glBufferData(GLenum target, size_t size, const void *data, GLenum usage);
|
typedef void proc_glBufferData(GLenum target, size_t size, const void *data, GLenum usage);
|
||||||
|
typedef void proc_glBufferSubData(GLenum target, size_t offset, size_t size, const void* data);
|
||||||
typedef GLuint proc_glCreateShader(GLenum type);
|
typedef GLuint proc_glCreateShader(GLenum type);
|
||||||
typedef void proc_glShaderSource(GLuint shader, u32 count, const char* const* string, const GLint *length);
|
typedef void proc_glShaderSource(GLuint shader, u32 count, const char* const* string, const GLint *length);
|
||||||
typedef void proc_glCompileShader(GLuint shader);
|
typedef void proc_glCompileShader(GLuint shader);
|
||||||
|
@ -31,7 +32,8 @@ typedef void proc_glGetShaderiv(GLuint shader, GLenum ele, GLint* value_out);
|
||||||
typedef void proc_glGetShaderInfoLog(GLuint shader, GLuint buf_len, GLsizei* len_out, GLchar* buf);
|
typedef void proc_glGetShaderInfoLog(GLuint shader, GLuint buf_len, GLsizei* len_out, GLchar* buf);
|
||||||
typedef void proc_glGetProgramiv(GLuint program, GLenum ele, GLint* value_out);
|
typedef void proc_glGetProgramiv(GLuint program, GLenum ele, GLint* value_out);
|
||||||
typedef void proc_glGetProgramInfoLog(GLuint program, GLuint cap, GLsizei* len_out, GLchar* buf);
|
typedef void proc_glGetProgramInfoLog(GLuint program, GLuint cap, GLsizei* len_out, GLchar* buf);
|
||||||
|
typedef GLuint proc_glGetUniformLocation(GLuint program, const char* name);
|
||||||
|
typedef void proc_glUniformMatrix4fv(GLuint uniform, GLuint count, GLenum normalize, GLfloat* elements);
|
||||||
struct Win32_OpenGL_Extensions
|
struct Win32_OpenGL_Extensions
|
||||||
{
|
{
|
||||||
proc_wglGetExtensionsStringARB* wglGetExtensionsStringARB;
|
proc_wglGetExtensionsStringARB* wglGetExtensionsStringARB;
|
||||||
|
@ -43,6 +45,7 @@ struct Win32_OpenGL_Extensions
|
||||||
proc_glGenBuffers* glGenBuffers;
|
proc_glGenBuffers* glGenBuffers;
|
||||||
proc_glBindBuffer* glBindBuffer;
|
proc_glBindBuffer* glBindBuffer;
|
||||||
proc_glBufferData* glBufferData;
|
proc_glBufferData* glBufferData;
|
||||||
|
proc_glBufferSubData* glBufferSubData;
|
||||||
proc_glCreateShader* glCreateShader;
|
proc_glCreateShader* glCreateShader;
|
||||||
proc_glShaderSource* glShaderSource;
|
proc_glShaderSource* glShaderSource;
|
||||||
proc_glCompileShader* glCompileShader;
|
proc_glCompileShader* glCompileShader;
|
||||||
|
@ -57,6 +60,8 @@ struct Win32_OpenGL_Extensions
|
||||||
proc_glGetShaderInfoLog* glGetShaderInfoLog;
|
proc_glGetShaderInfoLog* glGetShaderInfoLog;
|
||||||
proc_glGetProgramiv* glGetProgramiv;
|
proc_glGetProgramiv* glGetProgramiv;
|
||||||
proc_glGetProgramInfoLog* glGetProgramInfoLog;
|
proc_glGetProgramInfoLog* glGetProgramInfoLog;
|
||||||
|
proc_glGetUniformLocation* glGetUniformLocation;
|
||||||
|
proc_glUniformMatrix4fv* glUniformMatrix4fv;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
|
|
|
@ -381,6 +381,7 @@ win32_window_opengl_get_wgl_ext(HINSTANCE hinstance)
|
||||||
wgl_load_ext(result, glGenBuffers);
|
wgl_load_ext(result, glGenBuffers);
|
||||||
wgl_load_ext(result, glBindBuffer);
|
wgl_load_ext(result, glBindBuffer);
|
||||||
wgl_load_ext(result, glBufferData);
|
wgl_load_ext(result, glBufferData);
|
||||||
|
wgl_load_ext(result, glBufferSubData);
|
||||||
wgl_load_ext(result, glCreateShader);
|
wgl_load_ext(result, glCreateShader);
|
||||||
wgl_load_ext(result, glShaderSource);
|
wgl_load_ext(result, glShaderSource);
|
||||||
wgl_load_ext(result, glCompileShader);
|
wgl_load_ext(result, glCompileShader);
|
||||||
|
@ -395,6 +396,8 @@ win32_window_opengl_get_wgl_ext(HINSTANCE hinstance)
|
||||||
wgl_load_ext(result, glGetShaderInfoLog);
|
wgl_load_ext(result, glGetShaderInfoLog);
|
||||||
wgl_load_ext(result, glGetProgramiv);
|
wgl_load_ext(result, glGetProgramiv);
|
||||||
wgl_load_ext(result, glGetProgramInfoLog);
|
wgl_load_ext(result, glGetProgramInfoLog);
|
||||||
|
wgl_load_ext(result, glGetUniformLocation);
|
||||||
|
wgl_load_ext(result, glUniformMatrix4fv);
|
||||||
}
|
}
|
||||||
|
|
||||||
wglMakeCurrent(NULL, NULL);
|
wglMakeCurrent(NULL, NULL);
|
||||||
|
|
|
@ -10,8 +10,6 @@ incenter_get_init_desc()
|
||||||
internal void
|
internal void
|
||||||
incenter_init(App_State* state)
|
incenter_init(App_State* state)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
|
|
||||||
// create a fake sculpture
|
// create a fake sculpture
|
||||||
Assembly_Handle ah = assembly_add(&state->assemblies, lit_str("test"), 3000, 100);
|
Assembly_Handle ah = assembly_add(&state->assemblies, lit_str("test"), 3000, 100);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue