Merge branch 'main' into clang-format

This commit is contained in:
Reuben Dunnington 2023-08-18 08:31:35 -07:00
commit a931f08067
Signed by: rdunnington
GPG Key ID: 4EC5290E704FD482
132 changed files with 18723 additions and 19705 deletions

1
.gitignore vendored
View File

@ -28,7 +28,6 @@ src/orca_surface.c
src/graphics/orca_gl31.h
*bind_gen.c
*_stubs.c
gles_gen.log
.vscode/launch.json
.vscode/settings.json

45
orca
View File

@ -7,24 +7,45 @@ import os
import sys
root = True
try:
os.stat(".orcaroot")
except FileNotFoundError:
root = False
if __name__ != "__main__":
print("why are you importing the orca command-line tool as a Python module, you absolute goofball")
exit(1)
if root:
# Running from Orca source checkout; use local source's scripts.
scriptdir = os.path.dirname(os.path.abspath(__file__))
if scriptdir != os.getcwd():
# Only print this warning if running the system-installed Orca.
# It's annoying to see this if you run ./orca from the source.
# If you modify this, be sure to modify the version in scripts/dev.py as well.
def check_if_source():
def path_is_in_orca_source(path):
dir = path
while True:
try:
os.stat(os.path.join(dir, ".orcaroot"))
return (True, dir)
except FileNotFoundError:
pass
newdir = os.path.dirname(dir)
if newdir == dir:
return (False, None)
dir = newdir
in_source, current_source_dir = path_is_in_orca_source(os.getcwd())
script_is_source, script_source_dir = path_is_in_orca_source(os.path.dirname(os.path.abspath(__file__)))
use_source = in_source or script_is_source
source_dir = current_source_dir or script_source_dir
return (use_source, source_dir, script_is_source)
use_source, source_dir, is_source = check_if_source()
if use_source:
# Use the source checkout's scripts instead of the system-installed scripts.
if not is_source:
print("The Orca tool is running from a local source checkout and will")
print("use that instead of the system Orca installation.")
print()
sys.path.append(os.getcwd())
sys.path.append(source_dir)
import scripts.orca
else:
# Running from outside Orca source checkout; use system Orca install.

View File

@ -162,23 +162,23 @@ GLuint compile_shader(const char* vs, const char* fs)
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if(status != GL_TRUE)
{
log_error("program failed to link: ");
oc_log_error("program failed to link: ");
int logSize = 0;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logSize);
mem_arena_scope scratch = mem_scratch_begin();
char* log = mem_arena_alloc(scratch.arena, logSize);
oc_arena_scope scratch = oc_scratch_begin();
char* log = oc_arena_push(scratch.arena, logSize);
glGetProgramInfoLog(prog, logSize, 0, log);
log_error("%s\n", log);
oc_log_error("%s\n", log);
mem_scratch_end(scratch);
oc_scratch_end(scratch);
}
int err = glGetError();
if(err)
{
log_error("gl error %i\n", err);
oc_log_error("gl error %i\n", err);
}
return(prog);
@ -186,7 +186,7 @@ GLuint compile_shader(const char* vs, const char* fs)
void init_advect(advect_program* program)
{
log_info("compiling advect...");
oc_log_info("compiling advect...");
program->prog = compile_shader(glsl_common_vertex, glsl_advect);
program->pos = glGetAttribLocation(program->prog, "pos");
program->src = glGetUniformLocation(program->prog, "src");
@ -197,7 +197,7 @@ void init_advect(advect_program* program)
void init_div(div_program* program)
{
log_info("compiling div...");
oc_log_info("compiling div...");
program->prog = compile_shader(glsl_common_vertex, glsl_divergence);
program->pos = glGetAttribLocation(program->prog, "pos");
program->src = glGetUniformLocation(program->prog, "src");
@ -205,7 +205,7 @@ void init_div(div_program* program)
void init_jacobi(jacobi_program* program)
{
log_info("compiling jacobi...");
oc_log_info("compiling jacobi...");
program->prog = compile_shader(glsl_common_vertex, glsl_jacobi_step);
program->pos = glGetAttribLocation(program->prog, "pos");
program->xTex = glGetUniformLocation(program->prog, "xTex");
@ -214,7 +214,7 @@ void init_jacobi(jacobi_program* program)
void init_multigrid_restrict_residual(multigrid_restrict_residual_program* program)
{
log_info("compiling multigrid restrict residual...");
oc_log_info("compiling multigrid restrict residual...");
program->prog = compile_shader(glsl_common_vertex, glsl_multigrid_restrict_residual);
program->pos = glGetAttribLocation(program->prog, "pos");
program->xTex = glGetUniformLocation(program->prog, "xTex");
@ -223,7 +223,7 @@ void init_multigrid_restrict_residual(multigrid_restrict_residual_program* progr
void init_multigrid_correct(multigrid_correct_program* program)
{
log_info("compiling multigrid correct...");
oc_log_info("compiling multigrid correct...");
program->prog = compile_shader(glsl_common_vertex, glsl_multigrid_correct);
program->pos = glGetAttribLocation(program->prog, "pos");
program->src = glGetUniformLocation(program->prog, "src");
@ -233,7 +233,7 @@ void init_multigrid_correct(multigrid_correct_program* program)
void init_subtract(subtract_program* program)
{
log_info("compiling subtract...");
oc_log_info("compiling subtract...");
program->prog = compile_shader(glsl_common_vertex, glsl_subtract_pressure);
program->pos = glGetAttribLocation(program->prog, "pos");
program->src = glGetUniformLocation(program->prog, "src");
@ -243,7 +243,7 @@ void init_subtract(subtract_program* program)
void init_splat(splat_program* program)
{
log_info("compiling splat...");
oc_log_info("compiling splat...");
program->prog = compile_shader(glsl_common_vertex, glsl_splat);
program->pos = glGetAttribLocation(program->prog, "pos");
program->src = glGetUniformLocation(program->prog, "src");
@ -257,7 +257,7 @@ void init_splat(splat_program* program)
void init_blit(blit_program* program)
{
log_info("compiling blit...");
oc_log_info("compiling blit...");
program->prog = compile_shader(glsl_blit_vertex, glsl_blit_fragment);
program->pos = glGetAttribLocation(program->prog, "pos");
program->mvp = glGetUniformLocation(program->prog, "mvp");
@ -267,7 +267,7 @@ void init_blit(blit_program* program)
void init_blit_div(blit_program* program)
{
log_info("compiling blit div...");
oc_log_info("compiling blit div...");
program->prog = compile_shader(glsl_blit_div_vertex, glsl_blit_div_fragment);
program->pos = glGetAttribLocation(program->prog, "pos");
program->mvp = glGetUniformLocation(program->prog, "mvp");
@ -276,7 +276,7 @@ void init_blit_div(blit_program* program)
void init_blit_residue(blit_residue_program* program)
{
log_info("compiling blit residue...");
oc_log_info("compiling blit residue...");
program->prog = compile_shader(glsl_blit_div_vertex, glsl_blit_residue_fragment);
program->pos = glGetAttribLocation(program->prog, "pos");
program->mvp = glGetUniformLocation(program->prog, "mvp");
@ -325,7 +325,7 @@ void init_frame_buffer(frame_buffer* framebuffer,
GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(err != GL_FRAMEBUFFER_COMPLETE)
{
log_info("Frame buffer incomplete, %i", err);
oc_log_info("Frame buffer incomplete, %i", err);
}
}
@ -372,7 +372,7 @@ static bool resetCmd = false;
void reset()
{
// resetCmd = true;
log_info("reset");
oc_log_info("reset");
reset_texture(colorBuffer.textures[0], texWidth, texHeight, (char*)colorInitData);
reset_texture(colorBuffer.textures[1], texWidth, texHeight, (char*)colorInitData);
@ -407,17 +407,17 @@ int frameWidth = 800;
int frameHeight = 600;
ORCA_EXPORT void OnMouseDown(int button)
ORCA_EXPORT void oc_on_mouse_down(int button)
{
mouseInput.down = true;
}
ORCA_EXPORT void OnMouseUp(int button)
ORCA_EXPORT void oc_on_mouse_up(int button)
{
mouseInput.down = false;
}
ORCA_EXPORT void OnMouseMove(float x, float y, float dx, float dy)
ORCA_EXPORT void oc_on_mouse_move(float x, float y, float dx, float dy)
{
mouseInput.x = x * 2;
mouseInput.y = y * 2;
@ -611,14 +611,14 @@ void input_splat(float t)
float testDiv[texWidth/2][texWidth/2][4];
mg_surface surface;
oc_surface surface;
ORCA_EXPORT void OnInit()
ORCA_EXPORT void oc_on_init()
{
log_info("Hello, world (from C)");
oc_log_info("Hello, world (from C)");
surface = mg_surface_gles();
mg_surface_prepare(surface);
surface = oc_surface_gles();
oc_surface_select(surface);
// init_color_checker();
// init_velocity_vortex();
@ -637,17 +637,17 @@ ORCA_EXPORT void OnInit()
init_blit_div(&blitDivProgram);
// init frame buffers
log_info("create color buffer");
oc_log_info("create color buffer");
init_frame_buffer(&colorBuffer, texWidth, texHeight, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, (char*)colorInitData);
log_info("create velocity buffer");
oc_log_info("create velocity buffer");
init_frame_buffer(&velocityBuffer, texWidth, texHeight, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, (char*)velocityInitData);
int gridFactor = 1;
for(int i=0; i<MULTIGRID_COUNT; i++)
{
log_info("create div buffer %i", i);
oc_log_info("create div buffer %i", i);
init_frame_buffer(&divBuffer[i], texWidth/gridFactor, texHeight/gridFactor, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, 0);
log_info("create pressure buffer %i", i);
oc_log_info("create pressure buffer %i", i);
init_frame_buffer(&pressureBuffer[i], texWidth/gridFactor, texHeight/gridFactor, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, 0);
gridFactor *= 2;
}
@ -682,20 +682,20 @@ ORCA_EXPORT void OnInit()
}
}
ORCA_EXPORT void OnFrameResize(u32 width, u32 height)
ORCA_EXPORT void oc_on_resize(u32 width, u32 height)
{
frameWidth = width*2;
frameHeight = height*2;
}
ORCA_EXPORT void OnFrameRefresh()
ORCA_EXPORT void oc_on_frame_refresh()
{
float aspectRatio = texWidth/texHeight; //TODO replace with actual aspect ratio?
static float t = 0;
t += 1./60.;
mg_surface_prepare(surface);
oc_surface_select(surface);
glViewport(0, 0, texWidth, texHeight);
@ -925,5 +925,5 @@ ORCA_EXPORT void OnFrameRefresh()
//*/
mg_surface_present(surface);
oc_surface_present(surface);
}

View File

@ -2,9 +2,9 @@
#include <orca.h>
vec2 frameSize = {100, 100};
oc_vec2 frameSize = {100, 100};
mg_surface surface;
oc_surface surface;
unsigned int program;
@ -31,26 +31,24 @@ void compile_shader(GLuint shader, const char* source)
int err = glGetError();
if(err)
{
log_info("gl error");
oc_log_info("gl error");
}
}
char* ORCA_IMPORT(orca_mem_grow)(u64 size);
ORCA_EXPORT void OnInit(void)
ORCA_EXPORT void oc_on_init(void)
{
surface = mg_surface_gles();
mg_surface_prepare(surface);
surface = oc_surface_gles();
oc_surface_select(surface);
const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
log_info("GLES extensions: %s\n", extensions);
oc_log_info("GLES extensions: %s\n", extensions);
int extensionCount = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount);
for(int i=0; i<extensionCount; i++)
{
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
log_info("GLES extension %i: %s\n", i, extension);
oc_log_info("GLES extension %i: %s\n", i, extension);
}
unsigned int vshader = glCreateShader(GL_VERTEX_SHADER);
@ -78,18 +76,18 @@ ORCA_EXPORT void OnInit(void)
glEnableVertexAttribArray(0);
}
ORCA_EXPORT void OnFrameResize(u32 width, u32 height)
ORCA_EXPORT void oc_on_resize(u32 width, u32 height)
{
log_info("frame resize %u, %u", width, height);
oc_log_info("frame resize %u, %u", width, height);
frameSize.x = width;
frameSize.y = height;
}
ORCA_EXPORT void OnFrameRefresh(void)
ORCA_EXPORT void oc_on_frame_refresh(void)
{
f32 aspect = frameSize.x/frameSize.y;
mg_surface_prepare(surface);
oc_surface_select(surface);
glClearColor(0, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
@ -108,5 +106,5 @@ ORCA_EXPORT void OnFrameRefresh(void)
glDrawArrays(GL_TRIANGLES, 0, 3);
mg_surface_present(surface);
oc_surface_present(surface);
}

View File

@ -13,13 +13,13 @@ const f32 BLOCK_WIDTH = (BLOCKS_WIDTH - ((NUM_BLOCKS_PER_ROW + 1) * BLOCKS_PADDI
#define PADDLE_MAX_LAUNCH_ANGLE 0.7f
const mg_color paddleColor = { 1, 0, 0, 1 };
mp_rect paddle = { 300, 50, 200, 24 };
const oc_color paddleColor = { 1, 0, 0, 1 };
oc_rect paddle = { 300, 50, 200, 24 };
const mg_color ballColor = { 1, 1, 0, 1 };
mp_rect ball = { 200, 200, 20, 20 };
const oc_color ballColor = { 1, 1, 0, 1 };
oc_rect ball = { 200, 200, 20, 20 };
vec2 velocity = { 5, 5 };
oc_vec2 velocity = { 5, 5 };
// This is upside down from how it will actually be drawn.
int blockHealth[NUM_BLOCKS] = {
@ -31,128 +31,128 @@ int blockHealth[NUM_BLOCKS] = {
3, 3, 3, 3, 3, 3, 3
};
vec2 frameSize = { 100, 100 };
oc_vec2 frameSize = { 100, 100 };
bool leftDown = false;
bool rightDown = false;
mg_surface surface;
mg_canvas canvas;
mg_image waterImage;
mg_image ballImage;
mg_image paddleImage;
mg_font pongFont;
oc_surface surface;
oc_canvas canvas;
oc_image waterImage;
oc_image ballImage;
oc_image paddleImage;
oc_font pongFont;
f32 lerp(f32 a, f32 b, f32 t);
mp_rect blockRect(int i);
int checkCollision(mp_rect block);
mg_mat2x3 flipY(mp_rect r);
mg_mat2x3 flipYAt(vec2 pos);
oc_rect blockRect(int i);
int checkCollision(oc_rect block);
oc_mat2x3 flipY(oc_rect r);
oc_mat2x3 flipYAt(oc_vec2 pos);
str8 loadFile(mem_arena* arena, str8 filename)
oc_str8 loadFile(oc_arena* arena, oc_str8 filename)
{
file_handle file = file_open(filename, FILE_ACCESS_READ, 0);
if(file_last_error(file) != IO_OK)
oc_file file = oc_file_open(filename, OC_FILE_ACCESS_READ, 0);
if(oc_file_last_error(file) != OC_IO_OK)
{
log_error("Couldn't open file %s\n", str8_to_cstring(mem_scratch(), filename));
oc_log_error("Couldn't open file %s\n", oc_str8_to_cstring(oc_scratch(), filename));
}
u64 size = file_size(file);
char* buffer = mem_arena_alloc(arena, size);
file_read(file, size, buffer);
file_close(file);
return str8_from_buffer(size, buffer);
u64 size = oc_file_size(file);
char* buffer = oc_arena_push(arena, size);
oc_file_read(file, size, buffer);
oc_file_close(file);
return oc_str8_from_buffer(size, buffer);
}
ORCA_EXPORT void OnInit(void)
ORCA_EXPORT void oc_on_init(void)
{
surface = mg_surface_canvas();
canvas = mg_canvas_create();
surface = oc_surface_canvas();
canvas = oc_canvas_create();
waterImage = mg_image_create_from_data(surface, loadFile(mem_scratch(), STR8("/underwater.jpg")), false);
ballImage = mg_image_create_from_data(surface, loadFile(mem_scratch(), STR8("/ball.png")), false);
paddleImage = mg_image_create_from_data(surface, loadFile(mem_scratch(), STR8("/wall.png")), false);
waterImage = oc_image_create_from_memory(surface, loadFile(oc_scratch(), OC_STR8("/underwater.jpg")), false);
ballImage = oc_image_create_from_memory(surface, loadFile(oc_scratch(), OC_STR8("/ball.png")), false);
paddleImage = oc_image_create_from_memory(surface, loadFile(oc_scratch(), OC_STR8("/wall.png")), false);
if(mg_image_is_nil(waterImage))
if(oc_image_is_nil(waterImage))
{
log_error("couldn't load water image\n");
oc_log_error("couldn't load water image\n");
}
if(mg_image_is_nil(ballImage))
if(oc_image_is_nil(ballImage))
{
log_error("couldn't load ball image\n");
oc_log_error("couldn't load ball image\n");
}
if(mg_image_is_nil(paddleImage))
if(oc_image_is_nil(paddleImage))
{
log_error("couldn't load paddle image\n");
oc_log_error("couldn't load paddle image\n");
}
str8 fontStr = loadFile(mem_scratch(), STR8("/Literata-SemiBoldItalic.ttf"));
unicode_range ranges[5] = { UNICODE_RANGE_BASIC_LATIN,
UNICODE_RANGE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT,
UNICODE_RANGE_LATIN_EXTENDED_A,
UNICODE_RANGE_LATIN_EXTENDED_B,
UNICODE_RANGE_SPECIALS };
//NOTE(ben): Weird that images are "create from data" but fonts are "create from memory"
//TODO: Decide whether we're using strings or explicit pointer + length
pongFont = mg_font_create_from_memory(fontStr.len, (byte*)fontStr.ptr, 5, ranges);
oc_str8 fontStr = loadFile(oc_scratch(), OC_STR8("/Literata-SemiBoldItalic.ttf"));
oc_unicode_range ranges[5] = { OC_UNICODE_BASIC_LATIN,
OC_UNICODE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT,
OC_UNICODE_LATIN_EXTENDED_A,
OC_UNICODE_LATIN_EXTENDED_B,
OC_UNICODE_SPECIALS };
// NOTE(ben): Weird that images are "create from data" but fonts are "create from memory"
// TODO: Decide whether we're using strings or explicit pointer + length
pongFont = oc_font_create_from_memory(fontStr, 5, ranges);
mem_arena_clear(mem_scratch());
oc_arena_clear(oc_scratch());
}
ORCA_EXPORT void OnFrameResize(u32 width, u32 height)
ORCA_EXPORT void oc_on_resize(u32 width, u32 height)
{
log_info("frame resize %u, %u", width, height);
oc_log_info("frame resize %u, %u", width, height);
frameSize.x = width;
frameSize.y = height;
}
ORCA_EXPORT void OnMouseDown(int button)
ORCA_EXPORT void oc_on_mouse_down(int button)
{
log_info("mouse down!");
oc_log_info("mouse down!");
}
ORCA_EXPORT void OnKeyDown(int key)
ORCA_EXPORT void oc_on_key_down(int key)
{
if(key == MP_KEY_SPACE)
if(key == OC_KEY_SPACE)
{
log_error("(this is just for testing errors)");
oc_log_error("(this is just for testing errors)");
return;
}
if(key == MP_KEY_ENTER)
if(key == OC_KEY_ENTER)
{
log_warning("(this is just for testing warning)");
oc_log_warning("(this is just for testing warning)");
return;
}
log_info("key down: %i", key);
if(key == MP_KEY_LEFT)
oc_log_info("key down: %i", key);
if(key == OC_KEY_LEFT)
{
leftDown = true;
}
if(key == MP_KEY_RIGHT)
if(key == OC_KEY_RIGHT)
{
rightDown = true;
}
}
ORCA_EXPORT void OnKeyUp(int key)
ORCA_EXPORT void oc_on_key_up(int key)
{
if(key == MP_KEY_ENTER || key == MP_KEY_SPACE)
if(key == OC_KEY_ENTER || key == OC_KEY_SPACE)
{
return;
}
log_info("key up: %i", key);
if(key == MP_KEY_LEFT)
oc_log_info("key up: %i", key);
if(key == OC_KEY_LEFT)
{
leftDown = false;
}
if(key == MP_KEY_RIGHT)
if(key == OC_KEY_RIGHT)
{
rightDown = false;
}
}
ORCA_EXPORT void OnFrameRefresh(void)
ORCA_EXPORT void oc_on_frame_refresh(void)
{
f32 aspect = frameSize.x / frameSize.y;
@ -164,12 +164,12 @@ ORCA_EXPORT void OnFrameRefresh(void)
{
paddle.x += 10;
}
paddle.x = Clamp(paddle.x, 0, frameSize.x - paddle.w);
paddle.x = oc_clamp(paddle.x, 0, frameSize.x - paddle.w);
ball.x += velocity.x;
ball.y += velocity.y;
ball.x = Clamp(ball.x, 0, frameSize.x - ball.w);
ball.y = Clamp(ball.y, 0, frameSize.y - ball.h);
ball.x = oc_clamp(ball.x, 0, frameSize.x - ball.w);
ball.y = oc_clamp(ball.y, 0, frameSize.y - ball.h);
if(ball.x + ball.w >= frameSize.x)
{
@ -190,13 +190,13 @@ ORCA_EXPORT void OnFrameRefresh(void)
f32 t = ((ball.x + ball.w / 2) - paddle.x) / paddle.w;
f32 launchAngle = lerp(-PADDLE_MAX_LAUNCH_ANGLE, PADDLE_MAX_LAUNCH_ANGLE, t);
f32 speed = sqrtf(velocity.x * velocity.x + velocity.y * velocity.y);
velocity = (vec2){
velocity = (oc_vec2){
sinf(launchAngle) * speed,
cosf(launchAngle) * speed,
};
ball.y = paddle.y + paddle.h;
log_info("PONG!");
oc_log_info("PONG!");
}
if(ball.y <= 0)
@ -212,11 +212,11 @@ ORCA_EXPORT void OnFrameRefresh(void)
continue;
}
mp_rect r = blockRect(i);
oc_rect r = blockRect(i);
int result = checkCollision(r);
if(result)
{
log_info("Collision! direction=%d", result);
oc_log_info("Collision! direction=%d", result);
blockHealth[i] -= 1;
f32 vx = velocity.x;
@ -246,19 +246,19 @@ ORCA_EXPORT void OnFrameRefresh(void)
}
}
mg_canvas_set_current(canvas);
oc_canvas_set_current(canvas);
mg_set_color_rgba(10.0f / 255.0f, 31.0f / 255.0f, 72.0f / 255.0f, 1);
mg_clear();
oc_set_color_rgba(10.0f / 255.0f, 31.0f / 255.0f, 72.0f / 255.0f, 1);
oc_clear();
mg_image_draw(waterImage, (mp_rect){ 0, 0, frameSize.x, frameSize.y });
oc_image_draw(waterImage, (oc_rect){ 0, 0, frameSize.x, frameSize.y });
mg_mat2x3 yUp = {
oc_mat2x3 yUp = {
1, 0, 0,
0, -1, frameSize.y
};
mg_matrix_push(yUp);
oc_matrix_push(yUp);
{
for(int i = 0; i < NUM_BLOCKS; i++)
{
@ -267,55 +267,55 @@ ORCA_EXPORT void OnFrameRefresh(void)
continue;
}
mp_rect r = blockRect(i);
mg_set_color_rgba(0, 0, 0, 0.2);
mg_rounded_rectangle_fill(r.x, r.y - 2, r.w, r.h, 4);
mg_set_color_rgba(0.9, 0.9, 0.9, 1);
mg_rounded_rectangle_fill(r.x, r.y, r.w, r.h, 4);
oc_rect r = blockRect(i);
oc_set_color_rgba(0, 0, 0, 0.2);
oc_rounded_rectangle_fill(r.x, r.y - 2, r.w, r.h, 4);
oc_set_color_rgba(0.9, 0.9, 0.9, 1);
oc_rounded_rectangle_fill(r.x, r.y, r.w, r.h, 4);
int fontSize = 18;
str8 text = str8_pushf(mem_scratch(),
"%d", blockHealth[i]);
mp_rect textRect = mg_text_bounding_box(pongFont, fontSize, text);
oc_str8 text = oc_str8_pushf(oc_scratch(),
"%d", blockHealth[i]);
oc_rect textRect = oc_text_bounding_box(pongFont, fontSize, text);
vec2 textPos = {
oc_vec2 textPos = {
r.x + r.w / 2 - textRect.w / 2,
r.y + 9, // TODO: mg_text_bounding_box is returning extremely wack results for height.
r.y + 9, // TODO: oc_text_bounding_box is returning extremely wack results for height.
};
mg_set_color_rgba(0, 0, 0, 1);
mg_set_font(pongFont);
mg_set_font_size(18);
mg_move_to(textPos.x, textPos.y);
mg_matrix_push(flipYAt(textPos));
oc_set_color_rgba(0, 0, 0, 1);
oc_set_font(pongFont);
oc_set_font_size(18);
oc_move_to(textPos.x, textPos.y);
oc_matrix_push(flipYAt(textPos));
{
mg_text_outlines(text);
mg_fill();
oc_text_outlines(text);
oc_fill();
}
mg_matrix_pop();
oc_matrix_pop();
}
mg_set_color_rgba(0.9, 0.9, 0.9, 1);
mg_rounded_rectangle_fill(paddle.x, paddle.y, paddle.w, paddle.h, 4);
oc_set_color_rgba(0.9, 0.9, 0.9, 1);
oc_rounded_rectangle_fill(paddle.x, paddle.y, paddle.w, paddle.h, 4);
mg_matrix_push(flipY(ball));
oc_matrix_push(flipY(ball));
{
mg_image_draw(ballImage, ball);
oc_image_draw(ballImage, ball);
}
mg_matrix_pop();
oc_matrix_pop();
}
mg_matrix_pop();
oc_matrix_pop();
mg_surface_prepare(surface);
mg_render(surface, canvas);
mg_surface_present(surface);
oc_surface_select(surface);
oc_render(surface, canvas);
oc_surface_present(surface);
}
mp_rect blockRect(int i)
oc_rect blockRect(int i)
{
int row = i / NUM_BLOCKS_PER_ROW;
int col = i % NUM_BLOCKS_PER_ROW;
return (mp_rect){
return (oc_rect){
BLOCKS_PADDING + (BLOCKS_PADDING + BLOCK_WIDTH) * col,
BLOCKS_BOTTOM + (BLOCKS_PADDING + BLOCK_HEIGHT) * row,
BLOCK_WIDTH,
@ -325,7 +325,7 @@ mp_rect blockRect(int i)
// Returns a cardinal direction 1-8 for the collision with the block, or zero
// if no collision. 1 is straight up and directions proceed clockwise.
int checkCollision(mp_rect block)
int checkCollision(oc_rect block)
{
// Note that all the logic for this game has the origin in the bottom left.
@ -358,8 +358,8 @@ int checkCollision(mp_rect block)
//
// We assume significant tunneling can't happen.
vec2 ballCenter = (vec2){ ball.x + ball.w / 2, ball.y + ball.h / 2 };
vec2 blockCenter = (vec2){ block.x + block.w / 2, block.y + block.h / 2 };
oc_vec2 ballCenter = (oc_vec2){ ball.x + ball.w / 2, ball.y + ball.h / 2 };
oc_vec2 blockCenter = (oc_vec2){ block.x + block.w / 2, block.y + block.h / 2 };
// Moving right
if(velocity.x > 0)
@ -457,17 +457,17 @@ f32 lerp(f32 a, f32 b, f32 t)
return (1 - t) * a + t * b;
}
mg_mat2x3 flipY(mp_rect r)
oc_mat2x3 flipY(oc_rect r)
{
return (mg_mat2x3){
return (oc_mat2x3){
1, 0, 0,
0, -1, 2 * r.y + r.h
};
}
mg_mat2x3 flipYAt(vec2 pos)
oc_mat2x3 flipYAt(oc_vec2 pos)
{
return (mg_mat2x3){
return (oc_mat2x3){
1, 0, 0,
0, -1, 2 * pos.y
};

View File

@ -1,230 +1,229 @@
#include"orca.h"
vec2 frameSize = {100, 100};
oc_vec2 frameSize = {100, 100};
mg_surface surface;
mg_canvas canvas;
mg_font font;
ui_context ui;
mem_arena textArena = {0};
oc_surface surface;
oc_canvas canvas;
oc_font font;
oc_ui_context ui;
oc_arena textArena = {0};
ORCA_EXPORT void OnInit(void)
ORCA_EXPORT void oc_on_init(void)
{
//TODO create surface for main window
surface = mg_surface_canvas();
canvas = mg_canvas_create();
ui_init(&ui);
surface = oc_surface_canvas();
canvas = oc_canvas_create();
oc_ui_init(&ui);
//NOTE: load font
{
file_handle file = file_open(STR8("/OpenSansLatinSubset.ttf"), FILE_ACCESS_READ, 0);
if(file_last_error(file) != IO_OK)
oc_file file = oc_file_open(OC_STR8("/OpenSansLatinSubset.ttf"), OC_FILE_ACCESS_READ, 0);
if(oc_file_last_error(file) != OC_IO_OK)
{
log_error("Couldn't open file OpenSansLatinSubset.ttf\n");
oc_log_error("Couldn't open file OpenSansLatinSubset.ttf\n");
}
u64 size = file_size(file);
char* buffer = mem_arena_alloc(mem_scratch(), size);
file_read(file, size, buffer);
file_close(file);
unicode_range ranges[5] = {UNICODE_RANGE_BASIC_LATIN,
UNICODE_RANGE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT,
UNICODE_RANGE_LATIN_EXTENDED_A,
UNICODE_RANGE_LATIN_EXTENDED_B,
UNICODE_RANGE_SPECIALS};
u64 size = oc_file_size(file);
char* buffer = oc_arena_push(oc_scratch(), size);
oc_file_read(file, size, buffer);
oc_file_close(file);
oc_unicode_range ranges[5] = {OC_UNICODE_BASIC_LATIN,
OC_UNICODE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT,
OC_UNICODE_LATIN_EXTENDED_A,
OC_UNICODE_LATIN_EXTENDED_B,
OC_UNICODE_SPECIALS};
// TODO: Decide whether we're using strings or explicit pointer + length
font = mg_font_create_from_memory(size, (byte*)buffer, 5, ranges);
font = oc_font_create_from_memory(oc_str8_from_buffer(size, buffer), 5, ranges);
}
mem_arena_clear(mem_scratch());
mem_arena_init(&textArena);
oc_arena_clear(oc_scratch());
oc_arena_init(&textArena);
}
ORCA_EXPORT void OnFrameResize(u32 width, u32 height)
ORCA_EXPORT void oc_on_resize(u32 width, u32 height)
{
log_info("frame resize %u, %u", width, height);
oc_log_info("frame resize %u, %u", width, height);
frameSize.x = width;
frameSize.y = height;
}
ORCA_EXPORT void OnRawEvent(mp_event *event)
ORCA_EXPORT void oc_on_raw_event(oc_event *event)
{
ui_process_event(event);
oc_ui_process_event(event);
}
void widget_begin_view(char* str)
{
ui_style_next(&(ui_style){.layout.axis = UI_AXIS_Y,
oc_ui_style_next(&(oc_ui_style){.layout.axis = OC_UI_AXIS_Y,
.layout.spacing = 10,
.layout.margin.x = 10,
.layout.margin.y = 10,
.layout.align.x = UI_ALIGN_CENTER,
.layout.align.y = UI_ALIGN_START},
UI_STYLE_LAYOUT);
.layout.align.x = OC_UI_ALIGN_CENTER,
.layout.align.y = OC_UI_ALIGN_START},
OC_UI_STYLE_LAYOUT);
ui_box_begin(str, UI_FLAG_DRAW_BORDER);
ui_label(str);
oc_ui_box_begin(str, OC_UI_FLAG_DRAW_BORDER);
oc_ui_label(str);
}
void widget_end_view(void)
{
ui_box_end();
oc_ui_box_end();
}
#define widget_view(s) defer_loop(widget_begin_view(s), widget_end_view())
#define widget_view(s) oc_defer_loop(widget_begin_view(s), widget_end_view())
ORCA_EXPORT void OnFrameRefresh(void)
ORCA_EXPORT void oc_on_frame_refresh(void)
{
ui_style defaultStyle = {.bgColor = {0},
oc_ui_style defaultStyle = {.bgColor = {0},
.color = {1, 1, 1, 1},
.font = font,
.fontSize = 16,
.borderColor = {0.278, 0.333, 0.412, 1},
.borderSize = 2};
ui_style_mask defaultMask = UI_STYLE_BG_COLOR
| UI_STYLE_COLOR
| UI_STYLE_BORDER_COLOR
| UI_STYLE_BORDER_SIZE
| UI_STYLE_FONT
| UI_STYLE_FONT_SIZE;
oc_ui_style_mask defaultMask = OC_UI_STYLE_BG_COLOR
| OC_UI_STYLE_COLOR
| OC_UI_STYLE_BORDER_COLOR
| OC_UI_STYLE_BORDER_SIZE
| OC_UI_STYLE_FONT
| OC_UI_STYLE_FONT_SIZE;
ui_frame(frameSize, &defaultStyle, defaultMask)
oc_ui_frame(frameSize, &defaultStyle, defaultMask)
{
ui_style_match_before(ui_pattern_all(), &defaultStyle, defaultMask);
oc_ui_style_match_before(oc_ui_pattern_all(), &defaultStyle, defaultMask);
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_PARENT, 1},
.layout.axis = UI_AXIS_Y,
.layout.align.x = UI_ALIGN_CENTER,
.layout.align.y = UI_ALIGN_START,
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PARENT, 1},
.size.height = {OC_UI_SIZE_PARENT, 1},
.layout.axis = OC_UI_AXIS_Y,
.layout.align.x = OC_UI_ALIGN_CENTER,
.layout.align.y = OC_UI_ALIGN_START,
.layout.spacing = 10,
.layout.margin.x = 10,
.layout.margin.y = 10,
.bgColor = {0.11, 0.11, 0.11, 1}},
UI_STYLE_SIZE
| UI_STYLE_LAYOUT
| UI_STYLE_BG_COLOR);
OC_UI_STYLE_SIZE
| OC_UI_STYLE_LAYOUT
| OC_UI_STYLE_BG_COLOR);
ui_container("background", UI_FLAG_DRAW_BACKGROUND)
oc_ui_container("background", OC_UI_FLAG_DRAW_BACKGROUND)
{
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_CHILDREN},
.layout.align.x = UI_ALIGN_CENTER},
UI_STYLE_SIZE
|UI_STYLE_LAYOUT_ALIGN_X);
ui_container("title", 0)
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PARENT, 1},
.size.height = {OC_UI_SIZE_CHILDREN},
.layout.align.x = OC_UI_ALIGN_CENTER},
OC_UI_STYLE_SIZE
|OC_UI_STYLE_LAYOUT_ALIGN_X);
oc_ui_container("title", 0)
{
ui_style_next(&(ui_style){.fontSize = 26}, UI_STYLE_FONT_SIZE);
ui_label("Orca UI Demo");
oc_ui_style_next(&(oc_ui_style){.fontSize = 26}, OC_UI_STYLE_FONT_SIZE);
oc_ui_label("Orca UI Demo");
if(ui_box_sig(ui_box_top()).hovering)
if(oc_ui_box_sig(oc_ui_box_top()).hovering)
{
ui_tooltip("tooltip")
oc_ui_tooltip("tooltip")
{
ui_style_next(&(ui_style){.bgColor = {1, 0.99, 0.82, 1}},
UI_STYLE_BG_COLOR);
oc_ui_style_next(&(oc_ui_style){.bgColor = {1, 0.99, 0.82, 1}},
OC_UI_STYLE_BG_COLOR);
ui_container("background", UI_FLAG_DRAW_BACKGROUND)
oc_ui_container("background", OC_UI_FLAG_DRAW_BACKGROUND)
{
ui_style_next(&(ui_style){.color = {0, 0, 0, 1}},
UI_STYLE_COLOR);
oc_ui_style_next(&(oc_ui_style){.color = {0, 0, 0, 1}},
OC_UI_STYLE_COLOR);
ui_label("That is a tooltip!");
oc_ui_label("That is a tooltip!");
}
}
}
}
ui_menu_bar("Menu bar")
oc_ui_menu_bar("Menu bar")
{
ui_menu("Menu 1")
oc_ui_menu("Menu 1")
{
if(ui_menu_button("Option 1.1").pressed)
if(oc_ui_menu_button("Option 1.1").pressed)
{
log_info("Pressed option 1.1\n");
oc_log_info("Pressed option 1.1\n");
}
ui_menu_button("Option 1.2");
ui_menu_button("Option 1.3");
ui_menu_button("Option 1.4");
oc_ui_menu_button("Option 1.2");
oc_ui_menu_button("Option 1.3");
oc_ui_menu_button("Option 1.4");
}
ui_menu("Menu 2")
oc_ui_menu("Menu 2")
{
ui_menu_button("Option 2.1");
ui_menu_button("Option 2.2");
ui_menu_button("Option 2.3");
ui_menu_button("Option 2.4");
oc_ui_menu_button("Option 2.1");
oc_ui_menu_button("Option 2.2");
oc_ui_menu_button("Option 2.3");
oc_ui_menu_button("Option 2.4");
}
ui_menu("Menu 3")
oc_ui_menu("Menu 3")
{
ui_menu_button("Option 3.1");
ui_menu_button("Option 3.2");
ui_menu_button("Option 3.3");
ui_menu_button("Option 3.4");
oc_ui_menu_button("Option 3.1");
oc_ui_menu_button("Option 3.2");
oc_ui_menu_button("Option 3.3");
oc_ui_menu_button("Option 3.4");
}
}
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_PARENT, 1, 1}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PARENT, 1},
.size.height = {OC_UI_SIZE_PARENT, 1, 1}},
OC_UI_STYLE_SIZE);
ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X}, UI_STYLE_LAYOUT_AXIS);
ui_container("contents", 0)
oc_ui_style_next(&(oc_ui_style){.layout.axis = OC_UI_AXIS_X}, OC_UI_STYLE_LAYOUT_AXIS);
oc_ui_container("contents", 0)
{
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 0.5},
.size.height = {UI_SIZE_PARENT, 1}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PARENT, 0.5},
.size.height = {OC_UI_SIZE_PARENT, 1}},
OC_UI_STYLE_SIZE);
ui_container("left", 0)
oc_ui_container("left", 0)
{
ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X,
oc_ui_style_next(&(oc_ui_style){.layout.axis = OC_UI_AXIS_X,
.layout.spacing = 10,
.layout.margin.x = 10,
.layout.margin.y = 10,
.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_PARENT, 0.5}},
UI_STYLE_LAYOUT_AXIS
|UI_STYLE_LAYOUT_SPACING
|UI_STYLE_LAYOUT_MARGIN_X
|UI_STYLE_LAYOUT_MARGIN_Y
|UI_STYLE_SIZE);
.size.width = {OC_UI_SIZE_PARENT, 1},
.size.height = {OC_UI_SIZE_PARENT, 0.5}},
OC_UI_STYLE_LAYOUT_AXIS
|OC_UI_STYLE_LAYOUT_SPACING
|OC_UI_STYLE_LAYOUT_MARGIN_X
|OC_UI_STYLE_LAYOUT_MARGIN_Y
|OC_UI_STYLE_SIZE);
ui_container("up", 0)
oc_ui_container("up", 0)
{
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 0.5},
.size.height = {UI_SIZE_PARENT, 1}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PARENT, 0.5},
.size.height = {OC_UI_SIZE_PARENT, 1}},
OC_UI_STYLE_SIZE);
widget_view("Buttons")
{
if(ui_button("Button A").clicked)
if(oc_ui_button("Button A").clicked)
{
log_info("A clicked");
oc_log_info("A clicked");
}
if(ui_button("Button B").clicked)
if(oc_ui_button("Button B").clicked)
{
log_info("B clicked");
oc_log_info("B clicked");
}
if(ui_button("Button C").clicked)
if(oc_ui_button("Button C").clicked)
{
log_info("C clicked");
oc_log_info("C clicked");
}
}
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 0.5},
.size.height = {UI_SIZE_PARENT, 1}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PARENT, 0.5},
.size.height = {OC_UI_SIZE_PARENT, 1}},
OC_UI_STYLE_SIZE);
ui_pattern pattern = {0};
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TAG, .tag = ui_tag_make("checkbox")});
ui_style_match_after(pattern,
&(ui_style){.bgColor = {0, 1, 0, 1},
oc_ui_pattern pattern = {0};
oc_ui_pattern_push(oc_scratch(), &pattern, (oc_ui_selector){.kind = OC_UI_SEL_TAG, .tag = oc_ui_tag_make("checkbox")});
oc_ui_style_match_after(pattern,
&(oc_ui_style){.bgColor = {0, 1, 0, 1},
.color = {1, 1, 1, 1}},
UI_STYLE_COLOR | UI_STYLE_BG_COLOR);
OC_UI_STYLE_COLOR | OC_UI_STYLE_BG_COLOR);
widget_view("checkboxes")
{
@ -232,156 +231,156 @@ ORCA_EXPORT void OnFrameRefresh(void)
static bool check2 = false;
static bool check3 = false;
ui_checkbox("check1", &check1);
ui_checkbox("check2", &check2);
ui_checkbox("check3", &check3);
oc_ui_checkbox("check1", &check1);
oc_ui_checkbox("check2", &check2);
oc_ui_checkbox("check3", &check3);
}
}
ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X,
.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_PARENT, 0.5}},
UI_STYLE_LAYOUT_AXIS
|UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.layout.axis = OC_UI_AXIS_X,
.size.width = {OC_UI_SIZE_PARENT, 1},
.size.height = {OC_UI_SIZE_PARENT, 0.5}},
OC_UI_STYLE_LAYOUT_AXIS
|OC_UI_STYLE_SIZE);
ui_container("down", 0)
oc_ui_container("down", 0)
{
widget_view("Vertical Sliders")
{
ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X,
oc_ui_style_next(&(oc_ui_style){.layout.axis = OC_UI_AXIS_X,
.layout.spacing = 10},
UI_STYLE_LAYOUT_AXIS
|UI_STYLE_LAYOUT_SPACING);
ui_container("contents", 0)
OC_UI_STYLE_LAYOUT_AXIS
|OC_UI_STYLE_LAYOUT_SPACING);
oc_ui_container("contents", 0)
{
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 20},
.size.height = {UI_SIZE_PIXELS, 200}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PIXELS, 20},
.size.height = {OC_UI_SIZE_PIXELS, 200}},
OC_UI_STYLE_SIZE);
static f32 slider1 = 0;
ui_slider("slider1", 0.2, &slider1);
oc_ui_slider("slider1", 0.2, &slider1);
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 20},
.size.height = {UI_SIZE_PIXELS, 200}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PIXELS, 20},
.size.height = {OC_UI_SIZE_PIXELS, 200}},
OC_UI_STYLE_SIZE);
static f32 slider2 = 0;
ui_slider("slider2", 0.2, &slider2);
oc_ui_slider("slider2", 0.2, &slider2);
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 20},
.size.height = {UI_SIZE_PIXELS, 200}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PIXELS, 20},
.size.height = {OC_UI_SIZE_PIXELS, 200}},
OC_UI_STYLE_SIZE);
static f32 slider3 = 0;
ui_slider("slider3", 0.2, &slider3);
oc_ui_slider("slider3", 0.2, &slider3);
}
}
widget_view("Horizontal Sliders")
{
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 200},
.size.height = {UI_SIZE_PIXELS, 20}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PIXELS, 200},
.size.height = {OC_UI_SIZE_PIXELS, 20}},
OC_UI_STYLE_SIZE);
static f32 slider1 = 0;
ui_slider("slider1", 0.2, &slider1);
oc_ui_slider("slider1", 0.2, &slider1);
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 200},
.size.height = {UI_SIZE_PIXELS, 20}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PIXELS, 200},
.size.height = {OC_UI_SIZE_PIXELS, 20}},
OC_UI_STYLE_SIZE);
static f32 slider2 = 0;
ui_slider("slider2", 0.2, &slider2);
oc_ui_slider("slider2", 0.2, &slider2);
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 200},
.size.height = {UI_SIZE_PIXELS, 20}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PIXELS, 200},
.size.height = {OC_UI_SIZE_PIXELS, 20}},
OC_UI_STYLE_SIZE);
static f32 slider3 = 0;
ui_slider("slider3", 0.2, &slider3);
oc_ui_slider("slider3", 0.2, &slider3);
}
}
}
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 0.5},
.size.height = {UI_SIZE_PARENT, 1}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PARENT, 0.5},
.size.height = {OC_UI_SIZE_PARENT, 1}},
OC_UI_STYLE_SIZE);
ui_container("right", 0)
oc_ui_container("right", 0)
{
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_PARENT, 0.33}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PARENT, 1},
.size.height = {OC_UI_SIZE_PARENT, 0.33}},
OC_UI_STYLE_SIZE);
widget_view("Text box")
{
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 300},
.size.height = {UI_SIZE_TEXT}},
UI_STYLE_SIZE);
static str8 text = {0};
ui_text_box_result res = ui_text_box("textbox", mem_scratch(), text);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PIXELS, 300},
.size.height = {OC_UI_SIZE_TEXT}},
OC_UI_STYLE_SIZE);
static oc_str8 text = {0};
oc_ui_text_box_result res = oc_ui_text_box("textbox", oc_scratch(), text);
if(res.changed)
{
mem_arena_clear(&textArena);
text = str8_push_copy(&textArena, res.text);
oc_arena_clear(&textArena);
text = oc_str8_push_copy(&textArena, res.text);
}
}
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_PARENT, 0.33}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PARENT, 1},
.size.height = {OC_UI_SIZE_PARENT, 0.33}},
OC_UI_STYLE_SIZE);
widget_view("Test")
{
ui_pattern pattern = {0};
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TEXT, .text = STR8("panel")});
ui_style_match_after(pattern, &(ui_style){.bgColor = {0.3, 0.3, 1, 1}}, UI_STYLE_BG_COLOR);
oc_ui_pattern pattern = {0};
oc_ui_pattern_push(oc_scratch(), &pattern, (oc_ui_selector){.kind = OC_UI_SEL_TEXT, .text = OC_STR8("panel")});
oc_ui_style_match_after(pattern, &(oc_ui_style){.bgColor = {0.3, 0.3, 1, 1}}, OC_UI_STYLE_BG_COLOR);
static int selected = 0;
str8 options[] = {STR8("option 1"),
STR8("option 2"),
STR8("long option 3"),
STR8("option 4"),
STR8("option 5")};
ui_select_popup_info info = {.selectedIndex = selected,
oc_str8 options[] = {OC_STR8("option 1"),
OC_STR8("option 2"),
OC_STR8("long option 3"),
OC_STR8("option 4"),
OC_STR8("option 5")};
oc_ui_select_popup_info info = {.selectedIndex = selected,
.optionCount = 5,
.options = options};
ui_select_popup_info result = ui_select_popup("popup", &info);
oc_ui_select_popup_info result = oc_ui_select_popup("popup", &info);
selected = result.selectedIndex;
}
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_PARENT, 0.33}},
UI_STYLE_SIZE);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PARENT, 1},
.size.height = {OC_UI_SIZE_PARENT, 0.33}},
OC_UI_STYLE_SIZE);
widget_view("Color")
{
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_PARENT, 0.7},
.layout.axis = UI_AXIS_X},
UI_STYLE_SIZE
|UI_STYLE_LAYOUT_AXIS);
oc_ui_style_next(&(oc_ui_style){.size.width = {OC_UI_SIZE_PARENT, 1},
.size.height = {OC_UI_SIZE_PARENT, 0.7},
.layout.axis = OC_UI_AXIS_X},
OC_UI_STYLE_SIZE
|OC_UI_STYLE_LAYOUT_AXIS);
ui_panel("Panel", UI_FLAG_DRAW_BORDER)
oc_ui_panel("Panel", OC_UI_FLAG_DRAW_BORDER)
{
ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X},
UI_STYLE_LAYOUT_AXIS);
ui_container("contents", 0)
oc_ui_style_next(&(oc_ui_style){.layout.axis = OC_UI_AXIS_X},
OC_UI_STYLE_LAYOUT_AXIS);
oc_ui_container("contents", 0)
{
ui_style_next(&(ui_style){.layout.spacing = 20},
UI_STYLE_LAYOUT_SPACING);
ui_container("buttons", 0)
oc_ui_style_next(&(oc_ui_style){.layout.spacing = 20},
OC_UI_STYLE_LAYOUT_SPACING);
oc_ui_container("buttons", 0)
{
ui_button("Button A");
ui_button("Button B");
ui_button("Button C");
ui_button("Button D");
oc_ui_button("Button A");
oc_ui_button("Button B");
oc_ui_button("Button C");
oc_ui_button("Button D");
}
ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X,
oc_ui_style_next(&(oc_ui_style){.layout.axis = OC_UI_AXIS_X,
.layout.spacing = 20},
UI_STYLE_LAYOUT_SPACING
|UI_STYLE_LAYOUT_AXIS);
OC_UI_STYLE_LAYOUT_SPACING
|OC_UI_STYLE_LAYOUT_AXIS);
ui_container("buttons2", 0)
oc_ui_container("buttons2", 0)
{
ui_button("Button A");
ui_button("Button B");
ui_button("Button C");
ui_button("Button D");
oc_ui_button("Button A");
oc_ui_button("Button B");
oc_ui_button("Button C");
oc_ui_button("Button D");
}
}
}
@ -393,9 +392,9 @@ ORCA_EXPORT void OnFrameRefresh(void)
}
mg_canvas_set_current(canvas);
mg_surface_prepare(surface);
ui_draw();
mg_render(surface, canvas);
mg_surface_present(surface);
oc_canvas_set_current(canvas);
oc_surface_select(surface);
oc_ui_draw();
oc_render(surface, canvas);
oc_surface_present(surface);
}

View File

@ -155,8 +155,8 @@ def bindgen(apiName, spec, **kwargs):
if argTag == 'p' and argLen != None:
s += '\t{\n'
s += '\t\tORCA_ASSERT(((char*)'+ argName + ' >= (char*)_mem) && (((char*)'+ argName +' - (char*)_mem) < m3_GetMemorySize(runtime)), "parameter \''+argName+'\' is out of bounds");\n'
s += '\t\tORCA_ASSERT((char*)' + argName + ' + '
s += '\t\tOC_ASSERT(((char*)'+ argName + ' >= (char*)_mem) && (((char*)'+ argName +' - (char*)_mem) < m3_GetMemorySize(runtime)), "parameter \''+argName+'\' is out of bounds");\n'
s += '\t\tOC_ASSERT((char*)' + argName + ' + '
proc = argLen.get('proc')
if proc != None:
@ -245,7 +245,7 @@ def bindgen(apiName, spec, **kwargs):
s += ' res = m3_LinkRawFunction(module, "*", "' + name + '", "' + m3Sig + '", ' + cname + '_stub);\n'
s += ' if(res != m3Err_none && res != m3Err_functionLookupFailed)\n'
s += ' {\n'
s += ' log_error("Couldn\'t link function ' + name + ' (%s)\\n", res);\n'
s += ' oc_log_error("Couldn\'t link function ' + name + ' (%s)\\n", res);\n'
s += ' ret = -1;\n'
s += ' }\n\n'

View File

@ -1,4 +1,3 @@
import argparse
from datetime import datetime
import glob
import os
@ -20,9 +19,9 @@ ANGLE_VERSION = "2023-07-05"
def attach_dev_commands(subparsers):
dev_cmd = subparsers.add_parser("dev", help="Commands for building Orca itself. Must be run from the root of an Orca source checkout.")
dev_cmd.set_defaults(func=orca_root_only)
dev_cmd.set_defaults(func=orca_source_only)
dev_sub = dev_cmd.add_subparsers(required=is_orca_root(), title='commands')
dev_sub = dev_cmd.add_subparsers(required=is_orca_source(), title='commands')
build_cmd = dev_sub.add_parser("build-runtime", help="Build the Orca runtime from source.")
build_cmd.add_argument("--release", action="store_true", help="compile Orca in release mode (default is debug)")
@ -36,15 +35,39 @@ def attach_dev_commands(subparsers):
install_cmd.set_defaults(func=dev_shellish(install))
def is_orca_root():
try:
os.stat(".orcaroot")
return True
except FileNotFoundError:
return False
# Checks if the Orca tool should use a source checkout of Orca instead of a system install.
# This is copy-pasted to the command-line tool so it can work before loading anything.
#
# Returns: (use source, source directory, is actually the source's tool)
def check_if_source():
def path_is_in_orca_source(path):
dir = path
while True:
try:
os.stat(os.path.join(dir, ".orcaroot"))
return (True, dir)
except FileNotFoundError:
pass
newdir = os.path.dirname(dir)
if newdir == dir: # TODO: Verify on Windows (it will probably not work)
return (False, None)
dir = newdir
in_source, current_source_dir = path_is_in_orca_source(os.getcwd())
script_is_source, script_source_dir = path_is_in_orca_source(os.path.dirname(os.path.abspath(__file__)))
use_source = in_source or script_is_source
source_dir = current_source_dir or script_source_dir
return (use_source, source_dir, script_is_source)
def orca_root_only(args):
def is_orca_source():
use_source, _, _ = check_if_source()
return use_source
def orca_source_only(args):
print("The Orca dev commands can only be run from an Orca source checkout.")
print()
print("If you want to build Orca yourself, download the source here:")
@ -53,7 +76,14 @@ def orca_root_only(args):
def dev_shellish(func):
return shellish(func) if is_orca_root() else orca_root_only
use_source, source_dir, _ = check_if_source()
if not use_source:
return orca_source_only
def func_from_source(args):
os.chdir(source_dir)
func(args)
return shellish(func_from_source)
def build_runtime(args):
@ -137,7 +167,7 @@ def build_platform_layer_lib_win(release):
subprocess.run([
"cl", "/nologo",
"/we4013", "/Zi", "/Zc:preprocessor",
"/DMP_BUILD_DLL",
"/DOC_BUILD_DLL",
"/std:c11", "/experimental:c11atomics",
*includes,
"src/orca.c", "/Fo:build/bin/orca.o",
@ -154,7 +184,7 @@ def build_platform_layer_lib_mac(release):
flags = ["-mmacos-version-min=10.15.4", "-maes"]
cflags = ["-std=c11"]
debug_flags = ["-O3"] if release else ["-g", "-DDEBUG", "-DLOG_COMPILE_DEBUG"]
debug_flags = ["-O3"] if release else ["-g", "-DOC_DEBUG", "-DOC_LOG_COMPILE_DEBUG"]
ldflags = [f"-L{sdk_dir}/usr/lib", f"-F{sdk_dir}/System/Library/Frameworks/"]
includes = ["-Isrc", "-Isrc/util", "-Isrc/platform", "-Iext", "-Iext/angle/include"]
@ -327,7 +357,7 @@ def build_orca_mac(release):
"-Iext/wasm3/source"
]
libs = ["-Lbuild/bin", "-Lbuild/lib", "-lorca", "-lwasm3"]
debug_flags = ["-O2"] if release else ["-g", "-DLOG_COMPILE_DEBUG"]
debug_flags = ["-O2"] if release else ["-g", "-DOC_DEBUG -DOC_LOG_COMPILE_DEBUG"]
flags = [
*debug_flags,
"-mmacos-version-min=10.15.4",
@ -485,6 +515,17 @@ def yeet(path):
shutil.rmtree(path)
def prompt(msg):
while True:
answer = input(f"{msg} (y/n)> ")
if answer.lower() in ["y", "yes"]:
return True
elif answer.lower() in ["n", "no"]:
return False
else:
print("Please enter \"yes\" or \"no\" and press return.")
def install(args):
if platform.system() == "Windows":
dest = os.path.join(os.getenv("LOCALAPPDATA"), "orca")
@ -495,31 +536,42 @@ def install(args):
print("The Orca command-line tools will be installed to:")
print(dest)
print()
while True:
answer = input("Proceed with the installation? (y/n) >")
if answer.lower() in ["y", "yes"]:
break
elif answer.lower() in ["n", "no"]:
return
else:
print("Please enter \"yes\" or \"no\" and press return.")
if not prompt("Proceed with the installation?"):
return
bin_dir = os.path.join(dest, "bin")
yeet(bin_dir)
# The MS Store version of Python does some really stupid stuff with AppData:
# https://git.handmade.network/hmn/orca/issues/32
#
# Any new files and folders created in AppData actually get created in a special
# folder specific to the Python version. However, if the files or folders already
# exist, the redirect does not happen. So, if we first use the shell to create the
# paths we need, the following scripts work regardless of Python install.
#
# Also apparently you can't just do mkdir in a subprocess call here, hence the
# trivial batch script.
if platform.system() == "Windows":
subprocess.run(["scripts\\mkdir.bat", bin_dir], check=True)
shutil.copytree("scripts", os.path.join(bin_dir, "sys_scripts"))
shutil.copy("orca", bin_dir)
if platform.system() == "Windows":
shutil.copy("orca.bat", bin_dir)
# TODO: Customize these instructions for Windows
print()
if platform.system() == "Windows":
print("The Orca tools have been installed. Make sure the Orca tools are on your PATH by")
print("adding the following path to your system PATH variable:")
print()
print("The Orca tools have been installed to the following directory:")
print(bin_dir)
print()
print("You can do this in the Windows settings by searching for \"environment variables\".")
print("The tools will need to be on your PATH in order to actually use them.")
if prompt("Would you like to automatically add Orca to your PATH?"):
subprocess.run(["powershell", "scripts\\updatepath.ps1", bin_dir], check=True)
print("Orca has been added to your PATH. Restart any open terminals to use it.")
else:
print("No worries. You can manually add Orca to your PATH in the Windows settings")
print("this in the Windows settings by searching for \"environment variables\".")
else:
print("The Orca tools have been installed. Make sure the Orca tools are on your PATH by")
print("adding the following to your shell config:")

View File

@ -99,21 +99,21 @@ f.write('#include"GL/glcorearb.h"\n')
f.write('#include"GLES3/gl32.h"\n\n')
# generate interface struct
f.write('typedef struct mg_gl_api\n{\n')
f.write('typedef struct oc_gl_api\n{\n')
f.write(' const char* name;\n')
for func in glall:
f.write('\t' + 'PFN' + func.upper() + 'PROC ' + remove_prefix(func, 'gl') + ';\n')
f.write('} mg_gl_api;\n\n')
f.write('} oc_gl_api;\n\n')
# generate interface macros
# TODO guard for different api/versions and only #define functions present in desired version
f.write("MP_API mg_gl_api* mg_gl_get_api(void);\n\n")
f.write("ORCA_API oc_gl_api* oc_gl_get_api(void);\n\n")
for func in glall:
f.write('#define ' + func + ' mg_gl_get_api()->' + remove_prefix(func, 'gl') + '\n')
f.write('#define ' + func + ' oc_gl_get_api()->' + remove_prefix(func, 'gl') + '\n')
emit_end_guard(f, apiName)
f.close()
@ -129,15 +129,15 @@ emit_begin_guard(f, loaderName)
f.write('#include"gl_api.h"\n\n')
f.write("typedef void*(*mg_gl_load_proc)(const char* name);\n\n")
f.write("typedef void*(*oc_gl_load_proc)(const char* name);\n\n")
f.write("void mg_gl_load_gl41(mg_gl_api* api, mg_gl_load_proc loadProc);\n")
f.write("void mg_gl_load_gl43(mg_gl_api* api, mg_gl_load_proc loadProc);\n")
f.write("void mg_gl_load_gl44(mg_gl_api* api, mg_gl_load_proc loadProc);\n")
f.write("void mg_gl_load_gles30(mg_gl_api* api, mg_gl_load_proc loadProc);\n")
f.write("void mg_gl_load_gles31(mg_gl_api* api, mg_gl_load_proc loadProc);\n\n")
f.write("void oc_gl_load_gl41(oc_gl_api* api, oc_gl_load_proc loadProc);\n")
f.write("void oc_gl_load_gl43(oc_gl_api* api, oc_gl_load_proc loadProc);\n")
f.write("void oc_gl_load_gl44(oc_gl_api* api, oc_gl_load_proc loadProc);\n")
f.write("void oc_gl_load_gles30(oc_gl_api* api, oc_gl_load_proc loadProc);\n")
f.write("void oc_gl_load_gles31(oc_gl_api* api, oc_gl_load_proc loadProc);\n\n")
f.write("void mg_gl_select_api(mg_gl_api* api);\n\n")
f.write("void oc_gl_select_api(oc_gl_api* api);\n\n")
emit_end_guard(f, loaderName)
f.close()
@ -146,7 +146,7 @@ f.close()
#---------------------------------------------------------------
def emit_loader(f, name, procs):
f.write('void mg_gl_load_'+ name +'(mg_gl_api* api, mg_gl_load_proc loadProc)\n')
f.write('void oc_gl_load_'+ name +'(oc_gl_api* api, oc_gl_load_proc loadProc)\n')
f.write("{\n")
f.write(' api->name = "'+ name +'";\n')
@ -154,14 +154,14 @@ def emit_loader(f, name, procs):
if proc in procs:
f.write(' api->' + remove_prefix(proc, 'gl') + ' = loadProc("' + proc + '");\n')
else:
f.write(' api->' + remove_prefix(proc, 'gl') + ' = mg_' + proc + '_noimpl;\n')
f.write(' api->' + remove_prefix(proc, 'gl') + ' = oc_' + proc + '_noimpl;\n')
f.write("}\n\n")
def emit_null_api(f, procs):
f.write('mg_gl_api __mgGLNoAPI;\n\n')
f.write('oc_gl_api oc_glNoAPI;\n\n')
for name in procs:
@ -185,7 +185,7 @@ def emit_null_api(f, procs):
retType = retType.strip()
f.write(retType + ' mg_' + name + '_noimpl(')
f.write(retType + ' oc_' + name + '_noimpl(')
params = command.findall('param')
@ -217,21 +217,21 @@ def emit_null_api(f, procs):
f.write(')\n')
f.write('{\n')
f.write(' if(__mgGLAPI == &__mgGLNoAPI)\n')
f.write(' if(oc_glAPI == &oc_glNoAPI)\n')
f.write(' {\n')
f.write(' log_error("No GL or GLES API is selected. Make sure you call mg_surface_prepare() before calling OpenGL API functions.\\n");\n')
f.write(' oc_log_error("No GL or GLES API is selected. Make sure you call oc_surface_prepare() before calling OpenGL API functions.\\n");\n')
f.write(' }\n')
f.write(' else\n')
f.write(' {\n')
f.write(' log_error("'+ name +' is not part of currently selected %s API\\n", __mgGLAPI->name);\n')
f.write(' oc_log_error("'+ name +' is not part of currently selected %s API\\n", oc_glAPI->name);\n')
f.write(' }\n')
if retType != 'void':
f.write(' return(('+ retType +')0);\n')
f.write('}\n')
f.write('mg_gl_api __mgGLNoAPI = {\n')
f.write('oc_gl_api oc_glNoAPI = {\n')
for proc in procs:
f.write(' .' + remove_prefix(proc, 'gl') + ' = mg_' + proc + '_noimpl,\n')
f.write(' .' + remove_prefix(proc, 'gl') + ' = oc_' + proc + '_noimpl,\n')
f.write("};\n\n")
f = open(loaderCPath, 'w')
@ -241,7 +241,7 @@ emit_doc(f, loaderName, '.c')
f.write('#include"' + loaderName + '.h"\n')
f.write('#include"platform/platform.h"\n\n')
f.write("mp_thread_local mg_gl_api* __mgGLAPI = 0;\n")
f.write("oc_thread_local oc_gl_api* oc_glAPI = 0;\n")
emit_null_api(f, glall)
emit_loader(f, 'gl41', gl41)
@ -250,8 +250,8 @@ emit_loader(f, 'gl44', gl44)
emit_loader(f, 'gles31', gles31)
emit_loader(f, 'gles32', gles32)
f.write("void mg_gl_select_api(mg_gl_api* api){ __mgGLAPI = api; }\n")
f.write("void mg_gl_deselect_api(){ __mgGLAPI = &__mgGLNoAPI; }\n")
f.write("mg_gl_api* mg_gl_get_api(void) { return(__mgGLAPI); }\n\n")
f.write("void oc_gl_select_api(oc_gl_api* api){ oc_glAPI = api; }\n")
f.write("void oc_gl_deselect_api(){ oc_glAPI = &oc_glNoAPI; }\n")
f.write("oc_gl_api* oc_gl_get_api(void) { return(oc_glAPI); }\n\n")
f.close()

View File

@ -32,7 +32,7 @@ def gen_gles_header(spec, filename):
tree = et.parse(spec)
reg.loadElementTree(tree)
logFile = open('./gles_gen.log', 'w')
logFile = open('./build/gles_gen.log', 'w')
gen = COutputGenerator(diagFile=logFile)
reg.setGenerator(gen)
reg.apiGen(genOpts)

3
scripts/mkdir.bat Normal file
View File

@ -0,0 +1,3 @@
@echo off
mkdir %1
exit /b %errorlevel%

11
scripts/updatepath.ps1 Normal file
View File

@ -0,0 +1,11 @@
param (
[parameter(Mandatory=$true)]
[string]$orcaPath
)
$arrPath = [System.Environment]::GetEnvironmentVariable('PATH', 'User') -split ';'
$arrPath = $arrPath | Where-Object { $_ -ne $orcaPath } | Where-Object { $_ -ne '' }
$newPath = ($arrPath + $orcaPath) -join ';'
[System.Environment]::SetEnvironmentVariable('PATH', $newPath, 'User')
# echo $newPath

View File

@ -6,7 +6,7 @@ SRCDIR=../../src
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app"
LIBS="-L$BINDIR -lmilepost"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_atlas main.c

View File

@ -6,7 +6,7 @@ EXTDIR=../../ext
INCLUDES="-I$SRCDIR -I$EXTDIR"
LIBS="-L$BINDIR -lmilepost"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_canvas main.c

View File

@ -6,7 +6,7 @@ SRCDIR=../../src
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app"
LIBS="-L$BINDIR -lmilepost"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_image main.c

View File

@ -7,7 +7,7 @@ EXTDIR=../../ext
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app -I$EXTDIR"
LIBS="-L$BINDIR -lmilepost"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_multi_surface main.c

View File

@ -6,7 +6,7 @@ SRCDIR=../../src
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app"
LIBS="-L$BINDIR -lmilepost"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_polygon main.c

View File

@ -7,7 +7,7 @@ EXTDIR=../../ext
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app -I$EXTDIR"
LIBS="-L$BINDIR -lmilepost"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_render_thread main.c

View File

@ -7,7 +7,7 @@ EXTDIR=../../ext
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app"
LIBS="-L$BINDIR -lmilepost -framework Carbon -framework Cocoa -framework Metal -framework QuartzCore"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
clang -g $FLAGS -Wl,-dead_strip $LIBS $INCLUDES -o $BINDIR/example_simple_window main.c

View File

@ -6,7 +6,7 @@ SRCDIR=../../src
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app"
LIBS="-L$BINDIR -lmilepost"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_smooth_resize main.c

View File

@ -7,7 +7,7 @@ EXTDIR=../../ext
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app -I$EXTDIR"
LIBS="-L$BINDIR -lmilepost"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_surface_sharing main.c

View File

@ -6,7 +6,7 @@ EXTDIR=../../ext
INCLUDES="-I$SRCDIR -I$EXTDIR"
LIBS="-L$BINDIR -lmilepost"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_tiger main.c

View File

@ -6,6 +6,6 @@ SRCDIR=../../src
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app"
LIBS="-L$BINDIR -lmilepost -framework Carbon -framework Cocoa -framework Metal -framework QuartzCore"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
clang -g $FLAGS $LIBS $INCLUDES -o test main.c

View File

@ -7,7 +7,7 @@ EXTDIR=../../ext
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app -I$EXTDIR"
LIBS="-L$BINDIR -lmilepost"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_gles_triangle main.c

View File

@ -6,7 +6,7 @@ SRCDIR=../../src
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app"
LIBS="-L$BINDIR -lmilepost -framework Foundation -framework Metal"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
xcrun -sdk macosx metal -c -o shader.air shader.metal
xcrun -sdk macosx metallib -o shader.metallib shader.air

View File

@ -6,7 +6,7 @@ SRCDIR=../../src
INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app"
LIBS="-L$BINDIR -lmilepost"
FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG"
FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG"
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_ui main.c

217
src/app/app.c Normal file
View File

@ -0,0 +1,217 @@
/************************************************************//**
*
* @file: app.c
* @author: Martin Fouilleul
* @date: 23/12/2022
* @revision:
*
*****************************************************************/
#include"platform/platform_debug.h"
#include"app_internal.h"
oc_app oc_appData = {0};
//---------------------------------------------------------------
// Window handles
//---------------------------------------------------------------
void oc_init_window_handles()
{
oc_list_init(&oc_appData.windowFreeList);
for(int i=0; i<OC_APP_MAX_WINDOWS; i++)
{
oc_appData.windowPool[i].generation = 1;
oc_list_append(&oc_appData.windowFreeList, &oc_appData.windowPool[i].freeListElt);
}
}
bool oc_window_handle_is_null(oc_window window)
{
return(window.h == 0);
}
oc_window oc_window_null_handle()
{
return((oc_window){.h = 0});
}
oc_window_data* oc_window_alloc()
{
return(oc_list_pop_entry(&oc_appData.windowFreeList, oc_window_data, freeListElt));
}
oc_window_data* oc_window_ptr_from_handle(oc_window handle)
{
u32 index = handle.h>>32;
u32 generation = handle.h & 0xffffffff;
if(index >= OC_APP_MAX_WINDOWS)
{
return(0);
}
oc_window_data* window = &oc_appData.windowPool[index];
if(window->generation != generation)
{
return(0);
}
else
{
return(window);
}
}
oc_window oc_window_handle_from_ptr(oc_window_data* window)
{
OC_DEBUG_ASSERT( (window - oc_appData.windowPool) >= 0
&& (window - oc_appData.windowPool) < OC_APP_MAX_WINDOWS);
u64 h = ((u64)(window - oc_appData.windowPool))<<32
| ((u64)window->generation);
return((oc_window){h});
}
void oc_window_recycle_ptr(oc_window_data* window)
{
window->generation++;
oc_list_push(&oc_appData.windowFreeList, &window->freeListElt);
}
//---------------------------------------------------------------
// Init
//---------------------------------------------------------------
static void oc_init_common()
{
oc_init_window_handles();
oc_ringbuffer_init(&oc_appData.eventQueue, 16);
}
static void oc_terminate_common()
{
oc_ringbuffer_cleanup(&oc_appData.eventQueue);
}
//---------------------------------------------------------------
// Event handling
//---------------------------------------------------------------
void oc_queue_event(oc_event* event)
{
oc_ringbuffer* queue = &oc_appData.eventQueue;
if(oc_ringbuffer_write_available(queue) < sizeof(oc_event))
{
oc_log_error("event queue full\n");
}
else
{
bool error = false;
oc_ringbuffer_reserve(queue, sizeof(oc_event), (u8*)event);
if(event->type == OC_EVENT_PATHDROP)
{
oc_list_for(&event->paths.list, elt, oc_str8_elt, listElt)
{
oc_str8* path = &elt->string;
if(oc_ringbuffer_write_available(queue) < (sizeof(u64) + path->len))
{
oc_log_error("event queue full\n");
error = true;
break;
}
else
{
oc_ringbuffer_reserve(queue, sizeof(u64), (u8*)&path->len);
oc_ringbuffer_reserve(queue, path->len, (u8*)path->ptr);
}
}
}
if(error)
{
oc_ringbuffer_rewind(queue);
}
else
{
oc_ringbuffer_commit(queue);
}
}
}
oc_event* oc_next_event(oc_arena* arena)
{
//NOTE: pop and return event from queue
oc_event* event = 0;
oc_ringbuffer* queue = &oc_appData.eventQueue;
if(oc_ringbuffer_read_available(queue) >= sizeof(oc_event))
{
event = oc_arena_push_type(arena, oc_event);
u64 read = oc_ringbuffer_read(queue, sizeof(oc_event), (u8*)event);
OC_DEBUG_ASSERT(read == sizeof(oc_event));
if(event->type == OC_EVENT_PATHDROP)
{
u64 pathCount = event->paths.eltCount;
event->paths = (oc_str8_list){0};
for(int i=0; i<pathCount; i++)
{
if(oc_ringbuffer_read_available(queue) < sizeof(u64))
{
oc_log_error("malformed path payload: no string size\n");
break;
}
u64 len = 0;
oc_ringbuffer_read(queue, sizeof(u64), (u8*)&len);
if(oc_ringbuffer_read_available(queue) < len)
{
oc_log_error("malformed path payload: string shorter than expected\n");
break;
}
char* buffer = oc_arena_push_array(arena, char, len);
oc_ringbuffer_read(queue, len, (u8*)buffer);
oc_str8_list_push(arena, &event->paths, oc_str8_from_buffer(len, buffer));
}
}
}
return(event);
}
//---------------------------------------------------------------
// window rects helpers
//---------------------------------------------------------------
void oc_window_set_content_position(oc_window window, oc_vec2 position)
{
oc_rect rect = oc_window_get_content_rect(window);
rect.x = position.x;
rect.y = position.y;
oc_window_set_content_rect(window, rect);
}
void oc_window_set_content_size(oc_window window, oc_vec2 size)
{
oc_rect rect = oc_window_get_content_rect(window);
rect.w = size.x;
rect.h = size.y;
oc_window_set_content_rect(window, rect);
}
void oc_window_set_frame_position(oc_window window, oc_vec2 position)
{
oc_rect frame = oc_window_get_frame_rect(window);
frame.x = position.x;
frame.y = position.y;
oc_window_set_frame_rect(window, frame);
}
void oc_window_set_frame_size(oc_window window, oc_vec2 size)
{
oc_rect frame = oc_window_get_frame_rect(window);
frame.w = size.x;
frame.h = size.y;
oc_window_set_frame_rect(window, frame);
}

392
src/app/app.h Normal file
View File

@ -0,0 +1,392 @@
/************************************************************//**
*
* @file: platform_app.h
* @author: Martin Fouilleul
* @date: 16/05/2020
* @revision:
*
*****************************************************************/
#ifndef __APP_H_
#define __APP_H_
#include"util/typedefs.h"
#include"util/utf8.h"
#include"util/lists.h"
#include"util/memory.h"
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------
// Typedefs, enums and constants
//--------------------------------------------------------------------
typedef struct oc_window { u64 h; } oc_window;
typedef enum { OC_MOUSE_CURSOR_ARROW,
OC_MOUSE_CURSOR_RESIZE_0,
OC_MOUSE_CURSOR_RESIZE_90,
OC_MOUSE_CURSOR_RESIZE_45,
OC_MOUSE_CURSOR_RESIZE_135,
OC_MOUSE_CURSOR_TEXT } oc_mouse_cursor;
typedef i32 oc_window_style;
static const oc_window_style OC_WINDOW_STYLE_NO_TITLE = 0x01<<0,
OC_WINDOW_STYLE_FIXED_SIZE = 0x01<<1,
OC_WINDOW_STYLE_NO_CLOSE = 0x01<<2,
OC_WINDOW_STYLE_NO_MINIFY = 0x01<<3,
OC_WINDOW_STYLE_NO_FOCUS = 0x01<<4,
OC_WINDOW_STYLE_FLOAT = 0x01<<5,
OC_WINDOW_STYLE_POPUPMENU = 0x01<<6,
OC_WINDOW_STYLE_NO_BUTTONS = 0x01<<7;
typedef enum { OC_EVENT_NONE,
OC_EVENT_KEYBOARD_MODS, //TODO: remove, keep only key?
OC_EVENT_KEYBOARD_KEY,
OC_EVENT_KEYBOARD_CHAR,
OC_EVENT_MOUSE_BUTTON,
OC_EVENT_MOUSE_MOVE,
OC_EVENT_MOUSE_WHEEL,
OC_EVENT_MOUSE_ENTER,
OC_EVENT_MOUSE_LEAVE,
OC_EVENT_WINDOW_RESIZE,
OC_EVENT_WINDOW_MOVE,
OC_EVENT_WINDOW_FOCUS,
OC_EVENT_WINDOW_UNFOCUS,
OC_EVENT_WINDOW_HIDE, // rename to minimize?
OC_EVENT_WINDOW_SHOW, // rename to restore?
OC_EVENT_WINDOW_CLOSE,
OC_EVENT_PATHDROP,
OC_EVENT_FRAME,
OC_EVENT_QUIT } oc_event_type;
typedef enum { OC_KEY_NO_ACTION,
OC_KEY_PRESS,
OC_KEY_RELEASE,
OC_KEY_REPEAT } oc_key_action;
typedef enum { OC_KEY_UNKNOWN = 0,
OC_KEY_SPACE = 32,
OC_KEY_APOSTROPHE = 39, /* ' */
OC_KEY_COMMA = 44, /* , */
OC_KEY_MINUS = 45, // -
OC_KEY_PERIOD = 46, // .
OC_KEY_SLASH = 47, // /
OC_KEY_0 = 48,
OC_KEY_1 = 49,
OC_KEY_2 = 50,
OC_KEY_3 = 51,
OC_KEY_4 = 52,
OC_KEY_5 = 53,
OC_KEY_6 = 54,
OC_KEY_7 = 55,
OC_KEY_8 = 56,
OC_KEY_9 = 57,
OC_KEY_SEMICOLON = 59, // ;
OC_KEY_EQUAL = 61, // =
OC_KEY_A = 65,
OC_KEY_B = 66,
OC_KEY_C = 67,
OC_KEY_D = 68,
OC_KEY_E = 69,
OC_KEY_F = 70,
OC_KEY_G = 71,
OC_KEY_H = 72,
OC_KEY_I = 73,
OC_KEY_J = 74,
OC_KEY_K = 75,
OC_KEY_L = 76,
OC_KEY_M = 77,
OC_KEY_N = 78,
OC_KEY_O = 79,
OC_KEY_P = 80,
OC_KEY_Q = 81,
OC_KEY_R = 82,
OC_KEY_S = 83,
OC_KEY_T = 84,
OC_KEY_U = 85,
OC_KEY_V = 86,
OC_KEY_W = 87,
OC_KEY_X = 88,
OC_KEY_Y = 89,
OC_KEY_Z = 90,
OC_KEY_LEFT_BRACKET = 91, // [
OC_KEY_BACKSLASH = 92, // \ */
OC_KEY_RIGHT_BRACKET = 93, // ]
OC_KEY_GRAVE_ACCENT = 96, // `
OC_KEY_WORLD_1 = 161, // non-US #1
OC_KEY_WORLD_2 = 162, // non-US #2
OC_KEY_ESCAPE = 256,
OC_KEY_ENTER = 257,
OC_KEY_TAB = 258,
OC_KEY_BACKSPACE = 259,
OC_KEY_INSERT = 260,
OC_KEY_DELETE = 261,
OC_KEY_RIGHT = 262,
OC_KEY_LEFT = 263,
OC_KEY_DOWN = 264,
OC_KEY_UP = 265,
OC_KEY_PAGE_UP = 266,
OC_KEY_PAGE_DOWN = 267,
OC_KEY_HOME = 268,
OC_KEY_END = 269,
OC_KEY_CAPS_LOCK = 280,
OC_KEY_SCROLL_LOCK = 281,
OC_KEY_NUM_LOCK = 282,
OC_KEY_PRINT_SCREEN = 283,
OC_KEY_PAUSE = 284,
OC_KEY_F1 = 290,
OC_KEY_F2 = 291,
OC_KEY_F3 = 292,
OC_KEY_F4 = 293,
OC_KEY_F5 = 294,
OC_KEY_F6 = 295,
OC_KEY_F7 = 296,
OC_KEY_F8 = 297,
OC_KEY_F9 = 298,
OC_KEY_F10 = 299,
OC_KEY_F11 = 300,
OC_KEY_F12 = 301,
OC_KEY_F13 = 302,
OC_KEY_F14 = 303,
OC_KEY_F15 = 304,
OC_KEY_F16 = 305,
OC_KEY_F17 = 306,
OC_KEY_F18 = 307,
OC_KEY_F19 = 308,
OC_KEY_F20 = 309,
OC_KEY_F21 = 310,
OC_KEY_F22 = 311,
OC_KEY_F23 = 312,
OC_KEY_F24 = 313,
OC_KEY_F25 = 314,
OC_KEY_KP_0 = 320,
OC_KEY_KP_1 = 321,
OC_KEY_KP_2 = 322,
OC_KEY_KP_3 = 323,
OC_KEY_KP_4 = 324,
OC_KEY_KP_5 = 325,
OC_KEY_KP_6 = 326,
OC_KEY_KP_7 = 327,
OC_KEY_KP_8 = 328,
OC_KEY_KP_9 = 329,
OC_KEY_KP_DECIMAL = 330,
OC_KEY_KP_DIVIDE = 331,
OC_KEY_KP_MULTIPLY = 332,
OC_KEY_KP_SUBTRACT = 333,
OC_KEY_KP_ADD = 334,
OC_KEY_KP_ENTER = 335,
OC_KEY_KP_EQUAL = 336,
OC_KEY_LEFT_SHIFT = 340,
OC_KEY_LEFT_CONTROL = 341,
OC_KEY_LEFT_ALT = 342,
OC_KEY_LEFT_SUPER = 343,
OC_KEY_RIGHT_SHIFT = 344,
OC_KEY_RIGHT_CONTROL = 345,
OC_KEY_RIGHT_ALT = 346,
OC_KEY_RIGHT_SUPER = 347,
OC_KEY_MENU = 348,
OC_KEY_COUNT } oc_key_code;
typedef enum {
OC_KEYMOD_NONE = 0x00,
OC_KEYMOD_ALT = 0x01,
OC_KEYMOD_SHIFT = 0x02,
OC_KEYMOD_CTRL = 0x04,
OC_KEYMOD_CMD = 0x08,
OC_KEYMOD_MAIN_MODIFIER = 0x16 /* CMD on Mac, CTRL on Win32 */ } oc_keymod_flags;
typedef enum {
OC_MOUSE_LEFT = 0x00,
OC_MOUSE_RIGHT = 0x01,
OC_MOUSE_MIDDLE = 0x02,
OC_MOUSE_EXT1 = 0x03,
OC_MOUSE_EXT2 = 0x04,
OC_MOUSE_BUTTON_COUNT } oc_mouse_button;
typedef struct oc_key_event // keyboard and mouse buttons input
{
oc_key_action action;
i32 code;
oc_keymod_flags mods;
char label[8];
u8 labelLen;
int clickCount;
} oc_key_event;
typedef struct oc_char_event // character input
{
oc_utf32 codepoint;
char sequence[8];
u8 seqLen;
} oc_char_event;
typedef struct oc_mouse_event // mouse move/scroll
{
f32 x;
f32 y;
f32 deltaX;
f32 deltaY;
oc_keymod_flags mods;
} oc_mouse_event;
typedef struct oc_move_event // window resize / move
{
oc_rect frame;
oc_rect content;
} oc_move_event;
typedef struct oc_event
{
//TODO clipboard and path drop
oc_window window;
oc_event_type type;
union
{
oc_key_event key;
oc_char_event character;
oc_mouse_event mouse;
oc_move_event move;
oc_str8_list paths;
};
} oc_event;
//NOTE: these APIs are not directly available to Orca apps
#if !defined(OC_PLATFORM_ORCA) || !(OC_PLATFORM_ORCA)
//--------------------------------------------------------------------
// app management
//--------------------------------------------------------------------
ORCA_API void oc_init(void);
ORCA_API void oc_terminate(void);
ORCA_API bool oc_should_quit(void);
ORCA_API void oc_cancel_quit(void);
ORCA_API void oc_request_quit(void);
ORCA_API void oc_set_cursor(oc_mouse_cursor cursor);
//--------------------------------------------------------------------
// Main loop and events handling
//--------------------------------------------------------------------
/*NOTE:
oc_pump_events() pumps system events into the event queue. A timeout of 0 polls for events,
while a timeout of -1 blocks for events. A timeout > 0 blocks until new events are available
or the timeout elapses.
oc_next_event() get the next event from the event queue, allocating from the passed arena
*/
ORCA_API void oc_pump_events(f64 timeout);
ORCA_API oc_event* oc_next_event(oc_arena* arena);
typedef void(*oc_live_resize_callback)(oc_event event, void* data);
ORCA_API void oc_set_live_resize_callback(oc_live_resize_callback callback, void* data);
//--------------------------------------------------------------------
// window management
//--------------------------------------------------------------------
ORCA_API bool oc_window_handle_is_null(oc_window window);
ORCA_API oc_window oc_window_null_handle(void);
ORCA_API oc_window oc_window_create(oc_rect contentRect, oc_str8 title, oc_window_style style);
ORCA_API void oc_window_destroy(oc_window window);
ORCA_API void* oc_window_native_pointer(oc_window window);
ORCA_API bool oc_window_should_close(oc_window window);
ORCA_API void oc_window_request_close(oc_window window);
ORCA_API void oc_window_cancel_close(oc_window window);
ORCA_API bool oc_window_is_hidden(oc_window window);
ORCA_API void oc_window_hide(oc_window window);
ORCA_API void oc_window_show(oc_window window);
ORCA_API bool oc_window_is_minimized(oc_window window);
ORCA_API bool oc_window_is_maximized(oc_window window);
ORCA_API void oc_window_minimize(oc_window window);
ORCA_API void oc_window_maximize(oc_window window);
ORCA_API void oc_window_restore(oc_window window);
ORCA_API bool oc_window_has_focus(oc_window window);
ORCA_API void oc_window_focus(oc_window window);
ORCA_API void oc_window_unfocus(oc_window window);
ORCA_API void oc_window_send_to_back(oc_window window);
ORCA_API void oc_window_bring_to_front(oc_window window);
ORCA_API oc_rect oc_window_get_frame_rect(oc_window window);
ORCA_API void oc_window_set_frame_rect(oc_window window, oc_rect rect);
ORCA_API void oc_window_set_frame_position(oc_window window, oc_vec2 position);
ORCA_API void oc_window_set_frame_size(oc_window window, oc_vec2 size);
ORCA_API oc_rect oc_window_get_content_rect(oc_window window);
ORCA_API void oc_window_set_content_rect(oc_window window, oc_rect rect);
ORCA_API void oc_window_set_content_position(oc_window window, oc_vec2 position);
ORCA_API void oc_window_set_content_size(oc_window window, oc_vec2 size);
ORCA_API void oc_window_center(oc_window window);
ORCA_API oc_rect oc_window_content_rect_for_frame_rect(oc_rect frameRect, oc_window_style style);
ORCA_API oc_rect oc_window_frame_rect_for_content_rect(oc_rect contentRect, oc_window_style style);
//---------------------------------------------------------------
// Dispatching stuff to the main thread
//---------------------------------------------------------------
typedef i32 (*oc_dispatch_proc)(void* user);
ORCA_API i32 oc_dispatch_on_main_thread_sync(oc_window main_window, oc_dispatch_proc proc, void* user);
//--------------------------------------------------------------------
// Clipboard
//--------------------------------------------------------------------
ORCA_API void oc_clipboard_clear(void);
ORCA_API void oc_clipboard_set_string(oc_str8 string);
ORCA_API oc_str8 oc_clipboard_get_string(oc_arena* arena);
ORCA_API oc_str8 oc_clipboard_copy_string(oc_str8 backing);
ORCA_API bool oc_clipboard_has_tag(const char* tag);
ORCA_API void oc_clipboard_set_data_for_tag(const char* tag, oc_str8 data);
ORCA_API oc_str8 oc_clipboard_get_data_for_tag(oc_arena* arena, const char* tag);
//--------------------------------------------------------------------
// native open/save/alert windows
//--------------------------------------------------------------------
ORCA_API oc_str8 oc_open_dialog(oc_arena* arena,
oc_str8 title,
oc_str8 defaultPath,
oc_str8_list filters,
bool directory);
ORCA_API oc_str8 oc_save_dialog(oc_arena* arena,
oc_str8 title,
oc_str8 defaultPath,
oc_str8_list filters);
ORCA_API int oc_alert_popup(oc_str8 title,
oc_str8 message,
oc_str8_list options);
//--------------------------------------------------------------------
// file system stuff... //TODO: move elsewhere
//--------------------------------------------------------------------
ORCA_API int oc_file_move(oc_str8 from, oc_str8 to);
ORCA_API int oc_file_remove(oc_str8 path);
ORCA_API int oc_directory_create(oc_str8 path);
#endif // !defined(OC_PLATFORM_ORCA) || !(OC_PLATFORM_ORCA)
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__APP_H_

View File

@ -1,22 +1,22 @@
/************************************************************//**
*
* @file: mp_app_internal.h
* @file: app_internal.h
* @author: Martin Fouilleul
* @date: 23/12/2022
* @revision:
*
*****************************************************************/
#ifndef __MP_APP_INTERNAL_H_
#define __MP_APP_INTERNAL_H_
#ifndef __APP_INTERNAL_H_
#define __APP_INTERNAL_H_
#include"mp_app.h"
#include"app.h"
#include"platform/platform.h"
#include"util/ringbuffer.h"
#if PLATFORM_WINDOWS
#if OC_PLATFORM_WINDOWS
#include"win32_app.h"
#elif PLATFORM_MACOS
#elif OC_PLATFORM_MACOS
#include"osx_app.h"
#else
#error "platform not supported yet"
@ -26,66 +26,66 @@
// Window structure
//---------------------------------------------------------------
typedef struct mp_frame_stats
typedef struct oc_frame_stats
{
f64 start;
f64 workTime;
f64 remainingTime;
f64 targetFramePeriod;
} mp_frame_stats;
} oc_frame_stats;
typedef struct mp_window_data
typedef struct oc_window_data
{
list_elt freeListElt;
oc_list_elt freeListElt;
u32 generation;
mp_window_style style;
oc_window_style style;
bool shouldClose; //TODO could be in status flags
bool hidden;
bool minimized;
MP_PLATFORM_WINDOW_DATA
} mp_window_data;
OC_PLATFORM_WINDOW_DATA
} oc_window_data;
//---------------------------------------------------------------
// Global App State
//---------------------------------------------------------------
typedef struct mp_key_utf8
typedef struct oc_key_utf8
{
u8 labelLen;
char label[8];
} mp_key_utf8;
} oc_key_utf8;
enum { MP_APP_MAX_WINDOWS = 128 };
enum { OC_APP_MAX_WINDOWS = 128 };
typedef struct mp_app
typedef struct oc_app
{
bool init;
bool shouldQuit;
bool minimized;
str8 pendingPathDrop;
mem_arena eventArena;
oc_str8 pendingPathDrop;
oc_arena eventArena;
ringbuffer eventQueue;
oc_ringbuffer eventQueue;
mp_frame_stats frameStats;
oc_frame_stats frameStats;
mp_window_data windowPool[MP_APP_MAX_WINDOWS];
list_info windowFreeList;
oc_window_data windowPool[OC_APP_MAX_WINDOWS];
oc_list windowFreeList;
mp_live_resize_callback liveResizeCallback;
oc_live_resize_callback liveResizeCallback;
void* liveResizeData;
mp_key_utf8 keyLabels[512];
oc_key_utf8 keyLabels[512];
int keyCodes[512];
int nativeKeys[MP_KEY_COUNT];
int nativeKeys[OC_KEY_COUNT];
MP_PLATFORM_APP_DATA
} mp_app;
OC_PLATFORM_APP_DATA
} oc_app;
#endif // __MP_APP_INTERNAL_H_
#endif // __APP_INTERNAL_H_

View File

@ -1,217 +0,0 @@
/************************************************************//**
*
* @file: mp_app_internal.c
* @author: Martin Fouilleul
* @date: 23/12/2022
* @revision:
*
*****************************************************************/
#include"platform/platform_debug.h"
#include"mp_app_internal.h"
mp_app __mpApp = {0};
//---------------------------------------------------------------
// Window handles
//---------------------------------------------------------------
void mp_init_window_handles()
{
list_init(&__mpApp.windowFreeList);
for(int i=0; i<MP_APP_MAX_WINDOWS; i++)
{
__mpApp.windowPool[i].generation = 1;
list_append(&__mpApp.windowFreeList, &__mpApp.windowPool[i].freeListElt);
}
}
bool mp_window_handle_is_null(mp_window window)
{
return(window.h == 0);
}
mp_window mp_window_null_handle()
{
return((mp_window){.h = 0});
}
mp_window_data* mp_window_alloc()
{
return(list_pop_entry(&__mpApp.windowFreeList, mp_window_data, freeListElt));
}
mp_window_data* mp_window_ptr_from_handle(mp_window handle)
{
u32 index = handle.h>>32;
u32 generation = handle.h & 0xffffffff;
if(index >= MP_APP_MAX_WINDOWS)
{
return(0);
}
mp_window_data* window = &__mpApp.windowPool[index];
if(window->generation != generation)
{
return(0);
}
else
{
return(window);
}
}
mp_window mp_window_handle_from_ptr(mp_window_data* window)
{
DEBUG_ASSERT( (window - __mpApp.windowPool) >= 0
&& (window - __mpApp.windowPool) < MP_APP_MAX_WINDOWS);
u64 h = ((u64)(window - __mpApp.windowPool))<<32
| ((u64)window->generation);
return((mp_window){h});
}
void mp_window_recycle_ptr(mp_window_data* window)
{
window->generation++;
list_push(&__mpApp.windowFreeList, &window->freeListElt);
}
//---------------------------------------------------------------
// Init
//---------------------------------------------------------------
static void mp_init_common()
{
mp_init_window_handles();
ringbuffer_init(&__mpApp.eventQueue, 16);
}
static void mp_terminate_common()
{
ringbuffer_cleanup(&__mpApp.eventQueue);
}
//---------------------------------------------------------------
// Event handling
//---------------------------------------------------------------
void mp_queue_event(mp_event* event)
{
ringbuffer* queue = &__mpApp.eventQueue;
if(ringbuffer_write_available(queue) < sizeof(mp_event))
{
log_error("event queue full\n");
}
else
{
bool error = false;
ringbuffer_reserve(queue, sizeof(mp_event), (u8*)event);
if(event->type == MP_EVENT_PATHDROP)
{
for_list(&event->paths.list, elt, str8_elt, listElt)
{
str8* path = &elt->string;
if(ringbuffer_write_available(queue) < (sizeof(u64) + path->len))
{
log_error("event queue full\n");
error = true;
break;
}
else
{
ringbuffer_reserve(queue, sizeof(u64), (u8*)&path->len);
ringbuffer_reserve(queue, path->len, (u8*)path->ptr);
}
}
}
if(error)
{
ringbuffer_rewind(queue);
}
else
{
ringbuffer_commit(queue);
}
}
}
mp_event* mp_next_event(mem_arena* arena)
{
//NOTE: pop and return event from queue
mp_event* event = 0;
ringbuffer* queue = &__mpApp.eventQueue;
if(ringbuffer_read_available(queue) >= sizeof(mp_event))
{
event = mem_arena_alloc_type(arena, mp_event);
u64 read = ringbuffer_read(queue, sizeof(mp_event), (u8*)event);
DEBUG_ASSERT(read == sizeof(mp_event));
if(event->type == MP_EVENT_PATHDROP)
{
u64 pathCount = event->paths.eltCount;
event->paths = (str8_list){0};
for(int i=0; i<pathCount; i++)
{
if(ringbuffer_read_available(queue) < sizeof(u64))
{
log_error("malformed path payload: no string size\n");
break;
}
u64 len = 0;
ringbuffer_read(queue, sizeof(u64), (u8*)&len);
if(ringbuffer_read_available(queue) < len)
{
log_error("malformed path payload: string shorter than expected\n");
break;
}
char* buffer = mem_arena_alloc_array(arena, char, len);
ringbuffer_read(queue, len, (u8*)buffer);
str8_list_push(arena, &event->paths, str8_from_buffer(len, buffer));
}
}
}
return(event);
}
//---------------------------------------------------------------
// window rects helpers
//---------------------------------------------------------------
void mp_window_set_content_position(mp_window window, vec2 position)
{
mp_rect rect = mp_window_get_content_rect(window);
rect.x = position.x;
rect.y = position.y;
mp_window_set_content_rect(window, rect);
}
void mp_window_set_content_size(mp_window window, vec2 size)
{
mp_rect rect = mp_window_get_content_rect(window);
rect.w = size.x;
rect.h = size.y;
mp_window_set_content_rect(window, rect);
}
void mp_window_set_frame_position(mp_window window, vec2 position)
{
mp_rect frame = mp_window_get_frame_rect(window);
frame.x = position.x;
frame.y = position.y;
mp_window_set_frame_rect(window, frame);
}
void mp_window_set_frame_size(mp_window window, vec2 size)
{
mp_rect frame = mp_window_get_frame_rect(window);
frame.w = size.x;
frame.h = size.y;
mp_window_set_frame_rect(window, frame);
}

View File

@ -1,395 +0,0 @@
/************************************************************//**
*
* @file: platform_app.h
* @author: Martin Fouilleul
* @date: 16/05/2020
* @revision:
*
*****************************************************************/
#ifndef __PLATFORM_APP_H_
#define __PLATFORM_APP_H_
#include"util/typedefs.h"
#include"util/utf8.h"
#include"util/lists.h"
#include"util/memory.h"
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------
// Typedefs, enums and constants
//--------------------------------------------------------------------
typedef struct mp_window { u64 h; } mp_window;
typedef enum { MP_MOUSE_CURSOR_ARROW,
MP_MOUSE_CURSOR_RESIZE_0,
MP_MOUSE_CURSOR_RESIZE_90,
MP_MOUSE_CURSOR_RESIZE_45,
MP_MOUSE_CURSOR_RESIZE_135,
MP_MOUSE_CURSOR_TEXT } mp_mouse_cursor;
typedef i32 mp_window_style;
static const mp_window_style MP_WINDOW_STYLE_NO_TITLE = 0x01<<0,
MP_WINDOW_STYLE_FIXED_SIZE = 0x01<<1,
MP_WINDOW_STYLE_NO_CLOSE = 0x01<<2,
MP_WINDOW_STYLE_NO_MINIFY = 0x01<<3,
MP_WINDOW_STYLE_NO_FOCUS = 0x01<<4,
MP_WINDOW_STYLE_FLOAT = 0x01<<5,
MP_WINDOW_STYLE_POPUPMENU = 0x01<<6,
MP_WINDOW_STYLE_NO_BUTTONS = 0x01<<7;
typedef enum { MP_EVENT_NONE,
MP_EVENT_KEYBOARD_MODS, //TODO: remove, keep only key?
MP_EVENT_KEYBOARD_KEY,
MP_EVENT_KEYBOARD_CHAR,
MP_EVENT_MOUSE_BUTTON,
MP_EVENT_MOUSE_MOVE,
MP_EVENT_MOUSE_WHEEL,
MP_EVENT_MOUSE_ENTER,
MP_EVENT_MOUSE_LEAVE,
MP_EVENT_WINDOW_RESIZE,
MP_EVENT_WINDOW_MOVE,
MP_EVENT_WINDOW_FOCUS,
MP_EVENT_WINDOW_UNFOCUS,
MP_EVENT_WINDOW_HIDE, // rename to minimize?
MP_EVENT_WINDOW_SHOW, // rename to restore?
MP_EVENT_WINDOW_CLOSE,
MP_EVENT_PATHDROP,
MP_EVENT_FRAME,
MP_EVENT_QUIT } mp_event_type;
typedef enum { MP_KEY_NO_ACTION,
MP_KEY_PRESS,
MP_KEY_RELEASE,
MP_KEY_REPEAT } mp_key_action;
typedef enum { MP_KEY_UNKNOWN = 0,
MP_KEY_SPACE = 32,
MP_KEY_APOSTROPHE = 39, /* ' */
MP_KEY_COMMA = 44, /* , */
MP_KEY_MINUS = 45, // -
MP_KEY_PERIOD = 46, // .
MP_KEY_SLASH = 47, // /
MP_KEY_0 = 48,
MP_KEY_1 = 49,
MP_KEY_2 = 50,
MP_KEY_3 = 51,
MP_KEY_4 = 52,
MP_KEY_5 = 53,
MP_KEY_6 = 54,
MP_KEY_7 = 55,
MP_KEY_8 = 56,
MP_KEY_9 = 57,
MP_KEY_SEMICOLON = 59, // ;
MP_KEY_EQUAL = 61, // =
MP_KEY_A = 65,
MP_KEY_B = 66,
MP_KEY_C = 67,
MP_KEY_D = 68,
MP_KEY_E = 69,
MP_KEY_F = 70,
MP_KEY_G = 71,
MP_KEY_H = 72,
MP_KEY_I = 73,
MP_KEY_J = 74,
MP_KEY_K = 75,
MP_KEY_L = 76,
MP_KEY_M = 77,
MP_KEY_N = 78,
MP_KEY_O = 79,
MP_KEY_P = 80,
MP_KEY_Q = 81,
MP_KEY_R = 82,
MP_KEY_S = 83,
MP_KEY_T = 84,
MP_KEY_U = 85,
MP_KEY_V = 86,
MP_KEY_W = 87,
MP_KEY_X = 88,
MP_KEY_Y = 89,
MP_KEY_Z = 90,
MP_KEY_LEFT_BRACKET = 91, // [
MP_KEY_BACKSLASH = 92, // \ */
MP_KEY_RIGHT_BRACKET = 93, // ]
MP_KEY_GRAVE_ACCENT = 96, // `
MP_KEY_WORLD_1 = 161, // non-US #1
MP_KEY_WORLD_2 = 162, // non-US #2
MP_KEY_ESCAPE = 256,
MP_KEY_ENTER = 257,
MP_KEY_TAB = 258,
MP_KEY_BACKSPACE = 259,
MP_KEY_INSERT = 260,
MP_KEY_DELETE = 261,
MP_KEY_RIGHT = 262,
MP_KEY_LEFT = 263,
MP_KEY_DOWN = 264,
MP_KEY_UP = 265,
MP_KEY_PAGE_UP = 266,
MP_KEY_PAGE_DOWN = 267,
MP_KEY_HOME = 268,
MP_KEY_END = 269,
MP_KEY_CAPS_LOCK = 280,
MP_KEY_SCROLL_LOCK = 281,
MP_KEY_NUM_LOCK = 282,
MP_KEY_PRINT_SCREEN = 283,
MP_KEY_PAUSE = 284,
MP_KEY_F1 = 290,
MP_KEY_F2 = 291,
MP_KEY_F3 = 292,
MP_KEY_F4 = 293,
MP_KEY_F5 = 294,
MP_KEY_F6 = 295,
MP_KEY_F7 = 296,
MP_KEY_F8 = 297,
MP_KEY_F9 = 298,
MP_KEY_F10 = 299,
MP_KEY_F11 = 300,
MP_KEY_F12 = 301,
MP_KEY_F13 = 302,
MP_KEY_F14 = 303,
MP_KEY_F15 = 304,
MP_KEY_F16 = 305,
MP_KEY_F17 = 306,
MP_KEY_F18 = 307,
MP_KEY_F19 = 308,
MP_KEY_F20 = 309,
MP_KEY_F21 = 310,
MP_KEY_F22 = 311,
MP_KEY_F23 = 312,
MP_KEY_F24 = 313,
MP_KEY_F25 = 314,
MP_KEY_KP_0 = 320,
MP_KEY_KP_1 = 321,
MP_KEY_KP_2 = 322,
MP_KEY_KP_3 = 323,
MP_KEY_KP_4 = 324,
MP_KEY_KP_5 = 325,
MP_KEY_KP_6 = 326,
MP_KEY_KP_7 = 327,
MP_KEY_KP_8 = 328,
MP_KEY_KP_9 = 329,
MP_KEY_KP_DECIMAL = 330,
MP_KEY_KP_DIVIDE = 331,
MP_KEY_KP_MULTIPLY = 332,
MP_KEY_KP_SUBTRACT = 333,
MP_KEY_KP_ADD = 334,
MP_KEY_KP_ENTER = 335,
MP_KEY_KP_EQUAL = 336,
MP_KEY_LEFT_SHIFT = 340,
MP_KEY_LEFT_CONTROL = 341,
MP_KEY_LEFT_ALT = 342,
MP_KEY_LEFT_SUPER = 343,
MP_KEY_RIGHT_SHIFT = 344,
MP_KEY_RIGHT_CONTROL = 345,
MP_KEY_RIGHT_ALT = 346,
MP_KEY_RIGHT_SUPER = 347,
MP_KEY_MENU = 348,
MP_KEY_COUNT } mp_key_code;
typedef enum {
MP_KEYMOD_NONE = 0x00,
MP_KEYMOD_ALT = 0x01,
MP_KEYMOD_SHIFT = 0x02,
MP_KEYMOD_CTRL = 0x04,
MP_KEYMOD_CMD = 0x08,
MP_KEYMOD_MAIN_MODIFIER = 0x16 /* CMD on Mac, CTRL on Win32 */ } mp_keymod_flags;
typedef enum {
MP_MOUSE_LEFT = 0x00,
MP_MOUSE_RIGHT = 0x01,
MP_MOUSE_MIDDLE = 0x02,
MP_MOUSE_EXT1 = 0x03,
MP_MOUSE_EXT2 = 0x04,
MP_MOUSE_BUTTON_COUNT } mp_mouse_button;
typedef struct mp_key_event // keyboard and mouse buttons input
{
mp_key_action action;
i32 code;
mp_keymod_flags mods;
char label[8];
u8 labelLen;
int clickCount;
} mp_key_event;
typedef struct mp_char_event // character input
{
utf32 codepoint;
char sequence[8];
u8 seqLen;
} mp_char_event;
typedef struct mp_mouse_event // mouse move/scroll
{
f32 x;
f32 y;
f32 deltaX;
f32 deltaY;
mp_keymod_flags mods;
} mp_mouse_event;
typedef struct mp_move_event // window resize / move
{
mp_rect frame;
mp_rect content;
} mp_move_event;
typedef struct mp_event
{
//TODO clipboard and path drop
mp_window window;
mp_event_type type;
union
{
mp_key_event key;
mp_char_event character;
mp_mouse_event mouse;
mp_move_event move;
str8_list paths;
};
} mp_event;
//NOTE: these APIs are not directly available to Orca apps
#if !defined(PLATFORM_ORCA) || !(PLATFORM_ORCA)
//--------------------------------------------------------------------
// app management
//--------------------------------------------------------------------
MP_API void mp_init(void);
MP_API void mp_terminate(void);
MP_API bool mp_should_quit(void);
MP_API void mp_cancel_quit(void);
MP_API void mp_request_quit(void);
MP_API void mp_set_cursor(mp_mouse_cursor cursor);
//--------------------------------------------------------------------
// Main loop and events handling
//--------------------------------------------------------------------
/*NOTE:
mp_pump_events() pumps system events into the event queue. A timeout of 0 polls for events,
while a timeout of -1 blocks for events. A timeout > 0 blocks until new events are available
or the timeout elapses.
mp_next_event() get the next event from the event queue, allocating from the passed arena
*/
MP_API void mp_pump_events(f64 timeout);
MP_API mp_event* mp_next_event(mem_arena* arena);
typedef void(*mp_live_resize_callback)(mp_event event, void* data);
MP_API void mp_set_live_resize_callback(mp_live_resize_callback callback, void* data);
//--------------------------------------------------------------------
// window management
//--------------------------------------------------------------------
MP_API bool mp_window_handle_is_null(mp_window window);
MP_API mp_window mp_window_null_handle(void);
MP_API mp_window mp_window_create(mp_rect contentRect, const char* title, mp_window_style style);
MP_API void mp_window_destroy(mp_window window);
MP_API void* mp_window_native_pointer(mp_window window);
MP_API bool mp_window_should_close(mp_window window);
MP_API void mp_window_request_close(mp_window window);
MP_API void mp_window_cancel_close(mp_window window);
MP_API bool mp_window_is_hidden(mp_window window);
MP_API void mp_window_hide(mp_window window);
MP_API void mp_window_show(mp_window window);
MP_API bool mp_window_is_minimized(mp_window window);
MP_API bool mp_window_is_maximized(mp_window window);
MP_API void mp_window_minimize(mp_window window);
MP_API void mp_window_maximize(mp_window window);
MP_API void mp_window_restore(mp_window window);
MP_API bool mp_window_has_focus(mp_window window);
MP_API void mp_window_focus(mp_window window);
MP_API void mp_window_unfocus(mp_window window);
MP_API void mp_window_send_to_back(mp_window window);
MP_API void mp_window_bring_to_front(mp_window window);
MP_API mp_rect mp_window_get_frame_rect(mp_window window);
MP_API void mp_window_set_frame_rect(mp_window window, mp_rect rect);
MP_API void mp_window_set_frame_position(mp_window window, vec2 position);
MP_API void mp_window_set_frame_size(mp_window window, vec2 size);
MP_API mp_rect mp_window_get_content_rect(mp_window window);
MP_API void mp_window_set_content_rect(mp_window window, mp_rect rect);
MP_API void mp_window_set_content_position(mp_window window, vec2 position);
MP_API void mp_window_set_content_size(mp_window window, vec2 size);
MP_API void mp_window_center(mp_window window);
MP_API mp_rect mp_window_content_rect_for_frame_rect(mp_rect frameRect, mp_window_style style);
MP_API mp_rect mp_window_frame_rect_for_content_rect(mp_rect contentRect, mp_window_style style);
//---------------------------------------------------------------
// Dispatching stuff to the main thread
//---------------------------------------------------------------
typedef i32 (*mp_dispatch_proc)(void* user);
MP_API i32 mp_dispatch_on_main_thread_sync(mp_window main_window, mp_dispatch_proc proc, void* user);
//--------------------------------------------------------------------
// Clipboard
//--------------------------------------------------------------------
MP_API void mp_clipboard_clear(void);
MP_API void mp_clipboard_set_string(str8 string);
MP_API str8 mp_clipboard_get_string(mem_arena* arena);
MP_API str8 mp_clipboard_copy_string(str8 backing);
MP_API bool mp_clipboard_has_tag(const char* tag);
MP_API void mp_clipboard_set_data_for_tag(const char* tag, str8 data);
MP_API str8 mp_clipboard_get_data_for_tag(mem_arena* arena, const char* tag);
//--------------------------------------------------------------------
// native open/save/alert windows
//--------------------------------------------------------------------
MP_API str8 mp_open_dialog(mem_arena* arena,
const char* title,
const char* defaultPath,
int filterCount,
const char** filters,
bool directory);
MP_API str8 mp_save_dialog(mem_arena* arena,
const char* title,
const char* defaultPath,
int filterCount,
const char** filters);
MP_API int mp_alert_popup(const char* title,
const char* message,
u32 count,
const char** options);
//--------------------------------------------------------------------
// file system stuff... //TODO: move elsewhere
//--------------------------------------------------------------------
MP_API int mp_file_move(str8 from, str8 to);
MP_API int mp_file_remove(str8 path);
MP_API int mp_directory_create(str8 path);
#endif // !defined(PLATFORM_ORCA) || !(PLATFORM_ORCA)
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__PLATFORM_APP_H_

View File

@ -1,4 +1,4 @@
#include"orca.h"
//This is used to pass raw events from the runtime
ORCA_EXPORT mp_event _OrcaRawEvent;
ORCA_EXPORT oc_event oc_rawEvent;

View File

@ -9,7 +9,7 @@
#ifndef __OSX_APP_H_
#define __OSX_APP_H_
#include"mp_app.h"
#include"app.h"
#include"graphics/graphics.h"
#ifdef __OBJC__
@ -26,19 +26,19 @@
#include<Carbon/Carbon.h>
typedef struct osx_window_data
typedef struct oc_osx_window_data
{
NSWindow* nsWindow;
NSView* nsView;
NSObject* nsWindowDelegate;
} osx_window_data;
} oc_osx_window_data;
#define MP_PLATFORM_WINDOW_DATA osx_window_data osx;
#define OC_PLATFORM_WINDOW_DATA oc_osx_window_data osx;
const u32 MP_APP_MAX_VIEWS = 128;
const u32 OC_APP_MAX_VIEWS = 128;
typedef struct osx_app_data
typedef struct oc_osx_app_data
{
NSTimer* frameTimer;
NSCursor* cursor;
@ -47,9 +47,9 @@ typedef struct osx_app_data
void* kbLayoutUnicodeData;
id kbLayoutListener;
} osx_app_data;
} oc_osx_app_data;
#define MP_PLATFORM_APP_DATA osx_app_data osx;
#define OC_PLATFORM_APP_DATA oc_osx_app_data osx;
//-----------------------------------------------
// Surface layer
@ -76,11 +76,11 @@ typedef struct osx_app_data
@end
#endif
typedef struct mp_layer
typedef struct oc_layer
{
CALayer* caLayer;
CAContext* caContext;
} mp_layer;
} oc_layer;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,45 +10,45 @@
#ifndef __WIN32_APP_H_
#define __WIN32_APP_H_
#include"mp_app.h"
#include"app.h"
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#include<windows.h>
typedef struct win32_window_data
typedef struct oc_win32_window_data
{
HWND hWnd;
list_info layers;
} win32_window_data;
oc_list layers;
} oc_win32_window_data;
typedef struct mp_window_data mp_window_data;
typedef struct mp_layer
typedef struct oc_window_data oc_window_data;
typedef struct oc_layer
{
mp_window_data* parent;
list_elt listElt;
oc_window_data* parent;
oc_list_elt listElt;
HWND hWnd;
} mp_layer;
} oc_layer;
#define MP_PLATFORM_WINDOW_DATA win32_window_data win32;
#define OC_PLATFORM_WINDOW_DATA oc_win32_window_data win32;
typedef struct win32_app_data
typedef struct oc_win32_app_data
{
u32 savedConsoleCodePage;
int mouseCaptureMask;
bool mouseTracked;
vec2 lastMousePos;
oc_vec2 lastMousePos;
u32 wheelScrollLines;
} win32_app_data;
} oc_win32_app_data;
#define MP_PLATFORM_APP_DATA win32_app_data win32;
#define OC_PLATFORM_APP_DATA oc_win32_app_data win32;
enum MP_WM_USER
enum OC_WM_USER
{
MP_WM_USER_DISPATCH_PROC = 0x0400, // WM_USER messages are defined from 0x400 to 0x7FFF
OC_WM_USER_DISPATCH_PROC = 0x0400, // WM_USER messages are defined from 0x400 to 0x7FFF
};
#endif __WIN32_APP_H_

View File

@ -10,47 +10,47 @@
#define EGL_EGLEXT_PROTOTYPES
#include<EGL/egl.h>
#include<EGL/eglext.h>
#include"app/mp_app_internal.h"
#include"app/app_internal.h"
#include"graphics_surface.h"
#include"gl_loader.h"
#if PLATFORM_MACOS
#if OC_PLATFORM_MACOS
//NOTE: EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE on osx defaults to CGL backend, which doesn't handle SwapInterval correctly
#define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE
#define OC_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE
//NOTE: hardcode GLES versions for now
//TODO: use version hints, once we have all api versions correctly categorized by glapi.py
#define MG_GLES_VERSION_MAJOR 3
#define MG_GLES_VERSION_MINOR 0
#define mg_gl_load_gles mg_gl_load_gles31
#define OC_GLES_VERSION_MAJOR 3
#define OC_GLES_VERSION_MINOR 0
#define oc_gl_load_gles oc_gl_load_gles31
#else
#define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE
#define MG_GLES_VERSION_MAJOR 3
#define MG_GLES_VERSION_MINOR 1
#define mg_gl_load_gles mg_gl_load_gles32
#define OC_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE
#define OC_GLES_VERSION_MAJOR 3
#define OC_GLES_VERSION_MINOR 1
#define oc_gl_load_gles oc_gl_load_gles32
#endif
typedef struct mg_egl_surface
typedef struct oc_egl_surface
{
mg_surface_data interface;
oc_surface_data interface;
EGLDisplay eglDisplay;
EGLConfig eglConfig;
EGLContext eglContext;
EGLSurface eglSurface;
mg_gl_api api;
oc_gl_api api;
} mg_egl_surface;
} oc_egl_surface;
void mg_egl_surface_destroy(mg_surface_data* interface)
void oc_egl_surface_destroy(oc_surface_data* interface)
{
mg_egl_surface* surface = (mg_egl_surface*)interface;
oc_egl_surface* surface = (oc_egl_surface*)interface;
if(&surface->api == mg_gl_get_api())
if(&surface->api == oc_gl_get_api())
{
mg_gl_deselect_api();
oc_gl_deselect_api();
}
if(eglGetCurrentContext() == surface->eglContext)
{
@ -59,50 +59,50 @@ void mg_egl_surface_destroy(mg_surface_data* interface)
eglDestroyContext(surface->eglDisplay, surface->eglContext);
eglDestroySurface(surface->eglDisplay, surface->eglSurface);
mg_surface_cleanup((mg_surface_data*)surface);
oc_surface_cleanup((oc_surface_data*)surface);
free(surface);
}
void mg_egl_surface_prepare(mg_surface_data* interface)
void oc_egl_surface_prepare(oc_surface_data* interface)
{
mg_egl_surface* surface = (mg_egl_surface*)interface;
oc_egl_surface* surface = (oc_egl_surface*)interface;
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
mg_gl_select_api(&surface->api);
oc_gl_select_api(&surface->api);
}
void mg_egl_surface_present(mg_surface_data* interface)
void oc_egl_surface_present(oc_surface_data* interface)
{
mg_egl_surface* surface = (mg_egl_surface*)interface;
oc_egl_surface* surface = (oc_egl_surface*)interface;
eglSwapBuffers(surface->eglDisplay, surface->eglSurface);
}
void mg_egl_surface_deselect(mg_surface_data* interface)
void oc_egl_surface_deselect(oc_surface_data* interface)
{
mg_egl_surface* surface = (mg_egl_surface*)interface;
oc_egl_surface* surface = (oc_egl_surface*)interface;
eglMakeCurrent(surface->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
mg_gl_deselect_api();
oc_gl_deselect_api();
}
void mg_egl_surface_swap_interval(mg_surface_data* interface, int swap)
void oc_egl_surface_swap_interval(oc_surface_data* interface, int swap)
{
mg_egl_surface* surface = (mg_egl_surface*)interface;
oc_egl_surface* surface = (oc_egl_surface*)interface;
eglSwapInterval(surface->eglDisplay, swap);
}
void mg_egl_surface_init(mg_egl_surface* surface)
void oc_egl_surface_init(oc_egl_surface* surface)
{
void* nativeLayer = surface->interface.nativeLayer((mg_surface_data*)surface);
void* nativeLayer = surface->interface.nativeLayer((oc_surface_data*)surface);
surface->interface.api = MG_GLES;
surface->interface.api = OC_GLES;
surface->interface.destroy = mg_egl_surface_destroy;
surface->interface.prepare = mg_egl_surface_prepare;
surface->interface.present = mg_egl_surface_present;
surface->interface.deselect = mg_egl_surface_deselect;
surface->interface.swapInterval = mg_egl_surface_swap_interval;
surface->interface.destroy = oc_egl_surface_destroy;
surface->interface.prepare = oc_egl_surface_prepare;
surface->interface.present = oc_egl_surface_present;
surface->interface.deselect = oc_egl_surface_deselect;
surface->interface.swapInterval = oc_egl_surface_swap_interval;
EGLAttrib displayAttribs[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE, MG_EGL_PLATFORM_ANGLE_TYPE,
EGL_PLATFORM_ANGLE_TYPE_ANGLE, OC_EGL_PLATFORM_ANGLE_TYPE,
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
EGL_NONE};
@ -133,8 +133,8 @@ void mg_egl_surface_init(mg_egl_surface* surface)
eglBindAPI(EGL_OPENGL_ES_API);
EGLint contextAttributes[] = {
EGL_CONTEXT_MAJOR_VERSION_KHR, MG_GLES_VERSION_MAJOR,
EGL_CONTEXT_MINOR_VERSION_KHR, MG_GLES_VERSION_MINOR,
EGL_CONTEXT_MAJOR_VERSION_KHR, OC_GLES_VERSION_MAJOR,
EGL_CONTEXT_MINOR_VERSION_KHR, OC_GLES_VERSION_MINOR,
EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE,
EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE, EGL_TRUE,
EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE, EGL_FALSE,
@ -143,41 +143,41 @@ void mg_egl_surface_init(mg_egl_surface* surface)
surface->eglContext = eglCreateContext(surface->eglDisplay, surface->eglConfig, EGL_NO_CONTEXT, contextAttributes);
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
mg_gl_load_gles(&surface->api, (mg_gl_load_proc)eglGetProcAddress);
oc_gl_load_gles(&surface->api, (oc_gl_load_proc)eglGetProcAddress);
eglSwapInterval(surface->eglDisplay, 1);
}
mg_surface_data* mg_egl_surface_create_remote(u32 width, u32 height)
oc_surface_data* oc_egl_surface_create_remote(u32 width, u32 height)
{
mg_egl_surface* surface = 0;
oc_egl_surface* surface = 0;
surface = malloc_type(mg_egl_surface);
surface = oc_malloc_type(oc_egl_surface);
if(surface)
{
memset(surface, 0, sizeof(mg_egl_surface));
memset(surface, 0, sizeof(oc_egl_surface));
mg_surface_init_remote((mg_surface_data*)surface, width, height);
mg_egl_surface_init(surface);
oc_surface_init_remote((oc_surface_data*)surface, width, height);
oc_egl_surface_init(surface);
}
return((mg_surface_data*)surface);
return((oc_surface_data*)surface);
}
mg_surface_data* mg_egl_surface_create_for_window(mp_window window)
oc_surface_data* oc_egl_surface_create_for_window(oc_window window)
{
mg_egl_surface* surface = 0;
mp_window_data* windowData = mp_window_ptr_from_handle(window);
oc_egl_surface* surface = 0;
oc_window_data* windowData = oc_window_ptr_from_handle(window);
if(windowData)
{
surface = malloc_type(mg_egl_surface);
surface = oc_malloc_type(oc_egl_surface);
if(surface)
{
memset(surface, 0, sizeof(mg_egl_surface));
memset(surface, 0, sizeof(oc_egl_surface));
mg_surface_init_for_window((mg_surface_data*)surface, windowData);
mg_egl_surface_init(surface);
oc_surface_init_for_window((oc_surface_data*)surface, windowData);
oc_egl_surface_init(surface);
}
}
return((mg_surface_data*)surface);
return((oc_surface_data*)surface);
}

View File

@ -10,9 +10,9 @@
#define __EGL_SURFACE_H_
#include"graphics_surface.h"
#include"app/mp_app.h"
#include"app/app.h"
mg_surface_data* mg_egl_surface_create_for_window(mp_window window);
mg_surface_data* mg_egl_surface_create_remote(u32 width, u32 height);
oc_surface_data* oc_egl_surface_create_for_window(oc_window window);
oc_surface_data* oc_egl_surface_create_remote(u32 width, u32 height);
#endif // __EGL_SURFACE_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +1,23 @@
/********************************************************
*
* @file: gl_loader.h
* @note: auto-generated by glapi.py from gl.xml
* @date: 11/082023
*
*********************************************************/
#ifndef __GL_LOADER_H__
#define __GL_LOADER_H__
#include"gl_api.h"
typedef void*(*mg_gl_load_proc)(const char* name);
void mg_gl_load_gl41(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_load_gl43(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_load_gl44(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_load_gles30(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_load_gles31(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_select_api(mg_gl_api* api);
#endif // __GL_LOADER_H__
/********************************************************
*
* @file: gl_loader.h
* @note: auto-generated by glapi.py from gl.xml
* @date: 15/082023
*
*********************************************************/
#ifndef __GL_LOADER_H__
#define __GL_LOADER_H__
#include"gl_api.h"
typedef void*(*oc_gl_load_proc)(const char* name);
void oc_gl_load_gl41(oc_gl_api* api, oc_gl_load_proc loadProc);
void oc_gl_load_gl43(oc_gl_api* api, oc_gl_load_proc loadProc);
void oc_gl_load_gl44(oc_gl_api* api, oc_gl_load_proc loadProc);
void oc_gl_load_gles30(oc_gl_api* api, oc_gl_load_proc loadProc);
void oc_gl_load_gles31(oc_gl_api* api, oc_gl_load_proc loadProc);
void oc_gl_select_api(oc_gl_api* api);
#endif // __GL_LOADER_H__

View File

@ -6,12 +6,12 @@ layout(std430) buffer;
layout(binding = 0) restrict readonly buffer pathQueueBufferSSBO
{
mg_gl_path_queue elements[];
oc_gl_path_queue elements[];
} pathQueueBuffer;
layout(binding = 1) restrict buffer tileQueueBufferSSBO
{
mg_gl_tile_queue elements[];
oc_gl_tile_queue elements[];
} tileQueueBuffer;
layout(location = 0) uniform int pathQueueBufferStart;
@ -30,7 +30,7 @@ void main()
barrier();
int rowIndex = 0;
mg_gl_path_queue pathQueue = pathQueueBuffer.elements[pathQueueBufferStart + pathIndex];
oc_gl_path_queue pathQueue = pathQueueBuffer.elements[pathQueueBufferStart + pathIndex];
int tileQueueBase = pathQueue.tileQueues;
int rowSize = pathQueue.area.z;
int rowCount = pathQueue.area.w;

View File

@ -11,7 +11,7 @@ layout(binding = 0) coherent restrict readonly buffer screenTilesCountBufferSSBO
layout(binding = 1) coherent restrict writeonly buffer dispatchBufferSSBO
{
mg_gl_dispatch_indirect_command elements[];
oc_gl_dispatch_indirect_command elements[];
} dispatchBuffer;

View File

@ -2,32 +2,32 @@
layout(std430) buffer;
// command
#define MG_GL_FILL 0
#define MG_GL_STROKE 1
#define OC_GL_FILL 0
#define OC_GL_STROKE 1
// element kind
#define MG_GL_LINE 1
#define MG_GL_QUADRATIC 2
#define MG_GL_CUBIC 3
#define OC_GL_LINE 1
#define OC_GL_QUADRATIC 2
#define OC_GL_CUBIC 3
// curve config
#define MG_GL_BL 1 /* curve on bottom left */
#define MG_GL_BR 2 /* curve on bottom right */
#define MG_GL_TL 3 /* curve on top left */
#define MG_GL_TR 4 /* curve on top right */
#define OC_GL_BL 1 /* curve on bottom left */
#define OC_GL_BR 2 /* curve on bottom right */
#define OC_GL_TL 3 /* curve on top left */
#define OC_GL_TR 4 /* curve on top right */
// Operations
#define MG_GL_OP_FILL 0
#define MG_GL_OP_CLIP_FILL 1
#define MG_GL_OP_START 2
#define MG_GL_OP_END 3
#define MG_GL_OP_SEGMENT 4
#define OC_GL_OP_FILL 0
#define OC_GL_OP_CLIP_FILL 1
#define OC_GL_OP_START 2
#define OC_GL_OP_END 3
#define OC_GL_OP_SEGMENT 4
// MSAA
#define MG_GL_MAX_SAMPLE_COUNT 8
#define MG_GL_MAX_SRC_SAMPLE_COUNT 4
#define OC_GL_MAX_SAMPLE_COUNT 8
#define OC_GL_MAX_SRC_SAMPLE_COUNT 4
struct mg_gl_path
struct oc_gl_path
{
mat3 uvTransform;
vec4 color;
@ -37,14 +37,14 @@ struct mg_gl_path
int textureID;
};
struct mg_gl_path_elt
struct oc_gl_path_elt
{
vec2 p[4];
int pathIndex;
int kind;
};
struct mg_gl_segment
struct oc_gl_segment
{
int kind;
int pathIndex;
@ -56,13 +56,13 @@ struct mg_gl_segment
float sign;
};
struct mg_gl_path_queue
struct oc_gl_path_queue
{
ivec4 area;
int tileQueues;
};
struct mg_gl_tile_op
struct oc_gl_tile_op
{
int kind;
int next;
@ -70,20 +70,20 @@ struct mg_gl_tile_op
int windingOffsetOrCrossRight;
};
struct mg_gl_tile_queue
struct oc_gl_tile_queue
{
int windingOffset;
int first;
int last;
};
struct mg_gl_screen_tile
struct oc_gl_screen_tile
{
uvec2 tileCoord;
int first;
};
struct mg_gl_dispatch_indirect_command
struct oc_gl_dispatch_indirect_command
{
uint num_groups_x;
uint num_groups_y;
@ -95,7 +95,7 @@ float ccw(vec2 a, vec2 b, vec2 c)
return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
}
int side_of_segment(vec2 p, mg_gl_segment seg)
int side_of_segment(vec2 p, oc_gl_segment seg)
{
int side = 0;
if(p.y > seg.box.w || p.y <= seg.box.y)
@ -104,11 +104,11 @@ int side_of_segment(vec2 p, mg_gl_segment seg)
{
if(p.y > seg.box.w)
{
side = (seg.config == MG_GL_TL || seg.config == MG_GL_BR)? -1 : 1;
side = (seg.config == OC_GL_TL || seg.config == OC_GL_BR)? -1 : 1;
}
else
{
side = (seg.config == MG_GL_TL || seg.config == MG_GL_BR)? 1 : -1;
side = (seg.config == OC_GL_TL || seg.config == OC_GL_BR)? 1 : -1;
}
}
}
@ -125,22 +125,22 @@ int side_of_segment(vec2 p, mg_gl_segment seg)
vec2 a, b, c;
switch(seg.config)
{
case MG_GL_TL:
case OC_GL_TL:
a = seg.box.xy;
b = seg.box.zw;
break;
case MG_GL_BR:
case OC_GL_BR:
a = seg.box.zw;
b = seg.box.xy;
break;
case MG_GL_TR:
case OC_GL_TR:
a = seg.box.xw;
b = seg.box.zy;
break;
case MG_GL_BL:
case OC_GL_BL:
a = seg.box.zy;
b = seg.box.xw;
break;
@ -150,30 +150,30 @@ int side_of_segment(vec2 p, mg_gl_segment seg)
if(ccw(a, b, p) < 0)
{
// other side of the diagonal
side = (seg.config == MG_GL_BR || seg.config == MG_GL_TR) ? -1 : 1;
side = (seg.config == OC_GL_BR || seg.config == OC_GL_TR) ? -1 : 1;
}
else if(ccw(b, c, p) < 0 || ccw(c, a, p) < 0)
{
// same side of the diagonal, but outside curve hull
side = (seg.config == MG_GL_BL || seg.config == MG_GL_TL) ? -1 : 1;
side = (seg.config == OC_GL_BL || seg.config == OC_GL_TL) ? -1 : 1;
}
else
{
// inside curve hull
switch(seg.kind)
{
case MG_GL_LINE:
case OC_GL_LINE:
side = 1;
break;
case MG_GL_QUADRATIC:
case OC_GL_QUADRATIC:
{
vec3 ph = {p.x, p.y, 1};
vec3 klm = seg.implicitMatrix * ph;
side = ((klm.x*klm.x - klm.y)*klm.z < 0)? -1 : 1;
} break;
case MG_GL_CUBIC:
case OC_GL_CUBIC:
{
vec3 ph = {p.x, p.y, 1};
vec3 klm = seg.implicitMatrix * ph;

View File

@ -6,17 +6,17 @@ layout(std430) buffer;
layout(binding = 0) restrict readonly buffer pathBufferSSBO
{
mg_gl_path elements[];
oc_gl_path elements[];
} pathBuffer;
layout(binding = 1) restrict readonly buffer pathQueueBufferSSBO
{
mg_gl_path_queue elements[];
oc_gl_path_queue elements[];
} pathQueueBuffer;
layout(binding = 2) restrict readonly buffer tileQueueBufferSSBO
{
mg_gl_tile_queue elements[];
oc_gl_tile_queue elements[];
} tileQueueBuffer;
layout(binding = 3) coherent restrict buffer tileOpCountBufferSSBO
@ -26,12 +26,12 @@ layout(binding = 3) coherent restrict buffer tileOpCountBufferSSBO
layout(binding = 4) restrict buffer tileOpBufferSSBO
{
mg_gl_tile_op elements[];
oc_gl_tile_op elements[];
} tileOpBuffer;
layout(binding = 5) restrict writeonly buffer screenTilesBufferSSBO
{
mg_gl_screen_tile elements[];
oc_gl_screen_tile elements[];
} screenTilesBuffer;
layout(binding = 6) coherent restrict buffer screenTilesCountBufferSSBO
@ -54,7 +54,7 @@ void main()
for(int pathIndex = 0; pathIndex < pathCount; pathIndex++)
{
mg_gl_path_queue pathQueue = pathQueueBuffer.elements[pathIndex];
oc_gl_path_queue pathQueue = pathQueueBuffer.elements[pathIndex];
ivec2 pathTileCoord = tileCoord - pathQueue.area.xy;
vec4 pathBox = pathBuffer.elements[pathBufferStart + pathIndex].box;
@ -77,7 +77,7 @@ void main()
}
int pathTileIndex = pathQueue.tileQueues + pathTileCoord.y * pathQueue.area.z + pathTileCoord.x;
mg_gl_tile_queue tileQueue = tileQueueBuffer.elements[pathTileIndex];
oc_gl_tile_queue tileQueue = tileQueueBuffer.elements[pathTileIndex];
int windingOffset = tileQueue.windingOffset;
int firstOpIndex = tileQueue.first;
@ -107,7 +107,7 @@ void main()
return;
}
tileOpBuffer.elements[pathOpIndex].kind = MG_GL_OP_CLIP_FILL;
tileOpBuffer.elements[pathOpIndex].kind = OC_GL_OP_CLIP_FILL;
tileOpBuffer.elements[pathOpIndex].next = -1;
tileOpBuffer.elements[pathOpIndex].index = pathIndex;
tileOpBuffer.elements[pathOpIndex].windingOffsetOrCrossRight = windingOffset;
@ -126,7 +126,7 @@ void main()
&& tileBox.y >= clip.y
&& tileBox.w < clip.w)
{
tileOpBuffer.elements[pathOpIndex].kind = MG_GL_OP_FILL;
tileOpBuffer.elements[pathOpIndex].kind = OC_GL_OP_FILL;
if( pathBuffer.elements[pathBufferStart + pathIndex].color.a == 1
&& pathBuffer.elements[pathBufferStart + pathIndex].textureID < 0)
@ -147,7 +147,7 @@ void main()
return;
}
tileOpBuffer.elements[startOpIndex].kind = MG_GL_OP_START;
tileOpBuffer.elements[startOpIndex].kind = OC_GL_OP_START;
tileOpBuffer.elements[startOpIndex].next = -1;
tileOpBuffer.elements[startOpIndex].index = pathIndex;
tileOpBuffer.elements[startOpIndex].windingOffsetOrCrossRight = windingOffset;
@ -173,7 +173,7 @@ void main()
return;
}
tileOpBuffer.elements[endOpIndex].kind = MG_GL_OP_END;
tileOpBuffer.elements[endOpIndex].kind = OC_GL_OP_END;
tileOpBuffer.elements[endOpIndex].next = -1;
tileOpBuffer.elements[endOpIndex].index = pathIndex;
tileOpBuffer.elements[endOpIndex].windingOffsetOrCrossRight = windingOffset;

View File

@ -6,12 +6,12 @@ layout(std430) buffer;
layout(binding = 0) restrict readonly buffer pathBufferSSBO
{
mg_gl_path elements[];
oc_gl_path elements[];
} pathBuffer;
layout(binding = 1) restrict writeonly buffer pathQueueBufferSSBO
{
mg_gl_path_queue elements[];
oc_gl_path_queue elements[];
} pathQueueBuffer;
layout(binding = 2) coherent restrict buffer tileQueueCountBufferSSBO
@ -21,7 +21,7 @@ layout(binding = 2) coherent restrict buffer tileQueueCountBufferSSBO
layout(binding = 3) restrict writeonly buffer tileQueueBufferSSBO
{
mg_gl_tile_queue elements[];
oc_gl_tile_queue elements[];
} tileQueueBuffer;
layout(location = 0) uniform int tileSize;
@ -32,7 +32,7 @@ layout(location = 3) uniform int pathQueueBufferStart;
void main()
{
uint pathIndex = gl_WorkGroupID.x;
const mg_gl_path path = pathBuffer.elements[pathIndex + pathBufferStart];
const oc_gl_path path = pathBuffer.elements[pathIndex + pathBufferStart];
//NOTE: we don't clip on the right, since we need those tiles to accurately compute
// the prefix sum of winding increments in the backprop pass.

View File

@ -6,22 +6,22 @@ layout(std430) buffer;
layout(binding = 0) restrict readonly buffer pathBufferSSBO
{
mg_gl_path elements[];
oc_gl_path elements[];
} pathBuffer;
layout(binding = 1) restrict readonly buffer segmentBufferSSBO
{
mg_gl_segment elements[];
oc_gl_segment elements[];
} segmentBuffer;
layout(binding = 2) restrict readonly buffer tileOpBufferSSBO
{
mg_gl_tile_op elements[];
oc_gl_tile_op elements[];
} tileOpBuffer;
layout(binding = 3) restrict readonly buffer screenTilesBufferSSBO
{
mg_gl_screen_tile elements[];
oc_gl_screen_tile elements[];
} screenTilesBuffer;
layout(binding = 4) restrict readonly buffer screenTilesCountBufferSSBO
@ -67,7 +67,7 @@ void main()
return;
}
*/
vec2 sampleCoords[MG_GL_MAX_SAMPLE_COUNT] = {
vec2 sampleCoords[OC_GL_MAX_SAMPLE_COUNT] = {
centerCoord + vec2(1, 3)/16,
centerCoord + vec2(-1, -3)/16,
centerCoord + vec2(5, -1)/16,
@ -87,14 +87,14 @@ void main()
const int srcSampleCount = 2;
vec2 imgSampleCoords[MG_GL_MAX_SRC_SAMPLE_COUNT] = {
vec2 imgSampleCoords[OC_GL_MAX_SRC_SAMPLE_COUNT] = {
centerCoord + vec2(-0.25, 0.25),
centerCoord + vec2(+0.25, +0.25),
centerCoord + vec2(+0.25, -0.25),
centerCoord + vec2(-0.25, +0.25)};
vec4 color = vec4(0);
int winding[MG_GL_MAX_SAMPLE_COUNT];
int winding[OC_GL_MAX_SAMPLE_COUNT];
for(int i=0; i<sampleCount; i++)
{
@ -106,19 +106,19 @@ void main()
while(opIndex >= 0)
{
mg_gl_tile_op op = tileOpBuffer.elements[opIndex];
oc_gl_tile_op op = tileOpBuffer.elements[opIndex];
if(op.kind == MG_GL_OP_START)
if(op.kind == OC_GL_OP_START)
{
for(int sampleIndex = 0; sampleIndex<sampleCount; sampleIndex++)
{
winding[sampleIndex] = op.windingOffsetOrCrossRight;
}
}
else if(op.kind == MG_GL_OP_SEGMENT)
else if(op.kind == OC_GL_OP_SEGMENT)
{
int segIndex = op.index;
mg_gl_segment seg = segmentBuffer.elements[segIndex];
oc_gl_segment seg = segmentBuffer.elements[segIndex];
for(int sampleIndex=0; sampleIndex<sampleCount; sampleIndex++)
{
@ -133,12 +133,12 @@ void main()
if(op.windingOffsetOrCrossRight != 0)
{
if( (seg.config == MG_GL_BR || seg.config == MG_GL_TL)
if( (seg.config == OC_GL_BR || seg.config == OC_GL_TL)
&&(sampleCoord.y > seg.box.w))
{
winding[sampleIndex] += seg.windingIncrement;
}
else if( (seg.config == MG_GL_BL || seg.config == MG_GL_TR)
else if( (seg.config == OC_GL_BL || seg.config == OC_GL_TR)
&&(sampleCoord.y > seg.box.y))
{
winding[sampleIndex] -= seg.windingIncrement;
@ -202,7 +202,7 @@ void main()
nextColor *= texColor;
}
if(op.kind == MG_GL_OP_FILL)
if(op.kind == OC_GL_OP_FILL)
{
color = color*(1-nextColor.a) + nextColor;
}
@ -220,10 +220,10 @@ void main()
&& sampleCoord.y >= clip.y
&& sampleCoord.y < clip.w)
{
bool filled = op.kind == MG_GL_OP_CLIP_FILL
||(pathBuffer.elements[pathBufferStart + pathIndex].cmd == MG_GL_FILL
bool filled = op.kind == OC_GL_OP_CLIP_FILL
||(pathBuffer.elements[pathBufferStart + pathIndex].cmd == OC_GL_FILL
&& ((winding[sampleIndex] & 1) != 0))
||(pathBuffer.elements[pathBufferStart + pathIndex].cmd == MG_GL_STROKE
||(pathBuffer.elements[pathBufferStart + pathIndex].cmd == OC_GL_STROKE
&& (winding[sampleIndex] != 0));
if(filled)
{

View File

@ -6,7 +6,7 @@ layout(std430) buffer;
layout(binding = 0) restrict readonly buffer elementBufferSSBO
{
mg_gl_path_elt elements[];
oc_gl_path_elt elements[];
} elementBuffer;
layout(binding = 1) coherent restrict buffer segmentCountBufferSSBO
@ -16,17 +16,17 @@ layout(binding = 1) coherent restrict buffer segmentCountBufferSSBO
layout(binding = 2) restrict buffer segmentBufferSSBO
{
mg_gl_segment elements[];
oc_gl_segment elements[];
} segmentBuffer;
layout(binding = 3) restrict buffer pathQueueBufferSSBO
{
mg_gl_path_queue elements[];
oc_gl_path_queue elements[];
} pathQueueBuffer;
layout(binding = 4) coherent restrict buffer tileQueueBufferSSBO
{
mg_gl_tile_queue elements[];
oc_gl_tile_queue elements[];
} tileQueueBuffer;
layout(binding = 5) coherent restrict buffer tileOpCountBufferSSBO
@ -36,7 +36,7 @@ layout(binding = 5) coherent restrict buffer tileOpCountBufferSSBO
layout(binding = 6) restrict buffer tileOpBufferSSBO
{
mg_gl_tile_op elements[];
oc_gl_tile_op elements[];
} tileOpBuffer;
layout(location = 0) uniform float scale;
@ -46,8 +46,8 @@ layout(location = 2) uniform int elementBufferStart;
void bin_to_tiles(int segIndex)
{
//NOTE: add segment index to the queues of tiles it overlaps with
const mg_gl_segment seg = segmentBuffer.elements[segIndex];
const mg_gl_path_queue pathQueue = pathQueueBuffer.elements[seg.pathIndex];
const oc_gl_segment seg = segmentBuffer.elements[segIndex];
const oc_gl_path_queue pathQueue = pathQueueBuffer.elements[seg.pathIndex];
ivec4 pathArea = pathQueue.area;
ivec4 coveredTiles = ivec4(seg.box)/int(tileSize);
@ -81,7 +81,7 @@ void bin_to_tiles(int segIndex)
bool crossB = (sbl*sbr < 0);
vec2 s0, s1;
if(seg.config == MG_GL_TL||seg.config == MG_GL_BR)
if(seg.config == OC_GL_TL||seg.config == OC_GL_BR)
{
s0 = seg.box.xy;
s1 = seg.box.zw;
@ -107,7 +107,7 @@ void bin_to_tiles(int segIndex)
if(tileOpIndex < tileOpBuffer.elements.length())
{
tileOpBuffer.elements[tileOpIndex].kind = MG_GL_OP_SEGMENT;
tileOpBuffer.elements[tileOpIndex].kind = OC_GL_OP_SEGMENT;
tileOpBuffer.elements[tileOpIndex].index = segIndex;
tileOpBuffer.elements[tileOpIndex].windingOffsetOrCrossRight = 0;
tileOpBuffer.elements[tileOpIndex].next = -1;
@ -148,19 +148,19 @@ int push_segment(in vec2 p[4], int kind, int pathIndex)
switch(kind)
{
case MG_GL_LINE:
case OC_GL_LINE:
s = p[0];
c = p[0];
e = p[1];
break;
case MG_GL_QUADRATIC:
case OC_GL_QUADRATIC:
s = p[0];
c = p[1];
e = p[2];
break;
case MG_GL_CUBIC:
case OC_GL_CUBIC:
{
s = p[0];
float sqrNorm0 = dot(p[1]-p[0], p[1]-p[0]);
@ -197,32 +197,32 @@ int push_segment(in vec2 p[4], int kind, int pathIndex)
if(goingUp == goingRight)
{
if(kind == MG_GL_LINE)
if(kind == OC_GL_LINE)
{
segmentBuffer.elements[segIndex].config = MG_GL_BR;
segmentBuffer.elements[segIndex].config = OC_GL_BR;
}
else if(dy > alpha*dx)
{
segmentBuffer.elements[segIndex].config = MG_GL_TL;
segmentBuffer.elements[segIndex].config = OC_GL_TL;
}
else
{
segmentBuffer.elements[segIndex].config = MG_GL_BR;
segmentBuffer.elements[segIndex].config = OC_GL_BR;
}
}
else
{
if(kind == MG_GL_LINE)
if(kind == OC_GL_LINE)
{
segmentBuffer.elements[segIndex].config = MG_GL_TR;
segmentBuffer.elements[segIndex].config = OC_GL_TR;
}
else if(dy < ofs - alpha*dx)
{
segmentBuffer.elements[segIndex].config = MG_GL_BL;
segmentBuffer.elements[segIndex].config = OC_GL_BL;
}
else
{
segmentBuffer.elements[segIndex].config = MG_GL_TR;
segmentBuffer.elements[segIndex].config = OC_GL_TR;
}
}
}
@ -234,7 +234,7 @@ int push_segment(in vec2 p[4], int kind, int pathIndex)
void line_setup(vec2 p[4], int pathIndex)
{
int segIndex = push_segment(p, MG_GL_LINE, pathIndex);
int segIndex = push_segment(p, OC_GL_LINE, pathIndex);
if(segIndex < segmentBuffer.elements.length())
{
segmentBuffer.elements[segIndex].hullVertex = p[0];
@ -304,7 +304,7 @@ mat3 barycentric_matrix(vec2 v0, vec2 v1, vec2 v2)
void quadratic_emit(vec2 p[4], int pathIndex)
{
int segIndex = push_segment(p, MG_GL_QUADRATIC, pathIndex);
int segIndex = push_segment(p, OC_GL_QUADRATIC, pathIndex);
if(segIndex < segmentBuffer.elements.length())
{
@ -318,8 +318,8 @@ void quadratic_emit(vec2 p[4], int pathIndex)
float e = p[1].x - p[0].x;
float f = p[0].x*p[1].y - p[1].x*p[0].y;
float flip = ( segmentBuffer.elements[segIndex].config == MG_GL_TL
|| segmentBuffer.elements[segIndex].config == MG_GL_BL)? -1 : 1;
float flip = ( segmentBuffer.elements[segIndex].config == OC_GL_TL
|| segmentBuffer.elements[segIndex].config == OC_GL_BL)? -1 : 1;
float g = flip*(p[2].x*(p[0].y - p[1].y) + p[0].x*(p[1].y - p[2].y) + p[1].x*(p[2].y - p[0].y));
@ -663,7 +663,7 @@ vec2 select_hull_vertex(vec2 p0, vec2 p1, vec2 p2, vec2 p3)
void cubic_emit(cubic_info curve, vec2 p[4], float s0, float s1, vec2 sp[4], int pathIndex)
{
int segIndex = push_segment(sp, MG_GL_CUBIC, pathIndex);
int segIndex = push_segment(sp, OC_GL_CUBIC, pathIndex);
if(segIndex < segmentBuffer.elements.length())
{
@ -839,23 +839,23 @@ void main()
{
int eltIndex = int(gl_WorkGroupID.x);
mg_gl_path_elt elt = elementBuffer.elements[elementBufferStart + eltIndex];
oc_gl_path_elt elt = elementBuffer.elements[elementBufferStart + eltIndex];
switch(elt.kind)
{
case MG_GL_LINE:
case OC_GL_LINE:
{
vec2 p[4] = {elt.p[0]*scale, elt.p[1]*scale, vec2(0), vec2(0)};
line_setup(p, elt.pathIndex);
} break;
case MG_GL_QUADRATIC:
case OC_GL_QUADRATIC:
{
vec2 p[4] = {elt.p[0]*scale, elt.p[1]*scale, elt.p[2]*scale, vec2(0)};
quadratic_setup(p, elt.pathIndex);
} break;
case MG_GL_CUBIC:
case OC_GL_CUBIC:
{
vec2 p[4] = {elt.p[0]*scale, elt.p[1]*scale, elt.p[2]*scale, elt.p[3]*scale};
cubic_setup(p, elt.pathIndex);

View File

@ -11,126 +11,121 @@
#include"util/typedefs.h"
#include"platform/platform.h"
#include"app/mp_app.h"
#include"app/app.h"
//------------------------------------------------------------------------------------------
//NOTE(martin): backends selection
//------------------------------------------------------------------------------------------
typedef enum {
MG_NONE,
MG_METAL,
MG_GL,
MG_GLES,
MG_CANVAS,
MG_HOST } mg_surface_api;
OC_NONE,
OC_METAL,
OC_GL,
OC_GLES,
OC_CANVAS,
OC_HOST } oc_surface_api;
//NOTE: these macros are used to select which backend to include when building milepost
// they can be overridden by passing them to the compiler command line
#if PLATFORM_MACOS
#ifndef MG_COMPILE_METAL
#define MG_COMPILE_METAL 1
#if OC_PLATFORM_MACOS
#ifndef OC_COMPILE_METAL
#define OC_COMPILE_METAL 1
#endif
#ifndef MG_COMPILE_GLES
#define MG_COMPILE_GLES 1
#ifndef OC_COMPILE_GLES
#define OC_COMPILE_GLES 1
#endif
#ifndef MG_COMPILE_CANVAS
#if !MG_COMPILE_METAL
#error "Canvas surface requires a Metal backend on macOS. Make sure you define MG_COMPILE_METAL to 1."
#ifndef OC_COMPILE_CANVAS
#if !OC_COMPILE_METAL
#error "Canvas surface requires a Metal backend on macOS. Make sure you define OC_COMPILE_METAL to 1."
#endif
#define MG_COMPILE_CANVAS 1
#define OC_COMPILE_CANVAS 1
#endif
#define MG_COMPILE_GL 0
#define OC_COMPILE_GL 0
#elif PLATFORM_WINDOWS
#ifndef MG_COMPILE_GL
#define MG_COMPILE_GL 1
#elif OC_PLATFORM_WINDOWS
#ifndef OC_COMPILE_GL
#define OC_COMPILE_GL 1
#endif
#ifndef MG_COMPILE_GLES
#define MG_COMPILE_GLES 1
#ifndef OC_COMPILE_GLES
#define OC_COMPILE_GLES 1
#endif
#ifndef MG_COMPILE_CANVAS
#if !MG_COMPILE_GL
#error "Canvas surface requires an OpenGL backend on Windows. Make sure you define MG_COMPILE_GL to 1."
#ifndef OC_COMPILE_CANVAS
#if !OC_COMPILE_GL
#error "Canvas surface requires an OpenGL backend on Windows. Make sure you define OC_COMPILE_GL to 1."
#endif
#define MG_COMPILE_CANVAS 1
#define OC_COMPILE_CANVAS 1
#endif
#elif PLATFORM_LINUX
#ifndef MG_COMPILE_GL
#define MG_COMPILE_GL 1
#ifndef OC_COMPILE_GL
#define OC_COMPILE_GL 1
#endif
#ifndef MG_COMPILE_CANVAS
#if !MG_COMPILE_GL
#error "Canvas surface requires an OpenGL backend on Linux. Make sure you define MG_COMPILE_GL to 1."
#ifndef OC_COMPILE_CANVAS
#if !OC_COMPILE_GL
#error "Canvas surface requires an OpenGL backend on Linux. Make sure you define OC_COMPILE_GL to 1."
#endif
#define MG_COMPILE_CANVAS 1
#define OC_COMPILE_CANVAS 1
#endif
#endif
//NOTE: these macros are used to select backend-specific APIs to include when using milepost
#ifdef MG_EXPOSE_SURFACE_METAL
#ifdef OC_EXPOSE_SURFACE_METAL
#include"mtl_surface.h"
#endif
#ifdef MG_EXPOSE_SURFACE_WGL
#ifdef OC_EXPOSE_SURFACE_WGL
#include"wgl_surface.h"
#endif
//TODO: expose nsgl surface when supported, expose egl surface, etc...
//TODO: add MG_INCLUDE_OPENGL/GLES/etc, once we know how we make different gl versions co-exist
//TODO: add OC_INCLUDE_OPENGL/GLES/etc, once we know how we make different gl versions co-exist
MP_API bool mg_is_surface_api_available(mg_surface_api api);
ORCA_API bool oc_is_surface_api_available(oc_surface_api api);
//------------------------------------------------------------------------------------------
//NOTE(martin): graphics surface
//------------------------------------------------------------------------------------------
typedef struct mg_surface { u64 h; } mg_surface;
typedef struct oc_surface { u64 h; } oc_surface;
MP_API mg_surface mg_surface_nil(void);
MP_API bool mg_surface_is_nil(mg_surface surface);
ORCA_API oc_surface oc_surface_nil(void);
ORCA_API bool oc_surface_is_nil(oc_surface surface);
MP_API mg_surface mg_surface_create_for_window(mp_window window, mg_surface_api api);
MP_API void mg_surface_destroy(mg_surface surface);
ORCA_API oc_surface oc_surface_create_for_window(oc_window window, oc_surface_api api);
ORCA_API void oc_surface_destroy(oc_surface surface);
MP_API void mg_surface_prepare(mg_surface surface);
MP_API void mg_surface_present(mg_surface surface);
MP_API void mg_surface_deselect(void);
ORCA_API void oc_surface_select(oc_surface surface);
ORCA_API void oc_surface_present(oc_surface surface);
ORCA_API void oc_surface_deselect(void);
MP_API void mg_surface_swap_interval(mg_surface surface, int swap);
MP_API vec2 mg_surface_get_size(mg_surface surface);
MP_API vec2 mg_surface_contents_scaling(mg_surface surface);
MP_API bool mg_surface_get_hidden(mg_surface surface);
MP_API void mg_surface_set_hidden(mg_surface surface, bool hidden);
ORCA_API void oc_surface_swap_interval(oc_surface surface, int swap);
ORCA_API oc_vec2 oc_surface_get_size(oc_surface surface);
ORCA_API oc_vec2 oc_surface_contents_scaling(oc_surface surface);
ORCA_API bool oc_surface_get_hidden(oc_surface surface);
ORCA_API void oc_surface_set_hidden(oc_surface surface, bool hidden);
//NOTE(martin): surface sharing
typedef u64 mg_surface_id;
typedef u64 oc_surface_id;
MP_API mg_surface mg_surface_create_remote(u32 width, u32 height, mg_surface_api api);
MP_API mg_surface mg_surface_create_host(mp_window window);
MP_API mg_surface_id mg_surface_remote_id(mg_surface surface);
MP_API void mg_surface_host_connect(mg_surface surface, mg_surface_id remoteId);
ORCA_API oc_surface oc_surface_create_remote(u32 width, u32 height, oc_surface_api api);
ORCA_API oc_surface oc_surface_create_host(oc_window window);
ORCA_API oc_surface_id oc_surface_remote_id(oc_surface surface);
ORCA_API void oc_surface_host_connect(oc_surface surface, oc_surface_id remoteId);
//------------------------------------------------------------------------------------------
//NOTE(martin): graphics canvas structs
//------------------------------------------------------------------------------------------
typedef struct mg_canvas { u64 h; } mg_canvas;
typedef struct mg_font { u64 h; } mg_font;
typedef struct mg_image { u64 h; } mg_image;
typedef struct oc_canvas { u64 h; } oc_canvas;
typedef struct oc_font { u64 h; } oc_font;
typedef struct oc_image { u64 h; } oc_image;
typedef struct mg_mat2x3
{
f32 m[6];
} mg_mat2x3;
typedef struct mg_color
typedef struct oc_color
{
union
{
@ -143,16 +138,16 @@ typedef struct mg_color
};
f32 c[4];
};
} mg_color;
} oc_color;
typedef enum {MG_JOINT_MITER = 0,
MG_JOINT_BEVEL,
MG_JOINT_NONE } mg_joint_type;
typedef enum {OC_JOINT_MITER = 0,
OC_JOINT_BEVEL,
OC_JOINT_NONE } oc_joint_type;
typedef enum {MG_CAP_NONE = 0,
MG_CAP_SQUARE } mg_cap_type;
typedef enum {OC_CAP_NONE = 0,
OC_CAP_SQUARE } oc_cap_type;
typedef struct mg_font_extents
typedef struct oc_font_extents
{
f32 ascent; // the extent above the baseline (by convention a positive value extends above the baseline)
f32 descent; // the extent below the baseline (by convention, positive value extends below the baseline)
@ -161,9 +156,9 @@ typedef struct mg_font_extents
f32 capHeight; // height of the upper case letter 'M'
f32 width; // maximum width of the font
} mg_font_extents;
} oc_font_extents;
typedef struct mg_text_extents
typedef struct oc_text_extents
{
f32 xBearing;
f32 yBearing;
@ -172,159 +167,159 @@ typedef struct mg_text_extents
f32 xAdvance;
f32 yAdvance;
} mg_text_extents;
} oc_text_extents;
//------------------------------------------------------------------------------------------
//NOTE(martin): graphics canvas
//------------------------------------------------------------------------------------------
MP_API mg_canvas mg_canvas_nil(void);
MP_API bool mg_canvas_is_nil(mg_canvas canvas);
ORCA_API oc_canvas oc_canvas_nil(void);
ORCA_API bool oc_canvas_is_nil(oc_canvas canvas);
MP_API mg_canvas mg_canvas_create(void);
MP_API void mg_canvas_destroy(mg_canvas canvas);
MP_API mg_canvas mg_canvas_set_current(mg_canvas canvas);
MP_API void mg_render(mg_surface surface, mg_canvas canvas);
ORCA_API oc_canvas oc_canvas_create(void);
ORCA_API void oc_canvas_destroy(oc_canvas canvas);
ORCA_API oc_canvas oc_canvas_set_current(oc_canvas canvas);
ORCA_API void oc_render(oc_surface surface, oc_canvas canvas);
//------------------------------------------------------------------------------------------
//NOTE(martin): fonts
//------------------------------------------------------------------------------------------
MP_API mg_font mg_font_nil(void);
MP_API mg_font mg_font_create_from_memory(u32 size, byte* buffer, u32 rangeCount, unicode_range* ranges);
MP_API void mg_font_destroy(mg_font font);
ORCA_API oc_font oc_font_nil(void);
ORCA_API oc_font oc_font_create_from_memory(oc_str8 mem, u32 rangeCount, oc_unicode_range* ranges);
ORCA_API void oc_font_destroy(oc_font font);
//NOTE(martin): the following int valued functions return -1 if font is invalid or codepoint is not present in font//
//TODO(martin): add enum error codes
MP_API mg_font_extents mg_font_get_extents(mg_font font);
MP_API mg_font_extents mg_font_get_scaled_extents(mg_font font, f32 emSize);
MP_API f32 mg_font_get_scale_for_em_pixels(mg_font font, f32 emSize);
ORCA_API oc_font_extents oc_font_get_extents(oc_font font);
ORCA_API oc_font_extents oc_font_get_scaled_extents(oc_font font, f32 emSize);
ORCA_API f32 oc_font_get_scale_for_em_pixels(oc_font font, f32 emSize);
//NOTE(martin): if you need to process more than one codepoint, first convert your codepoints to glyph indices, then use the
// glyph index versions of the functions, which can take an array of glyph indices.
MP_API str32 mg_font_get_glyph_indices(mg_font font, str32 codePoints, str32 backing);
MP_API str32 mg_font_push_glyph_indices(mg_font font, mem_arena* arena, str32 codePoints);
MP_API u32 mg_font_get_glyph_index(mg_font font, utf32 codePoint);
ORCA_API oc_str32 oc_font_get_glyph_indices(oc_font font, oc_str32 codePoints, oc_str32 backing);
ORCA_API oc_str32 oc_font_push_glyph_indices(oc_font font, oc_arena* arena, oc_str32 codePoints);
ORCA_API u32 oc_font_get_glyph_index(oc_font font, oc_utf32 codePoint);
MP_API int mg_font_get_codepoint_extents(mg_font font, utf32 codePoint, mg_text_extents* outExtents);
ORCA_API int oc_font_get_codepoint_extents(oc_font font, oc_utf32 codePoint, oc_text_extents* outExtents);
MP_API int mg_font_get_glyph_extents(mg_font font, str32 glyphIndices, mg_text_extents* outExtents);
ORCA_API int oc_font_get_glyph_extents(oc_font font, oc_str32 glyphIndices, oc_text_extents* outExtents);
MP_API mp_rect mg_text_bounding_box_utf32(mg_font font, f32 fontSize, str32 text);
MP_API mp_rect mg_text_bounding_box(mg_font font, f32 fontSize, str8 text);
ORCA_API oc_rect oc_text_bounding_box_utf32(oc_font font, f32 fontSize, oc_str32 text);
ORCA_API oc_rect oc_text_bounding_box(oc_font font, f32 fontSize, oc_str8 text);
//------------------------------------------------------------------------------------------
//NOTE(martin): images
//------------------------------------------------------------------------------------------
MP_API mg_image mg_image_nil(void);
MP_API bool mg_image_is_nil(mg_image a);
ORCA_API oc_image oc_image_nil(void);
ORCA_API bool oc_image_is_nil(oc_image a);
MP_API mg_image mg_image_create(mg_surface surface, u32 width, u32 height);
MP_API mg_image mg_image_create_from_rgba8(mg_surface surface, u32 width, u32 height, u8* pixels);
MP_API mg_image mg_image_create_from_data(mg_surface surface, str8 data, bool flip);
MP_API mg_image mg_image_create_from_file(mg_surface surface, str8 path, bool flip);
ORCA_API oc_image oc_image_create(oc_surface surface, u32 width, u32 height);
ORCA_API oc_image oc_image_create_from_rgba8(oc_surface surface, u32 width, u32 height, u8* pixels);
ORCA_API oc_image oc_image_create_from_memory(oc_surface surface, oc_str8 mem, bool flip);
ORCA_API oc_image oc_image_create_from_file(oc_surface surface, oc_str8 path, bool flip);
MP_API void mg_image_destroy(mg_image image);
ORCA_API void oc_image_destroy(oc_image image);
MP_API void mg_image_upload_region_rgba8(mg_image image, mp_rect region, u8* pixels);
MP_API vec2 mg_image_size(mg_image image);
ORCA_API void oc_image_upload_region_rgba8(oc_image image, oc_rect region, u8* pixels);
ORCA_API oc_vec2 oc_image_size(oc_image image);
//------------------------------------------------------------------------------------------
//NOTE(martin): atlasing
//------------------------------------------------------------------------------------------
//NOTE: rectangle allocator
typedef struct mg_rect_atlas mg_rect_atlas;
typedef struct oc_rect_atlas oc_rect_atlas;
MP_API mg_rect_atlas* mg_rect_atlas_create(mem_arena* arena, i32 width, i32 height);
MP_API mp_rect mg_rect_atlas_alloc(mg_rect_atlas* atlas, i32 width, i32 height);
MP_API void mg_rect_atlas_recycle(mg_rect_atlas* atlas, mp_rect rect);
ORCA_API oc_rect_atlas* oc_rect_atlas_create(oc_arena* arena, i32 width, i32 height);
ORCA_API oc_rect oc_rect_atlas_alloc(oc_rect_atlas* atlas, i32 width, i32 height);
ORCA_API void oc_rect_atlas_recycle(oc_rect_atlas* atlas, oc_rect rect);
//NOTE: image atlas helpers
typedef struct mg_image_region
typedef struct oc_image_region
{
mg_image image;
mp_rect rect;
} mg_image_region;
oc_image image;
oc_rect rect;
} oc_image_region;
MP_API mg_image_region mg_image_atlas_alloc_from_rgba8(mg_rect_atlas* atlas, mg_image backingImage, u32 width, u32 height, u8* pixels);
MP_API mg_image_region mg_image_atlas_alloc_from_data(mg_rect_atlas* atlas, mg_image backingImage, str8 data, bool flip);
MP_API mg_image_region mg_image_atlas_alloc_from_file(mg_rect_atlas* atlas, mg_image backingImage, str8 path, bool flip);
MP_API void mg_image_atlas_recycle(mg_rect_atlas* atlas, mg_image_region imageRgn);
ORCA_API oc_image_region oc_image_atlas_alloc_from_rgba8(oc_rect_atlas* atlas, oc_image backingImage, u32 width, u32 height, u8* pixels);
ORCA_API oc_image_region oc_image_atlas_alloc_from_data(oc_rect_atlas* atlas, oc_image backingImage, oc_str8 data, bool flip);
ORCA_API oc_image_region oc_image_atlas_alloc_from_file(oc_rect_atlas* atlas, oc_image backingImage, oc_str8 path, bool flip);
ORCA_API void oc_image_atlas_recycle(oc_rect_atlas* atlas, oc_image_region imageRgn);
//------------------------------------------------------------------------------------------
//NOTE(martin): transform, viewport and clipping
//------------------------------------------------------------------------------------------
MP_API void mg_viewport(mp_rect viewPort);
ORCA_API void oc_viewport(oc_rect viewPort);
MP_API void mg_matrix_push(mg_mat2x3 matrix);
MP_API void mg_matrix_pop(void);
ORCA_API void oc_matrix_push(oc_mat2x3 matrix);
ORCA_API void oc_matrix_pop(void);
MP_API void mg_clip_push(f32 x, f32 y, f32 w, f32 h);
MP_API void mg_clip_pop(void);
ORCA_API void oc_clip_push(f32 x, f32 y, f32 w, f32 h);
ORCA_API void oc_clip_pop(void);
//------------------------------------------------------------------------------------------
//NOTE(martin): graphics attributes setting/getting
//------------------------------------------------------------------------------------------
MP_API void mg_set_color(mg_color color);
MP_API void mg_set_color_rgba(f32 r, f32 g, f32 b, f32 a);
MP_API void mg_set_width(f32 width);
MP_API void mg_set_tolerance(f32 tolerance);
MP_API void mg_set_joint(mg_joint_type joint);
MP_API void mg_set_max_joint_excursion(f32 maxJointExcursion);
MP_API void mg_set_cap(mg_cap_type cap);
MP_API void mg_set_font(mg_font font);
MP_API void mg_set_font_size(f32 size);
MP_API void mg_set_text_flip(bool flip);
MP_API void mg_set_image(mg_image image);
MP_API void mg_set_image_source_region(mp_rect region);
ORCA_API void oc_set_color(oc_color color);
ORCA_API void oc_set_color_rgba(f32 r, f32 g, f32 b, f32 a);
ORCA_API void oc_set_width(f32 width);
ORCA_API void oc_set_tolerance(f32 tolerance);
ORCA_API void oc_set_joint(oc_joint_type joint);
ORCA_API void oc_set_max_joint_excursion(f32 maxJointExcursion);
ORCA_API void oc_set_cap(oc_cap_type cap);
ORCA_API void oc_set_font(oc_font font);
ORCA_API void oc_set_font_size(f32 size);
ORCA_API void oc_set_text_flip(bool flip);
ORCA_API void oc_set_image(oc_image image);
ORCA_API void oc_set_image_source_region(oc_rect region);
MP_API mg_color mg_get_color(void);
MP_API f32 mg_get_width(void);
MP_API f32 mg_get_tolerance(void);
MP_API mg_joint_type mg_get_joint(void);
MP_API f32 mg_get_max_joint_excursion(void);
MP_API mg_cap_type mg_get_cap(void);
MP_API mg_font mg_get_font(void);
MP_API f32 mg_get_font_size(void);
MP_API bool mg_get_text_flip(void);
ORCA_API oc_color oc_get_color(void);
ORCA_API f32 oc_get_width(void);
ORCA_API f32 oc_get_tolerance(void);
ORCA_API oc_joint_type oc_get_joint(void);
ORCA_API f32 oc_get_max_joint_excursion(void);
ORCA_API oc_cap_type oc_get_cap(void);
ORCA_API oc_font oc_get_font(void);
ORCA_API f32 oc_get_font_size(void);
ORCA_API bool oc_get_text_flip(void);
//------------------------------------------------------------------------------------------
//NOTE(martin): path construction
//------------------------------------------------------------------------------------------
MP_API vec2 mg_get_position(void);
MP_API void mg_move_to(f32 x, f32 y);
MP_API void mg_line_to(f32 x, f32 y);
MP_API void mg_quadratic_to(f32 x1, f32 y1, f32 x2, f32 y2);
MP_API void mg_cubic_to(f32 x1, f32 y1, f32 x2, f32 y2, f32 x3, f32 y3);
MP_API void mg_close_path(void);
ORCA_API oc_vec2 oc_get_position(void);
ORCA_API void oc_move_to(f32 x, f32 y);
ORCA_API void oc_line_to(f32 x, f32 y);
ORCA_API void oc_quadratic_to(f32 x1, f32 y1, f32 x2, f32 y2);
ORCA_API void oc_cubic_to(f32 x1, f32 y1, f32 x2, f32 y2, f32 x3, f32 y3);
ORCA_API void oc_close_path(void);
MP_API mp_rect mg_glyph_outlines(str32 glyphIndices);
MP_API void mg_codepoints_outlines(str32 string);
MP_API void mg_text_outlines(str8 string);
ORCA_API oc_rect oc_glyph_outlines(oc_str32 glyphIndices);
ORCA_API void oc_codepoints_outlines(oc_str32 string);
ORCA_API void oc_text_outlines(oc_str8 string);
//------------------------------------------------------------------------------------------
//NOTE(martin): clear/fill/stroke
//------------------------------------------------------------------------------------------
MP_API void mg_clear(void);
MP_API void mg_fill(void);
MP_API void mg_stroke(void);
ORCA_API void oc_clear(void);
ORCA_API void oc_fill(void);
ORCA_API void oc_stroke(void);
//------------------------------------------------------------------------------------------
//NOTE(martin): 'fast' shapes primitives
//------------------------------------------------------------------------------------------
MP_API void mg_rectangle_fill(f32 x, f32 y, f32 w, f32 h);
MP_API void mg_rectangle_stroke(f32 x, f32 y, f32 w, f32 h);
MP_API void mg_rounded_rectangle_fill(f32 x, f32 y, f32 w, f32 h, f32 r);
MP_API void mg_rounded_rectangle_stroke(f32 x, f32 y, f32 w, f32 h, f32 r);
MP_API void mg_ellipse_fill(f32 x, f32 y, f32 rx, f32 ry);
MP_API void mg_ellipse_stroke(f32 x, f32 y, f32 rx, f32 ry);
MP_API void mg_circle_fill(f32 x, f32 y, f32 r);
MP_API void mg_circle_stroke(f32 x, f32 y, f32 r);
MP_API void mg_arc(f32 x, f32 y, f32 r, f32 arcAngle, f32 startAngle);
ORCA_API void oc_rectangle_fill(f32 x, f32 y, f32 w, f32 h);
ORCA_API void oc_rectangle_stroke(f32 x, f32 y, f32 w, f32 h);
ORCA_API void oc_rounded_rectangle_fill(f32 x, f32 y, f32 w, f32 h, f32 r);
ORCA_API void oc_rounded_rectangle_stroke(f32 x, f32 y, f32 w, f32 h, f32 r);
ORCA_API void oc_ellipse_fill(f32 x, f32 y, f32 rx, f32 ry);
ORCA_API void oc_ellipse_stroke(f32 x, f32 y, f32 rx, f32 ry);
ORCA_API void oc_circle_fill(f32 x, f32 y, f32 r);
ORCA_API void oc_circle_stroke(f32 x, f32 y, f32 r);
ORCA_API void oc_arc(f32 x, f32 y, f32 r, f32 arcAngle, f32 startAngle);
//NOTE: image helpers
MP_API void mg_image_draw(mg_image image, mp_rect rect);
MP_API void mg_image_draw_region(mg_image image, mp_rect srcRegion, mp_rect dstRegion);
ORCA_API void oc_image_draw(oc_image image, oc_rect rect);
ORCA_API void oc_image_draw_region(oc_image image, oc_rect srcRegion, oc_rect dstRegion);
#endif //__GRAPHICS_H_

File diff suppressed because it is too large Load Diff

View File

@ -13,70 +13,70 @@
//------------------------------------------------------------------------
// canvas structs
//------------------------------------------------------------------------
typedef enum { MG_PATH_MOVE,
MG_PATH_LINE,
MG_PATH_QUADRATIC,
MG_PATH_CUBIC } mg_path_elt_type;
typedef enum { OC_PATH_MOVE,
OC_PATH_LINE,
OC_PATH_QUADRATIC,
OC_PATH_CUBIC } oc_path_elt_type;
typedef struct mg_path_elt
typedef struct oc_path_elt
{
mg_path_elt_type type;
vec2 p[3];
oc_path_elt_type type;
oc_vec2 p[3];
} mg_path_elt;
} oc_path_elt;
typedef struct mg_path_descriptor
typedef struct oc_path_descriptor
{
u32 startIndex;
u32 count;
vec2 startPoint;
oc_vec2 startPoint;
} mg_path_descriptor;
} oc_path_descriptor;
typedef struct mg_attributes
typedef struct oc_attributes
{
f32 width;
f32 tolerance;
mg_color color;
mg_joint_type joint;
oc_color color;
oc_joint_type joint;
f32 maxJointExcursion;
mg_cap_type cap;
oc_cap_type cap;
mg_font font;
oc_font font;
f32 fontSize;
mg_image image;
mp_rect srcRegion;
oc_image image;
oc_rect srcRegion;
mg_mat2x3 transform;
mp_rect clip;
oc_mat2x3 transform;
oc_rect clip;
} mg_attributes;
} oc_attributes;
typedef enum { MG_CMD_FILL,
MG_CMD_STROKE,
MG_CMD_JUMP
} mg_primitive_cmd;
typedef enum { OC_CMD_FILL,
OC_CMD_STROKE,
OC_CMD_JUMP
} oc_primitive_cmd;
typedef struct mg_primitive
typedef struct oc_primitive
{
mg_primitive_cmd cmd;
mg_attributes attributes;
oc_primitive_cmd cmd;
oc_attributes attributes;
union
{
mg_path_descriptor path;
mp_rect rect;
oc_path_descriptor path;
oc_rect rect;
u32 jump;
};
} mg_primitive;
} oc_primitive;
MP_API void mg_surface_render_commands(mg_surface surface,
mg_color clearColor,
ORCA_API void oc_surface_render_commands(oc_surface surface,
oc_color clearColor,
u32 primitiveCount,
mg_primitive* primitives,
oc_primitive* primitives,
u32 eltCount,
mg_path_elt* elements);
oc_path_elt* elements);
#endif //__GRAPHICS_COMMON_H_

View File

@ -12,33 +12,33 @@
// per-thread selected surface
//---------------------------------------------------------------
mp_thread_local mg_surface __mgSelectedSurface = {0};
oc_thread_local oc_surface oc_selectedSurface = {0};
//---------------------------------------------------------------
// typed handles functions
//---------------------------------------------------------------
mg_surface mg_surface_handle_alloc(mg_surface_data* surface)
oc_surface oc_surface_handle_alloc(oc_surface_data* surface)
{
mg_surface handle = {.h = mg_handle_alloc(MG_HANDLE_SURFACE, (void*)surface) };
oc_surface handle = {.h = oc_graphics_handle_alloc(OC_GRAPHICS_HANDLE_SURFACE, (void*)surface) };
return(handle);
}
mg_surface_data* mg_surface_data_from_handle(mg_surface handle)
oc_surface_data* oc_surface_data_from_handle(oc_surface handle)
{
mg_surface_data* data = mg_data_from_handle(MG_HANDLE_SURFACE, handle.h);
oc_surface_data* data = oc_graphics_data_from_handle(OC_GRAPHICS_HANDLE_SURFACE, handle.h);
return(data);
}
mg_image mg_image_handle_alloc(mg_image_data* image)
oc_image oc_image_handle_alloc(oc_image_data* image)
{
mg_image handle = {.h = mg_handle_alloc(MG_HANDLE_IMAGE, (void*)image) };
oc_image handle = {.h = oc_graphics_handle_alloc(OC_GRAPHICS_HANDLE_IMAGE, (void*)image) };
return(handle);
}
mg_image_data* mg_image_data_from_handle(mg_image handle)
oc_image_data* oc_image_data_from_handle(oc_image handle)
{
mg_image_data* data = mg_data_from_handle(MG_HANDLE_IMAGE, handle.h);
oc_image_data* data = oc_graphics_data_from_handle(OC_GRAPHICS_HANDLE_IMAGE, handle.h);
return(data);
}
@ -46,48 +46,48 @@ mg_image_data* mg_image_data_from_handle(mg_image handle)
// surface API
//---------------------------------------------------------------
#if MG_COMPILE_GL
#if PLATFORM_WINDOWS
#if OC_COMPILE_GL
#if OC_PLATFORM_WINDOWS
#include"wgl_surface.h"
#define gl_surface_create_for_window mg_wgl_surface_create_for_window
#define oc_gl_surface_create_for_window oc_wgl_surface_create_for_window
#endif
#endif
#if MG_COMPILE_GLES
#if OC_COMPILE_GLES
#include"egl_surface.h"
#endif
#if MG_COMPILE_METAL
#if OC_COMPILE_METAL
#include"mtl_surface.h"
#endif
#if MG_COMPILE_CANVAS
#if PLATFORM_MACOS
mg_surface_data* mtl_canvas_surface_create_for_window(mp_window window);
#elif PLATFORM_WINDOWS
mg_surface_data* gl_canvas_surface_create_for_window(mp_window window);
#if OC_COMPILE_CANVAS
#if OC_PLATFORM_MACOS
oc_surface_data* oc_mtl_canvas_surface_create_for_window(oc_window window);
#elif OC_PLATFORM_WINDOWS
oc_surface_data* oc_gl_canvas_surface_create_for_window(oc_window window);
#endif
#endif
bool mg_is_surface_backend_available(mg_surface_api api)
bool oc_is_surface_backend_available(oc_surface_api api)
{
bool result = false;
switch(api)
{
#if MG_COMPILE_METAL
case MG_METAL:
#if OC_COMPILE_METAL
case OC_METAL:
#endif
#if MG_COMPILE_GL
case MG_GL:
#if OC_COMPILE_GL
case OC_GL:
#endif
#if MG_COMPILE_GLES
case MG_GLES:
#if OC_COMPILE_GLES
case OC_GLES:
#endif
#if MG_COMPILE_CANVAS
case MG_CANVAS:
#if OC_COMPILE_CANVAS
case OC_CANVAS:
#endif
result = true;
break;
@ -98,45 +98,45 @@ bool mg_is_surface_backend_available(mg_surface_api api)
return(result);
}
mg_surface mg_surface_nil() { return((mg_surface){.h = 0}); }
bool mg_surface_is_nil(mg_surface surface) { return(surface.h == 0); }
oc_surface oc_surface_nil() { return((oc_surface){.h = 0}); }
bool oc_surface_is_nil(oc_surface surface) { return(surface.h == 0); }
mg_surface mg_surface_create_for_window(mp_window window, mg_surface_api api)
oc_surface oc_surface_create_for_window(oc_window window, oc_surface_api api)
{
if(__mgData.init)
if(oc_graphicsData.init)
{
mg_init();
oc_graphics_init();
}
mg_surface surfaceHandle = mg_surface_nil();
mg_surface_data* surface = 0;
oc_surface surfaceHandle = oc_surface_nil();
oc_surface_data* surface = 0;
switch(api)
{
#if MG_COMPILE_GL
case MG_GL:
surface = gl_surface_create_for_window(window);
#if OC_COMPILE_GL
case OC_GL:
surface = oc_gl_surface_create_for_window(window);
break;
#endif
#if MG_COMPILE_GLES
case MG_GLES:
surface = mg_egl_surface_create_for_window(window);
#if OC_COMPILE_GLES
case OC_GLES:
surface = oc_egl_surface_create_for_window(window);
break;
#endif
#if MG_COMPILE_METAL
case MG_METAL:
surface = mg_mtl_surface_create_for_window(window);
#if OC_COMPILE_METAL
case OC_METAL:
surface = oc_mtl_surface_create_for_window(window);
break;
#endif
#if MG_COMPILE_CANVAS
case MG_CANVAS:
#if OC_COMPILE_CANVAS
case OC_CANVAS:
#if PLATFORM_MACOS
surface = mtl_canvas_surface_create_for_window(window);
#elif PLATFORM_WINDOWS
surface = gl_canvas_surface_create_for_window(window);
#if OC_PLATFORM_MACOS
surface = oc_mtl_canvas_surface_create_for_window(window);
#elif OC_PLATFORM_WINDOWS
surface = oc_gl_canvas_surface_create_for_window(window);
#endif
break;
#endif
@ -146,26 +146,26 @@ mg_surface mg_surface_create_for_window(mp_window window, mg_surface_api api)
}
if(surface)
{
surfaceHandle = mg_surface_handle_alloc(surface);
mg_surface_prepare(surfaceHandle);
surfaceHandle = oc_surface_handle_alloc(surface);
oc_surface_select(surfaceHandle);
}
return(surfaceHandle);
}
mg_surface mg_surface_create_remote(u32 width, u32 height, mg_surface_api api)
oc_surface oc_surface_create_remote(u32 width, u32 height, oc_surface_api api)
{
if(!__mgData.init)
if(!oc_graphicsData.init)
{
mg_init();
oc_graphics_init();
}
mg_surface surfaceHandle = mg_surface_nil();
mg_surface_data* surface = 0;
oc_surface surfaceHandle = oc_surface_nil();
oc_surface_data* surface = 0;
switch(api)
{
#if MG_COMPILE_GLES
case MG_GLES:
surface = mg_egl_surface_create_remote(width, height);
#if OC_COMPILE_GLES
case OC_GLES:
surface = oc_egl_surface_create_remote(width, height);
break;
#endif
@ -174,42 +174,42 @@ mg_surface mg_surface_create_remote(u32 width, u32 height, mg_surface_api api)
}
if(surface)
{
surfaceHandle = mg_surface_handle_alloc(surface);
mg_surface_prepare(surfaceHandle);
surfaceHandle = oc_surface_handle_alloc(surface);
oc_surface_select(surfaceHandle);
}
return(surfaceHandle);
}
mg_surface mg_surface_create_host(mp_window window)
oc_surface oc_surface_create_host(oc_window window)
{
if(!__mgData.init)
if(!oc_graphicsData.init)
{
mg_init();
oc_graphics_init();
}
mg_surface handle = mg_surface_nil();
mg_surface_data* surface = 0;
#if PLATFORM_MACOS
surface = mg_osx_surface_create_host(window);
#elif PLATFORM_WINDOWS
surface = mg_win32_surface_create_host(window);
oc_surface handle = oc_surface_nil();
oc_surface_data* surface = 0;
#if OC_PLATFORM_MACOS
surface = oc_osx_surface_create_host(window);
#elif OC_PLATFORM_WINDOWS
surface = oc_win32_surface_create_host(window);
#endif
if(surface)
{
handle = mg_surface_handle_alloc(surface);
handle = oc_surface_handle_alloc(surface);
}
return(handle);
}
void mg_surface_destroy(mg_surface handle)
void oc_surface_destroy(oc_surface handle)
{
DEBUG_ASSERT(__mgData.init);
mg_surface_data* surface = mg_surface_data_from_handle(handle);
OC_DEBUG_ASSERT(oc_graphicsData.init);
oc_surface_data* surface = oc_surface_data_from_handle(handle);
if(surface)
{
if(__mgSelectedSurface.h == handle.h)
if(oc_selectedSurface.h == handle.h)
{
mg_surface_deselect();
oc_surface_deselect();
}
if(surface->backend && surface->backend->destroy)
@ -217,64 +217,64 @@ void mg_surface_destroy(mg_surface handle)
surface->backend->destroy(surface->backend);
}
surface->destroy(surface);
mg_handle_recycle(handle.h);
oc_graphics_handle_recycle(handle.h);
}
}
void mg_surface_deselect()
void oc_surface_deselect()
{
DEBUG_ASSERT(__mgData.init);
OC_DEBUG_ASSERT(oc_graphicsData.init);
mg_surface_data* prevSurface = mg_surface_data_from_handle(__mgSelectedSurface);
oc_surface_data* prevSurface = oc_surface_data_from_handle(oc_selectedSurface);
if(prevSurface && prevSurface->deselect)
{
prevSurface->deselect(prevSurface);
}
__mgSelectedSurface = mg_surface_nil();
oc_selectedSurface = oc_surface_nil();
}
void mg_surface_prepare(mg_surface surface)
void oc_surface_select(oc_surface surface)
{
DEBUG_ASSERT(__mgData.init);
OC_DEBUG_ASSERT(oc_graphicsData.init);
if(surface.h != __mgSelectedSurface.h)
if(surface.h != oc_selectedSurface.h)
{
mg_surface_deselect();
oc_surface_deselect();
}
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
oc_surface_data* surfaceData = oc_surface_data_from_handle(surface);
if(surfaceData && surfaceData->prepare)
{
surfaceData->prepare(surfaceData);
__mgSelectedSurface = surface;
oc_selectedSurface = surface;
}
}
void mg_surface_present(mg_surface surface)
void oc_surface_present(oc_surface surface)
{
DEBUG_ASSERT(__mgData.init);
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
OC_DEBUG_ASSERT(oc_graphicsData.init);
oc_surface_data* surfaceData = oc_surface_data_from_handle(surface);
if(surfaceData && surfaceData->present)
{
surfaceData->present(surfaceData);
}
}
void mg_surface_swap_interval(mg_surface surface, int swap)
void oc_surface_swap_interval(oc_surface surface, int swap)
{
DEBUG_ASSERT(__mgData.init);
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
OC_DEBUG_ASSERT(oc_graphicsData.init);
oc_surface_data* surfaceData = oc_surface_data_from_handle(surface);
if(surfaceData && surfaceData->swapInterval)
{
surfaceData->swapInterval(surfaceData, swap);
}
}
vec2 mg_surface_get_size(mg_surface surface)
oc_vec2 oc_surface_get_size(oc_surface surface)
{
DEBUG_ASSERT(__mgData.init);
vec2 size = {0};
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
OC_DEBUG_ASSERT(oc_graphicsData.init);
oc_vec2 size = {0};
oc_surface_data* surfaceData = oc_surface_data_from_handle(surface);
if(surfaceData && surfaceData->getSize)
{
size = surfaceData->getSize(surfaceData);
@ -282,11 +282,11 @@ vec2 mg_surface_get_size(mg_surface surface)
return(size);
}
vec2 mg_surface_contents_scaling(mg_surface surface)
oc_vec2 oc_surface_contents_scaling(oc_surface surface)
{
DEBUG_ASSERT(__mgData.init);
vec2 scaling = {1, 1};
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
OC_DEBUG_ASSERT(oc_graphicsData.init);
oc_vec2 scaling = {1, 1};
oc_surface_data* surfaceData = oc_surface_data_from_handle(surface);
if(surfaceData && surfaceData->contentsScaling)
{
scaling = surfaceData->contentsScaling(surfaceData);
@ -294,21 +294,21 @@ vec2 mg_surface_contents_scaling(mg_surface surface)
return(scaling);
}
void mg_surface_set_hidden(mg_surface surface, bool hidden)
void oc_surface_set_hidden(oc_surface surface, bool hidden)
{
DEBUG_ASSERT(__mgData.init);
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
OC_DEBUG_ASSERT(oc_graphicsData.init);
oc_surface_data* surfaceData = oc_surface_data_from_handle(surface);
if(surfaceData && surfaceData->setHidden)
{
surfaceData->setHidden(surfaceData, hidden);
}
}
bool mg_surface_get_hidden(mg_surface surface)
bool oc_surface_get_hidden(oc_surface surface)
{
DEBUG_ASSERT(__mgData.init);
OC_DEBUG_ASSERT(oc_graphicsData.init);
bool res = false;
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
oc_surface_data* surfaceData = oc_surface_data_from_handle(surface);
if(surfaceData && surfaceData->getHidden)
{
res = surfaceData->getHidden(surfaceData);
@ -316,10 +316,10 @@ bool mg_surface_get_hidden(mg_surface surface)
return(res);
}
void* mg_surface_native_layer(mg_surface surface)
void* oc_surface_native_layer(oc_surface surface)
{
void* res = 0;
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
oc_surface_data* surfaceData = oc_surface_data_from_handle(surface);
if(surfaceData && surfaceData->nativeLayer)
{
res = surfaceData->nativeLayer(surfaceData);
@ -327,10 +327,10 @@ void* mg_surface_native_layer(mg_surface surface)
return(res);
}
mg_surface_id mg_surface_remote_id(mg_surface handle)
oc_surface_id oc_surface_remote_id(oc_surface handle)
{
mg_surface_id remoteId = 0;
mg_surface_data* surface = mg_surface_data_from_handle(handle);
oc_surface_id remoteId = 0;
oc_surface_data* surface = oc_surface_data_from_handle(handle);
if(surface && surface->remoteID)
{
remoteId = surface->remoteID(surface);
@ -338,27 +338,27 @@ mg_surface_id mg_surface_remote_id(mg_surface handle)
return(remoteId);
}
void mg_surface_host_connect(mg_surface handle, mg_surface_id remoteID)
void oc_surface_host_connect(oc_surface handle, oc_surface_id remoteID)
{
mg_surface_data* surface = mg_surface_data_from_handle(handle);
oc_surface_data* surface = oc_surface_data_from_handle(handle);
if(surface && surface->hostConnect)
{
surface->hostConnect(surface, remoteID);
}
}
void mg_surface_render_commands(mg_surface surface,
mg_color clearColor,
void oc_surface_render_commands(oc_surface surface,
oc_color clearColor,
u32 primitiveCount,
mg_primitive* primitives,
oc_primitive* primitives,
u32 eltCount,
mg_path_elt* elements)
oc_path_elt* elements)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
oc_surface_data* surfaceData = oc_surface_data_from_handle(surface);
if(surface.h != __mgSelectedSurface.h)
if(surface.h != oc_selectedSurface.h)
{
log_error("surface is not selected. Make sure to call mg_surface_prepare() before drawing onto a surface.\n");
oc_log_error("surface is not selected. Make sure to call oc_surface_select() before drawing onto a surface.\n");
}
else if(surfaceData && surfaceData->backend)
{
@ -375,10 +375,10 @@ void mg_surface_render_commands(mg_surface surface,
//NOTE(martin): images
//------------------------------------------------------------------------------------------
vec2 mg_image_size(mg_image image)
oc_vec2 oc_image_size(oc_image image)
{
vec2 res = {0};
mg_image_data* imageData = mg_image_data_from_handle(image);
oc_vec2 res = {0};
oc_image_data* imageData = oc_image_data_from_handle(image);
if(imageData)
{
res = imageData->size;
@ -386,67 +386,67 @@ vec2 mg_image_size(mg_image image)
return(res);
}
mg_image mg_image_create(mg_surface surface, u32 width, u32 height)
oc_image oc_image_create(oc_surface surface, u32 width, u32 height)
{
mg_image image = mg_image_nil();
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
oc_image image = oc_image_nil();
oc_surface_data* surfaceData = oc_surface_data_from_handle(surface);
if(surface.h != __mgSelectedSurface.h)
if(surface.h != oc_selectedSurface.h)
{
log_error("surface is not selected. Make sure to call mg_surface_prepare() before modifying graphics resources.\n");
oc_log_error("surface is not selected. Make sure to call oc_surface_select() before modifying graphics resources.\n");
}
else if(surfaceData && surfaceData->backend)
{
DEBUG_ASSERT(surfaceData->api == MG_CANVAS);
OC_DEBUG_ASSERT(surfaceData->api == OC_CANVAS);
mg_image_data* imageData = surfaceData->backend->imageCreate(surfaceData->backend, (vec2){width, height});
oc_image_data* imageData = surfaceData->backend->imageCreate(surfaceData->backend, (oc_vec2){width, height});
if(imageData)
{
imageData->surface = surface;
image = mg_image_handle_alloc(imageData);
image = oc_image_handle_alloc(imageData);
}
}
return(image);
}
void mg_image_destroy(mg_image image)
void oc_image_destroy(oc_image image)
{
mg_image_data* imageData = mg_image_data_from_handle(image);
oc_image_data* imageData = oc_image_data_from_handle(image);
if(imageData)
{
if(imageData->surface.h != __mgSelectedSurface.h)
if(imageData->surface.h != oc_selectedSurface.h)
{
log_error("surface is not selected. Make sure to call mg_surface_prepare() before modifying graphics resources.\n");
oc_log_error("surface is not selected. Make sure to call oc_surface_select() before modifying graphics resources.\n");
}
else
{
mg_surface_data* surface = mg_surface_data_from_handle(imageData->surface);
oc_surface_data* surface = oc_surface_data_from_handle(imageData->surface);
if(surface && surface->backend)
{
surface->backend->imageDestroy(surface->backend, imageData);
mg_handle_recycle(image.h);
oc_graphics_handle_recycle(image.h);
}
}
}
}
void mg_image_upload_region_rgba8(mg_image image, mp_rect region, u8* pixels)
void oc_image_upload_region_rgba8(oc_image image, oc_rect region, u8* pixels)
{
mg_image_data* imageData = mg_image_data_from_handle(image);
oc_image_data* imageData = oc_image_data_from_handle(image);
if(imageData)
{
if(imageData->surface.h != __mgSelectedSurface.h)
if(imageData->surface.h != oc_selectedSurface.h)
{
log_error("surface is not selected. Make sure to call mg_surface_prepare() before modifying graphics resources.\n");
oc_log_error("surface is not selected. Make sure to call oc_surface_select() before modifying graphics resources.\n");
}
else
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(imageData->surface);
oc_surface_data* surfaceData = oc_surface_data_from_handle(imageData->surface);
if(surfaceData)
{
DEBUG_ASSERT(surfaceData->backend);
OC_DEBUG_ASSERT(surfaceData->backend);
surfaceData->backend->imageUploadRegion(surfaceData->backend, imageData, region, pixels);
}
}

View File

@ -9,7 +9,7 @@
#define __GRAPHICS_SURFACE_H_
#include"graphics_common.h"
#include"app/mp_app_internal.h"
#include"app/app_internal.h"
#ifdef __cplusplus
extern "C" {
@ -18,92 +18,92 @@ extern "C" {
//---------------------------------------------------------------
// surface interface
//---------------------------------------------------------------
typedef struct mg_surface_data mg_surface_data;
typedef struct mg_canvas_backend mg_canvas_backend;
typedef struct oc_surface_data oc_surface_data;
typedef struct oc_canvas_backend oc_canvas_backend;
typedef void (*mg_surface_destroy_proc)(mg_surface_data* surface);
typedef void (*mg_surface_prepare_proc)(mg_surface_data* surface);
typedef void (*mg_surface_deselect_proc)(mg_surface_data* surface);
typedef void (*mg_surface_present_proc)(mg_surface_data* surface);
typedef void (*mg_surface_swap_interval_proc)(mg_surface_data* surface, int swap);
typedef vec2 (*mg_surface_get_size_proc)(mg_surface_data* surface);
typedef vec2 (*mg_surface_contents_scaling_proc)(mg_surface_data* surface);
typedef bool (*mg_surface_get_hidden_proc)(mg_surface_data* surface);
typedef void (*mg_surface_set_hidden_proc)(mg_surface_data* surface, bool hidden);
typedef void* (*mg_surface_native_layer_proc)(mg_surface_data* surface);
typedef mg_surface_id (*mg_surface_remote_id_proc)(mg_surface_data* surface);
typedef void (*mg_surface_host_connect_proc)(mg_surface_data* surface, mg_surface_id remoteId);
typedef void (*oc_surface_destroy_proc)(oc_surface_data* surface);
typedef void (*oc_surface_select_proc)(oc_surface_data* surface);
typedef void (*oc_surface_deselect_proc)(oc_surface_data* surface);
typedef void (*oc_surface_present_proc)(oc_surface_data* surface);
typedef void (*oc_surface_swap_interval_proc)(oc_surface_data* surface, int swap);
typedef oc_vec2 (*oc_surface_get_size_proc)(oc_surface_data* surface);
typedef oc_vec2 (*oc_surface_contents_scaling_proc)(oc_surface_data* surface);
typedef bool (*oc_surface_get_hidden_proc)(oc_surface_data* surface);
typedef void (*oc_surface_set_hidden_proc)(oc_surface_data* surface, bool hidden);
typedef void* (*oc_surface_native_layer_proc)(oc_surface_data* surface);
typedef oc_surface_id (*oc_surface_remote_id_proc)(oc_surface_data* surface);
typedef void (*oc_surface_host_connect_proc)(oc_surface_data* surface, oc_surface_id remoteId);
typedef struct mg_surface_data
typedef struct oc_surface_data
{
mg_surface_api api;
mp_layer layer;
oc_surface_api api;
oc_layer layer;
mg_surface_destroy_proc destroy;
mg_surface_prepare_proc prepare;
mg_surface_present_proc present;
mg_surface_deselect_proc deselect;
mg_surface_swap_interval_proc swapInterval;
mg_surface_get_size_proc getSize;
mg_surface_contents_scaling_proc contentsScaling;
mg_surface_get_hidden_proc getHidden;
mg_surface_set_hidden_proc setHidden;
mg_surface_native_layer_proc nativeLayer;
mg_surface_remote_id_proc remoteID;
mg_surface_host_connect_proc hostConnect;
oc_surface_destroy_proc destroy;
oc_surface_select_proc prepare;
oc_surface_present_proc present;
oc_surface_deselect_proc deselect;
oc_surface_swap_interval_proc swapInterval;
oc_surface_get_size_proc getSize;
oc_surface_contents_scaling_proc contentsScaling;
oc_surface_get_hidden_proc getHidden;
oc_surface_set_hidden_proc setHidden;
oc_surface_native_layer_proc nativeLayer;
oc_surface_remote_id_proc remoteID;
oc_surface_host_connect_proc hostConnect;
mg_canvas_backend* backend;
oc_canvas_backend* backend;
} mg_surface_data;
} oc_surface_data;
mg_surface mg_surface_alloc_handle(mg_surface_data* surface);
mg_surface_data* mg_surface_data_from_handle(mg_surface handle);
oc_surface oc_surface_handle_alloc(oc_surface_data* surface);
oc_surface_data* oc_surface_data_from_handle(oc_surface handle);
void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window);
void mg_surface_init_remote(mg_surface_data* surface, u32 width, u32 height);
void mg_surface_init_host(mg_surface_data* surface, mp_window_data* window);
void mg_surface_cleanup(mg_surface_data* surface);
void* mg_surface_native_layer(mg_surface surface);
void oc_surface_init_for_window(oc_surface_data* surface, oc_window_data* window);
void oc_surface_init_remote(oc_surface_data* surface, u32 width, u32 height);
void oc_surface_init_host(oc_surface_data* surface, oc_window_data* window);
void oc_surface_cleanup(oc_surface_data* surface);
void* oc_surface_native_layer(oc_surface surface);
//---------------------------------------------------------------
// canvas backend interface
//---------------------------------------------------------------
typedef struct mg_image_data
typedef struct oc_image_data
{
list_elt listElt;
oc_list_elt listElt;
u32 generation;
mg_surface surface;
vec2 size;
oc_surface surface;
oc_vec2 size;
} mg_image_data;
} oc_image_data;
typedef void (*mg_canvas_backend_destroy_proc)(mg_canvas_backend* backend);
typedef void (*oc_canvas_backend_destroy_proc)(oc_canvas_backend* backend);
typedef mg_image_data* (*mg_canvas_backend_image_create_proc)(mg_canvas_backend* backend, vec2 size);
typedef void (*mg_canvas_backend_image_destroy_proc)(mg_canvas_backend* backend, mg_image_data* image);
typedef void (*mg_canvas_backend_image_upload_region_proc)(mg_canvas_backend* backend,
mg_image_data* image,
mp_rect region,
typedef oc_image_data* (*oc_canvas_backend_image_create_proc)(oc_canvas_backend* backend, oc_vec2 size);
typedef void (*oc_canvas_backend_image_destroy_proc)(oc_canvas_backend* backend, oc_image_data* image);
typedef void (*oc_canvas_backend_image_upload_region_proc)(oc_canvas_backend* backend,
oc_image_data* image,
oc_rect region,
u8* pixels);
typedef void (*mg_canvas_backend_render_proc)(mg_canvas_backend* backend,
mg_color clearColor,
typedef void (*oc_canvas_backend_render_proc)(oc_canvas_backend* backend,
oc_color clearColor,
u32 primitiveCount,
mg_primitive* primitives,
oc_primitive* primitives,
u32 eltCount,
mg_path_elt* pathElements);
oc_path_elt* pathElements);
typedef struct mg_canvas_backend
typedef struct oc_canvas_backend
{
mg_canvas_backend_destroy_proc destroy;
oc_canvas_backend_destroy_proc destroy;
mg_canvas_backend_image_create_proc imageCreate;
mg_canvas_backend_image_destroy_proc imageDestroy;
mg_canvas_backend_image_upload_region_proc imageUploadRegion;
oc_canvas_backend_image_create_proc imageCreate;
oc_canvas_backend_image_destroy_proc imageDestroy;
oc_canvas_backend_image_upload_region_proc imageUploadRegion;
mg_canvas_backend_render_proc render;
oc_canvas_backend_render_proc render;
} mg_canvas_backend;
} oc_canvas_backend;
#ifdef __cplusplus
} // extern "C"

View File

@ -12,45 +12,45 @@
#include<simd/simd.h>
typedef enum {
MG_MTL_FILL,
MG_MTL_STROKE,
} mg_mtl_cmd;
OC_MTL_FILL,
OC_MTL_STROKE,
} oc_mtl_cmd;
typedef struct mg_mtl_path
typedef struct oc_mtl_path
{
mg_mtl_cmd cmd;
oc_mtl_cmd cmd;
matrix_float3x3 uvTransform;
vector_float4 color;
vector_float4 box;
vector_float4 clip;
int texture;
} mg_mtl_path;
} oc_mtl_path;
typedef enum {
MG_MTL_LINE = 1,
MG_MTL_QUADRATIC,
MG_MTL_CUBIC,
} mg_mtl_seg_kind;
OC_MTL_LINE = 1,
OC_MTL_QUADRATIC,
OC_MTL_CUBIC,
} oc_mtl_seg_kind;
typedef struct mg_mtl_path_elt
typedef struct oc_mtl_path_elt
{
int pathIndex;
mg_mtl_seg_kind kind;
oc_mtl_seg_kind kind;
vector_float2 p[4];
} mg_mtl_path_elt;
} oc_mtl_path_elt;
typedef enum {
MG_MTL_BL, // curve on bottom left
MG_MTL_BR, // curve on bottom right
MG_MTL_TL, // curve on top left
MG_MTL_TR // curve on top right
} mg_mtl_seg_config;
OC_MTL_BL, // curve on bottom left
OC_MTL_BR, // curve on bottom right
OC_MTL_TL, // curve on top left
OC_MTL_TR // curve on top right
} oc_mtl_seg_config;
typedef struct mg_mtl_segment
typedef struct oc_mtl_segment
{
mg_mtl_seg_kind kind;
oc_mtl_seg_kind kind;
int pathIndex;
mg_mtl_seg_config config; //TODO pack these
oc_mtl_seg_config config; //TODO pack these
int windingIncrement;
vector_float4 box;
matrix_float3x3 implicitMatrix;
@ -58,27 +58,27 @@ typedef struct mg_mtl_segment
vector_float2 hullVertex;
int debugID;
} mg_mtl_segment;
} oc_mtl_segment;
typedef struct mg_mtl_path_queue
typedef struct oc_mtl_path_queue
{
vector_int4 area;
int tileQueues;
} mg_mtl_path_queue;
} oc_mtl_path_queue;
#ifdef __METAL_VERSION__
using namespace metal;
#endif
typedef enum { MG_MTL_OP_FILL,
MG_MTL_OP_CLIP_FILL,
MG_MTL_OP_START,
MG_MTL_OP_END,
MG_MTL_OP_SEGMENT } mg_mtl_tile_op_kind;
typedef enum { OC_MTL_OP_FILL,
OC_MTL_OP_CLIP_FILL,
OC_MTL_OP_START,
OC_MTL_OP_END,
OC_MTL_OP_SEGMENT } oc_mtl_tile_op_kind;
typedef struct mg_mtl_tile_op
typedef struct oc_mtl_tile_op
{
mg_mtl_tile_op_kind kind;
oc_mtl_tile_op_kind kind;
int index;
int next;
union
@ -87,25 +87,25 @@ typedef struct mg_mtl_tile_op
int windingOffset;
};
} mg_mtl_tile_op;
} oc_mtl_tile_op;
typedef struct mg_mtl_tile_queue
typedef struct oc_mtl_tile_queue
{
atomic_int windingOffset;
atomic_int first;
int last;
} mg_mtl_tile_queue;
} oc_mtl_tile_queue;
typedef struct mg_mtl_screen_tile
typedef struct oc_mtl_screen_tile
{
vector_uint2 tileCoord;
int first;
} mg_mtl_screen_tile;
} oc_mtl_screen_tile;
enum {
MG_MTL_MAX_IMAGES_PER_BATCH = 30
OC_MTL_MAX_IMAGES_PER_BATCH = 30
};
#endif //__MTL_RENDERER_H_

File diff suppressed because it is too large Load Diff

View File

@ -227,16 +227,16 @@ void log_cubic_bezier(thread float2* p, mtl_log_context logCtx)
}
kernel void mtl_path_setup(constant int* pathCount [[buffer(0)]],
const device mg_mtl_path* pathBuffer [[buffer(1)]],
device mg_mtl_path_queue* pathQueueBuffer [[buffer(2)]],
device mg_mtl_tile_queue* tileQueueBuffer [[buffer(3)]],
const device oc_mtl_path* pathBuffer [[buffer(1)]],
device oc_mtl_path_queue* pathQueueBuffer [[buffer(2)]],
device oc_mtl_tile_queue* tileQueueBuffer [[buffer(3)]],
device atomic_int* tileQueueCount [[buffer(4)]],
constant int* tileQueueMax [[buffer(5)]],
constant int* tileSize [[buffer(6)]],
constant float* scale [[buffer(7)]],
uint pathIndex [[thread_position_in_grid]])
{
const device mg_mtl_path* path = &pathBuffer[pathIndex];
const device oc_mtl_path* path = &pathBuffer[pathIndex];
//NOTE: we don't clip on the right, since we need those tiles to accurately compute
@ -265,7 +265,7 @@ kernel void mtl_path_setup(constant int* pathCount [[buffer(0)]],
pathQueueBuffer[pathIndex].area = int4(firstTile.x, firstTile.y, nTilesX, nTilesY);
pathQueueBuffer[pathIndex].tileQueues = tileQueuesIndex;
device mg_mtl_tile_queue* tileQueues = &tileQueueBuffer[tileQueuesIndex];
device oc_mtl_tile_queue* tileQueues = &tileQueueBuffer[tileQueuesIndex];
for(int i=0; i<tileCount; i++)
{
@ -281,7 +281,7 @@ float ccw(float2 a, float2 b, float2 c)
return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
}
int mtl_side_of_segment(float2 p, const device mg_mtl_segment* seg, mtl_log_context log = {.enabled = false})
int mtl_side_of_segment(float2 p, const device oc_mtl_segment* seg, mtl_log_context log = {.enabled = false})
{
int side = 0;
if(p.y > seg->box.w || p.y <= seg->box.y)
@ -290,11 +290,11 @@ int mtl_side_of_segment(float2 p, const device mg_mtl_segment* seg, mtl_log_cont
{
if(p.y > seg->box.w)
{
side = (seg->config == MG_MTL_TL || seg->config == MG_MTL_BR)? -1 : 1;
side = (seg->config == OC_MTL_TL || seg->config == OC_MTL_BR)? -1 : 1;
}
else
{
side = (seg->config == MG_MTL_TL || seg->config == MG_MTL_BR)? 1 : -1;
side = (seg->config == OC_MTL_TL || seg->config == OC_MTL_BR)? 1 : -1;
}
}
}
@ -311,22 +311,22 @@ int mtl_side_of_segment(float2 p, const device mg_mtl_segment* seg, mtl_log_cont
float2 a, b, c;
switch(seg->config)
{
case MG_MTL_TL:
case OC_MTL_TL:
a = seg->box.xy;
b = seg->box.zw;
break;
case MG_MTL_BR:
case OC_MTL_BR:
a = seg->box.zw;
b = seg->box.xy;
break;
case MG_MTL_TR:
case OC_MTL_TR:
a = seg->box.xw;
b = seg->box.zy;
break;
case MG_MTL_BL:
case OC_MTL_BL:
a = seg->box.zy;
b = seg->box.xw;
break;
@ -336,30 +336,30 @@ int mtl_side_of_segment(float2 p, const device mg_mtl_segment* seg, mtl_log_cont
if(ccw(a, b, p) < 0)
{
// other side of the diagonal
side = (seg->config == MG_MTL_BR || seg->config == MG_MTL_TR) ? -1 : 1;
side = (seg->config == OC_MTL_BR || seg->config == OC_MTL_TR) ? -1 : 1;
}
else if(ccw(b, c, p) < 0 || ccw(c, a, p) < 0)
{
// same side of the diagonal, but outside curve hull
side = (seg->config == MG_MTL_BL || seg->config == MG_MTL_TL) ? -1 : 1;
side = (seg->config == OC_MTL_BL || seg->config == OC_MTL_TL) ? -1 : 1;
}
else
{
// inside curve hull
switch(seg->kind)
{
case MG_MTL_LINE:
case OC_MTL_LINE:
side = 1;
break;
case MG_MTL_QUADRATIC:
case OC_MTL_QUADRATIC:
{
float3 ph = {p.x, p.y, 1};
float3 klm = seg->implicitMatrix * ph;
side = ((klm.x*klm.x - klm.y)*klm.z < 0)? -1 : 1;
} break;
case MG_MTL_CUBIC:
case OC_MTL_CUBIC:
{
float3 ph = {p.x, p.y, 1};
float3 klm = seg->implicitMatrix * ph;
@ -375,10 +375,10 @@ int mtl_side_of_segment(float2 p, const device mg_mtl_segment* seg, mtl_log_cont
typedef struct mtl_segment_setup_context
{
device atomic_int* segmentCount;
device mg_mtl_segment* segmentBuffer;
const device mg_mtl_path_queue* pathQueue;
device mg_mtl_tile_queue* tileQueues;
device mg_mtl_tile_op* tileOpBuffer;
device oc_mtl_segment* segmentBuffer;
const device oc_mtl_path_queue* pathQueue;
device oc_mtl_tile_queue* tileQueues;
device oc_mtl_tile_op* tileOpBuffer;
device atomic_int* tileOpCount;
int tileSize;
mtl_log_context log;
@ -390,7 +390,7 @@ typedef struct mtl_segment_setup_context
} mtl_segment_setup_context;
void mtl_segment_bin_to_tiles(thread mtl_segment_setup_context* context, device mg_mtl_segment* seg)
void mtl_segment_bin_to_tiles(thread mtl_segment_setup_context* context, device oc_mtl_segment* seg)
{
//NOTE: add segment index to the queues of tiles it overlaps with
int segIndex = seg - context->segmentBuffer;
@ -428,7 +428,7 @@ void mtl_segment_bin_to_tiles(thread mtl_segment_setup_context* context, device
bool crossB = (sbl*sbr < 0);
float2 s0, s1;
if(seg->config == MG_MTL_TL||seg->config == MG_MTL_BR)
if(seg->config == OC_MTL_TL||seg->config == OC_MTL_BR)
{
s0 = seg->box.xy;
s1 = seg->box.zw;
@ -454,15 +454,15 @@ void mtl_segment_bin_to_tiles(thread mtl_segment_setup_context* context, device
if(tileOpIndex < context->tileOpMax)
{
device mg_mtl_tile_op* op = &context->tileOpBuffer[tileOpIndex];
device oc_mtl_tile_op* op = &context->tileOpBuffer[tileOpIndex];
op->kind = MG_MTL_OP_SEGMENT;
op->kind = OC_MTL_OP_SEGMENT;
op->index = segIndex;
op->crossRight = false;
op->next = -1;
int tileIndex = y*pathArea.z + x;
device mg_mtl_tile_queue* tile = &context->tileQueues[tileIndex];
device oc_mtl_tile_queue* tile = &context->tileQueues[tileIndex];
op->next = atomic_exchange_explicit(&tile->first, tileOpIndex, memory_order_relaxed);
if(op->next == -1)
{
@ -489,25 +489,25 @@ void mtl_segment_bin_to_tiles(thread mtl_segment_setup_context* context, device
}
}
device mg_mtl_segment* mtl_segment_push(thread mtl_segment_setup_context* context, float2 p[4], mg_mtl_seg_kind kind)
device oc_mtl_segment* mtl_segment_push(thread mtl_segment_setup_context* context, float2 p[4], oc_mtl_seg_kind kind)
{
float2 s, e, c;
switch(kind)
{
case MG_MTL_LINE:
case OC_MTL_LINE:
s = p[0];
c = p[0];
e = p[1];
break;
case MG_MTL_QUADRATIC:
case OC_MTL_QUADRATIC:
s = p[0];
c = p[1];
e = p[2];
break;
case MG_MTL_CUBIC:
case OC_MTL_CUBIC:
{
s = p[0];
float sqrNorm0 = length_squared(p[1]-p[0]);
@ -524,7 +524,7 @@ device mg_mtl_segment* mtl_segment_push(thread mtl_segment_setup_context* contex
} break;
}
device mg_mtl_segment* seg = 0;
device oc_mtl_segment* seg = 0;
int segIndex = atomic_fetch_add_explicit(context->segmentCount, 1, memory_order_relaxed);
@ -551,32 +551,32 @@ device mg_mtl_segment* mtl_segment_push(thread mtl_segment_setup_context* contex
if(goingUp == goingRight)
{
if(seg->kind == MG_MTL_LINE)
if(seg->kind == OC_MTL_LINE)
{
seg->config = MG_MTL_BR;
seg->config = OC_MTL_BR;
}
else if(dy > alpha*dx)
{
seg->config = MG_MTL_TL;
seg->config = OC_MTL_TL;
}
else
{
seg->config = MG_MTL_BR;
seg->config = OC_MTL_BR;
}
}
else
{
if(seg->kind == MG_MTL_LINE)
if(seg->kind == OC_MTL_LINE)
{
seg->config = MG_MTL_TR;
seg->config = OC_MTL_TR;
}
else if(dy < ofs - alpha*dx)
{
seg->config = MG_MTL_BL;
seg->config = OC_MTL_BL;
}
else
{
seg->config = MG_MTL_TR;
seg->config = OC_MTL_TR;
}
}
}
@ -588,7 +588,7 @@ device mg_mtl_segment* mtl_segment_push(thread mtl_segment_setup_context* contex
void mtl_line_setup(thread mtl_segment_setup_context* context, float2 p[2])
{
device mg_mtl_segment* seg = mtl_segment_push(context, p, MG_MTL_LINE);
device oc_mtl_segment* seg = mtl_segment_push(context, p, OC_MTL_LINE);
if(seg)
{
seg->hullVertex = p[0];
@ -659,7 +659,7 @@ matrix_float3x3 mtl_barycentric_matrix(float2 v0, float2 v1, float2 v2)
void mtl_quadratic_emit(thread mtl_segment_setup_context* context,
thread float2* p)
{
device mg_mtl_segment* seg = mtl_segment_push(context, p, MG_MTL_QUADRATIC);
device oc_mtl_segment* seg = mtl_segment_push(context, p, OC_MTL_QUADRATIC);
if(seg)
{
@ -673,7 +673,7 @@ void mtl_quadratic_emit(thread mtl_segment_setup_context* context,
float e = p[1].x - p[0].x;
float f = p[0].x*p[1].y - p[1].x*p[0].y;
float flip = (seg->config == MG_MTL_TL || seg->config == MG_MTL_BL)? -1 : 1;
float flip = (seg->config == OC_MTL_TL || seg->config == OC_MTL_BL)? -1 : 1;
float g = flip*(p[2].x*(p[0].y - p[1].y) + p[0].x*(p[1].y - p[2].y) + p[1].x*(p[2].y - p[0].y));
seg->implicitMatrix = (1/det)*matrix_float3x3({a, d, 0.},
@ -1070,7 +1070,7 @@ float2 mtl_select_hull_vertex(float2 p0, float2 p1, float2 p2, float2 p3, mtl_lo
void mtl_cubic_emit(thread mtl_segment_setup_context* context, mtl_cubic_info curve, float2 p[4], float s0, float s1, float2 sp[4])
{
device mg_mtl_segment* seg = mtl_segment_push(context, sp, MG_MTL_CUBIC);
device oc_mtl_segment* seg = mtl_segment_push(context, sp, OC_MTL_CUBIC);
if(seg)
{
@ -1253,12 +1253,12 @@ void mtl_cubic_setup(thread mtl_segment_setup_context* context, float2 p[4])
}
kernel void mtl_segment_setup(constant int* elementCount [[buffer(0)]],
const device mg_mtl_path_elt* elementBuffer [[buffer(1)]],
const device oc_mtl_path_elt* elementBuffer [[buffer(1)]],
device atomic_int* segmentCount [[buffer(2)]],
device mg_mtl_segment* segmentBuffer [[buffer(3)]],
const device mg_mtl_path_queue* pathQueueBuffer [[buffer(4)]],
device mg_mtl_tile_queue* tileQueueBuffer [[buffer(5)]],
device mg_mtl_tile_op* tileOpBuffer [[buffer(6)]],
device oc_mtl_segment* segmentBuffer [[buffer(3)]],
const device oc_mtl_path_queue* pathQueueBuffer [[buffer(4)]],
device oc_mtl_tile_queue* tileQueueBuffer [[buffer(5)]],
device oc_mtl_tile_op* tileOpBuffer [[buffer(6)]],
device atomic_int* tileOpCount [[buffer(7)]],
constant int* segmentMax [[buffer(8)]],
constant int* tileOpMax [[buffer(9)]],
@ -1269,9 +1269,9 @@ kernel void mtl_segment_setup(constant int* elementCount [[buffer(0)]],
device atomic_int* logOffsetBuffer [[buffer(13)]],
uint eltIndex [[thread_position_in_grid]])
{
const device mg_mtl_path_elt* elt = &elementBuffer[eltIndex];
const device mg_mtl_path_queue* pathQueue = &pathQueueBuffer[elt->pathIndex];
device mg_mtl_tile_queue* tileQueues = &tileQueueBuffer[pathQueue->tileQueues];
const device oc_mtl_path_elt* elt = &elementBuffer[eltIndex];
const device oc_mtl_path_queue* pathQueue = &pathQueueBuffer[elt->pathIndex];
device oc_mtl_tile_queue* tileQueues = &tileQueueBuffer[pathQueue->tileQueues];
mtl_segment_setup_context setupCtx = {.pathIndex = elt->pathIndex,
.segmentCount = segmentCount,
@ -1289,7 +1289,7 @@ kernel void mtl_segment_setup(constant int* elementCount [[buffer(0)]],
switch(elt->kind)
{
case MG_MTL_LINE:
case OC_MTL_LINE:
{
float2 p[2] = {elt->p[0]*scale[0], elt->p[1]*scale[0]};
mtl_log(setupCtx.log, "line: ");
@ -1297,7 +1297,7 @@ kernel void mtl_segment_setup(constant int* elementCount [[buffer(0)]],
mtl_line_setup(&setupCtx, p);
} break;
case MG_MTL_QUADRATIC:
case OC_MTL_QUADRATIC:
{
float2 p[3] = {elt->p[0]*scale[0], elt->p[1]*scale[0], elt->p[2]*scale[0]};
mtl_log(setupCtx.log, "quadratic: ");
@ -1305,7 +1305,7 @@ kernel void mtl_segment_setup(constant int* elementCount [[buffer(0)]],
mtl_quadratic_setup(&setupCtx, p);
} break;
case MG_MTL_CUBIC:
case OC_MTL_CUBIC:
{
float2 p[4] = {elt->p[0]*scale[0], elt->p[1]*scale[0], elt->p[2]*scale[0], elt->p[3]*scale[0]};
mtl_log(setupCtx.log, "cubic: ");
@ -1316,8 +1316,8 @@ kernel void mtl_segment_setup(constant int* elementCount [[buffer(0)]],
}
}
kernel void mtl_backprop(const device mg_mtl_path_queue* pathQueueBuffer [[buffer(0)]],
device mg_mtl_tile_queue* tileQueueBuffer [[buffer(1)]],
kernel void mtl_backprop(const device oc_mtl_path_queue* pathQueueBuffer [[buffer(0)]],
device oc_mtl_tile_queue* tileQueueBuffer [[buffer(1)]],
device char* logBuffer [[buffer(2)]],
device atomic_int* logOffsetBuffer [[buffer(3)]],
uint pathIndex [[threadgroup_position_in_grid]],
@ -1333,19 +1333,19 @@ kernel void mtl_backprop(const device mg_mtl_path_queue* pathQueueBuffer [[buffe
threadgroup_barrier(mem_flags::mem_threadgroup);
int rowIndex = 0;
const device mg_mtl_path_queue* pathQueue = &pathQueueBuffer[pathIndex];
device mg_mtl_tile_queue* tiles = &tileQueueBuffer[pathQueue->tileQueues];
const device oc_mtl_path_queue* pathQueue = &pathQueueBuffer[pathIndex];
device oc_mtl_tile_queue* tiles = &tileQueueBuffer[pathQueue->tileQueues];
int rowSize = pathQueue->area.z;
int rowCount = pathQueue->area.w;
rowIndex = atomic_fetch_add_explicit(&nextRowIndex, 1, memory_order_relaxed);
while(rowIndex < rowCount)
{
device mg_mtl_tile_queue* row = &tiles[rowIndex * rowSize];
device oc_mtl_tile_queue* row = &tiles[rowIndex * rowSize];
int sum = 0;
for(int x = rowSize-1; x >= 0; x--)
{
device mg_mtl_tile_queue* tile = &row[x];
device oc_mtl_tile_queue* tile = &row[x];
int offset = *(device int*)&tile->windingOffset;
*(device int*)(&tile->windingOffset) = sum;
sum += offset;
@ -1355,13 +1355,13 @@ kernel void mtl_backprop(const device mg_mtl_path_queue* pathQueueBuffer [[buffe
}
kernel void mtl_merge(constant int* pathCount [[buffer(0)]],
const device mg_mtl_path* pathBuffer [[buffer(1)]],
const device mg_mtl_path_queue* pathQueueBuffer [[buffer(2)]],
const device mg_mtl_tile_queue* tileQueueBuffer [[buffer(3)]],
device mg_mtl_tile_op* tileOpBuffer [[buffer(4)]],
const device oc_mtl_path* pathBuffer [[buffer(1)]],
const device oc_mtl_path_queue* pathQueueBuffer [[buffer(2)]],
const device oc_mtl_tile_queue* tileQueueBuffer [[buffer(3)]],
device oc_mtl_tile_op* tileOpBuffer [[buffer(4)]],
device atomic_int* tileOpCount [[buffer(5)]],
device MTLDispatchThreadgroupsIndirectArguments* dispatchBuffer [[buffer(6)]],
device mg_mtl_screen_tile* screenTilesBuffer [[buffer(7)]],
device oc_mtl_screen_tile* screenTilesBuffer [[buffer(7)]],
constant int* tileOpMax [[buffer(8)]],
constant int* tileSize [[buffer(9)]],
constant float* scale [[buffer(10)]],
@ -1384,10 +1384,10 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]],
for(int pathIndex = 0; pathIndex < pathCount[0]; pathIndex++)
{
const device mg_mtl_path_queue* pathQueue = &pathQueueBuffer[pathIndex];
const device oc_mtl_path_queue* pathQueue = &pathQueueBuffer[pathIndex];
int2 pathTileCoord = tileCoord - pathQueue->area.xy;
const device mg_mtl_path* path = &pathBuffer[pathIndex];
const device oc_mtl_path* path = &pathBuffer[pathIndex];
float xMax = min(path->box.z, path->clip.z);
int tileMaxX = xMax * scale[0] / tileSize[0];
int pathTileMaxX = tileMaxX - pathQueue->area.x;
@ -1406,7 +1406,7 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]],
}
int pathTileIndex = pathTileCoord.y * pathQueue->area.z + pathTileCoord.x;
const device mg_mtl_tile_queue* tileQueue = &tileQueueBuffer[pathQueue->tileQueues + pathTileIndex];
const device oc_mtl_tile_queue* tileQueue = &tileQueueBuffer[pathQueue->tileQueues + pathTileIndex];
int windingOffset = atomic_load_explicit(&tileQueue->windingOffset, memory_order_relaxed);
int firstOpIndex = atomic_load_explicit(&tileQueue->first, memory_order_relaxed);
@ -1435,8 +1435,8 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]],
return;
}
device mg_mtl_tile_op* pathOp = &tileOpBuffer[pathOpIndex];
pathOp->kind = MG_MTL_OP_CLIP_FILL;
device oc_mtl_tile_op* pathOp = &tileOpBuffer[pathOpIndex];
pathOp->kind = OC_MTL_OP_CLIP_FILL;
pathOp->next = -1;
pathOp->index = pathIndex;
pathOp->windingOffset = windingOffset;
@ -1448,7 +1448,7 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]],
&& tileBox.y >= clip.y
&& tileBox.w < clip.w)
{
pathOp->kind = MG_MTL_OP_FILL;
pathOp->kind = OC_MTL_OP_FILL;
if(pathBuffer[pathIndex].color.a == 1 && pathBuffer[pathIndex].texture < 0)
{
@ -1468,8 +1468,8 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]],
return;
}
device mg_mtl_tile_op* startOp = &tileOpBuffer[startOpIndex];
startOp->kind = MG_MTL_OP_START;
device oc_mtl_tile_op* startOp = &tileOpBuffer[startOpIndex];
startOp->kind = OC_MTL_OP_START;
startOp->next = -1;
startOp->index = pathIndex;
startOp->windingOffset = windingOffset;
@ -1479,7 +1479,7 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]],
//NOTE: chain remaining path ops to end of tile list
int lastOpIndex = tileQueue->last;
device mg_mtl_tile_op* lastOp = &tileOpBuffer[lastOpIndex];
device oc_mtl_tile_op* lastOp = &tileOpBuffer[lastOpIndex];
*nextLink = firstOpIndex;
nextLink = &lastOp->next;
@ -1491,8 +1491,8 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]],
return;
}
device mg_mtl_tile_op* endOp = &tileOpBuffer[endOpIndex];
endOp->kind = MG_MTL_OP_END;
device oc_mtl_tile_op* endOp = &tileOpBuffer[endOpIndex];
endOp->kind = OC_MTL_OP_END;
endOp->next = -1;
endOp->index = pathIndex;
@ -1503,17 +1503,17 @@ kernel void mtl_merge(constant int* pathCount [[buffer(0)]],
}
}
kernel void mtl_raster(const device mg_mtl_screen_tile* screenTilesBuffer [[buffer(0)]],
const device mg_mtl_tile_op* tileOpBuffer [[buffer(1)]],
const device mg_mtl_path* pathBuffer [[buffer(2)]],
const device mg_mtl_segment* segmentBuffer [[buffer(3)]],
kernel void mtl_raster(const device oc_mtl_screen_tile* screenTilesBuffer [[buffer(0)]],
const device oc_mtl_tile_op* tileOpBuffer [[buffer(1)]],
const device oc_mtl_path* pathBuffer [[buffer(2)]],
const device oc_mtl_segment* segmentBuffer [[buffer(3)]],
constant int* tileSize [[buffer(4)]],
constant float* scale [[buffer(5)]],
constant int* sampleCountBuffer [[buffer(6)]],
device char* logBuffer [[buffer(7)]],
device atomic_int* logOffsetBuffer [[buffer(8)]],
texture2d<float, access::write> outTexture [[texture(0)]],
array<texture2d<float>, MG_MTL_MAX_IMAGES_PER_BATCH> srcTextures [[texture(1)]],
array<texture2d<float>, OC_MTL_MAX_IMAGES_PER_BATCH> srcTextures [[texture(1)]],
uint2 threadGroupCoord [[threadgroup_position_in_grid]],
uint2 localCoord [[thread_position_in_threadgroup]])
{
@ -1528,8 +1528,8 @@ kernel void mtl_raster(const device mg_mtl_screen_tile* screenTilesBuffer [[buff
int opIndex = screenTilesBuffer[tileIndex].first;
const int MG_MTL_MAX_SAMPLE_COUNT = 8;
float2 sampleCoords[MG_MTL_MAX_SAMPLE_COUNT];
const int OC_MTL_MAX_SAMPLE_COUNT = 8;
float2 sampleCoords[OC_MTL_MAX_SAMPLE_COUNT];
int sampleCount = sampleCountBuffer[0];
float2 centerCoord = float2(pixelCoord) + float2(0.5, 0.5);
@ -1551,33 +1551,33 @@ kernel void mtl_raster(const device mg_mtl_screen_tile* screenTilesBuffer [[buff
sampleCoords[0] = centerCoord;
}
const int MG_MTL_MAX_SRC_SAMPLE_COUNT = 4;
const int OC_MTL_MAX_SRC_SAMPLE_COUNT = 4;
const int srcSampleCount = 2;
const float2 imgSampleCoords[MG_MTL_MAX_SRC_SAMPLE_COUNT] = {
const float2 imgSampleCoords[OC_MTL_MAX_SRC_SAMPLE_COUNT] = {
centerCoord + float2(-0.25, 0.25),
centerCoord + float2(+0.25, +0.25),
centerCoord + float2(+0.25, -0.25),
centerCoord + float2(-0.25, +0.25)};
float4 color = {0};
int winding[MG_MTL_MAX_SAMPLE_COUNT] = {0};
int winding[OC_MTL_MAX_SAMPLE_COUNT] = {0};
while(opIndex != -1)
{
const device mg_mtl_tile_op* op = &tileOpBuffer[opIndex];
const device oc_mtl_tile_op* op = &tileOpBuffer[opIndex];
int pathIndex = op->index;
if(op->kind == MG_MTL_OP_START)
if(op->kind == OC_MTL_OP_START)
{
for(int sampleIndex=0; sampleIndex<sampleCount; sampleIndex++)
{
winding[sampleIndex] = op->windingOffset;
}
}
else if(op->kind == MG_MTL_OP_SEGMENT)
else if(op->kind == OC_MTL_OP_SEGMENT)
{
const device mg_mtl_segment* seg = &segmentBuffer[op->index];
const device oc_mtl_segment* seg = &segmentBuffer[op->index];
for(int sampleIndex=0; sampleIndex<sampleCount; sampleIndex++)
{
@ -1592,12 +1592,12 @@ kernel void mtl_raster(const device mg_mtl_screen_tile* screenTilesBuffer [[buff
if(op->crossRight)
{
if( (seg->config == MG_MTL_BR || seg->config == MG_MTL_TL)
if( (seg->config == OC_MTL_BR || seg->config == OC_MTL_TL)
&&(sampleCoord.y > seg->box.w))
{
winding[sampleIndex] += seg->windingIncrement;
}
else if( (seg->config == MG_MTL_BL || seg->config == MG_MTL_TR)
else if( (seg->config == OC_MTL_BL || seg->config == OC_MTL_TR)
&&(sampleCoord.y > seg->box.y))
{
winding[sampleIndex] -= seg->windingIncrement;
@ -1611,7 +1611,7 @@ kernel void mtl_raster(const device mg_mtl_screen_tile* screenTilesBuffer [[buff
nextColor.rgb *= nextColor.a;
int textureIndex = pathBuffer[pathIndex].texture;
if(textureIndex >= 0 && textureIndex < MG_MTL_MAX_IMAGES_PER_BATCH)
if(textureIndex >= 0 && textureIndex < OC_MTL_MAX_IMAGES_PER_BATCH)
{
constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear);
@ -1629,7 +1629,7 @@ kernel void mtl_raster(const device mg_mtl_screen_tile* screenTilesBuffer [[buff
nextColor *= texColor;
}
if(op->kind == MG_MTL_OP_FILL)
if(op->kind == OC_MTL_OP_FILL)
{
color = color*(1-nextColor.a) + nextColor;
}
@ -1647,9 +1647,9 @@ kernel void mtl_raster(const device mg_mtl_screen_tile* screenTilesBuffer [[buff
&& sampleCoord.y >= clip.y
&& sampleCoord.y < clip.w)
{
bool filled = op->kind == MG_MTL_OP_CLIP_FILL
||(pathBuffer[pathIndex].cmd == MG_MTL_FILL && (winding[sampleIndex] & 1))
||(pathBuffer[pathIndex].cmd == MG_MTL_STROKE && (winding[sampleIndex] != 0));
bool filled = op->kind == OC_MTL_OP_CLIP_FILL
||(pathBuffer[pathIndex].cmd == OC_MTL_FILL && (winding[sampleIndex] & 1))
||(pathBuffer[pathIndex].cmd == OC_MTL_STROKE && (winding[sampleIndex] != 0));
if(filled)
{
coverage++;

View File

@ -15,12 +15,12 @@
#import<Metal/Metal.h>
#endif
mg_surface_data* mg_mtl_surface_create_for_window(mp_window window);
oc_surface_data* oc_mtl_surface_create_for_window(oc_window window);
void* mg_mtl_surface_render_encoder(mg_surface surface);
void* mg_mtl_surface_compute_encoder(mg_surface surface);
void* mg_mtl_surface_layer(mg_surface surface);
void* mg_mtl_surface_drawable(mg_surface surface);
void* mg_mtl_surface_command_buffer(mg_surface surface);
void* oc_mtl_surface_render_encoder(oc_surface surface);
void* oc_mtl_surface_compute_encoder(oc_surface surface);
void* oc_mtl_surface_layer(oc_surface surface);
void* oc_mtl_surface_drawable(oc_surface surface);
void* oc_mtl_surface_command_buffer(oc_surface surface);
#endif //__MTL_SURFACE_H_

View File

@ -12,12 +12,12 @@
#include<simd/simd.h>
#include"graphics_surface.h"
#include"util/macro_helpers.h"
#include"util/macros.h"
#include"app/osx_app.h"
typedef struct mg_mtl_surface
typedef struct oc_mtl_surface
{
mg_surface_data interface;
oc_surface_data interface;
// permanent mtl resources
id<MTLDevice> device;
@ -28,11 +28,11 @@ typedef struct mg_mtl_surface
id<CAMetalDrawable> drawable;
id<MTLCommandBuffer> commandBuffer;
} mg_mtl_surface;
} oc_mtl_surface;
void mg_mtl_surface_destroy(mg_surface_data* interface)
void oc_mtl_surface_destroy(oc_surface_data* interface)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
oc_mtl_surface* surface = (oc_mtl_surface*)interface;
@autoreleasepool
{
@ -48,10 +48,10 @@ void mg_mtl_surface_destroy(mg_surface_data* interface)
[surface->mtlLayer release];
[surface->device release];
}
//NOTE: we don't use mp_layer_cleanup here, because the CAMetalLayer is taken care off by the surface itself
//NOTE: we don't use oc_layer_cleanup here, because the CAMetalLayer is taken care off by the surface itself
}
void mg_mtl_surface_acquire_command_buffer(mg_mtl_surface* surface)
void oc_mtl_surface_acquire_command_buffer(oc_mtl_surface* surface)
{
if(surface->commandBuffer == nil)
{
@ -60,7 +60,7 @@ void mg_mtl_surface_acquire_command_buffer(mg_mtl_surface* surface)
}
}
void mg_mtl_surface_acquire_drawable(mg_mtl_surface* surface)
void oc_mtl_surface_acquire_drawable(oc_mtl_surface* surface)
{@autoreleasepool{
/*WARN(martin):
//TODO: we should stop trying to render if we detect that the app is in the background
@ -81,15 +81,15 @@ void mg_mtl_surface_acquire_drawable(mg_mtl_surface* surface)
}
}}
void mg_mtl_surface_prepare(mg_surface_data* interface)
void oc_mtl_surface_prepare(oc_surface_data* interface)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
mg_mtl_surface_acquire_command_buffer(surface);
oc_mtl_surface* surface = (oc_mtl_surface*)interface;
oc_mtl_surface_acquire_command_buffer(surface);
}
void mg_mtl_surface_present(mg_surface_data* interface)
void oc_mtl_surface_present(oc_surface_data* interface)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
oc_mtl_surface* surface = (oc_mtl_surface*)interface;
@autoreleasepool
{
if(surface->commandBuffer != nil)
@ -107,9 +107,9 @@ void mg_mtl_surface_present(mg_surface_data* interface)
}
}
void mg_mtl_surface_swap_interval(mg_surface_data* interface, int swap)
void oc_mtl_surface_swap_interval(oc_surface_data* interface, int swap)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
oc_mtl_surface* surface = (oc_mtl_surface*)interface;
@autoreleasepool
{
[surface->mtlLayer setDisplaySyncEnabled: (swap ? YES : NO)];
@ -117,11 +117,11 @@ void mg_mtl_surface_swap_interval(mg_surface_data* interface, int swap)
}
/*
void mg_mtl_surface_set_frame(mg_surface_data* interface, mp_rect frame)
void oc_mtl_surface_set_frame(oc_surface_data* interface, oc_rect frame)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
mg_osx_surface_set_frame(interface, frame);
vec2 scale = mg_osx_surface_contents_scaling(interface);
oc_mtl_surface* surface = (oc_mtl_surface*)interface;
oc_osx_surface_set_frame(interface, frame);
oc_vec2 scale = oc_osx_surface_contents_scaling(interface);
CGRect cgFrame = {{frame.x, frame.y}, {frame.w, frame.h}};
@ -140,29 +140,29 @@ void mg_mtl_surface_set_frame(mg_surface_data* interface, mp_rect frame)
//TODO fix that according to real scaling, depending on the monitor settings
static const f32 MG_MTL_SURFACE_CONTENTS_SCALING = 2;
static const f32 OC_MTL_SURFACE_CONTENTS_SCALING = 2;
//NOTE: max frames in flight (n frames being queued on the GPU while we're working on the n+1 frame).
// for triple buffering, there's 2 frames being queued on the GPU while we're working on the 3rd frame
static const int MG_MTL_MAX_FRAMES_IN_FLIGHT = 2;
static const int OC_MTL_MAX_FRAMES_IN_FLIGHT = 2;
mg_surface_data* mg_mtl_surface_create_for_window(mp_window window)
oc_surface_data* oc_mtl_surface_create_for_window(oc_window window)
{
mg_mtl_surface* surface = 0;
mp_window_data* windowData = mp_window_ptr_from_handle(window);
oc_mtl_surface* surface = 0;
oc_window_data* windowData = oc_window_ptr_from_handle(window);
if(windowData)
{
surface = (mg_mtl_surface*)malloc(sizeof(mg_mtl_surface));
surface = (oc_mtl_surface*)malloc(sizeof(oc_mtl_surface));
mg_surface_init_for_window((mg_surface_data*)surface, windowData);
oc_surface_init_for_window((oc_surface_data*)surface, windowData);
//NOTE(martin): setup interface functions
surface->interface.api = MG_METAL;
surface->interface.destroy = mg_mtl_surface_destroy;
surface->interface.prepare = mg_mtl_surface_prepare;
surface->interface.api = OC_METAL;
surface->interface.destroy = oc_mtl_surface_destroy;
surface->interface.prepare = oc_mtl_surface_prepare;
surface->interface.deselect = 0;
surface->interface.present = mg_mtl_surface_present;
surface->interface.swapInterval = mg_mtl_surface_swap_interval;
surface->interface.present = oc_mtl_surface_present;
surface->interface.swapInterval = oc_mtl_surface_swap_interval;
@autoreleasepool
{
@ -191,7 +191,7 @@ mg_surface_data* mg_mtl_surface_create_for_window(mp_window window)
}
if(surface->device == nil)
{
log_warning("Couldn't select a discrete GPU, using first available device\n");
oc_log_warning("Couldn't select a discrete GPU, using first available device\n");
surface->device = devices[0];
}
@ -212,10 +212,10 @@ mg_surface_data* mg_mtl_surface_create_for_window(mp_window window)
NSRect frame = [[windowData->osx.nsWindow contentView] frame];
CGSize size = frame.size;
surface->mtlLayer.frame = (CGRect){{0, 0}, size};
size.width *= MG_MTL_SURFACE_CONTENTS_SCALING;
size.height *= MG_MTL_SURFACE_CONTENTS_SCALING;
size.width *= OC_MTL_SURFACE_CONTENTS_SCALING;
size.height *= OC_MTL_SURFACE_CONTENTS_SCALING;
surface->mtlLayer.drawableSize = size;
surface->mtlLayer.contentsScale = MG_MTL_SURFACE_CONTENTS_SCALING;
surface->mtlLayer.contentsScale = OC_MTL_SURFACE_CONTENTS_SCALING;
surface->mtlLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
@ -234,15 +234,15 @@ mg_surface_data* mg_mtl_surface_create_for_window(mp_window window)
surface->commandBuffer = nil;
}
}
return((mg_surface_data*)surface);
return((oc_surface_data*)surface);
}
void* mg_mtl_surface_layer(mg_surface surface)
void* oc_mtl_surface_layer(oc_surface surface)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->api == MG_METAL)
oc_surface_data* surfaceData = oc_surface_data_from_handle(surface);
if(surfaceData && surfaceData->api == OC_METAL)
{
mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
oc_mtl_surface* mtlSurface = (oc_mtl_surface*)surfaceData;
return(mtlSurface->mtlLayer);
}
else
@ -251,13 +251,13 @@ void* mg_mtl_surface_layer(mg_surface surface)
}
}
void* mg_mtl_surface_drawable(mg_surface surface)
void* oc_mtl_surface_drawable(oc_surface surface)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->api == MG_METAL)
oc_surface_data* surfaceData = oc_surface_data_from_handle(surface);
if(surfaceData && surfaceData->api == OC_METAL)
{
mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
mg_mtl_surface_acquire_drawable(mtlSurface);
oc_mtl_surface* mtlSurface = (oc_mtl_surface*)surfaceData;
oc_mtl_surface_acquire_drawable(mtlSurface);
return(mtlSurface->drawable);
}
else
@ -266,13 +266,13 @@ void* mg_mtl_surface_drawable(mg_surface surface)
}
}
void* mg_mtl_surface_command_buffer(mg_surface surface)
void* oc_mtl_surface_command_buffer(oc_surface surface)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->api == MG_METAL)
oc_surface_data* surfaceData = oc_surface_data_from_handle(surface);
if(surfaceData && surfaceData->api == OC_METAL)
{
mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
mg_mtl_surface_acquire_command_buffer(mtlSurface);
oc_mtl_surface* mtlSurface = (oc_mtl_surface*)surfaceData;
oc_mtl_surface_acquire_command_buffer(mtlSurface);
return(mtlSurface->commandBuffer);
}
else

View File

@ -11,42 +11,42 @@
#include"gl_loader.h"
#include<GL/wglext.h>
#include"util/macro_helpers.h"
#include"util/macros.h"
#define WGL_PROC_LIST \
WGL_PROC(WGLCHOOSEPIXELFORMATARB, wglChoosePixelFormatARB) \
WGL_PROC(WGLCREATECONTEXTATTRIBSARB, wglCreateContextAttribsARB) \
WGL_PROC(WGLMAKECONTEXTCURRENTARB, wglMakeContextCurrentARB) \
WGL_PROC(WGLSWAPINTERVALEXT, wglSwapIntervalEXT) \
#define OC_WGL_PROC_LIST \
OC_WGL_PROC(WGLCHOOSEPIXELFORMATARB, wglChoosePixelFormatARB) \
OC_WGL_PROC(WGLCREATECONTEXTATTRIBSARB, wglCreateContextAttribsARB) \
OC_WGL_PROC(WGLMAKECONTEXTCURRENTARB, wglMakeContextCurrentARB) \
OC_WGL_PROC(WGLSWAPINTERVALEXT, wglSwapIntervalEXT) \
//NOTE: wgl function pointers declarations
#define WGL_PROC(type, name) _cat3_(PFN, type, PROC) name = 0;
WGL_PROC_LIST
#undef WGL_PROC
#define OC_WGL_PROC(type, name) OC_CAT3(PFN, type, PROC) name = 0;
OC_WGL_PROC_LIST
#undef OC_WGL_PROC
//NOTE: wgl loader
typedef struct wgl_dummy_context
typedef struct oc_wgl_dummy_context
{
bool init;
HWND hWnd;
HDC hDC;
HGLRC glContext;
} wgl_dummy_context;
} oc_wgl_dummy_context;
static wgl_dummy_context __mgWGLDummyContext = {0};
static oc_wgl_dummy_context oc_wglDummyContext = {0};
static void wgl_init()
static void oc_wgl_init()
{
if(!__mgWGLDummyContext.init)
if(!oc_wglDummyContext.init)
{
//NOTE: create a dummy window
WNDCLASS windowClass = {.style = CS_OWNDC,
.lpfnWndProc = DefWindowProc,
.hInstance = GetModuleHandleW(NULL),
.lpszClassName = "wgl_helper_window_class",
.lpszClassName = "oc_wgl_helper_window_class",
.hCursor = LoadCursor(0, IDC_ARROW)};
if(!RegisterClass(&windowClass))
@ -55,18 +55,18 @@ static void wgl_init()
goto quit;
}
__mgWGLDummyContext.hWnd = CreateWindow("wgl_helper_window_class",
oc_wglDummyContext.hWnd = CreateWindow("oc_wgl_helper_window_class",
"dummy",
WS_OVERLAPPEDWINDOW,
0, 0, 100, 100,
0, 0, windowClass.hInstance, 0);
if(!__mgWGLDummyContext.hWnd)
if(!oc_wglDummyContext.hWnd)
{
//TODO: error
goto quit;
}
__mgWGLDummyContext.hDC = GetDC(__mgWGLDummyContext.hWnd);
oc_wglDummyContext.hDC = GetDC(oc_wglDummyContext.hWnd);
PIXELFORMATDESCRIPTOR pixelFormatDesc =
{
@ -88,44 +88,44 @@ static void wgl_init()
0, 0, 0
};
int pixelFormat = ChoosePixelFormat(__mgWGLDummyContext.hDC, &pixelFormatDesc);
SetPixelFormat(__mgWGLDummyContext.hDC, pixelFormat, &pixelFormatDesc);
int pixelFormat = ChoosePixelFormat(oc_wglDummyContext.hDC, &pixelFormatDesc);
SetPixelFormat(oc_wglDummyContext.hDC, pixelFormat, &pixelFormatDesc);
__mgWGLDummyContext.glContext = wglCreateContext(__mgWGLDummyContext.hDC);
wglMakeCurrent(__mgWGLDummyContext.hDC, __mgWGLDummyContext.glContext);
oc_wglDummyContext.glContext = wglCreateContext(oc_wglDummyContext.hDC);
wglMakeCurrent(oc_wglDummyContext.hDC, oc_wglDummyContext.glContext);
//NOTE(martin): now load WGL extension functions
#define WGL_PROC(type, name) name = (_cat3_(PFN, type, PROC))wglGetProcAddress( #name );
WGL_PROC_LIST
#undef WGL_PROC
#define OC_WGL_PROC(type, name) name = (OC_CAT3(PFN, type, PROC))wglGetProcAddress( #name );
OC_WGL_PROC_LIST
#undef OC_WGL_PROC
__mgWGLDummyContext.init = true;
oc_wglDummyContext.init = true;
}
else
{
wglMakeCurrent(__mgWGLDummyContext.hDC, __mgWGLDummyContext.glContext);
wglMakeCurrent(oc_wglDummyContext.hDC, oc_wglDummyContext.glContext);
}
quit:;
}
#undef WGL_PROC_LIST
#undef OC_WGL_PROC_LIST
typedef struct mg_wgl_surface
typedef struct oc_wgl_surface
{
mg_surface_data interface;
oc_surface_data interface;
HDC hDC;
HGLRC glContext;
//NOTE: this may be a bit wasteful to have one api struct per surface, but win32 docs says that loading procs
// from different contexts might select different implementations (eg. depending on context version/pixel format)
mg_gl_api api;
} mg_wgl_surface;
oc_gl_api api;
} oc_wgl_surface;
void mg_wgl_surface_destroy(mg_surface_data* interface)
void oc_wgl_surface_destroy(oc_surface_data* interface)
{
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
oc_wgl_surface* surface = (oc_wgl_surface*)interface;
if(surface->glContext == wglGetCurrentContext())
{
@ -133,39 +133,39 @@ void mg_wgl_surface_destroy(mg_surface_data* interface)
}
wglDeleteContext(surface->glContext);
mg_surface_cleanup(interface);
oc_surface_cleanup(interface);
free(surface);
}
void mg_wgl_surface_prepare(mg_surface_data* interface)
void oc_wgl_surface_prepare(oc_surface_data* interface)
{
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
oc_wgl_surface* surface = (oc_wgl_surface*)interface;
wglMakeCurrent(surface->hDC, surface->glContext);
mg_gl_select_api(&surface->api);
oc_gl_select_api(&surface->api);
}
void mg_wgl_surface_present(mg_surface_data* interface)
void oc_wgl_surface_present(oc_surface_data* interface)
{
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
oc_wgl_surface* surface = (oc_wgl_surface*)interface;
SwapBuffers(surface->hDC);
}
void mg_wgl_surface_deselect(mg_surface_data* interface)
void oc_wgl_surface_deselect(oc_surface_data* interface)
{
wglMakeCurrent(NULL, NULL);
mg_gl_deselect_api();
oc_gl_deselect_api();
}
void mg_wgl_surface_swap_interval(mg_surface_data* interface, int swap)
void oc_wgl_surface_swap_interval(oc_surface_data* interface, int swap)
{
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
oc_wgl_surface* surface = (oc_wgl_surface*)interface;
wglSwapIntervalEXT(swap);
}
void* mg_wgl_get_proc(const char* name)
void* oc_wgl_get_proc(const char* name)
{
void* p = wglGetProcAddress(name);
if( p == 0
@ -181,28 +181,28 @@ void* mg_wgl_get_proc(const char* name)
return(p);
}
mg_surface_data* mg_wgl_surface_create_for_window(mp_window window)
oc_surface_data* oc_wgl_surface_create_for_window(oc_window window)
{
mg_wgl_surface* surface = 0;
oc_wgl_surface* surface = 0;
mp_window_data* windowData = mp_window_ptr_from_handle(window);
oc_window_data* windowData = oc_window_ptr_from_handle(window);
if(windowData)
{
wgl_init();
oc_wgl_init();
//NOTE: fill surface data and load api
surface = malloc_type(mg_wgl_surface);
surface = oc_malloc_type(oc_wgl_surface);
if(surface)
{
memset(surface, 0, sizeof(mg_wgl_surface));
mg_surface_init_for_window((mg_surface_data*)surface, windowData);
memset(surface, 0, sizeof(oc_wgl_surface));
oc_surface_init_for_window((oc_surface_data*)surface, windowData);
surface->interface.api = MG_GL;
surface->interface.destroy = mg_wgl_surface_destroy;
surface->interface.prepare = mg_wgl_surface_prepare;
surface->interface.present = mg_wgl_surface_present;
surface->interface.swapInterval = mg_wgl_surface_swap_interval;
surface->interface.deselect = mg_wgl_surface_deselect;
surface->interface.api = OC_GL;
surface->interface.destroy = oc_wgl_surface_destroy;
surface->interface.prepare = oc_wgl_surface_prepare;
surface->interface.present = oc_wgl_surface_present;
surface->interface.swapInterval = oc_wgl_surface_swap_interval;
surface->interface.deselect = oc_wgl_surface_deselect;
surface->hDC = GetDC(surface->interface.layer.hWnd);
@ -259,7 +259,7 @@ mg_surface_data* mg_wgl_surface_create_for_window(mp_window window)
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0};
surface->glContext = wglCreateContextAttribsARB(surface->hDC, __mgWGLDummyContext.glContext, contextAttrs);
surface->glContext = wglCreateContextAttribsARB(surface->hDC, oc_wglDummyContext.glContext, contextAttrs);
if(!surface->glContext)
{
@ -271,8 +271,8 @@ mg_surface_data* mg_wgl_surface_create_for_window(mp_window window)
//NOTE: make gl context current and load api
wglMakeCurrent(surface->hDC, surface->glContext);
wglSwapIntervalEXT(1);
mg_gl_load_gl44(&surface->api, mg_wgl_get_proc);
oc_gl_load_gl44(&surface->api, oc_wgl_get_proc);
}
}
return((mg_surface_data*)surface);
return((oc_surface_data*)surface);
}

View File

@ -11,6 +11,6 @@
#include"graphics_surface.h"
mg_surface_data* mg_wgl_surface_create_for_window(mp_window window);
oc_surface_data* oc_wgl_surface_create_for_window(oc_window window);
#endif // __WIN32_GL_SURFACE_H_

View File

@ -6,7 +6,7 @@
#ifdef NDEBUG
#define assert(x) (void)0
#else
#define assert(x) ASSERT(x)
#define assert(x) OC_ASSERT(x)
#endif
#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus)

View File

@ -5,7 +5,7 @@
extern "C" {
#endif
#define abort(...) ORCA_ABORT(__VA_ARGS__)
#define abort(...) OC_ABORT(__VA_ARGS__)
int abs (int);

View File

@ -12,7 +12,7 @@
//---------------------------------------------------------------
#include"platform/platform.h"
#if PLATFORM_WINDOWS
#if OC_PLATFORM_WINDOWS
#include"platform/native_debug.c"
#include"platform/win32_memory.c"
#include"platform/win32_clock.c"
@ -21,7 +21,7 @@
#include"platform/win32_io.c"
#include"platform/win32_thread.c"
//TODO
#elif PLATFORM_MACOS
#elif OC_PLATFORM_MACOS
#include"platform/native_debug.c"
#include"platform/unix_memory.c"
#include"platform/osx_clock.c"
@ -43,7 +43,7 @@
#include"platform/unix_rng.c"
#include"platform/posix_socket.c"
*/
#elif PLATFORM_ORCA
#elif OC_PLATFORM_ORCA
#include"platform/orca_debug.c"
#include"platform/orca_clock.c"
#include"platform/orca_memory.c"
@ -62,35 +62,36 @@
#include"util/utf8.c"
#include"util/hash.c"
#include"util/ringbuffer.c"
#include"util/algebra.c"
//---------------------------------------------------------------
// app/graphics layer
//---------------------------------------------------------------
#if PLATFORM_WINDOWS
#if OC_PLATFORM_WINDOWS
#include"app/win32_app.c"
#include"graphics/graphics_common.c"
#include"graphics/graphics_surface.c"
#if MG_COMPILE_GL || MG_COMPILE_GLES
#if OC_COMPILE_GL || OC_COMPILE_GLES
#include"graphics/gl_loader.c"
#endif
#if MG_COMPILE_GL
#if OC_COMPILE_GL
#include"graphics/wgl_surface.c"
#endif
#if MG_COMPILE_CANVAS
#if OC_COMPILE_CANVAS
#include"graphics/gl_canvas.c"
#endif
#if MG_COMPILE_GLES
#if OC_COMPILE_GLES
#include"graphics/egl_surface.c"
#endif
#elif PLATFORM_MACOS
#elif OC_PLATFORM_MACOS
//NOTE: macos application layer and graphics backends are defined in orca.m
#elif PLATFORM_ORCA
#elif OC_PLATFORM_ORCA
#include"app/orca_app.c"
#include"graphics/graphics_common.c"
#include"graphics/orca_surface_stubs.c"

View File

@ -10,39 +10,40 @@
#define __ORCA_H_
#include"util/typedefs.h"
#include"util/macro_helpers.h"
#include"util/macros.h"
#include"util/debug.h"
#include"util/lists.h"
#include"util/memory.h"
#include"util/strings.h"
#include"util/utf8.h"
#include"util/hash.h"
#include"util/algebra.h"
#include"platform/platform.h"
#include"platform/platform_clock.h"
#include"platform/platform_path.h"
#include"platform/platform_io.h"
#if !defined(PLATFORM_ORCA) || !(PLATFORM_ORCA)
#if !defined(OC_PLATFORM_ORCA) || !(OC_PLATFORM_ORCA)
#include"platform/platform_thread.h"
#endif
#include"app/mp_app.h"
#include"app/app.h"
//----------------------------------------------------------------
// graphics
//----------------------------------------------------------------
#include"graphics/graphics.h"
#if PLATFORM_ORCA
#if OC_PLATFORM_ORCA
//TODO: maybe make this conditional
#include"graphics/orca_gl31.h"
mg_surface mg_surface_canvas();
mg_surface mg_surface_gles();
oc_surface oc_surface_canvas();
oc_surface oc_surface_gles();
#else
#ifdef MG_INCLUDE_GL_API
#ifdef OC_INCLUDE_GL_API
#include"graphics/gl_api.h"
#endif
#endif

View File

@ -12,15 +12,15 @@
#include"graphics/graphics_common.c"
#include"graphics/graphics_surface.c"
#if MG_COMPILE_METAL
#if OC_COMPILE_METAL
#include"graphics/mtl_surface.m"
#endif
#if MG_COMPILE_CANVAS
#if OC_COMPILE_CANVAS
#include"graphics/mtl_renderer.m"
#endif
#if MG_COMPILE_GLES
#if OC_COMPILE_GLES
#include"graphics/gl_loader.c"
#include"graphics/egl_surface.c"
#endif

View File

@ -1,193 +0,0 @@
/************************************************************//**
*
* @file: linux_clock.c
* @author: Martin Fouilleul
* @date: 20/04/2020
* @revision:
*
*****************************************************************/
#include<math.h> //fabs()
#include<time.h>
#include<sys/time.h> // gettimeofday()
#include<sys/types.h>
#include<sys/sysctl.h>
#include<unistd.h> // nanosleep()
#include"platform_rng.h"
#include"platform_clock.h"
extern "C" {
//TODO(martin): measure the actual values of these constants
const f64 SYSTEM_FUZZ = 25e-9, // minimum time to read the clock (s)
SYSTEM_TICK = 25e-9; // minimum step between two clock readings (s)
static u64 __initialTimestamp__ = 0;
static u64 __initialMonotonicNanoseconds__ = 0;
static inline u64 LinuxGetMonotonicNanoseconds()
{
timespec ts;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
//WARN(martin): do not multiply ts.tv_sec directly (implicit conversion will overflow)
u64 r = ts.tv_sec;
r *= 1000000000;
r += ts.tv_nsec;
return(r);
}
static inline u64 LinuxGetUptimeNanoseconds()
{
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
//WARN(martin): do not multiply ts.tv_sec directly (implicit conversion will overflow)
u64 r = ts.tv_sec;
r *= 1000000000;
r += ts.tv_nsec;
return(r);
}
void ClockSystemInit()
{
//NOTE(martin): we don't know of a widely supported way of getting the boot time on linux, so
// we fallback to our second best choice, which is taking an initial timestamp and
// the initial monotonic time now
timeval tv;
gettimeofday(&tv, 0);
__initialMonotonicNanoseconds__ = LinuxGetMonotonicNanoseconds();
//NOTE(martin): convert boot date to timestamp
__initialTimestamp__ = (((u64)tv.tv_sec + JAN_1970) << 32)
+ (u64)(tv.tv_usec * 1e-6 * TIMESTAMPS_PER_SECOND);
//TODO(martin): maybe get a state vector for exclusive clock usage ?
RandomSeedFromDevice();
}
fx_timestamp ClockGetTimestamp(clock_kind clock)
{
fx_timestamp ts = {0};
switch(clock)
{
case SYS_CLOCK_MONOTONIC:
{
//NOTE(martin): compute monotonic offset and add it to bootup timestamp
u64 noff = LinuxGetMonotonicNanoseconds() - __initialMonotonicNanoseconds__;
u64 foff = (u64)(noff * 1e-9 * TIMESTAMPS_PER_SECOND);
ts.ts = __initialTimestamp__ + foff;
} break;
case SYS_CLOCK_UPTIME:
{
//TODO(martin): maybe we should warn that this date is inconsistent after a sleep ?
//NOTE(martin): compute uptime offset and add it to bootup timestamp
u64 noff = LinuxGetUptimeNanoseconds() - __initialMonotonicNanoseconds__ ;
u64 foff = (u64)(noff * 1e-9 * TIMESTAMPS_PER_SECOND);
ts.ts = __initialTimestamp__ + foff;
} break;
case SYS_CLOCK_DATE:
{
//NOTE(martin): get system date and convert it to a fixed-point timestamp
timeval tv;
gettimeofday(&tv, 0);
ts.ts = (((u64)tv.tv_sec + JAN_1970) << 32)
+ (u64)(tv.tv_usec * 1e-6 * TIMESTAMPS_PER_SECOND);
} break;
}
//NOTE(martin): add a random fuzz between 0 and 1 times the system fuzz
f64 fuzz = RandomU32()/(f64)(~(0UL)) * SYSTEM_FUZZ;
fx_timediff tdfuzz = TimediffFromSeconds(fuzz);
ts = TimestampAdd(ts, tdfuzz);
//TODO(martin): ensure that we always return a value greater than the last value
return(ts);
}
f64 ClockGetTime(clock_kind clock)
{
switch(clock)
{
case SYS_CLOCK_MONOTONIC:
{
//NOTE(martin): compute monotonic offset and add it to bootup timestamp
u64 noff = LinuxGetMonotonicNanoseconds();
return((f64)noff * 1e-9);
} break;
case SYS_CLOCK_UPTIME:
{
//TODO(martin): maybe we should warn that this date is inconsistent after a sleep ?
//NOTE(martin): compute uptime offset and add it to bootup timestamp
u64 noff = LinuxGetUptimeNanoseconds();
return((f64)noff * 1e-9);
} break;
case SYS_CLOCK_DATE:
{
//TODO(martin): maybe warn about precision loss ?
// could also change the epoch since we only promise to return a relative time
//NOTE(martin): get system date and convert it to seconds
timeval tv;
gettimeofday(&tv, 0);
return(((f64)tv.tv_sec + JAN_1970) + ((f64)tv.tv_usec * 1e-6));
} break;
}
return(0);
}
void ClockSleepNanoseconds(u64 nanoseconds)
{
timespec rqtp;
rqtp.tv_sec = nanoseconds / 1000000000;
rqtp.tv_nsec = nanoseconds - rqtp.tv_sec * 1000000000;
nanosleep(&rqtp, 0);
}
////////////////////////////////////////////////////////////////////
//TODO: update these functions for various clocks besides monotonic
////////////////////////////////////////////////////////////////////
f64 ClockGetGranularity(clock_kind clock)
{
u64 minDiff = ~(0ULL);
const int GRANULARITY_NUM_ITERATION = 100000;
for(int i=0; i<GRANULARITY_NUM_ITERATION; i++)
{
u64 a = LinuxGetMonotonicNanoseconds();
u64 b = LinuxGetMonotonicNanoseconds();
u64 diff = b - a;
if(diff != 0 && diff < minDiff)
{
minDiff = diff;
}
}
return(minDiff * 1e-9);
}
f64 ClockGetMeanReadTime(clock_kind clock)
{
u64 start = LinuxGetMonotonicNanoseconds();
fx_timestamp time;
const int READ_NUM_ITERATION = 1000000;
for(int i=0; i<READ_NUM_ITERATION; i++)
{
time = ClockGetTimestamp(SYS_CLOCK_MONOTONIC);
}
volatile u64 ts = time.ts;
u64 end = LinuxGetMonotonicNanoseconds();
f64 mean = (end - start)/(f64)READ_NUM_ITERATION;
return(mean * 1e-9);
}
} // extern "C"

View File

@ -7,49 +7,49 @@
*****************************************************************/
#include<stdio.h>
#include"app/mp_app.h"
#include"app/app.h"
#include"platform_debug.c"
//----------------------------------------------------------------
// Logging
//----------------------------------------------------------------
#if PLATFORM_WINDOWS
#if OC_PLATFORM_WINDOWS
#include<io.h>
#define isatty _isatty
#define fileno _fileno
#elif PLATFORM_MACOS || PLATFORM_LINUX
#elif OC_PLATFORM_MACOS || PLATFORM_LINUX
#include<unistd.h>
#endif
static const char* LOG_HEADINGS[LOG_LEVEL_COUNT] = {
static const char* OC_LOG_HEADINGS[OC_LOG_LEVEL_COUNT] = {
"Error",
"Warning",
"Info"};
static const char* LOG_FORMATS[LOG_LEVEL_COUNT] = {
static const char* OC_LOG_FORMATS[OC_LOG_LEVEL_COUNT] = {
"\033[38;5;9m\033[1m",
"\033[38;5;13m\033[1m",
"\033[38;5;10m\033[1m"};
static const char* LOG_FORMAT_STOP = "\033[m";
static const char* OC_LOG_FORMAT_STOP = "\033[m";
typedef struct log_output
typedef struct oc_log_output
{
FILE* f;
} log_output;
} oc_log_output;
static log_output _logDefaultOutput = {0};
log_output* LOG_DEFAULT_OUTPUT = &_logDefaultOutput;
static oc_log_output oc_logDefaultOutput = {0};
oc_log_output* OC_LOG_DEFAULT_OUTPUT = &oc_logDefaultOutput;
void platform_log_push(log_output* output,
log_level level,
void platform_log_push(oc_log_output* output,
oc_log_level level,
const char* file,
const char* function,
int line,
const char* fmt,
va_list ap)
{
if(output == LOG_DEFAULT_OUTPUT && output->f == 0)
if(output == OC_LOG_DEFAULT_OUTPUT && output->f == 0)
{
output->f = stdout;
}
@ -59,9 +59,9 @@ void platform_log_push(log_output* output,
{
fprintf(output->f,
"%s%s:%s %s() in %s:%i: ",
LOG_FORMATS[level],
LOG_HEADINGS[level],
LOG_FORMAT_STOP,
OC_LOG_FORMATS[level],
OC_LOG_HEADINGS[level],
OC_LOG_FORMAT_STOP,
function,
file,
line);
@ -70,7 +70,7 @@ void platform_log_push(log_output* output,
{
fprintf(output->f,
"%s: %s() in %s:%i: ",
LOG_HEADINGS[level],
OC_LOG_HEADINGS[level],
function,
file,
line);
@ -82,16 +82,16 @@ void platform_log_push(log_output* output,
// Assert/Abort
//----------------------------------------------------------------
_Noreturn void orca_abort(const char* file, const char* function, int line, const char* fmt, ...)
_Noreturn void oc_abort_ext(const char* file, const char* function, int line, const char* fmt, ...)
{
mem_arena* scratch = mem_scratch();
oc_arena* scratch = oc_scratch();
va_list ap;
va_start(ap, fmt);
str8 note = str8_pushfv(scratch, fmt, ap);
oc_str8 note = oc_str8_pushfv(scratch, fmt, ap);
va_end(ap);
str8 msg = str8_pushf(scratch,
oc_str8 msg = oc_str8_pushf(scratch,
"Fatal error in function %s() in file \"%s\", line %i:\n%.*s\n",
function,
file,
@ -99,38 +99,40 @@ _Noreturn void orca_abort(const char* file, const char* function, int line, cons
(int)note.len,
note.ptr);
const char* msgCStr = str8_to_cstring(scratch, msg);
log_error(msgCStr);
oc_log_error(msg.ptr);
const char* options[] = {"OK"};
mp_alert_popup("Fatal Error", msgCStr, 1, options);
oc_str8_list options = {0};
oc_str8_list_push(scratch, &options, OC_STR8("OK"));
oc_alert_popup(OC_STR8("Fatal Error"), msg, options);
//TODO: could terminate more gracefully?
exit(-1);
}
_Noreturn void orca_assert_fail(const char* file, const char* function, int line, const char* src, const char* fmt, ...)
_Noreturn void oc_assert_fail(const char* file, const char* function, int line, const char* src, const char* fmt, ...)
{
mem_arena* scratch = mem_scratch();
oc_arena* scratch = oc_scratch();
va_list ap;
va_start(ap, fmt);
str8 note = str8_pushfv(scratch, fmt, ap);
oc_str8 note = oc_str8_pushfv(scratch, fmt, ap);
va_end(ap);
str8 msg = str8_pushf(scratch,
oc_str8 msg = oc_str8_pushf(scratch,
"Assertion failed in function %s() in file \"%s\", line %i:\n%s\nNote: %.*s\n",
function,
file,
line,
src,
str8_ip(note));
oc_str8_ip(note));
const char* msgCStr = str8_to_cstring(scratch, msg);
log_error(msgCStr);
oc_log_error(msg.ptr);
const char* options[] = {"OK"};
mp_alert_popup("Assertion Failed", msgCStr, 1, options);
oc_str8_list options = {0};
oc_str8_list_push(scratch, &options, OC_STR8("OK"));
oc_alert_popup(OC_STR8("Assertion Failed"), msg, options);
//TODO: could terminate more gracefully?
exit(-1);

View File

@ -1,4 +1,4 @@
#include"util/typedefs.h"
#include"platform_clock.h"
f64 ORCA_IMPORT(mp_get_time)(mp_clock_kind clock);
f64 ORCA_IMPORT(oc_clock_time)(oc_clock_kind clock);

View File

@ -15,18 +15,18 @@
// stb sprintf callback and user struct
//----------------------------------------------------------------
typedef struct orca_stbsp_context
typedef struct oc_stbsp_context
{
mem_arena* arena;
str8_list list;
} orca_stbsp_context;
oc_arena* arena;
oc_str8_list list;
} oc_stbsp_context;
char* orca_stbsp_callback(char const* buf, void* user, int len)
char* oc_stbsp_callback(char const* buf, void* user, int len)
{
orca_stbsp_context* ctx = (orca_stbsp_context*)user;
oc_stbsp_context* ctx = (oc_stbsp_context*)user;
str8 string = str8_push_buffer(ctx->arena, len, (char*)buf);
str8_list_push(ctx->arena, &ctx->list, string);
oc_str8 string = oc_str8_push_buffer(ctx->arena, len, (char*)buf);
oc_str8_list_push(ctx->arena, &ctx->list, string);
return((char*)buf);
}
@ -39,18 +39,18 @@ typedef enum
{
ORCA_LOG_OUTPUT_CONSOLE,
ORCA_LOG_OUTPUT_FILE
} orca_log_output_kind;
} oc_log_output_kind;
typedef struct log_output
typedef struct oc_log_output
{
orca_log_output_kind kind;
oc_log_output_kind kind;
//TODO: file output
} log_output;
} oc_log_output;
static log_output _logDefaultOutput = {.kind = ORCA_LOG_OUTPUT_CONSOLE};
log_output* LOG_DEFAULT_OUTPUT = &_logDefaultOutput;
static oc_log_output oc_logDefaultOutput = {.kind = ORCA_LOG_OUTPUT_CONSOLE};
oc_log_output* OC_LOG_DEFAULT_OUTPUT = &oc_logDefaultOutput;
void ORCA_IMPORT(orca_log)(log_level level,
void ORCA_IMPORT(oc_runtime_log)(oc_log_level level,
int fileLen,
const char* file,
int functionLen,
@ -59,42 +59,42 @@ void ORCA_IMPORT(orca_log)(log_level level,
int msgLen,
const char* msg);
void platform_log_push(log_output* output,
log_level level,
void platform_log_push(oc_log_output* output,
oc_log_level level,
const char* file,
const char* function,
int line,
const char* fmt,
va_list ap)
{
mem_arena* scratch = mem_scratch();
mem_arena_scope tmp = mem_arena_scope_begin(scratch);
oc_arena* scratch = oc_scratch();
oc_arena_scope tmp = oc_arena_scope_begin(scratch);
orca_stbsp_context ctx = {.arena = scratch,
oc_stbsp_context ctx = {.arena = scratch,
.list = {0}};
char buf[STB_SPRINTF_MIN];
stbsp_vsprintfcb(orca_stbsp_callback, &ctx, buf, fmt, ap);
stbsp_vsprintfcb(oc_stbsp_callback, &ctx, buf, fmt, ap);
str8 string = str8_list_join(scratch, ctx.list);
oc_str8 string = oc_str8_list_join(scratch, ctx.list);
orca_log(level, strlen(file), file, strlen(function), function, line, str8_ip(string));
oc_runtime_log(level, strlen(file), file, strlen(function), function, line, oc_str8_ip(string));
mem_arena_scope_end(tmp);
oc_arena_scope_end(tmp);
}
//----------------------------------------------------------------
// Assert/Abort
//----------------------------------------------------------------
_Noreturn void ORCA_IMPORT(orca_runtime_abort)(const char* file, const char* function, int line, const char* msg);
_Noreturn void ORCA_IMPORT(orca_runtime_assert_fail)(const char* file, const char* function, int line, const char* src, const char* msg);
_Noreturn void ORCA_IMPORT(oc_runtime_abort_ext)(const char* file, const char* function, int line, const char* msg);
_Noreturn void ORCA_IMPORT(oc_runtime_assert_fail)(const char* file, const char* function, int line, const char* src, const char* msg);
_Noreturn void orca_abort(const char* file, const char* function, int line, const char* fmt, ...)
_Noreturn void oc_abort_ext(const char* file, const char* function, int line, const char* fmt, ...)
{
mem_arena_scope scratch = mem_scratch_begin();
oc_arena_scope scratch = oc_scratch_begin();
orca_stbsp_context ctx = {
oc_stbsp_context ctx = {
.arena = scratch.arena,
.list = {0}
};
@ -103,22 +103,22 @@ _Noreturn void orca_abort(const char* file, const char* function, int line, cons
va_start(ap, fmt);
char buf[STB_SPRINTF_MIN];
stbsp_vsprintfcb(orca_stbsp_callback, &ctx, buf, fmt, ap);
stbsp_vsprintfcb(oc_stbsp_callback, &ctx, buf, fmt, ap);
va_end(ap);
str8 msg = str8_list_join(scratch.arena, ctx.list);
oc_str8 msg = oc_str8_list_join(scratch.arena, ctx.list);
orca_runtime_abort(file, function, line, msg.ptr);
oc_runtime_abort_ext(file, function, line, msg.ptr);
mem_scratch_end(scratch);
oc_scratch_end(scratch);
}
_Noreturn void orca_assert_fail(const char* file, const char* function, int line, const char* src, const char* fmt, ...)
_Noreturn void oc_assert_fail(const char* file, const char* function, int line, const char* src, const char* fmt, ...)
{
mem_arena_scope scratch = mem_scratch_begin();
oc_arena_scope scratch = oc_scratch_begin();
orca_stbsp_context ctx = {
oc_stbsp_context ctx = {
.arena = scratch.arena,
.list = {0}
};
@ -127,13 +127,13 @@ _Noreturn void orca_assert_fail(const char* file, const char* function, int line
va_start(ap, fmt);
char buf[STB_SPRINTF_MIN];
stbsp_vsprintfcb(orca_stbsp_callback, &ctx, buf, fmt, ap);
stbsp_vsprintfcb(oc_stbsp_callback, &ctx, buf, fmt, ap);
va_end(ap);
str8 msg = str8_list_join(scratch.arena, ctx.list);
oc_str8 msg = oc_str8_list_join(scratch.arena, ctx.list);
orca_runtime_assert_fail(file, function, line, src, msg.ptr);
oc_runtime_assert_fail(file, function, line, src, msg.ptr);
mem_scratch_end(scratch);
oc_scratch_end(scratch);
}

View File

@ -6,8 +6,8 @@
#define LACKS_UNISTD_H
#define LACKS_SYS_PARAM_H
extern void* orca_mem_grow(u64 size);
#define MORECORE orca_mem_grow
extern void* oc_mem_grow(u64 size);
#define MORECORE oc_mem_grow
#define MORECORE_CONTIGUOUS 0
/*
This is a version (aka dlmalloc) of malloc/free/realloc written by
@ -5485,7 +5485,7 @@ History:
* Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
memory allocation routines
* Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
* Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
* Use 'assert' rather than 'OC_ASSERT' in WIN32 code to conform to
usage of 'assert' in non-WIN32 code
* Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
avoid infinite loop

View File

@ -8,24 +8,24 @@
#include"platform_memory.h"
void* ORCA_IMPORT(orca_mem_grow)(u64 size);
void* ORCA_IMPORT(oc_mem_grow)(u64 size);
void* orca_mem_base_reserve(mem_base_allocator* context, u64 size)
void* orca_oc_base_reserve(oc_base_allocator* context, u64 size)
{
return(orca_mem_grow(size));
return(oc_mem_grow(size));
}
void orca_mem_base_nop(mem_base_allocator* context, void* ptr, u64 size) {}
void orca_oc_base_nop(oc_base_allocator* context, void* ptr, u64 size) {}
mem_base_allocator* mem_base_allocator_default()
oc_base_allocator* oc_base_allocator_default()
{
static mem_base_allocator base = {0};
static oc_base_allocator base = {0};
if(base.reserve == 0)
{
base.reserve = orca_mem_base_reserve;
base.commit = orca_mem_base_nop;
base.decommit = orca_mem_base_nop;
base.release = orca_mem_base_nop;
base.reserve = orca_oc_base_reserve;
base.commit = orca_oc_base_nop;
base.decommit = orca_oc_base_nop;
base.release = orca_oc_base_nop;
}
return(&base);
}

View File

@ -18,8 +18,6 @@
#include<sys/types.h>
#include<sys/sysctl.h>
#include<unistd.h> // nanosleep()
#include"platform_clock.h"
@ -27,8 +25,8 @@ typedef struct timeval timeval;
typedef struct timespec timespec;
//TODO(martin): measure the actual values of these constants
const f64 SYSTEM_FUZZ = 25e-9, // minimum time to read the clock (s)
SYSTEM_TICK = 25e-9; // minimum step between two clock readings (s)
const f64 OC_CLOCK_FUZZ = 25e-9, // minimum time to read the clock (s)
OC_CLOCK_TICK = 25e-9; // minimum step between two clock readings (s)
static mach_timebase_info_data_t __machTimeBase__ = {1,1};
static u64 __initialTimestamp__ = 0;
@ -45,9 +43,9 @@ static inline u64 OSXGetUptimeNanoseconds()
static inline u64 OSXGetMonotonicNanoseconds()
{
//NOTE(martin): according to the documentation, MP_CLOCK_MONOTONIC increment monotonically
// on systems where MP_CLOCK_MONOTONIC_RAW is present, we may want to use that instead,
// because MP_CLOCK_MONOTONIC seems to be subject to frequency changes ?
//NOTE(martin): according to the documentation, OC_CLOCK_MONOTONIC increment monotonically
// on systems where OC_CLOCK_MONOTONIC_RAW is present, we may want to use that instead,
// because OC_CLOCK_MONOTONIC seems to be subject to frequency changes ?
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
#ifndef CLOCK_MONOTONIC_RAW
@ -65,7 +63,7 @@ static inline u64 OSXGetMonotonicNanoseconds()
static const f64 CLK_TIMESTAMPS_PER_SECOND = 4294967296.; // 2^32 as a double
static const u64 CLK_JAN_1970 = 2208988800ULL; // seconds from january 1900 to january 1970
void mp_clock_init()
void oc_clock_init()
{
mach_timebase_info(&__machTimeBase__);
@ -78,7 +76,7 @@ void mp_clock_init()
if(sysctl(mib, 2, &tv, &size, 0, 0) == -1)
{
log_error("can't read boot time\n");
oc_log_error("can't read boot time\n");
}
//NOTE(martin): convert boot date to timestamp
__initialTimestamp__ = (((u64)tv.tv_sec + CLK_JAN_1970) << 32)
@ -88,12 +86,12 @@ void mp_clock_init()
//RandomSeedFromDevice();
}
u64 mp_get_timestamp(mp_clock_kind clock)
u64 oc_clock_timestamp(oc_clock_kind clock)
{
u64 ts = 0;
switch(clock)
{
case MP_CLOCK_MONOTONIC:
case OC_CLOCK_MONOTONIC:
{
//NOTE(martin): compute monotonic offset and add it to bootup timestamp
u64 noff = OSXGetMonotonicNanoseconds() ;
@ -101,7 +99,7 @@ u64 mp_get_timestamp(mp_clock_kind clock)
ts = __initialTimestamp__ + foff;
} break;
case MP_CLOCK_UPTIME:
case OC_CLOCK_UPTIME:
{
//TODO(martin): maybe we should warn that this date is inconsistent after a sleep ?
//NOTE(martin): compute uptime offset and add it to bootup timestamp
@ -110,7 +108,7 @@ u64 mp_get_timestamp(mp_clock_kind clock)
ts = __initialTimestamp__ + foff;
} break;
case MP_CLOCK_DATE:
case OC_CLOCK_DATE:
{
//NOTE(martin): get system date and convert it to a fixed-point timestamp
timeval tv;
@ -123,7 +121,7 @@ u64 mp_get_timestamp(mp_clock_kind clock)
/*
//NOTE(martin): add a random fuzz between 0 and 1 times the system fuzz
//TODO(martin): ensure that we always return a value greater than the last value
f64 fuzz = RandomU32()/(f64)(~(0UL)) * SYSTEM_FUZZ;
f64 fuzz = RandomU32()/(f64)(~(0UL)) * OC_CLOCK_FUZZ;
ts_timediff tdfuzz = TimediffFromSeconds(fuzz);
ts = TimestampAdd(ts, tdfuzz);
*/
@ -132,18 +130,18 @@ u64 mp_get_timestamp(mp_clock_kind clock)
}
f64 mp_get_time(mp_clock_kind clock)
f64 oc_clock_time(oc_clock_kind clock)
{
switch(clock)
{
case MP_CLOCK_MONOTONIC:
case OC_CLOCK_MONOTONIC:
{
//NOTE(martin): compute monotonic offset and add it to bootup timestamp
u64 noff = OSXGetMonotonicNanoseconds();
return((f64)noff * 1e-9);
} break;
case MP_CLOCK_UPTIME:
case OC_CLOCK_UPTIME:
{
//TODO(martin): maybe we should warn that this date is inconsistent after a sleep ?
//NOTE(martin): compute uptime offset and add it to bootup timestamp
@ -151,7 +149,7 @@ f64 mp_get_time(mp_clock_kind clock)
return((f64)noff * 1e-9);
} break;
case MP_CLOCK_DATE:
case OC_CLOCK_DATE:
{
//TODO(martin): maybe warn about precision loss ?
// could also change the epoch since we only promise to return a relative time
@ -162,11 +160,3 @@ f64 mp_get_time(mp_clock_kind clock)
} break;
}
}
void mp_sleep_nanoseconds(u64 nanoseconds)
{
timespec rqtp;
rqtp.tv_sec = nanoseconds / 1000000000;
rqtp.tv_nsec = nanoseconds - rqtp.tv_sec * 1000000000;
nanosleep(&rqtp, 0);
}

View File

@ -12,33 +12,33 @@
#include"platform_path.c"
bool path_is_absolute(str8 path)
bool oc_path_is_absolute(oc_str8 path)
{
return(path.len && (path.ptr[0] == '/'));
}
str8 path_executable(mem_arena* arena)
oc_str8 oc_path_executable(oc_arena* arena)
{@autoreleasepool{
str8 result = {};
oc_str8 result = {};
u32 size = 0;
_NSGetExecutablePath(0, &size);
result.len = size;
result.ptr = mem_arena_alloc_array(arena, char, result.len+1);
result.ptr = oc_arena_push_array(arena, char, result.len+1);
_NSGetExecutablePath(result.ptr, &size);
result.ptr[result.len] = '\0';
return(result);
}}
str8 path_canonical(mem_arena* arena, str8 path)
oc_str8 oc_path_canonical(oc_arena* arena, oc_str8 path)
{
mem_arena_scope scratch = mem_scratch_begin_next(arena);
char* pathCString = str8_to_cstring(scratch.arena, path);
oc_arena_scope scratch = oc_scratch_begin_next(arena);
char* pathCString = oc_str8_to_cstring(scratch.arena, path);
char* real = realpath(pathCString, 0);
str8 result = str8_push_cstring(arena, real);
oc_str8 result = oc_str8_push_cstring(arena, real);
free(real);
mem_scratch_end(scratch);
oc_scratch_end(scratch);
return(result);
}

View File

@ -14,17 +14,17 @@
// Compiler identification
//-----------------------------------------------------------------
#if defined(__clang__)
#define COMPILER_CLANG 1
#define OC_COMPILER_CLANG 1
#if defined(__apple_build_version__)
#define COMPILER_CLANG_APPLE 1
#define OC_COMPILER_CLANG_APPLE 1
#elif defined(_MSC_VER)
#define COMPILER_CLANG_CL 1
#define OC_COMPILER_CLANG_CL 1
#endif
#elif defined(_MSC_VER)
#define COMPILER_CL 1
#define OC_COMPILER_CL 1
#elif defined(__GNUC__)
#define COMPILER_GCC 1
#define OC_COMPILER_GCC 1
#else
#error "Can't identify compiler"
#endif
@ -33,15 +33,15 @@
// OS identification
//-----------------------------------------------------------------
#if defined(_WIN64)
#define PLATFORM_WINDOWS 1
#define OC_PLATFORM_WINDOWS 1
#elif defined(_WIN32)
#error "Unsupported OS (32bit only version of Windows)"
#elif defined(__APPLE__) && defined(__MACH__)
#define PLATFORM_MACOS 1
#define OC_PLATFORM_MACOS 1
#elif defined(__gnu_linux__)
#define PLATFORM_LINUX 1
#elif defined(__ORCA__)
#define PLATFORM_ORCA 1
#define OC_PLATFORM_ORCA 1
#else
#error "Can't identify platform"
#endif
@ -49,29 +49,29 @@
//-----------------------------------------------------------------
// Architecture identification
//-----------------------------------------------------------------
#if defined(COMPILER_CL)
#if defined(OC_COMPILER_CL)
#if defined(_M_AMD64)
#define ARCH_X64 1
#define OC_ARCH_X64 1
#elif defined(_M_I86)
#define ARCH_X86 1
#define OC_ARCH_X86 1
#elif defined(_M_ARM64)
#define ARCH_ARM64 1
#define OC_ARCH_ARM64 1
#elif defined(_M_ARM)
#define ARCH_ARM32 1
#define OC_ARCH_ARM32 1
#else
#error "Can't identify architecture"
#endif
#else
#if defined(__x86_64__)
#define ARCH_X64 1
#define OC_ARCH_X64 1
#elif defined(__i386__)
#define ARCH_X86 1
#define OC_ARCH_X86 1
#elif defined(__arm__)
#define ARCH_ARM32 1
#define OC_ARCH_ARM32 1
#elif defined(__aarch64__)
#define ARCH_ARM64 1
#define OC_ARCH_ARM64 1
#elif defined(__ORCA__)
#define ARCH_WASM 1
#define OC_ARCH_WASM32 1
#else
#error "Can't identify architecture"
#endif
@ -80,28 +80,28 @@
//-----------------------------------------------------------------
// platform helper macros
//-----------------------------------------------------------------
#if defined(COMPILER_CL)
#if defined(MP_BUILD_DLL)
#define MP_API __declspec(dllexport)
#if defined(OC_COMPILER_CL)
#if defined(OC_BUILD_DLL)
#define ORCA_API __declspec(dllexport)
#else
#define MP_API __declspec(dllimport)
#define ORCA_API __declspec(dllimport)
#endif
#elif defined(COMPILER_GCC) || defined(COMPILER_CLANG)
#define MP_API
#elif defined(OC_COMPILER_GCC) || defined(OC_COMPILER_CLANG)
#define ORCA_API
#endif
#if PLATFORM_ORCA
#define mp_thread_local // no tls (or threads) for now on wasm orca
#elif defined(COMPILER_CL)
#define mp_thread_local __declspec(thread)
#elif defined(COMPILER_GCC) || defined(COMPILER_CLANG)
#define mp_thread_local __thread
#if OC_PLATFORM_ORCA
#define oc_thread_local // no tls (or threads) for now on wasm orca
#elif defined(OC_COMPILER_CL)
#define oc_thread_local __declspec(thread)
#elif defined(OC_COMPILER_GCC) || defined(OC_COMPILER_CLANG)
#define oc_thread_local __thread
#endif
#if PLATFORM_ORCA
#if OC_PLATFORM_ORCA
#define ORCA_IMPORT(f) __attribute__((import_name(#f))) f
#if COMPILER_CLANG
#if OC_COMPILER_CLANG
#define ORCA_EXPORT __attribute__((visibility("default")))
#else
#error "Orca apps can only be compiled with clang for now"

View File

@ -17,15 +17,14 @@ extern "C" {
#endif // __cplusplus
typedef enum {
MP_CLOCK_MONOTONIC, // clock that increment monotonically
MP_CLOCK_UPTIME, // clock that increment monotonically during uptime
MP_CLOCK_DATE // clock that is driven by the platform time
} mp_clock_kind;
OC_CLOCK_MONOTONIC, // clock that increment monotonically
OC_CLOCK_UPTIME, // clock that increment monotonically during uptime
OC_CLOCK_DATE // clock that is driven by the platform time
} oc_clock_kind;
MP_API void mp_clock_init(); // initialize the clock subsystem
MP_API u64 mp_get_timestamp(mp_clock_kind clock);
MP_API f64 mp_get_time(mp_clock_kind clock);
MP_API void mp_sleep_nanoseconds(u64 nanoseconds); // sleep for a given number of nanoseconds
ORCA_API void oc_clock_init(); // initialize the clock subsystem
ORCA_API u64 oc_clock_timestamp(oc_clock_kind clock);
ORCA_API f64 oc_clock_time(oc_clock_kind clock);
#ifdef __cplusplus
} // extern "C"

View File

@ -7,34 +7,34 @@
*****************************************************************/
#include"platform_debug.h"
typedef struct log_config
typedef struct oc_log_config
{
log_output* output;
log_level level;
} log_config;
oc_log_output* output;
oc_log_level level;
} oc_log_config;
//TODO: make default output a compile-time constant to avoid check in log_push()?
static log_config __logConfig = {0, LOG_LEVEL_INFO};
//TODO: make default output a compile-time constant to avoid check in oc_log_ext()?
static oc_log_config __logConfig = {0, OC_LOG_LEVEL_INFO};
void log_set_output(log_output* output)
void oc_log_set_output(oc_log_output* output)
{
__logConfig.output = output;
}
void log_set_level(log_level level)
void oc_log_set_level(oc_log_level level)
{
__logConfig.level = level;
}
void platform_log_push(log_output* output,
log_level level,
void platform_log_push(oc_log_output* output,
oc_log_level level,
const char* file,
const char* function,
int line,
const char* fmt,
va_list ap);
void log_push(log_level level,
void oc_log_ext(oc_log_level level,
const char* function,
const char* file,
int line,
@ -43,7 +43,7 @@ void log_push(log_level level,
{
if(!__logConfig.output)
{
__logConfig.output = LOG_DEFAULT_OUTPUT;
__logConfig.output = OC_LOG_DEFAULT_OUTPUT;
}
if(level <= __logConfig.level)

View File

@ -14,30 +14,30 @@
// Assert / Abort
//----------------------------------------------------------------
MP_API _Noreturn void orca_abort(const char* file, const char* function, int line, const char* fmt, ...);
MP_API _Noreturn void orca_assert_fail(const char* file, const char* function, int line, const char* src, const char* fmt, ...);
ORCA_API _Noreturn void oc_abort_ext(const char* file, const char* function, int line, const char* fmt, ...);
ORCA_API _Noreturn void oc_assert_fail(const char* file, const char* function, int line, const char* src, const char* fmt, ...);
//----------------------------------------------------------------
// Logging
//----------------------------------------------------------------
typedef enum { LOG_LEVEL_ERROR,
LOG_LEVEL_WARNING,
LOG_LEVEL_INFO,
LOG_LEVEL_COUNT } log_level;
typedef enum { OC_LOG_LEVEL_ERROR,
OC_LOG_LEVEL_WARNING,
OC_LOG_LEVEL_INFO,
OC_LOG_LEVEL_COUNT } oc_log_level;
typedef struct log_output log_output;
typedef struct oc_log_output oc_log_output;
extern log_output* LOG_DEFAULT_OUTPUT;
extern oc_log_output* OC_LOG_DEFAULT_OUTPUT;
MP_API void log_set_level(log_level level);
MP_API void log_set_output(log_output* output);
MP_API void log_push(log_level level,
const char* function,
const char* file,
int line,
const char* fmt,
...);
ORCA_API void oc_log_set_level(oc_log_level level);
ORCA_API void oc_log_set_output(oc_log_output* output);
ORCA_API void oc_log_ext(oc_log_level level,
const char* function,
const char* file,
int line,
const char* fmt,
...);
#endif //__PLATFORM_DEBUG_H_

View File

@ -15,56 +15,56 @@
// IO API
//----------------------------------------------------------------
typedef struct { u64 h; } file_handle;
typedef struct { u64 h; } oc_file;
typedef u16 file_open_flags;
enum _file_open_flags
typedef u16 oc_file_open_flags;
enum oc_file_open_flags_enum
{
FILE_OPEN_NONE = 0,
FILE_OPEN_APPEND = 1<<1,
FILE_OPEN_TRUNCATE = 1<<2,
FILE_OPEN_CREATE = 1<<3,
OC_FILE_OPEN_NONE = 0,
OC_FILE_OPEN_APPEND = 1<<1,
OC_FILE_OPEN_TRUNCATE = 1<<2,
OC_FILE_OPEN_CREATE = 1<<3,
FILE_OPEN_SYMLINK = 1<<4,
FILE_OPEN_NO_FOLLOW = 1<<5,
FILE_OPEN_RESTRICT = 1<<6,
OC_FILE_OPEN_SYMLINK = 1<<4,
OC_FILE_OPEN_NO_FOLLOW = 1<<5,
OC_FILE_OPEN_RESTRICT = 1<<6,
//...
};
typedef u16 file_access_rights;
enum _file_access_rights
typedef u16 oc_file_access;
enum oc_file_access_enum
{
FILE_ACCESS_NONE = 0,
FILE_ACCESS_READ = 1<<1,
FILE_ACCESS_WRITE = 1<<2,
OC_FILE_ACCESS_NONE = 0,
OC_FILE_ACCESS_READ = 1<<1,
OC_FILE_ACCESS_WRITE = 1<<2,
};
typedef enum { FILE_SEEK_SET, FILE_SEEK_END, FILE_SEEK_CURRENT } file_whence;
typedef enum { OC_FILE_SEEK_SET, OC_FILE_SEEK_END, OC_FILE_SEEK_CURRENT } oc_file_whence;
typedef u64 io_req_id;
typedef u64 oc_io_req_id;
typedef u32 io_op;
enum _io_op
typedef u32 oc_io_op;
enum oc_io_op_enum
{
IO_OP_OPEN_AT = 0,
IO_OP_CLOSE,
OC_IO_OPEN_AT = 0,
OC_IO_CLOSE,
IO_OP_FSTAT,
OC_IO_FSTAT,
IO_OP_SEEK,
IO_OP_READ,
IO_OP_WRITE,
OC_IO_SEEK,
OC_IO_READ,
OC_IO_WRITE,
IO_OP_ERROR,
OC_OC_IO_ERROR,
//...
};
typedef struct io_req
typedef struct oc_io_req
{
io_req_id id;
io_op op;
file_handle handle;
oc_io_req_id id;
oc_io_op op;
oc_file handle;
i64 offset;
u64 size;
@ -78,133 +78,133 @@ typedef struct io_req
{
struct
{
file_access_rights rights;
file_open_flags flags;
oc_file_access rights;
oc_file_open_flags flags;
} open;
file_whence whence;
oc_file_whence whence;
};
} io_req;
} oc_io_req;
typedef i32 io_error;
enum _io_error {
IO_OK = 0,
IO_ERR_UNKNOWN,
IO_ERR_OP, // unsupported operation
IO_ERR_HANDLE, // invalid handle
IO_ERR_PREV, // previously had a fatal error (last error stored on handle)
IO_ERR_ARG, // invalid argument or argument combination
IO_ERR_PERM, // access denied
IO_ERR_SPACE, // no space left
IO_ERR_NO_ENTRY, // file or directory does not exist
IO_ERR_EXISTS, // file already exists
IO_ERR_NOT_DIR, // path element is not a directory
IO_ERR_DIR, // attempted to write directory
IO_ERR_MAX_FILES, // max open files reached
IO_ERR_MAX_LINKS, // too many symbolic links in path
IO_ERR_PATH_LENGTH, // path too long
IO_ERR_FILE_SIZE, // file too big
IO_ERR_OVERFLOW, // offset too big
IO_ERR_NOT_READY, // no data ready to be read/written
IO_ERR_MEM, // failed to allocate memory
IO_ERR_INTERRUPT, // operation interrupted by a signal
IO_ERR_PHYSICAL, // physical IO error
IO_ERR_NO_DEVICE, // device not found
IO_ERR_WALKOUT, // attempted to walk out of root directory
typedef i32 oc_io_error;
enum oc_io_error_enum {
OC_IO_OK = 0,
OC_IO_ERR_UNKNOWN,
OC_IO_ERR_OP, // unsupported operation
OC_IO_ERR_HANDLE, // invalid handle
OC_IO_ERR_PREV, // previously had a fatal error (last error stored on handle)
OC_IO_ERR_ARG, // invalid argument or argument combination
OC_IO_ERR_PERM, // access denied
OC_IO_ERR_SPACE, // no space left
OC_IO_ERR_NO_ENTRY, // file or directory does not exist
OC_IO_ERR_EXISTS, // file already exists
OC_IO_ERR_NOT_DIR, // path element is not a directory
OC_IO_ERR_DIR, // attempted to write directory
OC_IO_ERR_MAX_FILES, // max open files reached
OC_IO_ERR_MAX_LINKS, // too many symbolic links in path
OC_IO_ERR_PATH_LENGTH, // path too long
OC_IO_ERR_FILE_SIZE, // file too big
OC_IO_ERR_OVERFLOW, // offset too big
OC_IO_ERR_NOT_READY, // no data ready to be read/written
OC_IO_ERR_MEM, // failed to allocate memory
OC_IO_ERR_INTERRUPT, // operation interrupted by a signal
OC_IO_ERR_PHYSICAL, // physical IO error
OC_IO_ERR_NO_DEVICE, // device not found
OC_IO_ERR_WALKOUT, // attempted to walk out of root directory
//...
};
typedef struct io_cmp
typedef struct oc_io_cmp
{
io_req_id id;
io_error error;
oc_io_req_id id;
oc_io_error error;
union
{
i64 result;
u64 size;
i64 offset;
file_handle handle;
oc_file handle;
//...
};
} io_cmp;
} oc_io_cmp;
//----------------------------------------------------------------
//TODO: complete io queue api
//----------------------------------------------------------------
MP_API io_cmp io_wait_single_req(io_req* req);
ORCA_API oc_io_cmp oc_io_wait_single_req(oc_io_req* req);
//----------------------------------------------------------------
// File IO wrapper API
//----------------------------------------------------------------
MP_API file_handle file_handle_nil();
MP_API bool file_handle_is_nil(file_handle handle);
ORCA_API oc_file oc_file_nil();
ORCA_API bool oc_file_is_nil(oc_file handle);
MP_API file_handle file_open(str8 path, file_access_rights rights, file_open_flags flags);
MP_API file_handle file_open_at(file_handle dir, str8 path, file_access_rights rights, file_open_flags flags);
MP_API void file_close(file_handle file);
ORCA_API oc_file oc_file_open(oc_str8 path, oc_file_access rights, oc_file_open_flags flags);
ORCA_API oc_file oc_file_open_at(oc_file dir, oc_str8 path, oc_file_access rights, oc_file_open_flags flags);
ORCA_API void oc_file_close(oc_file file);
MP_API i64 file_pos(file_handle file);
MP_API i64 file_seek(file_handle file, i64 offset, file_whence whence);
ORCA_API i64 oc_file_pos(oc_file file);
ORCA_API i64 oc_file_seek(oc_file file, i64 offset, oc_file_whence whence);
MP_API u64 file_write(file_handle file, u64 size, char* buffer);
MP_API u64 file_read(file_handle file, u64 size, char* buffer);
ORCA_API u64 oc_file_write(oc_file file, u64 size, char* buffer);
ORCA_API u64 oc_file_read(oc_file file, u64 size, char* buffer);
MP_API io_error file_last_error(file_handle handle);
ORCA_API oc_io_error oc_file_last_error(oc_file handle);
//----------------------------------------------------------------
// File System wrapper API
//----------------------------------------------------------------
typedef enum file_type
typedef enum oc_file_type
{
MP_FILE_UNKNOWN,
MP_FILE_REGULAR,
MP_FILE_DIRECTORY,
MP_FILE_SYMLINK,
MP_FILE_BLOCK,
MP_FILE_CHARACTER,
MP_FILE_FIFO,
MP_FILE_SOCKET,
OC_FILE_UNKNOWN,
OC_FILE_REGULAR,
OC_FILE_DIRECTORY,
OC_FILE_SYMLINK,
OC_FILE_BLOCK,
OC_FILE_CHARACTER,
OC_FILE_FIFO,
OC_FILE_SOCKET,
} file_type;
} oc_file_type;
typedef u16 file_perm;
enum file_perm
typedef u16 oc_file_perm;
enum oc_file_perm
{
MP_FILE_OTHER_EXEC = 1<<0,
MP_FILE_OTHER_WRITE = 1<<1,
MP_FILE_OTHER_READ = 1<<2,
OC_FILE_OTHER_EXEC = 1<<0,
OC_FILE_OTHER_WRITE = 1<<1,
OC_FILE_OTHER_READ = 1<<2,
MP_FILE_GROUP_EXEC = 1<<3,
MP_FILE_GROUP_WRITE = 1<<4,
MP_FILE_GROUP_READ = 1<<5,
OC_FILE_GROUP_EXEC = 1<<3,
OC_FILE_GROUP_WRITE = 1<<4,
OC_FILE_GROUP_READ = 1<<5,
MP_FILE_OWNER_EXEC = 1<<6,
MP_FILE_OWNER_WRITE = 1<<7,
MP_FILE_OWNER_READ = 1<<8,
OC_FILE_OWNER_EXEC = 1<<6,
OC_FILE_OWNER_WRITE = 1<<7,
OC_FILE_OWNER_READ = 1<<8,
MP_FILE_STICKY_BIT = 1<<9,
MP_FILE_SET_GID = 1<<10,
MP_FILE_SET_UID = 1<<11,
OC_FILE_STICKY_BIT = 1<<9,
OC_FILE_SET_GID = 1<<10,
OC_FILE_SET_UID = 1<<11,
};
typedef struct file_status
typedef struct oc_file_status
{
u64 uid;
file_type type;
file_perm perm;
oc_file_type type;
oc_file_perm perm;
u64 size;
//TODO times
} file_status;
} oc_file_status;
MP_API file_status file_get_status(file_handle file);
MP_API u64 file_size(file_handle file);
ORCA_API oc_file_status oc_file_get_status(oc_file file);
ORCA_API u64 oc_file_size(oc_file file);
//TODO: Complete as needed...

View File

@ -11,112 +11,112 @@
// File stream read/write API
//------------------------------------------------------------------------------
file_handle file_handle_nil()
oc_file oc_file_nil()
{
return((file_handle){0});
return((oc_file){0});
}
bool file_handle_is_nil(file_handle handle)
bool oc_file_is_nil(oc_file handle)
{
return(handle.h == 0);
}
file_handle file_open(str8 path, file_access_rights rights, file_open_flags flags)
oc_file oc_file_open(oc_str8 path, oc_file_access rights, oc_file_open_flags flags)
{
io_req req = {.op = IO_OP_OPEN_AT,
oc_io_req req = {.op = OC_IO_OPEN_AT,
.size = path.len,
.buffer = path.ptr,
.open.rights = rights,
.open.flags = flags };
io_cmp cmp = io_wait_single_req(&req);
oc_io_cmp cmp = oc_io_wait_single_req(&req);
//WARN: we always return a handle that can be queried for errors. Handles must be closed
// even if there was an error when opening
return(cmp.handle);
}
file_handle file_open_at(file_handle dir, str8 path, file_access_rights rights, file_open_flags flags)
oc_file oc_file_open_at(oc_file dir, oc_str8 path, oc_file_access rights, oc_file_open_flags flags)
{
io_req req = {.op = IO_OP_OPEN_AT,
oc_io_req req = {.op = OC_IO_OPEN_AT,
.handle = dir,
.size = path.len,
.buffer = path.ptr,
.open.rights = rights,
.open.flags = flags,};
io_cmp cmp = io_wait_single_req(&req);
oc_io_cmp cmp = oc_io_wait_single_req(&req);
return(cmp.handle);
}
void file_close(file_handle file)
void oc_file_close(oc_file file)
{
io_req req = {.op = IO_OP_CLOSE,
oc_io_req req = {.op = OC_IO_CLOSE,
.handle = file};
io_wait_single_req(&req);
oc_io_wait_single_req(&req);
}
i64 file_seek(file_handle file, i64 offset, file_whence whence)
i64 oc_file_seek(oc_file file, i64 offset, oc_file_whence whence)
{
io_req req = {.op = IO_OP_SEEK,
oc_io_req req = {.op = OC_IO_SEEK,
.handle = file,
.offset = offset,
.whence = whence};
io_cmp cmp = io_wait_single_req(&req);
oc_io_cmp cmp = oc_io_wait_single_req(&req);
return(cmp.offset);
}
i64 file_pos(file_handle file)
i64 oc_file_pos(oc_file file)
{
return(file_seek(file, 0, FILE_SEEK_CURRENT));
return(oc_file_seek(file, 0, OC_FILE_SEEK_CURRENT));
}
u64 file_write(file_handle file, u64 size, char* buffer)
u64 oc_file_write(oc_file file, u64 size, char* buffer)
{
io_req req = {.op = IO_OP_WRITE,
oc_io_req req = {.op = OC_IO_WRITE,
.handle = file,
.size = size,
.buffer = buffer};
io_cmp cmp = io_wait_single_req(&req);
oc_io_cmp cmp = oc_io_wait_single_req(&req);
return(cmp.size);
}
u64 file_read(file_handle file, u64 size, char* buffer)
u64 oc_file_read(oc_file file, u64 size, char* buffer)
{
io_req req = {.op = IO_OP_READ,
oc_io_req req = {.op = OC_IO_READ,
.handle = file,
.size = size,
.buffer = buffer};
io_cmp cmp = io_wait_single_req(&req);
oc_io_cmp cmp = oc_io_wait_single_req(&req);
return(cmp.size);
}
io_error file_last_error(file_handle file)
oc_io_error oc_file_last_error(oc_file file)
{
io_req req = {.op = IO_OP_ERROR,
oc_io_req req = {.op = OC_OC_IO_ERROR,
.handle = file};
io_cmp cmp = io_wait_single_req(&req);
return((io_error)cmp.result);
oc_io_cmp cmp = oc_io_wait_single_req(&req);
return((oc_io_error)cmp.result);
}
file_status file_get_status(file_handle file)
oc_file_status oc_file_get_status(oc_file file)
{
file_status status = {0};
io_req req = {.op = IO_OP_FSTAT,
oc_file_status status = {0};
oc_io_req req = {.op = OC_IO_FSTAT,
.handle = file,
.size = sizeof(file_status),
.size = sizeof(oc_file_status),
.buffer = (char*)&status};
io_cmp cmp = io_wait_single_req(&req);
oc_io_cmp cmp = oc_io_wait_single_req(&req);
return(status);
}
u64 file_size(file_handle file)
u64 oc_file_size(oc_file file)
{
file_status status = file_get_status(file);
oc_file_status status = oc_file_get_status(file);
return(status.size);
}

View File

@ -9,12 +9,12 @@
#include"platform_io_internal.h"
#include"platform_path.h"
file_table __globalFileTable = {0};
oc_file_table oc_globalFileTable = {0};
file_slot* file_slot_alloc(file_table* table)
oc_file_slot* oc_file_slot_alloc(oc_file_table* table)
{
file_slot* slot = list_pop_entry(&table->freeList, file_slot, freeListElt);
if(!slot && table->nextSlot < ORCA_MAX_FILE_SLOTS)
oc_file_slot* slot = oc_list_pop_entry(&table->freeList, oc_file_slot, freeListElt);
if(!slot && table->nextSlot < OC_IO_MAX_FILE_SLOTS)
{
slot = &table->slots[table->nextSlot];
slot->generation = 1;
@ -22,36 +22,36 @@ file_slot* file_slot_alloc(file_table* table)
}
u32 tmpGeneration = slot->generation;
memset(slot, 0, sizeof(file_slot));
memset(slot, 0, sizeof(oc_file_slot));
slot->generation = tmpGeneration;
return(slot);
}
void file_slot_recycle(file_table* table, file_slot* slot)
void oc_file_slot_recycle(oc_file_table* table, oc_file_slot* slot)
{
slot->generation++;
list_push(&table->freeList, &slot->freeListElt);
oc_list_push(&table->freeList, &slot->freeListElt);
}
file_handle file_handle_from_slot(file_table* table, file_slot* slot)
oc_file oc_file_from_slot(oc_file_table* table, oc_file_slot* slot)
{
u64 index = slot - table->slots;
u64 generation = slot->generation;
file_handle handle = {.h = (generation<<32) | index };
oc_file handle = {.h = (generation<<32) | index };
return(handle);
}
file_slot* file_slot_from_handle(file_table* table, file_handle handle)
oc_file_slot* oc_file_slot_from_handle(oc_file_table* table, oc_file handle)
{
file_slot* slot = 0;
oc_file_slot* slot = 0;
u64 index = handle.h & 0xffffffff;
u64 generation = handle.h>>32;
if(index < table->nextSlot)
{
file_slot* candidate = &table->slots[index];
oc_file_slot* candidate = &table->slots[index];
if(candidate->generation == generation)
{
slot = candidate;
@ -60,149 +60,149 @@ file_slot* file_slot_from_handle(file_table* table, file_handle handle)
return(slot);
}
io_cmp io_wait_single_req(io_req* req)
oc_io_cmp oc_io_wait_single_req(oc_io_req* req)
{
return(io_wait_single_req_with_table(req, &__globalFileTable));
return(oc_io_wait_single_req_with_table(req, &oc_globalFileTable));
}
//-----------------------------------------------------------------------
// io common primitives
//-----------------------------------------------------------------------
typedef struct io_open_restrict_context
typedef struct oc_io_open_restrict_context
{
io_error error;
oc_io_error error;
u64 rootUID;
io_file_desc rootFd;
io_file_desc fd;
oc_file_desc rootFd;
oc_file_desc fd;
} io_open_restrict_context;
} oc_io_open_restrict_context;
io_error io_open_restrict_enter(io_open_restrict_context* context, str8 name, file_access_rights accessRights, file_open_flags openFlags)
oc_io_error oc_io_open_restrict_enter(oc_io_open_restrict_context* context, oc_str8 name, oc_file_access accessRights, oc_file_open_flags openFlags)
{
io_file_desc nextFd = io_raw_open_at(context->fd, name, accessRights, openFlags);
if(io_file_desc_is_nil(nextFd))
oc_file_desc nextFd = oc_io_raw_open_at(context->fd, name, accessRights, openFlags);
if(oc_file_desc_is_nil(nextFd))
{
context->error = io_raw_last_error();
context->error = oc_io_raw_last_error();
}
else
{
if(context->fd != context->rootFd)
{
io_raw_close(context->fd);
oc_io_raw_close(context->fd);
}
context->fd = nextFd;
}
return(context->error);
}
typedef struct io_open_restrict_result
typedef struct oc_io_open_restrict_result
{
io_error error;
io_file_desc fd;
} io_open_restrict_result;
oc_io_error error;
oc_file_desc fd;
} oc_io_open_restrict_result;
io_open_restrict_result io_open_restrict(io_file_desc dirFd, str8 path, file_access_rights accessRights, file_open_flags openFlags)
oc_io_open_restrict_result oc_io_open_restrict(oc_file_desc dirFd, oc_str8 path, oc_file_access accessRights, oc_file_open_flags openFlags)
{
mem_arena_scope scratch = mem_scratch_begin();
oc_arena_scope scratch = oc_scratch_begin();
str8_list sep = {0};
str8_list_push(scratch.arena, &sep, STR8("/"));
str8_list_push(scratch.arena, &sep, STR8("\\"));
str8_list pathElements = str8_split(scratch.arena, path, sep);
oc_str8_list sep = {0};
oc_str8_list_push(scratch.arena, &sep, OC_STR8("/"));
oc_str8_list_push(scratch.arena, &sep, OC_STR8("\\"));
oc_str8_list pathElements = oc_str8_split(scratch.arena, path, sep);
io_open_restrict_context context = {
.error = IO_OK,
oc_io_open_restrict_context context = {
.error = OC_IO_OK,
.rootFd = dirFd,
.fd = dirFd,
};
if(io_file_desc_is_nil(dirFd))
if(oc_file_desc_is_nil(dirFd))
{
context.error = IO_ERR_HANDLE;
context.error = OC_IO_ERR_HANDLE;
}
else
{
file_status status;
context.error = io_raw_fstat(dirFd, &status);
oc_file_status status;
context.error = oc_io_raw_fstat(dirFd, &status);
context.rootUID = status.uid;
}
if(context.error == IO_OK)
if(context.error == OC_IO_OK)
{
for_list(&pathElements.list, elt, str8_elt, listElt)
oc_list_for(&pathElements.list, elt, oc_str8_elt, listElt)
{
str8 name = elt->string;
file_access_rights eltAccessRights = FILE_ACCESS_READ;
file_open_flags eltOpenFlags = 0;
oc_str8 name = elt->string;
oc_file_access eltAccessRights = OC_FILE_ACCESS_READ;
oc_file_open_flags eltOpenFlags = 0;
bool atLastElement = (&elt->listElt == list_last(&pathElements.list));
bool atLastElement = (&elt->listElt == oc_list_last(&pathElements.list));
if(atLastElement)
{
eltAccessRights = accessRights;
eltOpenFlags = openFlags;
}
if( !str8_cmp(name, STR8("."))
if( !oc_str8_cmp(name, OC_STR8("."))
&& !atLastElement)
{
//NOTE: if we're not at the last element we can just skip '.' elements
continue;
}
else if(!str8_cmp(name, STR8("..")))
else if(!oc_str8_cmp(name, OC_STR8("..")))
{
//NOTE: check that we don't escape root dir
file_status status;
context.error = io_raw_fstat(context.fd, &status);
oc_file_status status;
context.error = oc_io_raw_fstat(context.fd, &status);
if(context.error)
{
break;
}
else if(status.uid == context.rootUID)
{
context.error = IO_ERR_WALKOUT;
context.error = OC_IO_ERR_WALKOUT;
break;
}
}
else if(!io_raw_file_exists_at(context.fd, name, FILE_OPEN_SYMLINK))
else if(!oc_io_raw_file_exists_at(context.fd, name, OC_FILE_OPEN_SYMLINK))
{
//NOTE: if the file doesn't exists, but we're at the last element and FILE_OPEN_CREATE
// is set, we create the file. Otherwise it is a IO_ERROR_NO_ENTRY error.
//NOTE: if the file doesn't exists, but we're at the last element and OC_FILE_OPEN_CREATE
// is set, we create the file. Otherwise it is a OC_IO_ERROR_NO_ENTRY error.
if( !atLastElement
|| !(openFlags & FILE_OPEN_CREATE))
|| !(openFlags & OC_FILE_OPEN_CREATE))
{
context.error = IO_ERR_NO_ENTRY;
context.error = OC_IO_ERR_NO_ENTRY;
break;
}
}
else
{
//NOTE: if the file exists, we check the type of file
file_status status = {0};
context.error = io_raw_fstat_at(context.fd, name, FILE_OPEN_SYMLINK, &status);
oc_file_status status = {0};
context.error = oc_io_raw_fstat_at(context.fd, name, OC_FILE_OPEN_SYMLINK, &status);
if(context.error)
{
break;
}
if(status.type == MP_FILE_REGULAR)
if(status.type == OC_FILE_REGULAR)
{
if(!atLastElement)
{
context.error = IO_ERR_NOT_DIR;
context.error = OC_IO_ERR_NOT_DIR;
break;
}
}
else if(status.type == MP_FILE_SYMLINK)
else if(status.type == OC_FILE_SYMLINK)
{
//TODO - do we need a FILE_OPEN_NO_FOLLOW that fails if last element is a symlink?
// - do we need a FILE_OPEN_NO_SYMLINKS that fails if _any_ element is a symlink?
//TODO - do we need a OC_FILE_OPEN_NO_FOLLOW that fails if last element is a symlink?
// - do we need a OC_FILE_OPEN_NO_SYMLINKS that fails if _any_ element is a symlink?
if( !atLastElement
|| !(openFlags & FILE_OPEN_SYMLINK))
|| !(openFlags & OC_FILE_OPEN_SYMLINK))
{
io_raw_read_link_result link = io_raw_read_link_at(scratch.arena, context.fd, name);
oc_io_raw_read_link_result link = oc_io_raw_read_link_at(scratch.arena, context.fd, name);
if(link.error)
{
context.error = link.error;
@ -211,19 +211,19 @@ io_open_restrict_result io_open_restrict(io_file_desc dirFd, str8 path, file_acc
if(link.target.len == 0)
{
//NOTE: treat an empty target as a '.'
link.target = STR8(".");
link.target = OC_STR8(".");
}
else if(path_is_absolute(link.target))
else if(oc_path_is_absolute(link.target))
{
context.error = IO_ERR_WALKOUT;
context.error = OC_IO_ERR_WALKOUT;
break;
}
str8_list linkElements = str8_split(scratch.arena, link.target, sep);
if(!list_empty(&linkElements.list))
oc_str8_list linkElements = oc_str8_split(scratch.arena, link.target, sep);
if(!oc_list_empty(&linkElements.list))
{
//NOTE: insert linkElements into pathElements after elt
list_elt* tmp = elt->listElt.next;
oc_list_elt* tmp = elt->listElt.next;
elt->listElt.next = linkElements.list.first;
linkElements.list.last->next = tmp;
if(!tmp)
@ -234,63 +234,63 @@ io_open_restrict_result io_open_restrict(io_file_desc dirFd, str8 path, file_acc
continue;
}
}
else if(status.type != MP_FILE_DIRECTORY)
else if(status.type != OC_FILE_DIRECTORY)
{
context.error = IO_ERR_NOT_DIR;
context.error = OC_IO_ERR_NOT_DIR;
break;
}
}
//NOTE: if we arrive here, we have no errors and the correct flags are set,
// so we can enter the element
DEBUG_ASSERT(context.error == IO_OK);
io_open_restrict_enter(&context, name, eltAccessRights, eltOpenFlags);
OC_DEBUG_ASSERT(context.error == OC_IO_OK);
oc_io_open_restrict_enter(&context, name, eltAccessRights, eltOpenFlags);
}
}
if(context.error && !io_file_desc_is_nil(context.fd))
if(context.error && !oc_file_desc_is_nil(context.fd))
{
if(context.fd != context.rootFd)
{
io_raw_close(context.fd);
oc_io_raw_close(context.fd);
}
context.fd = io_file_desc_nil();
context.fd = oc_file_desc_nil();
}
io_open_restrict_result result = {
oc_io_open_restrict_result result = {
.error = context.error,
.fd = context.fd
};
mem_scratch_end(scratch);
oc_scratch_end(scratch);
return(result);
}
io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table)
oc_io_cmp oc_io_open_at(oc_file_slot* atSlot, oc_io_req* req, oc_file_table* table)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
file_slot* slot = file_slot_alloc(table);
oc_file_slot* slot = oc_file_slot_alloc(table);
if(!slot)
{
cmp.error = IO_ERR_MAX_FILES;
cmp.error = OC_IO_ERR_MAX_FILES;
cmp.result = 0;
}
else
{
slot->fd = io_file_desc_nil();
cmp.handle = file_handle_from_slot(table, slot);
slot->fd = oc_file_desc_nil();
cmp.handle = oc_file_from_slot(table, slot);
str8 path = str8_from_buffer(req->size, req->buffer);
oc_str8 path = oc_str8_from_buffer(req->size, req->buffer);
if(!path.len)
{
slot->error = IO_ERR_ARG;
slot->error = OC_IO_ERR_ARG;
}
else if(!atSlot && !file_handle_is_nil(req->handle))
else if(!atSlot && !oc_file_is_nil(req->handle))
{
slot->error = IO_ERR_HANDLE;
slot->error = OC_IO_ERR_HANDLE;
}
else
{
@ -302,34 +302,34 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table)
if(slot->rights != req->open.rights)
{
slot->error = IO_ERR_PERM;
slot->error = OC_IO_ERR_PERM;
}
else
{
io_file_desc dirFd = atSlot ? atSlot->fd : io_file_desc_nil();
oc_file_desc dirFd = atSlot ? atSlot->fd : oc_file_desc_nil();
if(req->open.flags & FILE_OPEN_RESTRICT)
if(req->open.flags & OC_FILE_OPEN_RESTRICT)
{
io_open_restrict_result res = io_open_restrict(dirFd, path, slot->rights, req->open.flags);
oc_io_open_restrict_result res = oc_io_open_restrict(dirFd, path, slot->rights, req->open.flags);
slot->error = res.error;
slot->fd = res.fd;
}
else
{
slot->fd = io_raw_open_at(dirFd, path, slot->rights, req->open.flags);
if(io_file_desc_is_nil(slot->fd))
slot->fd = oc_io_raw_open_at(dirFd, path, slot->rights, req->open.flags);
if(oc_file_desc_is_nil(slot->fd))
{
slot->error = io_raw_last_error();
slot->error = oc_io_raw_last_error();
}
}
}
}
if(slot->error == IO_OK)
if(slot->error == OC_IO_OK)
{
file_status status;
slot->error = io_raw_fstat(slot->fd, &status);
if(slot->error == IO_OK)
oc_file_status status;
slot->error = oc_io_raw_fstat(slot->fd, &status);
if(slot->error == OC_IO_OK)
{
slot->type = status.type;
}

View File

@ -11,60 +11,60 @@
#include"platform_io.h"
#include"platform.h"
#if PLATFORM_MACOS || PLATFORM_LINUX
typedef int io_file_desc;
#elif PLATFORM_WINDOWS
#if OC_PLATFORM_MACOS || PLATFORM_LINUX
typedef int oc_file_desc;
#elif OC_PLATFORM_WINDOWS
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include<windows.h>
typedef HANDLE io_file_desc;
typedef HANDLE oc_file_desc;
#endif
typedef struct file_slot
typedef struct oc_file_slot
{
u32 generation;
io_error error;
oc_io_error error;
bool fatal;
list_elt freeListElt;
oc_list_elt freeListElt;
file_type type;
file_access_rights rights;
io_file_desc fd;
oc_file_type type;
oc_file_access rights;
oc_file_desc fd;
} file_slot;
} oc_file_slot;
enum
{
ORCA_MAX_FILE_SLOTS = 256,
OC_IO_MAX_FILE_SLOTS = 256,
};
typedef struct file_table
typedef struct oc_file_table
{
file_slot slots[ORCA_MAX_FILE_SLOTS];
oc_file_slot slots[OC_IO_MAX_FILE_SLOTS];
u32 nextSlot;
list_info freeList;
} file_table;
oc_list freeList;
} oc_file_table;
file_slot* file_slot_alloc(file_table* table);
void file_slot_recycle(file_table* table, file_slot* slot);
file_handle file_handle_from_slot(file_table* table, file_slot* slot);
file_slot* file_slot_from_handle(file_table* table, file_handle handle);
oc_file_slot* oc_file_slot_alloc(oc_file_table* table);
void oc_file_slot_recycle(oc_file_table* table, oc_file_slot* slot);
oc_file oc_file_from_slot(oc_file_table* table, oc_file_slot* slot);
oc_file_slot* oc_file_slot_from_handle(oc_file_table* table, oc_file handle);
MP_API io_cmp io_wait_single_req_with_table(io_req* req, file_table* table);
ORCA_API oc_io_cmp oc_io_wait_single_req_with_table(oc_io_req* req, oc_file_table* table);
//-----------------------------------------------------------------------
// raw io primitives
//-----------------------------------------------------------------------
io_file_desc io_file_desc_nil();
bool io_file_desc_is_nil(io_file_desc fd);
oc_file_desc oc_file_desc_nil();
bool oc_file_desc_is_nil(oc_file_desc fd);
/*WARN
io_raw_xxx_at functions are similar to posix openat() regarding path resolution,
oc_io_raw_xxx_at functions are similar to posix openat() regarding path resolution,
but with some important differences:
- If dirFd is a non-nil fd, path is considered relative to dirFd _even if it is an absolute path_
- If dirFd is a non-nil fd, path is considered relative to dirFd _even if it is an absolute oc_path_
- If dirFd is a nil fd, it is _ignored_ (i.e., path can be absolute, or relative to the current directory)
This means that:
@ -72,19 +72,19 @@ bool io_file_desc_is_nil(io_file_desc fd);
- we don't need a special handle value to use a path relative to the current working directory
(we just pass a nil dirFd with a relative path)
*/
io_file_desc io_raw_open_at(io_file_desc dirFd, str8 path, file_access_rights accessRights, file_open_flags openFlags);
void io_raw_close(io_file_desc fd);
io_error io_raw_last_error();
bool io_raw_file_exists_at(io_file_desc dirFd, str8 path, file_open_flags openFlags);
io_error io_raw_fstat(io_file_desc fd, file_status* status);
io_error io_raw_fstat_at(io_file_desc dirFd, str8 path, file_open_flags openFlags, file_status* status);
oc_file_desc oc_io_raw_open_at(oc_file_desc dirFd, oc_str8 path, oc_file_access accessRights, oc_file_open_flags openFlags);
void oc_io_raw_close(oc_file_desc fd);
oc_io_error oc_io_raw_last_error();
bool oc_io_raw_file_exists_at(oc_file_desc dirFd, oc_str8 path, oc_file_open_flags openFlags);
oc_io_error oc_io_raw_fstat(oc_file_desc fd, oc_file_status* status);
oc_io_error oc_io_raw_fstat_at(oc_file_desc dirFd, oc_str8 path, oc_file_open_flags openFlags, oc_file_status* status);
typedef struct io_raw_read_link_result
typedef struct oc_io_raw_read_link_result
{
io_error error;
str8 target;
} io_raw_read_link_result;
oc_io_error error;
oc_str8 target;
} oc_io_raw_read_link_result;
io_raw_read_link_result io_raw_read_link_at(mem_arena* arena, io_file_desc dirFd, str8 path);
oc_io_raw_read_link_result oc_io_raw_read_link_at(oc_arena* arena, oc_file_desc dirFd, oc_str8 path);
#endif //__PLATFORM_IO_INTERNAL_H_

View File

@ -19,40 +19,34 @@ extern "C" {
//--------------------------------------------------------------------------------
//NOTE(martin): base allocator
//--------------------------------------------------------------------------------
typedef struct mem_base_allocator mem_base_allocator;
typedef struct oc_base_allocator oc_base_allocator;
typedef void*(*mem_reserve_function)(mem_base_allocator* context, u64 size);
typedef void(*mem_modify_function)(mem_base_allocator* context, void* ptr, u64 size);
typedef void*(*oc_mem_reserve_function)(oc_base_allocator* context, u64 size);
typedef void(*oc_mem_modify_function)(oc_base_allocator* context, void* ptr, u64 size);
typedef struct mem_base_allocator
typedef struct oc_base_allocator
{
mem_reserve_function reserve;
mem_modify_function commit;
mem_modify_function decommit;
mem_modify_function release;
oc_mem_reserve_function reserve;
oc_mem_modify_function commit;
oc_mem_modify_function decommit;
oc_mem_modify_function release;
} mem_base_allocator;
} oc_base_allocator;
MP_API mem_base_allocator* mem_base_allocator_default();
ORCA_API oc_base_allocator* oc_base_allocator_default();
#define mem_base_reserve(base, size) base->reserve(base, size)
#define mem_base_commit(base, ptr, size) base->commit(base, ptr, size)
#define mem_base_decommit(base, ptr, size) base->decommit(base, ptr, size)
#define mem_base_release(base, ptr, size) base->release(base, ptr, size)
#define oc_base_reserve(base, size) base->reserve(base, size)
#define oc_base_commit(base, ptr, size) base->commit(base, ptr, size)
#define oc_base_decommit(base, ptr, size) base->decommit(base, ptr, size)
#define oc_base_release(base, ptr, size) base->release(base, ptr, size)
//--------------------------------------------------------------------------------
//NOTE(martin): malloc/free
//--------------------------------------------------------------------------------
#if PLATFORM_ORCA
void* malloc(size_t size);
void* realloc(void* ptr, size_t size);
void free(void* ptr);
#else
#include<stdlib.h>
#endif
#include<stdlib.h>
#define malloc_type(type) ((type*)malloc(sizeof(type)))
#define malloc_array(type, count) ((type*)malloc(sizeof(type)*count))
#define oc_malloc_type(type) ((type*)malloc(sizeof(type)))
#define oc_malloc_array(type, count) ((type*)malloc(sizeof(type)*count))
//--------------------------------------------------------------------------------
//NOTE(martin): memset / memcpy

View File

@ -8,7 +8,7 @@
#include"platform_path.h"
str8 path_slice_directory(str8 fullPath)
oc_str8 oc_path_slice_directory(oc_str8 fullPath)
{
i64 lastSlashIndex = -1;
@ -20,11 +20,11 @@ str8 path_slice_directory(str8 fullPath)
break;
}
}
str8 directory = str8_slice(fullPath, 0, lastSlashIndex+1);
oc_str8 directory = oc_str8_slice(fullPath, 0, lastSlashIndex+1);
return(directory);
}
str8 path_slice_filename(str8 fullPath)
oc_str8 oc_path_slice_filename(oc_str8 fullPath)
{
i64 lastSlashIndex = -1;
@ -37,69 +37,69 @@ str8 path_slice_filename(str8 fullPath)
}
}
str8 basename = str8_slice(fullPath, lastSlashIndex+1, fullPath.len);
oc_str8 basename = oc_str8_slice(fullPath, lastSlashIndex+1, fullPath.len);
return(basename);
}
str8_list path_split(mem_arena* arena, str8 path)
oc_str8_list oc_path_split(oc_arena* arena, oc_str8 path)
{
mem_arena_scope tmp = mem_scratch_begin_next(arena);
str8_list split = {0};
str8_list_push(tmp.arena, &split, STR8("/"));
str8_list res = str8_split(arena, path, split);
mem_scratch_end(tmp);
oc_arena_scope tmp = oc_scratch_begin_next(arena);
oc_str8_list split = {0};
oc_str8_list_push(tmp.arena, &split, OC_STR8("/"));
oc_str8_list res = oc_str8_split(arena, path, split);
oc_scratch_end(tmp);
return(res);
}
str8 path_join(mem_arena* arena, str8_list elements)
oc_str8 oc_path_join(oc_arena* arena, oc_str8_list elements)
{
//TODO: check if elements have ending/begining '/' ?
str8 res = str8_list_collate(arena, elements, STR8("/"), STR8("/"), (str8){0});
oc_str8 res = oc_str8_list_collate(arena, elements, OC_STR8("/"), OC_STR8("/"), (oc_str8){0});
return(res);
}
str8 path_append(mem_arena* arena, str8 parent, str8 relPath)
oc_str8 oc_path_append(oc_arena* arena, oc_str8 parent, oc_str8 relPath)
{
str8 result = {0};
oc_str8 result = {0};
if(parent.len == 0)
{
result = str8_push_copy(arena, relPath);
result = oc_str8_push_copy(arena, relPath);
}
else if(relPath.len == 0)
{
result = str8_push_copy(arena, parent);
result = oc_str8_push_copy(arena, parent);
}
else
{
mem_arena_scope tmp = mem_scratch_begin_next(arena);
oc_arena_scope tmp = oc_scratch_begin_next(arena);
str8_list list = {0};
str8_list_push(tmp.arena, &list, parent);
oc_str8_list list = {0};
oc_str8_list_push(tmp.arena, &list, parent);
if( (parent.ptr[parent.len-1] != '/')
&&(relPath.ptr[relPath.len-1] != '/'))
{
str8_list_push(tmp.arena, &list, STR8("/"));
oc_str8_list_push(tmp.arena, &list, OC_STR8("/"));
}
str8_list_push(tmp.arena, &list, relPath);
oc_str8_list_push(tmp.arena, &list, relPath);
result = str8_list_join(arena, list);
result = oc_str8_list_join(arena, list);
mem_scratch_end(tmp);
oc_scratch_end(tmp);
}
return(result);
}
str8 path_executable_relative(mem_arena* arena, str8 relPath)
oc_str8 oc_path_executable_relative(oc_arena* arena, oc_str8 relPath)
{
str8_list list = {0};
mem_arena_scope scratch = mem_scratch_begin_next(arena);
oc_str8_list list = {0};
oc_arena_scope scratch = oc_scratch_begin_next(arena);
str8 executablePath = path_executable(scratch.arena);
str8 dirPath = path_slice_directory(executablePath);
oc_str8 executablePath = oc_path_executable(scratch.arena);
oc_str8 dirPath = oc_path_slice_directory(executablePath);
str8 path = path_append(arena, dirPath, relPath);
oc_str8 path = oc_path_append(arena, dirPath, relPath);
mem_scratch_end(scratch);
oc_scratch_end(scratch);
return(path);
}

View File

@ -16,18 +16,18 @@
the string.
*/
MP_API str8 path_slice_directory(str8 path);
MP_API str8 path_slice_filename(str8 path);
ORCA_API oc_str8 oc_path_slice_directory(oc_str8 path);
ORCA_API oc_str8 oc_path_slice_filename(oc_str8 path);
MP_API str8_list path_split(mem_arena* arena, str8 path);
MP_API str8 path_join(mem_arena* arena, str8_list elements);
MP_API str8 path_append(mem_arena* arena, str8 parent, str8 relPath);
ORCA_API oc_str8_list oc_path_split(oc_arena* arena, oc_str8 path);
ORCA_API oc_str8 oc_path_join(oc_arena* arena, oc_str8_list elements);
ORCA_API oc_str8 oc_path_append(oc_arena* arena, oc_str8 parent, oc_str8 relPath);
MP_API bool path_is_absolute(str8 path);
MP_API str8 path_executable(mem_arena* arena);
MP_API str8 path_canonical(mem_arena* arena, str8 path);
ORCA_API bool oc_path_is_absolute(oc_str8 path);
ORCA_API oc_str8 oc_path_executable(oc_arena* arena);
ORCA_API oc_str8 oc_path_canonical(oc_arena* arena, oc_str8 path);
// helper: gets the path from path_executable() and appends relPath
MP_API str8 path_executable_relative(mem_arena* arena, str8 relPath);
// helper: gets the path from oc_path_executable() and appends relPath
ORCA_API oc_str8 oc_path_executable_relative(oc_arena* arena, oc_str8 relPath);
#endif //__PLATFORM_PATH_H_

View File

@ -1,18 +0,0 @@
/************************************************************//**
*
* @file: platform_rng.h
* @author: Martin Fouilleul
* @date: 06/03/2020
* @revision:
*
*****************************************************************/
#ifndef __PLATFORM_RANDOM_H_
#define __PLATFORM_RANDOM_H_
#include"typedefs.h"
int RandomSeedFromDevice();
u32 RandomU32();
u64 RandomU64();
#endif //__PLATFORM_RANDOM_H_

View File

@ -1,161 +0,0 @@
/************************************************************//**
*
* @file: platform_socket.h
* @author: Martin Fouilleul
* @date: 22/03/2019
* @revision:
*
*****************************************************************/
#ifndef __PLATFORM_SOCKET_H_
#define __PLATFORM_SOCKET_H_
#include<sys/time.h> // timeval
#include"typedefs.h"
#ifdef __cplusplus
extern "C" {
#else
typedef struct timeval timeval;
#endif //__cplusplus
//----------------------------------------------------------------------------------
// Errors
//----------------------------------------------------------------------------------
//TODO(martin): extend these error codes
const int SOCK_ERR_OK = 0,
SOCK_ERR_UNKNOWN = -1,
SOCK_ERR_ACCESS = -2,
SOCK_ERR_MEM = -3,
SOCK_ERR_INTR = -4,
SOCK_ERR_USED = -5,
SOCK_ERR_BADF = -6,
SOCK_ERR_ABORT = -7,
SOCK_ERR_NBLOCK = -8;
int SocketGetLastError();
const char* SocketGetLastErrorMessage();
//----------------------------------------------------------------------------------
// Addresses
//----------------------------------------------------------------------------------
//NOTE(martin): net_ip and net_port are stored in network byte order
// host_ip and host_port are stored in host byte order
typedef uint32 net_ip;
typedef uint16 net_port;
typedef uint32 host_ip;
typedef uint16 host_port;
typedef struct
{
net_ip ip;
net_port port;
} socket_address;
//NOTE(martin): these are in host byte order !
const host_ip SOCK_IP_LOOPBACK = 0x7f000001;
const host_ip SOCK_IP_ANY = 0;
const host_port SOCK_PORT_ANY = 0;
net_ip StringToNetIP(const char* addr);
const char* NetIPToString(net_ip ip);
host_ip StringToHostIP(const char* addr);
const char* HostIPToString(host_ip ip);
net_ip HostToNetIP(host_ip ip);
net_port HostToNetPort(host_port port);
host_ip NetToHostIP(net_ip ip);
host_port NetToHostPort(net_port port);
int SocketGetIFAddresses(int* count, net_ip* ips);
net_ip SocketGetDefaultExternalIP();
//----------------------------------------------------------------------------------
// Socket API
//----------------------------------------------------------------------------------
typedef struct platform_socket platform_socket;
typedef enum { SOCK_UDP, SOCK_TCP } socket_transport;
const int SOCK_MSG_OOB = 0x01,
SOCK_MSG_PEEK = 0x02,
SOCK_MSG_DONTROUTE = 0x04,
SOCK_MSG_WAITALL = 0x40;
platform_socket* SocketOpen(socket_transport transport);
int SocketClose(platform_socket* socket);
int SocketBind(platform_socket* socket, socket_address* addr);
int SocketListen(platform_socket* socket, int backlog);
platform_socket* SocketAccept(platform_socket* socket, socket_address* from);
int SocketConnect(platform_socket* socket, socket_address* addr);
int64 SocketReceive(platform_socket* socket, void* buffer, uint64 size, int flags);
int64 SocketReceiveFrom(platform_socket* socket, void* buffer, uint64 size, int flags, socket_address* from);
int64 SocketSend(platform_socket* socket, void* buffer, uint64 size, int flags);
int64 SocketSendTo(platform_socket* socket, void* buffer, uint64 size, int flags, socket_address* to);
int SocketGetAddress(platform_socket* socket, socket_address* addr);
//----------------------------------------------------------------------------------
// Multiplexing
//----------------------------------------------------------------------------------
const uint8 SOCK_ACTIVITY_IN = 1<<0,
SOCK_ACTIVITY_OUT = 1<<2,
SOCK_ACTIVITY_ERR = 1<<3;
typedef struct
{
platform_socket* sock;
uint8 watch;
uint8 set;
} socket_activity;
int SocketSelect(uint32 count, socket_activity* set, double timeout);
//----------------------------------------------------------------------------------
// Socket Options
//----------------------------------------------------------------------------------
int SocketSetReceiveTimeout(platform_socket* socket, timeval* tv);
int SocketSetSendTimeout(platform_socket* socket, timeval* tv);
int SocketSetBroadcast(platform_socket* sock, bool enable);
int SocketSetReuseAddress(platform_socket* sock, bool enable);
int SocketSetReusePort(platform_socket* sock, bool enable);
int SocketSetReceiveTimestamping(platform_socket* socket, bool enable);
//----------------------------------------------------------------------------------
// Multicast
//----------------------------------------------------------------------------------
int SocketSetMulticastLoop(platform_socket* sock, bool enable);
int SocketJoinMulticastGroup(platform_socket* socket, host_ip group, host_ip interface);
int SocketLeaveMulticastGroup(platform_socket* socket, host_ip group, host_ip interface);
//----------------------------------------------------------------------------------
//Ancillary data API
//----------------------------------------------------------------------------------
typedef struct
{
u64 messageBufferSize;
char* messageBuffer;
u64 controlBufferSize;
char* controlBuffer;
} socket_msg;
int SocketReceiveMessage(platform_socket* socket, socket_msg* msg, socket_address* from);
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__PLATFORM_SOCKET_H_

View File

@ -9,6 +9,7 @@
#ifndef __PLATFORM_THREAD_H_
#define __PLATFORM_THREAD_H_
#include"util/strings.h"
#ifdef __cplusplus
#include<atomic>
@ -27,59 +28,64 @@ extern "C" {
enum
{
MP_THREAD_NAME_MAX_SIZE = 64, // including null terminator
OC_THREAD_NAME_MAX_SIZE = 64, // including null terminator
};
typedef struct mp_thread mp_thread;
typedef struct oc_thread oc_thread;
typedef i32 (*mp_thread_start_function)(void* userPointer);
typedef i32 (*oc_thread_start_function)(void* userPointer);
MP_API mp_thread* mp_thread_create(mp_thread_start_function start, void* userPointer);
MP_API mp_thread* mp_thread_create_with_name(mp_thread_start_function start, void* userPointer, const char* name);
MP_API const char* mp_thread_get_name(mp_thread* thread);
MP_API u64 mp_thread_unique_id(mp_thread* thread);
MP_API u64 mp_thread_self_id();
MP_API int mp_thread_signal(mp_thread* thread, int sig);
MP_API int mp_thread_join(mp_thread* thread, i64* exitCode);
MP_API int mp_thread_detach(mp_thread* thread);
ORCA_API oc_thread* oc_thread_create(oc_thread_start_function start, void* userPointer);
ORCA_API oc_thread* oc_thread_create_with_name(oc_thread_start_function start, void* userPointer, oc_str8 name);
ORCA_API oc_str8 oc_thread_get_name(oc_thread* thread);
ORCA_API u64 oc_thread_unique_id(oc_thread* thread);
ORCA_API u64 oc_thread_self_id();
ORCA_API int oc_thread_signal(oc_thread* thread, int sig);
ORCA_API int oc_thread_join(oc_thread* thread, i64* exitCode);
ORCA_API int oc_thread_detach(oc_thread* thread);
//---------------------------------------------------------------
// Platform Mutex API
//---------------------------------------------------------------
typedef struct mp_mutex mp_mutex;
typedef struct oc_mutex oc_mutex;
MP_API mp_mutex* mp_mutex_create();
MP_API int mp_mutex_destroy(mp_mutex* mutex);
MP_API int mp_mutex_lock(mp_mutex* mutex);
MP_API int mp_mutex_unlock(mp_mutex* mutex);
ORCA_API oc_mutex* oc_mutex_create();
ORCA_API int oc_mutex_destroy(oc_mutex* mutex);
ORCA_API int oc_mutex_lock(oc_mutex* mutex);
ORCA_API int oc_mutex_unlock(oc_mutex* mutex);
//---------------------------------------------------------------
// Lightweight ticket mutex API
//---------------------------------------------------------------
typedef struct mp_ticket_spin_mutex
typedef struct oc_ticket
{
volatile _Atomic(u64) nextTicket;
volatile _Atomic(u64) serving;
} mp_ticket_spin_mutex;
} oc_ticket;
MP_API void mp_ticket_spin_mutex_init(mp_ticket_spin_mutex* mutex);
MP_API void mp_ticket_spin_mutex_lock(mp_ticket_spin_mutex* mutex);
MP_API void mp_ticket_spin_mutex_unlock(mp_ticket_spin_mutex* mutex);
ORCA_API void oc_ticket_init(oc_ticket* mutex);
ORCA_API void oc_ticket_lock(oc_ticket* mutex);
ORCA_API void oc_ticket_unlock(oc_ticket* mutex);
//---------------------------------------------------------------
// Platform condition variable API
//---------------------------------------------------------------
typedef struct mp_condition mp_condition;
typedef struct oc_condition oc_condition;
MP_API mp_condition* mp_condition_create();
MP_API int mp_condition_destroy(mp_condition* cond);
MP_API int mp_condition_wait(mp_condition* cond, mp_mutex* mutex);
MP_API int mp_condition_timedwait(mp_condition* cond, mp_mutex* mutex, f64 seconds);
MP_API int mp_condition_signal(mp_condition* cond);
MP_API int mp_condition_broadcast(mp_condition* cond);
ORCA_API oc_condition* oc_condition_create();
ORCA_API int oc_condition_destroy(oc_condition* cond);
ORCA_API int oc_condition_wait(oc_condition* cond, oc_mutex* mutex);
ORCA_API int oc_condition_timedwait(oc_condition* cond, oc_mutex* mutex, f64 seconds);
ORCA_API int oc_condition_signal(oc_condition* cond);
ORCA_API int oc_condition_broadcast(oc_condition* cond);
//---------------------------------------------------------------
// Putting threads to sleep
//---------------------------------------------------------------
ORCA_API void oc_sleep_nano(u64 nanoseconds); // sleep for a given number of nanoseconds
#ifdef __cplusplus
} // extern "C"

View File

@ -15,116 +15,116 @@
#include"platform_io_common.c"
#include"platform_io_internal.c"
io_file_desc io_file_desc_nil()
oc_file_desc oc_file_desc_nil()
{
return(-1);
}
bool io_file_desc_is_nil(io_file_desc fd)
bool oc_file_desc_is_nil(oc_file_desc fd)
{
return(fd < 0);
}
io_error io_raw_last_error()
oc_io_error oc_io_raw_last_error()
{
io_error error = IO_OK;
oc_io_error error = OC_IO_OK;
switch(errno)
{
case EPERM:
case EACCES:
case EROFS:
error = IO_ERR_PERM;
error = OC_IO_ERR_PERM;
break;
case ENOENT:
error = IO_ERR_NO_ENTRY;
error = OC_IO_ERR_NO_ENTRY;
break;
case EINTR:
error = IO_ERR_INTERRUPT;
error = OC_IO_ERR_INTERRUPT;
break;
case EIO:
error = IO_ERR_PHYSICAL;
error = OC_IO_ERR_PHYSICAL;
break;
case ENXIO:
error = IO_ERR_NO_DEVICE;
error = OC_IO_ERR_NO_DEVICE;
break;
case EBADF:
// this should only happen when user tries to write/read to a file handle
// opened with readonly/writeonly access
error = IO_ERR_PERM;
error = OC_IO_ERR_PERM;
break;
case ENOMEM:
error = IO_ERR_MEM;
error = OC_IO_ERR_MEM;
break;
case EFAULT:
case EINVAL:
case EDOM:
error = IO_ERR_ARG;
error = OC_IO_ERR_ARG;
break;
case EBUSY:
case EAGAIN:
error = IO_ERR_NOT_READY;
error = OC_IO_ERR_NOT_READY;
break;
case EEXIST:
error = IO_ERR_EXISTS;
error = OC_IO_ERR_EXISTS;
break;
case ENOTDIR:
error = IO_ERR_NOT_DIR;
error = OC_IO_ERR_NOT_DIR;
break;
case EISDIR:
error = IO_ERR_DIR;
error = OC_IO_ERR_DIR;
break;
case ENFILE:
case EMFILE:
error = IO_ERR_MAX_FILES;
error = OC_IO_ERR_MAX_FILES;
break;
case EFBIG:
error = IO_ERR_FILE_SIZE;
error = OC_IO_ERR_FILE_SIZE;
break;
case ENOSPC:
case EDQUOT:
error = IO_ERR_SPACE;
error = OC_IO_ERR_SPACE;
break;
case ELOOP:
error = IO_ERR_MAX_LINKS;
error = OC_IO_ERR_MAX_LINKS;
break;
case ENAMETOOLONG:
error = IO_ERR_PATH_LENGTH;
error = OC_IO_ERR_PATH_LENGTH;
break;
case EOVERFLOW:
error = IO_ERR_OVERFLOW;
error = OC_IO_ERR_OVERFLOW;
break;
default:
error = IO_ERR_UNKNOWN;
error = OC_IO_ERR_UNKNOWN;
break;
}
return(error);
}
int io_convert_access_rights(file_access_rights rights)
static int oc_io_convert_access_rights(oc_file_access rights)
{
int oflags = 0;
if(rights & FILE_ACCESS_READ)
if(rights & OC_FILE_ACCESS_READ)
{
if(rights & FILE_ACCESS_WRITE)
if(rights & OC_FILE_ACCESS_WRITE)
{
oflags = O_RDWR;
}
@ -133,41 +133,41 @@ int io_convert_access_rights(file_access_rights rights)
oflags = O_RDONLY;
}
}
else if(rights & FILE_ACCESS_WRITE)
else if(rights & OC_FILE_ACCESS_WRITE)
{
oflags = O_WRONLY;
}
return(oflags);
}
int io_convert_open_flags(file_open_flags flags)
static int oc_io_convert_open_flags(oc_file_open_flags flags)
{
int oflags = 0;
if(flags & FILE_OPEN_TRUNCATE)
if(flags & OC_FILE_OPEN_TRUNCATE)
{
oflags |= O_TRUNC;
}
if(flags & FILE_OPEN_APPEND)
if(flags & OC_FILE_OPEN_APPEND)
{
oflags |= O_APPEND;
}
if(flags & FILE_OPEN_CREATE)
if(flags & OC_FILE_OPEN_CREATE)
{
oflags |= O_CREAT;
}
if(flags & FILE_OPEN_NO_FOLLOW)
if(flags & OC_FILE_OPEN_NO_FOLLOW)
{
oflags |= O_NOFOLLOW;
}
if(flags & FILE_OPEN_SYMLINK)
if(flags & OC_FILE_OPEN_SYMLINK)
{
oflags |= O_SYMLINK;
}
return(oflags);
}
int io_update_dir_flags_at(int dirFd, char* path, int flags)
static int oc_io_update_dir_flags_at(int dirFd, char* path, int flags)
{
struct stat s;
if(!fstatat(dirFd, path, &s, AT_SYMLINK_NOFOLLOW))
@ -188,10 +188,10 @@ int io_update_dir_flags_at(int dirFd, char* path, int flags)
return(flags);
}
io_file_desc io_raw_open_at(io_file_desc dirFd, str8 path, file_access_rights accessRights, file_open_flags openFlags)
oc_file_desc oc_io_raw_open_at(oc_file_desc dirFd, oc_str8 path, oc_file_access accessRights, oc_file_open_flags openFlags)
{
int flags = io_convert_access_rights(accessRights);
flags |= io_convert_open_flags(openFlags);
int flags = oc_io_convert_access_rights(accessRights);
flags |= oc_io_convert_open_flags(openFlags);
mode_t mode = S_IRUSR
| S_IWUSR
@ -200,18 +200,18 @@ io_file_desc io_raw_open_at(io_file_desc dirFd, str8 path, file_access_rights ac
| S_IROTH
| S_IWOTH;
mem_arena_scope scratch = mem_scratch_begin();
oc_arena_scope scratch = oc_scratch_begin();
io_file_desc fd = -1;
oc_file_desc fd = -1;
if(dirFd >= 0)
{
if(path.len && path.ptr[0] == '/')
{
//NOTE: if path is absolute, change for a relative one, otherwise openat ignores fd.
str8_list list = {0};
str8_list_push(scratch.arena, &list, STR8("."));
str8_list_push(scratch.arena, &list, path);
path = str8_list_join(scratch.arena, list);
oc_str8_list list = {0};
oc_str8_list_push(scratch.arena, &list, OC_STR8("."));
oc_str8_list_push(scratch.arena, &list, path);
path = oc_str8_list_join(scratch.arena, list);
}
}
else
@ -219,98 +219,98 @@ io_file_desc io_raw_open_at(io_file_desc dirFd, str8 path, file_access_rights ac
dirFd = AT_FDCWD;
}
char* pathCStr = str8_to_cstring(scratch.arena, path);
char* pathCStr = oc_str8_to_cstring(scratch.arena, path);
flags = io_update_dir_flags_at(dirFd, pathCStr, flags);
flags = oc_io_update_dir_flags_at(dirFd, pathCStr, flags);
fd = openat(dirFd, pathCStr, flags, mode);
mem_scratch_end(scratch);
oc_scratch_end(scratch);
return(fd);
}
void io_raw_close(io_file_desc fd)
void oc_io_raw_close(oc_file_desc fd)
{
close(fd);
}
file_perm io_convert_perm_from_stat(u16 mode)
static oc_file_perm oc_io_convert_perm_from_stat(u16 mode)
{
file_perm perm = mode & 07777;
oc_file_perm perm = mode & 07777;
return(perm);
}
file_type io_convert_type_from_stat(u16 mode)
static oc_file_type oc_io_convert_type_from_stat(u16 mode)
{
file_type type;
oc_file_type type;
switch(mode & S_IFMT)
{
case S_IFIFO:
type = MP_FILE_FIFO;
type = OC_FILE_FIFO;
break;
case S_IFCHR:
type = MP_FILE_CHARACTER;
type = OC_FILE_CHARACTER;
break;
case S_IFDIR:
type = MP_FILE_DIRECTORY;
type = OC_FILE_DIRECTORY;
break;
case S_IFBLK:
type = MP_FILE_BLOCK;
type = OC_FILE_BLOCK;
break;
case S_IFREG:
type = MP_FILE_REGULAR;
type = OC_FILE_REGULAR;
break;
case S_IFLNK:
type = MP_FILE_SYMLINK;
type = OC_FILE_SYMLINK;
break;
case S_IFSOCK:
type = MP_FILE_SOCKET;
type = OC_FILE_SOCKET;
break;
default:
type = MP_FILE_UNKNOWN;
type = OC_FILE_UNKNOWN;
break;
}
return(type);
}
io_error io_raw_fstat(io_file_desc fd, file_status* status)
oc_io_error oc_io_raw_fstat(oc_file_desc fd, oc_file_status* status)
{
io_error error = IO_OK;
oc_io_error error = OC_IO_OK;
struct stat s;
if(fstat(fd, &s))
{
error = io_raw_last_error();
error = oc_io_raw_last_error();
}
else
{
status->uid = s.st_ino;
status->perm = io_convert_perm_from_stat(s.st_mode);
status->type = io_convert_type_from_stat(s.st_mode);
status->perm = oc_io_convert_perm_from_stat(s.st_mode);
status->type = oc_io_convert_type_from_stat(s.st_mode);
status->size = s.st_size;
//TODO: times
}
return(error);
}
io_error io_raw_fstat_at(io_file_desc dirFd, str8 path, file_open_flags flags, file_status* status)
oc_io_error oc_io_raw_fstat_at(oc_file_desc dirFd, oc_str8 path, oc_file_open_flags flags, oc_file_status* status)
{
mem_arena_scope scratch = mem_scratch_begin();
oc_arena_scope scratch = oc_scratch_begin();
if(dirFd >= 0)
{
if(path.len && path.ptr[0] == '/')
{
str8_list list = {0};
str8_list_push(scratch.arena, &list, STR8("."));
str8_list_push(scratch.arena, &list, path);
path = str8_list_join(scratch.arena, list);
oc_str8_list list = {0};
oc_str8_list_push(scratch.arena, &list, OC_STR8("."));
oc_str8_list_push(scratch.arena, &list, path);
path = oc_str8_list_join(scratch.arena, list);
}
}
else
@ -318,40 +318,40 @@ io_error io_raw_fstat_at(io_file_desc dirFd, str8 path, file_open_flags flags, f
dirFd = AT_FDCWD;
}
char* pathCStr = str8_to_cstring(scratch.arena, path);
char* pathCStr = oc_str8_to_cstring(scratch.arena, path);
int statFlag = (flags & FILE_OPEN_SYMLINK)? AT_SYMLINK_NOFOLLOW : 0;
io_error error = IO_OK;
int statFlag = (flags & OC_FILE_OPEN_SYMLINK)? AT_SYMLINK_NOFOLLOW : 0;
oc_io_error error = OC_IO_OK;
struct stat s;
if(fstatat(dirFd, pathCStr, &s, statFlag))
{
error = io_raw_last_error();
error = oc_io_raw_last_error();
}
else
{
status->uid = s.st_ino;
status->perm = io_convert_perm_from_stat(s.st_mode);
status->type = io_convert_type_from_stat(s.st_mode);
status->perm = oc_io_convert_perm_from_stat(s.st_mode);
status->type = oc_io_convert_type_from_stat(s.st_mode);
status->size = s.st_size;
//TODO: times
}
mem_scratch_end(scratch);
oc_scratch_end(scratch);
return(error);
}
io_raw_read_link_result io_raw_read_link_at(mem_arena* arena, io_file_desc dirFd, str8 path)
oc_io_raw_read_link_result oc_io_raw_read_link_at(oc_arena* arena, oc_file_desc dirFd, oc_str8 path)
{
mem_arena_scope scratch = mem_scratch_begin_next(arena);
oc_arena_scope scratch = oc_scratch_begin_next(arena);
if(dirFd >= 0)
{
if(path.len && path.ptr[0] == '/')
{
str8_list list = {0};
str8_list_push(scratch.arena, &list, STR8("."));
str8_list_push(scratch.arena, &list, path);
path = str8_list_join(scratch.arena, list);
oc_str8_list list = {0};
oc_str8_list_push(scratch.arena, &list, OC_STR8("."));
oc_str8_list_push(scratch.arena, &list, path);
path = oc_str8_list_join(scratch.arena, list);
}
}
else
@ -359,9 +359,9 @@ io_raw_read_link_result io_raw_read_link_at(mem_arena* arena, io_file_desc dirFd
dirFd = AT_FDCWD;
}
char* pathCStr = str8_to_cstring(scratch.arena, path);
char* pathCStr = oc_str8_to_cstring(scratch.arena, path);
io_raw_read_link_result result = {0};
oc_io_raw_read_link_result result = {0};
char buffer[PATH_MAX];
u64 bufferSize = PATH_MAX;
@ -369,31 +369,31 @@ io_raw_read_link_result io_raw_read_link_at(mem_arena* arena, io_file_desc dirFd
if(r<0)
{
result.error = io_raw_last_error();
result.error = oc_io_raw_last_error();
}
else
{
result.target.len = r;
result.target.ptr = mem_arena_alloc_array(arena, char, result.target.len);
result.target.ptr = oc_arena_push_array(arena, char, result.target.len);
memcpy(result.target.ptr, buffer, result.target.len);
}
mem_scratch_end(scratch);
oc_scratch_end(scratch);
return(result);
}
bool io_raw_file_exists_at(io_file_desc dirFd, str8 path, file_open_flags openFlags)
bool oc_io_raw_file_exists_at(oc_file_desc dirFd, oc_str8 path, oc_file_open_flags openFlags)
{
mem_arena_scope scratch = mem_scratch_begin();
oc_arena_scope scratch = oc_scratch_begin();
if(dirFd >= 0)
{
if(path.len && path.ptr[0] == '/')
{
str8_list list = {0};
str8_list_push(scratch.arena, &list, STR8("."));
str8_list_push(scratch.arena, &list, path);
path = str8_list_join(scratch.arena, list);
oc_str8_list list = {0};
oc_str8_list_push(scratch.arena, &list, OC_STR8("."));
oc_str8_list_push(scratch.arena, &list, path);
path = oc_str8_list_join(scratch.arena, list);
}
}
else
@ -401,48 +401,48 @@ bool io_raw_file_exists_at(io_file_desc dirFd, str8 path, file_open_flags openFl
dirFd = AT_FDCWD;
}
char* pathCStr = str8_to_cstring(scratch.arena, path);
char* pathCStr = oc_str8_to_cstring(scratch.arena, path);
int flags = (openFlags & FILE_OPEN_SYMLINK)? AT_SYMLINK_NOFOLLOW : 0;
int flags = (openFlags & OC_FILE_OPEN_SYMLINK)? AT_SYMLINK_NOFOLLOW : 0;
int r = faccessat(dirFd, pathCStr, F_OK, flags);
bool result = (r == 0);
mem_scratch_end(scratch);
oc_scratch_end(scratch);
return(result);
}
io_cmp io_close(file_slot* slot, io_req* req, file_table* table)
oc_io_cmp oc_io_close(oc_file_slot* slot, oc_io_req* req, oc_file_table* table)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
if(slot->fd >= 0)
{
close(slot->fd);
}
file_slot_recycle(table, slot);
oc_file_slot_recycle(table, slot);
return(cmp);
}
io_cmp io_fstat(file_slot* slot, io_req* req)
oc_io_cmp oc_io_fstat(oc_file_slot* slot, oc_io_req* req)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
if(req->size < sizeof(file_status))
if(req->size < sizeof(oc_file_status))
{
cmp.error = IO_ERR_ARG;
cmp.error = OC_IO_ERR_ARG;
}
else
{
struct stat s;
if(fstat(slot->fd, &s))
{
slot->error = io_raw_last_error();
slot->error = oc_io_raw_last_error();
cmp.error = slot->error;
}
else
{
file_status* status = (file_status*)req->buffer;
status->perm = io_convert_perm_from_stat(s.st_mode);
status->type = io_convert_type_from_stat(s.st_mode);
oc_file_status* status = (oc_file_status*)req->buffer;
status->perm = oc_io_convert_perm_from_stat(s.st_mode);
status->type = oc_io_convert_type_from_stat(s.st_mode);
status->size = s.st_size;
//TODO: times
}
@ -450,44 +450,44 @@ io_cmp io_fstat(file_slot* slot, io_req* req)
return(cmp);
}
io_cmp io_seek(file_slot* slot, io_req* req)
oc_io_cmp oc_io_seek(oc_file_slot* slot, oc_io_req* req)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
int whence;
switch(req->whence)
{
case FILE_SEEK_CURRENT:
case OC_FILE_SEEK_CURRENT:
whence = SEEK_CUR;
break;
case FILE_SEEK_SET:
case OC_FILE_SEEK_SET:
whence = SEEK_SET;
break;
case FILE_SEEK_END:
case OC_FILE_SEEK_END:
whence = SEEK_END;
}
cmp.result = lseek(slot->fd, req->offset, whence);
if(cmp.result < 0)
{
slot->error = io_raw_last_error();
slot->error = oc_io_raw_last_error();
cmp.error = slot->error;
}
return(cmp);
}
io_cmp io_read(file_slot* slot, io_req* req)
oc_io_cmp oc_io_read(oc_file_slot* slot, oc_io_req* req)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
cmp.result = read(slot->fd, req->buffer, req->size);
if(cmp.result < 0)
{
slot->error = io_raw_last_error();
slot->error = oc_io_raw_last_error();
cmp.result = 0;
cmp.error = slot->error;
}
@ -495,15 +495,15 @@ io_cmp io_read(file_slot* slot, io_req* req)
return(cmp);
}
io_cmp io_write(file_slot* slot, io_req* req)
oc_io_cmp oc_io_write(oc_file_slot* slot, oc_io_req* req)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
cmp.result = write(slot->fd, req->buffer, req->size);
if(cmp.result < 0)
{
slot->error = io_raw_last_error();
slot->error = oc_io_raw_last_error();
cmp.result = 0;
cmp.error = slot->error;
}
@ -511,66 +511,66 @@ io_cmp io_write(file_slot* slot, io_req* req)
return(cmp);
}
io_cmp io_get_error(file_slot* slot, io_req* req)
oc_io_cmp oc_io_get_error(oc_file_slot* slot, oc_io_req* req)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
cmp.result = slot->error;
return(cmp);
}
io_cmp io_wait_single_req_with_table(io_req* req, file_table* table)
oc_io_cmp oc_io_wait_single_req_with_table(oc_io_req* req, oc_file_table* table)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
file_slot* slot = file_slot_from_handle(table, req->handle);
oc_file_slot* slot = oc_file_slot_from_handle(table, req->handle);
if(!slot)
{
if(req->op != IO_OP_OPEN_AT)
if(req->op != OC_IO_OPEN_AT)
{
cmp.error = IO_ERR_HANDLE;
cmp.error = OC_IO_ERR_HANDLE;
}
}
else if( slot->fatal
&& req->op != IO_OP_CLOSE
&& req->op != IO_OP_ERROR)
&& req->op != OC_IO_CLOSE
&& req->op != OC_OC_IO_ERROR)
{
cmp.error = IO_ERR_PREV;
cmp.error = OC_IO_ERR_PREV;
}
if(cmp.error == IO_OK)
if(cmp.error == OC_IO_OK)
{
switch(req->op)
{
case IO_OP_OPEN_AT:
cmp = io_open_at(slot, req, table);
case OC_IO_OPEN_AT:
cmp = oc_io_open_at(slot, req, table);
break;
case IO_OP_FSTAT:
cmp = io_fstat(slot, req);
case OC_IO_FSTAT:
cmp = oc_io_fstat(slot, req);
break;
case IO_OP_CLOSE:
cmp = io_close(slot, req, table);
case OC_IO_CLOSE:
cmp = oc_io_close(slot, req, table);
break;
case IO_OP_READ:
cmp = io_read(slot, req);
case OC_IO_READ:
cmp = oc_io_read(slot, req);
break;
case IO_OP_WRITE:
cmp = io_write(slot, req);
case OC_IO_WRITE:
cmp = oc_io_write(slot, req);
break;
case IO_OP_SEEK:
cmp = io_seek(slot, req);
case OC_IO_SEEK:
cmp = oc_io_seek(slot, req);
break;
case IO_OP_ERROR:
cmp = io_get_error(slot, req);
case OC_OC_IO_ERROR:
cmp = oc_io_get_error(slot, req);
break;
default:
cmp.error = IO_ERR_OP;
cmp.error = OC_IO_ERR_OP;
break;
}
}

View File

@ -1,511 +0,0 @@
/************************************************************//**
*
* @file: posix_socket.c
* @author: Martin Fouilleul
* @date: 22/03/2019
* @revision:
*
*****************************************************************/
#include<sys/socket.h> // socket()
#include<netinet/ip.h> // socaddr_in
#include<arpa/inet.h> // inet_addr()
#include<ifaddrs.h> // getifaddrs() / freeifaddrs()
#include<unistd.h> // close()
#include<string.h> // strerror()
#include<errno.h> // errno
#include<stdlib.h> // malloc()/free()
#include"platform_socket.h"
#include"platform_debug.h"
typedef struct in_addr in_addr;
typedef struct sockaddr_in sockaddr_in;
typedef struct sockaddr sockaddr;
typedef struct msghdr msghdr;
typedef struct cmsghdr cmsghdr;
typedef struct ip_mreq ip_mreq;
typedef struct iovec iovec;
net_ip StringToNetIP(const char* addr)
{
return(inet_addr(addr));
}
const char* NetIPToString(net_ip ip)
{
in_addr in;
in.s_addr = ip;
return(inet_ntoa(in));
}
host_ip StringToHostIP(const char* addr)
{
return(NetToHostIP(StringToNetIP(addr)));
}
const char* HostIPToString(host_ip ip)
{
return(NetIPToString(HostToNetIP(ip)));
}
net_ip HostToNetIP(uint32 ip)
{
return(htonl(ip));
}
net_port HostToNetPort(uint16 port)
{
return(htons(port));
}
uint32 NetToHostIP(net_ip ip)
{
return(ntohl(ip));
}
uint16 NetToHostPort(net_port port)
{
return(ntohs(port));
}
static int PlatformToSocketFlags(int flags)
{
int sflags = 0;
if(flags & SOCK_MSG_OOB)
{
sflags |= MSG_OOB;
}
if(flags & SOCK_MSG_PEEK)
{
sflags |= MSG_PEEK;
}
if(flags & SOCK_MSG_DONTROUTE)
{
sflags |= MSG_DONTROUTE;
}
if(flags & SOCK_MSG_WAITALL)
{
sflags |= MSG_WAITALL;
}
return(sflags);
}
static int ErrnoToSocketError(int err)
{
//TODO(martin): extend these error codes
switch(err)
{
case 0: return(SOCK_ERR_OK);
case EACCES: return(SOCK_ERR_ACCESS);
case ENOBUFS:
case ENOMEM: return(SOCK_ERR_MEM);
case EINTR: return(SOCK_ERR_INTR);
case EADDRINUSE: return(SOCK_ERR_USED);
case EBADF: return(SOCK_ERR_BADF);
case ECONNABORTED: return(SOCK_ERR_ABORT);
case EWOULDBLOCK:
#if EAGAIN != EWOULDBLOCK
case EAGAIN:
#endif
return(SOCK_ERR_NBLOCK);
default:
return(SOCK_ERR_UNKNOWN);
}
}
int SocketGetLastError()
{
return(ErrnoToSocketError(errno));
}
const char* SocketGetLastErrorMessage()
{
return(strerror(errno));
}
struct platform_socket
{
int sd;
};
platform_socket* SocketOpen(socket_transport transport)
{
int sd = 0;
switch(transport)
{
case SOCK_UDP:
sd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
break;
case SOCK_TCP:
sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
break;
}
if(!sd)
{
return(0);
}
platform_socket* sock = (platform_socket*)malloc(sizeof(platform_socket));
if(!sock)
{
close(sd);
return(0);
}
sock->sd = sd;
return(sock);
}
int SocketClose(platform_socket* sock)
{
if(!sock)
{
return(-1);
}
int res = close(sock->sd);
free(sock);
return(res);
}
int SocketBind(platform_socket* sock, socket_address* addr)
{
sockaddr_in saddr;
saddr.sin_addr.s_addr = addr->ip;
saddr.sin_port = addr->port;
saddr.sin_family = AF_INET;
return(bind(sock->sd, (sockaddr*)&saddr, sizeof(saddr)));
}
int SocketListen(platform_socket* sock, int backlog)
{
return(listen(sock->sd, backlog));
}
platform_socket* SocketAccept(platform_socket* sock, socket_address* from)
{
sockaddr_in saddr;
socklen_t saddrSize = sizeof(saddr);
int sd = accept(sock->sd, (sockaddr*)&saddr, &saddrSize);
from->ip = saddr.sin_addr.s_addr;
from->port = saddr.sin_port;
if(sd <= 0)
{
return(0);
}
else
{
platform_socket* client = (platform_socket*)malloc(sizeof(platform_socket));
if(!client)
{
close(sd);
return(0);
}
client->sd = sd;
return(client);
}
}
int SocketConnect(platform_socket* sock, socket_address* addr)
{
sockaddr_in saddr;
saddr.sin_addr.s_addr = addr->ip;
saddr.sin_port = addr->port;
saddr.sin_family = AF_INET;
return(connect(sock->sd, (sockaddr*)&saddr, sizeof(saddr)));
}
int64 SocketReceive(platform_socket* sock, void* buffer, uint64 size, int flags)
{
return(recv(sock->sd, buffer, size, PlatformToSocketFlags(flags)));
}
int64 SocketReceiveFrom(platform_socket* sock, void* buffer, uint64 size, int flags, socket_address* from)
{
sockaddr_in saddr;
socklen_t saddrSize = sizeof(saddr);
int res = recvfrom(sock->sd, buffer, size, PlatformToSocketFlags(flags), (sockaddr*)&saddr, &saddrSize);
from->ip = saddr.sin_addr.s_addr;
from->port = saddr.sin_port;
return(res);
}
int64 SocketSend(platform_socket* sock, void* buffer, uint64 size, int flags)
{
return(send(sock->sd, buffer, size, PlatformToSocketFlags(flags)));
}
int64 SocketSendTo(platform_socket* sock, void* buffer, uint64 size, int flags, socket_address* to)
{
sockaddr_in saddr;
saddr.sin_addr.s_addr = to->ip;
saddr.sin_port = to->port;
saddr.sin_family = AF_INET;
return(sendto(sock->sd, buffer, size, PlatformToSocketFlags(flags), (sockaddr*)&saddr, sizeof(saddr)));
}
int SocketSetReceiveTimeout(platform_socket* sock, timeval* tv)
{
DEBUG_ASSERT(sock);
DEBUG_ASSERT(sock->sd);
return(setsockopt(sock->sd, SOL_SOCKET, SO_RCVTIMEO, tv, sizeof(timeval)));
}
int SocketSetSendTimeout(platform_socket* sock, timeval* tv)
{
DEBUG_ASSERT(sock);
DEBUG_ASSERT(sock->sd);
return(setsockopt(sock->sd, SOL_SOCKET, SO_SNDTIMEO, tv, sizeof(timeval)));
}
int SocketSetReceiveTimestamping(platform_socket* socket, bool enable)
{
int opt = enable ? 1 : 0;
socklen_t len = sizeof(int);
return(setsockopt(socket->sd, SOL_SOCKET, SO_TIMESTAMP, &enable, len));
}
int SocketSetBroadcast(platform_socket* sock, bool enable)
{
DEBUG_ASSERT(sock);
DEBUG_ASSERT(sock->sd);
int opt = enable ? 1 : 0;
return(setsockopt(sock->sd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(int)));
}
int SocketSelect(uint32 count, socket_activity* set, double timeout)
{
fd_set fdInSet;
fd_set fdOutSet;
fd_set fdErrSet;
FD_ZERO(&fdInSet);
FD_ZERO(&fdOutSet);
FD_ZERO(&fdErrSet);
int maxSd = -1;
for(int i=0; i<count; i++)
{
socket_activity* item = &(set[i]);
if(item->sock)
{
item->set = 0;
if(item->watch & SOCK_ACTIVITY_IN)
{
FD_SET(item->sock->sd, &fdInSet);
}
if(item->watch & SOCK_ACTIVITY_OUT)
{
FD_SET(item->sock->sd, &fdOutSet);
}
if(item->watch & SOCK_ACTIVITY_ERR)
{
FD_SET(item->sock->sd, &fdErrSet);
}
if(item->watch && (item->sock->sd > maxSd))
{
maxSd = item->sock->sd;
}
}
}
if(maxSd <= 0)
{
return(0);
}
timeval tv;
tv.tv_sec = (time_t)timeout;
tv.tv_usec = (suseconds_t)((timeout - tv.tv_sec)*1000000);
timeval* ptv = timeout >= 0 ? &tv : 0;
int activity = select(maxSd+1, &fdInSet, &fdOutSet, &fdErrSet, ptv);
if(activity < 0)
{
return(-1);
}
int processed = 0;
for(int i=0; i<count; i++)
{
if(processed >= activity)
{
break;
}
socket_activity* item = &(set[i]);
if(item->sock)
{
if(FD_ISSET(item->sock->sd, &fdInSet))
{
item->set |= SOCK_ACTIVITY_IN;
}
if(FD_ISSET(item->sock->sd, &fdOutSet))
{
item->set |= SOCK_ACTIVITY_OUT;
}
if(FD_ISSET(item->sock->sd, &fdErrSet))
{
item->set |= SOCK_ACTIVITY_ERR;
}
if(item->set)
{
processed++;
}
}
}
return(activity);
}
int SocketGetAddress(platform_socket* sock, socket_address* addr)
{
sockaddr_in saddr;
socklen_t sockLen = sizeof(saddr);
if(getsockname(sock->sd, (sockaddr*)&saddr, &sockLen))
{
return(-1);
}
addr->ip = saddr.sin_addr.s_addr;
addr->port = saddr.sin_port;
return(0);
}
int SocketGetIFAddresses(int* count, net_ip* ips)
{
struct ifaddrs* ifaList = 0;
if(getifaddrs(&ifaList))
{
return(-1);
}
int maxCount = *count;
int i = 0;
for(struct ifaddrs* ifa = ifaList; ifa != 0 ; ifa = ifa->ifa_next)
{
if(i >= maxCount)
{
freeifaddrs(ifaList);
*count = i;
return(-1);
}
if(ifa->ifa_addr->sa_family == AF_INET)
{
struct in_addr in = ((sockaddr_in*)ifa->ifa_addr)->sin_addr;
ips[i] = in.s_addr;
i++;
}
}
freeifaddrs(ifaList);
*count = i;
return(0);
}
int SocketSetReuseAddress(platform_socket* sock, bool enable)
{
int reuse = enable ? 1 : 0;
return(setsockopt(sock->sd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)));
}
int SocketSetReusePort(platform_socket* sock, bool enable)
{
int reuse = enable ? 1 : 0;
return(setsockopt(sock->sd, SOL_SOCKET, SO_REUSEPORT, (char*)&reuse, sizeof(reuse)));
}
int SocketSetMulticastLoop(platform_socket* sock, bool enable)
{
int on = enable ? 1 : 0;
return(setsockopt(sock->sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&on, sizeof(on)));
}
int SocketJoinMulticastGroup(platform_socket* sock, host_ip group, host_ip interface)
{
ip_mreq mreq;
mreq.imr_multiaddr.s_addr = HostToNetIP(group);
mreq.imr_interface.s_addr = HostToNetIP(interface);
return(setsockopt(sock->sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)));
}
int SocketLeaveMulticastGroup(platform_socket* sock, host_ip group, host_ip interface)
{
ip_mreq mreq;
mreq.imr_multiaddr.s_addr = HostToNetIP(group);
mreq.imr_interface.s_addr = HostToNetIP(interface);
return(setsockopt(sock->sd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&mreq, sizeof(mreq)));
}
net_ip SocketGetDefaultExternalIP()
{
//NOTE(martin): get the default local ip. This is a dumb way to do this
// 'cause I can't be bothered to think of a better way right now :(
socket_address addr = {.ip = StringToNetIP("8.8.8.8"),
.port = HostToNetPort(5001)};
platform_socket* sock = SocketOpen(SOCK_UDP);
if(!sock)
{
log_error("can't create socket");
return(0);
}
if(SocketConnect(sock, &addr) != 0)
{
log_error("can't connect socket: %s\n", SocketGetLastErrorMessage());
log_warning("try loopback interface\n");
addr.ip = HostToNetIP(SOCK_IP_LOOPBACK);
if(SocketConnect(sock, &addr) != 0)
{
log_error("can't connect socket: %s\n", SocketGetLastErrorMessage());
SocketClose(sock);
return(0);
}
}
SocketGetAddress(sock, &addr);
SocketClose(sock);
return(addr.ip);
}
int SocketReceiveMessage(platform_socket* socket, socket_msg* msg, socket_address* from)
{
sockaddr_in saddr;
iovec iov;
iov.iov_base = msg->messageBuffer;
iov.iov_len = msg->messageBufferSize;
msghdr hdr;
hdr.msg_name = &saddr;
hdr.msg_namelen = sizeof(saddr);
hdr.msg_iov = &iov;
hdr.msg_iovlen = 1;
hdr.msg_control = msg->controlBuffer;
hdr.msg_controllen = msg->controlBufferSize;
int size = recvmsg(socket->sd, &hdr, 0);
if(size <= 0)
{
return(size);
}
from->ip = saddr.sin_addr.s_addr;
from->port = saddr.sin_port;
msg->controlBufferSize = hdr.msg_controllen;
msg->messageBufferSize = iov.iov_len;
return(size);
}

View File

@ -11,50 +11,54 @@
#include<signal.h> //needed for pthread_kill() on linux
#include<string.h>
#include<sys/time.h>
#include<unistd.h> // nanosleep()
#include"platform_thread.h"
struct mp_thread
struct oc_thread
{
bool valid;
pthread_t pthread;
mp_thread_start_function start;
oc_thread_start_function start;
void* userPointer;
char name[MP_THREAD_NAME_MAX_SIZE];
oc_str8 name;
char nameBuffer[OC_THREAD_NAME_MAX_SIZE];
};
static void* mp_thread_bootstrap(void* data)
static void* oc_thread_bootstrap(void* data)
{
mp_thread* thread = (mp_thread*)data;
if(strlen(thread->name))
oc_thread* thread = (oc_thread*)data;
if(thread->name.len)
{
pthread_setname_np(thread->name);
pthread_setname_np(thread->nameBuffer);
}
i32 exitCode = thread->start(thread->userPointer);
return((void*)(ptrdiff_t)exitCode);
}
mp_thread* mp_thread_create_with_name(mp_thread_start_function start, void* userPointer, const char* name)
oc_thread* oc_thread_create_with_name(oc_thread_start_function start, void* userPointer, oc_str8 name)
{
mp_thread* thread = (mp_thread*)malloc(sizeof(mp_thread));
oc_thread* thread = (oc_thread*)malloc(sizeof(oc_thread));
if(!thread)
{
return(0);
}
if(name)
if(name.len && name.ptr)
{
char* end = stpncpy(thread->name, name, MP_THREAD_NAME_MAX_SIZE-1);
char* end = stpncpy(thread->nameBuffer, name.ptr, oc_min(name.len, OC_THREAD_NAME_MAX_SIZE-1));
*end = '\0';
thread->name = oc_str8_from_buffer(end - thread->nameBuffer, thread->nameBuffer);
}
else
{
thread->name[0] = '\0';
thread->nameBuffer[0] = '\0';
thread->name = oc_str8_from_buffer(0, thread->nameBuffer);
}
thread->start = start;
thread->userPointer = userPointer;
if(pthread_create(&thread->pthread, 0, mp_thread_bootstrap, thread) != 0)
if(pthread_create(&thread->pthread, 0, oc_thread_bootstrap, thread) != 0)
{
free(thread);
return(0);
@ -66,24 +70,24 @@ mp_thread* mp_thread_create_with_name(mp_thread_start_function start, void* user
}
}
mp_thread* mp_thread_create(mp_thread_start_function start, void* userPointer)
oc_thread* oc_thread_create(oc_thread_start_function start, void* userPointer)
{
return(mp_thread_create_with_name(start, userPointer, 0));
return(oc_thread_create_with_name(start, userPointer, (oc_str8){0}));
}
const char* mp_thread_get_name(mp_thread* thread)
oc_str8 oc_thread_get_name(oc_thread* thread)
{
return(thread->name);
}
u64 mp_thread_unique_id(mp_thread* thread)
u64 oc_thread_unique_id(oc_thread* thread)
{
u64 id;
pthread_threadid_np(thread->pthread, &id);
return(id);
}
u64 mp_thread_self_id()
u64 oc_thread_self_id()
{
pthread_t thread = pthread_self();
u64 id;
@ -91,12 +95,12 @@ u64 mp_thread_self_id()
return(id);
}
int mp_thread_signal(mp_thread* thread, int sig)
int oc_thread_signal(oc_thread* thread, int sig)
{
return(pthread_kill(thread->pthread, sig));
}
int mp_thread_join(mp_thread* thread, i64* exitCode)
int oc_thread_join(oc_thread* thread, i64* exitCode)
{
void* ret;
if(pthread_join(thread->pthread, &ret))
@ -112,7 +116,7 @@ int mp_thread_join(mp_thread* thread, i64* exitCode)
return(0);
}
int mp_thread_detach(mp_thread* thread)
int oc_thread_detach(oc_thread* thread)
{
if(pthread_detach(thread->pthread))
{
@ -123,14 +127,14 @@ int mp_thread_detach(mp_thread* thread)
}
struct mp_mutex
struct oc_mutex
{
pthread_mutex_t pmutex;
};
mp_mutex* mp_mutex_create()
oc_mutex* oc_mutex_create()
{
mp_mutex* mutex = (mp_mutex*)malloc(sizeof(mp_mutex));
oc_mutex* mutex = (oc_mutex*)malloc(sizeof(oc_mutex));
if(!mutex)
{
return(0);
@ -143,7 +147,7 @@ mp_mutex* mp_mutex_create()
return(mutex);
}
int mp_mutex_destroy(mp_mutex* mutex)
int oc_mutex_destroy(oc_mutex* mutex)
{
if(pthread_mutex_destroy(&mutex->pmutex) != 0)
{
@ -153,44 +157,44 @@ int mp_mutex_destroy(mp_mutex* mutex)
return(0);
}
int mp_mutex_lock(mp_mutex* mutex)
int oc_mutex_lock(oc_mutex* mutex)
{
return(pthread_mutex_lock(&mutex->pmutex));
}
int mp_mutex_unlock(mp_mutex* mutex)
int oc_mutex_unlock(oc_mutex* mutex)
{
return(pthread_mutex_unlock(&mutex->pmutex));
}
// mp_ticket_spin_mutex has a mirrored implementation in win32_thread.c
// oc_ticket has a mirrored implementation in win32_thread.c
void mp_ticket_spin_mutex_init(mp_ticket_spin_mutex* mutex)
void oc_ticket_init(oc_ticket* mutex)
{
mutex->nextTicket = 0;
mutex->serving = 0;
}
void mp_ticket_spin_mutex_lock(mp_ticket_spin_mutex* mutex)
void oc_ticket_lock(oc_ticket* mutex)
{
u64 ticket = atomic_fetch_add(&mutex->nextTicket, 1ULL);
while(ticket != mutex->serving); //spin
}
void mp_ticket_spin_mutex_unlock(mp_ticket_spin_mutex* mutex)
void oc_ticket_unlock(oc_ticket* mutex)
{
atomic_fetch_add(&mutex->serving, 1ULL);
}
struct mp_condition
struct oc_condition
{
pthread_cond_t pcond;
};
mp_condition* mp_condition_create()
oc_condition* oc_condition_create()
{
mp_condition* cond = (mp_condition*)malloc(sizeof(mp_condition));
oc_condition* cond = (oc_condition*)malloc(sizeof(oc_condition));
if(!cond)
{
return(0);
@ -203,7 +207,7 @@ mp_condition* mp_condition_create()
return(cond);
}
int mp_condition_destroy(mp_condition* cond)
int oc_condition_destroy(oc_condition* cond)
{
if(pthread_cond_destroy(&cond->pcond) != 0)
{
@ -213,12 +217,12 @@ int mp_condition_destroy(mp_condition* cond)
return(0);
}
int mp_condition_wait(mp_condition* cond, mp_mutex* mutex)
int oc_condition_wait(oc_condition* cond, oc_mutex* mutex)
{
return(pthread_cond_wait(&cond->pcond, &mutex->pmutex));
}
int mp_condition_timedwait(mp_condition* cond, mp_mutex* mutex, f64 seconds)
int oc_condition_timedwait(oc_condition* cond, oc_mutex* mutex, f64 seconds)
{
struct timeval tv;
gettimeofday(&tv, 0);
@ -235,12 +239,21 @@ int mp_condition_timedwait(mp_condition* cond, mp_mutex* mutex, f64 seconds)
return(pthread_cond_timedwait(&cond->pcond, &mutex->pmutex, &ts));
}
int mp_condition_signal(mp_condition* cond)
int oc_condition_signal(oc_condition* cond)
{
return(pthread_cond_signal(&cond->pcond));
}
int mp_condition_broadcast(mp_condition* cond)
int oc_condition_broadcast(oc_condition* cond)
{
return(pthread_cond_broadcast(&cond->pcond));
}
void oc_sleep_nano(u64 nanoseconds)
{
timespec rqtp;
rqtp.tv_sec = nanoseconds / 1000000000;
rqtp.tv_nsec = nanoseconds - rqtp.tv_sec * 1000000000;
nanosleep(&rqtp, 0);
}

View File

@ -12,27 +12,27 @@
/*NOTE(martin):
Linux and MacOS don't make a distinction between reserved and committed memory, contrary to Windows
*/
void mem_base_nop(mem_base_allocator* context, void* ptr, u64 size) {}
void oc_base_nop(oc_base_allocator* context, void* ptr, u64 size) {}
void* mem_base_reserve_mmap(mem_base_allocator* context, u64 size)
void* oc_base_reserve_mmap(oc_base_allocator* context, u64 size)
{
return(mmap(0, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0));
}
void mem_base_release_mmap(mem_base_allocator* context, void* ptr, u64 size)
void oc_base_release_mmap(oc_base_allocator* context, void* ptr, u64 size)
{
munmap(ptr, size);
}
mem_base_allocator* mem_base_allocator_default()
oc_base_allocator* oc_base_allocator_default()
{
static mem_base_allocator base = {};
static oc_base_allocator base = {};
if(base.reserve == 0)
{
base.reserve = mem_base_reserve_mmap;
base.commit = mem_base_nop;
base.decommit = mem_base_nop;
base.release = mem_base_release_mmap;
base.reserve = oc_base_reserve_mmap;
base.commit = oc_base_nop;
base.decommit = oc_base_nop;
base.release = oc_base_release_mmap;
}
return(&base);
}

View File

@ -1,56 +0,0 @@
/************************************************************//**
*
* @file: unix_rng.c
* @author: Martin Fouilleul
* @date: 06/03/2020
* @revision:
*
*****************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include"platform_debug.h"
#include"typedefs.h"
int RandomSeedFromDevice()
{
FILE* urandom = fopen("/dev/urandom", "r");
if(!urandom)
{
log_error("can't open /dev/urandom\n");
return(-1);
}
union
{
u32 u;
char buff[4];
} seed;
int size = fread(seed.buff, 1, 4, urandom);
if(size != 4)
{
log_error("couldn't read from /dev/urandom\n");
return(-1);
}
fclose(urandom);
srandom(seed.u);
return(0);
}
u32 RandomU32()
{
u32 u1 = (u32)random();
u32 u2 = (u32)random();
return((u1<<1) | (u2 & 0x01));
}
u64 RandomU64()
{
u64 u1 = (u64)random();
u64 u2 = (u64)random();
u64 u3 = (u64)random();
return((u1<<33) | (u2<<2) | (u3 & 0x03));
}

View File

@ -17,14 +17,14 @@ extern "C" {
static u64 __performanceCounterFreq = 0;
void mp_clock_init()
void oc_clock_init()
{
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
__performanceCounterFreq = freq.QuadPart;
}
f64 mp_get_time(mp_clock_kind clock)
f64 oc_clock_time(oc_clock_kind clock)
{
LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);

View File

@ -15,72 +15,72 @@
#include"platform_io_internal.c"
#include"platform_io_common.c"
io_error io_raw_last_error()
oc_io_error oc_io_raw_last_error()
{
io_error error = 0;
oc_io_error error = 0;
int winError = GetLastError();
switch(winError)
{
case ERROR_SUCCESS:
error = IO_OK;
error = OC_IO_OK;
break;
case ERROR_ACCESS_DENIED:
error = IO_ERR_PERM;
error = OC_IO_ERR_PERM;
break;
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
case ERROR_INVALID_DRIVE:
case ERROR_DIRECTORY:
error = IO_ERR_NO_ENTRY;
error = OC_IO_ERR_NO_ENTRY;
break;
case ERROR_TOO_MANY_OPEN_FILES:
error = IO_ERR_MAX_FILES;
error = OC_IO_ERR_MAX_FILES;
break;
case ERROR_NOT_ENOUGH_MEMORY:
case ERROR_OUTOFMEMORY:
error = IO_ERR_MEM;
error = OC_IO_ERR_MEM;
break;
case ERROR_DEV_NOT_EXIST:
error = IO_ERR_NO_DEVICE;
error = OC_IO_ERR_NO_DEVICE;
break;
case ERROR_FILE_EXISTS:
case ERROR_ALREADY_EXISTS:
error = IO_ERR_EXISTS;
error = OC_IO_ERR_EXISTS;
break;
case ERROR_BUFFER_OVERFLOW:
case ERROR_FILENAME_EXCED_RANGE:
error = IO_ERR_PATH_LENGTH;
error = OC_IO_ERR_PATH_LENGTH;
break;
case ERROR_FILE_TOO_LARGE:
error = IO_ERR_FILE_SIZE;
error = OC_IO_ERR_FILE_SIZE;
break;
//TODO: complete
default:
error = IO_ERR_UNKNOWN;
error = OC_IO_ERR_UNKNOWN;
break;
}
return(error);
}
str16 win32_path_from_handle_null_terminated(mem_arena* arena, HANDLE handle)
static oc_str16 win32_path_from_handle_null_terminated(oc_arena* arena, HANDLE handle)
{
str16 res = {0};
oc_str16 res = {0};
res.len = GetFinalPathNameByHandleW(handle, NULL, 0, FILE_NAME_NORMALIZED);
if(res.len)
{
res.ptr = mem_arena_alloc_array(arena, u16, res.len);
res.ptr = oc_arena_push_array(arena, u16, res.len);
if(!GetFinalPathNameByHandleW(handle, res.ptr, res.len, FILE_NAME_NORMALIZED))
{
res.len = 0;
@ -90,36 +90,36 @@ str16 win32_path_from_handle_null_terminated(mem_arena* arena, HANDLE handle)
return(res);
}
typedef HANDLE io_file_desc;
typedef HANDLE oc_file_desc;
io_file_desc io_file_desc_nil()
oc_file_desc oc_file_desc_nil()
{
return(INVALID_HANDLE_VALUE);
}
bool io_file_desc_is_nil(io_file_desc fd)
bool oc_file_desc_is_nil(oc_file_desc fd)
{
return(fd == NULL || fd == INVALID_HANDLE_VALUE);
}
str16 win32_get_path_at_null_terminated(mem_arena* arena, io_file_desc dirFd, str8 path)
static oc_str16 win32_get_path_at_null_terminated(oc_arena* arena, oc_file_desc dirFd, oc_str8 path)
{
str16 result = {0};
mem_arena_scope scratch = mem_scratch_begin_next(arena);
oc_str16 result = {0};
oc_arena_scope scratch = oc_scratch_begin_next(arena);
str16 dirPathW = win32_path_from_handle_null_terminated(scratch.arena, dirFd);
str16 pathW = win32_utf8_to_wide_null_terminated(scratch.arena, path);
oc_str16 dirPathW = win32_path_from_handle_null_terminated(scratch.arena, dirFd);
oc_str16 pathW = oc_win32_utf8_to_wide_null_terminated(scratch.arena, path);
if(dirPathW.len && pathW.len)
{
u64 fullPathWSize = dirPathW.len + pathW.len;
LPWSTR fullPathW = mem_arena_alloc_array(scratch.arena, u16, fullPathWSize);
LPWSTR fullPathW = oc_arena_push_array(scratch.arena, u16, fullPathWSize);
memcpy(fullPathW, dirPathW.ptr, (dirPathW.len-1)*sizeof(u16));
fullPathW[dirPathW.len-1] = '\\';
memcpy(fullPathW + dirPathW.len, pathW.ptr, pathW.len*sizeof(u16));
result.len = fullPathWSize;
result.ptr = mem_arena_alloc_array(arena, wchar_t, result.len);
result.ptr = oc_arena_push_array(arena, wchar_t, result.len);
if(PathCanonicalizeW(result.ptr, fullPathW))
{
@ -131,12 +131,12 @@ str16 win32_get_path_at_null_terminated(mem_arena* arena, io_file_desc dirFd, st
result.len = 0;
}
}
mem_scratch_end(scratch);
oc_scratch_end(scratch);
return(result);
}
io_file_desc io_raw_open_at(io_file_desc dirFd, str8 path, file_access_rights accessRights, file_open_flags openFlags)
oc_file_desc oc_io_raw_open_at(oc_file_desc dirFd, oc_str8 path, oc_file_access accessRights, oc_file_open_flags openFlags)
{
HANDLE handle = INVALID_HANDLE_VALUE;
@ -147,13 +147,13 @@ io_file_desc io_raw_open_at(io_file_desc dirFd, str8 path, file_access_rights ac
DWORD win32AttributeFlags = FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_BACKUP_SEMANTICS;
if(accessRights & FILE_ACCESS_READ)
if(accessRights & OC_FILE_ACCESS_READ)
{
win32AccessFlags |= GENERIC_READ;
}
if(accessRights & FILE_ACCESS_WRITE)
if(accessRights & OC_FILE_ACCESS_WRITE)
{
if(accessRights & FILE_OPEN_APPEND)
if(accessRights & OC_FILE_OPEN_APPEND)
{
win32AccessFlags |= FILE_APPEND_DATA;
}
@ -163,9 +163,9 @@ io_file_desc io_raw_open_at(io_file_desc dirFd, str8 path, file_access_rights ac
}
}
if(openFlags & FILE_OPEN_TRUNCATE)
if(openFlags & OC_FILE_OPEN_TRUNCATE)
{
if(openFlags & FILE_OPEN_CREATE)
if(openFlags & OC_FILE_OPEN_CREATE)
{
win32CreateFlags |= CREATE_ALWAYS;
}
@ -174,7 +174,7 @@ io_file_desc io_raw_open_at(io_file_desc dirFd, str8 path, file_access_rights ac
win32CreateFlags |= TRUNCATE_EXISTING;
}
}
if(openFlags & FILE_OPEN_CREATE)
if(openFlags & OC_FILE_OPEN_CREATE)
{
if(!(win32CreateFlags & CREATE_ALWAYS))
{
@ -188,13 +188,13 @@ io_file_desc io_raw_open_at(io_file_desc dirFd, str8 path, file_access_rights ac
win32CreateFlags |= OPEN_EXISTING;
}
if(openFlags & FILE_OPEN_SYMLINK)
if(openFlags & OC_FILE_OPEN_SYMLINK)
{
win32AttributeFlags |= FILE_FLAG_OPEN_REPARSE_POINT;
}
mem_arena_scope scratch = mem_scratch_begin();
str16 pathW = win32_utf8_to_wide_null_terminated(scratch.arena, path);
oc_arena_scope scratch = oc_scratch_begin();
oc_str16 pathW = oc_win32_utf8_to_wide_null_terminated(scratch.arena, path);
if(dirFd == NULL || dirFd == INVALID_HANDLE_VALUE)
{
@ -202,41 +202,41 @@ io_file_desc io_raw_open_at(io_file_desc dirFd, str8 path, file_access_rights ac
}
else
{
str16 fullPathW = win32_get_path_at_null_terminated(scratch.arena, dirFd, path);
oc_str16 fullPathW = win32_get_path_at_null_terminated(scratch.arena, dirFd, path);
if(fullPathW.len)
{
handle = CreateFileW(fullPathW.ptr, win32AccessFlags, win32ShareMode, NULL, win32CreateFlags, win32AttributeFlags, NULL);
}
}
mem_scratch_end(scratch);
oc_scratch_end(scratch);
return(handle);
}
void io_raw_close(io_file_desc fd)
void oc_io_raw_close(oc_file_desc fd)
{
CloseHandle(fd);
}
bool io_raw_file_exists_at(io_file_desc dirFd, str8 path, file_open_flags openFlags)
bool oc_io_raw_file_exists_at(oc_file_desc dirFd, oc_str8 path, oc_file_open_flags openFlags)
{
bool result = false;
io_file_desc fd = io_raw_open_at(dirFd, path, FILE_ACCESS_NONE, (openFlags & FILE_OPEN_SYMLINK));
if(!io_file_desc_is_nil(fd))
oc_file_desc fd = oc_io_raw_open_at(dirFd, path, OC_FILE_ACCESS_NONE, (openFlags & OC_FILE_OPEN_SYMLINK));
if(!oc_file_desc_is_nil(fd))
{
result = true;
io_raw_close(fd);
oc_io_raw_close(fd);
}
return(result);
}
io_error io_raw_fstat(io_file_desc fd, file_status* status)
oc_io_error oc_io_raw_fstat(oc_file_desc fd, oc_file_status* status)
{
io_error error = IO_OK;
oc_io_error error = OC_IO_OK;
BY_HANDLE_FILE_INFORMATION info;
if(!GetFileInformationByHandle(fd, &info))
{
error = io_raw_last_error();
error = oc_io_raw_last_error();
}
else
{
@ -260,53 +260,53 @@ io_error io_raw_fstat(io_file_desc fd, file_status* status)
FILE_ATTRIBUTE_TAG_INFO tagInfo;
if(!GetFileInformationByHandleEx(fd, FileAttributeTagInfo, &tagInfo, sizeof(tagInfo)))
{
error = io_raw_last_error();
error = oc_io_raw_last_error();
}
else if(tagInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK)
{
status->type = MP_FILE_SYMLINK;
status->type = OC_FILE_SYMLINK;
}
else
{
status->type = MP_FILE_UNKNOWN;
status->type = OC_FILE_UNKNOWN;
}
}
else if(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
status->type = MP_FILE_DIRECTORY;
status->type = OC_FILE_DIRECTORY;
}
else if(info.dwFileAttributes & attrRegularSet)
{
status->type = MP_FILE_REGULAR;
status->type = OC_FILE_REGULAR;
}
else
{
//TODO: might want to check for socket/block/character devices? (otoh MS STL impl. doesn't seem to do it)
status->type = MP_FILE_UNKNOWN;
status->type = OC_FILE_UNKNOWN;
}
status->perm = MP_FILE_OWNER_READ | MP_FILE_GROUP_READ | MP_FILE_OTHER_READ;
status->perm = OC_FILE_OWNER_READ | OC_FILE_GROUP_READ | OC_FILE_OTHER_READ;
if(!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
{
status->perm = MP_FILE_OWNER_WRITE | MP_FILE_GROUP_WRITE | MP_FILE_OTHER_WRITE;
status->perm = OC_FILE_OWNER_WRITE | OC_FILE_GROUP_WRITE | OC_FILE_OTHER_WRITE;
}
//TODO: times
}
return(error);
}
io_error io_raw_fstat_at(io_file_desc dirFd, str8 name, file_open_flags openFlags, file_status* status)
oc_io_error oc_io_raw_fstat_at(oc_file_desc dirFd, oc_str8 name, oc_file_open_flags openFlags, oc_file_status* status)
{
io_error error = IO_OK;
io_file_desc fd = io_raw_open_at(dirFd, name, FILE_ACCESS_NONE, FILE_OPEN_SYMLINK);
if(io_file_desc_is_nil(fd))
oc_io_error error = OC_IO_OK;
oc_file_desc fd = oc_io_raw_open_at(dirFd, name, OC_FILE_ACCESS_NONE, OC_FILE_OPEN_SYMLINK);
if(oc_file_desc_is_nil(fd))
{
error = io_raw_last_error();
error = oc_io_raw_last_error();
}
else
{
error = io_raw_fstat(fd, status);
io_raw_close(fd);
error = oc_io_raw_fstat(fd, status);
oc_io_raw_close(fd);
}
return(error);
}
@ -342,88 +342,88 @@ typedef struct
UCHAR DataBuffer[1];
} GenericReparseBuffer;
};
} REPARSE_DATA_BUFFER;
} oc_win32_reparse_data_buffer;
io_raw_read_link_result io_raw_read_link(mem_arena* arena, io_file_desc fd)
oc_io_raw_read_link_result oc_io_raw_read_link(oc_arena* arena, oc_file_desc fd)
{
io_raw_read_link_result result = {0};
oc_io_raw_read_link_result result = {0};
char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
DWORD bytesReturned;
if(!DeviceIoControl(fd, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned, 0))
{
result.error = io_raw_last_error();
result.error = oc_io_raw_last_error();
}
else
{
REPARSE_DATA_BUFFER* reparse = (REPARSE_DATA_BUFFER*)buffer;
oc_win32_reparse_data_buffer* reparse = (oc_win32_reparse_data_buffer*)buffer;
if(reparse->ReparseTag == IO_REPARSE_TAG_SYMLINK)
{
str16 nameW = {0};
oc_str16 nameW = {0};
nameW.len = reparse->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
nameW.ptr = (u16*)((char*)reparse->SymbolicLinkReparseBuffer.PathBuffer + reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset);
result.target = win32_wide_to_utf8(arena, nameW);
result.target = oc_win32_wide_to_utf8(arena, nameW);
}
else
{
result.error = IO_ERR_UNKNOWN;
result.error = OC_IO_ERR_UNKNOWN;
}
}
return(result);
}
io_raw_read_link_result io_raw_read_link_at(mem_arena* arena, io_file_desc dirFd, str8 name)
oc_io_raw_read_link_result oc_io_raw_read_link_at(oc_arena* arena, oc_file_desc dirFd, oc_str8 name)
{
io_file_desc fd = io_raw_open_at(dirFd, name, FILE_ACCESS_READ, FILE_OPEN_SYMLINK);
io_raw_read_link_result result = io_raw_read_link(arena, fd);
io_raw_close(fd);
oc_file_desc fd = oc_io_raw_open_at(dirFd, name, OC_FILE_ACCESS_READ, OC_FILE_OPEN_SYMLINK);
oc_io_raw_read_link_result result = oc_io_raw_read_link(arena, fd);
oc_io_raw_close(fd);
return(result);
}
io_cmp io_close(file_slot* slot, io_req* req, file_table* table)
static oc_io_cmp oc_io_close(oc_file_slot* slot, oc_io_req* req, oc_file_table* table)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
if(slot->fd)
{
CloseHandle(slot->fd);
}
file_slot_recycle(table, slot);
oc_file_slot_recycle(table, slot);
return(cmp);
}
io_cmp io_fstat(file_slot* slot, io_req* req)
static oc_io_cmp oc_io_fstat(oc_file_slot* slot, oc_io_req* req)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
if(req->size < sizeof(file_status))
if(req->size < sizeof(oc_file_status))
{
cmp.error = IO_ERR_ARG;
cmp.error = OC_IO_ERR_ARG;
}
else
{
slot->error = io_raw_fstat(slot->fd, (file_status*)req->buffer);
slot->error = oc_io_raw_fstat(slot->fd, (oc_file_status*)req->buffer);
cmp.error = slot->error;
}
return(cmp);
}
io_cmp io_seek(file_slot* slot, io_req* req)
static oc_io_cmp oc_io_seek(oc_file_slot* slot, oc_io_req* req)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
DWORD whence;
switch(req->whence)
{
case FILE_SEEK_CURRENT:
case OC_FILE_SEEK_CURRENT:
whence = FILE_CURRENT;
break;
case FILE_SEEK_SET:
case OC_FILE_SEEK_SET:
whence = FILE_BEGIN;
break;
case FILE_SEEK_END:
case OC_FILE_SEEK_END:
whence = FILE_END;
}
@ -432,7 +432,7 @@ io_cmp io_seek(file_slot* slot, io_req* req)
if(!SetFilePointerEx(slot->fd, off, &newPos, whence))
{
slot->error = io_raw_last_error();
slot->error = oc_io_raw_last_error();
cmp.error = slot->error;
}
else
@ -443,13 +443,13 @@ io_cmp io_seek(file_slot* slot, io_req* req)
return(cmp);
}
io_cmp io_read(file_slot* slot, io_req* req)
static oc_io_cmp oc_io_read(oc_file_slot* slot, oc_io_req* req)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
if(slot->type != MP_FILE_REGULAR)
if(slot->type != OC_FILE_REGULAR)
{
slot->error = IO_ERR_PERM;
slot->error = OC_IO_ERR_PERM;
cmp.error = slot->error;
}
else
@ -458,7 +458,7 @@ io_cmp io_read(file_slot* slot, io_req* req)
if(!ReadFile(slot->fd, req->buffer, req->size, &bytesRead, NULL))
{
slot->error = io_raw_last_error();
slot->error = oc_io_raw_last_error();
cmp.result = 0;
cmp.error = slot->error;
}
@ -470,13 +470,13 @@ io_cmp io_read(file_slot* slot, io_req* req)
return(cmp);
}
io_cmp io_write(file_slot* slot, io_req* req)
static oc_io_cmp oc_io_write(oc_file_slot* slot, oc_io_req* req)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
if(slot->type != MP_FILE_REGULAR)
if(slot->type != OC_FILE_REGULAR)
{
slot->error = IO_ERR_PERM;
slot->error = OC_IO_ERR_PERM;
cmp.error = slot->error;
}
else
@ -485,7 +485,7 @@ io_cmp io_write(file_slot* slot, io_req* req)
if(!WriteFile(slot->fd, req->buffer, req->size, &bytesWritten, NULL))
{
slot->error = io_raw_last_error();
slot->error = oc_io_raw_last_error();
cmp.result = 0;
cmp.error = slot->error;
}
@ -497,64 +497,64 @@ io_cmp io_write(file_slot* slot, io_req* req)
return(cmp);
}
io_cmp io_get_error(file_slot* slot, io_req* req)
static oc_io_cmp oc_io_get_error(oc_file_slot* slot, oc_io_req* req)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
cmp.result = slot->error;
return(cmp);
}
io_cmp io_wait_single_req_with_table(io_req* req, file_table* table)
oc_io_cmp oc_io_wait_single_req_with_table(oc_io_req* req, oc_file_table* table)
{
io_cmp cmp = {0};
oc_io_cmp cmp = {0};
file_slot* slot = file_slot_from_handle(table, req->handle);
oc_file_slot* slot = oc_file_slot_from_handle(table, req->handle);
if(!slot)
{
if(req->op != IO_OP_OPEN_AT)
if(req->op != OC_IO_OPEN_AT)
{
cmp.error = IO_ERR_HANDLE;
cmp.error = OC_IO_ERR_HANDLE;
}
}
else if(slot->fatal && req->op != IO_OP_CLOSE && req->op != IO_OP_ERROR)
else if(slot->fatal && req->op != OC_IO_CLOSE && req->op != OC_OC_IO_ERROR)
{
cmp.error = IO_ERR_PREV;
cmp.error = OC_IO_ERR_PREV;
}
if(cmp.error == IO_OK)
if(cmp.error == OC_IO_OK)
{
switch(req->op)
{
case IO_OP_OPEN_AT:
cmp = io_open_at(slot, req, table);
case OC_IO_OPEN_AT:
cmp = oc_io_open_at(slot, req, table);
break;
case IO_OP_FSTAT:
cmp = io_fstat(slot, req);
case OC_IO_FSTAT:
cmp = oc_io_fstat(slot, req);
break;
case IO_OP_CLOSE:
cmp = io_close(slot, req, table);
case OC_IO_CLOSE:
cmp = oc_io_close(slot, req, table);
break;
case IO_OP_READ:
cmp = io_read(slot, req);
case OC_IO_READ:
cmp = oc_io_read(slot, req);
break;
case IO_OP_WRITE:
cmp = io_write(slot, req);
case OC_IO_WRITE:
cmp = oc_io_write(slot, req);
break;
case IO_OP_SEEK:
cmp = io_seek(slot, req);
case OC_IO_SEEK:
cmp = oc_io_seek(slot, req);
break;
case IO_OP_ERROR:
cmp = io_get_error(slot, req);
case OC_OC_IO_ERROR:
cmp = oc_io_get_error(slot, req);
break;
default:
cmp.error = IO_ERR_OP;
cmp.error = OC_IO_ERR_OP;
if(slot)
{
slot->error = cmp.error;

View File

@ -10,36 +10,36 @@
#include<windows.h>
#include"platform_memory.h"
void* mem_base_reserve_win32(mem_base_allocator* context, u64 size)
void* oc_base_reserve_win32(oc_base_allocator* context, u64 size)
{
void* result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
return(result);
}
void mem_base_commit_win32(mem_base_allocator* context, void* ptr, u64 size)
void oc_base_commit_win32(oc_base_allocator* context, void* ptr, u64 size)
{
VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE);
}
void mem_base_release_win32(mem_base_allocator* context, void* ptr, u64 size)
void oc_base_release_win32(oc_base_allocator* context, void* ptr, u64 size)
{
VirtualFree(ptr, size, MEM_RELEASE);
}
void mem_base_decommit_win32(mem_base_allocator* context, void* ptr, u64 size)
void oc_base_decommit_win32(oc_base_allocator* context, void* ptr, u64 size)
{
VirtualFree(ptr, size, MEM_DECOMMIT);
}
mem_base_allocator* mem_base_allocator_default()
oc_base_allocator* oc_base_allocator_default()
{
static mem_base_allocator base = {0};
static oc_base_allocator base = {0};
if(base.reserve == 0)
{
base.reserve = mem_base_reserve_win32;
base.commit = mem_base_commit_win32;
base.decommit = mem_base_decommit_win32;
base.release = mem_base_release_win32;
base.reserve = oc_base_reserve_win32;
base.commit = oc_base_commit_win32;
base.decommit = oc_base_decommit_win32;
base.release = oc_base_release_win32;
}
return(&base);
}

View File

@ -10,23 +10,23 @@
#include"win32_string_helpers.h"
#include"platform_path.c"
bool path_is_absolute(str8 path)
bool oc_path_is_absolute(oc_str8 path)
{
mem_arena_scope scratch = mem_scratch_begin();
str16 pathW = win32_utf8_to_wide_null_terminated(scratch.arena, path);
oc_arena_scope scratch = oc_scratch_begin();
oc_str16 pathW = oc_win32_utf8_to_wide_null_terminated(scratch.arena, path);
bool result = !PathIsRelativeW(pathW.ptr);
mem_scratch_end(scratch);
oc_scratch_end(scratch);
return(result);
}
str8 path_executable(mem_arena* arena)
oc_str8 oc_path_executable(oc_arena* arena)
{
///////////////////////////////////////////////////////////////////
//TODO use wide chars
///////////////////////////////////////////////////////////////////
char* buffer = mem_arena_alloc_array(arena, char, MAX_PATH+2);
char* buffer = oc_arena_push_array(arena, char, MAX_PATH+2);
int size = GetModuleFileName(NULL, buffer, MAX_PATH+1);
//TODO: check for errors...
for(int i=0; i<size; i++)
@ -36,7 +36,7 @@ str8 path_executable(mem_arena* arena)
buffer[i] = '/';
}
}
return(str8_from_buffer(size, buffer));
return(oc_str8_from_buffer(size, buffer));
}
str8 path_canonical(mem_arena* arena, str8 path); //TODO
oc_str8 oc_path_canonical(oc_arena* arena, oc_str8 path); //TODO

View File

@ -11,21 +11,21 @@
#include"win32_string_helpers.h"
str16 win32_utf8_to_wide_null_terminated(mem_arena* arena, str8 s)
oc_str16 oc_win32_utf8_to_wide_null_terminated(oc_arena* arena, oc_str8 s)
{
str16 res = {0};
oc_str16 res = {0};
res.len = 1 + MultiByteToWideChar(CP_UTF8, 0, s.ptr, s.len, NULL, 0);
res.ptr = mem_arena_alloc_array(arena, u16, res.len);
res.ptr = oc_arena_push_array(arena, u16, res.len);
MultiByteToWideChar(CP_UTF8, 0, s.ptr, s.len, res.ptr, res.len);
res.ptr[res.len-1] = '\0';
return(res);
}
str8 win32_wide_to_utf8(mem_arena* arena, str16 s)
oc_str8 oc_win32_wide_to_utf8(oc_arena* arena, oc_str16 s)
{
str8 res = {0};
oc_str8 res = {0};
res.len = WideCharToMultiByte(CP_UTF8, 0, s.ptr, s.len, NULL, 0, NULL, NULL);
res.ptr = mem_arena_alloc_array(arena, u8, res.len);
res.ptr = oc_arena_push_array(arena, u8, res.len);
WideCharToMultiByte(CP_UTF8, 0, s.ptr, s.len, res.ptr, res.len, NULL, NULL);
return(res);
}

View File

@ -10,8 +10,8 @@
#include"util/strings.h"
str16 win32_utf8_to_wide_null_terminated(mem_arena* arena, str8 s);
str8 win32_wide_to_utf8(mem_arena* arena, str16 s);
oc_str16 oc_win32_utf8_to_wide_null_terminated(oc_arena* arena, oc_str8 s);
oc_str8 oc_win32_wide_to_utf8(oc_arena* arena, oc_str16 s);
#endif // __WIN32_STRING_HELPERS_H_

View File

@ -12,36 +12,39 @@
#include"platform_thread.h"
struct mp_thread
struct oc_thread
{
mp_thread_start_function start;
oc_thread_start_function start;
HANDLE handle;
DWORD threadId;
void* userPointer;
char name[MP_THREAD_NAME_MAX_SIZE];
oc_str8 name;
char nameBuffer[OC_THREAD_NAME_MAX_SIZE];
};
static DWORD WINAPI mp_thread_bootstrap(LPVOID lpParameter)
static DWORD WINAPI oc_thread_bootstrap(LPVOID lpParameter)
{
mp_thread* thread = (mp_thread*)lpParameter;
oc_thread* thread = (oc_thread*)lpParameter;
i32 exitCode = thread->start(thread->userPointer);
return(exitCode);
}
mp_thread* mp_thread_create_with_name(mp_thread_start_function start, void* userPointer, const char* name)
oc_thread* oc_thread_create_with_name(oc_thread_start_function start, void* userPointer, oc_str8 name)
{
mp_thread* thread = (mp_thread*)malloc(sizeof(mp_thread));
oc_thread* thread = (oc_thread*)malloc(sizeof(oc_thread));
thread->start = start;
thread->handle = INVALID_HANDLE_VALUE;
thread->userPointer = userPointer;
if(name)
if(name.len && name.ptr)
{
char* end = strncpy(thread->name, name, MP_THREAD_NAME_MAX_SIZE-1);
*end = '\0';
strncpy(thread->nameBuffer, name.ptr, oc_min(name.len, OC_THREAD_NAME_MAX_SIZE-1));
thread->nameBuffer[OC_THREAD_NAME_MAX_SIZE-1] = '\0';
thread->name = OC_STR8(thread->nameBuffer);
}
else
{
thread->name[0] = '\0';
thread->nameBuffer[0] = '\0';
thread->name = oc_str8_from_buffer(0, thread->nameBuffer);
}
SECURITY_ATTRIBUTES childProcessSecurity = {
@ -51,7 +54,7 @@ mp_thread* mp_thread_create_with_name(mp_thread_start_function start, void* user
SIZE_T stackSize = 0; // uses process default
DWORD flags = 0;
DWORD threadId = 0;
thread->handle = CreateThread(&childProcessSecurity, stackSize, mp_thread_bootstrap, thread, flags, &threadId);
thread->handle = CreateThread(&childProcessSecurity, stackSize, oc_thread_bootstrap, thread, flags, &threadId);
if (thread->handle == NULL) {
free(thread);
return(NULL);
@ -59,9 +62,9 @@ mp_thread* mp_thread_create_with_name(mp_thread_start_function start, void* user
thread->threadId = threadId;
if (thread->name[0]) {
wchar_t widename[MP_THREAD_NAME_MAX_SIZE];
size_t length = mbstowcs(widename, thread->name, MP_THREAD_NAME_MAX_SIZE - 1);
if (thread->name.len) {
wchar_t widename[OC_THREAD_NAME_MAX_SIZE];
size_t length = mbstowcs(widename, thread->nameBuffer, OC_THREAD_NAME_MAX_SIZE - 1);
widename[length] = '\0';
SetThreadDescription(thread->handle, widename);
@ -70,33 +73,33 @@ mp_thread* mp_thread_create_with_name(mp_thread_start_function start, void* user
return(thread);
}
mp_thread* mp_thread_create(mp_thread_start_function start, void* userPointer)
oc_thread* oc_thread_create(oc_thread_start_function start, void* userPointer)
{
return(mp_thread_create_with_name(start, userPointer, NULL));
return(oc_thread_create_with_name(start, userPointer, (oc_str8){0}));
}
const char* mp_thread_get_name(mp_thread* thread)
oc_str8 oc_thread_get_name(oc_thread* thread)
{
return(thread->name);
}
u64 mp_thread_unique_id(mp_thread* thread)
u64 oc_thread_unique_id(oc_thread* thread)
{
return(thread->threadId);
}
u64 mp_thread_self_id()
u64 oc_thread_self_id()
{
return(GetCurrentThreadId());
}
int mp_thread_signal(mp_thread* thread, int sig)
int oc_thread_signal(oc_thread* thread, int sig)
{
BOOL success = TerminateThread(thread->handle, (DWORD)sig);
return(success ? 0 : -1);
}
int mp_thread_join(mp_thread* thread, i64* exitCode)
int oc_thread_join(oc_thread* thread, i64* exitCode)
{
DWORD result = WaitForSingleObject(thread->handle, INFINITE);
if (result == WAIT_FAILED) {
@ -116,7 +119,7 @@ int mp_thread_join(mp_thread* thread, i64* exitCode)
return(0);
}
int mp_thread_detach(mp_thread* thread)
int oc_thread_detach(oc_thread* thread)
{
if (CloseHandle(thread->handle))
{
@ -127,86 +130,86 @@ int mp_thread_detach(mp_thread* thread)
}
struct mp_mutex
struct oc_mutex
{
u64 owningThreadId;
SRWLOCK lock;
};
mp_mutex* mp_mutex_create()
oc_mutex* oc_mutex_create()
{
mp_mutex* mutex = (mp_mutex*)malloc(sizeof(mp_mutex));
oc_mutex* mutex = (oc_mutex*)malloc(sizeof(oc_mutex));
mutex->owningThreadId = 0;
InitializeSRWLock(&mutex->lock);
return mutex;
}
int mp_mutex_destroy(mp_mutex* mutex)
int oc_mutex_destroy(oc_mutex* mutex)
{
DEBUG_ASSERT(mutex->owningThreadId == 0);
OC_DEBUG_ASSERT(mutex->owningThreadId == 0);
free(mutex);
return(0);
}
int mp_mutex_lock(mp_mutex* mutex)
int oc_mutex_lock(oc_mutex* mutex)
{
DEBUG_ASSERT(mutex->owningThreadId == 0);
OC_DEBUG_ASSERT(mutex->owningThreadId == 0);
AcquireSRWLockExclusive(&mutex->lock);
return(0);
}
int mp_mutex_unlock(mp_mutex* mutex)
int oc_mutex_unlock(oc_mutex* mutex)
{
DEBUG_ASSERT(mp_thread_self_id() == mutex->owningThreadId);
OC_DEBUG_ASSERT(oc_thread_self_id() == mutex->owningThreadId);
ReleaseSRWLockExclusive(&mutex->lock);
mutex->owningThreadId = 0;
return(0);
}
// mp_ticket_spin_mutex has a mirrored implementation in posix_thread.c
// oc_ticket has a mirrored implementation in posix_thread.c
void mp_ticket_spin_mutex_init(mp_ticket_spin_mutex* mutex)
void oc_ticket_init(oc_ticket* mutex)
{
mutex->nextTicket = 0;
mutex->serving = 0;
}
void mp_ticket_spin_mutex_lock(mp_ticket_spin_mutex* mutex)
void oc_ticket_lock(oc_ticket* mutex)
{
u64 ticket = atomic_fetch_add(&mutex->nextTicket, 1ULL);
while(ticket != mutex->serving); //spin
}
void mp_ticket_spin_mutex_unlock(mp_ticket_spin_mutex* mutex)
void oc_ticket_unlock(oc_ticket* mutex)
{
atomic_fetch_add(&mutex->serving, 1ULL);
}
struct mp_condition
struct oc_condition
{
CONDITION_VARIABLE cond;
};
mp_condition* mp_condition_create()
oc_condition* oc_condition_create()
{
mp_condition* cond = (mp_condition*)malloc(sizeof(mp_condition));
oc_condition* cond = (oc_condition*)malloc(sizeof(oc_condition));
InitializeConditionVariable(&cond->cond);
return cond;
}
int mp_condition_destroy(mp_condition* cond)
int oc_condition_destroy(oc_condition* cond)
{
free(cond);
return(0);
}
int mp_condition_wait(mp_condition* cond, mp_mutex* mutex)
int oc_condition_wait(oc_condition* cond, oc_mutex* mutex)
{
return mp_condition_timedwait(cond, mutex, INFINITY);
return oc_condition_timedwait(cond, mutex, INFINITY);
}
int mp_condition_timedwait(mp_condition* cond, mp_mutex* mutex, f64 seconds)
int oc_condition_timedwait(oc_condition* cond, oc_mutex* mutex, f64 seconds)
{
const f32 ms = (seconds == INFINITY) ? INFINITE : seconds * 1000;
if (!SleepConditionVariableSRW(&cond->cond, &mutex->lock, ms, 0))
@ -216,13 +219,13 @@ int mp_condition_timedwait(mp_condition* cond, mp_mutex* mutex, f64 seconds)
return(0);
}
int mp_condition_signal(mp_condition* cond)
int oc_condition_signal(oc_condition* cond)
{
WakeConditionVariable(&cond->cond);
return(0);
}
int mp_condition_broadcast(mp_condition* cond)
int oc_condition_broadcast(oc_condition* cond)
{
WakeAllConditionVariable(&cond->cond);
return(0);

Some files were not shown because too many files have changed in this diff Show More