Paged memory allocator, and async file system

This commit is contained in:
PS 2022-04-06 20:29:32 +02:00
parent 6775ea26d3
commit 6e80c811cf
42 changed files with 2334 additions and 139 deletions

View File

@ -7,14 +7,20 @@
## TODO
1. Upgrade Lumenarium's plubming
1. switch over to compiling with clang & bash based build scripts
2. better platform layer separation
1. Upgrade Lumenarium's plumbing
x. switch over to compiling with clang & bash based build scripts
x. better platform layer separation
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
1. default to using a basic layout object
2. improve widget handling (see a_trick_of_fate)
[ ] get widgets and widget ids working
- 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
1. Sculpture generation from list of lat-long coordinates

View File

@ -144,7 +144,7 @@ CompilerFlags_DEBUG_win32=""
add_flag CompilerFlags_DEBUG_win32 "-Od" #
add_flag CompilerFlags_DEBUG_win32 "-Zi" #
add_flag CompilerFlags_DEBUG_win32 "-DDEBUG" #
add_flag CompilerFlags_DEBUG_win32 "-DPRINT_ASSERTS"
# add_flag CompilerFlags_DEBUG_win32 "-DPRINT_ASSERTS"
CompilerFlags_DEBUG="-O0"
add_flag CompilerFlags_DEBUG "-g" #

BIN
run_tree/data/font.ttf Normal file

Binary file not shown.

Binary file not shown.

View File

@ -81,7 +81,7 @@ void make_quad(Platform_Geometry_Buffer* geo, Platform_Shader* shd, Platform_Tex
lit_str("uv"),
};
*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);
@ -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);
}
internal void
ed_load_font_cb(Platform_File_Async_Job_Args result)
{
s32 x = 5;
}
internal void
ed_init(App_State* state)
{
Editor* editor = allocator_alloc_struct(permanent, 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);
platform_file_async_read(lit_str("data/font.ttf"), ed_load_font_cb);
}
internal void
ed_frame_prepare(App_State* state)
{
ui_frame_prepare(&state->editor->ui, state->editor->window_dim);
}
internal void
ed_frame(App_State* state)
{
for (u32 i = 0; i < 16; i++)
{
if (i % 2 == 1) continue;
pix[i] += 1;
}
platform_texture_update(state->editor->renderer.tex, (u8*)pix, 4, 4, 4);
edr_render_begin(state);
ui_draw(&state->editor->ui);
edr_render(state);
}

View File

@ -7,6 +7,7 @@ struct Editor
{
v2 window_dim;
Editor_Renderer renderer;
UI ui;
};
#endif //LUMENARIUM_EDITOR_H

View File

@ -1,7 +1,6 @@
internal void
edr_render(App_State* state)
edr_render_begin(App_State* state)
{
Platform_Graphics_Frame_Desc desc = {};
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;
platform_frame_begin(desc);
platform_frame_clear();
}
internal void
edr_render(App_State* state)
{
#if 0
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_geometry_draw(state->editor->renderer.geo);
#endif
}

View File

@ -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;
}

View File

@ -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

View File

@ -1 +0,0 @@
//

View File

@ -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

View File

@ -3,6 +3,10 @@ internal void
en_init(App_State* state, App_Init_Desc desc)
{
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
@ -15,6 +19,52 @@ internal void
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

View File

@ -42,6 +42,9 @@ struct Assembly_Strip
u32 pixels_len;
// array of indices into the Assembly_Pixel_Buffer for the same assembly
u32* pixels;
Output_Data_Kind output_kind;
u32 sacn_universe;
};
struct Assembly_Strip_Array

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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)
{
}

View File

@ -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

View File

@ -462,6 +462,12 @@ extern "C"
float Ignored0_;
float Ignored1_;
};
struct
{
hmm_vec2 xy;
float Ignored0b_;
float Ignored1b_;
};
struct
{
@ -469,6 +475,12 @@ extern "C"
hmm_vec2 YZ;
float Ignored3_;
};
struct
{
float Ignored2b_;
hmm_vec2 yz;
float Ignored3b_;
};
struct
{
@ -477,6 +489,13 @@ extern "C"
hmm_vec2 ZW;
};
struct
{
float Ignored4b_;
float Ignored5b_;
hmm_vec2 zw;
};
float Elements[4];
} hmm_vec4;

View File

@ -6,8 +6,9 @@ lumenarium_init()
{
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));
platform_file_jobs_init();
run_tests();
@ -18,7 +19,7 @@ lumenarium_init()
add_flag(state->flags, AppState_IsRunning);
add_flag(state->flags, AppState_RunEditor);
state->input_state = input_state_create();
state->input_state = input_state_create(permanent);
en_init(state, desc);
if (has_flag(state->flags, AppState_RunEditor))
@ -34,7 +35,7 @@ lumenarium_frame_prepare(App_State* state)
{
allocator_clear(scratch);
input_state_swap_frames(&state->input_state);
input_state_swap_frames(state->input_state);
en_frame_prepare(state);
if (has_flag(state->flags, AppState_RunEditor))
@ -42,12 +43,14 @@ lumenarium_frame_prepare(App_State* state)
ed_frame_prepare(state);
}
incenter_frame_prepare(state);
platform_file_async_jobs_do_work(4);
}
internal void
lumenarium_frame(App_State* state)
{
en_frame(state);
//en_frame(state);
if (has_flag(state->flags, AppState_RunEditor))
{
ed_frame(state);
@ -58,7 +61,7 @@ lumenarium_frame(App_State* state)
internal void
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)
{
case WindowEvent_MouseScroll:
@ -66,6 +69,13 @@ lumenarium_event(Platform_Window_Event evt, App_State* state)
frame->mouse_scroll = evt.scroll_amt;
} 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_ButtonUp:
{

View File

@ -9,11 +9,18 @@ typedef struct App_State App_State;
#include "lumenarium_memory.cpp"
#include "lumenarium_string.cpp"
#include "lumenarium_input.cpp"
#include "lumenarium_texture_atlas.cpp"
#include "lumenarium_hash.cpp"
// Engine
typedef struct Assembly_Strip Assembly_Strip;
#include "engine/lumenarium_engine_output.h"
#include "engine/lumenarium_engine_assembly.h"
#include "engine/output/lumenarium_output_uart.h"
#include "engine/output/lumenarium_output_sacn.h"
// Editor
#include "editor/lumenarium_editor_ui.h"
#include "editor/lumenarium_editor_renderer.h"
#include "editor/lumenarium_editor.h"
@ -49,15 +56,21 @@ struct App_State
{
App_State_Flags flags;
Input_State input_state;
Input_State* input_state;
Assembly_Array assemblies;
Output output;
Editor* editor;
};
#include "engine/lumenarium_engine_assembly.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.cpp"

View File

@ -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

View File

@ -24,15 +24,30 @@ struct Input_State
#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_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_was_up(key_flags) (!has_flag((key_flags), KeyFlag_State_WasDown))
#define key_is_up(key_flags) (!has_flag((key_flags), KeyFlag_State_IsDown))
internal Input_State
input_state_create()
internal Input_State*
input_state_create(Allocator* a)
{
Input_State result = {};
result.frame_hot = result.frames + 0;
result.frame_cold = result.frames + 1;
Input_State* result = allocator_alloc_struct(a, Input_State);
result->frame_hot = result->frames + 0;
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;
}
@ -46,7 +61,10 @@ input_state_swap_frames(Input_State* input_state)
// Clear the new hot input frame
Platform_Key_Flags* hot_key_flags = input_state->frame_hot->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;
}

View File

@ -32,21 +32,25 @@ memory_copy_simd(u8* from, u8* to, u64 size)
memory_copy_no_simd(from, to, size);
}
# define memory_zero(b,s) memory_zero_simd((b),(s))
# define memory_copy(f,t,s) memory_copy_simd((f),(t),(s))
# define memory_zero_(b,s) memory_zero_simd((b),(s))
# define memory_copy_(f,t,s) memory_copy_simd((f),(t),(s))
#else
# 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_zero_(b,s) memory_zero_no_simd((b),(s))
# define memory_copy_(f,t,s) memory_copy_no_simd((f),(t),(s))
#endif // defined(PLATFORM_HAS_SIMD)
#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
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;
if (rem != 0 || size < page_size)
{
@ -56,6 +60,13 @@ size_to_pages(u64 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
//
@ -64,37 +75,14 @@ size_to_pages(u64 size)
// To implement a complete allocator, all that is really required
// is to create its Allocator_Alloc function
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);
struct Allocator
internal void
allocator_destroy_(Allocator* allocator, u64 custom_data_size)
{
Allocator_Alloc* alloc;
Allocator_Free* free;
Allocator_Realloc* realloc;
Allocator_Clear* clear;
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)
zero_struct(*allocator);
u64 size = sizeof(Allocator) + custom_data_size;
platform_mem_decommit((u8*)allocator, size);
platform_mem_release((u8*)allocator, size);
}
/////////////////////////////////////////
// Bump Allocator
@ -105,13 +93,12 @@ struct Allocator_Bump
u64 at;
u64 size_committed;
u64 size_reserved;
u64 page_size;
};
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;
// TODO(PS): align up to 8 bytes
@ -119,8 +106,15 @@ bump_allocator_alloc(Allocator* allocator, u64 size)
{
// determine new size of the arena
u64 new_size = bump->size_committed * 2;
if (new_size == 0) new_size = platform_page_size();
if (new_size < at_after) new_size = size_to_pages(at_after);
if (new_size == 0)
{
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)
{
@ -140,7 +134,7 @@ bump_allocator_alloc(Allocator* allocator, u64 size)
{
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;
u64 commit_amt = new_size - next_page;
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;
}
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*
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;
}
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*
bump_allocator_create_()
{
@ -195,6 +212,7 @@ bump_allocator_create_()
result->alloc = bump_allocator_alloc;
result->realloc = bump_allocator_realloc;
result->clear = bump_allocator_clear;
result->destroy = bump_allocator_destroy;
result->allocator_data = (u8*)bump;
return result;
@ -206,7 +224,7 @@ bump_allocator_create_reserve(u64 reserve_size)
Allocator* result = bump_allocator_create_();
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);
if (bump->base != 0) bump->size_reserved = reserve_pages;
@ -229,3 +247,286 @@ bump_allocator_create_child(Allocator* parent, u64 init_size)
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;
}

View File

@ -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

View File

@ -54,6 +54,16 @@ char_to_forward_slash(u8 c)
// Note that these don't actually modify any memory
// 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
string_substring(String s, u64 min, u64 max)
{
@ -213,15 +223,25 @@ string_chop_last_slash(String s)
/////////////////////////////////////
// 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
string_copy(String s, Allocator* a)
{
u64 size = s.cap;
if (s.str[s.cap] != 0) size += 1;
String result = allocator_alloc_string(a, size);
memory_copy(s.str, result.str, s.cap);
result.str[size] = 0;
result.len = size;
string_copy_to(&result, s);
return result;
}

View File

@ -6,6 +6,90 @@ thread_proc(Platform_Thread_Data* td)
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
run_tests()
{
@ -29,6 +113,8 @@ run_tests()
assert(a1[i] == (100 + i));
}
memory_tests();
#if defined(PLATFORM_wasm)
// NOTE(PS): the tests below this point don't make sense on a web assembly
// platform

View File

@ -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

View File

@ -37,16 +37,149 @@ typedef s64 b64;
typedef float r32;
typedef double r64;
#define get_byte(value, byte_index) ((value >> (8 * byte_index)) & 0xFF)
struct Data
{
u8* base;
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 KB(x) ((x) << 10)
#define MB(x) ((x) << 20)
#define GB(x) ((x) << 30)
#define GB(x) (((u64)x) << 30)
#define TB(x) (((u64)x) << 40)
#define has_flag(data, flag) (((data) & (flag)) != 0)
@ -65,17 +198,66 @@ else { (last)->next = (ele); } \
// 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
// null terminated
struct String
internal void
hash_table_init(u32* ids, u32 cap)
{
u8* str;
u64 len;
u64 cap;
};
for (u32 i = 0; i < cap; i++) ids[i] = 0;
}
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;
#endif //LUMENARIUM_TYPES_H

View File

@ -34,7 +34,12 @@ WASM_EXTERN void wasm_assert_always(char* file, unsigned int file_len, unsigned
#endif // defined(PLATFORM_WASM)
#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
// want to be alerted when they happen

View File

@ -80,6 +80,148 @@ bool platform_file_write_all(Platform_File_Handle file_handle, Data file_data);
String platform_get_exe_path(Allocator* allocator);
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;
enum
{
@ -100,6 +242,7 @@ enum Platform_Window_Event_Kind
WindowEvent_Invalid = 0,
WindowEvent_MouseScroll,
WindowEvent_MouseMoved,
WindowEvent_ButtonDown,
WindowEvent_ButtonUp,
WindowEvent_Char,
@ -299,6 +442,7 @@ struct Platform_Shader
{
u32 id;
u32 attrs[PLATFORM_SHADER_MAX_ATTRS];
u32 uniforms[PLATFORM_SHADER_MAX_ATTRS];
};
struct Platform_Geometry_Buffer
@ -306,6 +450,7 @@ struct Platform_Geometry_Buffer
u32 buffer_id_vao;
u32 buffer_id_vertices;
u32 buffer_id_indices;
u32 vertices_len;
u32 indices_len;
};
@ -329,16 +474,19 @@ void platform_frame_clear();
// Geometry
Platform_Geometry_Buffer platform_geometry_buffer_create(r32* vertices, u32 vertices_len, u32* indices, u32 indices_len);
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
void platform_geometry_bind(Platform_Geometry_Buffer geo);
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_vertex_attrib_pointer(
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
Platform_Texture platform_texture_create(u8* pixels, u32 width, u32 height, u32 stride);

View File

@ -20,8 +20,9 @@ typedef unsigned int GLsizei;
// I resorted to hard coding these rather than passing them in because
// passing them in didn't seem to be working.
#define GL_FALSE 0
#define GL_TRUE 1
#define GL_TEXTURE_2D 0x0DE1
#define GL_DEPTH_BUFFER_BIT 0x00000100
#define GL_STENCIL_BUFFER_BIT 0x00000400
#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 glUseProgram(GLuint program);
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 glEnableVertexAttribArray(GLuint index);
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_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 = {};
@ -139,6 +141,16 @@ platform_shader_create(
}
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;
}
@ -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
platform_geometry_draw(
Platform_Geometry_Buffer geo

View File

@ -7,6 +7,7 @@
#include <stdio.h>
#include "../../lumenarium_types.h"
#include "../../lumenarium_memory.h"
#include "../lumenarium_platform.h"
#include "../../lumenarium_first.cpp"
@ -215,6 +216,20 @@ WinMain(
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
MSG window_msg;
while (PeekMessageA(

View File

@ -256,3 +256,36 @@ platform_pwd_set(String path)
if (!result) win32_get_last_error();
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);
}

View File

@ -39,6 +39,7 @@ platform_geometry_buffer_create(
GL_ARRAY_BUFFER, sizeof(r32) * vertices_len, vertices, GL_STATIC_DRAW
);
win32_gl_no_error();
result.vertices_len = vertices_len;
// Indices
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, result.buffer_id_indices);
@ -56,9 +57,61 @@ platform_geometry_buffer_create(
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_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 = {};
@ -117,12 +170,29 @@ platform_shader_create(
result.attrs[i] = gl.glGetAttribLocation(
result.id, (char*)attrs[i].str
);
win32_gl_no_error();
}
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;
}
void
platform_set_uniform(Platform_Shader shader, u32 index, m44 u)
{
gl.glUniformMatrix4fv(shader.uniforms[index], 1, GL_FALSE, (r32*)u.Elements);
}
void
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
platform_geometry_draw(
Platform_Geometry_Buffer geo
){
glDrawElements(GL_TRIANGLES, geo.indices_len, GL_UNSIGNED_INT, 0);
win32_gl_no_error();
platform_geometry_draw(geo, geo.indices_len);
}
void platform_vertex_attrib_pointer(

View File

@ -5,7 +5,7 @@ u64 platform_page_size() { return WIN32_PAGE_SIZE; }
u8*
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 protection = PAGE_READWRITE;
u8* result = (u8*)VirtualAlloc(0, size_cvt, alloc_type, protection);
@ -16,7 +16,7 @@ platform_mem_reserve(u64 size)
u8*
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 protection = PAGE_READWRITE;
u8* result = (u8*)VirtualAlloc(base, size_cvt, alloc_type, protection);
@ -37,7 +37,9 @@ bool
platform_mem_release(u8* base, u64 size)
{
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();
return result;
}

View File

@ -17,6 +17,7 @@ typedef void proc_glBindVertexArray(GLuint array);
typedef void proc_glGenBuffers (GLsizei n, GLuint *buffers);
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_glBufferSubData(GLenum target, size_t offset, size_t size, const void* data);
typedef GLuint proc_glCreateShader(GLenum type);
typedef void proc_glShaderSource(GLuint shader, u32 count, const char* const* string, const GLint *length);
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_glGetProgramiv(GLuint program, GLenum ele, GLint* value_out);
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
{
proc_wglGetExtensionsStringARB* wglGetExtensionsStringARB;
@ -43,6 +45,7 @@ struct Win32_OpenGL_Extensions
proc_glGenBuffers* glGenBuffers;
proc_glBindBuffer* glBindBuffer;
proc_glBufferData* glBufferData;
proc_glBufferSubData* glBufferSubData;
proc_glCreateShader* glCreateShader;
proc_glShaderSource* glShaderSource;
proc_glCompileShader* glCompileShader;
@ -57,6 +60,8 @@ struct Win32_OpenGL_Extensions
proc_glGetShaderInfoLog* glGetShaderInfoLog;
proc_glGetProgramiv* glGetProgramiv;
proc_glGetProgramInfoLog* glGetProgramInfoLog;
proc_glGetUniformLocation* glGetUniformLocation;
proc_glUniformMatrix4fv* glUniformMatrix4fv;
};
////////////////////////////////////////

View File

@ -381,6 +381,7 @@ win32_window_opengl_get_wgl_ext(HINSTANCE hinstance)
wgl_load_ext(result, glGenBuffers);
wgl_load_ext(result, glBindBuffer);
wgl_load_ext(result, glBufferData);
wgl_load_ext(result, glBufferSubData);
wgl_load_ext(result, glCreateShader);
wgl_load_ext(result, glShaderSource);
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, glGetProgramiv);
wgl_load_ext(result, glGetProgramInfoLog);
wgl_load_ext(result, glGetUniformLocation);
wgl_load_ext(result, glUniformMatrix4fv);
}
wglMakeCurrent(NULL, NULL);

View File

@ -10,8 +10,6 @@ incenter_get_init_desc()
internal void
incenter_init(App_State* state)
{
return;
// create a fake sculpture
Assembly_Handle ah = assembly_add(&state->assemblies, lit_str("test"), 3000, 100);