Init new repository
This commit is contained in:
7
tests/example_ui_and_hot_reloading/build.bat
Normal file
7
tests/example_ui_and_hot_reloading/build.bat
Normal file
@@ -0,0 +1,7 @@
|
||||
@echo off
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
clang unity_exe.c -o platform.exe -g -O0 -I"../.."
|
||||
clang unity_dll.c -o game.dll -O0 -shared -g -I"../.." -Wl,-export:APP_Update
|
||||
|
||||
78
tests/example_ui_and_hot_reloading/dll/app_main.lc
Normal file
78
tests/example_ui_and_hot_reloading/dll/app_main.lc
Normal file
@@ -0,0 +1,78 @@
|
||||
import "shared";
|
||||
IO_Assertf :: proc(b: bool, s: *char, ...); @foreign
|
||||
IO_Assert :: proc(b: bool); @foreign
|
||||
IO_InvalidCodepath :: proc(); @foreign
|
||||
S8_Lit :: proc(s: *char): S8_String; @foreign
|
||||
IO_FatalErrorf :: proc(msg: *char, ...); @foreign
|
||||
IO_FatalError :: proc(msg: *char); @foreign
|
||||
|
||||
HashBytes :: proc(data: *void, data_size: u64): u64; @foreign
|
||||
|
||||
// @todo: hmm ?
|
||||
SLL_QUEUE_ADD :: proc(first: *void, last: *void, data: *void); @foreign
|
||||
|
||||
Mu: *MU_Context;
|
||||
Gs: *GameState;
|
||||
Perm: *MA_Arena;
|
||||
Temp: *MA_Arena;
|
||||
R: *R_Render;
|
||||
|
||||
GameState :: struct {
|
||||
render: R_Render;
|
||||
}
|
||||
|
||||
activated: bool;
|
||||
APP_Update :: proc(event: LibraryEvent, mu: *MU_Context, dll_context: *DLL_Context) {
|
||||
Mu = mu;
|
||||
Perm = &dll_context.perm;
|
||||
Temp = dll_context.temp;
|
||||
Gs = dll_context.context;
|
||||
|
||||
if event == Init {
|
||||
dll_context.context = MA_PushSize(Perm, :usize(sizeof(:GameState)));
|
||||
Gs = dll_context.context;
|
||||
|
||||
R_Init(&Gs.render);
|
||||
return;
|
||||
}
|
||||
|
||||
if event == Reload {
|
||||
R_Reload();
|
||||
return;
|
||||
}
|
||||
|
||||
if event == Unload {
|
||||
return;
|
||||
}
|
||||
|
||||
UI_Begin();
|
||||
Ui.cut = UI_Cut_Top;
|
||||
UI_PushLayout({});
|
||||
{
|
||||
Ui.cut = UI_Cut_Left;
|
||||
|
||||
if (UI_Checkbox(&activated, "File")) {
|
||||
}
|
||||
UI_Button("Edit");
|
||||
Ui.cut = UI_Cut_Right;
|
||||
UI_Button("Memes");
|
||||
|
||||
Ui.s.cut_size.x += 100000;
|
||||
UI_Fill();
|
||||
UI_PopLayout();
|
||||
UI_PopStyle();
|
||||
}
|
||||
UI_End();
|
||||
|
||||
R_Text2D({
|
||||
pos = {100, 100},
|
||||
text = S8_Lit("Testing memes"),
|
||||
color = R_ColorWhite,
|
||||
do_draw = true,
|
||||
scale = 1.0,
|
||||
});
|
||||
|
||||
R_Rect2D(R2P_SizeF(200, 200, 100, 100), R.atlas.white_texture_bounding_box, R_ColorWhite);
|
||||
|
||||
R_EndFrame();
|
||||
}
|
||||
122
tests/example_ui_and_hot_reloading/dll/math.lc
Normal file
122
tests/example_ui_and_hot_reloading/dll/math.lc
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
V2 :: struct { x: f32; y: f32; }
|
||||
V3 :: struct { x: f32; y: f32; z: f32; }
|
||||
V4 :: struct { x: f32; y: f32; z: f32; w: f32; }
|
||||
R2P :: struct { min: V2; max: V2; }
|
||||
|
||||
V2I :: struct { x: i32; y: i32; }
|
||||
V3I :: struct { x: i32; y: i32; z: i32; }
|
||||
V4I :: struct { x: i32; y: i32; z: i32; w: i32; }
|
||||
|
||||
R2P_SizeF :: proc(px: f32, py: f32, sx: f32, sy: f32): R2P {
|
||||
result: R2P = {{px, py}, {px + sx, py + sy}};
|
||||
return result;
|
||||
}
|
||||
|
||||
R2P_Size :: proc(pos: V2, size: V2): R2P {
|
||||
result := :R2P{{pos.x, pos.y}, {pos.x + size.x, pos.y + size.y}};
|
||||
return result;
|
||||
}
|
||||
|
||||
R2P_GetSize :: proc(r: R2P): V2 {
|
||||
result := :V2{r.max.x - r.min.x, r.max.y - r.min.y};
|
||||
return result;
|
||||
}
|
||||
|
||||
V2_Mul :: proc(a: V2, b: V2): V2 {
|
||||
result := :V2{a.x * b.x, a.y * b.y};
|
||||
return result;
|
||||
}
|
||||
|
||||
V2_MulF :: proc(a: V2, b: f32): V2 {
|
||||
result := :V2{a.x * b, a.y * b};
|
||||
return result;
|
||||
}
|
||||
|
||||
V2_FromV2I :: proc(a: V2I): V2 {
|
||||
result := :V2{:f32(a.x), :f32(a.y)};
|
||||
return result;
|
||||
}
|
||||
|
||||
I32_Max :: proc(a: i32, b: i32): i32 {
|
||||
if a > b return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
I32_Min :: proc(a: i32, b: i32): i32 {
|
||||
if a > b return b;
|
||||
return a;
|
||||
}
|
||||
|
||||
F32_Max :: proc(a: f32, b: f32): f32 {
|
||||
if a > b return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
F32_Min :: proc(a: f32, b: f32): f32 {
|
||||
if a > b return b;
|
||||
return a;
|
||||
}
|
||||
|
||||
F32_Clamp :: proc(val: f32, min: f32, max: f32): f32 {
|
||||
if (val > max) return max;
|
||||
if (val < min) return min;
|
||||
return val;
|
||||
}
|
||||
|
||||
R2P_CutLeft :: proc(r: *R2P, value: float): R2P {
|
||||
minx := r.min.x;
|
||||
r.min.x = F32_Min(r.max.x, r.min.x + value);
|
||||
return :R2P{
|
||||
{ minx, r.min.y},
|
||||
{r.min.x, r.max.y}
|
||||
};
|
||||
}
|
||||
|
||||
R2P_CutRight :: proc(r: *R2P, value: f32): R2P {
|
||||
maxx := r.max.x;
|
||||
r.max.x = F32_Max(r.max.x - value, r.min.x);
|
||||
return :R2P{
|
||||
{r.max.x, r.min.y},
|
||||
{ maxx, r.max.y}
|
||||
};
|
||||
}
|
||||
|
||||
R2P_CutTop :: proc(r: *R2P, value: f32): R2P { // Y is up
|
||||
maxy := r.max.y;
|
||||
r.max.y = F32_Max(r.min.y, r.max.y - value);
|
||||
return :R2P{
|
||||
{r.min.x, r.max.y},
|
||||
{r.max.x, maxy}
|
||||
};
|
||||
}
|
||||
|
||||
R2P_CutBottom :: proc(r: *R2P, value: f32): R2P { // Y is up
|
||||
miny := r.min.y;
|
||||
r.min.y = F32_Min(r.min.y + value, r.max.y);
|
||||
return :R2P{
|
||||
{r.min.x, miny},
|
||||
{r.max.x, r.min.y}
|
||||
};
|
||||
}
|
||||
|
||||
R2P_Shrink :: proc(r: R2P, size: f32): R2P {
|
||||
return :R2P{
|
||||
:V2{r.min.x + size, r.min.y + size},
|
||||
:V2{r.max.x - size, r.max.y - size}
|
||||
};
|
||||
}
|
||||
|
||||
R2P_CollidesV2 :: proc(rect: R2P , point: V2): bool {
|
||||
result := point.x > rect.min.x && point.x < rect.max.x && point.y > rect.min.y && point.y < rect.max.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
R2P_CollidesR2P :: proc(a: R2P, b: R2P): bool {
|
||||
result := a.min.x < b.max.x && a.max.x > b.min.x && a.min.y < b.max.y && a.max.y > b.min.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
V2_Add :: proc(a: V2, b: V2): V2 { return {a.x + b.x, a.y + b.y}; }
|
||||
V2_Sub :: proc(a: V2, b: V2): V2 { return {a.x - b.x, a.y - b.y}; }
|
||||
V2_DivF :: proc(a: V2, b: f32): V2 { return {a.x / b, a.y / b}; }
|
||||
3012
tests/example_ui_and_hot_reloading/dll/opengl.lc
Normal file
3012
tests/example_ui_and_hot_reloading/dll/opengl.lc
Normal file
File diff suppressed because it is too large
Load Diff
545
tests/example_ui_and_hot_reloading/dll/render_opengl.lc
Normal file
545
tests/example_ui_and_hot_reloading/dll/render_opengl.lc
Normal file
@@ -0,0 +1,545 @@
|
||||
R_CommandBufferSize :: 1024 * 1024;
|
||||
|
||||
R_Atlas :: struct {
|
||||
bitmap : *u32;
|
||||
sizei : V2I;
|
||||
size : V2;
|
||||
inverse_size : V2;
|
||||
cursor : V2I;
|
||||
biggest_height : i32;
|
||||
white_texture_bounding_box : R2P;
|
||||
texture_id : u32;
|
||||
padding : V2I;
|
||||
}
|
||||
|
||||
R_FontGlyph :: struct {
|
||||
size : V2;
|
||||
offset : V2;
|
||||
x_advance : f32;
|
||||
left_side_bearing : f32;
|
||||
atlas_bounding_box : R2P;
|
||||
}
|
||||
|
||||
R_Font :: struct {
|
||||
atlas : *R_Atlas;
|
||||
glyphs : [96]R_FontGlyph;
|
||||
glyph_count : i32;
|
||||
|
||||
first_char : i32;
|
||||
last_char : i32;
|
||||
|
||||
// This is for oversampling
|
||||
// 0.5 = we draw the font as 2 times smaller then it is.
|
||||
// Should lead to better quality result.
|
||||
scaling_transform : f32;
|
||||
|
||||
// scaling transform is applied to these
|
||||
size : f32;
|
||||
ascent : f32;
|
||||
descent : f32;
|
||||
line_gap : f32;
|
||||
|
||||
// scaling factor not applied, not sure if these will be useful
|
||||
scale : f32;
|
||||
em_scale : f32;
|
||||
|
||||
white_texture_bounding_box : R2P;
|
||||
}
|
||||
|
||||
R_Vertex2D :: struct {
|
||||
pos : V2;
|
||||
tex : V2;
|
||||
color: V4;
|
||||
}
|
||||
|
||||
R_CommandKind :: typedef int;
|
||||
R_CommandKind_Null :: 0;
|
||||
R_CommandKind_Triangle :: ^;
|
||||
R_CommandKind_Triangle2D :: ^;
|
||||
|
||||
R_Command :: struct {
|
||||
kind: R_CommandKind;
|
||||
next: *R_Command;
|
||||
|
||||
out : *R_Vertex2D; // user write
|
||||
data: *R_Vertex2D;
|
||||
count: i32;
|
||||
max_count: i32;
|
||||
}
|
||||
|
||||
R_Shader :: struct {
|
||||
pipeline: u32;
|
||||
fragment: u32;
|
||||
vertex : u32;
|
||||
}
|
||||
|
||||
R_Render :: struct {
|
||||
first_command2d: *R_Command;
|
||||
last_command2d : *R_Command;
|
||||
total_vertex_count: u64;
|
||||
|
||||
vbo: u32;
|
||||
vao: u32;
|
||||
shader2d: R_Shader;
|
||||
|
||||
atlas: R_Atlas;
|
||||
font_medium: R_Font;
|
||||
font: *R_Font;
|
||||
}
|
||||
|
||||
R_Text2DDesc :: struct {
|
||||
pos: V2;
|
||||
text: S8_String;
|
||||
color: V4;
|
||||
scale: f32;
|
||||
|
||||
do_draw: bool;
|
||||
rects_arena: *MA_Arena;
|
||||
}
|
||||
|
||||
R_StringMeasure :: struct {
|
||||
first_rect: *R_RectNode;
|
||||
last_rect : *R_RectNode;
|
||||
rect: R2P;
|
||||
}
|
||||
|
||||
R_RectNode :: struct {
|
||||
next: *R_RectNode;
|
||||
rect: R2P;
|
||||
utf8_codepoint_byte_size: i32;
|
||||
}
|
||||
|
||||
R_PackType :: typedef int;
|
||||
R_PackType_MonoColorFont :: 0;
|
||||
R_PackType_RGBABitmap :: ^;
|
||||
|
||||
R_CreateAtlas :: proc(arena: *MA_Arena, size: V2I, padding: V2I): R_Atlas {
|
||||
result: R_Atlas;
|
||||
result.padding = padding;
|
||||
result.sizei = size;
|
||||
result.size = V2_FromV2I(size);
|
||||
result.inverse_size.x = 1.0 / result.size.x;
|
||||
result.inverse_size.y = 1.0 / result.size.y;
|
||||
result.bitmap = MA_PushSize(arena, :usize(:i32(sizeof(:u32)) * size.x * size.y));
|
||||
|
||||
// Add a whitebox first for rectangle rendering
|
||||
for y: i32 = 0; y < 16; y += 1 {
|
||||
for x: i32 = 0; x < 16; x += 1 {
|
||||
dst := &result.bitmap[x + y * result.sizei.x];
|
||||
*dst = 0xffffffff;
|
||||
}
|
||||
}
|
||||
// Skipping some pixels to avoid linear interpolation on edges
|
||||
result.white_texture_bounding_box = :R2P{
|
||||
{2.0 * result.inverse_size.x, 2.0 / result.size.y},
|
||||
{14.0 * result.inverse_size.x, 14.0 / result.size.y},
|
||||
};
|
||||
result.cursor.x += 16 + padding.x;
|
||||
result.biggest_height += 16 + padding.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
R_PackBitmapInvertY :: proc(atlas: *R_Atlas, pack_type: R_PackType, bitmap: *u8, width: i32, height: i32): R2P {
|
||||
// Packing into a texture atlas
|
||||
// @Inefficient The algorithm is a simplest thing I had in mind, first we advance
|
||||
// through the atlas in X packing consecutive glyphs. After we get to the end of the row
|
||||
// we advance to the next row by the Y size of the biggest packed glyph. If we get to the
|
||||
// end of atlas and fail to pack everything the app panics.
|
||||
|
||||
if (atlas.cursor.x + width > atlas.sizei.x) {
|
||||
if (atlas.cursor.y + height < atlas.sizei.y) {
|
||||
atlas.cursor.x = 0;
|
||||
atlas.cursor.y += atlas.biggest_height + atlas.padding.y;
|
||||
}
|
||||
else {
|
||||
IO_FatalErrorf("Error while packing a font into atlas. Atlas size for this font scale is a bit too small");
|
||||
}
|
||||
}
|
||||
|
||||
// Write the bitmap with inverted Y
|
||||
src := bitmap;
|
||||
// @todo: ambigious syntax, expression parsing doesn't stop at '{', error in wrong place
|
||||
// for y := atlas.cursor.y + height - 1; y >= atlas.cursor.y; y++ {
|
||||
for y := atlas.cursor.y + height - 1; y >= atlas.cursor.y; y -= 1 {
|
||||
for x := atlas.cursor.x; x < atlas.cursor.x + width; x += 1 {
|
||||
if (pack_type == R_PackType_RGBABitmap) {
|
||||
atlas.bitmap[x + y * atlas.sizei.x] = *:*u32(src);
|
||||
src = &src[4];
|
||||
continue;
|
||||
}
|
||||
if (pack_type == R_PackType_MonoColorFont) {
|
||||
dst := :*u8(&atlas.bitmap[x + y * atlas.sizei.x]);
|
||||
dst[0] = 0xFF;
|
||||
dst[1] = 0xFF;
|
||||
dst[2] = 0xFF;
|
||||
dst[3] = *src;
|
||||
src = &src[1];
|
||||
continue;
|
||||
}
|
||||
IO_InvalidCodepath();
|
||||
}
|
||||
}
|
||||
|
||||
size := :V2{:f32(width) * atlas.inverse_size.x, :f32(height) * atlas.inverse_size.y};
|
||||
cursor := V2_FromV2I(atlas.cursor);
|
||||
pos := V2_Mul(cursor, atlas.inverse_size);
|
||||
result := R2P_Size(pos, size);
|
||||
|
||||
atlas.cursor.x += width + atlas.padding.x;
|
||||
atlas.biggest_height = I32_Max(atlas.biggest_height, height);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Font_Create :: proc(atlas: *R_Atlas, size: f32, path: S8_String, oversampling: f32): R_Font {
|
||||
scratch := MA_GetScratch();
|
||||
font_file := OS_ReadFile(scratch.arena, path);
|
||||
|
||||
result: R_Font;
|
||||
result.scaling_transform = 1.0 / oversampling;
|
||||
result.size = oversampling * size;
|
||||
|
||||
result.first_char = ' ';
|
||||
result.last_char = '~';
|
||||
stb_font: stbtt_fontinfo;
|
||||
if (font_file.len) {
|
||||
success := stbtt_InitFont(&stb_font, :*uchar(font_file.str), 0);
|
||||
if (success) {
|
||||
ascent: int;
|
||||
descent: int;
|
||||
gap: int;
|
||||
stbtt_GetFontVMetrics(&stb_font, &ascent, &descent, &gap);
|
||||
result.scale = stbtt_ScaleForPixelHeight(&stb_font, result.size);
|
||||
result.em_scale = stbtt_ScaleForMappingEmToPixels(&stb_font, result.size);
|
||||
result.ascent = :f32(ascent) * result.scale;
|
||||
result.descent = :f32(descent) * result.scale;
|
||||
result.line_gap = :f32(gap) * result.scale;
|
||||
result.white_texture_bounding_box = atlas.white_texture_bounding_box;
|
||||
|
||||
for ascii_symbol := result.first_char; ascii_symbol <= result.last_char; ascii_symbol+=1 {
|
||||
width: int;
|
||||
height: int;
|
||||
xoff: int;
|
||||
yoff: int;
|
||||
bitmap := :*u8(stbtt_GetCodepointBitmap(&stb_font, 0, result.scale, :int(ascii_symbol), &width, &height, &xoff, &yoff));
|
||||
|
||||
x_advance: int;
|
||||
left_side_bearing: int;
|
||||
stbtt_GetCodepointHMetrics(&stb_font, :int(ascii_symbol), &x_advance, &left_side_bearing);
|
||||
|
||||
g := &result.glyphs[result.glyph_count];
|
||||
result.glyph_count += 1;
|
||||
|
||||
g.atlas_bounding_box = R_PackBitmapInvertY(atlas, R_PackType_MonoColorFont, bitmap, :i32(width), :i32(height));
|
||||
g.size = :V2{:f32(width), :f32(height)};
|
||||
|
||||
// Offset y needs to be inverted cause bitmap has inverted Y
|
||||
g.offset = :V2{:f32(xoff), -(g.size.y + :f32(yoff))};
|
||||
g.x_advance = :f32(x_advance) * result.scale;
|
||||
g.left_side_bearing = :f32(left_side_bearing) * result.scale;
|
||||
|
||||
// Apply scaling transform
|
||||
g.offset = V2_MulF(g.offset, result.scaling_transform);
|
||||
g.x_advance = g.x_advance * result.scaling_transform;
|
||||
g.left_side_bearing = g.left_side_bearing * result.scaling_transform;
|
||||
g.size = V2_MulF(g.size, result.scaling_transform);
|
||||
|
||||
stbtt_FreeBitmap(:*uchar(bitmap), nil);
|
||||
}
|
||||
|
||||
result.ascent *= result.scaling_transform;
|
||||
result.descent *= result.scaling_transform;
|
||||
result.size *= result.scaling_transform;
|
||||
result.line_gap *= result.scaling_transform;
|
||||
}
|
||||
}
|
||||
|
||||
MA_EndTemp(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
Font_GetGlyph :: proc(font: *R_Font, codepoint: i32): *R_FontGlyph {
|
||||
is_in_range := codepoint >= font.first_char && codepoint <= font.last_char;
|
||||
if (is_in_range) {
|
||||
index := codepoint - font.first_char;
|
||||
return &font.glyphs[index];
|
||||
}
|
||||
else {
|
||||
index := '?' - font.first_char;
|
||||
return &font.glyphs[index];
|
||||
}
|
||||
}
|
||||
|
||||
GL_DebugCallback :: proc(source: GLenum @unused, type: GLenum @unused, id: GLuint @unused, severity: GLenum, length: GLsizei @unused, message: *GLchar, user: *void @unused) {
|
||||
IO_Printf("%s\n", message);
|
||||
if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM) {
|
||||
IO_FatalErrorf("%s", message);
|
||||
}
|
||||
}
|
||||
|
||||
GL_SetProcAddress :: proc(p: *void, name: *char) {
|
||||
pp := :**void(p);
|
||||
*pp = Mu.gl_get_proc_address(name);
|
||||
}
|
||||
|
||||
GL_LoadProcs :: proc() {
|
||||
load_up_to(4, 5, :*void(GL_SetProcAddress));
|
||||
glDebugMessageCallback(:*void(GL_DebugCallback), nil);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
}
|
||||
|
||||
R_Reload :: proc() {
|
||||
GL_LoadProcs();
|
||||
}
|
||||
|
||||
R_Init :: proc(render: *R_Render) {
|
||||
R = render;
|
||||
GL_LoadProcs();
|
||||
atlas := R_CreateAtlas(Temp, :V2I{1024, 1024}, :V2I{4, 4});
|
||||
R.font_medium = Font_Create(&atlas, 32, S8_Lit("C:/windows/fonts/Calibri.ttf"), 1.0);
|
||||
{
|
||||
glCreateTextures(GL_TEXTURE_2D, 1, &atlas.texture_id);
|
||||
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTextureStorage2D(atlas.texture_id, 1, GL_RGBA8, :i32(atlas.sizei.x), :i32(atlas.sizei.y));
|
||||
glTextureSubImage2D(atlas.texture_id, 0, 0, 0, :i32(atlas.sizei.x), :i32(atlas.sizei.y), GL_RGBA, GL_UNSIGNED_BYTE, atlas.bitmap);
|
||||
}
|
||||
R.atlas = atlas;
|
||||
R.font_medium.atlas = &R.atlas;
|
||||
R.font = &R.font_medium;
|
||||
|
||||
glCreateBuffers(1, &R.vbo);
|
||||
glNamedBufferStorage(R.vbo, R_CommandBufferSize, nil, GL_DYNAMIC_STORAGE_BIT);
|
||||
|
||||
{
|
||||
glCreateVertexArrays(1, &R.vao);
|
||||
|
||||
vbuf_index: u32 = 0;
|
||||
glVertexArrayVertexBuffer(R.vao, vbuf_index, R.vbo, 0, :i32(sizeof(:R_Vertex2D)));
|
||||
|
||||
a_pos: u32 = 0;
|
||||
pos_offset: u32 = #`offsetof(R_Vertex2D, pos)`;
|
||||
glVertexArrayAttribFormat(R.vao, a_pos, 2, GL_FLOAT, GL_FALSE, pos_offset);
|
||||
glVertexArrayAttribBinding(R.vao, a_pos, vbuf_index);
|
||||
glEnableVertexArrayAttrib(R.vao, a_pos);
|
||||
|
||||
a_tex: u32 = 1;
|
||||
tex_offset: u32 = #`offsetof(R_Vertex2D, tex)`;
|
||||
glVertexArrayAttribFormat(R.vao, a_tex, 2, GL_FLOAT, GL_FALSE, tex_offset);
|
||||
glVertexArrayAttribBinding(R.vao, a_tex, vbuf_index);
|
||||
glEnableVertexArrayAttrib(R.vao, a_tex);
|
||||
|
||||
a_color: u32 = 2;
|
||||
color_offset: u32 = #`offsetof(R_Vertex2D, color)`; // @todo
|
||||
glVertexArrayAttribFormat(R.vao, a_color, 4, GL_FLOAT, GL_FALSE, color_offset);
|
||||
glVertexArrayAttribBinding(R.vao, a_color, vbuf_index);
|
||||
glEnableVertexArrayAttrib(R.vao, a_color);
|
||||
}
|
||||
|
||||
vshader := `#version 450 core
|
||||
layout(location=0) uniform vec2 U_InvHalfScreenSize;
|
||||
layout(location=0) in vec2 IN_Pos;
|
||||
layout(location=1) in vec2 IN_Tex;
|
||||
layout(location=2) in vec4 IN_Color;
|
||||
|
||||
out gl_PerVertex { vec4 gl_Position; }; // required because of ARB_separate_shader_objects
|
||||
out vec2 OUT_UV;
|
||||
out vec4 OUT_Color;
|
||||
void main() {
|
||||
vec2 pos = IN_Pos * U_InvHalfScreenSize;
|
||||
pos -= vec2(1, 1);
|
||||
gl_Position = vec4(pos, 0, 1);
|
||||
OUT_UV = IN_Tex;
|
||||
OUT_Color = IN_Color;
|
||||
}
|
||||
`;
|
||||
|
||||
fshader := `#version 450 core
|
||||
in vec2 IN_UV;
|
||||
in vec4 IN_Color;
|
||||
layout (binding=0) uniform sampler2D S_Texture;
|
||||
layout (location=0) out vec4 OUT_Color;
|
||||
void main() {
|
||||
vec4 c = IN_Color;
|
||||
vec4 texture_color = texture(S_Texture, IN_UV);
|
||||
OUT_Color = c * texture_color;
|
||||
}
|
||||
`;
|
||||
|
||||
R.shader2d = R_CreateShader(vshader, fshader);
|
||||
}
|
||||
|
||||
|
||||
R_CreateShader :: proc(glsl_vshader: *char, glsl_fshader: *char): R_Shader {
|
||||
result: R_Shader;
|
||||
result.vertex = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vshader);
|
||||
result.fragment = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fshader);
|
||||
|
||||
linked: i32;
|
||||
glGetProgramiv(result.vertex, GL_LINK_STATUS, &linked);
|
||||
if (!linked) {
|
||||
message: [1024]char;
|
||||
glGetProgramInfoLog(result.vertex, :i32(sizeof(message)), nil, :*u8(&message[0]));
|
||||
IO_FatalErrorf("[GL] Failed to create vertex shader! %s", message);
|
||||
}
|
||||
|
||||
glGetProgramiv(result.fragment, GL_LINK_STATUS, &linked);
|
||||
if (!linked) {
|
||||
message: [1024]char;
|
||||
glGetProgramInfoLog(result.fragment, :i32(sizeof(message)), nil, :*u8(&message[0]));
|
||||
IO_FatalErrorf("[GL] Failed to create fragment shader! %s", message);
|
||||
}
|
||||
|
||||
glGenProgramPipelines(1, &result.pipeline);
|
||||
glUseProgramStages(result.pipeline, GL_VERTEX_SHADER_BIT, result.vertex);
|
||||
glUseProgramStages(result.pipeline, GL_FRAGMENT_SHADER_BIT, result.fragment);
|
||||
return result;
|
||||
}
|
||||
|
||||
R_GetCommand :: proc(kind: R_CommandKind, vcount_to_add: i32): *R_Command {
|
||||
make_new := R.last_command2d == 0 ||
|
||||
R.last_command2d.kind != kind ||
|
||||
R.last_command2d.count + vcount_to_add > R.last_command2d.max_count;
|
||||
|
||||
if make_new {
|
||||
sizeof_r_command: usize = #`sizeof(R_Command)`;
|
||||
c: *R_Command = MA_PushSize(Temp, sizeof_r_command);
|
||||
c.kind = kind;
|
||||
c.data = MA_PushSizeNonZeroed(Temp, R_CommandBufferSize);
|
||||
if (kind == R_CommandKind_Triangle2D) {
|
||||
c.max_count = R_CommandBufferSize / :i32(sizeof(:R_Vertex2D));
|
||||
SLL_QUEUE_ADD(R.first_command2d, R.last_command2d, c);
|
||||
}
|
||||
else IO_InvalidCodepath();
|
||||
}
|
||||
|
||||
c := R.last_command2d;
|
||||
c.out = &c.data[c.count];
|
||||
c.count += vcount_to_add;
|
||||
R.total_vertex_count += :u64(vcount_to_add);
|
||||
return c;
|
||||
}
|
||||
|
||||
R_Rect2D :: proc(rect: R2P, tex: R2P, color: V4) {
|
||||
c := R_GetCommand(R_CommandKind_Triangle2D, 6);
|
||||
c.out[0].pos = :V2{rect.min.x, rect.max.y};
|
||||
c.out[0].tex = :V2{tex.min.x, tex.max.y};
|
||||
c.out[0].color = color;
|
||||
c.out[1].pos = :V2{rect.max.x, rect.max.y};
|
||||
c.out[1].tex = :V2{tex.max.x, tex.max.y};
|
||||
c.out[1].color = color;
|
||||
c.out[2].pos = :V2{rect.min.x, rect.min.y};
|
||||
c.out[2].tex = :V2{tex.min.x, tex.min.y};
|
||||
c.out[2].color = color;
|
||||
c.out[3].pos = :V2{rect.min.x, rect.min.y};
|
||||
c.out[3].tex = :V2{tex.min.x, tex.min.y};
|
||||
c.out[3].color = color;
|
||||
c.out[4].pos = :V2{rect.max.x, rect.max.y};
|
||||
c.out[4].tex = :V2{tex.max.x, tex.max.y};
|
||||
c.out[4].color = color;
|
||||
c.out[5].pos = :V2{rect.max.x, rect.min.y};
|
||||
c.out[5].tex = :V2{tex.max.x, tex.min.y};
|
||||
c.out[5].color = color;
|
||||
}
|
||||
|
||||
R_Text2D :: proc(params: R_Text2DDesc): R_StringMeasure {
|
||||
result: R_StringMeasure;
|
||||
|
||||
original_pos := params.pos;
|
||||
max_pos := params.pos;
|
||||
pos := params.pos;
|
||||
scale := params.scale;
|
||||
for iter := UTF8_IterateEx(params.text.str, :int(params.text.len)); iter.item /*;UTF8_Advance(&iter)@todo*/ {
|
||||
it: u32 = iter.item;
|
||||
if it == '\n' {
|
||||
pos.x = original_pos.x;
|
||||
pos.y -= R.font.size * scale;
|
||||
if (pos.x > max_pos.x) max_pos.x = pos.x;
|
||||
if (pos.y < max_pos.y) max_pos.y = pos.y; // @warning: min position y actually
|
||||
continue;
|
||||
}
|
||||
g: *R_FontGlyph = Font_GetGlyph(R.font, :i32(it));
|
||||
|
||||
sym_pos := pos;
|
||||
pos.x += g.x_advance * scale;
|
||||
if (pos.x > max_pos.x) max_pos.x = pos.x;
|
||||
if (pos.y < max_pos.y) max_pos.y = pos.y; // @warning: min position y actually
|
||||
|
||||
sym_pos.x += g.offset.x * scale;
|
||||
sym_pos.y += g.offset.y * scale;
|
||||
|
||||
minp: V2 = {sym_pos.x, sym_pos.y};
|
||||
rect: R2P = R2P_Size(minp, V2_MulF(g.size, scale));
|
||||
if (params.do_draw) {
|
||||
R_Rect2D(rect, g.atlas_bounding_box, params.color);
|
||||
}
|
||||
if (params.rects_arena) {
|
||||
node: *R_RectNode = MA_PushSize(params.rects_arena, :usize(sizeof(:R_RectNode)));
|
||||
node.rect = rect;
|
||||
node.utf8_codepoint_byte_size = :i32(iter.utf8_codepoint_byte_size);
|
||||
SLL_QUEUE_ADD(result.first_rect, result.last_rect, node);
|
||||
}
|
||||
UTF8_Advance(&iter); // @todo
|
||||
}
|
||||
|
||||
result.rect = {
|
||||
{original_pos.x, max_pos.y + R.font.descent * scale}, /* @warning: min position y actually */
|
||||
{max_pos.x, original_pos.y + R.font.ascent * scale},
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
R_GetTextSize :: proc(text: S8_String): f32 {
|
||||
m := R_Text2D({text = text, scale = 1.0});
|
||||
size := R2P_GetSize(m.rect).x;
|
||||
return size;
|
||||
}
|
||||
|
||||
R_ColorWhite: V4 = {1,1,1,1};
|
||||
R_ColorBlack: V4 = {0,0,0,1};
|
||||
|
||||
R_DrawText :: proc(text: S8_String, pos: V2, color: V4): R_StringMeasure {
|
||||
result := R_Text2D({text = text, color = color, pos = pos, do_draw = true, scale = 1.0});
|
||||
return result;
|
||||
}
|
||||
|
||||
R_EndFrame :: proc() {
|
||||
ws := :V2{:f32(Mu.window.size.x), :f32(Mu.window.size.y)};
|
||||
wsi := :V2I{:i32(Mu.window.size.x), :i32(Mu.window.size.y)};
|
||||
x: f32 = 1 / (ws.x / 2);
|
||||
y: f32 = 1 / (ws.y / 2);
|
||||
|
||||
glViewport(0, 0, wsi.x, wsi.y);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
// Default draw using the font texture
|
||||
{
|
||||
glBindProgramPipeline(R.shader2d.pipeline);
|
||||
glProgramUniform2f(R.shader2d.vertex, 0, x, y);
|
||||
for it := R.first_command2d; it; it = it.next {
|
||||
if (it.kind == R_CommandKind_Triangle2D) {
|
||||
glNamedBufferSubData(R.vbo, 0, :int(it.count) * :int(sizeof(:R_Vertex2D)), it.data);
|
||||
glBindVertexArray(R.vao);
|
||||
s_texture: u32 = 0; // texture unit that sampler2D will use in GLSL code
|
||||
glBindTextureUnit(s_texture, R.font.atlas.texture_id);
|
||||
glDrawArrays(GL_TRIANGLES, 0, it.count);
|
||||
continue;
|
||||
}
|
||||
IO_InvalidCodepath();
|
||||
}
|
||||
}
|
||||
|
||||
R.first_command2d = nil;
|
||||
R.last_command2d = nil;
|
||||
R.total_vertex_count = 0;
|
||||
}
|
||||
183
tests/example_ui_and_hot_reloading/dll/stb_truetype.lc
Normal file
183
tests/example_ui_and_hot_reloading/dll/stb_truetype.lc
Normal file
@@ -0,0 +1,183 @@
|
||||
#`#include "vendor/stb_truetype.c"`;
|
||||
|
||||
@foreign stbrp_rect :: struct {f: int;}
|
||||
|
||||
@foreign
|
||||
stbtt__buf :: struct {
|
||||
data: *uchar;
|
||||
cursor: int;
|
||||
size: int;
|
||||
}
|
||||
|
||||
@foreign
|
||||
stbtt_bakedchar :: struct {
|
||||
x0: ushort;
|
||||
y0: ushort;
|
||||
x1: ushort;
|
||||
y1: ushort;
|
||||
xoff: float;
|
||||
yoff: float;
|
||||
xadvance: float;
|
||||
}
|
||||
|
||||
@foreign stbtt_BakeFontBitmap :: proc(data: *uchar, offset: int, pixel_height: float, pixels: *uchar, pw: int, ph: int, first_char: int, num_chars: int, chardata: *stbtt_bakedchar): int;
|
||||
@foreign
|
||||
stbtt_aligned_quad :: struct {
|
||||
x0: float;
|
||||
y0: float;
|
||||
s0: float;
|
||||
t0: float;
|
||||
x1: float;
|
||||
y1: float;
|
||||
s1: float;
|
||||
t1: float;
|
||||
}
|
||||
|
||||
@foreign stbtt_GetBakedQuad :: proc(chardata: *stbtt_bakedchar, pw: int, ph: int, char_index: int, xpos: *float, ypos: *float, q: *stbtt_aligned_quad, opengl_fillrule: int);
|
||||
@foreign stbtt_GetScaledFontVMetrics :: proc(fontdata: *uchar, index: int, size: float, ascent: *float, descent: *float, lineGap: *float);
|
||||
@foreign
|
||||
stbtt_packedchar :: struct {
|
||||
x0: ushort;
|
||||
y0: ushort;
|
||||
x1: ushort;
|
||||
y1: ushort;
|
||||
xoff: float;
|
||||
yoff: float;
|
||||
xadvance: float;
|
||||
xoff2: float;
|
||||
yoff2: float;
|
||||
}
|
||||
|
||||
@foreign stbtt_PackBegin :: proc(spc: *stbtt_pack_context, pixels: *uchar, width: int, height: int, stride_in_bytes: int, padding: int, alloc_context: *void): int;
|
||||
@foreign stbtt_PackEnd :: proc(spc: *stbtt_pack_context);
|
||||
@foreign stbtt_PackFontRange :: proc(spc: *stbtt_pack_context, fontdata: *uchar, font_index: int, font_size: float, first_unicode_char_in_range: int, num_chars_in_range: int, chardata_for_range: *stbtt_packedchar): int;
|
||||
@foreign
|
||||
stbtt_pack_range :: struct {
|
||||
font_size: float;
|
||||
first_unicode_codepoint_in_range: int;
|
||||
array_of_unicode_codepoints: *int;
|
||||
num_chars: int;
|
||||
chardata_for_range: *stbtt_packedchar;
|
||||
h_oversample: uchar;
|
||||
v_oversample: uchar;
|
||||
}
|
||||
|
||||
@foreign stbtt_PackFontRanges :: proc(spc: *stbtt_pack_context, fontdata: *uchar, font_index: int, ranges: *stbtt_pack_range, num_ranges: int): int;
|
||||
@foreign stbtt_PackSetOversampling :: proc(spc: *stbtt_pack_context, h_oversample: uint, v_oversample: uint);
|
||||
@foreign stbtt_PackSetSkipMissingCodepoints :: proc(spc: *stbtt_pack_context, skip: int);
|
||||
@foreign stbtt_GetPackedQuad :: proc(chardata: *stbtt_packedchar, pw: int, ph: int, char_index: int, xpos: *float, ypos: *float, q: *stbtt_aligned_quad, align_to_integer: int);
|
||||
@foreign stbtt_PackFontRangesGatherRects :: proc(spc: *stbtt_pack_context, info: *stbtt_fontinfo, ranges: *stbtt_pack_range, num_ranges: int, rects: *stbrp_rect): int;
|
||||
@foreign stbtt_PackFontRangesPackRects :: proc(spc: *stbtt_pack_context, rects: *stbrp_rect, num_rects: int);
|
||||
@foreign stbtt_PackFontRangesRenderIntoRects :: proc(spc: *stbtt_pack_context, info: *stbtt_fontinfo, ranges: *stbtt_pack_range, num_ranges: int, rects: *stbrp_rect): int;
|
||||
@foreign
|
||||
stbtt_pack_context :: struct {
|
||||
user_allocator_context: *void;
|
||||
pack_info: *void;
|
||||
width: int;
|
||||
height: int;
|
||||
stride_in_bytes: int;
|
||||
padding: int;
|
||||
skip_missing: int;
|
||||
h_oversample: uint;
|
||||
v_oversample: uint;
|
||||
pixels: *uchar;
|
||||
nodes: *void;
|
||||
}
|
||||
|
||||
@foreign stbtt_GetNumberOfFonts :: proc(data: *uchar): int;
|
||||
@foreign stbtt_GetFontOffsetForIndex :: proc(data: *uchar, index: int): int;
|
||||
@foreign
|
||||
stbtt_fontinfo :: struct {
|
||||
userdata: *void;
|
||||
data: *uchar;
|
||||
fontstart: int;
|
||||
numGlyphs: int;
|
||||
loca: int;
|
||||
head: int;
|
||||
glyf: int;
|
||||
hhea: int;
|
||||
hmtx: int;
|
||||
kern: int;
|
||||
gpos: int;
|
||||
svg: int;
|
||||
index_map: int;
|
||||
indexToLocFormat: int;
|
||||
cff: stbtt__buf;
|
||||
charstrings: stbtt__buf;
|
||||
gsubrs: stbtt__buf;
|
||||
subrs: stbtt__buf;
|
||||
fontdicts: stbtt__buf;
|
||||
fdselect: stbtt__buf;
|
||||
}
|
||||
|
||||
@foreign stbtt_InitFont :: proc(info: *stbtt_fontinfo, data: *uchar, offset: int): int;
|
||||
@foreign stbtt_FindGlyphIndex :: proc(info: *stbtt_fontinfo, unicode_codepoint: int): int;
|
||||
@foreign stbtt_ScaleForPixelHeight :: proc(info: *stbtt_fontinfo, pixels: float): float;
|
||||
@foreign stbtt_ScaleForMappingEmToPixels :: proc(info: *stbtt_fontinfo, pixels: float): float;
|
||||
@foreign stbtt_GetFontVMetrics :: proc(info: *stbtt_fontinfo, ascent: *int, descent: *int, lineGap: *int);
|
||||
@foreign stbtt_GetFontVMetricsOS2 :: proc(info: *stbtt_fontinfo, typoAscent: *int, typoDescent: *int, typoLineGap: *int): int;
|
||||
@foreign stbtt_GetFontBoundingBox :: proc(info: *stbtt_fontinfo, x0: *int, y0: *int, x1: *int, y1: *int);
|
||||
@foreign stbtt_GetCodepointHMetrics :: proc(info: *stbtt_fontinfo, codepoint: int, advanceWidth: *int, leftSideBearing: *int);
|
||||
@foreign stbtt_GetCodepointKernAdvance :: proc(info: *stbtt_fontinfo, ch1: int, ch2: int): int;
|
||||
@foreign stbtt_GetCodepointBox :: proc(info: *stbtt_fontinfo, codepoint: int, x0: *int, y0: *int, x1: *int, y1: *int): int;
|
||||
@foreign stbtt_GetGlyphHMetrics :: proc(info: *stbtt_fontinfo, glyph_index: int, advanceWidth: *int, leftSideBearing: *int);
|
||||
@foreign stbtt_GetGlyphKernAdvance :: proc(info: *stbtt_fontinfo, glyph1: int, glyph2: int): int;
|
||||
@foreign stbtt_GetGlyphBox :: proc(info: *stbtt_fontinfo, glyph_index: int, x0: *int, y0: *int, x1: *int, y1: *int): int;
|
||||
@foreign
|
||||
stbtt_kerningentry :: struct {
|
||||
glyph1: int;
|
||||
glyph2: int;
|
||||
advance: int;
|
||||
}
|
||||
|
||||
@foreign stbtt_GetKerningTableLength :: proc(info: *stbtt_fontinfo): int;
|
||||
@foreign stbtt_GetKerningTable :: proc(info: *stbtt_fontinfo, table: *stbtt_kerningentry, table_length: int): int;
|
||||
@foreign
|
||||
stbtt_vertex :: struct {
|
||||
x: short;
|
||||
y: short;
|
||||
cx: short;
|
||||
cy: short;
|
||||
cx1: short;
|
||||
cy1: short;
|
||||
type: uchar;
|
||||
padding: uchar;
|
||||
}
|
||||
|
||||
@foreign stbtt_IsGlyphEmpty :: proc(info: *stbtt_fontinfo, glyph_index: int): int;
|
||||
@foreign stbtt_GetCodepointShape :: proc(info: *stbtt_fontinfo, unicode_codepoint: int, vertices: **stbtt_vertex): int;
|
||||
@foreign stbtt_GetGlyphShape :: proc(info: *stbtt_fontinfo, glyph_index: int, vertices: **stbtt_vertex): int;
|
||||
@foreign stbtt_FreeShape :: proc(info: *stbtt_fontinfo, vertices: *stbtt_vertex);
|
||||
@foreign stbtt_FindSVGDoc :: proc(info: *stbtt_fontinfo, gl: int): *uchar;
|
||||
@foreign stbtt_GetCodepointSVG :: proc(info: *stbtt_fontinfo, unicode_codepoint: int, svg: **char): int;
|
||||
@foreign stbtt_GetGlyphSVG :: proc(info: *stbtt_fontinfo, gl: int, svg: **char): int;
|
||||
@foreign stbtt_FreeBitmap :: proc(bitmap: *uchar, userdata: *void);
|
||||
@foreign stbtt_GetCodepointBitmap :: proc(info: *stbtt_fontinfo, scale_x: float, scale_y: float, codepoint: int, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
|
||||
@foreign stbtt_GetCodepointBitmapSubpixel :: proc(info: *stbtt_fontinfo, scale_x: float, scale_y: float, shift_x: float, shift_y: float, codepoint: int, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
|
||||
@foreign stbtt_MakeCodepointBitmap :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, codepoint: int);
|
||||
@foreign stbtt_MakeCodepointBitmapSubpixel :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, codepoint: int);
|
||||
@foreign stbtt_MakeCodepointBitmapSubpixelPrefilter :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, oversample_x: int, oversample_y: int, sub_x: *float, sub_y: *float, codepoint: int);
|
||||
@foreign stbtt_GetCodepointBitmapBox :: proc(font: *stbtt_fontinfo, codepoint: int, scale_x: float, scale_y: float, ix0: *int, iy0: *int, ix1: *int, iy1: *int);
|
||||
@foreign stbtt_GetCodepointBitmapBoxSubpixel :: proc(font: *stbtt_fontinfo, codepoint: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, ix0: *int, iy0: *int, ix1: *int, iy1: *int);
|
||||
@foreign stbtt_GetGlyphBitmap :: proc(info: *stbtt_fontinfo, scale_x: float, scale_y: float, glyph: int, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
|
||||
@foreign stbtt_GetGlyphBitmapSubpixel :: proc(info: *stbtt_fontinfo, scale_x: float, scale_y: float, shift_x: float, shift_y: float, glyph: int, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
|
||||
@foreign stbtt_MakeGlyphBitmap :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, glyph: int);
|
||||
@foreign stbtt_MakeGlyphBitmapSubpixel :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, glyph: int);
|
||||
@foreign stbtt_MakeGlyphBitmapSubpixelPrefilter :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, oversample_x: int, oversample_y: int, sub_x: *float, sub_y: *float, glyph: int);
|
||||
@foreign stbtt_GetGlyphBitmapBox :: proc(font: *stbtt_fontinfo, glyph: int, scale_x: float, scale_y: float, ix0: *int, iy0: *int, ix1: *int, iy1: *int);
|
||||
@foreign stbtt_GetGlyphBitmapBoxSubpixel :: proc(font: *stbtt_fontinfo, glyph: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, ix0: *int, iy0: *int, ix1: *int, iy1: *int);
|
||||
@foreign
|
||||
stbtt__bitmap :: struct {
|
||||
w: int;
|
||||
h: int;
|
||||
stride: int;
|
||||
pixels: *uchar;
|
||||
}
|
||||
|
||||
@foreign stbtt_Rasterize :: proc(result: *stbtt__bitmap, flatness_in_pixels: float, vertices: *stbtt_vertex, num_verts: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, x_off: int, y_off: int, invert: int, userdata: *void);
|
||||
@foreign stbtt_FreeSDF :: proc(bitmap: *uchar, userdata: *void);
|
||||
@foreign stbtt_GetGlyphSDF :: proc(info: *stbtt_fontinfo, scale: float, glyph: int, padding: int, onedge_value: uchar, pixel_dist_scale: float, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
|
||||
@foreign stbtt_GetCodepointSDF :: proc(info: *stbtt_fontinfo, scale: float, codepoint: int, padding: int, onedge_value: uchar, pixel_dist_scale: float, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
|
||||
@foreign stbtt_FindMatchingFont :: proc(fontdata: *uchar, name: *char, flags: int): int;
|
||||
@foreign stbtt_CompareUTF8toUTF16_bigendian :: proc(s1: *char, len1: int, s2: *char, len2: int): int;
|
||||
@foreign stbtt_GetFontNameString :: proc(font: *stbtt_fontinfo, length: *int, platformID: int, encodingID: int, languageID: int, nameID: int): *char;
|
||||
342
tests/example_ui_and_hot_reloading/dll/ui.lc
Normal file
342
tests/example_ui_and_hot_reloading/dll/ui.lc
Normal file
@@ -0,0 +1,342 @@
|
||||
Ui: UI_State;
|
||||
|
||||
UI_TextAlign :: typedef int;
|
||||
UI_TextAlign_Center :: 0;
|
||||
UI_TextAlign_CenterLeft :: ^;
|
||||
|
||||
|
||||
UI_Layout :: struct {
|
||||
rect: R2P;
|
||||
}
|
||||
|
||||
UI_Widget :: struct {
|
||||
next: *UI_Widget;
|
||||
id: u64;
|
||||
last_touched_frame_index: u64;
|
||||
}
|
||||
|
||||
UI_Cut :: typedef int;
|
||||
UI_Cut_Left :: 0;
|
||||
UI_Cut_Right :: ^;
|
||||
UI_Cut_Top :: ^;
|
||||
UI_Cut_Bottom :: ^;
|
||||
|
||||
UI_Style :: struct {
|
||||
cut_size: V2;
|
||||
text_align: UI_TextAlign;
|
||||
scroll: V2;
|
||||
absolute: bool;
|
||||
absolute_rect: R2P;
|
||||
button_background_color: V4;
|
||||
hot_button_background_color: V4;
|
||||
interacting_with_button_background_color: V4;
|
||||
active_button_background_color: V4;
|
||||
text_color: V4;
|
||||
button_border_color: V4;
|
||||
checked_checkbox_button_background_color: V4;
|
||||
draw_text_shadow: bool;
|
||||
}
|
||||
|
||||
UI_BaseButtonDesc :: struct {
|
||||
text: S8_String;
|
||||
draw_text: bool;
|
||||
draw_border: bool;
|
||||
draw_background: bool;
|
||||
use_checked_checkbox_button_background_colors: bool;
|
||||
}
|
||||
|
||||
UI_Result :: struct {
|
||||
pressed: bool;
|
||||
interacting_with: bool;
|
||||
hot: bool;
|
||||
drag: V2;
|
||||
}
|
||||
|
||||
UI_LayoutStack :: struct {
|
||||
data: [256]UI_Layout;
|
||||
len : i32;
|
||||
}
|
||||
|
||||
UI_State :: struct {
|
||||
cut: UI_Cut;
|
||||
s: UI_Style; // current style
|
||||
base_style: UI_Style;
|
||||
|
||||
// @todo: add stack id concept
|
||||
cached_widgets: LC_Map; // @todo: add removing widgets at end of frame
|
||||
layouts: UI_LayoutStack;
|
||||
|
||||
font: *R_Font;
|
||||
|
||||
hot: u64;
|
||||
interacting_with: u64;
|
||||
id: u64;
|
||||
inside_begin_end_pair: bool;
|
||||
|
||||
// next cut output
|
||||
text_width: f32;
|
||||
text_size: V2;
|
||||
}
|
||||
|
||||
UI_AddLayout :: proc(s: *UI_LayoutStack, layout: UI_Layout) {
|
||||
if s.len + 1 > lengthof(s.data) {
|
||||
IO_FatalErrorf("layout stack overflow reached max item count: %d", lengthof(s.data));
|
||||
}
|
||||
|
||||
s.data[s.len] = layout;
|
||||
s.len += 1;
|
||||
}
|
||||
|
||||
UI_GetLastLayout :: proc(s: *UI_LayoutStack): *UI_Layout {
|
||||
if (s.len == 0) IO_FatalErrorf("error, trying to get last layout but there are none");
|
||||
|
||||
return &s.data[s.len - 1];
|
||||
}
|
||||
|
||||
UI_Begin :: proc() {
|
||||
IO_Assert(Ui.inside_begin_end_pair == false);
|
||||
Ui.inside_begin_end_pair = true;
|
||||
|
||||
IO_Assert(Ui.layouts.len == 0 || Ui.layouts.len == 1);
|
||||
Ui.layouts.len = 0;
|
||||
UI_AddLayout(&Ui.layouts, {R2P_SizeF(0, 0, :f32(Mu.window.size.x), :f32(Mu.window.size.y))});
|
||||
|
||||
UI_SetStyle();
|
||||
}
|
||||
|
||||
UI_SetStyle :: proc() {
|
||||
Ui.font = R.font;
|
||||
Ui.base_style = {
|
||||
cut_size = :V2{-1, Ui.font.size + 4},
|
||||
button_background_color = :V4{0, 0, 0, 1.0},
|
||||
text_color = :V4{1, 1, 1, 1},
|
||||
button_border_color = :V4{1, 1, 1, 1},
|
||||
checked_checkbox_button_background_color = :V4{0.5, 0.5, 0.5, 1.0},
|
||||
hot_button_background_color = :V4{0.5, 0, 0, 1},
|
||||
interacting_with_button_background_color = :V4{1.0, 0, 0, 1},
|
||||
active_button_background_color = :V4{1, 0, 0, 1},
|
||||
};
|
||||
Ui.s = Ui.base_style;
|
||||
}
|
||||
|
||||
UI_End :: proc() {
|
||||
IO_Assert(Ui.inside_begin_end_pair);
|
||||
Ui.inside_begin_end_pair = false;
|
||||
|
||||
if (Mu.window.mouse.left.unpress) {
|
||||
Ui.interacting_with = NULL;
|
||||
}
|
||||
Ui.hot = NULL;
|
||||
}
|
||||
|
||||
R_DrawBorder :: proc(r: R2P, color: V4) {
|
||||
r = R2P_Shrink(r, 1);
|
||||
R_Rect2D(R2P_CutLeft(&r, 1), R.atlas.white_texture_bounding_box, color);
|
||||
R_Rect2D(R2P_CutRight(&r, 1), R.atlas.white_texture_bounding_box, color);
|
||||
R_Rect2D(R2P_CutTop(&r, 1), R.atlas.white_texture_bounding_box, color);
|
||||
R_Rect2D(R2P_CutBottom(&r, 1), R.atlas.white_texture_bounding_box, color);
|
||||
}
|
||||
|
||||
UI_GetNextRect :: proc(text: S8_String): R2P {
|
||||
if (Ui.s.absolute) return Ui.s.absolute_rect;
|
||||
l := UI_GetLastLayout(&Ui.layouts);
|
||||
cut := Ui.s.cut_size;
|
||||
font := Ui.font;
|
||||
|
||||
if (text.len) {
|
||||
Ui.text_width = R_GetTextSize(text);
|
||||
Ui.text_size = :V2{Ui.text_width, font.ascent};
|
||||
}
|
||||
|
||||
if (cut.x < 0) {
|
||||
cut.x = Ui.text_width + 32;
|
||||
if (cut.x < 0) {
|
||||
cut.x = 32;
|
||||
}
|
||||
}
|
||||
|
||||
if (cut.y < 0) {
|
||||
cut.y = font.ascent;
|
||||
}
|
||||
|
||||
if (Ui.cut == UI_Cut_Top || Ui.cut == UI_Cut_Bottom) {
|
||||
scroll_y := F32_Clamp(Ui.s.scroll.y, -cut.y, cut.y);
|
||||
cut.y -= scroll_y;
|
||||
Ui.s.scroll.y -= scroll_y;
|
||||
}
|
||||
|
||||
if (Ui.cut == UI_Cut_Left || Ui.cut == UI_Cut_Right) {
|
||||
scrollx := F32_Clamp(Ui.s.scroll.x, -cut.x, cut.x);
|
||||
cut.x -= scrollx;
|
||||
Ui.s.scroll.x -= scrollx;
|
||||
}
|
||||
|
||||
if (Ui.cut == UI_Cut_Left) {
|
||||
return R2P_CutLeft(&l.rect, cut.x);
|
||||
}
|
||||
if (Ui.cut == UI_Cut_Right) {
|
||||
return R2P_CutRight(&l.rect, cut.x);
|
||||
}
|
||||
if (Ui.cut == UI_Cut_Top) {
|
||||
return R2P_CutTop(&l.rect, cut.y);
|
||||
}
|
||||
if (Ui.cut == UI_Cut_Bottom) {
|
||||
return R2P_CutBottom(&l.rect, cut.y);
|
||||
}
|
||||
IO_InvalidCodepath();
|
||||
return :R2P{};
|
||||
}
|
||||
|
||||
UI_GetWidget :: proc(text: S8_String): *UI_Widget {
|
||||
if (Ui.cached_widgets.allocator.p == NULL) {
|
||||
Ui.cached_widgets.allocator = Perm.allocator;
|
||||
}
|
||||
|
||||
hash := HashBytes(text.str, :u64(text.len));
|
||||
widget: *UI_Widget = LC_MapGetU64(&Ui.cached_widgets, hash);
|
||||
if (!widget) {
|
||||
widget = MA_PushSize(Perm, :usize(sizeof(:UI_Widget)));
|
||||
widget.id = hash;
|
||||
LC_MapInsertU64(&Ui.cached_widgets, hash, widget);
|
||||
}
|
||||
IO_Assert(widget.id == hash);
|
||||
widget.last_touched_frame_index = :u64(Mu.frame);
|
||||
return widget;
|
||||
}
|
||||
|
||||
UI_BaseButton :: proc(desc: UI_BaseButtonDesc): UI_Result {
|
||||
result: UI_Result;
|
||||
rect := UI_GetNextRect(desc.text);
|
||||
|
||||
mouse_pos: V2 = {:f32(Mu.window.mouse.pos.x), :f32(Mu.window.mouse.pos.y)};
|
||||
delta_mouse_pos: V2 = {:f32(Mu.window.mouse.delta_pos.x), :f32(Mu.window.mouse.delta_pos.y)};
|
||||
|
||||
if (rect.min.x == rect.max.x || rect.min.y == rect.max.y) {
|
||||
return result;
|
||||
}
|
||||
|
||||
widget := UI_GetWidget(desc.text);
|
||||
if (R2P_CollidesV2(rect, mouse_pos)) {
|
||||
Ui.hot = widget.id;
|
||||
}
|
||||
|
||||
if (Ui.hot == widget.id) {
|
||||
result.hot = true;
|
||||
if (Mu.window.mouse.left.press) {
|
||||
Ui.interacting_with = widget.id;
|
||||
}
|
||||
}
|
||||
|
||||
if (Ui.interacting_with == widget.id) {
|
||||
result.interacting_with = true;
|
||||
result.drag = delta_mouse_pos;
|
||||
if (Ui.hot == widget.id && Mu.window.mouse.left.unpress) {
|
||||
result.pressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
text_pos := rect.min;
|
||||
rect_size := R2P_GetSize(rect);
|
||||
centered_text_pos := V2_Add(text_pos, V2_DivF(V2_Sub(rect_size, Ui.text_size), 2.0));
|
||||
if (Ui.s.text_align == UI_TextAlign_Center) {
|
||||
text_pos = centered_text_pos;
|
||||
}
|
||||
if (Ui.s.text_align == UI_TextAlign_CenterLeft) {
|
||||
text_pos.y = centered_text_pos.y;
|
||||
text_pos.x += 4;
|
||||
}
|
||||
|
||||
button_background_color: V4 = Ui.s.button_background_color;
|
||||
text_color: V4 = Ui.s.text_color;
|
||||
button_border_color: V4 = Ui.s.button_border_color;
|
||||
|
||||
if (desc.use_checked_checkbox_button_background_colors) {
|
||||
button_background_color = Ui.s.checked_checkbox_button_background_color;
|
||||
}
|
||||
|
||||
if (Ui.hot == widget.id) {
|
||||
button_background_color = Ui.s.hot_button_background_color;
|
||||
}
|
||||
if (Ui.interacting_with == widget.id) {
|
||||
button_background_color = Ui.s.interacting_with_button_background_color;
|
||||
}
|
||||
if (result.pressed) {
|
||||
button_background_color = Ui.s.active_button_background_color;
|
||||
}
|
||||
|
||||
if (desc.draw_background) {
|
||||
R_Rect2D(rect, R.atlas.white_texture_bounding_box, button_background_color);
|
||||
}
|
||||
if (desc.draw_border) {
|
||||
R_DrawBorder(rect, button_border_color);
|
||||
}
|
||||
if (desc.draw_text) {
|
||||
if (Ui.s.draw_text_shadow) {
|
||||
R_Text2D({
|
||||
text = desc.text,
|
||||
color = R_ColorWhite,
|
||||
pos = :V2{text_pos.x + 2, text_pos.y - 2},
|
||||
do_draw = true,
|
||||
scale = 1.0,
|
||||
});
|
||||
}
|
||||
|
||||
R_DrawText(desc.text, text_pos, text_color);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
UI_Button :: proc(str: *char): bool {
|
||||
result := UI_BaseButton({
|
||||
text = S8_MakeFromChar(str),
|
||||
draw_text = true,
|
||||
draw_border = true,
|
||||
draw_background = true,
|
||||
});
|
||||
return result.pressed;
|
||||
}
|
||||
|
||||
UI_Checkbox :: proc(val: *bool, str: *char): bool {
|
||||
result: UI_Result = UI_BaseButton({
|
||||
text = S8_MakeFromChar(str),
|
||||
draw_text = true,
|
||||
draw_border = true,
|
||||
draw_background = true,
|
||||
use_checked_checkbox_button_background_colors = *val,
|
||||
});
|
||||
if (result.pressed) {
|
||||
*val = !*val;
|
||||
}
|
||||
return *val;
|
||||
}
|
||||
|
||||
UI_Fill :: proc() {
|
||||
rect := UI_GetNextRect(S8_MakeEmpty());
|
||||
R_Rect2D(rect, R.atlas.white_texture_bounding_box, Ui.s.button_background_color);
|
||||
R_DrawBorder(rect, Ui.s.button_border_color);
|
||||
}
|
||||
|
||||
UI_PopStyle :: proc() {
|
||||
Ui.s = Ui.base_style;
|
||||
}
|
||||
|
||||
UI_PopLayout :: proc() {
|
||||
if Ui.layouts.len == 0 {
|
||||
IO_FatalError("tryign to pop a layout but layout stack is empty");
|
||||
}
|
||||
Ui.layouts.len -= 1;
|
||||
}
|
||||
|
||||
UI_PushLayout :: proc(rect_override: R2P): R2P {
|
||||
rect: R2P;
|
||||
if (rect_override.min.x != 0 || rect_override.min.y != 0 || rect_override.max.x != 0 || rect_override.max.y != 0) {
|
||||
rect = rect_override;
|
||||
}
|
||||
else {
|
||||
rect = UI_GetNextRect(S8_MakeEmpty());
|
||||
}
|
||||
|
||||
UI_AddLayout(&Ui.layouts, {rect});
|
||||
return rect;
|
||||
}
|
||||
89
tests/example_ui_and_hot_reloading/exe/exe_main.lc
Normal file
89
tests/example_ui_and_hot_reloading/exe/exe_main.lc
Normal file
@@ -0,0 +1,89 @@
|
||||
import "shared";
|
||||
|
||||
Mu: *MU_Context;
|
||||
TempArena: MA_Arena;
|
||||
Temp := &TempArena;
|
||||
|
||||
@foreign RandomSeed :: struct { a: u64; }
|
||||
@foreign GetRandomU64 :: proc(state: *RandomSeed): u64;
|
||||
|
||||
LibraryHotLoad :: struct {
|
||||
reload_count: int;
|
||||
user_context: DLL_Context;
|
||||
library: LIB_Library;
|
||||
update_proc: LibraryUpdate;
|
||||
last_write_time: i64;
|
||||
seed: RandomSeed;
|
||||
init_happened_on_this_frame: bool;
|
||||
}
|
||||
|
||||
ReloadUpdate :: proc(lib: *LibraryHotLoad) {
|
||||
new_write_time := OS_GetFileModTime(S8_MakeFromChar("game.dll"));
|
||||
if new_write_time == -1 || new_write_time == lib.last_write_time {
|
||||
return;
|
||||
}
|
||||
|
||||
if lib.update_proc {
|
||||
lib.update_proc(Unload, Mu, &lib.user_context);
|
||||
lib.update_proc = nil;
|
||||
}
|
||||
|
||||
if (lib.seed.a == 0) lib.seed.a = 13;
|
||||
random_value := GetRandomU64(&lib.seed);
|
||||
out_filename_dll := S8_Format(Temp, "temp_%u.dll", random_value);
|
||||
out_filename_pdb := S8_Format(Temp, "temp_%u.pdb", random_value);
|
||||
OS_CopyFile(S8_MakeFromChar("game.dll"), out_filename_dll, true);
|
||||
OS_CopyFile(S8_MakeFromChar("game.pdb"), out_filename_pdb, true);
|
||||
|
||||
library := LIB_LoadLibrary(out_filename_dll.str);
|
||||
if !library {
|
||||
IO_Printf("Failed to load library %Q\n", out_filename_dll);
|
||||
return;
|
||||
}
|
||||
|
||||
update_proc: LibraryUpdate = LIB_LoadSymbol(library, "APP_Update");
|
||||
if !library {
|
||||
IO_Printf("Failed to load library %Q\n", out_filename_dll);
|
||||
return;
|
||||
}
|
||||
|
||||
lib.library = library;
|
||||
lib.update_proc = update_proc;
|
||||
lib.last_write_time = new_write_time;
|
||||
if lib.reload_count == 0 {
|
||||
lib.update_proc(Init, Mu, &lib.user_context);
|
||||
lib.init_happened_on_this_frame = true;
|
||||
}
|
||||
else {
|
||||
lib.update_proc(Reload, Mu, &lib.user_context);
|
||||
}
|
||||
lib.reload_count += 1;
|
||||
}
|
||||
|
||||
CallUpdate :: proc(lib: *LibraryHotLoad) {
|
||||
ReloadUpdate(lib);
|
||||
if lib.update_proc && !lib.init_happened_on_this_frame {
|
||||
lib.update_proc(Update, Mu, &lib.user_context);
|
||||
}
|
||||
lib.init_happened_on_this_frame = false;
|
||||
}
|
||||
|
||||
main :: proc(): int {
|
||||
Mu = MU_Start({
|
||||
enable_opengl = true,
|
||||
window = {
|
||||
size = {1280, 720}
|
||||
},
|
||||
delta_time = 0.0166666
|
||||
});
|
||||
|
||||
|
||||
lib: LibraryHotLoad = {user_context = {temp = Temp}};
|
||||
for MU_Update(Mu) {
|
||||
CallUpdate(&lib);
|
||||
if (Mu.window.key[MU_KEY_ESCAPE].down) {
|
||||
MU_Quit(Mu);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
557
tests/example_ui_and_hot_reloading/shared/core.lc
Normal file
557
tests/example_ui_and_hot_reloading/shared/core.lc
Normal file
@@ -0,0 +1,557 @@
|
||||
#`
|
||||
|
||||
#include "core/core.c"
|
||||
#include "core/map.c"
|
||||
`;
|
||||
@foreign
|
||||
UTF32_Result :: struct {
|
||||
out_str: u32;
|
||||
advance: int;
|
||||
error: int;
|
||||
}
|
||||
|
||||
@foreign
|
||||
UTF8_Result :: struct {
|
||||
out_str: [4]u8;
|
||||
len: int;
|
||||
error: int;
|
||||
}
|
||||
|
||||
@foreign
|
||||
UTF16_Result :: struct {
|
||||
out_str: [2]u16;
|
||||
len: int;
|
||||
error: int;
|
||||
}
|
||||
|
||||
@foreign
|
||||
UTF8_Iter :: struct {
|
||||
str: *char;
|
||||
len: int;
|
||||
utf8_codepoint_byte_size: int;
|
||||
i: int;
|
||||
item: u32;
|
||||
}
|
||||
|
||||
@foreign UTF_ConvertUTF16ToUTF32 :: proc(c: *u16, max_advance: int): UTF32_Result;
|
||||
@foreign UTF_ConvertUTF32ToUTF8 :: proc(codepoint: u32): UTF8_Result;
|
||||
@foreign UTF_ConvertUTF8ToUTF32 :: proc(c: *char, max_advance: int): UTF32_Result;
|
||||
@foreign UTF_ConvertUTF32ToUTF16 :: proc(codepoint: u32): UTF16_Result;
|
||||
@foreign UTF_CreateCharFromWidechar :: proc(buffer: *char, buffer_size: i64, in: *wchar_t, inlen: i64): i64;
|
||||
@foreign UTF_CreateWidecharFromChar :: proc(buffer: *wchar_t, buffer_size: i64, in: *char, inlen: i64): i64;
|
||||
@foreign UTF8_Advance :: proc(iter: *UTF8_Iter);
|
||||
@foreign UTF8_IterateEx :: proc(str: *char, len: int): UTF8_Iter;
|
||||
@foreign UTF8_Iterate :: proc(str: *char): UTF8_Iter;
|
||||
@foreign UTF_CreateStringFromWidechar :: proc(arena: *MA_Arena, wstr: *wchar_t, wsize: i64): S8_String;
|
||||
|
||||
@foreign
|
||||
IO_ErrorResult :: typedef int;
|
||||
IO_ErrorResult_Continue :: 0;
|
||||
IO_ErrorResult_Break :: ^;
|
||||
IO_ErrorResult_Exit :: ^;
|
||||
|
||||
@foreign IO_Printf :: proc(msg: *char, ...);
|
||||
@foreign IO_Print :: proc(msg: *char);
|
||||
@foreign IO_OutputMessage :: proc(str: *char, len: int);
|
||||
@foreign IO_OutputError :: proc(str: *char, len: int): IO_ErrorResult;
|
||||
@foreign IO_Exit :: proc(error_code: int);
|
||||
@foreign IO_IsDebuggerPresent :: proc(): bool;
|
||||
@foreign
|
||||
M_AllocatorOp :: typedef int;
|
||||
M_AllocatorOp_Allocate :: 0;
|
||||
M_AllocatorOp_Deallocate :: ^;
|
||||
|
||||
@foreign M_AllocatorProc :: typedef proc(a: *void, b: M_AllocatorOp, c: *void, d: usize): *void;
|
||||
@foreign
|
||||
M_Allocator :: struct {
|
||||
obj: *void;
|
||||
p: proc(a: *void, b: M_AllocatorOp, c: *void, d: usize): *void;
|
||||
}
|
||||
|
||||
@foreign M_AllocNonZeroed :: proc(allocator: M_Allocator, size: usize): *void;
|
||||
@foreign M_Alloc :: proc(allocator: M_Allocator, size: usize): *void;
|
||||
@foreign M_AllocCopy :: proc(allocator: M_Allocator, p: *void, size: usize): *void;
|
||||
@foreign M_Dealloc :: proc(allocator: M_Allocator, p: *void);
|
||||
@foreign MA_AllocatorProc :: proc(allocator: M_Allocator, kind: M_AllocatorOp, p: *void, size: usize): *void;
|
||||
@foreign M_GetSystemAllocator :: proc(): M_Allocator;
|
||||
@foreign
|
||||
MV_Memory :: struct {
|
||||
commit: usize;
|
||||
reserve: usize;
|
||||
data: *u8;
|
||||
}
|
||||
|
||||
@foreign
|
||||
MA_Arena :: struct {
|
||||
allocator: M_Allocator;
|
||||
memory: MV_Memory;
|
||||
alignment: int;
|
||||
saved_alignment: int;
|
||||
len: usize;
|
||||
packed_array_element_size: usize;
|
||||
packed_array_begin: usize;
|
||||
}
|
||||
|
||||
@foreign
|
||||
MA_Temp :: struct {
|
||||
arena: *MA_Arena;
|
||||
pos: usize;
|
||||
}
|
||||
|
||||
@foreign MA_MemoryZero :: proc(p: *void, size: usize);
|
||||
@foreign MA_MemoryCopy :: proc(dst: *void, src: *void, size: usize);
|
||||
@foreign MA_GetAlignOffset :: proc(size: usize, align: usize): usize;
|
||||
@foreign MA_AlignUp :: proc(size: usize, align: usize): usize;
|
||||
@foreign MA_AlignDown :: proc(size: usize, align: usize): usize;
|
||||
@foreign MA_DeallocateStub :: proc(arena: *MA_Arena, p: *void);
|
||||
@foreign MA_PopToPos :: proc(arena: *MA_Arena, pos: usize);
|
||||
@foreign MA_PopSize :: proc(arena: *MA_Arena, size: usize): *void;
|
||||
@foreign MA_DeallocateArena :: proc(arena: *MA_Arena);
|
||||
@foreign MA_Reset :: proc(arena: *MA_Arena);
|
||||
@foreign MA__BeginPackedArray :: proc(arena: *MA_Arena, element_size: usize): *void;
|
||||
@foreign MA_EndPackedArray :: proc(arena: *MA_Arena): int;
|
||||
@foreign MA_SetAlignment :: proc(arena: *MA_Arena, alignment: int);
|
||||
@foreign MA_GetTop :: proc(a: *MA_Arena): *u8;
|
||||
@foreign MA_PushSizeNonZeroed :: proc(a: *MA_Arena, size: usize): *void;
|
||||
@foreign MA_PushSize :: proc(arena: *MA_Arena, size: usize): *void;
|
||||
@foreign MA_Init :: proc(a: *MA_Arena, reserve: usize);
|
||||
@foreign MA_Create :: proc(): MA_Arena;
|
||||
@foreign MA_InitFromBuffer :: proc(arena: *MA_Arena, buffer: *void, size: usize);
|
||||
@foreign MA_MakeFromBuffer :: proc(buffer: *void, size: usize): MA_Arena;
|
||||
@foreign MA_PushStringCopy :: proc(arena: *MA_Arena, p: *char, size: usize): *char;
|
||||
@foreign MA_PushCopy :: proc(arena: *MA_Arena, p: *void, size: usize): *void;
|
||||
@foreign MA_IsPointerInside :: proc(arena: *MA_Arena, p: *void): bool;
|
||||
@foreign MA_PushArena :: proc(arena: *MA_Arena, size: usize): MA_Arena;
|
||||
@foreign MA_BeginTemp :: proc(arena: *MA_Arena): MA_Temp;
|
||||
@foreign MA_EndTemp :: proc(checkpoint: MA_Temp);
|
||||
@foreign MA_GetScratchEx :: proc(conflicts: **MA_Arena, conflict_count: int): MA_Temp;
|
||||
@foreign MA_GetScratch :: proc(): MA_Temp;
|
||||
@foreign MA_GetScratch1 :: proc(conflict: *MA_Arena): MA_Temp;
|
||||
@foreign MV_Reserve :: proc(size: usize): MV_Memory;
|
||||
@foreign MV_Commit :: proc(m: *MV_Memory, commit: usize): bool;
|
||||
@foreign MV_Deallocate :: proc(m: *MV_Memory);
|
||||
@foreign MV_DecommitPos :: proc(m: *MV_Memory, pos: usize): bool;
|
||||
@foreign
|
||||
S8_String :: struct {
|
||||
str: *char;
|
||||
len: i64;
|
||||
}
|
||||
|
||||
@foreign
|
||||
S8_Node :: struct {
|
||||
next: *S8_Node;
|
||||
string: S8_String;
|
||||
}
|
||||
|
||||
@foreign
|
||||
S8_List :: struct {
|
||||
node_count: i64;
|
||||
char_count: i64;
|
||||
first: *S8_Node;
|
||||
last: *S8_Node;
|
||||
}
|
||||
|
||||
@foreign S8_AreEqual :: proc(a: S8_String, b: S8_String, ignore_case: uint): bool;
|
||||
@foreign S8_EndsWith :: proc(a: S8_String, end: S8_String, ignore_case: uint): bool;
|
||||
@foreign S8_StartsWith :: proc(a: S8_String, start: S8_String, ignore_case: uint): bool;
|
||||
@foreign S8_Make :: proc(str: *char, len: i64): S8_String;
|
||||
@foreign S8_Copy :: proc(allocator: *MA_Arena, string: S8_String): S8_String;
|
||||
@foreign S8_NormalizePath :: proc(s: S8_String);
|
||||
@foreign S8_Chop :: proc(string: S8_String, len: i64): S8_String;
|
||||
@foreign S8_Skip :: proc(string: S8_String, len: i64): S8_String;
|
||||
@foreign S8_GetPostfix :: proc(string: S8_String, len: i64): S8_String;
|
||||
@foreign S8_GetPrefix :: proc(string: S8_String, len: i64): S8_String;
|
||||
@foreign S8_Slice :: proc(string: S8_String, first_index: i64, one_past_last_index: i64): S8_String;
|
||||
@foreign S8_Trim :: proc(string: S8_String): S8_String;
|
||||
@foreign S8_TrimEnd :: proc(string: S8_String): S8_String;
|
||||
@foreign S8_ToLowerCase :: proc(allocator: *MA_Arena, s: S8_String): S8_String;
|
||||
@foreign S8_ToUpperCase :: proc(allocator: *MA_Arena, s: S8_String): S8_String;
|
||||
@foreign S8_Find :: proc(string: S8_String, find: S8_String, flags: uint, index_out: *i64): bool;
|
||||
@foreign S8_Split :: proc(allocator: *MA_Arena, string: S8_String, find: S8_String, flags: uint): S8_List;
|
||||
@foreign S8_MergeWithSeparator :: proc(allocator: *MA_Arena, list: S8_List, separator: S8_String): S8_String;
|
||||
@foreign S8_Merge :: proc(allocator: *MA_Arena, list: S8_List): S8_String;
|
||||
@foreign S8_ReplaceAll :: proc(allocator: *MA_Arena, string: S8_String, replace: S8_String, with: S8_String, flags: uint): S8_String;
|
||||
@foreign S8_FindAll :: proc(allocator: *MA_Arena, string: S8_String, find: S8_String, flags: uint): S8_List;
|
||||
@foreign S8_ChopLastSlash :: proc(s: S8_String): S8_String;
|
||||
@foreign S8_ChopLastPeriod :: proc(s: S8_String): S8_String;
|
||||
@foreign S8_SkipToLastSlash :: proc(s: S8_String): S8_String;
|
||||
@foreign S8_SkipToLastPeriod :: proc(s: S8_String): S8_String;
|
||||
@foreign S8_Length :: proc(string: *char): i64;
|
||||
@foreign S8_WideLength :: proc(string: *wchar_t): i64;
|
||||
@foreign S8_MakeFromChar :: proc(string: *char): S8_String;
|
||||
@foreign S8_MakeEmpty :: proc(): S8_String;
|
||||
@foreign S8_MakeEmptyList :: proc(): S8_List;
|
||||
@foreign S8_FormatV :: proc(allocator: *MA_Arena, str: *char, args1: va_list): S8_String;
|
||||
@foreign S8_Format :: proc(allocator: *MA_Arena, str: *char, ...): S8_String;
|
||||
@foreign S8_CreateNode :: proc(allocator: *MA_Arena, string: S8_String): *S8_Node;
|
||||
@foreign S8_ReplaceNodeString :: proc(list: *S8_List, node: *S8_Node, new_string: S8_String);
|
||||
@foreign S8_AddExistingNode :: proc(list: *S8_List, node: *S8_Node);
|
||||
@foreign S8_AddArray :: proc(allocator: *MA_Arena, list: *S8_List, array: **char, count: int);
|
||||
@foreign S8_AddArrayWithPrefix :: proc(allocator: *MA_Arena, list: *S8_List, prefix: *char, array: **char, count: int);
|
||||
@foreign S8_MakeList :: proc(allocator: *MA_Arena, a: S8_String): S8_List;
|
||||
@foreign S8_CopyList :: proc(allocator: *MA_Arena, a: S8_List): S8_List;
|
||||
@foreign S8_ConcatLists :: proc(allocator: *MA_Arena, a: S8_List, b: S8_List): S8_List;
|
||||
@foreign S8_AddNode :: proc(allocator: *MA_Arena, list: *S8_List, string: S8_String): *S8_Node;
|
||||
@foreign S8_AddF :: proc(allocator: *MA_Arena, list: *S8_List, str: *char, ...): S8_String;
|
||||
@foreign
|
||||
MU__Float2 :: struct {
|
||||
x: float;
|
||||
y: float;
|
||||
}
|
||||
|
||||
@foreign
|
||||
MU__Int2 :: struct {
|
||||
x: int;
|
||||
y: int;
|
||||
}
|
||||
|
||||
@foreign MU_glGetProcAddress :: typedef proc(a: *char): *void;
|
||||
@foreign
|
||||
MU_Window_Params :: struct {
|
||||
size: MU__Int2;
|
||||
pos: MU__Int2;
|
||||
title: *char;
|
||||
enable_canvas: bool;
|
||||
resizable: bool;
|
||||
borderless: bool;
|
||||
fps_cursor: bool;
|
||||
}
|
||||
|
||||
@foreign
|
||||
MU_Params :: struct {
|
||||
memory: *void;
|
||||
cap: usize;
|
||||
enable_opengl: bool;
|
||||
opengl_major: int;
|
||||
opengl_minor: int;
|
||||
delta_time: double;
|
||||
window: MU_Window_Params;
|
||||
sound_callback: proc(a: *MU_Context, b: *u16, c: u32): void;
|
||||
}
|
||||
|
||||
@foreign
|
||||
MU_Key_State :: struct {
|
||||
down: bool;
|
||||
press: bool;
|
||||
unpress: bool;
|
||||
raw_press: bool;
|
||||
}
|
||||
|
||||
@foreign
|
||||
MU_Key :: typedef int;
|
||||
MU_KEY_INVALID :: 0;
|
||||
MU_KEY_ESCAPE :: ^;
|
||||
MU_KEY_ENTER :: ^;
|
||||
MU_KEY_TAB :: ^;
|
||||
MU_KEY_BACKSPACE :: ^;
|
||||
MU_KEY_INSERT :: ^;
|
||||
MU_KEY_DELETE :: ^;
|
||||
MU_KEY_RIGHT :: ^;
|
||||
MU_KEY_LEFT :: ^;
|
||||
MU_KEY_DOWN :: ^;
|
||||
MU_KEY_UP :: ^;
|
||||
MU_KEY_PAGE_UP :: ^;
|
||||
MU_KEY_PAGE_DOWN :: ^;
|
||||
MU_KEY_HOME :: ^;
|
||||
MU_KEY_END :: ^;
|
||||
MU_KEY_F1 :: ^;
|
||||
MU_KEY_F2 :: ^;
|
||||
MU_KEY_F3 :: ^;
|
||||
MU_KEY_F4 :: ^;
|
||||
MU_KEY_F5 :: ^;
|
||||
MU_KEY_F6 :: ^;
|
||||
MU_KEY_F7 :: ^;
|
||||
MU_KEY_F8 :: ^;
|
||||
MU_KEY_F9 :: ^;
|
||||
MU_KEY_F10 :: ^;
|
||||
MU_KEY_F11 :: ^;
|
||||
MU_KEY_F12 :: ^;
|
||||
MU_KEY_SPACE :: 32;
|
||||
MU_KEY_APOSTROPHE :: 39;
|
||||
MU_KEY_PLUS :: 43;
|
||||
MU_KEY_COMMA :: 44;
|
||||
MU_KEY_MINUS :: 45;
|
||||
MU_KEY_PERIOD :: 46;
|
||||
MU_KEY_SLASH :: 47;
|
||||
MU_KEY_0 :: 48;
|
||||
MU_KEY_1 :: 49;
|
||||
MU_KEY_2 :: 50;
|
||||
MU_KEY_3 :: 51;
|
||||
MU_KEY_4 :: 52;
|
||||
MU_KEY_5 :: 53;
|
||||
MU_KEY_6 :: 54;
|
||||
MU_KEY_7 :: 55;
|
||||
MU_KEY_8 :: 56;
|
||||
MU_KEY_9 :: 57;
|
||||
MU_KEY_SEMICOLON :: 59;
|
||||
MU_KEY_EQUAL :: 61;
|
||||
MU_KEY_A :: 65;
|
||||
MU_KEY_B :: 66;
|
||||
MU_KEY_C :: 67;
|
||||
MU_KEY_D :: 68;
|
||||
MU_KEY_E :: 69;
|
||||
MU_KEY_F :: 70;
|
||||
MU_KEY_G :: 71;
|
||||
MU_KEY_H :: 72;
|
||||
MU_KEY_I :: 73;
|
||||
MU_KEY_J :: 74;
|
||||
MU_KEY_K :: 75;
|
||||
MU_KEY_L :: 76;
|
||||
MU_KEY_M :: 77;
|
||||
MU_KEY_N :: 78;
|
||||
MU_KEY_O :: 79;
|
||||
MU_KEY_P :: 80;
|
||||
MU_KEY_Q :: 81;
|
||||
MU_KEY_R :: 82;
|
||||
MU_KEY_S :: 83;
|
||||
MU_KEY_T :: 84;
|
||||
MU_KEY_U :: 85;
|
||||
MU_KEY_V :: 86;
|
||||
MU_KEY_W :: 87;
|
||||
MU_KEY_X :: 88;
|
||||
MU_KEY_Y :: 89;
|
||||
MU_KEY_Z :: 90;
|
||||
MU_KEY_LEFT_BRACKET :: 91;
|
||||
MU_KEY_BACKSLASH :: 92;
|
||||
MU_KEY_RIGHT_BRACKET :: 93;
|
||||
MU_KEY_GRAVE_ACCENT :: 96;
|
||||
MU_KEY_F13 :: ^;
|
||||
MU_KEY_F14 :: ^;
|
||||
MU_KEY_F15 :: ^;
|
||||
MU_KEY_F16 :: ^;
|
||||
MU_KEY_F17 :: ^;
|
||||
MU_KEY_F18 :: ^;
|
||||
MU_KEY_F19 :: ^;
|
||||
MU_KEY_F20 :: ^;
|
||||
MU_KEY_F21 :: ^;
|
||||
MU_KEY_F22 :: ^;
|
||||
MU_KEY_F23 :: ^;
|
||||
MU_KEY_F24 :: ^;
|
||||
MU_KEY_KP_0 :: ^;
|
||||
MU_KEY_KP_1 :: ^;
|
||||
MU_KEY_KP_2 :: ^;
|
||||
MU_KEY_KP_3 :: ^;
|
||||
MU_KEY_KP_4 :: ^;
|
||||
MU_KEY_KP_5 :: ^;
|
||||
MU_KEY_KP_6 :: ^;
|
||||
MU_KEY_KP_7 :: ^;
|
||||
MU_KEY_KP_8 :: ^;
|
||||
MU_KEY_KP_9 :: ^;
|
||||
MU_KEY_KP_DECIMAL :: ^;
|
||||
MU_KEY_KP_DIVIDE :: ^;
|
||||
MU_KEY_KP_MULTIPLY :: ^;
|
||||
MU_KEY_KP_SUBTRACT :: ^;
|
||||
MU_KEY_KP_ADD :: ^;
|
||||
MU_KEY_KP_ENTER :: ^;
|
||||
MU_KEY_LEFT_SHIFT :: ^;
|
||||
MU_KEY_LEFT_CONTROL :: ^;
|
||||
MU_KEY_LEFT_ALT :: ^;
|
||||
MU_KEY_LEFT_SUPER :: ^;
|
||||
MU_KEY_RIGHT_SHIFT :: ^;
|
||||
MU_KEY_RIGHT_CONTROL :: ^;
|
||||
MU_KEY_RIGHT_ALT :: ^;
|
||||
MU_KEY_RIGHT_SUPER :: ^;
|
||||
MU_KEY_CAPS_LOCK :: ^;
|
||||
MU_KEY_SCROLL_LOCK :: ^;
|
||||
MU_KEY_NUM_LOCK :: ^;
|
||||
MU_KEY_PRINT_SCREEN :: ^;
|
||||
MU_KEY_PAUSE :: ^;
|
||||
MU_KEY_SHIFT :: ^;
|
||||
MU_KEY_CONTROL :: ^;
|
||||
MU_KEY_COUNT :: ^;
|
||||
|
||||
@foreign
|
||||
MU_Mouse_State :: struct {
|
||||
pos: MU__Int2;
|
||||
posf: MU__Float2;
|
||||
delta_pos: MU__Int2;
|
||||
delta_pos_normalized: MU__Float2;
|
||||
left: MU_Key_State;
|
||||
middle: MU_Key_State;
|
||||
right: MU_Key_State;
|
||||
delta_wheel: float;
|
||||
}
|
||||
|
||||
@foreign
|
||||
MU_DroppedFile :: struct {
|
||||
next: *MU_DroppedFile;
|
||||
filename: *char;
|
||||
filename_size: int;
|
||||
}
|
||||
|
||||
@foreign
|
||||
MU_Arena :: struct {
|
||||
memory: *char;
|
||||
len: usize;
|
||||
cap: usize;
|
||||
}
|
||||
|
||||
@foreign
|
||||
MU_Window :: struct {
|
||||
size: MU__Int2;
|
||||
sizef: MU__Float2;
|
||||
pos: MU__Int2;
|
||||
posf: MU__Float2;
|
||||
dpi_scale: float;
|
||||
is_fullscreen: bool;
|
||||
is_fps_mode: bool;
|
||||
is_focused: bool;
|
||||
change_cursor_on_mouse_hold: bool;
|
||||
processed_events_this_frame: u64;
|
||||
should_render: bool;
|
||||
first_dropped_file: *MU_DroppedFile;
|
||||
canvas: *u32;
|
||||
canvas_enabled: bool;
|
||||
mouse: MU_Mouse_State;
|
||||
key: [140]MU_Key_State;
|
||||
user_text32: [32]u32;
|
||||
user_text32_count: int;
|
||||
user_text8: [32]char;
|
||||
user_text8_count: int;
|
||||
next: *MU_Window;
|
||||
handle: *void;
|
||||
platform: *void;
|
||||
}
|
||||
|
||||
@foreign
|
||||
MU_Time :: struct {
|
||||
app_start: double;
|
||||
frame_start: double;
|
||||
update: double;
|
||||
update_total: double;
|
||||
delta: double;
|
||||
deltaf: float;
|
||||
total: double;
|
||||
totalf: float;
|
||||
}
|
||||
|
||||
@foreign
|
||||
MU_Sound :: struct {
|
||||
initialized: bool;
|
||||
samples_per_second: uint;
|
||||
number_of_channels: uint;
|
||||
bytes_per_sample: uint;
|
||||
callback: proc(a: *MU_Context, b: *u16, c: u32): void;
|
||||
}
|
||||
|
||||
@foreign
|
||||
MU_Context :: struct {
|
||||
quit: bool;
|
||||
sound: MU_Sound;
|
||||
time: MU_Time;
|
||||
first_frame: bool;
|
||||
_MU_Update_count: int;
|
||||
frame: usize;
|
||||
consecutive_missed_frames: usize;
|
||||
total_missed_frames: usize;
|
||||
primary_monitor_size: MU__Int2;
|
||||
opengl_initialized: bool;
|
||||
opengl_major: int;
|
||||
opengl_minor: int;
|
||||
gl_get_proc_address: proc(a: *char): *void;
|
||||
params: MU_Params;
|
||||
window: *MU_Window;
|
||||
all_windows: *MU_Window;
|
||||
perm_arena: MU_Arena;
|
||||
frame_arena: MU_Arena;
|
||||
platform: *void;
|
||||
}
|
||||
|
||||
@foreign MU_Quit :: proc(mu: *MU_Context);
|
||||
@foreign MU_DefaultSoundCallback :: proc(mu: *MU_Context, buffer: *u16, samples_to_fill: u32);
|
||||
@foreign MU_GetTime :: proc(): double;
|
||||
@foreign MU_ToggleFPSMode :: proc(window: *MU_Window);
|
||||
@foreign MU_DisableFPSMode :: proc(window: *MU_Window);
|
||||
@foreign MU_EnableFPSMode :: proc(window: *MU_Window);
|
||||
@foreign MU_ToggleFullscreen :: proc(window: *MU_Window);
|
||||
@foreign MU_Init :: proc(mu: *MU_Context, params: MU_Params, len: usize);
|
||||
@foreign MU_AddWindow :: proc(mu: *MU_Context, params: MU_Window_Params): *MU_Window;
|
||||
@foreign MU_InitWindow :: proc(mu: *MU_Context, window: *MU_Window, params: MU_Window_Params);
|
||||
@foreign MU_Start :: proc(params: MU_Params): *MU_Context;
|
||||
@foreign MU_Update :: proc(mu: *MU_Context): bool;
|
||||
@foreign LIB_Library :: typedef *void;
|
||||
@foreign LIB_LoadLibrary :: proc(str: *char): LIB_Library;
|
||||
@foreign LIB_LoadSymbol :: proc(lib: LIB_Library, symbol: *char): *void;
|
||||
@foreign LIB_UnloadLibrary :: proc(lib: LIB_Library): bool;
|
||||
@foreign
|
||||
CTX_Context :: struct {
|
||||
heap: M_Allocator;
|
||||
temp_alloc: M_Allocator;
|
||||
perm_alloc: M_Allocator;
|
||||
temp: *MA_Arena;
|
||||
perm: *MA_Arena;
|
||||
temporary_arena: MA_Arena;
|
||||
pernament_arena: MA_Arena;
|
||||
user_context: *void;
|
||||
}
|
||||
|
||||
@foreign CTX_Init :: proc();
|
||||
@foreign
|
||||
OS_Result :: typedef int;
|
||||
OS_SUCCESS :: 0;
|
||||
OS_ALREADY_EXISTS :: ^;
|
||||
OS_PATH_NOT_FOUND :: ^;
|
||||
OS_FAILURE :: ^;
|
||||
|
||||
@foreign
|
||||
OS_Date :: struct {
|
||||
year: u32;
|
||||
month: u32;
|
||||
day: u32;
|
||||
hour: u32;
|
||||
minute: u32;
|
||||
second: u32;
|
||||
milliseconds: u32;
|
||||
}
|
||||
|
||||
@foreign OS_IsAbsolute :: proc(path: S8_String): bool;
|
||||
@foreign OS_GetExePath :: proc(arena: *MA_Arena): S8_String;
|
||||
@foreign OS_GetExeDir :: proc(arena: *MA_Arena): S8_String;
|
||||
@foreign OS_GetWorkingDir :: proc(arena: *MA_Arena): S8_String;
|
||||
@foreign OS_SetWorkingDir :: proc(path: S8_String);
|
||||
@foreign OS_GetAbsolutePath :: proc(arena: *MA_Arena, relative: S8_String): S8_String;
|
||||
@foreign OS_FileExists :: proc(path: S8_String): bool;
|
||||
@foreign OS_IsDir :: proc(path: S8_String): bool;
|
||||
@foreign OS_IsFile :: proc(path: S8_String): bool;
|
||||
@foreign OS_GetTime :: proc(): double;
|
||||
@foreign OS_ListDir :: proc(arena: *MA_Arena, path: S8_String, flags: uint): S8_List;
|
||||
@foreign OS_MakeDir :: proc(path: S8_String): OS_Result;
|
||||
@foreign OS_CopyFile :: proc(from: S8_String, to: S8_String, overwrite: bool): OS_Result;
|
||||
@foreign OS_DeleteFile :: proc(path: S8_String): OS_Result;
|
||||
@foreign OS_DeleteDir :: proc(path: S8_String, flags: uint): OS_Result;
|
||||
@foreign OS_AppendFile :: proc(path: S8_String, string: S8_String): OS_Result;
|
||||
@foreign OS_WriteFile :: proc(path: S8_String, string: S8_String): OS_Result;
|
||||
@foreign OS_ReadFile :: proc(arena: *MA_Arena, path: S8_String): S8_String;
|
||||
@foreign OS_SystemF :: proc(string: *char, ...): int;
|
||||
@foreign OS_GetFileModTime :: proc(file: S8_String): i64;
|
||||
@foreign OS_GetDate :: proc(): OS_Date;
|
||||
@foreign S8_SplitOnRegex :: proc(arena: *MA_Arena, string: S8_String, regex: S8_String, flags: uint): S8_List;
|
||||
@foreign OS_ListDirRegex :: proc(arena: *MA_Arena, path: S8_String, flags: uint, regex: *char): S8_List;
|
||||
@foreign OS_ListDirRegexAsString :: proc(arena: *MA_Arena, path: S8_String, flags: uint, regex: *char): S8_String;
|
||||
@foreign OS_ExpandIncludesList :: proc(arena: *MA_Arena, out: *S8_List, filepath: S8_String): bool;
|
||||
@foreign OS_ExpandIncludes :: proc(arena: *MA_Arena, filepath: S8_String): S8_String;
|
||||
@foreign
|
||||
LC_MapEntry :: struct {
|
||||
key: u64;
|
||||
value: u64;
|
||||
}
|
||||
|
||||
@foreign
|
||||
LC_Map :: struct {
|
||||
allocator: M_Allocator;
|
||||
entries: *LC_MapEntry;
|
||||
cap: int;
|
||||
len: int;
|
||||
}
|
||||
|
||||
@foreign LC_MapReserve :: proc(map: *LC_Map, size: int);
|
||||
@foreign LC_GetMapEntryEx :: proc(map: *LC_Map, key: u64): *LC_MapEntry;
|
||||
@foreign LC_InsertMapEntry :: proc(map: *LC_Map, key: u64, value: u64): *LC_MapEntry;
|
||||
@foreign LC_GetMapEntry :: proc(map: *LC_Map, key: u64): *LC_MapEntry;
|
||||
@foreign LC_MapInsert :: proc(map: *LC_Map, keystr: S8_String, value: *void);
|
||||
@foreign LC_MapGet :: proc(map: *LC_Map, keystr: S8_String): *void;
|
||||
@foreign LC_MapInsertU64 :: proc(map: *LC_Map, keystr: u64, value: *void);
|
||||
@foreign LC_MapGetU64 :: proc(map: *LC_Map, keystr: u64): *void;
|
||||
@foreign LC_MapGetP :: proc(map: *LC_Map, key: *void): *void;
|
||||
@foreign LC_MapInsertP :: proc(map: *LC_Map, key: *void, value: *void);
|
||||
@foreign Map_Insert2P :: proc(map: *LC_Map, key: *void, value: *void);
|
||||
13
tests/example_ui_and_hot_reloading/shared/events.lc
Normal file
13
tests/example_ui_and_hot_reloading/shared/events.lc
Normal file
@@ -0,0 +1,13 @@
|
||||
LibraryUpdate :: typedef proc(event: LibraryEvent, mu: *MU_Context, context: *DLL_Context);
|
||||
|
||||
LibraryEvent :: typedef int;
|
||||
Init :: 0;
|
||||
Reload :: ^;
|
||||
Unload :: ^;
|
||||
Update :: ^;
|
||||
|
||||
DLL_Context :: struct {
|
||||
temp: *MA_Arena;
|
||||
perm: MA_Arena;
|
||||
context: *void;
|
||||
}
|
||||
34
tests/example_ui_and_hot_reloading/shared/windows_types.lc
Normal file
34
tests/example_ui_and_hot_reloading/shared/windows_types.lc
Normal file
@@ -0,0 +1,34 @@
|
||||
#`#include <stdint.h>`;
|
||||
|
||||
@foreign(int8_t) i8 :: typedef char;
|
||||
@foreign(int16_t) i16 :: typedef short;
|
||||
@foreign(int32_t) i32 :: typedef int;
|
||||
@foreign(int64_t) i64 :: typedef llong;
|
||||
|
||||
@foreign(uint8_t) u8 :: typedef uchar;
|
||||
@foreign(uint16_t) u16 :: typedef ushort;
|
||||
@foreign(uint32_t) u32 :: typedef uint;
|
||||
@foreign(uint64_t) u64 :: typedef ullong;
|
||||
|
||||
@foreign(size_t) usize :: typedef u64;
|
||||
@foreign(intptr_t) isize :: typedef i64;
|
||||
@foreign(intptr_t) intptr :: typedef i64;
|
||||
@foreign(uintptr_t) uintptr :: typedef u64;
|
||||
|
||||
@weak @foreign f32 :: typedef float;
|
||||
@weak @foreign f64 :: typedef double;
|
||||
|
||||
@foreign wchar_t :: typedef u16;
|
||||
@foreign va_list :: typedef u64;
|
||||
|
||||
NULL :: 0;
|
||||
|
||||
@foreign UINT64_MAX: u64;
|
||||
@foreign UINT32_MAX: u32;
|
||||
@foreign UINT16_MAX: u16;
|
||||
@foreign UINT8_MAX: u8;
|
||||
|
||||
@foreign INT64_MAX: i64;
|
||||
@foreign INT32_MAX: i32;
|
||||
@foreign INT16_MAX: i16;
|
||||
@foreign INT8_MAX: i8;
|
||||
Reference in New Issue
Block a user