[canvas] change surface/canvas APIs to treat canvas a 'just another kind of surface', and split canvas implementation (managed by surface) from canvas _command buffer_ and implicit context (represented by mg_canvas)

This commit is contained in:
Martin Fouilleul 2023-04-25 19:13:15 +02:00
parent 32d7d91893
commit 346979a21a
14 changed files with 2277 additions and 2114 deletions

View File

@ -52,8 +52,6 @@ mg_font create_font()
int main()
{
LogLevel(LOG_LEVEL_WARNING);
mp_init();
mp_clock_init(); //TODO put that in mp_init()?
@ -63,11 +61,10 @@ int main()
mp_rect contentRect = mp_window_get_content_rect(window);
//NOTE: create surface
mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT);
mg_surface surface = mg_surface_create_for_window(window, MG_CANVAS);
mg_surface_swap_interval(surface, 0);
//TODO: create canvas
mg_canvas canvas = mg_canvas_create(surface);
mg_canvas canvas = mg_canvas_create();
if(mg_canvas_is_nil(canvas))
{
@ -91,10 +88,10 @@ int main()
f64 startTime = mp_get_time(MP_CLOCK_MONOTONIC);
mp_pump_events(0);
mp_event event = {0};
while(mp_next_event(&event))
mp_event* event = 0;
while((event = mp_next_event(mem_scratch())) != 0)
{
switch(event.type)
switch(event->type)
{
case MP_EVENT_WINDOW_CLOSE:
{
@ -103,23 +100,23 @@ int main()
case MP_EVENT_KEYBOARD_KEY:
{
if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT)
if(event->key.action == MP_KEY_PRESS || event->key.action == MP_KEY_REPEAT)
{
f32 factor = (event.key.mods & MP_KEYMOD_SHIFT) ? 10 : 1;
f32 factor = (event->key.mods & MP_KEYMOD_SHIFT) ? 10 : 1;
if(event.key.code == MP_KEY_LEFT)
if(event->key.code == MP_KEY_LEFT)
{
x-=0.3*factor;
}
else if(event.key.code == MP_KEY_RIGHT)
else if(event->key.code == MP_KEY_RIGHT)
{
x+=0.3*factor;
}
else if(event.key.code == MP_KEY_UP)
else if(event->key.code == MP_KEY_UP)
{
y-=0.3*factor;
}
else if(event.key.code == MP_KEY_DOWN)
else if(event->key.code == MP_KEY_DOWN)
{
y+=0.3*factor;
}
@ -154,55 +151,47 @@ int main()
x += dx;
y += dy;
// background
mg_set_color_rgba(0, 1, 1, 1);
mg_clear();
// head
mg_set_color_rgba(1, 1, 0, 1);
mg_circle_fill(x, y, 200);
// smile
f32 frown = frameTime > 0.033 ? -100 : 0;
mg_set_color_rgba(0, 0, 0, 1);
mg_set_width(20);
mg_move_to(x-100, y+100);
mg_cubic_to(x-50, y+150+frown, x+50, y+150+frown, x+100, y+100);
mg_stroke();
// eyes
mg_ellipse_fill(x-70, y-50, 30, 50);
mg_ellipse_fill(x+70, y-50, 30, 50);
// text
mg_set_color_rgba(0, 0, 1, 1);
mg_set_font(font);
mg_set_font_size(12);
mg_move_to(50, 600-50);
str8 text = str8_pushf(mem_scratch(),
"Milepost vector graphics test program (frame time = %fs, fps = %f)...",
frameTime,
1./frameTime);
mg_text_outlines(text);
mg_fill();
printf("Milepost vector graphics test program (frame time = %fs, fps = %f)...\n",
frameTime,
1./frameTime);
mg_surface_prepare(surface);
// background
mg_set_color_rgba(0, 1, 1, 1);
mg_clear();
mg_set_color_rgba(1, 0, 0, 1);
mg_set_width(2);
mg_rectangle_stroke(304, 100, 300, 250);
mg_clip_push(304, 100, 300, 250);
// head
mg_set_color_rgba(1, 1, 0, 1);
mg_circle_fill(x, y, 200);
// smile
f32 frown = frameTime > 0.033 ? -100 : 0;
mg_set_color_rgba(0, 0, 0, 1);
mg_set_width(20);
mg_move_to(x-100, y+100);
mg_cubic_to(x-50, y+150+frown, x+50, y+150+frown, x+100, y+100);
mg_stroke();
// eyes
mg_ellipse_fill(x-70, y-50, 30, 50);
mg_ellipse_fill(x+70, y-50, 30, 50);
mg_clip_pop();
// text
mg_set_color_rgba(0, 0, 1, 1);
mg_set_font(font);
mg_set_font_size(12);
mg_move_to(50, 600-50);
str8 text = str8_pushf(mem_scratch(),
"Milepost vector graphics test program (frame time = %fs, fps = %f)...",
frameTime,
1./frameTime);
mg_text_outlines(text);
mg_fill();
printf("Milepost vector graphics test program (frame time = %fs, fps = %f)...\n",
frameTime,
1./frameTime);
mg_flush();
mg_flush(surface);
mg_surface_present(surface);
mem_arena_clear(mem_scratch());

View File

@ -94,7 +94,6 @@ mg_font create_font(const char* path)
int main()
{
LogLevel(LOG_LEVEL_MESSAGE);
mp_init();
mp_clock_init();
@ -105,10 +104,10 @@ int main()
//NOTE: create surface, canvas and font
mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT);
mg_surface surface = mg_surface_create_for_window(window, MG_CANVAS);
mg_surface_swap_interval(surface, 0);
mg_canvas canvas = mg_canvas_create(surface);
mg_canvas canvas = mg_canvas_create();
const int fontCount = 3;
int fontIndex = 0;
@ -153,15 +152,19 @@ int main()
f32 startX = 10;
f32 startY = 10 + lineHeights[fontIndex];
mp_input_state inputState = {0};
while(!mp_should_quit())
{
f64 startFrameTime = mp_get_time(MP_CLOCK_MONOTONIC);
mp_pump_events(0);
mp_event event = {0};
while(mp_next_event(&event))
mp_event* event = 0;
while((event = mp_next_event(mem_scratch())) != 0)
{
switch(event.type)
mp_input_process_event(&inputState, event);
switch(event->type)
{
case MP_EVENT_WINDOW_CLOSE:
{
@ -170,12 +173,12 @@ int main()
case MP_EVENT_MOUSE_BUTTON:
{
if(event.key.code == MP_MOUSE_LEFT)
if(event->key.code == MP_MOUSE_LEFT)
{
if(event.key.action == MP_KEY_PRESS)
if(event->key.action == MP_KEY_PRESS)
{
tracked = true;
vec2 mousePos = mp_mouse_position();
vec2 mousePos = mp_mouse_position(&inputState);
trackPoint.x = mousePos.x/zoom - startX;
trackPoint.y = mousePos.y/zoom - startY;
}
@ -188,11 +191,11 @@ int main()
case MP_EVENT_MOUSE_WHEEL:
{
vec2 mousePos = mp_mouse_position();
vec2 mousePos = mp_mouse_position(&inputState);
f32 trackX = mousePos.x/zoom - startX;
f32 trackY = mousePos.y/zoom - startY;
zoom *= 1 + event.move.deltaY * 0.01;
zoom *= 1 + event->move.deltaY * 0.01;
zoom = Clamp(zoom, 0.2, 10);
startX = mousePos.x/zoom - trackX;
@ -201,7 +204,7 @@ int main()
case MP_EVENT_KEYBOARD_KEY:
{
if(event.key.code == MP_KEY_SPACE && event.key.action == MP_KEY_PRESS)
if(event->key.code == MP_KEY_SPACE && event->key.action == MP_KEY_PRESS)
{
fontIndex = (fontIndex+1)%fontCount;
}
@ -214,7 +217,7 @@ int main()
if(tracked)
{
vec2 mousePos = mp_mouse_position();
vec2 mousePos = mp_mouse_position(&inputState);
startX = mousePos.x/zoom - trackPoint.x;
startY = mousePos.y/zoom - trackPoint.y;
}
@ -289,8 +292,7 @@ int main()
f64 startFlushTime = mp_get_time(MP_CLOCK_MONOTONIC);
mg_surface_prepare(surface);
mg_flush();
mg_flush(surface);
f64 startPresentTime = mp_get_time(MP_CLOCK_MONOTONIC);
mg_surface_present(surface);
@ -306,6 +308,7 @@ int main()
(startPresentTime - startFlushTime)*1000,
(endFrameTime - startPresentTime)*1000);
mp_input_next_frame(&inputState);
mem_arena_clear(mem_scratch());
}

View File

@ -15,8 +15,6 @@
#include"milepost.h"
#define LOG_SUBSYSTEM "Main"
#include"tiger.c"
mg_font create_font()
@ -53,8 +51,6 @@ mg_font create_font()
int main()
{
LogLevel(LOG_LEVEL_WARNING);
mp_init();
mp_clock_init(); //TODO put that in mp_init()?
@ -64,11 +60,11 @@ int main()
mp_rect contentRect = mp_window_get_content_rect(window);
//NOTE: create surface
mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT);
mg_surface surface = mg_surface_create_for_window(window, MG_CANVAS);
mg_surface_swap_interval(surface, 0);
//TODO: create canvas
mg_canvas canvas = mg_canvas_create(surface);
mg_canvas canvas = mg_canvas_create();
if(mg_canvas_is_nil(canvas))
{
@ -92,15 +88,19 @@ int main()
f64 frameTime = 0;
mp_input_state inputState = {0};
while(!mp_should_quit())
{
f64 startTime = mp_get_time(MP_CLOCK_MONOTONIC);
mp_pump_events(0);
mp_event event = {0};
while(mp_next_event(&event))
mp_event* event = 0;
while((event = mp_next_event(mem_scratch())) != 0)
{
switch(event.type)
mp_input_process_event(&inputState, event);
switch(event->type)
{
case MP_EVENT_WINDOW_CLOSE:
{
@ -109,18 +109,18 @@ int main()
case MP_EVENT_WINDOW_RESIZE:
{
mp_rect frame = {0, 0, event.frame.rect.w, event.frame.rect.h};
mp_rect frame = {0, 0, event->frame.rect.w, event->frame.rect.h};
mg_surface_set_frame(surface, frame);
} break;
case MP_EVENT_MOUSE_BUTTON:
{
if(event.key.code == MP_MOUSE_LEFT)
if(event->key.code == MP_MOUSE_LEFT)
{
if(event.key.action == MP_KEY_PRESS)
if(event->key.action == MP_KEY_PRESS)
{
tracked = true;
vec2 mousePos = mp_mouse_position();
vec2 mousePos = mp_mouse_position(&inputState);
trackPoint.x = (mousePos.x - startX)/zoom;
trackPoint.y = (mousePos.y - startY)/zoom;
}
@ -133,11 +133,11 @@ int main()
case MP_EVENT_MOUSE_WHEEL:
{
vec2 mousePos = mp_mouse_position();
vec2 mousePos = mp_mouse_position(&inputState);
f32 pinX = (mousePos.x - startX)/zoom;
f32 pinY = (mousePos.y - startY)/zoom;
zoom *= 1 + event.move.deltaY * 0.01;
zoom *= 1 + event->move.deltaY * 0.01;
zoom = Clamp(zoom, 0.5, 5);
startX = mousePos.x - pinX*zoom;
@ -146,9 +146,9 @@ int main()
case MP_EVENT_KEYBOARD_KEY:
{
if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT)
if(event->key.action == MP_KEY_PRESS || event->key.action == MP_KEY_REPEAT)
{
switch(event.key.code)
switch(event->key.code)
{
case MP_KEY_SPACE:
singlePath = !singlePath;
@ -156,7 +156,7 @@ int main()
case MP_KEY_UP:
{
if(event.key.mods & MP_KEYMOD_SHIFT)
if(event->key.mods & MP_KEYMOD_SHIFT)
{
singlePathIndex++;
}
@ -168,7 +168,7 @@ int main()
case MP_KEY_DOWN:
{
if(event.key.mods & MP_KEYMOD_SHIFT)
if(event->key.mods & MP_KEYMOD_SHIFT)
{
singlePathIndex--;
}
@ -188,7 +188,7 @@ int main()
if(tracked)
{
vec2 mousePos = mp_mouse_position();
vec2 mousePos = mp_mouse_position(&inputState);
startX = mousePos.x - trackPoint.x*zoom;
startY = mousePos.y - trackPoint.y*zoom;
}
@ -228,9 +228,10 @@ int main()
frameTime,
1./frameTime);
mg_flush();
mg_flush(surface);
mg_surface_present(surface);
mp_input_next_frame(&inputState);
mem_arena_clear(mem_scratch());
frameTime = mp_get_time(MP_CLOCK_MONOTONIC) - startTime;
}

File diff suppressed because it is too large Load Diff

View File

@ -27,43 +27,51 @@ typedef enum {
//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 defined(PLATFORM_MACOS)
#ifndef MG_COMPILE_BACKEND_METAL
#define MG_COMPILE_BACKEND_METAL 1
#if PLATFORM_MACOS
#ifndef MG_COMPILE_METAL
#define MG_COMPILE_METAL 1
#endif
#ifndef MG_COMPILE_BACKEND_GLES
#define MG_COMPILE_BACKEND_GLES 1
#ifndef MG_COMPILE_GLES
#define MG_COMPILE_GLES 1
#endif
#ifndef MG_COMPILE_BACKEND_CANVAS
#define MG_COMPILE_BACKEND_CANVAS 1
#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."
#endif
#define MG_COMPILE_CANVAS 1
#endif
#define MG_COMPILE_BACKEND_GL 0
#define MG_COMPILE_GL 0
#elif defined(PLATFORM_WIN64)
#ifndef MG_COMPILE_BACKEND_GL
#define MG_COMPILE_BACKEND_GL 1
#elif PLATFORM_WINDOWS
#ifndef MG_COMPILE_GL
#define MG_COMPILE_GL 1
#endif
#ifndef MG_COMPILE_BACKEND_GLES
#define MG_COMPILE_BACKEND_GLES 1
#ifndef MG_COMPILE_GLES
#define MG_COMPILE_GLES 1
#endif
#ifndef MG_COMPILE_BACKEND_CANVAS
#define MG_COMPILE_BACKEND_CANVAS 1
#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."
#endif
#define MG_COMPILE_CANVAS 1
#endif
#elif defined(PLATFORM_LINUX)
#ifndef MG_COMPILE_BACKEND_GL
#define MG_COMPILE_BACKEND_GL 1
#elif PLATFORM_LINUX
#ifndef MG_COMPILE_GL
#define MG_COMPILE_GL 1
#endif
#ifndef MG_COMPILE_BACKEND_CANVAS
#define MG_COMPILE_BACKEND_CANVAS 1
#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."
#endif
#define MG_COMPILE_CANVAS 1
#endif
#endif
//NOTE: these macros are used to select backend-specific APIs to include when using milepost
@ -170,14 +178,11 @@ typedef struct mg_text_extents
MP_API mg_canvas mg_canvas_nil(void);
MP_API bool mg_canvas_is_nil(mg_canvas canvas);
MP_API mg_canvas mg_canvas_create(mg_surface surface);
MP_API mg_canvas mg_canvas_create();
MP_API void mg_canvas_destroy(mg_canvas canvas);
mg_canvas mg_canvas_set_current(mg_canvas canvas);
MP_API void mg_flush(mg_surface surface); //TODO change to mg_canvas_render(mg_surface surface, mg_canvas canvas);
MP_API mg_canvas mg_canvas_prepare(mg_canvas canvas);
MP_API void mg_flush(void);
MP_API void mg_present(void);
MP_API vec2 mg_canvas_size(void);
//------------------------------------------------------------------------------------------
//NOTE(martin): fonts
//------------------------------------------------------------------------------------------
@ -212,10 +217,10 @@ MP_API mp_rect mg_text_bounding_box(mg_font font, f32 fontSize, str8 text);
MP_API mg_image mg_image_nil();
MP_API bool mg_image_is_nil(mg_image a);
MP_API mg_image mg_image_create(u32 width, u32 height);
MP_API mg_image mg_image_create_from_rgba8(u32 width, u32 height, u8* pixels);
MP_API mg_image mg_image_create_from_data(str8 data, bool flip);
MP_API mg_image mg_image_create_from_file(str8 path, bool flip);
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);
MP_API void mg_image_destroy(mg_image image);

View File

@ -20,6 +20,7 @@ extern "C" {
// surface interface
//---------------------------------------------------------------
typedef struct mg_surface_data mg_surface_data;
typedef struct mg_canvas_backend mg_canvas_backend;
typedef void (*mg_surface_destroy_proc)(mg_surface_data* surface);
typedef void (*mg_surface_prepare_proc)(mg_surface_data* surface);
@ -51,6 +52,9 @@ typedef struct mg_surface_data
mg_surface_native_layer_proc nativeLayer;
mg_surface_remote_id_proc remoteID;
mg_surface_host_connect_proc hostConnect;
mg_canvas_backend* backend;
} mg_surface_data;
mg_surface mg_surface_alloc_handle(mg_surface_data* surface);
@ -69,6 +73,7 @@ typedef struct mg_image_data
{
list_elt listElt;
u32 generation;
mg_surface surface;
vec2 size;
} mg_image_data;
@ -104,7 +109,6 @@ typedef struct mg_vertex_layout
} mg_vertex_layout;
typedef struct mg_canvas_backend mg_canvas_backend;
typedef void (*mg_canvas_backend_destroy_proc)(mg_canvas_backend* backend);
typedef void (*mg_canvas_backend_begin_proc)(mg_canvas_backend* backend, mg_color clearColor);

View File

@ -14,11 +14,11 @@
#include"platform/std_log.c"
#if defined(PLATFORM_WIN64)
#if PLATFORM_WINDOWS
#include"platform/win32_memory.c"
#include"platform/win32_clock.c"
//TODO
#elif defined(PLATFORM_MACOS)
#elif PLATFORM_MACOS
#include"platform/unix_memory.c"
#include"platform/osx_clock.c"
/*
@ -27,7 +27,7 @@
#include"platform/posix_socket.c"
*/
#elif defined(PLATFORM_LINUX)
#elif PLATFORM_LINUX
#include"platform/unix_base_memory.c"
#include"platform/linux_clock.c"
/*
@ -52,24 +52,27 @@
// app/graphics layer
//---------------------------------------------------------------
#if defined(PLATFORM_WIN64)
#if PLATFORM_WINDOWS
#include"win32_app.c"
#include"graphics.c"
#if MG_COMPILE_BACKEND_GL || MG_COMPILE_BACKEND_GLES
#if MG_COMPILE_GL || MG_COMPILE_GLES
#include"gl_loader.c"
#endif
#if MG_COMPILE_BACKEND_GL
#if MG_COMPILE_GL
#include"wgl_surface.c"
#endif
#if MG_COMPILE_CANVAS
#include"gl_canvas.c"
#endif
#if MG_COMPILE_BACKEND_GLES
#if MG_COMPILE_GLES
#include"egl_surface.c"
#endif
#elif defined(PLATFORM_MACOS)
#elif PLATFORM_MACOS
//NOTE: macos application layer and graphics backends are defined in milepost.m
#else
#error "Unsupported platform"

View File

@ -10,21 +10,15 @@
#include"osx_app.m"
#include"graphics.c"
#if MG_COMPILE_BACKEND_METAL
#if MG_COMPILE_METAL
#include"mtl_surface.m"
// #include"mtl_canvas.m"
#endif
#if MG_COMPILE_CANVAS
#include"mtl_renderer.m"
#endif
#if MG_COMPILE_BACKEND_GLES
#if MG_COMPILE_GLES
#include"gl_loader.c"
#include"egl_surface.c"
#endif
/*
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#include"osx_gles_surface.m"
#pragma clang diagnostic pop
*/
//#include"osx_surface_client.m"

View File

@ -14,9 +14,9 @@
#include"platform.h"
#include"ringbuffer.h"
#if defined(PLATFORM_WIN64) || defined(PLATFORM_WIN32)
#if PLATFORM_WINDOWS
#include"win32_app.h"
#elif defined(PLATFORM_MACOS)
#elif PLATFORM_MACOS
#include"osx_app.h"
#else
#error "platform not supported yet"

View File

@ -23,7 +23,7 @@ const int MG_MTL_INPUT_BUFFERS_COUNT = 3,
typedef struct mg_mtl_canvas_backend
{
mg_canvas_backend interface;
mg_surface surface;
mg_mtl_surface* surface;
id<MTLComputePipelineState> pathPipeline;
id<MTLComputePipelineState> segmentPipeline;
@ -64,15 +64,6 @@ typedef struct mg_mtl_image_data
id<MTLTexture> texture;
} mg_mtl_image_data;
static void mg_update_path_extents(vec4* extents, vec2 p)
{
extents->x = minimum(extents->x, p.x);
extents->y = minimum(extents->y, p.y);
extents->z = maximum(extents->z, p.x);
extents->w = maximum(extents->w, p.y);
}
void mg_mtl_print_log(int bufferIndex, id<MTLBuffer> logBuffer, id<MTLBuffer> logOffsetBuffer)
{
char* log = [logBuffer contents];
@ -106,6 +97,14 @@ typedef struct mg_mtl_encoding_context
} mg_mtl_encoding_context;
static void mg_update_path_extents(vec4* extents, vec2 p)
{
extents->x = minimum(extents->x, p.x);
extents->y = minimum(extents->y, p.y);
extents->z = maximum(extents->z, p.x);
extents->w = maximum(extents->w, p.y);
}
void mg_mtl_canvas_encode_element(mg_mtl_encoding_context* context, mg_path_elt_type kind, vec2* p)
{
mg_mtl_path_elt* mtlElt = &context->elementBufferData[context->mtlEltCount];
@ -147,6 +146,198 @@ void mg_mtl_canvas_encode_element(mg_mtl_encoding_context* context, mg_path_elt_
}
}
bool mg_intersect_hull_legs(vec2 p0, vec2 p1, vec2 p2, vec2 p3, vec2* intersection)
{
/*NOTE: check intersection of lines (p0-p1) and (p2-p3)
P = p0 + u(p1-p0)
P = p2 + w(p3-p2)
*/
bool found = false;
f32 den = (p0.x - p1.x)*(p2.y - p3.y) - (p0.y - p1.y)*(p2.x - p3.x);
if(fabs(den) > 0.0001)
{
f32 u = ((p0.x - p2.x)*(p2.y - p3.y) - (p0.y - p2.y)*(p2.x - p3.x))/den;
f32 w = ((p0.x - p2.x)*(p0.y - p1.y) - (p0.y - p2.y)*(p0.x - p1.x))/den;
intersection->x = p0.x + u*(p1.x - p0.x);
intersection->y = p0.y + u*(p1.y - p0.y);
found = true;
}
return(found);
}
bool mg_offset_hull(int count, vec2* p, vec2* result, f32 offset)
{
//NOTE: we should have no more than two coincident points here. This means the leg between
// those two points can't be offset, but we can set a double point at the start of first leg,
// end of first leg, or we can join the first and last leg to create a missing middle one
vec2 legs[3][2] = {0};
bool valid[3] = {0};
for(int i=0; i<count-1; i++)
{
vec2 n = {p[i].y - p[i+1].y,
p[i+1].x - p[i].x};
f32 norm = sqrt(n.x*n.x + n.y*n.y);
if(norm >= 1e-6)
{
n = vec2_mul(offset/norm, n);
legs[i][0] = vec2_add(p[i], n);
legs[i][1] = vec2_add(p[i+1], n);
valid[i] = true;
}
}
//NOTE: now we find intersections
// first point is either the start of the first or second leg
if(valid[0])
{
result[0] = legs[0][0];
}
else
{
ASSERT(valid[1]);
result[0] = legs[1][0];
}
for(int i=1; i<count-1; i++)
{
//NOTE: we're computing the control point i, at the end of leg (i-1)
if(!valid[i-1])
{
ASSERT(valid[i]);
result[i] = legs[i][0];
}
else if(!valid[i])
{
ASSERT(valid[i-1]);
result[i] = legs[i-1][0];
}
else
{
if(!mg_intersect_hull_legs(legs[i-1][0], legs[i-1][1], legs[i][0], legs[i][1], &result[i]))
{
// legs don't intersect.
return(false);
}
}
}
if(valid[count-2])
{
result[count-1] = legs[count-2][1];
}
else
{
ASSERT(valid[count-3]);
result[count-1] = legs[count-3][1];
}
return(true);
}
vec2 mg_quadratic_get_point(vec2 p[3], f32 t)
{
vec2 r;
f32 oneMt = 1-t;
f32 oneMt2 = Square(oneMt);
f32 t2 = Square(t);
r.x = oneMt2*p[0].x + 2*oneMt*t*p[1].x + t2*p[2].x;
r.y = oneMt2*p[0].y + 2*oneMt*t*p[1].y + t2*p[2].y;
return(r);
}
void mg_quadratic_split(vec2 p[3], f32 t, vec2 outLeft[3], vec2 outRight[3])
{
//DEBUG
__mgCurrentCanvas->splitCount++;
//NOTE(martin): split bezier curve p at parameter t, using De Casteljau's algorithm
// the q_n are the points along the hull's segments at parameter t
// s is the split point.
f32 oneMt = 1-t;
vec2 q0 = {oneMt*p[0].x + t*p[1].x,
oneMt*p[0].y + t*p[1].y};
vec2 q1 = {oneMt*p[1].x + t*p[2].x,
oneMt*p[1].y + t*p[2].y};
vec2 s = {oneMt*q0.x + t*q1.x,
oneMt*q0.y + t*q1.y};
outLeft[0] = p[0];
outLeft[1] = q0;
outLeft[2] = s;
outRight[0] = s;
outRight[1] = q1;
outRight[2] = p[2];
}
vec2 mg_cubic_get_point(vec2 p[4], f32 t)
{
vec2 r;
f32 oneMt = 1-t;
f32 oneMt2 = Square(oneMt);
f32 oneMt3 = oneMt2*oneMt;
f32 t2 = Square(t);
f32 t3 = t2*t;
r.x = oneMt3*p[0].x + 3*oneMt2*t*p[1].x + 3*oneMt*t2*p[2].x + t3*p[3].x;
r.y = oneMt3*p[0].y + 3*oneMt2*t*p[1].y + 3*oneMt*t2*p[2].y + t3*p[3].y;
return(r);
}
void mg_cubic_split(vec2 p[4], f32 t, vec2 outLeft[4], vec2 outRight[4])
{
//NOTE(martin): split bezier curve p at parameter t, using De Casteljau's algorithm
// the q_n are the points along the hull's segments at parameter t
// the r_n are the points along the (q_n, q_n+1) segments at parameter t
// s is the split point.
vec2 q0 = {(1-t)*p[0].x + t*p[1].x,
(1-t)*p[0].y + t*p[1].y};
vec2 q1 = {(1-t)*p[1].x + t*p[2].x,
(1-t)*p[1].y + t*p[2].y};
vec2 q2 = {(1-t)*p[2].x + t*p[3].x,
(1-t)*p[2].y + t*p[3].y};
vec2 r0 = {(1-t)*q0.x + t*q1.x,
(1-t)*q0.y + t*q1.y};
vec2 r1 = {(1-t)*q1.x + t*q2.x,
(1-t)*q1.y + t*q2.y};
vec2 s = {(1-t)*r0.x + t*r1.x,
(1-t)*r0.y + t*r1.y};;
outLeft[0] = p[0];
outLeft[1] = q0;
outLeft[2] = r0;
outLeft[3] = s;
outRight[0] = s;
outRight[1] = r1;
outRight[2] = q2;
outRight[3] = p[3];
}
void mg_mtl_render_stroke_line(mg_mtl_encoding_context* context, vec2* p)
{
f32 width = context->primitive->attributes.width;
@ -771,40 +962,36 @@ void mg_mtl_render_batch(mg_mtl_canvas_backend* backend,
void mg_mtl_canvas_resize(mg_mtl_canvas_backend* backend, vec2 size)
{
mg_mtl_surface* surface = (mg_mtl_surface*)mg_surface_data_from_handle(backend->surface);
if(surface)
@autoreleasepool
{
@autoreleasepool
if(backend->screenTilesBuffer)
{
if(backend->screenTilesBuffer)
{
[backend->screenTilesBuffer release];
backend->screenTilesBuffer = nil;
}
int tileSize = MG_MTL_TILE_SIZE;
int nTilesX = (int)(size.x + tileSize - 1)/tileSize;
int nTilesY = (int)(size.y + tileSize - 1)/tileSize;
MTLResourceOptions bufferOptions = MTLResourceStorageModePrivate;
backend->screenTilesBuffer = [surface->device newBufferWithLength: nTilesX*nTilesY*sizeof(int)
options: bufferOptions];
if(backend->outTexture)
{
[backend->outTexture release];
backend->outTexture = nil;
}
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
texDesc.textureType = MTLTextureType2D;
texDesc.storageMode = MTLStorageModePrivate;
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm;
texDesc.width = size.x;
texDesc.height = size.y;
backend->outTexture = [surface->device newTextureWithDescriptor:texDesc];
backend->frameSize = size;
[backend->screenTilesBuffer release];
backend->screenTilesBuffer = nil;
}
int tileSize = MG_MTL_TILE_SIZE;
int nTilesX = (int)(size.x + tileSize - 1)/tileSize;
int nTilesY = (int)(size.y + tileSize - 1)/tileSize;
MTLResourceOptions bufferOptions = MTLResourceStorageModePrivate;
backend->screenTilesBuffer = [backend->surface->device newBufferWithLength: nTilesX*nTilesY*sizeof(int)
options: bufferOptions];
if(backend->outTexture)
{
[backend->outTexture release];
backend->outTexture = nil;
}
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
texDesc.textureType = MTLTextureType2D;
texDesc.storageMode = MTLStorageModePrivate;
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm;
texDesc.width = size.x;
texDesc.height = size.y;
backend->outTexture = [backend->surface->device newTextureWithDescriptor:texDesc];
backend->frameSize = size;
}
}
@ -829,10 +1016,10 @@ void mg_mtl_canvas_render(mg_canvas_backend* interface,
/////////////////////////////////////////////////////////////////////////////////////
//NOTE: prepare rendering
mg_mtl_surface* surface = (mg_mtl_surface*)mg_surface_data_from_handle(backend->surface);
ASSERT(surface && surface->interface.api == MG_METAL);
mg_mtl_surface* surface = backend->surface;
mp_rect frame = surface->interface.getFrame((mg_surface_data*)surface);
mp_rect frame = mg_surface_get_frame(backend->surface);
f32 scale = surface->mtlLayer.contentsScale;
vec2 viewportSize = {frame.w * scale, frame.h * scale};
int tileSize = MG_MTL_TILE_SIZE;
@ -1068,34 +1255,31 @@ mg_image_data* mg_mtl_canvas_image_create(mg_canvas_backend* interface, vec2 siz
{
mg_mtl_image_data* image = 0;
mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface;
mg_mtl_surface* surface = (mg_mtl_surface*)mg_surface_data_from_handle(backend->surface);
mg_mtl_surface* surface = backend->surface;
if(surface && surface->interface.api == MG_METAL)
@autoreleasepool
{
@autoreleasepool{
image = malloc_type(mg_mtl_image_data);
if(image)
{
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
texDesc.textureType = MTLTextureType2D;
texDesc.storageMode = MTLStorageModeManaged;
texDesc.usage = MTLTextureUsageShaderRead;
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm;
texDesc.width = size.x;
texDesc.height = size.y;
image = malloc_type(mg_mtl_image_data);
if(image)
image->texture = [surface->device newTextureWithDescriptor:texDesc];
if(image->texture != nil)
{
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
texDesc.textureType = MTLTextureType2D;
texDesc.storageMode = MTLStorageModeManaged;
texDesc.usage = MTLTextureUsageShaderRead;
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm;
texDesc.width = size.x;
texDesc.height = size.y;
image->texture = [surface->device newTextureWithDescriptor:texDesc];
if(image->texture != nil)
{
[image->texture retain];
image->interface.size = size;
}
else
{
free(image);
image = 0;
}
[image->texture retain];
image->interface.size = size;
}
else
{
free(image);
image = 0;
}
}
}
@ -1129,153 +1313,166 @@ const u32 MG_MTL_PATH_BUFFER_SIZE = (4<<20)*sizeof(mg_mtl_path),
MG_MTL_TILE_QUEUE_BUFFER_SIZE = (4<<20)*sizeof(mg_mtl_tile_queue),
MG_MTL_TILE_OP_BUFFER_SIZE = (4<<20)*sizeof(mg_mtl_tile_op);
mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface)
mg_canvas_backend* mtl_canvas_backend_create(mg_mtl_surface* surface)
{
mg_mtl_canvas_backend* backend = 0;
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->api == MG_METAL)
{
mg_mtl_surface* metalSurface = (mg_mtl_surface*)surfaceData;
backend = malloc_type(mg_mtl_canvas_backend);
memset(backend, 0, sizeof(mg_mtl_canvas_backend));
backend = malloc_type(mg_mtl_canvas_backend);
memset(backend, 0, sizeof(mg_mtl_canvas_backend));
backend->msaaCount = MG_MTL_MSAA_COUNT;
backend->surface = surface;
backend->msaaCount = MG_MTL_MSAA_COUNT;
backend->surface = surface;
//NOTE(martin): setup interface functions
backend->interface.destroy = mg_mtl_canvas_destroy;
backend->interface.render = mg_mtl_canvas_render;
backend->interface.imageCreate = mg_mtl_canvas_image_create;
backend->interface.imageDestroy = mg_mtl_canvas_image_destroy;
backend->interface.imageUploadRegion = mg_mtl_canvas_image_upload_region;
//NOTE(martin): setup interface functions
backend->interface.destroy = mg_mtl_canvas_destroy;
backend->interface.render = mg_mtl_canvas_render;
backend->interface.imageCreate = mg_mtl_canvas_image_create;
backend->interface.imageDestroy = mg_mtl_canvas_image_destroy;
backend->interface.imageUploadRegion = mg_mtl_canvas_image_upload_region;
@autoreleasepool{
//NOTE: load metal library
str8 shaderPath = mp_app_get_resource_path(mem_scratch(), "mtl_renderer.metallib");
NSString* metalFileName = [[NSString alloc] initWithBytes: shaderPath.ptr length:shaderPath.len encoding: NSUTF8StringEncoding];
NSError* err = 0;
id<MTLLibrary> library = [surface->device newLibraryWithFile: metalFileName error:&err];
if(err != nil)
{
const char* errStr = [[err localizedDescription] UTF8String];
log_error("error : %s\n", errStr);
return(0);
}
id<MTLFunction> pathFunction = [library newFunctionWithName:@"mtl_path_setup"];
id<MTLFunction> segmentFunction = [library newFunctionWithName:@"mtl_segment_setup"];
id<MTLFunction> backpropFunction = [library newFunctionWithName:@"mtl_backprop"];
id<MTLFunction> mergeFunction = [library newFunctionWithName:@"mtl_merge"];
id<MTLFunction> rasterFunction = [library newFunctionWithName:@"mtl_raster"];
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"mtl_vertex_shader"];
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"mtl_fragment_shader"];
@autoreleasepool{
//NOTE: load metal library
str8 shaderPath = mp_app_get_resource_path(mem_scratch(), "mtl_renderer.metallib");
NSString* metalFileName = [[NSString alloc] initWithBytes: shaderPath.ptr length:shaderPath.len encoding: NSUTF8StringEncoding];
NSError* err = 0;
id<MTLLibrary> library = [metalSurface->device newLibraryWithFile: metalFileName error:&err];
if(err != nil)
{
const char* errStr = [[err localizedDescription] UTF8String];
log_error("error : %s\n", errStr);
return(0);
}
id<MTLFunction> pathFunction = [library newFunctionWithName:@"mtl_path_setup"];
id<MTLFunction> segmentFunction = [library newFunctionWithName:@"mtl_segment_setup"];
id<MTLFunction> backpropFunction = [library newFunctionWithName:@"mtl_backprop"];
id<MTLFunction> mergeFunction = [library newFunctionWithName:@"mtl_merge"];
id<MTLFunction> rasterFunction = [library newFunctionWithName:@"mtl_raster"];
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"mtl_vertex_shader"];
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"mtl_fragment_shader"];
//NOTE: create pipelines
NSError* error = NULL;
//NOTE: create pipelines
NSError* error = NULL;
backend->pathPipeline = [surface->device newComputePipelineStateWithFunction: pathFunction
error:&error];
backend->pathPipeline = [metalSurface->device newComputePipelineStateWithFunction: pathFunction
error:&error];
backend->segmentPipeline = [surface->device newComputePipelineStateWithFunction: segmentFunction
error:&error];
backend->segmentPipeline = [metalSurface->device newComputePipelineStateWithFunction: segmentFunction
error:&error];
backend->backpropPipeline = [surface->device newComputePipelineStateWithFunction: backpropFunction
error:&error];
backend->backpropPipeline = [metalSurface->device newComputePipelineStateWithFunction: backpropFunction
error:&error];
backend->mergePipeline = [surface->device newComputePipelineStateWithFunction: mergeFunction
error:&error];
backend->mergePipeline = [metalSurface->device newComputePipelineStateWithFunction: mergeFunction
error:&error];
backend->rasterPipeline = [surface->device newComputePipelineStateWithFunction: rasterFunction
error:&error];
backend->rasterPipeline = [metalSurface->device newComputePipelineStateWithFunction: rasterFunction
error:&error];
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
pipelineStateDescriptor.label = @"blit pipeline";
pipelineStateDescriptor.vertexFunction = vertexFunction;
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
pipelineStateDescriptor.colorAttachments[0].pixelFormat = surface->mtlLayer.pixelFormat;
pipelineStateDescriptor.colorAttachments[0].blendingEnabled = YES;
pipelineStateDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
pipelineStateDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorOne;
pipelineStateDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
pipelineStateDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
pipelineStateDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
pipelineStateDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
pipelineStateDescriptor.label = @"blit pipeline";
pipelineStateDescriptor.vertexFunction = vertexFunction;
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
pipelineStateDescriptor.colorAttachments[0].pixelFormat = metalSurface->mtlLayer.pixelFormat;
pipelineStateDescriptor.colorAttachments[0].blendingEnabled = YES;
pipelineStateDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
pipelineStateDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorOne;
pipelineStateDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
pipelineStateDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
pipelineStateDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
pipelineStateDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
backend->blitPipeline = [surface->device newRenderPipelineStateWithDescriptor: pipelineStateDescriptor error:&err];
backend->blitPipeline = [metalSurface->device newRenderPipelineStateWithDescriptor: pipelineStateDescriptor error:&err];
//NOTE: create textures
mp_rect frame = surface->interface.getFrame((mg_surface_data*)surface);
f32 scale = surface->mtlLayer.contentsScale;
//NOTE: create textures
mp_rect frame = mg_surface_get_frame(surface);
f32 scale = metalSurface->mtlLayer.contentsScale;
backend->frameSize = (vec2){frame.w*scale, frame.h*scale};
backend->frameSize = (vec2){frame.w*scale, frame.h*scale};
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
texDesc.textureType = MTLTextureType2D;
texDesc.storageMode = MTLStorageModePrivate;
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm;
texDesc.width = backend->frameSize.x;
texDesc.height = backend->frameSize.y;
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
texDesc.textureType = MTLTextureType2D;
texDesc.storageMode = MTLStorageModePrivate;
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm;
texDesc.width = backend->frameSize.x;
texDesc.height = backend->frameSize.y;
backend->outTexture = [surface->device newTextureWithDescriptor:texDesc];
backend->outTexture = [metalSurface->device newTextureWithDescriptor:texDesc];
//NOTE: create buffers
//NOTE: create buffers
backend->bufferSemaphore = dispatch_semaphore_create(MG_MTL_INPUT_BUFFERS_COUNT);
backend->bufferIndex = 0;
backend->bufferSemaphore = dispatch_semaphore_create(MG_MTL_INPUT_BUFFERS_COUNT);
backend->bufferIndex = 0;
MTLResourceOptions bufferOptions = MTLResourceCPUCacheModeWriteCombined
| MTLResourceStorageModeShared;
MTLResourceOptions bufferOptions = MTLResourceCPUCacheModeWriteCombined
| MTLResourceStorageModeShared;
for(int i=0; i<MG_MTL_INPUT_BUFFERS_COUNT; i++)
{
backend->pathBuffer[i] = [surface->device newBufferWithLength: MG_MTL_PATH_BUFFER_SIZE
options: bufferOptions];
for(int i=0; i<MG_MTL_INPUT_BUFFERS_COUNT; i++)
{
backend->pathBuffer[i] = [metalSurface->device newBufferWithLength: MG_MTL_PATH_BUFFER_SIZE
options: bufferOptions];
backend->elementBuffer[i] = [surface->device newBufferWithLength: MG_MTL_ELEMENT_BUFFER_SIZE
options: bufferOptions];
}
backend->elementBuffer[i] = [metalSurface->device newBufferWithLength: MG_MTL_ELEMENT_BUFFER_SIZE
options: bufferOptions];
}
bufferOptions = MTLResourceStorageModePrivate;
backend->segmentBuffer = [surface->device newBufferWithLength: MG_MTL_SEGMENT_BUFFER_SIZE
options: bufferOptions];
bufferOptions = MTLResourceStorageModePrivate;
backend->segmentBuffer = [metalSurface->device newBufferWithLength: MG_MTL_SEGMENT_BUFFER_SIZE
options: bufferOptions];
backend->segmentCountBuffer = [surface->device newBufferWithLength: sizeof(int)
options: bufferOptions];
backend->segmentCountBuffer = [metalSurface->device newBufferWithLength: sizeof(int)
options: bufferOptions];
backend->pathQueueBuffer = [surface->device newBufferWithLength: MG_MTL_PATH_QUEUE_BUFFER_SIZE
options: bufferOptions];
backend->tileQueueBuffer = [surface->device newBufferWithLength: MG_MTL_TILE_QUEUE_BUFFER_SIZE
options: bufferOptions];
backend->pathQueueBuffer = [metalSurface->device newBufferWithLength: MG_MTL_PATH_QUEUE_BUFFER_SIZE
options: bufferOptions];
backend->tileQueueCountBuffer = [surface->device newBufferWithLength: sizeof(int)
options: bufferOptions];
backend->tileQueueBuffer = [metalSurface->device newBufferWithLength: MG_MTL_TILE_QUEUE_BUFFER_SIZE
options: bufferOptions];
backend->tileOpBuffer = [surface->device newBufferWithLength: MG_MTL_TILE_OP_BUFFER_SIZE
options: bufferOptions];
backend->tileQueueCountBuffer = [metalSurface->device newBufferWithLength: sizeof(int)
options: bufferOptions];
backend->tileOpCountBuffer = [surface->device newBufferWithLength: sizeof(int)
options: bufferOptions];
backend->tileOpBuffer = [metalSurface->device newBufferWithLength: MG_MTL_TILE_OP_BUFFER_SIZE
options: bufferOptions];
int tileSize = MG_MTL_TILE_SIZE;
int nTilesX = (int)(frame.w * scale + tileSize - 1)/tileSize;
int nTilesY = (int)(frame.h * scale + tileSize - 1)/tileSize;
backend->screenTilesBuffer = [surface->device newBufferWithLength: nTilesX*nTilesY*sizeof(int)
options: bufferOptions];
backend->tileOpCountBuffer = [metalSurface->device newBufferWithLength: sizeof(int)
options: bufferOptions];
bufferOptions = MTLResourceStorageModeShared;
for(int i=0; i<MG_MTL_INPUT_BUFFERS_COUNT; i++)
{
backend->logBuffer[i] = [surface->device newBufferWithLength: 1<<20
options: bufferOptions];
int tileSize = MG_MTL_TILE_SIZE;
int nTilesX = (int)(frame.w * scale + tileSize - 1)/tileSize;
int nTilesY = (int)(frame.h * scale + tileSize - 1)/tileSize;
backend->screenTilesBuffer = [metalSurface->device newBufferWithLength: nTilesX*nTilesY*sizeof(int)
options: bufferOptions];
bufferOptions = MTLResourceStorageModeShared;
for(int i=0; i<MG_MTL_INPUT_BUFFERS_COUNT; i++)
{
backend->logBuffer[i] = [metalSurface->device newBufferWithLength: 1<<20
options: bufferOptions];
backend->logOffsetBuffer[i] = [metalSurface->device newBufferWithLength: sizeof(int)
options: bufferOptions];
}
backend->logOffsetBuffer[i] = [surface->device newBufferWithLength: sizeof(int)
options: bufferOptions];
}
}
return((mg_canvas_backend*)backend);
}
mg_surface_data* mtl_canvas_surface_create_for_window(mp_window window)
{
mg_mtl_surface* surface = (mg_mtl_surface*)mg_mtl_surface_create_for_window(window);
if(surface)
{
surface->interface.backend = mtl_canvas_backend_create(surface);
if(surface->interface.backend)
{
surface->interface.api = MG_CANVAS;
}
else
{
surface->interface.destroy((mg_surface_data*)surface);
surface = 0;
}
}
return((mg_surface_data*)surface);
}

View File

@ -33,7 +33,7 @@
// OS identification
//-----------------------------------------------------------------
#if defined(_WIN64)
#define PLATFORM_WIN64 1
#define PLATFORM_WINDOWS 1
#elif defined(_WIN32)
#error "Unsupported OS (32bit only version of Windows)"
#elif defined(__APPLE__) && defined(__MACH__)

View File

@ -8,7 +8,7 @@
#include<stdio.h>
#include"platform_log.c"
#if PLATFORM_WIN32 || PLATFORM_WIN64
#if PLATFORM_WINDOWS
#include<io.h>
#define isatty _isatty
#define fileno _fileno

1573
src/tmp_gl_canvas.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2293,7 +2293,7 @@ typedef struct ui_edit_command
} ui_edit_command;
#if PLATFORM_WIN64
#if PLATFORM_WINDOWS
#define OS_COPY_PASTE_MOD MP_KEYMOD_CTRL
#elif PLATFORM_MACOS
#define OS_COPY_PASTE_MOD MP_KEYMOD_CMD