Fixed indexing in gles_canvas_fragment shaders and fixed native keys buffer
This commit is contained in:
parent
8e87837fcc
commit
e0300e9e3c
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
if not exist bin mkdir bin
|
if not exist bin mkdir bin
|
||||||
|
|
||||||
|
call python scripts\embed_text.py src\gles_canvas_shaders\gles_canvas_fragment.glsl src\gles_canvas_shaders\gles_canvas_vertex.glsl --output src\gles_canvas_shaders.h
|
||||||
|
|
||||||
set INCLUDES=/I src /I src/util /I src/platform /I ext /I ext/angle_headers
|
set INCLUDES=/I src /I src/util /I src/platform /I ext /I ext/angle_headers
|
||||||
cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% /c /Fo:bin/milepost.obj src/milepost.c
|
cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GLES /std:c11 %INCLUDES% /c /Fo:bin/milepost.obj src/milepost.c
|
||||||
lib bin/milepost.obj /OUT:bin/milepost.lib
|
lib bin/milepost.obj /OUT:bin/milepost.lib
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers
|
||||||
|
cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GLES /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib /LIBPATH:../../bin libEGL.dll.lib libGLESv2.dll.lib user32.lib opengl32.lib gdi32.lib /out:../../bin/example_canvas.exe
|
|
@ -1,144 +1,153 @@
|
||||||
/************************************************************//**
|
/************************************************************//**
|
||||||
*
|
*
|
||||||
* @file: main.cpp
|
* @file: main.cpp
|
||||||
* @author: Martin Fouilleul
|
* @author: Martin Fouilleul
|
||||||
* @date: 30/07/2022
|
* @date: 30/07/2022
|
||||||
* @revision:
|
* @revision:
|
||||||
*
|
*
|
||||||
*****************************************************************/
|
*****************************************************************/
|
||||||
#include<stdlib.h>
|
#include<stdlib.h>
|
||||||
#include<string.h>
|
#include<string.h>
|
||||||
|
|
||||||
#define _USE_MATH_DEFINES //NOTE: necessary for MSVC
|
#define _USE_MATH_DEFINES //NOTE: necessary for MSVC
|
||||||
#include<math.h>
|
#include<math.h>
|
||||||
|
|
||||||
#include"milepost.h"
|
#include"milepost.h"
|
||||||
#include"metal_surface.h"
|
|
||||||
|
#define LOG_SUBSYSTEM "Main"
|
||||||
#define LOG_SUBSYSTEM "Main"
|
|
||||||
|
int main()
|
||||||
int main()
|
{
|
||||||
{
|
LogLevel(LOG_LEVEL_DEBUG);
|
||||||
LogLevel(LOG_LEVEL_DEBUG);
|
|
||||||
|
mp_init();
|
||||||
mp_init();
|
|
||||||
|
mp_rect rect = {.x = 100, .y = 100, .w = 800, .h = 600};
|
||||||
mp_rect rect = {.x = 100, .y = 100, .w = 800, .h = 600};
|
mp_window window = mp_window_create(rect, "test", 0);
|
||||||
mp_window window = mp_window_create(rect, "test", 0);
|
|
||||||
|
//NOTE: create surface
|
||||||
//NOTE: create surface
|
#if defined(OS_MACOS)
|
||||||
mg_surface surface = mg_metal_surface_create_for_window(window);
|
mg_surface surface = mg_metal_surface_create_for_window(window);
|
||||||
|
#elif defined(OS_WIN64)
|
||||||
//TODO: create canvas
|
mg_surface surface = mg_gles_surface_create_for_window(window);
|
||||||
mg_canvas canvas = mg_canvas_create(surface);
|
#else
|
||||||
|
#error "unsupported OS"
|
||||||
// start app
|
#endif
|
||||||
mp_window_bring_to_front(window);
|
|
||||||
mp_window_focus(window);
|
//TODO: create canvas
|
||||||
|
mg_canvas canvas = mg_canvas_create(surface);
|
||||||
while(!mp_should_quit())
|
|
||||||
{
|
// start app
|
||||||
mp_pump_events(0);
|
mp_window_bring_to_front(window);
|
||||||
mp_event event = {0};
|
mp_window_focus(window);
|
||||||
while(mp_next_event(&event))
|
|
||||||
{
|
while(!mp_should_quit())
|
||||||
switch(event.type)
|
{
|
||||||
{
|
mp_pump_events(0);
|
||||||
case MP_EVENT_WINDOW_CLOSE:
|
mp_event event = {0};
|
||||||
{
|
while(mp_next_event(&event))
|
||||||
mp_request_quit();
|
{
|
||||||
} break;
|
switch(event.type)
|
||||||
|
{
|
||||||
case MP_EVENT_WINDOW_RESIZE:
|
case MP_EVENT_WINDOW_CLOSE:
|
||||||
{
|
{
|
||||||
printf("resized, rect = {%f, %f, %f, %f}\n",
|
mp_request_quit();
|
||||||
event.frame.rect.x,
|
} break;
|
||||||
event.frame.rect.y,
|
|
||||||
event.frame.rect.w,
|
case MP_EVENT_WINDOW_RESIZE:
|
||||||
event.frame.rect.h);
|
{
|
||||||
} break;
|
printf("resized, rect = {%f, %f, %f, %f}\n",
|
||||||
|
event.frame.rect.x,
|
||||||
case MP_EVENT_WINDOW_MOVE:
|
event.frame.rect.y,
|
||||||
{
|
event.frame.rect.w,
|
||||||
printf("moved, rect = {%f, %f, %f, %f}\n",
|
event.frame.rect.h);
|
||||||
event.frame.rect.x,
|
} break;
|
||||||
event.frame.rect.y,
|
|
||||||
event.frame.rect.w,
|
case MP_EVENT_WINDOW_MOVE:
|
||||||
event.frame.rect.h);
|
{
|
||||||
} break;
|
printf("moved, rect = {%f, %f, %f, %f}\n",
|
||||||
|
event.frame.rect.x,
|
||||||
case MP_EVENT_MOUSE_MOVE:
|
event.frame.rect.y,
|
||||||
{
|
event.frame.rect.w,
|
||||||
printf("mouse moved, pos = {%f, %f}, delta = {%f, %f}\n",
|
event.frame.rect.h);
|
||||||
event.move.x,
|
} break;
|
||||||
event.move.y,
|
|
||||||
event.move.deltaX,
|
case MP_EVENT_MOUSE_MOVE:
|
||||||
event.move.deltaY);
|
{
|
||||||
} break;
|
printf("mouse moved, pos = {%f, %f}, delta = {%f, %f}\n",
|
||||||
|
event.move.x,
|
||||||
case MP_EVENT_MOUSE_WHEEL:
|
event.move.y,
|
||||||
{
|
event.move.deltaX,
|
||||||
printf("mouse wheel, delta = {%f, %f}\n",
|
event.move.deltaY);
|
||||||
event.move.deltaX,
|
} break;
|
||||||
event.move.deltaY);
|
|
||||||
} break;
|
case MP_EVENT_MOUSE_WHEEL:
|
||||||
|
{
|
||||||
case MP_EVENT_MOUSE_ENTER:
|
printf("mouse wheel, delta = {%f, %f}\n",
|
||||||
{
|
event.move.deltaX,
|
||||||
printf("mouse enter\n");
|
event.move.deltaY);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case MP_EVENT_MOUSE_LEAVE:
|
case MP_EVENT_MOUSE_ENTER:
|
||||||
{
|
{
|
||||||
printf("mouse leave\n");
|
printf("mouse enter\n");
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case MP_EVENT_MOUSE_BUTTON:
|
case MP_EVENT_MOUSE_LEAVE:
|
||||||
{
|
{
|
||||||
printf("mouse button %i: %i\n",
|
printf("mouse leave\n");
|
||||||
event.key.code,
|
} break;
|
||||||
event.key.action == MP_KEY_PRESS ? 1 : 0);
|
|
||||||
} break;
|
case MP_EVENT_MOUSE_BUTTON:
|
||||||
|
{
|
||||||
case MP_EVENT_KEYBOARD_KEY:
|
printf("mouse button %i: %i\n",
|
||||||
{
|
event.key.code,
|
||||||
printf("key %i: %s\n",
|
event.key.action == MP_KEY_PRESS ? 1 : 0);
|
||||||
event.key.code,
|
} break;
|
||||||
event.key.action == MP_KEY_PRESS ? "press" : (event.key.action == MP_KEY_RELEASE ? "release" : "repeat"));
|
|
||||||
} break;
|
case MP_EVENT_KEYBOARD_KEY:
|
||||||
|
{
|
||||||
case MP_EVENT_KEYBOARD_CHAR:
|
printf("key %i: %s\n",
|
||||||
{
|
event.key.code,
|
||||||
printf("entered char %s\n", event.character.sequence);
|
event.key.action == MP_KEY_PRESS ? "press" : (event.key.action == MP_KEY_RELEASE ? "release" : "repeat"));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default:
|
case MP_EVENT_KEYBOARD_CHAR:
|
||||||
break;
|
{
|
||||||
}
|
printf("entered char %s\n", event.character.sequence);
|
||||||
}
|
} break;
|
||||||
|
|
||||||
mg_surface_prepare(surface);
|
default:
|
||||||
mg_set_color_rgba(1, 0, 1, 1);
|
break;
|
||||||
mg_clear();
|
}
|
||||||
|
}
|
||||||
mg_set_color_rgba(1, 1, 0, 1);
|
|
||||||
mg_circle_fill(400, 300, 200);
|
mg_surface_prepare(surface);
|
||||||
|
// background
|
||||||
mg_set_color_rgba(0, 0, 0, 1);
|
mg_set_color_rgba(1, 0, 1, 1);
|
||||||
mg_set_width(20);
|
mg_clear();
|
||||||
|
|
||||||
mg_move_to(300, 200);
|
// head
|
||||||
mg_cubic_to(350, 150, 450, 150, 500, 200);
|
mg_set_color_rgba(1, 1, 0, 1);
|
||||||
mg_stroke();
|
mg_circle_fill(400, 300, 200);
|
||||||
|
|
||||||
mg_ellipse_fill(330, 350, 30, 50);
|
// smile
|
||||||
mg_ellipse_fill(470, 350, 30, 50);
|
mg_set_color_rgba(1, 0, 0, 1);
|
||||||
|
|
||||||
mg_flush();
|
mg_set_width(20);
|
||||||
mg_surface_present(surface);
|
mg_move_to(300, 200);
|
||||||
}
|
mg_cubic_to(350, 150, 450, 150, 500, 200);
|
||||||
|
mg_stroke();
|
||||||
mp_terminate();
|
|
||||||
|
// eyes
|
||||||
return(0);
|
mg_ellipse_fill(330, 350, 30, 50);
|
||||||
}
|
mg_ellipse_fill(470, 350, 30, 50);
|
||||||
|
|
||||||
|
mg_flush();
|
||||||
|
mg_surface_present(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_terminate();
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers
|
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers
|
||||||
cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib /LIBPATH:./ libEGL.dll.lib libGLESv2.dll.lib user32.lib opengl32.lib gdi32.lib /out:test.exe
|
cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib /LIBPATH:../../bin libEGL.dll.lib libGLESv2.dll.lib user32.lib opengl32.lib gdi32.lib /out:../../bin/example_gles_triangle.exe
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers
|
||||||
|
cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GLES /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib /LIBPATH:../../bin libEGL.dll.lib libGLESv2.dll.lib user32.lib opengl32.lib gdi32.lib /out:../../bin/example_canvas.exe
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
BINDIR=../../bin
|
||||||
|
RESDIR=../../resources
|
||||||
|
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 -Wl,-dead_strip"
|
||||||
|
|
||||||
|
clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_canvas main.c
|
|
@ -0,0 +1,136 @@
|
||||||
|
/************************************************************//**
|
||||||
|
*
|
||||||
|
* @file: main.cpp
|
||||||
|
* @author: Martin Fouilleul
|
||||||
|
* @date: 30/07/2022
|
||||||
|
* @revision:
|
||||||
|
*
|
||||||
|
*****************************************************************/
|
||||||
|
#include<stdlib.h>
|
||||||
|
#include<string.h>
|
||||||
|
|
||||||
|
#define _USE_MATH_DEFINES //NOTE: necessary for MSVC
|
||||||
|
#include<math.h>
|
||||||
|
|
||||||
|
#include"milepost.h"
|
||||||
|
|
||||||
|
#define LOG_SUBSYSTEM "Main"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
LogLevel(LOG_LEVEL_DEBUG);
|
||||||
|
|
||||||
|
mp_init();
|
||||||
|
|
||||||
|
mp_rect rect = {.x = 100, .y = 100, .w = 800, .h = 600};
|
||||||
|
mp_window window = mp_window_create(rect, "test", 0);
|
||||||
|
|
||||||
|
//NOTE: create surface
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
mg_surface surface = mg_metal_surface_create_for_window(window);
|
||||||
|
#elif defined(OS_WIN64)
|
||||||
|
mg_surface surface = mg_gles_surface_create_for_window(window);
|
||||||
|
#else
|
||||||
|
#error "unsupported OS"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//TODO: create canvas
|
||||||
|
mg_canvas canvas = mg_canvas_create(surface);
|
||||||
|
|
||||||
|
// start app
|
||||||
|
mp_window_bring_to_front(window);
|
||||||
|
mp_window_focus(window);
|
||||||
|
|
||||||
|
f32 dx = 17.000029, dy = 0;
|
||||||
|
|
||||||
|
while(!mp_should_quit())
|
||||||
|
{
|
||||||
|
mp_pump_events(0);
|
||||||
|
mp_event event = {0};
|
||||||
|
while(mp_next_event(&event))
|
||||||
|
{
|
||||||
|
switch(event.type)
|
||||||
|
{
|
||||||
|
case MP_EVENT_WINDOW_CLOSE:
|
||||||
|
{
|
||||||
|
mp_request_quit();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case MP_EVENT_WINDOW_RESIZE:
|
||||||
|
{
|
||||||
|
printf("resized, rect = {%f, %f, %f, %f}\n",
|
||||||
|
event.frame.rect.x,
|
||||||
|
event.frame.rect.y,
|
||||||
|
event.frame.rect.w,
|
||||||
|
event.frame.rect.h);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case MP_EVENT_KEYBOARD_KEY:
|
||||||
|
{
|
||||||
|
printf("key %i: %s\n",
|
||||||
|
event.key.code,
|
||||||
|
event.key.action == MP_KEY_PRESS ? "press" : (event.key.action == MP_KEY_RELEASE ? "release" : "repeat"));
|
||||||
|
if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT)
|
||||||
|
{
|
||||||
|
if(event.key.code == MP_KEY_LEFT)
|
||||||
|
{
|
||||||
|
printf("left\n");
|
||||||
|
dx-=0.1;
|
||||||
|
}
|
||||||
|
else if(event.key.code == MP_KEY_RIGHT)
|
||||||
|
{
|
||||||
|
printf("right\n");
|
||||||
|
dx+=0.1;
|
||||||
|
}
|
||||||
|
else if(event.key.code == MP_KEY_UP)
|
||||||
|
{
|
||||||
|
printf("up\n");
|
||||||
|
dy+=0.1;
|
||||||
|
}
|
||||||
|
else if(event.key.code == MP_KEY_DOWN)
|
||||||
|
{
|
||||||
|
printf("down\n");
|
||||||
|
dy-=0.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mg_surface_prepare(surface);
|
||||||
|
|
||||||
|
printf("dx = %f, dy = %f\n", dx, dy);
|
||||||
|
|
||||||
|
// background
|
||||||
|
mg_set_color_rgba(1, 0, 1, 1);
|
||||||
|
mg_clear();
|
||||||
|
/*
|
||||||
|
// head
|
||||||
|
mg_set_color_rgba(1, 1, 0, 1);
|
||||||
|
mg_circle_fill(dx+400, dy+300, 200);
|
||||||
|
|
||||||
|
// smile
|
||||||
|
mg_set_color_rgba(0, 0, 0, 1);
|
||||||
|
|
||||||
|
mg_set_width(20);
|
||||||
|
mg_move_to(dx+300, dy+200);
|
||||||
|
mg_cubic_to(dx+350, dy+150, dx+450, dy+150, dx+500, dy+200);
|
||||||
|
mg_stroke();
|
||||||
|
|
||||||
|
// eyes
|
||||||
|
mg_ellipse_fill(dx+330, dy+350, 30, 50);
|
||||||
|
mg_ellipse_fill(dx+470, dy+350, 30, 50);
|
||||||
|
*/
|
||||||
|
mg_rectangle_fill((int)(dx + 200), 200, (int)(dy+300), (int)(dy+300));
|
||||||
|
|
||||||
|
mg_flush();
|
||||||
|
mg_surface_present(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_terminate();
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
|
@ -38,41 +38,19 @@ mg_gles_surface* mg_gles_canvas_get_surface(mg_gles_canvas_backend* canvas)
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_gles_canvas_draw_buffers(mg_canvas_backend* interface, u32 vertexCount, u32 indexCount, mg_color clearColor)
|
//NOTE: debugger
|
||||||
|
typedef struct debug_vertex
|
||||||
{
|
{
|
||||||
mg_gles_canvas_backend* backend = (mg_gles_canvas_backend*)interface;
|
vec2 pos;
|
||||||
mg_gles_surface* surface = mg_gles_canvas_get_surface(backend);
|
u8 align0[8];
|
||||||
if(!surface)
|
vec4 cubic;
|
||||||
{
|
vec2 uv;
|
||||||
return;
|
u8 align1[8];
|
||||||
}
|
vec4 color;
|
||||||
|
vec4 clip;
|
||||||
//WARN: dummy test code
|
int zIndex;
|
||||||
|
u8 align2[12];
|
||||||
indexCount = 3;
|
} debug_vertex;
|
||||||
*(vec2*)(interface->vertexLayout.posBuffer) = (vec2){400, 300};
|
|
||||||
*(vec2*)(interface->vertexLayout.posBuffer + interface->vertexLayout.posStride) = (vec2){450, 300};
|
|
||||||
*(vec2*)(interface->vertexLayout.posBuffer + 2*interface->vertexLayout.posStride) = (vec2){400, 350};
|
|
||||||
|
|
||||||
for(int i=0; i<3; i++)
|
|
||||||
{
|
|
||||||
*(vec4*)(interface->vertexLayout.cubicBuffer + i*interface->vertexLayout.cubicStride) = (vec4){1, 1, 1, 1};
|
|
||||||
*(vec2*)(interface->vertexLayout.uvBuffer + i*interface->vertexLayout.uvStride) = (vec2){0, 0};
|
|
||||||
*(vec4*)(interface->vertexLayout.colorBuffer + i*interface->vertexLayout.colorStride) = (vec4){1, 0, 0, 1};
|
|
||||||
*(vec4*)(interface->vertexLayout.clipBuffer + i*interface->vertexLayout.clipStride) = (vec4){-FLT_MAX/2, -FLT_MAX/2, FLT_MAX, FLT_MAX};
|
|
||||||
*(u32*)(interface->vertexLayout.zIndexBuffer + i*interface->vertexLayout.zIndexStride) = 1;
|
|
||||||
*(u32*)(interface->vertexLayout.indexBuffer + i*interface->vertexLayout.indexStride) = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// end dummy test code
|
|
||||||
|
|
||||||
glUseProgram(backend->program);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, backend->dummyVertexBuffer);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->vertexBuffer);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->indexBuffer);
|
|
||||||
glUniform1i(0, indexCount);
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define LayoutNext(prevName, prevType, nextType) \
|
#define LayoutNext(prevName, prevType, nextType) \
|
||||||
AlignUpOnPow2(_cat3_(LAYOUT_, prevName, _OFFSET)+_cat3_(LAYOUT_, prevType, _SIZE), _cat3_(LAYOUT_, nextType, _ALIGN))
|
AlignUpOnPow2(_cat3_(LAYOUT_, prevName, _OFFSET)+_cat3_(LAYOUT_, prevType, _SIZE), _cat3_(LAYOUT_, nextType, _ALIGN))
|
||||||
|
@ -104,17 +82,9 @@ enum {
|
||||||
|
|
||||||
void mg_gles_canvas_update_vertex_layout(mg_gles_canvas_backend* backend)
|
void mg_gles_canvas_update_vertex_layout(mg_gles_canvas_backend* backend)
|
||||||
{
|
{
|
||||||
if(backend->vertexMapping)
|
|
||||||
{
|
|
||||||
glUnmapBuffer(backend->vertexBuffer);
|
|
||||||
}
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->vertexBuffer);
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->vertexBuffer);
|
||||||
backend->vertexMapping = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, MG_GLES_CANVAS_VERTEX_BUFFER_SIZE, GL_MAP_WRITE_BIT);
|
backend->vertexMapping = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, MG_GLES_CANVAS_VERTEX_BUFFER_SIZE, GL_MAP_WRITE_BIT);
|
||||||
|
|
||||||
if(backend->indexMapping)
|
|
||||||
{
|
|
||||||
free(backend->indexMapping);
|
|
||||||
}
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->indexBuffer);
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->indexBuffer);
|
||||||
backend->indexMapping = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, MG_GLES_CANVAS_INDEX_BUFFER_SIZE, GL_MAP_WRITE_BIT);
|
backend->indexMapping = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, MG_GLES_CANVAS_INDEX_BUFFER_SIZE, GL_MAP_WRITE_BIT);
|
||||||
|
|
||||||
|
@ -137,6 +107,35 @@ void mg_gles_canvas_update_vertex_layout(mg_gles_canvas_backend* backend)
|
||||||
.indexStride = LAYOUT_INT_SIZE};
|
.indexStride = LAYOUT_INT_SIZE};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mg_gles_canvas_draw_buffers(mg_canvas_backend* interface, u32 vertexCount, u32 indexCount, mg_color clearColor)
|
||||||
|
{
|
||||||
|
mg_gles_canvas_backend* backend = (mg_gles_canvas_backend*)interface;
|
||||||
|
mg_gles_surface* surface = mg_gles_canvas_get_surface(backend);
|
||||||
|
if(!surface)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*NOTE: if we want debug_vertex while debugging, the following ensures the struct def doesn't get stripped away
|
||||||
|
debug_vertex vertex;
|
||||||
|
printf("foo %p\n", &vertex);
|
||||||
|
//*/
|
||||||
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->vertexBuffer);
|
||||||
|
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
|
||||||
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->indexBuffer);
|
||||||
|
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
|
||||||
|
|
||||||
|
|
||||||
|
glUseProgram(backend->program);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, backend->dummyVertexBuffer);
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->vertexBuffer);
|
||||||
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->indexBuffer);
|
||||||
|
glUniform1i(0, indexCount);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
mg_gles_canvas_update_vertex_layout(backend);
|
||||||
|
}
|
||||||
|
|
||||||
void mg_gles_canvas_destroy(mg_canvas_backend* interface)
|
void mg_gles_canvas_destroy(mg_canvas_backend* interface)
|
||||||
{
|
{
|
||||||
mg_gles_canvas_backend* backend = (mg_gles_canvas_backend*)interface;
|
mg_gles_canvas_backend* backend = (mg_gles_canvas_backend*)interface;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* file: gles_canvas_shaders.h
|
* file: gles_canvas_shaders.h
|
||||||
* note: string literals auto-generated by embed_text.py
|
* note: string literals auto-generated by embed_text.py
|
||||||
* date: 31/012023
|
* date: 01/022023
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
#ifndef __GLES_CANVAS_SHADERS_H__
|
#ifndef __GLES_CANVAS_SHADERS_H__
|
||||||
|
@ -30,15 +30,112 @@ const char* gles_canvas_fragment =
|
||||||
"} vertexBuffer ;\n"
|
"} vertexBuffer ;\n"
|
||||||
"\n"
|
"\n"
|
||||||
"layout(binding = 1) buffer indexBufferSSBO {\n"
|
"layout(binding = 1) buffer indexBufferSSBO {\n"
|
||||||
" vec2 elements[];\n"
|
" uint elements[];\n"
|
||||||
"} indexBuffer ;\n"
|
"} indexBuffer ;\n"
|
||||||
"\n"
|
"\n"
|
||||||
"layout(location = 0) uniform int indexCount;\n"
|
"layout(location = 0) uniform int indexCount;\n"
|
||||||
"layout(location = 0) out vec4 fragColor;\n"
|
"layout(location = 0) out vec4 fragColor;\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"bool is_top_left(vec2 a, vec2 b)\n"
|
||||||
|
"{\n"
|
||||||
|
" return( (a.y == b.y && b.x < a.x)\n"
|
||||||
|
" ||(b.y < a.y));\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"float orient2d(vec2 a, vec2 b, vec2 c)\n"
|
||||||
|
"{\n"
|
||||||
|
" //////////////////////////////////////////////////////////////////////////////////////////\n"
|
||||||
|
" //TODO(martin): FIX this. This is a **horrible** quick hack to fix the precision issues\n"
|
||||||
|
" // arising when a, b, and c are close. But it degrades when a, c, and c\n"
|
||||||
|
" // are big. The proper solution is to change the expression to avoid\n"
|
||||||
|
" // precision loss but I'm too busy/lazy to do it now.\n"
|
||||||
|
" //////////////////////////////////////////////////////////////////////////////////////////\n"
|
||||||
|
" a *= 10.;\n"
|
||||||
|
" b *= 10.;\n"
|
||||||
|
" c *= 10.;\n"
|
||||||
|
" return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
"void main()\n"
|
"void main()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
" vec4 pixelColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
||||||
|
" vec4 currentColor = vec4(0., 0., 0., 1.0);\n"
|
||||||
|
"\n"
|
||||||
|
" vec2 samplePoint = gl_FragCoord.xy;\n"
|
||||||
|
"\n"
|
||||||
|
" int currentZIndex = -1;\n"
|
||||||
|
" int flipCount = 0;\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
" for(int i=0; i<indexCount; i+=3)\n"
|
||||||
|
" {\n"
|
||||||
|
" uint i0 = indexBuffer.elements[i];\n"
|
||||||
|
" uint i1 = indexBuffer.elements[i+1];\n"
|
||||||
|
" uint i2 = indexBuffer.elements[i+2];\n"
|
||||||
|
"\n"
|
||||||
|
" vec2 p0 = vertexBuffer.elements[i0].pos;\n"
|
||||||
|
" vec2 p1 = vertexBuffer.elements[i1].pos;\n"
|
||||||
|
" vec2 p2 = vertexBuffer.elements[i2].pos;\n"
|
||||||
|
"\n"
|
||||||
|
" int zIndex = vertexBuffer.elements[i0].zIndex;\n"
|
||||||
|
" vec4 color = vertexBuffer.elements[i0].color;\n"
|
||||||
|
"\n"
|
||||||
|
" //NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge\n"
|
||||||
|
" float cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;\n"
|
||||||
|
" if(cw < 0.)\n"
|
||||||
|
" {\n"
|
||||||
|
" uint tmpIndex = i1;\n"
|
||||||
|
" i1 = i2;\n"
|
||||||
|
" i2 = tmpIndex;\n"
|
||||||
|
"\n"
|
||||||
|
" vec2 tmpPoint = p1;\n"
|
||||||
|
" p1 = p2;\n"
|
||||||
|
" p2 = tmpPoint;\n"
|
||||||
|
" }\n"
|
||||||
|
"\n"
|
||||||
|
" vec4 cubic0 = vertexBuffer.elements[i0].cubic;\n"
|
||||||
|
" vec4 cubic1 = vertexBuffer.elements[i1].cubic;\n"
|
||||||
|
" vec4 cubic2 = vertexBuffer.elements[i2].cubic;\n"
|
||||||
|
"\n"
|
||||||
|
" int bias0 = is_top_left(p1, p2) ? 0 : -1;\n"
|
||||||
|
" int bias1 = is_top_left(p2, p0) ? 0 : -1;\n"
|
||||||
|
" int bias2 = is_top_left(p0, p1) ? 0 : -1;\n"
|
||||||
|
"\n"
|
||||||
|
" float w0 = orient2d(p1, p2, samplePoint);\n"
|
||||||
|
" float w1 = orient2d(p2, p0, samplePoint);\n"
|
||||||
|
" float w2 = orient2d(p0, p1, samplePoint);\n"
|
||||||
|
"\n"
|
||||||
|
" if((int(w0)+bias0) >= 0 && (int(w1)+bias1) >= 0 && (int(w2)+bias2) >= 0)\n"
|
||||||
|
" {\n"
|
||||||
|
" //TODO check cubic\n"
|
||||||
|
" vec4 cubic = (cubic0*w0 + cubic1*w1 + cubic2*w2)/(w0+w1+w2);\n"
|
||||||
|
"\n"
|
||||||
|
" float eps = 0.0001;\n"
|
||||||
|
" if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)\n"
|
||||||
|
" {\n"
|
||||||
|
" if(zIndex == currentZIndex)\n"
|
||||||
|
" {\n"
|
||||||
|
" flipCount++;\n"
|
||||||
|
" }\n"
|
||||||
|
" else\n"
|
||||||
|
" {\n"
|
||||||
|
" if((flipCount & 0x01) != 0)\n"
|
||||||
|
" {\n"
|
||||||
|
" pixelColor = currentColor;\n"
|
||||||
|
" }\n"
|
||||||
|
" currentColor = pixelColor*(1.-color.a) + color.a*color;\n"
|
||||||
|
" currentZIndex = zIndex;\n"
|
||||||
|
" flipCount = 1;\n"
|
||||||
|
" }\n"
|
||||||
|
" }\n"
|
||||||
|
" }\n"
|
||||||
|
" }\n"
|
||||||
|
" if((flipCount & 0x01) != 0)\n"
|
||||||
|
" {\n"
|
||||||
|
" pixelColor = currentColor;\n"
|
||||||
|
" }\n"
|
||||||
|
"\n"
|
||||||
|
" fragColor = pixelColor;\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
//NOTE: string imported from src\gles_canvas_shaders\gles_canvas_vertex.glsl
|
//NOTE: string imported from src\gles_canvas_shaders\gles_canvas_vertex.glsl
|
||||||
|
|
|
@ -17,13 +17,110 @@ layout(binding = 0) buffer vertexBufferSSBO {
|
||||||
} vertexBuffer ;
|
} vertexBuffer ;
|
||||||
|
|
||||||
layout(binding = 1) buffer indexBufferSSBO {
|
layout(binding = 1) buffer indexBufferSSBO {
|
||||||
vec2 elements[];
|
uint elements[];
|
||||||
} indexBuffer ;
|
} indexBuffer ;
|
||||||
|
|
||||||
layout(location = 0) uniform int indexCount;
|
layout(location = 0) uniform int indexCount;
|
||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
bool is_top_left(vec2 a, vec2 b)
|
||||||
|
{
|
||||||
|
return( (a.y == b.y && b.x < a.x)
|
||||||
|
||(b.y < a.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
float orient2d(vec2 a, vec2 b, vec2 c)
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//TODO(martin): FIX this. This is a **horrible** quick hack to fix the precision issues
|
||||||
|
// arising when a, b, and c are close. But it degrades when a, c, and c
|
||||||
|
// are big. The proper solution is to change the expression to avoid
|
||||||
|
// precision loss but I'm too busy/lazy to do it now.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
a *= 10.;
|
||||||
|
b *= 10.;
|
||||||
|
c *= 10.;
|
||||||
|
return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
|
||||||
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
vec4 pixelColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||||
|
vec4 currentColor = vec4(0., 0., 0., 1.0);
|
||||||
|
|
||||||
|
vec2 samplePoint = gl_FragCoord.xy;
|
||||||
|
|
||||||
|
int currentZIndex = -1;
|
||||||
|
int flipCount = 0;
|
||||||
|
|
||||||
|
|
||||||
|
for(int i=0; i<indexCount; i+=3)
|
||||||
|
{
|
||||||
|
uint i0 = indexBuffer.elements[i];
|
||||||
|
uint i1 = indexBuffer.elements[i+1];
|
||||||
|
uint i2 = indexBuffer.elements[i+2];
|
||||||
|
|
||||||
|
vec2 p0 = vertexBuffer.elements[i0].pos;
|
||||||
|
vec2 p1 = vertexBuffer.elements[i1].pos;
|
||||||
|
vec2 p2 = vertexBuffer.elements[i2].pos;
|
||||||
|
|
||||||
|
int zIndex = vertexBuffer.elements[i0].zIndex;
|
||||||
|
vec4 color = vertexBuffer.elements[i0].color;
|
||||||
|
|
||||||
|
//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
|
||||||
|
float cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;
|
||||||
|
if(cw < 0.)
|
||||||
|
{
|
||||||
|
uint tmpIndex = i1;
|
||||||
|
i1 = i2;
|
||||||
|
i2 = tmpIndex;
|
||||||
|
|
||||||
|
vec2 tmpPoint = p1;
|
||||||
|
p1 = p2;
|
||||||
|
p2 = tmpPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 cubic0 = vertexBuffer.elements[i0].cubic;
|
||||||
|
vec4 cubic1 = vertexBuffer.elements[i1].cubic;
|
||||||
|
vec4 cubic2 = vertexBuffer.elements[i2].cubic;
|
||||||
|
|
||||||
|
int bias0 = is_top_left(p1, p2) ? 0 : -1;
|
||||||
|
int bias1 = is_top_left(p2, p0) ? 0 : -1;
|
||||||
|
int bias2 = is_top_left(p0, p1) ? 0 : -1;
|
||||||
|
|
||||||
|
float w0 = orient2d(p1, p2, samplePoint);
|
||||||
|
float w1 = orient2d(p2, p0, samplePoint);
|
||||||
|
float w2 = orient2d(p0, p1, samplePoint);
|
||||||
|
|
||||||
|
if((int(w0)+bias0) >= 0 && (int(w1)+bias1) >= 0 && (int(w2)+bias2) >= 0)
|
||||||
|
{
|
||||||
|
//TODO check cubic
|
||||||
|
vec4 cubic = (cubic0*w0 + cubic1*w1 + cubic2*w2)/(w0+w1+w2);
|
||||||
|
|
||||||
|
float eps = 0.0001;
|
||||||
|
if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)
|
||||||
|
{
|
||||||
|
if(zIndex == currentZIndex)
|
||||||
|
{
|
||||||
|
flipCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if((flipCount & 0x01) != 0)
|
||||||
|
{
|
||||||
|
pixelColor = currentColor;
|
||||||
|
}
|
||||||
|
currentColor = pixelColor*(1.-color.a) + color.a*color;
|
||||||
|
currentZIndex = zIndex;
|
||||||
|
flipCount = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if((flipCount & 0x01) != 0)
|
||||||
|
{
|
||||||
|
pixelColor = currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragColor = pixelColor;
|
||||||
}
|
}
|
||||||
|
|
7483
src/graphics.c
7483
src/graphics.c
File diff suppressed because it is too large
Load Diff
|
@ -1,290 +1,290 @@
|
||||||
/************************************************************//**
|
/************************************************************//**
|
||||||
*
|
*
|
||||||
* @file: graphics_internal.h
|
* @file: graphics_internal.h
|
||||||
* @author: Martin Fouilleul
|
* @author: Martin Fouilleul
|
||||||
* @date: 23/01/2023
|
* @date: 23/01/2023
|
||||||
* @revision:
|
* @revision:
|
||||||
*
|
*
|
||||||
*****************************************************************/
|
*****************************************************************/
|
||||||
#ifndef __GRAPHICS_INTERNAL_H_
|
#ifndef __GRAPHICS_INTERNAL_H_
|
||||||
#define __GRAPHICS_INTERNAL_H_
|
#define __GRAPHICS_INTERNAL_H_
|
||||||
|
|
||||||
#include"graphics.h"
|
#include"graphics.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum { MG_BACKEND_DUMMY,
|
typedef enum { MG_BACKEND_DUMMY,
|
||||||
MG_BACKEND_METAL,
|
MG_BACKEND_METAL,
|
||||||
MG_BACKEND_GL,
|
MG_BACKEND_GL,
|
||||||
MG_BACKEND_GLES,
|
MG_BACKEND_GLES,
|
||||||
//...
|
//...
|
||||||
} mg_backend_id;
|
} mg_backend_id;
|
||||||
|
|
||||||
typedef struct mg_surface_data mg_surface_data;
|
typedef struct mg_surface_data mg_surface_data;
|
||||||
|
|
||||||
typedef void (*mg_surface_destroy_proc)(mg_surface_data* surface);
|
typedef void (*mg_surface_destroy_proc)(mg_surface_data* surface);
|
||||||
typedef void (*mg_surface_prepare_proc)(mg_surface_data* surface);
|
typedef void (*mg_surface_prepare_proc)(mg_surface_data* surface);
|
||||||
typedef void (*mg_surface_present_proc)(mg_surface_data* surface);
|
typedef void (*mg_surface_present_proc)(mg_surface_data* surface);
|
||||||
typedef mp_rect (*mg_surface_get_frame_proc)(mg_surface_data* surface);
|
typedef mp_rect (*mg_surface_get_frame_proc)(mg_surface_data* surface);
|
||||||
typedef void (*mg_surface_set_frame_proc)(mg_surface_data* surface, mp_rect frame);
|
typedef void (*mg_surface_set_frame_proc)(mg_surface_data* surface, mp_rect frame);
|
||||||
typedef bool (*mg_surface_get_hidden_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_set_hidden_proc)(mg_surface_data* surface, bool hidden);
|
||||||
|
|
||||||
typedef struct mg_surface_data
|
typedef struct mg_surface_data
|
||||||
{
|
{
|
||||||
mg_backend_id backend;
|
mg_backend_id backend;
|
||||||
|
|
||||||
mg_surface_destroy_proc destroy;
|
mg_surface_destroy_proc destroy;
|
||||||
mg_surface_prepare_proc prepare;
|
mg_surface_prepare_proc prepare;
|
||||||
mg_surface_present_proc present;
|
mg_surface_present_proc present;
|
||||||
mg_surface_get_frame_proc getFrame;
|
mg_surface_get_frame_proc getFrame;
|
||||||
mg_surface_set_frame_proc setFrame;
|
mg_surface_set_frame_proc setFrame;
|
||||||
mg_surface_get_hidden_proc getHidden;
|
mg_surface_get_hidden_proc getHidden;
|
||||||
mg_surface_set_hidden_proc setHidden;
|
mg_surface_set_hidden_proc setHidden;
|
||||||
|
|
||||||
} mg_surface_data;
|
} mg_surface_data;
|
||||||
|
|
||||||
mg_surface mg_surface_alloc_handle(mg_surface_data* surface);
|
mg_surface mg_surface_alloc_handle(mg_surface_data* surface);
|
||||||
mg_surface_data* mg_surface_data_from_handle(mg_surface handle);
|
mg_surface_data* mg_surface_data_from_handle(mg_surface handle);
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// graphics structs
|
// graphics structs
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
typedef enum { MG_PATH_MOVE,
|
typedef enum { MG_PATH_MOVE,
|
||||||
MG_PATH_LINE,
|
MG_PATH_LINE,
|
||||||
MG_PATH_QUADRATIC,
|
MG_PATH_QUADRATIC,
|
||||||
MG_PATH_CUBIC } mg_path_elt_type;
|
MG_PATH_CUBIC } mg_path_elt_type;
|
||||||
|
|
||||||
typedef struct mg_path_elt
|
typedef struct mg_path_elt
|
||||||
{
|
{
|
||||||
mg_path_elt_type type;
|
mg_path_elt_type type;
|
||||||
vec2 p[3];
|
vec2 p[3];
|
||||||
|
|
||||||
} mg_path_elt;
|
} mg_path_elt;
|
||||||
|
|
||||||
typedef struct mg_path_descriptor
|
typedef struct mg_path_descriptor
|
||||||
{
|
{
|
||||||
u32 startIndex;
|
u32 startIndex;
|
||||||
u32 count;
|
u32 count;
|
||||||
vec2 startPoint;
|
vec2 startPoint;
|
||||||
|
|
||||||
} mg_path_descriptor;
|
} mg_path_descriptor;
|
||||||
|
|
||||||
typedef struct mg_attributes
|
typedef struct mg_attributes
|
||||||
{
|
{
|
||||||
f32 width;
|
f32 width;
|
||||||
f32 tolerance;
|
f32 tolerance;
|
||||||
mg_color color;
|
mg_color color;
|
||||||
mg_joint_type joint;
|
mg_joint_type joint;
|
||||||
f32 maxJointExcursion;
|
f32 maxJointExcursion;
|
||||||
mg_cap_type cap;
|
mg_cap_type cap;
|
||||||
|
|
||||||
mg_font font;
|
mg_font font;
|
||||||
f32 fontSize;
|
f32 fontSize;
|
||||||
|
|
||||||
mg_image image;
|
mg_image image;
|
||||||
|
|
||||||
mp_rect clip;
|
mp_rect clip;
|
||||||
|
|
||||||
} mg_attributes;
|
} mg_attributes;
|
||||||
|
|
||||||
typedef struct mg_rounded_rect
|
typedef struct mg_rounded_rect
|
||||||
{
|
{
|
||||||
f32 x;
|
f32 x;
|
||||||
f32 y;
|
f32 y;
|
||||||
f32 w;
|
f32 w;
|
||||||
f32 h;
|
f32 h;
|
||||||
f32 r;
|
f32 r;
|
||||||
} mg_rounded_rect;
|
} mg_rounded_rect;
|
||||||
|
|
||||||
typedef enum { MG_CMD_CLEAR = 0,
|
typedef enum { MG_CMD_CLEAR = 0,
|
||||||
MG_CMD_FILL,
|
MG_CMD_FILL,
|
||||||
MG_CMD_STROKE,
|
MG_CMD_STROKE,
|
||||||
MG_CMD_RECT_FILL,
|
MG_CMD_RECT_FILL,
|
||||||
MG_CMD_RECT_STROKE,
|
MG_CMD_RECT_STROKE,
|
||||||
MG_CMD_ROUND_RECT_FILL,
|
MG_CMD_ROUND_RECT_FILL,
|
||||||
MG_CMD_ROUND_RECT_STROKE,
|
MG_CMD_ROUND_RECT_STROKE,
|
||||||
MG_CMD_ELLIPSE_FILL,
|
MG_CMD_ELLIPSE_FILL,
|
||||||
MG_CMD_ELLIPSE_STROKE,
|
MG_CMD_ELLIPSE_STROKE,
|
||||||
MG_CMD_JUMP,
|
MG_CMD_JUMP,
|
||||||
MG_CMD_MATRIX_PUSH,
|
MG_CMD_MATRIX_PUSH,
|
||||||
MG_CMD_MATRIX_POP,
|
MG_CMD_MATRIX_POP,
|
||||||
MG_CMD_CLIP_PUSH,
|
MG_CMD_CLIP_PUSH,
|
||||||
MG_CMD_CLIP_POP,
|
MG_CMD_CLIP_POP,
|
||||||
MG_CMD_IMAGE_DRAW,
|
MG_CMD_IMAGE_DRAW,
|
||||||
MG_CMD_ROUNDED_IMAGE_DRAW,
|
MG_CMD_ROUNDED_IMAGE_DRAW,
|
||||||
} mg_primitive_cmd;
|
} mg_primitive_cmd;
|
||||||
|
|
||||||
typedef struct mg_primitive
|
typedef struct mg_primitive
|
||||||
{
|
{
|
||||||
mg_primitive_cmd cmd;
|
mg_primitive_cmd cmd;
|
||||||
mg_attributes attributes;
|
mg_attributes attributes;
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
mg_path_descriptor path;
|
mg_path_descriptor path;
|
||||||
mp_rect rect;
|
mp_rect rect;
|
||||||
mg_rounded_rect roundedRect;
|
mg_rounded_rect roundedRect;
|
||||||
utf32 codePoint;
|
utf32 codePoint;
|
||||||
u32 jump;
|
u32 jump;
|
||||||
mg_mat2x3 matrix;
|
mg_mat2x3 matrix;
|
||||||
};
|
};
|
||||||
|
|
||||||
} mg_primitive;
|
} mg_primitive;
|
||||||
|
|
||||||
typedef struct mg_glyph_map_entry
|
typedef struct mg_glyph_map_entry
|
||||||
{
|
{
|
||||||
unicode_range range;
|
unicode_range range;
|
||||||
u32 firstGlyphIndex;
|
u32 firstGlyphIndex;
|
||||||
|
|
||||||
} mg_glyph_map_entry;
|
} mg_glyph_map_entry;
|
||||||
|
|
||||||
typedef struct mg_glyph_data
|
typedef struct mg_glyph_data
|
||||||
{
|
{
|
||||||
bool exists;
|
bool exists;
|
||||||
utf32 codePoint;
|
utf32 codePoint;
|
||||||
mg_path_descriptor pathDescriptor;
|
mg_path_descriptor pathDescriptor;
|
||||||
mg_text_extents extents;
|
mg_text_extents extents;
|
||||||
//...
|
//...
|
||||||
|
|
||||||
} mg_glyph_data;
|
} mg_glyph_data;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
MG_STREAM_MAX_COUNT = 128,
|
MG_STREAM_MAX_COUNT = 128,
|
||||||
MG_IMAGE_MAX_COUNT = 128
|
MG_IMAGE_MAX_COUNT = 128
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct mg_image_data
|
typedef struct mg_image_data
|
||||||
{
|
{
|
||||||
list_elt listElt;
|
list_elt listElt;
|
||||||
u32 generation;
|
u32 generation;
|
||||||
|
|
||||||
mp_rect rect;
|
mp_rect rect;
|
||||||
|
|
||||||
} mg_image_data;
|
} mg_image_data;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
MG_MATRIX_STACK_MAX_DEPTH = 64,
|
MG_MATRIX_STACK_MAX_DEPTH = 64,
|
||||||
MG_CLIP_STACK_MAX_DEPTH = 64,
|
MG_CLIP_STACK_MAX_DEPTH = 64,
|
||||||
MG_MAX_PATH_ELEMENT_COUNT = 2<<20,
|
MG_MAX_PATH_ELEMENT_COUNT = 2<<20,
|
||||||
MG_MAX_PRIMITIVE_COUNT = 8<<10
|
MG_MAX_PRIMITIVE_COUNT = 8<<10
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct mg_font_data
|
typedef struct mg_font_data
|
||||||
{
|
{
|
||||||
list_elt freeListElt;
|
list_elt freeListElt;
|
||||||
u32 generation;
|
u32 generation;
|
||||||
|
|
||||||
u32 rangeCount;
|
u32 rangeCount;
|
||||||
u32 glyphCount;
|
u32 glyphCount;
|
||||||
u32 outlineCount;
|
u32 outlineCount;
|
||||||
mg_glyph_map_entry* glyphMap;
|
mg_glyph_map_entry* glyphMap;
|
||||||
mg_glyph_data* glyphs;
|
mg_glyph_data* glyphs;
|
||||||
mg_path_elt* outlines;
|
mg_path_elt* outlines;
|
||||||
|
|
||||||
f32 unitsPerEm;
|
f32 unitsPerEm;
|
||||||
mg_font_extents extents;
|
mg_font_extents extents;
|
||||||
|
|
||||||
} mg_font_data;
|
} mg_font_data;
|
||||||
|
|
||||||
typedef struct mg_vertex_layout
|
typedef struct mg_vertex_layout
|
||||||
{
|
{
|
||||||
u32 maxVertexCount;
|
u32 maxVertexCount;
|
||||||
u32 maxIndexCount;
|
u32 maxIndexCount;
|
||||||
|
|
||||||
void* posBuffer;
|
char* posBuffer;
|
||||||
u32 posStride;
|
u32 posStride;
|
||||||
|
|
||||||
void* cubicBuffer;
|
char* cubicBuffer;
|
||||||
u32 cubicStride;
|
u32 cubicStride;
|
||||||
|
|
||||||
void* uvBuffer;
|
char* uvBuffer;
|
||||||
u32 uvStride;
|
u32 uvStride;
|
||||||
|
|
||||||
void* colorBuffer;
|
char* colorBuffer;
|
||||||
u32 colorStride;
|
u32 colorStride;
|
||||||
|
|
||||||
void* zIndexBuffer;
|
char* zIndexBuffer;
|
||||||
u32 zIndexStride;
|
u32 zIndexStride;
|
||||||
|
|
||||||
void* clipsBuffer;
|
char* clipBuffer;
|
||||||
u32 clipsStride;
|
u32 clipStride;
|
||||||
|
|
||||||
void* indexBuffer;
|
char* indexBuffer;
|
||||||
u32 indexStride;
|
u32 indexStride;
|
||||||
|
|
||||||
} mg_vertex_layout;
|
} mg_vertex_layout;
|
||||||
|
|
||||||
typedef struct mg_canvas_backend mg_canvas_backend;
|
typedef struct mg_canvas_backend mg_canvas_backend;
|
||||||
|
|
||||||
typedef void (*mg_canvas_backend_destroy_proc)(mg_canvas_backend* backend);
|
typedef void (*mg_canvas_backend_destroy_proc)(mg_canvas_backend* backend);
|
||||||
typedef void (*mg_canvas_backend_draw_buffers_proc)(mg_canvas_backend* backend, u32 vertexCount, u32 indexCount, mg_color clearColor);
|
typedef void (*mg_canvas_backend_draw_buffers_proc)(mg_canvas_backend* backend, u32 vertexCount, u32 indexCount, mg_color clearColor);
|
||||||
typedef void (*mg_canvas_backend_atlas_upload_proc)(mg_canvas_backend* backend, mp_rect rect, u8* bytes);
|
typedef void (*mg_canvas_backend_atlas_upload_proc)(mg_canvas_backend* backend, mp_rect rect, u8* bytes);
|
||||||
|
|
||||||
typedef struct mg_canvas_backend
|
typedef struct mg_canvas_backend
|
||||||
{
|
{
|
||||||
mg_vertex_layout vertexLayout;
|
mg_vertex_layout vertexLayout;
|
||||||
|
|
||||||
mg_canvas_backend_destroy_proc destroy;
|
mg_canvas_backend_destroy_proc destroy;
|
||||||
mg_canvas_backend_draw_buffers_proc drawBuffers;
|
mg_canvas_backend_draw_buffers_proc drawBuffers;
|
||||||
mg_canvas_backend_atlas_upload_proc atlasUpload;
|
mg_canvas_backend_atlas_upload_proc atlasUpload;
|
||||||
|
|
||||||
} mg_canvas_backend;
|
} mg_canvas_backend;
|
||||||
|
|
||||||
typedef struct mg_canvas_data
|
typedef struct mg_canvas_data
|
||||||
{
|
{
|
||||||
list_elt freeListElt;
|
list_elt freeListElt;
|
||||||
u32 generation;
|
u32 generation;
|
||||||
|
|
||||||
u64 frameCounter;
|
u64 frameCounter;
|
||||||
|
|
||||||
mg_mat2x3 transform;
|
mg_mat2x3 transform;
|
||||||
mp_rect clip;
|
mp_rect clip;
|
||||||
mg_attributes attributes;
|
mg_attributes attributes;
|
||||||
bool textFlip;
|
bool textFlip;
|
||||||
|
|
||||||
mg_path_elt pathElements[MG_MAX_PATH_ELEMENT_COUNT];
|
mg_path_elt pathElements[MG_MAX_PATH_ELEMENT_COUNT];
|
||||||
mg_path_descriptor path;
|
mg_path_descriptor path;
|
||||||
vec2 subPathStartPoint;
|
vec2 subPathStartPoint;
|
||||||
vec2 subPathLastPoint;
|
vec2 subPathLastPoint;
|
||||||
|
|
||||||
mg_mat2x3 matrixStack[MG_MATRIX_STACK_MAX_DEPTH];
|
mg_mat2x3 matrixStack[MG_MATRIX_STACK_MAX_DEPTH];
|
||||||
u32 matrixStackSize;
|
u32 matrixStackSize;
|
||||||
|
|
||||||
mp_rect clipStack[MG_CLIP_STACK_MAX_DEPTH];
|
mp_rect clipStack[MG_CLIP_STACK_MAX_DEPTH];
|
||||||
u32 clipStackSize;
|
u32 clipStackSize;
|
||||||
|
|
||||||
u32 nextZIndex;
|
u32 nextZIndex;
|
||||||
u32 primitiveCount;
|
u32 primitiveCount;
|
||||||
mg_primitive primitives[MG_MAX_PRIMITIVE_COUNT];
|
mg_primitive primitives[MG_MAX_PRIMITIVE_COUNT];
|
||||||
|
|
||||||
u32 vertexCount;
|
u32 vertexCount;
|
||||||
u32 indexCount;
|
u32 indexCount;
|
||||||
|
|
||||||
mg_image_data images[MG_IMAGE_MAX_COUNT];
|
mg_image_data images[MG_IMAGE_MAX_COUNT];
|
||||||
u32 imageNextIndex;
|
u32 imageNextIndex;
|
||||||
list_info imageFreeList;
|
list_info imageFreeList;
|
||||||
|
|
||||||
vec2 atlasPos;
|
vec2 atlasPos;
|
||||||
u32 atlasLineHeight;
|
u32 atlasLineHeight;
|
||||||
mg_image blankImage;
|
mg_image blankImage;
|
||||||
|
|
||||||
mg_canvas_backend* backend;
|
mg_canvas_backend* backend;
|
||||||
|
|
||||||
} mg_canvas_data;
|
} mg_canvas_data;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
MG_ATLAS_SIZE = 8192,
|
MG_ATLAS_SIZE = 8192,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif //__GRAPHICS_INTERNAL_H_
|
#endif //__GRAPHICS_INTERNAL_H_
|
||||||
|
|
|
@ -1,442 +1,442 @@
|
||||||
/************************************************************//**
|
/************************************************************//**
|
||||||
*
|
*
|
||||||
* @file: metal_canvas.m
|
* @file: metal_canvas.m
|
||||||
* @author: Martin Fouilleul
|
* @author: Martin Fouilleul
|
||||||
* @date: 12/07/2020
|
* @date: 12/07/2020
|
||||||
* @revision: 24/01/2023
|
* @revision: 24/01/2023
|
||||||
*
|
*
|
||||||
*****************************************************************/
|
*****************************************************************/
|
||||||
#import<Metal/Metal.h>
|
#import<Metal/Metal.h>
|
||||||
#import<QuartzCore/CAMetalLayer.h>
|
#import<QuartzCore/CAMetalLayer.h>
|
||||||
#include<simd/simd.h>
|
#include<simd/simd.h>
|
||||||
|
|
||||||
#include"graphics_internal.h"
|
#include"graphics_internal.h"
|
||||||
#include"macro_helpers.h"
|
#include"macro_helpers.h"
|
||||||
#include"osx_app.h"
|
#include"osx_app.h"
|
||||||
|
|
||||||
#include"metal_shader.h"
|
#include"metal_shader.h"
|
||||||
|
|
||||||
#define LOG_SUBSYSTEM "Graphics"
|
#define LOG_SUBSYSTEM "Graphics"
|
||||||
|
|
||||||
static const int MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH = 4<<20;
|
static const int MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH = 4<<20;
|
||||||
|
|
||||||
typedef struct mg_metal_canvas_backend
|
typedef struct mg_metal_canvas_backend
|
||||||
{
|
{
|
||||||
mg_canvas_backend interface;
|
mg_canvas_backend interface;
|
||||||
mg_surface surface;
|
mg_surface surface;
|
||||||
|
|
||||||
// permanent metal resources
|
// permanent metal resources
|
||||||
id<MTLComputePipelineState> tilingPipeline;
|
id<MTLComputePipelineState> tilingPipeline;
|
||||||
id<MTLComputePipelineState> sortingPipeline;
|
id<MTLComputePipelineState> sortingPipeline;
|
||||||
id<MTLComputePipelineState> boxingPipeline;
|
id<MTLComputePipelineState> boxingPipeline;
|
||||||
id<MTLComputePipelineState> computePipeline;
|
id<MTLComputePipelineState> computePipeline;
|
||||||
id<MTLRenderPipelineState> renderPipeline;
|
id<MTLRenderPipelineState> renderPipeline;
|
||||||
|
|
||||||
mp_rect viewPort;
|
mp_rect viewPort;
|
||||||
|
|
||||||
// textures and buffers
|
// textures and buffers
|
||||||
id<MTLTexture> outTexture;
|
id<MTLTexture> outTexture;
|
||||||
id<MTLTexture> atlasTexture;
|
id<MTLTexture> atlasTexture;
|
||||||
id<MTLBuffer> vertexBuffer;
|
id<MTLBuffer> vertexBuffer;
|
||||||
id<MTLBuffer> indexBuffer;
|
id<MTLBuffer> indexBuffer;
|
||||||
id<MTLBuffer> tileCounters;
|
id<MTLBuffer> tileCounters;
|
||||||
id<MTLBuffer> tilesArray;
|
id<MTLBuffer> tilesArray;
|
||||||
id<MTLBuffer> triangleArray;
|
id<MTLBuffer> triangleArray;
|
||||||
id<MTLBuffer> boxArray;
|
id<MTLBuffer> boxArray;
|
||||||
|
|
||||||
} mg_metal_canvas_backend;
|
} mg_metal_canvas_backend;
|
||||||
|
|
||||||
mg_metal_surface* mg_metal_canvas_get_surface(mg_metal_canvas_backend* canvas)
|
mg_metal_surface* mg_metal_canvas_get_surface(mg_metal_canvas_backend* canvas)
|
||||||
{
|
{
|
||||||
mg_metal_surface* res = 0;
|
mg_metal_surface* res = 0;
|
||||||
mg_surface_data* data = mg_surface_data_from_handle(canvas->surface);
|
mg_surface_data* data = mg_surface_data_from_handle(canvas->surface);
|
||||||
if(data && data->backend == MG_BACKEND_METAL)
|
if(data && data->backend == MG_BACKEND_METAL)
|
||||||
{
|
{
|
||||||
res = (mg_metal_surface*)data;
|
res = (mg_metal_surface*)data;
|
||||||
}
|
}
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_metal_canvas_draw_buffers(mg_canvas_backend* interface, u32 vertexCount, u32 indexCount, mg_color clearColor)
|
void mg_metal_canvas_draw_buffers(mg_canvas_backend* interface, u32 vertexCount, u32 indexCount, mg_color clearColor)
|
||||||
{
|
{
|
||||||
mg_metal_canvas_backend* backend = (mg_metal_canvas_backend*)interface;
|
mg_metal_canvas_backend* backend = (mg_metal_canvas_backend*)interface;
|
||||||
mg_metal_surface* surface = mg_metal_canvas_get_surface(backend);
|
mg_metal_surface* surface = mg_metal_canvas_get_surface(backend);
|
||||||
if(!surface)
|
if(!surface)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
{
|
{
|
||||||
if(surface->commandBuffer == nil || surface->commandBuffer == nil)
|
if(surface->commandBuffer == nil || surface->commandBuffer == nil)
|
||||||
{
|
{
|
||||||
mg_metal_surface_acquire_drawable_and_command_buffer(surface);
|
mg_metal_surface_acquire_drawable_and_command_buffer(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(indexCount * sizeof(i32) < [backend->indexBuffer length]);
|
ASSERT(indexCount * sizeof(i32) < [backend->indexBuffer length]);
|
||||||
|
|
||||||
f32 scale = surface->metalLayer.contentsScale;
|
f32 scale = surface->metalLayer.contentsScale;
|
||||||
vector_uint2 viewportSize = {backend->viewPort.w * scale, backend->viewPort.h * scale};
|
vector_uint2 viewportSize = {backend->viewPort.w * scale, backend->viewPort.h * scale};
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): encode the clear counter
|
//NOTE(martin): encode the clear counter
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
id<MTLBlitCommandEncoder> blitEncoder = [surface->commandBuffer blitCommandEncoder];
|
id<MTLBlitCommandEncoder> blitEncoder = [surface->commandBuffer blitCommandEncoder];
|
||||||
[blitEncoder fillBuffer: backend->tileCounters range: NSMakeRange(0, RENDERER_MAX_TILES*sizeof(uint)) value: 0];
|
[blitEncoder fillBuffer: backend->tileCounters range: NSMakeRange(0, RENDERER_MAX_TILES*sizeof(uint)) value: 0];
|
||||||
[blitEncoder endEncoding];
|
[blitEncoder endEncoding];
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): encode the boxing pass
|
//NOTE(martin): encode the boxing pass
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
id<MTLComputeCommandEncoder> boxEncoder = [surface->commandBuffer computeCommandEncoder];
|
id<MTLComputeCommandEncoder> boxEncoder = [surface->commandBuffer computeCommandEncoder];
|
||||||
[boxEncoder setComputePipelineState: backend->boxingPipeline];
|
[boxEncoder setComputePipelineState: backend->boxingPipeline];
|
||||||
[boxEncoder setBuffer: backend->vertexBuffer offset:0 atIndex: 0];
|
[boxEncoder setBuffer: backend->vertexBuffer offset:0 atIndex: 0];
|
||||||
[boxEncoder setBuffer: backend->indexBuffer offset:0 atIndex: 1];
|
[boxEncoder setBuffer: backend->indexBuffer offset:0 atIndex: 1];
|
||||||
[boxEncoder setBuffer: backend->triangleArray offset:0 atIndex: 2];
|
[boxEncoder setBuffer: backend->triangleArray offset:0 atIndex: 2];
|
||||||
[boxEncoder setBuffer: backend->boxArray offset:0 atIndex: 3];
|
[boxEncoder setBuffer: backend->boxArray offset:0 atIndex: 3];
|
||||||
[boxEncoder setBytes: &scale length: sizeof(float) atIndex: 4];
|
[boxEncoder setBytes: &scale length: sizeof(float) atIndex: 4];
|
||||||
|
|
||||||
MTLSize boxGroupSize = MTLSizeMake(backend->boxingPipeline.maxTotalThreadsPerThreadgroup, 1, 1);
|
MTLSize boxGroupSize = MTLSizeMake(backend->boxingPipeline.maxTotalThreadsPerThreadgroup, 1, 1);
|
||||||
MTLSize boxGridSize = MTLSizeMake(indexCount/3, 1, 1);
|
MTLSize boxGridSize = MTLSizeMake(indexCount/3, 1, 1);
|
||||||
|
|
||||||
[boxEncoder dispatchThreads: boxGridSize threadsPerThreadgroup: boxGroupSize];
|
[boxEncoder dispatchThreads: boxGridSize threadsPerThreadgroup: boxGroupSize];
|
||||||
[boxEncoder endEncoding];
|
[boxEncoder endEncoding];
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): encode the tiling pass
|
//NOTE(martin): encode the tiling pass
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
|
|
||||||
id<MTLComputeCommandEncoder> tileEncoder = [surface->commandBuffer computeCommandEncoder];
|
id<MTLComputeCommandEncoder> tileEncoder = [surface->commandBuffer computeCommandEncoder];
|
||||||
[tileEncoder setComputePipelineState: backend->tilingPipeline];
|
[tileEncoder setComputePipelineState: backend->tilingPipeline];
|
||||||
[tileEncoder setBuffer: backend->boxArray offset:0 atIndex: 0];
|
[tileEncoder setBuffer: backend->boxArray offset:0 atIndex: 0];
|
||||||
[tileEncoder setBuffer: backend->tileCounters offset:0 atIndex: 1];
|
[tileEncoder setBuffer: backend->tileCounters offset:0 atIndex: 1];
|
||||||
[tileEncoder setBuffer: backend->tilesArray offset:0 atIndex: 2];
|
[tileEncoder setBuffer: backend->tilesArray offset:0 atIndex: 2];
|
||||||
[tileEncoder setBytes: &viewportSize length: sizeof(vector_uint2) atIndex: 3];
|
[tileEncoder setBytes: &viewportSize length: sizeof(vector_uint2) atIndex: 3];
|
||||||
|
|
||||||
[tileEncoder dispatchThreads: boxGridSize threadsPerThreadgroup: boxGroupSize];
|
[tileEncoder dispatchThreads: boxGridSize threadsPerThreadgroup: boxGroupSize];
|
||||||
[tileEncoder endEncoding];
|
[tileEncoder endEncoding];
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): encode the sorting pass
|
//NOTE(martin): encode the sorting pass
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
|
|
||||||
id<MTLComputeCommandEncoder> sortEncoder = [surface->commandBuffer computeCommandEncoder];
|
id<MTLComputeCommandEncoder> sortEncoder = [surface->commandBuffer computeCommandEncoder];
|
||||||
[sortEncoder setComputePipelineState: backend->sortingPipeline];
|
[sortEncoder setComputePipelineState: backend->sortingPipeline];
|
||||||
[sortEncoder setBuffer: backend->tileCounters offset:0 atIndex: 0];
|
[sortEncoder setBuffer: backend->tileCounters offset:0 atIndex: 0];
|
||||||
[sortEncoder setBuffer: backend->triangleArray offset:0 atIndex: 1];
|
[sortEncoder setBuffer: backend->triangleArray offset:0 atIndex: 1];
|
||||||
[sortEncoder setBuffer: backend->tilesArray offset:0 atIndex: 2];
|
[sortEncoder setBuffer: backend->tilesArray offset:0 atIndex: 2];
|
||||||
[sortEncoder setBytes: &viewportSize length: sizeof(vector_uint2) atIndex: 3];
|
[sortEncoder setBytes: &viewportSize length: sizeof(vector_uint2) atIndex: 3];
|
||||||
|
|
||||||
u32 nTilesX = (viewportSize.x + RENDERER_TILE_SIZE - 1)/RENDERER_TILE_SIZE;
|
u32 nTilesX = (viewportSize.x + RENDERER_TILE_SIZE - 1)/RENDERER_TILE_SIZE;
|
||||||
u32 nTilesY = (viewportSize.y + RENDERER_TILE_SIZE - 1)/RENDERER_TILE_SIZE;
|
u32 nTilesY = (viewportSize.y + RENDERER_TILE_SIZE - 1)/RENDERER_TILE_SIZE;
|
||||||
|
|
||||||
MTLSize sortGroupSize = MTLSizeMake(backend->boxingPipeline.maxTotalThreadsPerThreadgroup, 1, 1);
|
MTLSize sortGroupSize = MTLSizeMake(backend->boxingPipeline.maxTotalThreadsPerThreadgroup, 1, 1);
|
||||||
MTLSize sortGridSize = MTLSizeMake(nTilesX*nTilesY, 1, 1);
|
MTLSize sortGridSize = MTLSizeMake(nTilesX*nTilesY, 1, 1);
|
||||||
|
|
||||||
[sortEncoder dispatchThreads: sortGridSize threadsPerThreadgroup: sortGroupSize];
|
[sortEncoder dispatchThreads: sortGridSize threadsPerThreadgroup: sortGroupSize];
|
||||||
[sortEncoder endEncoding];
|
[sortEncoder endEncoding];
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): create compute encoder and encode commands
|
//NOTE(martin): create compute encoder and encode commands
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
vector_float4 clearColorVec4 = {clearColor.r, clearColor.g, clearColor.b, clearColor.a};
|
vector_float4 clearColorVec4 = {clearColor.r, clearColor.g, clearColor.b, clearColor.a};
|
||||||
|
|
||||||
id<MTLComputeCommandEncoder> encoder = [surface->commandBuffer computeCommandEncoder];
|
id<MTLComputeCommandEncoder> encoder = [surface->commandBuffer computeCommandEncoder];
|
||||||
[encoder setComputePipelineState:backend->computePipeline];
|
[encoder setComputePipelineState:backend->computePipeline];
|
||||||
[encoder setTexture: backend->outTexture atIndex: 0];
|
[encoder setTexture: backend->outTexture atIndex: 0];
|
||||||
[encoder setTexture: backend->atlasTexture atIndex: 1];
|
[encoder setTexture: backend->atlasTexture atIndex: 1];
|
||||||
[encoder setBuffer: backend->vertexBuffer offset:0 atIndex: 0];
|
[encoder setBuffer: backend->vertexBuffer offset:0 atIndex: 0];
|
||||||
[encoder setBuffer: backend->tileCounters offset:0 atIndex: 1];
|
[encoder setBuffer: backend->tileCounters offset:0 atIndex: 1];
|
||||||
[encoder setBuffer: backend->tilesArray offset:0 atIndex: 2];
|
[encoder setBuffer: backend->tilesArray offset:0 atIndex: 2];
|
||||||
[encoder setBuffer: backend->triangleArray offset:0 atIndex: 3];
|
[encoder setBuffer: backend->triangleArray offset:0 atIndex: 3];
|
||||||
[encoder setBuffer: backend->boxArray offset:0 atIndex: 4];
|
[encoder setBuffer: backend->boxArray offset:0 atIndex: 4];
|
||||||
[encoder setBytes: &clearColorVec4 length: sizeof(vector_float4) atIndex: 5];
|
[encoder setBytes: &clearColorVec4 length: sizeof(vector_float4) atIndex: 5];
|
||||||
|
|
||||||
//TODO: check that we don't exceed maxTotalThreadsPerThreadgroup
|
//TODO: check that we don't exceed maxTotalThreadsPerThreadgroup
|
||||||
DEBUG_ASSERT(RENDERER_TILE_SIZE*RENDERER_TILE_SIZE <= backend->computePipeline.maxTotalThreadsPerThreadgroup);
|
DEBUG_ASSERT(RENDERER_TILE_SIZE*RENDERER_TILE_SIZE <= backend->computePipeline.maxTotalThreadsPerThreadgroup);
|
||||||
MTLSize threadGridSize = MTLSizeMake(viewportSize.x, viewportSize.y, 1);
|
MTLSize threadGridSize = MTLSizeMake(viewportSize.x, viewportSize.y, 1);
|
||||||
MTLSize threadGroupSize = MTLSizeMake(RENDERER_TILE_SIZE, RENDERER_TILE_SIZE, 1);
|
MTLSize threadGroupSize = MTLSizeMake(RENDERER_TILE_SIZE, RENDERER_TILE_SIZE, 1);
|
||||||
|
|
||||||
[encoder dispatchThreads: threadGridSize threadsPerThreadgroup:threadGroupSize];
|
[encoder dispatchThreads: threadGridSize threadsPerThreadgroup:threadGroupSize];
|
||||||
[encoder endEncoding];
|
[encoder endEncoding];
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): acquire drawable, create render encoder to blit texture to framebuffer
|
//NOTE(martin): acquire drawable, create render encoder to blit texture to framebuffer
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
|
|
||||||
MTLViewport viewport = {backend->viewPort.x * scale,
|
MTLViewport viewport = {backend->viewPort.x * scale,
|
||||||
backend->viewPort.y * scale,
|
backend->viewPort.y * scale,
|
||||||
backend->viewPort.w * scale,
|
backend->viewPort.w * scale,
|
||||||
backend->viewPort.h * scale,
|
backend->viewPort.h * scale,
|
||||||
0,
|
0,
|
||||||
1};
|
1};
|
||||||
|
|
||||||
MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||||
renderPassDescriptor.colorAttachments[0].texture = surface->drawable.texture;
|
renderPassDescriptor.colorAttachments[0].texture = surface->drawable.texture;
|
||||||
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
|
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||||
|
|
||||||
id<MTLRenderCommandEncoder> renderEncoder = [surface->commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
|
id<MTLRenderCommandEncoder> renderEncoder = [surface->commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
|
||||||
[renderEncoder setViewport: viewport];
|
[renderEncoder setViewport: viewport];
|
||||||
[renderEncoder setRenderPipelineState: backend->renderPipeline];
|
[renderEncoder setRenderPipelineState: backend->renderPipeline];
|
||||||
[renderEncoder setFragmentTexture: backend->outTexture atIndex: 0];
|
[renderEncoder setFragmentTexture: backend->outTexture atIndex: 0];
|
||||||
[renderEncoder drawPrimitives: MTLPrimitiveTypeTriangle
|
[renderEncoder drawPrimitives: MTLPrimitiveTypeTriangle
|
||||||
vertexStart: 0
|
vertexStart: 0
|
||||||
vertexCount: 3 ];
|
vertexCount: 3 ];
|
||||||
[renderEncoder endEncoding];
|
[renderEncoder endEncoding];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
void mg_metal_canvas_viewport(mg_canvas_backend* interface, mp_rect viewPort)
|
void mg_metal_canvas_viewport(mg_canvas_backend* interface, mp_rect viewPort)
|
||||||
{
|
{
|
||||||
mg_metal_canvas_backend* backend = (mg_metal_canvas_backend*)interface;
|
mg_metal_canvas_backend* backend = (mg_metal_canvas_backend*)interface;
|
||||||
mg_metal_surface* surface = mg_metal_canvas_get_surface(backend);
|
mg_metal_surface* surface = mg_metal_canvas_get_surface(backend);
|
||||||
if(!surface)
|
if(!surface)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
backend->viewPort = viewPort;
|
backend->viewPort = viewPort;
|
||||||
|
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
{
|
{
|
||||||
f32 scale = surface->metalLayer.contentsScale;
|
f32 scale = surface->metalLayer.contentsScale;
|
||||||
CGSize drawableSize = (CGSize){.width = viewPort.w * scale, .height = viewPort.h * scale};
|
CGSize drawableSize = (CGSize){.width = viewPort.w * scale, .height = viewPort.h * scale};
|
||||||
|
|
||||||
[backend->outTexture release];
|
[backend->outTexture release];
|
||||||
|
|
||||||
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
|
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
|
||||||
texDesc.textureType = MTLTextureType2D;
|
texDesc.textureType = MTLTextureType2D;
|
||||||
texDesc.storageMode = MTLStorageModePrivate;
|
texDesc.storageMode = MTLStorageModePrivate;
|
||||||
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
|
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
|
||||||
texDesc.pixelFormat = MTLPixelFormatBGRA8Unorm;// MTLPixelFormatBGRA8Unorm_sRGB;
|
texDesc.pixelFormat = MTLPixelFormatBGRA8Unorm;// MTLPixelFormatBGRA8Unorm_sRGB;
|
||||||
texDesc.width = drawableSize.width;
|
texDesc.width = drawableSize.width;
|
||||||
texDesc.height = drawableSize.height;
|
texDesc.height = drawableSize.height;
|
||||||
|
|
||||||
backend->outTexture = [surface->device newTextureWithDescriptor:texDesc];
|
backend->outTexture = [surface->device newTextureWithDescriptor:texDesc];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void mg_metal_canvas_update_vertex_layout(mg_metal_canvas_backend* backend)
|
void mg_metal_canvas_update_vertex_layout(mg_metal_canvas_backend* backend)
|
||||||
{
|
{
|
||||||
char* vertexBase = (char*)[backend->vertexBuffer contents];
|
char* vertexBase = (char*)[backend->vertexBuffer contents];
|
||||||
|
|
||||||
backend->interface.vertexLayout = (mg_vertex_layout){
|
backend->interface.vertexLayout = (mg_vertex_layout){
|
||||||
.maxVertexCount = MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH,
|
.maxVertexCount = MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH,
|
||||||
.maxIndexCount = MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH,
|
.maxIndexCount = MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH,
|
||||||
.posBuffer = vertexBase + offsetof(mg_vertex, pos),
|
.posBuffer = vertexBase + offsetof(mg_vertex, pos),
|
||||||
.posStride = sizeof(mg_vertex),
|
.posStride = sizeof(mg_vertex),
|
||||||
.cubicBuffer = vertexBase + offsetof(mg_vertex, cubic),
|
.cubicBuffer = vertexBase + offsetof(mg_vertex, cubic),
|
||||||
.cubicStride = sizeof(mg_vertex),
|
.cubicStride = sizeof(mg_vertex),
|
||||||
.uvBuffer = vertexBase + offsetof(mg_vertex, uv),
|
.uvBuffer = vertexBase + offsetof(mg_vertex, uv),
|
||||||
.uvStride = sizeof(mg_vertex),
|
.uvStride = sizeof(mg_vertex),
|
||||||
.colorBuffer = vertexBase + offsetof(mg_vertex, color),
|
.colorBuffer = vertexBase + offsetof(mg_vertex, color),
|
||||||
.colorStride = sizeof(mg_vertex),
|
.colorStride = sizeof(mg_vertex),
|
||||||
.zIndexBuffer = vertexBase + offsetof(mg_vertex, zIndex),
|
.zIndexBuffer = vertexBase + offsetof(mg_vertex, zIndex),
|
||||||
.zIndexStride = sizeof(mg_vertex),
|
.zIndexStride = sizeof(mg_vertex),
|
||||||
.clipsBuffer = vertexBase + offsetof(mg_vertex, clip),
|
.clipBuffer = vertexBase + offsetof(mg_vertex, clip),
|
||||||
.clipsStride = sizeof(mg_vertex),
|
.clipStride = sizeof(mg_vertex),
|
||||||
.indexBuffer = [backend->indexBuffer contents],
|
.indexBuffer = [backend->indexBuffer contents],
|
||||||
.indexStride = sizeof(int)};
|
.indexStride = sizeof(int)};
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_metal_canvas_destroy(mg_canvas_backend* interface)
|
void mg_metal_canvas_destroy(mg_canvas_backend* interface)
|
||||||
{
|
{
|
||||||
mg_metal_canvas_backend* backend = (mg_metal_canvas_backend*)interface;
|
mg_metal_canvas_backend* backend = (mg_metal_canvas_backend*)interface;
|
||||||
|
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
{
|
{
|
||||||
[backend->outTexture release];
|
[backend->outTexture release];
|
||||||
[backend->atlasTexture release];
|
[backend->atlasTexture release];
|
||||||
[backend->vertexBuffer release];
|
[backend->vertexBuffer release];
|
||||||
[backend->indexBuffer release];
|
[backend->indexBuffer release];
|
||||||
[backend->tilesArray release];
|
[backend->tilesArray release];
|
||||||
[backend->triangleArray release];
|
[backend->triangleArray release];
|
||||||
[backend->boxArray release];
|
[backend->boxArray release];
|
||||||
[backend->computePipeline release];
|
[backend->computePipeline release];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_metal_canvas_atlas_upload(mg_canvas_backend* interface, mp_rect rect, u8* bytes)
|
void mg_metal_canvas_atlas_upload(mg_canvas_backend* interface, mp_rect rect, u8* bytes)
|
||||||
{@autoreleasepool{
|
{@autoreleasepool{
|
||||||
mg_metal_canvas_backend* backend = (mg_metal_canvas_backend*)interface;
|
mg_metal_canvas_backend* backend = (mg_metal_canvas_backend*)interface;
|
||||||
|
|
||||||
MTLRegion region = MTLRegionMake2D(rect.x, rect.y, rect.w, rect.h);
|
MTLRegion region = MTLRegionMake2D(rect.x, rect.y, rect.w, rect.h);
|
||||||
[backend->atlasTexture replaceRegion:region
|
[backend->atlasTexture replaceRegion:region
|
||||||
mipmapLevel:0
|
mipmapLevel:0
|
||||||
withBytes:(void*)bytes
|
withBytes:(void*)bytes
|
||||||
bytesPerRow: 4 * rect.w];
|
bytesPerRow: 4 * rect.w];
|
||||||
}}
|
}}
|
||||||
|
|
||||||
mg_canvas_backend* mg_metal_canvas_create(mg_surface surface)
|
mg_canvas_backend* mg_metal_canvas_create(mg_surface surface)
|
||||||
{
|
{
|
||||||
mg_metal_canvas_backend* backend = 0;
|
mg_metal_canvas_backend* backend = 0;
|
||||||
|
|
||||||
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
|
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
|
||||||
if(surfaceData && surfaceData->backend == MG_BACKEND_METAL)
|
if(surfaceData && surfaceData->backend == MG_BACKEND_METAL)
|
||||||
{
|
{
|
||||||
mg_metal_surface* metalSurface = (mg_metal_surface*)surfaceData;
|
mg_metal_surface* metalSurface = (mg_metal_surface*)surfaceData;
|
||||||
|
|
||||||
backend = malloc_type(mg_metal_canvas_backend);
|
backend = malloc_type(mg_metal_canvas_backend);
|
||||||
backend->surface = surface;
|
backend->surface = surface;
|
||||||
|
|
||||||
//NOTE(martin): setup interface functions
|
//NOTE(martin): setup interface functions
|
||||||
backend->interface.destroy = mg_metal_canvas_destroy;
|
backend->interface.destroy = mg_metal_canvas_destroy;
|
||||||
backend->interface.drawBuffers = mg_metal_canvas_draw_buffers;
|
backend->interface.drawBuffers = mg_metal_canvas_draw_buffers;
|
||||||
backend->interface.atlasUpload = mg_metal_canvas_atlas_upload;
|
backend->interface.atlasUpload = mg_metal_canvas_atlas_upload;
|
||||||
|
|
||||||
mp_rect frame = mg_surface_get_frame(surface);
|
mp_rect frame = mg_surface_get_frame(surface);
|
||||||
backend->viewPort = (mp_rect){0, 0, frame.w, frame.h};
|
backend->viewPort = (mp_rect){0, 0, frame.w, frame.h};
|
||||||
|
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
{
|
{
|
||||||
f32 scale = metalSurface->metalLayer.contentsScale;
|
f32 scale = metalSurface->metalLayer.contentsScale;
|
||||||
CGSize drawableSize = (CGSize){.width = backend->viewPort.w * scale, .height = backend->viewPort.h * scale};
|
CGSize drawableSize = (CGSize){.width = backend->viewPort.w * scale, .height = backend->viewPort.h * scale};
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): create our output texture
|
//NOTE(martin): create our output texture
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
|
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
|
||||||
texDesc.textureType = MTLTextureType2D;
|
texDesc.textureType = MTLTextureType2D;
|
||||||
texDesc.storageMode = MTLStorageModePrivate;
|
texDesc.storageMode = MTLStorageModePrivate;
|
||||||
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
|
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
|
||||||
texDesc.pixelFormat = MTLPixelFormatBGRA8Unorm;// MTLPixelFormatBGRA8Unorm_sRGB;
|
texDesc.pixelFormat = MTLPixelFormatBGRA8Unorm;// MTLPixelFormatBGRA8Unorm_sRGB;
|
||||||
texDesc.width = drawableSize.width;
|
texDesc.width = drawableSize.width;
|
||||||
texDesc.height = drawableSize.height;
|
texDesc.height = drawableSize.height;
|
||||||
|
|
||||||
backend->outTexture = [metalSurface->device newTextureWithDescriptor:texDesc];
|
backend->outTexture = [metalSurface->device newTextureWithDescriptor:texDesc];
|
||||||
//TODO(martin): retain ?
|
//TODO(martin): retain ?
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): create our atlas texture
|
//NOTE(martin): create our atlas texture
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
texDesc.textureType = MTLTextureType2D;
|
texDesc.textureType = MTLTextureType2D;
|
||||||
texDesc.storageMode = MTLStorageModeManaged;
|
texDesc.storageMode = MTLStorageModeManaged;
|
||||||
texDesc.usage = MTLTextureUsageShaderRead;
|
texDesc.usage = MTLTextureUsageShaderRead;
|
||||||
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm; //MTLPixelFormatBGRA8Unorm;
|
texDesc.pixelFormat = MTLPixelFormatRGBA8Unorm; //MTLPixelFormatBGRA8Unorm;
|
||||||
texDesc.width = MG_ATLAS_SIZE;
|
texDesc.width = MG_ATLAS_SIZE;
|
||||||
texDesc.height = MG_ATLAS_SIZE;
|
texDesc.height = MG_ATLAS_SIZE;
|
||||||
|
|
||||||
backend->atlasTexture = [metalSurface->device newTextureWithDescriptor:texDesc];
|
backend->atlasTexture = [metalSurface->device newTextureWithDescriptor:texDesc];
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): create buffers for vertex and index
|
//NOTE(martin): create buffers for vertex and index
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
|
|
||||||
MTLResourceOptions bufferOptions = MTLResourceCPUCacheModeWriteCombined
|
MTLResourceOptions bufferOptions = MTLResourceCPUCacheModeWriteCombined
|
||||||
| MTLResourceStorageModeShared;
|
| MTLResourceStorageModeShared;
|
||||||
|
|
||||||
backend->indexBuffer = [metalSurface->device newBufferWithLength: MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(int)
|
backend->indexBuffer = [metalSurface->device newBufferWithLength: MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(int)
|
||||||
options: bufferOptions];
|
options: bufferOptions];
|
||||||
|
|
||||||
backend->vertexBuffer = [metalSurface->device newBufferWithLength: MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(mg_vertex)
|
backend->vertexBuffer = [metalSurface->device newBufferWithLength: MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(mg_vertex)
|
||||||
options: bufferOptions];
|
options: bufferOptions];
|
||||||
|
|
||||||
backend->tilesArray = [metalSurface->device newBufferWithLength: RENDERER_TILE_BUFFER_SIZE*sizeof(int)*RENDERER_MAX_TILES
|
backend->tilesArray = [metalSurface->device newBufferWithLength: RENDERER_TILE_BUFFER_SIZE*sizeof(int)*RENDERER_MAX_TILES
|
||||||
options: MTLResourceStorageModePrivate];
|
options: MTLResourceStorageModePrivate];
|
||||||
|
|
||||||
backend->triangleArray = [metalSurface->device newBufferWithLength: MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(mg_triangle_data)
|
backend->triangleArray = [metalSurface->device newBufferWithLength: MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(mg_triangle_data)
|
||||||
options: MTLResourceStorageModePrivate];
|
options: MTLResourceStorageModePrivate];
|
||||||
|
|
||||||
backend->boxArray = [metalSurface->device newBufferWithLength: MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(vector_float4)
|
backend->boxArray = [metalSurface->device newBufferWithLength: MG_METAL_CANVAS_DEFAULT_BUFFER_LENGTH*sizeof(vector_float4)
|
||||||
options: MTLResourceStorageModePrivate];
|
options: MTLResourceStorageModePrivate];
|
||||||
|
|
||||||
//TODO(martin): retain ?
|
//TODO(martin): retain ?
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): create and initialize tile counters
|
//NOTE(martin): create and initialize tile counters
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
backend->tileCounters = [metalSurface->device newBufferWithLength: RENDERER_MAX_TILES*sizeof(uint)
|
backend->tileCounters = [metalSurface->device newBufferWithLength: RENDERER_MAX_TILES*sizeof(uint)
|
||||||
options: MTLResourceStorageModePrivate];
|
options: MTLResourceStorageModePrivate];
|
||||||
id<MTLCommandBuffer> commandBuffer = [metalSurface->commandQueue commandBuffer];
|
id<MTLCommandBuffer> commandBuffer = [metalSurface->commandQueue commandBuffer];
|
||||||
id<MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];
|
id<MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];
|
||||||
[blitEncoder fillBuffer: backend->tileCounters range: NSMakeRange(0, RENDERER_MAX_TILES*sizeof(uint)) value: 0];
|
[blitEncoder fillBuffer: backend->tileCounters range: NSMakeRange(0, RENDERER_MAX_TILES*sizeof(uint)) value: 0];
|
||||||
[blitEncoder endEncoding];
|
[blitEncoder endEncoding];
|
||||||
[commandBuffer commit];
|
[commandBuffer commit];
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): load the library
|
//NOTE(martin): load the library
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
|
|
||||||
//TODO(martin): filepath magic to find metallib path when not in the working directory
|
//TODO(martin): filepath magic to find metallib path when not in the working directory
|
||||||
str8 shaderPath = mp_app_get_resource_path(mem_scratch(), "../resources/metal_shader.metallib");
|
str8 shaderPath = mp_app_get_resource_path(mem_scratch(), "../resources/metal_shader.metallib");
|
||||||
NSString* metalFileName = [[NSString alloc] initWithBytes: shaderPath.ptr length:shaderPath.len encoding: NSUTF8StringEncoding];
|
NSString* metalFileName = [[NSString alloc] initWithBytes: shaderPath.ptr length:shaderPath.len encoding: NSUTF8StringEncoding];
|
||||||
NSError* err = 0;
|
NSError* err = 0;
|
||||||
id<MTLLibrary> library = [metalSurface->device newLibraryWithFile: metalFileName error:&err];
|
id<MTLLibrary> library = [metalSurface->device newLibraryWithFile: metalFileName error:&err];
|
||||||
if(err != nil)
|
if(err != nil)
|
||||||
{
|
{
|
||||||
const char* errStr = [[err localizedDescription] UTF8String];
|
const char* errStr = [[err localizedDescription] UTF8String];
|
||||||
LOG_ERROR("error : %s\n", errStr);
|
LOG_ERROR("error : %s\n", errStr);
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
id<MTLFunction> tilingFunction = [library newFunctionWithName:@"TileKernel"];
|
id<MTLFunction> tilingFunction = [library newFunctionWithName:@"TileKernel"];
|
||||||
id<MTLFunction> sortingFunction = [library newFunctionWithName:@"SortKernel"];
|
id<MTLFunction> sortingFunction = [library newFunctionWithName:@"SortKernel"];
|
||||||
id<MTLFunction> boxingFunction = [library newFunctionWithName:@"BoundingBoxKernel"];
|
id<MTLFunction> boxingFunction = [library newFunctionWithName:@"BoundingBoxKernel"];
|
||||||
id<MTLFunction> computeFunction = [library newFunctionWithName:@"RenderKernel"];
|
id<MTLFunction> computeFunction = [library newFunctionWithName:@"RenderKernel"];
|
||||||
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"VertexShader"];
|
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"VertexShader"];
|
||||||
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"FragmentShader"];
|
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"FragmentShader"];
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): setup our data layout and pipeline state
|
//NOTE(martin): setup our data layout and pipeline state
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
NSError* error = NULL;
|
NSError* error = NULL;
|
||||||
backend->computePipeline = [metalSurface->device newComputePipelineStateWithFunction: computeFunction
|
backend->computePipeline = [metalSurface->device newComputePipelineStateWithFunction: computeFunction
|
||||||
error:&error];
|
error:&error];
|
||||||
ASSERT(backend->computePipeline);
|
ASSERT(backend->computePipeline);
|
||||||
|
|
||||||
MTLComputePipelineDescriptor* tilingPipelineDesc = [[MTLComputePipelineDescriptor alloc] init];
|
MTLComputePipelineDescriptor* tilingPipelineDesc = [[MTLComputePipelineDescriptor alloc] init];
|
||||||
tilingPipelineDesc.computeFunction = tilingFunction;
|
tilingPipelineDesc.computeFunction = tilingFunction;
|
||||||
// tilingPipelineDesc.threadGroupSizeIsMultipleOfThreadExecutionWidth = true;
|
// tilingPipelineDesc.threadGroupSizeIsMultipleOfThreadExecutionWidth = true;
|
||||||
|
|
||||||
backend->tilingPipeline = [metalSurface->device newComputePipelineStateWithDescriptor: tilingPipelineDesc
|
backend->tilingPipeline = [metalSurface->device newComputePipelineStateWithDescriptor: tilingPipelineDesc
|
||||||
options: MTLPipelineOptionNone
|
options: MTLPipelineOptionNone
|
||||||
reflection: nil
|
reflection: nil
|
||||||
error: &error];
|
error: &error];
|
||||||
|
|
||||||
MTLComputePipelineDescriptor* sortingPipelineDesc = [[MTLComputePipelineDescriptor alloc] init];
|
MTLComputePipelineDescriptor* sortingPipelineDesc = [[MTLComputePipelineDescriptor alloc] init];
|
||||||
sortingPipelineDesc.computeFunction = sortingFunction;
|
sortingPipelineDesc.computeFunction = sortingFunction;
|
||||||
// sortingPipelineDesc.threadGroupSizeIsMultipleOfThreadExecutionWidth = true;
|
// sortingPipelineDesc.threadGroupSizeIsMultipleOfThreadExecutionWidth = true;
|
||||||
|
|
||||||
backend->sortingPipeline = [metalSurface->device newComputePipelineStateWithDescriptor: sortingPipelineDesc
|
backend->sortingPipeline = [metalSurface->device newComputePipelineStateWithDescriptor: sortingPipelineDesc
|
||||||
options: MTLPipelineOptionNone
|
options: MTLPipelineOptionNone
|
||||||
reflection: nil
|
reflection: nil
|
||||||
error: &error];
|
error: &error];
|
||||||
|
|
||||||
MTLComputePipelineDescriptor* boxingPipelineDesc = [[MTLComputePipelineDescriptor alloc] init];
|
MTLComputePipelineDescriptor* boxingPipelineDesc = [[MTLComputePipelineDescriptor alloc] init];
|
||||||
boxingPipelineDesc.computeFunction = boxingFunction;
|
boxingPipelineDesc.computeFunction = boxingFunction;
|
||||||
// boxingPipelineDesc.threadGroupSizeIsMultipleOfThreadExecutionWidth = true;
|
// boxingPipelineDesc.threadGroupSizeIsMultipleOfThreadExecutionWidth = true;
|
||||||
|
|
||||||
backend->boxingPipeline = [metalSurface->device newComputePipelineStateWithDescriptor: boxingPipelineDesc
|
backend->boxingPipeline = [metalSurface->device newComputePipelineStateWithDescriptor: boxingPipelineDesc
|
||||||
options: MTLPipelineOptionNone
|
options: MTLPipelineOptionNone
|
||||||
reflection: nil
|
reflection: nil
|
||||||
error: &error];
|
error: &error];
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
//NOTE(martin): setup our render pipeline state
|
//NOTE(martin): setup our render pipeline state
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
// create and initialize the pipeline state descriptor
|
// create and initialize the pipeline state descriptor
|
||||||
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||||
pipelineStateDescriptor.label = @"My simple pipeline";
|
pipelineStateDescriptor.label = @"My simple pipeline";
|
||||||
pipelineStateDescriptor.vertexFunction = vertexFunction;
|
pipelineStateDescriptor.vertexFunction = vertexFunction;
|
||||||
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
|
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
|
||||||
pipelineStateDescriptor.colorAttachments[0].pixelFormat = metalSurface->metalLayer.pixelFormat;
|
pipelineStateDescriptor.colorAttachments[0].pixelFormat = metalSurface->metalLayer.pixelFormat;
|
||||||
|
|
||||||
// create render pipeline
|
// create render pipeline
|
||||||
backend->renderPipeline = [metalSurface->device newRenderPipelineStateWithDescriptor: pipelineStateDescriptor error:&err];
|
backend->renderPipeline = [metalSurface->device newRenderPipelineStateWithDescriptor: pipelineStateDescriptor error:&err];
|
||||||
if(err != nil)
|
if(err != nil)
|
||||||
{
|
{
|
||||||
const char* errStr = [[err localizedDescription] UTF8String];
|
const char* errStr = [[err localizedDescription] UTF8String];
|
||||||
const char* descStr = [[err localizedFailureReason] UTF8String];
|
const char* descStr = [[err localizedFailureReason] UTF8String];
|
||||||
const char* recovStr = [[err localizedRecoverySuggestion] UTF8String];
|
const char* recovStr = [[err localizedRecoverySuggestion] UTF8String];
|
||||||
LOG_ERROR("(%li) %s. %s. %s\n", [err code], errStr, descStr, recovStr);
|
LOG_ERROR("(%li) %s. %s. %s\n", [err code], errStr, descStr, recovStr);
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mg_metal_canvas_update_vertex_layout(backend);
|
mg_metal_canvas_update_vertex_layout(backend);
|
||||||
}
|
}
|
||||||
|
|
||||||
return((mg_canvas_backend*)backend);
|
return((mg_canvas_backend*)backend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef LOG_SUBSYSTEM
|
#undef LOG_SUBSYSTEM
|
||||||
|
|
|
@ -1,349 +1,349 @@
|
||||||
|
|
||||||
#include<metal_stdlib>
|
#include<metal_stdlib>
|
||||||
#include<simd/simd.h>
|
#include<simd/simd.h>
|
||||||
|
|
||||||
#include"metal_shader.h"
|
#include"metal_shader.h"
|
||||||
|
|
||||||
using namespace metal;
|
using namespace metal;
|
||||||
|
|
||||||
struct vs_out
|
struct vs_out
|
||||||
{
|
{
|
||||||
float4 pos [[position]];
|
float4 pos [[position]];
|
||||||
float2 uv;
|
float2 uv;
|
||||||
};
|
};
|
||||||
|
|
||||||
vertex vs_out VertexShader(ushort vid [[vertex_id]])
|
vertex vs_out VertexShader(ushort vid [[vertex_id]])
|
||||||
{
|
{
|
||||||
vs_out out;
|
vs_out out;
|
||||||
out.uv = float2((vid << 1) & 2, vid & 2);
|
out.uv = float2((vid << 1) & 2, vid & 2);
|
||||||
out.pos = float4(out.uv * float2(2, 2) + float2(-1, -1), 0, 1);
|
out.pos = float4(out.uv * float2(2, 2) + float2(-1, -1), 0, 1);
|
||||||
return(out);
|
return(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment float4 FragmentShader(vs_out i [[stage_in]], texture2d<float> tex [[texture(0)]])
|
fragment float4 FragmentShader(vs_out i [[stage_in]], texture2d<float> tex [[texture(0)]])
|
||||||
{
|
{
|
||||||
constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear);
|
constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear);
|
||||||
return(float4(tex.sample(smp, i.uv).rgb, 1));
|
return(float4(tex.sample(smp, i.uv).rgb, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_top_left(float2 a, float2 b)
|
bool is_top_left(float2 a, float2 b)
|
||||||
{
|
{
|
||||||
return( (a.y == b.y && b.x < a.x)
|
return( (a.y == b.y && b.x < a.x)
|
||||||
||(b.y < a.y));
|
||(b.y < a.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel void BoundingBoxKernel(constant mg_vertex* vertexBuffer [[buffer(0)]],
|
kernel void BoundingBoxKernel(constant mg_vertex* vertexBuffer [[buffer(0)]],
|
||||||
constant uint* indexBuffer [[buffer(1)]],
|
constant uint* indexBuffer [[buffer(1)]],
|
||||||
device mg_triangle_data* triangleArray [[buffer(2)]],
|
device mg_triangle_data* triangleArray [[buffer(2)]],
|
||||||
device float4* boxArray [[buffer(3)]],
|
device float4* boxArray [[buffer(3)]],
|
||||||
constant float* contentsScaling [[buffer(4)]],
|
constant float* contentsScaling [[buffer(4)]],
|
||||||
uint gid [[thread_position_in_grid]])
|
uint gid [[thread_position_in_grid]])
|
||||||
{
|
{
|
||||||
uint triangleIndex = gid;
|
uint triangleIndex = gid;
|
||||||
uint vertexIndex = triangleIndex*3;
|
uint vertexIndex = triangleIndex*3;
|
||||||
|
|
||||||
uint i0 = indexBuffer[vertexIndex];
|
uint i0 = indexBuffer[vertexIndex];
|
||||||
uint i1 = indexBuffer[vertexIndex+1];
|
uint i1 = indexBuffer[vertexIndex+1];
|
||||||
uint i2 = indexBuffer[vertexIndex+2];
|
uint i2 = indexBuffer[vertexIndex+2];
|
||||||
|
|
||||||
float2 p0 = vertexBuffer[i0].pos * contentsScaling[0];
|
float2 p0 = vertexBuffer[i0].pos * contentsScaling[0];
|
||||||
float2 p1 = vertexBuffer[i1].pos * contentsScaling[0];
|
float2 p1 = vertexBuffer[i1].pos * contentsScaling[0];
|
||||||
float2 p2 = vertexBuffer[i2].pos * contentsScaling[0];
|
float2 p2 = vertexBuffer[i2].pos * contentsScaling[0];
|
||||||
|
|
||||||
//NOTE(martin): compute triangle bounding box
|
//NOTE(martin): compute triangle bounding box
|
||||||
float2 boxMin = min(min(p0, p1), p2);
|
float2 boxMin = min(min(p0, p1), p2);
|
||||||
float2 boxMax = max(max(p0, p1), p2);
|
float2 boxMax = max(max(p0, p1), p2);
|
||||||
|
|
||||||
//NOTE(martin): clip bounding box against clip rect
|
//NOTE(martin): clip bounding box against clip rect
|
||||||
vector_float4 clip = contentsScaling[0]*vertexBuffer[indexBuffer[vertexIndex]].clip;
|
vector_float4 clip = contentsScaling[0]*vertexBuffer[indexBuffer[vertexIndex]].clip;
|
||||||
float2 clipMin(clip.x, clip.y);
|
float2 clipMin(clip.x, clip.y);
|
||||||
float2 clipMax(clip.x + clip.z-1, clip.y + clip.w-1);
|
float2 clipMax(clip.x + clip.z-1, clip.y + clip.w-1);
|
||||||
|
|
||||||
//NOTE(martin): intersect with current clip
|
//NOTE(martin): intersect with current clip
|
||||||
boxMin = max(boxMin, clipMin);
|
boxMin = max(boxMin, clipMin);
|
||||||
boxMax = min(boxMax, clipMax);
|
boxMax = min(boxMax, clipMax);
|
||||||
|
|
||||||
//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
|
//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
|
||||||
float cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;
|
float cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;
|
||||||
if(cw < 0)
|
if(cw < 0)
|
||||||
{
|
{
|
||||||
uint tmpIndex = i1;
|
uint tmpIndex = i1;
|
||||||
i1 = i2;
|
i1 = i2;
|
||||||
i2 = tmpIndex;
|
i2 = tmpIndex;
|
||||||
|
|
||||||
float2 tmpPoint = p1;
|
float2 tmpPoint = p1;
|
||||||
p1 = p2;
|
p1 = p2;
|
||||||
p2 = tmpPoint;
|
p2 = tmpPoint;
|
||||||
}
|
}
|
||||||
int bias0 = is_top_left(p1, p2) ? 0 : -1;
|
int bias0 = is_top_left(p1, p2) ? 0 : -1;
|
||||||
int bias1 = is_top_left(p2, p0) ? 0 : -1;
|
int bias1 = is_top_left(p2, p0) ? 0 : -1;
|
||||||
int bias2 = is_top_left(p0, p1) ? 0 : -1;
|
int bias2 = is_top_left(p0, p1) ? 0 : -1;
|
||||||
|
|
||||||
//NOTE(martin): fill triangle data
|
//NOTE(martin): fill triangle data
|
||||||
boxArray[triangleIndex] = float4(boxMin.x, boxMin.y, boxMax.x, boxMax.y);
|
boxArray[triangleIndex] = float4(boxMin.x, boxMin.y, boxMax.x, boxMax.y);
|
||||||
|
|
||||||
triangleArray[triangleIndex].zIndex = vertexBuffer[i0].zIndex;
|
triangleArray[triangleIndex].zIndex = vertexBuffer[i0].zIndex;
|
||||||
triangleArray[triangleIndex].i0 = i0;
|
triangleArray[triangleIndex].i0 = i0;
|
||||||
triangleArray[triangleIndex].i1 = i1;
|
triangleArray[triangleIndex].i1 = i1;
|
||||||
triangleArray[triangleIndex].i2 = i2;
|
triangleArray[triangleIndex].i2 = i2;
|
||||||
triangleArray[triangleIndex].p0 = p0;
|
triangleArray[triangleIndex].p0 = p0;
|
||||||
triangleArray[triangleIndex].p1 = p1;
|
triangleArray[triangleIndex].p1 = p1;
|
||||||
triangleArray[triangleIndex].p2 = p2;
|
triangleArray[triangleIndex].p2 = p2;
|
||||||
triangleArray[triangleIndex].bias0 = bias0;
|
triangleArray[triangleIndex].bias0 = bias0;
|
||||||
triangleArray[triangleIndex].bias1 = bias1;
|
triangleArray[triangleIndex].bias1 = bias1;
|
||||||
triangleArray[triangleIndex].bias2 = bias2;
|
triangleArray[triangleIndex].bias2 = bias2;
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel void TileKernel(const device float4* boxArray [[buffer(0)]],
|
kernel void TileKernel(const device float4* boxArray [[buffer(0)]],
|
||||||
device volatile atomic_uint* tileCounters [[buffer(1)]],
|
device volatile atomic_uint* tileCounters [[buffer(1)]],
|
||||||
device uint* tilesArray [[buffer(2)]],
|
device uint* tilesArray [[buffer(2)]],
|
||||||
constant vector_uint2* viewport [[buffer(3)]],
|
constant vector_uint2* viewport [[buffer(3)]],
|
||||||
uint gid [[thread_position_in_grid]])
|
uint gid [[thread_position_in_grid]])
|
||||||
{
|
{
|
||||||
uint2 tilesMatrixDim = (*viewport - 1) / RENDERER_TILE_SIZE + 1;
|
uint2 tilesMatrixDim = (*viewport - 1) / RENDERER_TILE_SIZE + 1;
|
||||||
uint nTilesX = tilesMatrixDim.x;
|
uint nTilesX = tilesMatrixDim.x;
|
||||||
uint nTilesY = tilesMatrixDim.y;
|
uint nTilesY = tilesMatrixDim.y;
|
||||||
|
|
||||||
uint triangleIndex = gid;
|
uint triangleIndex = gid;
|
||||||
uint4 box = uint4(floor(boxArray[triangleIndex]))/RENDERER_TILE_SIZE;
|
uint4 box = uint4(floor(boxArray[triangleIndex]))/RENDERER_TILE_SIZE;
|
||||||
uint xMin = max((uint)0, box.x);
|
uint xMin = max((uint)0, box.x);
|
||||||
uint yMin = max((uint)0, box.y);
|
uint yMin = max((uint)0, box.y);
|
||||||
uint xMax = min(box.z, nTilesX-1);
|
uint xMax = min(box.z, nTilesX-1);
|
||||||
uint yMax = min(box.w, nTilesY-1);
|
uint yMax = min(box.w, nTilesY-1);
|
||||||
|
|
||||||
for(uint y = yMin; y <= yMax; y++)
|
for(uint y = yMin; y <= yMax; y++)
|
||||||
{
|
{
|
||||||
for(uint x = xMin ; x <= xMax; x++)
|
for(uint x = xMin ; x <= xMax; x++)
|
||||||
{
|
{
|
||||||
uint tileIndex = y*nTilesX + x;
|
uint tileIndex = y*nTilesX + x;
|
||||||
device uint* tileBuffer = tilesArray + tileIndex*RENDERER_TILE_BUFFER_SIZE;
|
device uint* tileBuffer = tilesArray + tileIndex*RENDERER_TILE_BUFFER_SIZE;
|
||||||
uint counter = atomic_fetch_add_explicit(&(tileCounters[tileIndex]), 1, memory_order_relaxed);
|
uint counter = atomic_fetch_add_explicit(&(tileCounters[tileIndex]), 1, memory_order_relaxed);
|
||||||
tileBuffer[counter] = triangleIndex;
|
tileBuffer[counter] = triangleIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel void SortKernel(const device uint* tileCounters [[buffer(0)]],
|
kernel void SortKernel(const device uint* tileCounters [[buffer(0)]],
|
||||||
const device mg_triangle_data* triangleArray [[buffer(1)]],
|
const device mg_triangle_data* triangleArray [[buffer(1)]],
|
||||||
device uint* tilesArray [[buffer(2)]],
|
device uint* tilesArray [[buffer(2)]],
|
||||||
constant vector_uint2* viewport [[buffer(3)]],
|
constant vector_uint2* viewport [[buffer(3)]],
|
||||||
uint gid [[thread_position_in_grid]])
|
uint gid [[thread_position_in_grid]])
|
||||||
{
|
{
|
||||||
uint tileIndex = gid;
|
uint tileIndex = gid;
|
||||||
device uint* tileBuffer = tilesArray + tileIndex*RENDERER_TILE_BUFFER_SIZE;
|
device uint* tileBuffer = tilesArray + tileIndex*RENDERER_TILE_BUFFER_SIZE;
|
||||||
uint tileBufferSize = tileCounters[tileIndex];
|
uint tileBufferSize = tileCounters[tileIndex];
|
||||||
|
|
||||||
for(int eltIndex=0; eltIndex < (int)tileBufferSize; eltIndex++)
|
for(int eltIndex=0; eltIndex < (int)tileBufferSize; eltIndex++)
|
||||||
{
|
{
|
||||||
uint elt = tileBuffer[eltIndex];
|
uint elt = tileBuffer[eltIndex];
|
||||||
uint eltZIndex = triangleArray[elt].zIndex;
|
uint eltZIndex = triangleArray[elt].zIndex;
|
||||||
|
|
||||||
int backIndex = eltIndex-1;
|
int backIndex = eltIndex-1;
|
||||||
for(; backIndex >= 0; backIndex--)
|
for(; backIndex >= 0; backIndex--)
|
||||||
{
|
{
|
||||||
uint backElt = tileBuffer[backIndex];
|
uint backElt = tileBuffer[backIndex];
|
||||||
uint backEltZIndex = triangleArray[backElt].zIndex;
|
uint backEltZIndex = triangleArray[backElt].zIndex;
|
||||||
if(eltZIndex >= backEltZIndex)
|
if(eltZIndex >= backEltZIndex)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tileBuffer[backIndex+1] = backElt;
|
tileBuffer[backIndex+1] = backElt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tileBuffer[backIndex+1] = elt;
|
tileBuffer[backIndex+1] = elt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float orient2d(float2 a, float2 b, float2 c)
|
float orient2d(float2 a, float2 b, float2 c)
|
||||||
{
|
{
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//TODO(martin): FIX this. This is a **horrible** quick hack to fix the precision issues
|
//TODO(martin): FIX this. This is a **horrible** quick hack to fix the precision issues
|
||||||
// arising when a, b, and c are close. But it degrades when a, c, and c
|
// arising when a, b, and c are close. But it degrades when a, c, and c
|
||||||
// are big. The proper solution is to change the expression to avoid
|
// are big. The proper solution is to change the expression to avoid
|
||||||
// precision loss but I'm too busy/lazy to do it now.
|
// precision loss but I'm too busy/lazy to do it now.
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
a *= 10;
|
a *= 10;
|
||||||
b *= 10;
|
b *= 10;
|
||||||
c *= 10;
|
c *= 10;
|
||||||
return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
|
return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel void RenderKernel(texture2d<float, access::write> outTexture [[texture(0)]],
|
kernel void RenderKernel(texture2d<float, access::write> outTexture [[texture(0)]],
|
||||||
texture2d<float> texAtlas [[texture(1)]],
|
texture2d<float> texAtlas [[texture(1)]],
|
||||||
const device mg_vertex* vertexBuffer [[buffer(0)]],
|
const device mg_vertex* vertexBuffer [[buffer(0)]],
|
||||||
device uint* tileCounters [[buffer(1)]],
|
device uint* tileCounters [[buffer(1)]],
|
||||||
const device uint* tilesArray [[buffer(2)]],
|
const device uint* tilesArray [[buffer(2)]],
|
||||||
const device mg_triangle_data* triangleArray [[buffer(3)]],
|
const device mg_triangle_data* triangleArray [[buffer(3)]],
|
||||||
const device float4* boxArray [[buffer(4)]],
|
const device float4* boxArray [[buffer(4)]],
|
||||||
constant vector_float4* clearColor [[buffer(5)]],
|
constant vector_float4* clearColor [[buffer(5)]],
|
||||||
uint2 gid [[thread_position_in_grid]],
|
uint2 gid [[thread_position_in_grid]],
|
||||||
uint2 tgid [[threadgroup_position_in_grid]],
|
uint2 tgid [[threadgroup_position_in_grid]],
|
||||||
uint2 threadsPerThreadgroup [[threads_per_threadgroup]],
|
uint2 threadsPerThreadgroup [[threads_per_threadgroup]],
|
||||||
uint2 gridSize [[threads_per_grid]])
|
uint2 gridSize [[threads_per_grid]])
|
||||||
{
|
{
|
||||||
//TODO: guard against thread group size not equal to tile size?
|
//TODO: guard against thread group size not equal to tile size?
|
||||||
const uint2 tilesMatrixDim = (gridSize - 1) / RENDERER_TILE_SIZE + 1;
|
const uint2 tilesMatrixDim = (gridSize - 1) / RENDERER_TILE_SIZE + 1;
|
||||||
// const uint2 tilePos = tgid * threadsPerThreadgroup / RENDERER_TILE_SIZE;
|
// const uint2 tilePos = tgid * threadsPerThreadgroup / RENDERER_TILE_SIZE;
|
||||||
const uint2 tilePos = gid/RENDERER_TILE_SIZE;
|
const uint2 tilePos = gid/RENDERER_TILE_SIZE;
|
||||||
const uint tileIndex = tilePos.y * tilesMatrixDim.x + tilePos.x;
|
const uint tileIndex = tilePos.y * tilesMatrixDim.x + tilePos.x;
|
||||||
const device uint* tileBuffer = tilesArray + tileIndex * RENDERER_TILE_BUFFER_SIZE;
|
const device uint* tileBuffer = tilesArray + tileIndex * RENDERER_TILE_BUFFER_SIZE;
|
||||||
|
|
||||||
const uint tileBufferSize = tileCounters[tileIndex];
|
const uint tileBufferSize = tileCounters[tileIndex];
|
||||||
|
|
||||||
|
|
||||||
//#define RENDERER_DEBUG_TILES
|
//#define RENDERER_DEBUG_TILES
|
||||||
#ifdef RENDERER_DEBUG_TILES
|
#ifdef RENDERER_DEBUG_TILES
|
||||||
//NOTE(martin): color code debug values and show the tile grid
|
//NOTE(martin): color code debug values and show the tile grid
|
||||||
uint nTileX = tilesMatrixDim.x;
|
uint nTileX = tilesMatrixDim.x;
|
||||||
uint nTileY = tilesMatrixDim.y;
|
uint nTileY = tilesMatrixDim.y;
|
||||||
|
|
||||||
if(tilePos.x == 2 && tilePos.y == 12)
|
if(tilePos.x == 2 && tilePos.y == 12)
|
||||||
{
|
{
|
||||||
outTexture.write(float4(1, 0.5, 1, 1), gid);
|
outTexture.write(float4(1, 0.5, 1, 1), gid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nTileY != 13 || nTileX != 13)
|
if(nTileY != 13 || nTileX != 13)
|
||||||
{
|
{
|
||||||
outTexture.write(float4(1, 1, 0, 1), gid);
|
outTexture.write(float4(1, 1, 0, 1), gid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tilePos.x > nTileX || tilePos.y > nTileY)
|
if(tilePos.x > nTileX || tilePos.y > nTileY)
|
||||||
{
|
{
|
||||||
outTexture.write(float4(0, 1, 1, 1), gid);
|
outTexture.write(float4(0, 1, 1, 1), gid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((gid.x % RENDERER_TILE_SIZE == 0) || (gid.y % RENDERER_TILE_SIZE == 0))
|
if((gid.x % RENDERER_TILE_SIZE == 0) || (gid.y % RENDERER_TILE_SIZE == 0))
|
||||||
{
|
{
|
||||||
outTexture.write(float4(0, 0, 0, 1), gid);
|
outTexture.write(float4(0, 0, 0, 1), gid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(tileBufferSize <= 0)
|
if(tileBufferSize <= 0)
|
||||||
{
|
{
|
||||||
outTexture.write(float4(0, 1, 0, 1), gid);
|
outTexture.write(float4(0, 1, 0, 1), gid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
outTexture.write(float4(1, 0, 0, 1), gid);
|
outTexture.write(float4(1, 0, 0, 1), gid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
const float2 sampleOffsets[6] = { float2(5./12, 5./12),
|
const float2 sampleOffsets[6] = { float2(5./12, 5./12),
|
||||||
float2(-3./12, 3./12),
|
float2(-3./12, 3./12),
|
||||||
float2(1./12, 1./12),
|
float2(1./12, 1./12),
|
||||||
float2(3./12, -1./12),
|
float2(3./12, -1./12),
|
||||||
float2(-5./12, -3./12),
|
float2(-5./12, -3./12),
|
||||||
float2(-1./12, -5./12)};
|
float2(-1./12, -5./12)};
|
||||||
|
|
||||||
int zIndices[6];
|
int zIndices[6];
|
||||||
uint flipCounts[6];
|
uint flipCounts[6];
|
||||||
float4 pixelColors[6];
|
float4 pixelColors[6];
|
||||||
float4 nextColors[6];
|
float4 nextColors[6];
|
||||||
for(int i=0; i<6; i++)
|
for(int i=0; i<6; i++)
|
||||||
{
|
{
|
||||||
zIndices[i] = -1;
|
zIndices[i] = -1;
|
||||||
flipCounts[i] = 0;
|
flipCounts[i] = 0;
|
||||||
pixelColors[i] = *clearColor;
|
pixelColors[i] = *clearColor;
|
||||||
nextColors[i] = *clearColor;
|
nextColors[i] = *clearColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(uint tileBufferIndex=0; tileBufferIndex < tileBufferSize; tileBufferIndex++)
|
for(uint tileBufferIndex=0; tileBufferIndex < tileBufferSize; tileBufferIndex++)
|
||||||
{
|
{
|
||||||
float4 box = boxArray[tileBuffer[tileBufferIndex]];
|
float4 box = boxArray[tileBuffer[tileBufferIndex]];
|
||||||
const device mg_triangle_data* triangle = &triangleArray[tileBuffer[tileBufferIndex]];
|
const device mg_triangle_data* triangle = &triangleArray[tileBuffer[tileBufferIndex]];
|
||||||
|
|
||||||
float2 p0 = triangle->p0;
|
float2 p0 = triangle->p0;
|
||||||
float2 p1 = triangle->p1;
|
float2 p1 = triangle->p1;
|
||||||
float2 p2 = triangle->p2;
|
float2 p2 = triangle->p2;
|
||||||
|
|
||||||
int bias0 = triangle->bias0;
|
int bias0 = triangle->bias0;
|
||||||
int bias1 = triangle->bias1;
|
int bias1 = triangle->bias1;
|
||||||
int bias2 = triangle->bias2;
|
int bias2 = triangle->bias2;
|
||||||
|
|
||||||
const device mg_vertex* v0 = &(vertexBuffer[triangle->i0]);
|
const device mg_vertex* v0 = &(vertexBuffer[triangle->i0]);
|
||||||
const device mg_vertex* v1 = &(vertexBuffer[triangle->i1]);
|
const device mg_vertex* v1 = &(vertexBuffer[triangle->i1]);
|
||||||
const device mg_vertex* v2 = &(vertexBuffer[triangle->i2]);
|
const device mg_vertex* v2 = &(vertexBuffer[triangle->i2]);
|
||||||
|
|
||||||
float4 cubic0 = v0->cubic;
|
float4 cubic0 = v0->cubic;
|
||||||
float4 cubic1 = v1->cubic;
|
float4 cubic1 = v1->cubic;
|
||||||
float4 cubic2 = v2->cubic;
|
float4 cubic2 = v2->cubic;
|
||||||
|
|
||||||
float2 uv0 = v0->uv;
|
float2 uv0 = v0->uv;
|
||||||
float2 uv1 = v1->uv;
|
float2 uv1 = v1->uv;
|
||||||
float2 uv2 = v2->uv;
|
float2 uv2 = v2->uv;
|
||||||
|
|
||||||
int zIndex = v0->zIndex;
|
int zIndex = v0->zIndex;
|
||||||
float4 color = v0->color;
|
float4 color = v0->color;
|
||||||
|
|
||||||
for(int i=0; i<6; i++)
|
for(int i=0; i<6; i++)
|
||||||
{
|
{
|
||||||
float2 samplePoint = (float2)gid + sampleOffsets[i];
|
float2 samplePoint = (float2)gid + sampleOffsets[i];
|
||||||
|
|
||||||
//NOTE(martin): cull if pixel is outside box
|
//NOTE(martin): cull if pixel is outside box
|
||||||
if(samplePoint.x < box.x || samplePoint.x > box.z || samplePoint.y < box.y || samplePoint.y > box.w)
|
if(samplePoint.x < box.x || samplePoint.x > box.z || samplePoint.y < box.y || samplePoint.y > box.w)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float w0 = orient2d(p1, p2, samplePoint);
|
float w0 = orient2d(p1, p2, samplePoint);
|
||||||
float w1 = orient2d(p2, p0, samplePoint);
|
float w1 = orient2d(p2, p0, samplePoint);
|
||||||
float w2 = orient2d(p0, p1, samplePoint);
|
float w2 = orient2d(p0, p1, samplePoint);
|
||||||
|
|
||||||
if(((int)w0+bias0) >= 0 && ((int)w1+bias1) >= 0 && ((int)w2+bias2) >= 0)
|
if(((int)w0+bias0) >= 0 && ((int)w1+bias1) >= 0 && ((int)w2+bias2) >= 0)
|
||||||
{
|
{
|
||||||
float4 cubic = (cubic0*w0 + cubic1*w1 + cubic2*w2)/(w0+w1+w2);
|
float4 cubic = (cubic0*w0 + cubic1*w1 + cubic2*w2)/(w0+w1+w2);
|
||||||
float2 uv = (uv0*w0 + uv1*w1 + uv2*w2)/(w0+w1+w2);
|
float2 uv = (uv0*w0 + uv1*w1 + uv2*w2)/(w0+w1+w2);
|
||||||
|
|
||||||
constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear);
|
constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear);
|
||||||
float4 texColor = texAtlas.sample(smp, uv);
|
float4 texColor = texAtlas.sample(smp, uv);
|
||||||
|
|
||||||
//TODO(martin): this is a quick and dirty fix for solid polygons where we use
|
//TODO(martin): this is a quick and dirty fix for solid polygons where we use
|
||||||
// cubic = (1, 1, 1, 1) on all vertices, which can cause small errors to
|
// cubic = (1, 1, 1, 1) on all vertices, which can cause small errors to
|
||||||
// flip the sign.
|
// flip the sign.
|
||||||
// We should really use another value that always lead to <= 0, but we must
|
// We should really use another value that always lead to <= 0, but we must
|
||||||
// make sure we never share these vertices with bezier shapes.
|
// make sure we never share these vertices with bezier shapes.
|
||||||
// Alternatively, an ugly (but maybe less than this one) solution would be
|
// Alternatively, an ugly (but maybe less than this one) solution would be
|
||||||
// to check if uvs are equal on all vertices of the triangle and always render
|
// to check if uvs are equal on all vertices of the triangle and always render
|
||||||
// those triangles.
|
// those triangles.
|
||||||
float eps = 0.0001;
|
float eps = 0.0001;
|
||||||
if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)
|
if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)
|
||||||
{
|
{
|
||||||
if(zIndex == zIndices[i])
|
if(zIndex == zIndices[i])
|
||||||
{
|
{
|
||||||
flipCounts[i]++;
|
flipCounts[i]++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(flipCounts[i] & 0x01)
|
if(flipCounts[i] & 0x01)
|
||||||
{
|
{
|
||||||
pixelColors[i] = nextColors[i];
|
pixelColors[i] = nextColors[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
float4 nextCol = color*texColor;
|
float4 nextCol = color*texColor;
|
||||||
nextColors[i] = pixelColors[i]*(1-nextCol.a) +nextCol.a*nextCol;
|
nextColors[i] = pixelColors[i]*(1-nextCol.a) +nextCol.a*nextCol;
|
||||||
|
|
||||||
zIndices[i] = zIndex;
|
zIndices[i] = zIndex;
|
||||||
flipCounts[i] = 1;
|
flipCounts[i] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
float4 out = float4(0, 0, 0, 0);
|
float4 out = float4(0, 0, 0, 0);
|
||||||
for(int i=0; i<6; i++)
|
for(int i=0; i<6; i++)
|
||||||
{
|
{
|
||||||
if(flipCounts[i] & 0x01)
|
if(flipCounts[i] & 0x01)
|
||||||
{
|
{
|
||||||
pixelColors[i] = nextColors[i];
|
pixelColors[i] = nextColors[i];
|
||||||
}
|
}
|
||||||
out += pixelColors[i];
|
out += pixelColors[i];
|
||||||
}
|
}
|
||||||
out = float4(out.xyz/6, 1);
|
out = float4(out.xyz/6, 1);
|
||||||
outTexture.write(out, gid);
|
outTexture.write(out, gid);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
#include"win32_app.c"
|
#include"win32_app.c"
|
||||||
// #include"win32_gl_surface.c"
|
// #include"win32_gl_surface.c"
|
||||||
#include"win32_gles_surface.c"
|
#include"win32_gles_surface.c"
|
||||||
|
#include"gles_canvas.c"
|
||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
//NOTE: macos application layer is defined in milepost.m
|
//NOTE: macos application layer is defined in milepost.m
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -40,8 +40,17 @@
|
||||||
#if defined(OS_WIN64) || defined(OS_WIN32)
|
#if defined(OS_WIN64) || defined(OS_WIN32)
|
||||||
#define WIN32_GL_LOADER_API
|
#define WIN32_GL_LOADER_API
|
||||||
// #include"win32_gl_loader.h"
|
// #include"win32_gl_loader.h"
|
||||||
|
|
||||||
|
#if MG_IMPLEMENTS_BACKEND_GLES
|
||||||
|
#include"win32_gles_surface.h"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MG_IMPLEMENTS_BACKEND_METAL
|
||||||
|
#include"metal_surface.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// graphics/ui layer
|
// graphics/ui layer
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
698
src/mp_app.c
698
src/mp_app.c
|
@ -1,349 +1,349 @@
|
||||||
/************************************************************//**
|
/************************************************************//**
|
||||||
*
|
*
|
||||||
* @file: mp_app_internal.c
|
* @file: mp_app_internal.c
|
||||||
* @author: Martin Fouilleul
|
* @author: Martin Fouilleul
|
||||||
* @date: 23/12/2022
|
* @date: 23/12/2022
|
||||||
* @revision:
|
* @revision:
|
||||||
*
|
*
|
||||||
*****************************************************************/
|
*****************************************************************/
|
||||||
|
|
||||||
#include"mp_app_internal.h"
|
#include"mp_app_internal.h"
|
||||||
|
|
||||||
#define LOG_SUBSYSTEM "Application"
|
#define LOG_SUBSYSTEM "Application"
|
||||||
|
|
||||||
mp_app __mpApp = {0};
|
mp_app __mpApp = {0};
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Window handles
|
// Window handles
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
void mp_init_window_handles()
|
void mp_init_window_handles()
|
||||||
{
|
{
|
||||||
ListInit(&__mpApp.windowFreeList);
|
ListInit(&__mpApp.windowFreeList);
|
||||||
for(int i=0; i<MP_APP_MAX_WINDOWS; i++)
|
for(int i=0; i<MP_APP_MAX_WINDOWS; i++)
|
||||||
{
|
{
|
||||||
__mpApp.windowPool[i].generation = 1;
|
__mpApp.windowPool[i].generation = 1;
|
||||||
ListAppend(&__mpApp.windowFreeList, &__mpApp.windowPool[i].freeListElt);
|
ListAppend(&__mpApp.windowFreeList, &__mpApp.windowPool[i].freeListElt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mp_window_handle_is_null(mp_window window)
|
bool mp_window_handle_is_null(mp_window window)
|
||||||
{
|
{
|
||||||
return(window.h == 0);
|
return(window.h == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_window mp_window_null_handle()
|
mp_window mp_window_null_handle()
|
||||||
{
|
{
|
||||||
return((mp_window){.h = 0});
|
return((mp_window){.h = 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_window_data* mp_window_alloc()
|
mp_window_data* mp_window_alloc()
|
||||||
{
|
{
|
||||||
return(ListPopEntry(&__mpApp.windowFreeList, mp_window_data, freeListElt));
|
return(ListPopEntry(&__mpApp.windowFreeList, mp_window_data, freeListElt));
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_window_data* mp_window_ptr_from_handle(mp_window handle)
|
mp_window_data* mp_window_ptr_from_handle(mp_window handle)
|
||||||
{
|
{
|
||||||
u32 index = handle.h>>32;
|
u32 index = handle.h>>32;
|
||||||
u32 generation = handle.h & 0xffffffff;
|
u32 generation = handle.h & 0xffffffff;
|
||||||
if(index >= MP_APP_MAX_WINDOWS)
|
if(index >= MP_APP_MAX_WINDOWS)
|
||||||
{
|
{
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
mp_window_data* window = &__mpApp.windowPool[index];
|
mp_window_data* window = &__mpApp.windowPool[index];
|
||||||
if(window->generation != generation)
|
if(window->generation != generation)
|
||||||
{
|
{
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return(window);
|
return(window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_window mp_window_handle_from_ptr(mp_window_data* window)
|
mp_window mp_window_handle_from_ptr(mp_window_data* window)
|
||||||
{
|
{
|
||||||
DEBUG_ASSERT( (window - __mpApp.windowPool) >= 0
|
DEBUG_ASSERT( (window - __mpApp.windowPool) >= 0
|
||||||
&& (window - __mpApp.windowPool) < MP_APP_MAX_WINDOWS);
|
&& (window - __mpApp.windowPool) < MP_APP_MAX_WINDOWS);
|
||||||
|
|
||||||
u64 h = ((u64)(window - __mpApp.windowPool))<<32
|
u64 h = ((u64)(window - __mpApp.windowPool))<<32
|
||||||
| ((u64)window->generation);
|
| ((u64)window->generation);
|
||||||
|
|
||||||
return((mp_window){h});
|
return((mp_window){h});
|
||||||
}
|
}
|
||||||
|
|
||||||
void mp_window_recycle_ptr(mp_window_data* window)
|
void mp_window_recycle_ptr(mp_window_data* window)
|
||||||
{
|
{
|
||||||
window->generation++;
|
window->generation++;
|
||||||
ListPush(&__mpApp.windowFreeList, &window->freeListElt);
|
ListPush(&__mpApp.windowFreeList, &window->freeListElt);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Init
|
// Init
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
static void mp_init_common()
|
static void mp_init_common()
|
||||||
{
|
{
|
||||||
mp_init_window_handles();
|
mp_init_window_handles();
|
||||||
ringbuffer_init(&__mpApp.eventQueue, 16);
|
ringbuffer_init(&__mpApp.eventQueue, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mp_terminate_common()
|
static void mp_terminate_common()
|
||||||
{
|
{
|
||||||
ringbuffer_cleanup(&__mpApp.eventQueue);
|
ringbuffer_cleanup(&__mpApp.eventQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Event handling
|
// Event handling
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
void mp_queue_event(mp_event* event)
|
void mp_queue_event(mp_event* event)
|
||||||
{
|
{
|
||||||
if(ringbuffer_write_available(&__mpApp.eventQueue) < sizeof(mp_event))
|
if(ringbuffer_write_available(&__mpApp.eventQueue) < sizeof(mp_event))
|
||||||
{
|
{
|
||||||
LOG_ERROR("event queue full\n");
|
LOG_ERROR("event queue full\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 written = ringbuffer_write(&__mpApp.eventQueue, sizeof(mp_event), (u8*)event);
|
u32 written = ringbuffer_write(&__mpApp.eventQueue, sizeof(mp_event), (u8*)event);
|
||||||
DEBUG_ASSERT(written == sizeof(mp_event));
|
DEBUG_ASSERT(written == sizeof(mp_event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mp_next_event(mp_event* event)
|
bool mp_next_event(mp_event* event)
|
||||||
{
|
{
|
||||||
//NOTE pop and return event from queue
|
//NOTE pop and return event from queue
|
||||||
if(ringbuffer_read_available(&__mpApp.eventQueue) >= sizeof(mp_event))
|
if(ringbuffer_read_available(&__mpApp.eventQueue) >= sizeof(mp_event))
|
||||||
{
|
{
|
||||||
u64 read = ringbuffer_read(&__mpApp.eventQueue, sizeof(mp_event), (u8*)event);
|
u64 read = ringbuffer_read(&__mpApp.eventQueue, sizeof(mp_event), (u8*)event);
|
||||||
DEBUG_ASSERT(read == sizeof(mp_event));
|
DEBUG_ASSERT(read == sizeof(mp_event));
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Input state updating
|
// Input state updating
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
static void mp_update_key_state(mp_key_state* key, bool down)
|
static void mp_update_key_state(mp_key_state* key, bool down)
|
||||||
{
|
{
|
||||||
u64 frameCounter = __mpApp.inputState.frameCounter;
|
u64 frameCounter = __mpApp.inputState.frameCounter;
|
||||||
if(key->lastUpdate != frameCounter)
|
if(key->lastUpdate != frameCounter)
|
||||||
{
|
{
|
||||||
key->transitionCounter = 0;
|
key->transitionCounter = 0;
|
||||||
key->clicked = false;
|
key->clicked = false;
|
||||||
key->doubleClicked = false;
|
key->doubleClicked = false;
|
||||||
key->lastUpdate = frameCounter;
|
key->lastUpdate = frameCounter;
|
||||||
}
|
}
|
||||||
if(key->down == down)
|
if(key->down == down)
|
||||||
{
|
{
|
||||||
key->transitionCounter++;
|
key->transitionCounter++;
|
||||||
}
|
}
|
||||||
key->down = down;
|
key->down = down;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mp_update_mouse_move(f32 x, f32 y, f32 deltaX, f32 deltaY)
|
static void mp_update_mouse_move(f32 x, f32 y, f32 deltaX, f32 deltaY)
|
||||||
{
|
{
|
||||||
u64 frameCounter = __mpApp.inputState.frameCounter;
|
u64 frameCounter = __mpApp.inputState.frameCounter;
|
||||||
mp_mouse_state* mouse = &__mpApp.inputState.mouse;
|
mp_mouse_state* mouse = &__mpApp.inputState.mouse;
|
||||||
if(mouse->lastUpdate != frameCounter)
|
if(mouse->lastUpdate != frameCounter)
|
||||||
{
|
{
|
||||||
mouse->delta = (vec2){0, 0};
|
mouse->delta = (vec2){0, 0};
|
||||||
mouse->wheel = (vec2){0, 0};
|
mouse->wheel = (vec2){0, 0};
|
||||||
mouse->lastUpdate = frameCounter;
|
mouse->lastUpdate = frameCounter;
|
||||||
}
|
}
|
||||||
mouse->pos = (vec2){x, y};
|
mouse->pos = (vec2){x, y};
|
||||||
mouse->delta.x += deltaX;
|
mouse->delta.x += deltaX;
|
||||||
mouse->delta.y += deltaY;
|
mouse->delta.y += deltaY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mp_update_mouse_wheel(f32 deltaX, f32 deltaY)
|
static void mp_update_mouse_wheel(f32 deltaX, f32 deltaY)
|
||||||
{
|
{
|
||||||
u64 frameCounter = __mpApp.inputState.frameCounter;
|
u64 frameCounter = __mpApp.inputState.frameCounter;
|
||||||
mp_mouse_state* mouse = &__mpApp.inputState.mouse;
|
mp_mouse_state* mouse = &__mpApp.inputState.mouse;
|
||||||
if(mouse->lastUpdate != frameCounter)
|
if(mouse->lastUpdate != frameCounter)
|
||||||
{
|
{
|
||||||
mouse->delta = (vec2){0, 0};
|
mouse->delta = (vec2){0, 0};
|
||||||
mouse->wheel = (vec2){0, 0};
|
mouse->wheel = (vec2){0, 0};
|
||||||
mouse->lastUpdate = frameCounter;
|
mouse->lastUpdate = frameCounter;
|
||||||
}
|
}
|
||||||
mouse->wheel.x += deltaX;
|
mouse->wheel.x += deltaX;
|
||||||
mouse->wheel.y += deltaY;
|
mouse->wheel.y += deltaY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mp_update_text(utf32 codepoint)
|
static void mp_update_text(utf32 codepoint)
|
||||||
{
|
{
|
||||||
u64 frameCounter = __mpApp.inputState.frameCounter;
|
u64 frameCounter = __mpApp.inputState.frameCounter;
|
||||||
mp_text_state* text = &__mpApp.inputState.text;
|
mp_text_state* text = &__mpApp.inputState.text;
|
||||||
|
|
||||||
if(text->lastUpdate != frameCounter)
|
if(text->lastUpdate != frameCounter)
|
||||||
{
|
{
|
||||||
text->codePoints.len = 0;
|
text->codePoints.len = 0;
|
||||||
text->lastUpdate = frameCounter;
|
text->lastUpdate = frameCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
text->codePoints.ptr = text->backing;
|
text->codePoints.ptr = text->backing;
|
||||||
if(text->codePoints.len < MP_INPUT_TEXT_BACKING_SIZE)
|
if(text->codePoints.len < MP_INPUT_TEXT_BACKING_SIZE)
|
||||||
{
|
{
|
||||||
text->codePoints.ptr[text->codePoints.len] = codepoint;
|
text->codePoints.ptr[text->codePoints.len] = codepoint;
|
||||||
text->codePoints.len++;
|
text->codePoints.len++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_WARNING("too many input codepoints per frame, dropping input");
|
LOG_WARNING("too many input codepoints per frame, dropping input");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// Input state polling
|
// Input state polling
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
mp_key_state mp_input_get_key_state(mp_key_code key)
|
mp_key_state mp_input_get_key_state(mp_key_code key)
|
||||||
{
|
{
|
||||||
if(key <= MP_KEY_COUNT)
|
if(key <= MP_KEY_COUNT)
|
||||||
{
|
{
|
||||||
return(__mpApp.inputState.keyboard.keys[key]);
|
return(__mpApp.inputState.keyboard.keys[key]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return((mp_key_state){0});
|
return((mp_key_state){0});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mp_key_state mp_input_get_mouse_button_state(mp_mouse_button button)
|
mp_key_state mp_input_get_mouse_button_state(mp_mouse_button button)
|
||||||
{
|
{
|
||||||
if(button <= MP_MOUSE_BUTTON_COUNT)
|
if(button <= MP_MOUSE_BUTTON_COUNT)
|
||||||
{
|
{
|
||||||
return(__mpApp.inputState.mouse.buttons[button]);
|
return(__mpApp.inputState.mouse.buttons[button]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return((mp_key_state){0});
|
return((mp_key_state){0});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mp_input_check_key_transition(mp_key_state* key, bool pressed)
|
bool mp_input_check_key_transition(mp_key_state* key, bool pressed)
|
||||||
{
|
{
|
||||||
bool res = ( (key->lastUpdate == __mpApp.inputState.frameCounter)
|
bool res = ( (key->lastUpdate == __mpApp.inputState.frameCounter)
|
||||||
&& key->transitionCounter
|
&& key->transitionCounter
|
||||||
&&(key->down == pressed || key->transitionCounter > 1));
|
&&(key->down == pressed || key->transitionCounter > 1));
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mp_input_key_down(mp_key_code key)
|
bool mp_input_key_down(mp_key_code key)
|
||||||
{
|
{
|
||||||
mp_key_state state = mp_input_get_key_state(key);
|
mp_key_state state = mp_input_get_key_state(key);
|
||||||
return(state.down);
|
return(state.down);
|
||||||
}
|
}
|
||||||
bool mp_input_key_pressed(mp_key_code key)
|
bool mp_input_key_pressed(mp_key_code key)
|
||||||
{
|
{
|
||||||
mp_key_state state = mp_input_get_key_state(key);
|
mp_key_state state = mp_input_get_key_state(key);
|
||||||
bool res = mp_input_check_key_transition(&state, true);
|
bool res = mp_input_check_key_transition(&state, true);
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mp_input_key_released(mp_key_code key)
|
bool mp_input_key_released(mp_key_code key)
|
||||||
{
|
{
|
||||||
mp_key_state state = mp_input_get_key_state(key);
|
mp_key_state state = mp_input_get_key_state(key);
|
||||||
bool res = mp_input_check_key_transition(&state, false);
|
bool res = mp_input_check_key_transition(&state, false);
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mp_input_mouse_down(mp_mouse_button button)
|
bool mp_input_mouse_down(mp_mouse_button button)
|
||||||
{
|
{
|
||||||
mp_key_state state = mp_input_get_mouse_button_state(button);
|
mp_key_state state = mp_input_get_mouse_button_state(button);
|
||||||
return(state.down);
|
return(state.down);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mp_input_mouse_pressed(mp_mouse_button button)
|
bool mp_input_mouse_pressed(mp_mouse_button button)
|
||||||
{
|
{
|
||||||
mp_key_state state = mp_input_get_mouse_button_state(button);
|
mp_key_state state = mp_input_get_mouse_button_state(button);
|
||||||
bool res = mp_input_check_key_transition(&state, true);
|
bool res = mp_input_check_key_transition(&state, true);
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mp_input_mouse_released(mp_mouse_button button)
|
bool mp_input_mouse_released(mp_mouse_button button)
|
||||||
{
|
{
|
||||||
mp_key_state state = mp_input_get_mouse_button_state(button);
|
mp_key_state state = mp_input_get_mouse_button_state(button);
|
||||||
bool res = mp_input_check_key_transition(&state, false);
|
bool res = mp_input_check_key_transition(&state, false);
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mp_input_mouse_clicked(mp_mouse_button button)
|
bool mp_input_mouse_clicked(mp_mouse_button button)
|
||||||
{
|
{
|
||||||
mp_key_state state = mp_input_get_mouse_button_state(button);
|
mp_key_state state = mp_input_get_mouse_button_state(button);
|
||||||
return(state.clicked);
|
return(state.clicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mp_input_mouse_double_clicked(mp_mouse_button button)
|
bool mp_input_mouse_double_clicked(mp_mouse_button button)
|
||||||
{
|
{
|
||||||
mp_key_state state = mp_input_get_mouse_button_state(button);
|
mp_key_state state = mp_input_get_mouse_button_state(button);
|
||||||
if(state.lastUpdate == __mpApp.inputState.frameCounter)
|
if(state.lastUpdate == __mpApp.inputState.frameCounter)
|
||||||
{
|
{
|
||||||
return(state.doubleClicked);
|
return(state.doubleClicked);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_key_mods mp_input_key_mods()
|
mp_key_mods mp_input_key_mods()
|
||||||
{
|
{
|
||||||
return(__mpApp.inputState.keyboard.mods);
|
return(__mpApp.inputState.keyboard.mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 mp_input_mouse_position()
|
vec2 mp_input_mouse_position()
|
||||||
{
|
{
|
||||||
return(__mpApp.inputState.mouse.pos);
|
return(__mpApp.inputState.mouse.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 mp_input_mouse_delta()
|
vec2 mp_input_mouse_delta()
|
||||||
{
|
{
|
||||||
if(__mpApp.inputState.mouse.lastUpdate == __mpApp.inputState.frameCounter)
|
if(__mpApp.inputState.mouse.lastUpdate == __mpApp.inputState.frameCounter)
|
||||||
{
|
{
|
||||||
return(__mpApp.inputState.mouse.delta);
|
return(__mpApp.inputState.mouse.delta);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return((vec2){0, 0});
|
return((vec2){0, 0});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 mp_input_mouse_wheel()
|
vec2 mp_input_mouse_wheel()
|
||||||
{
|
{
|
||||||
if(__mpApp.inputState.mouse.lastUpdate == __mpApp.inputState.frameCounter)
|
if(__mpApp.inputState.mouse.lastUpdate == __mpApp.inputState.frameCounter)
|
||||||
{
|
{
|
||||||
return(__mpApp.inputState.mouse.wheel);
|
return(__mpApp.inputState.mouse.wheel);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return((vec2){0, 0});
|
return((vec2){0, 0});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
str32 mp_input_text_utf32(mem_arena* arena)
|
str32 mp_input_text_utf32(mem_arena* arena)
|
||||||
{
|
{
|
||||||
str32 res = {0};
|
str32 res = {0};
|
||||||
if(__mpApp.inputState.text.lastUpdate == __mpApp.inputState.frameCounter)
|
if(__mpApp.inputState.text.lastUpdate == __mpApp.inputState.frameCounter)
|
||||||
{
|
{
|
||||||
res = str32_push_copy(arena, __mpApp.inputState.text.codePoints);
|
res = str32_push_copy(arena, __mpApp.inputState.text.codePoints);
|
||||||
}
|
}
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
str8 mp_input_text_utf8(mem_arena* arena)
|
str8 mp_input_text_utf8(mem_arena* arena)
|
||||||
{
|
{
|
||||||
str8 res = {0};
|
str8 res = {0};
|
||||||
if(__mpApp.inputState.text.lastUpdate == __mpApp.inputState.frameCounter)
|
if(__mpApp.inputState.text.lastUpdate == __mpApp.inputState.frameCounter)
|
||||||
{
|
{
|
||||||
res = utf8_push_from_codepoints(arena, __mpApp.inputState.text.codePoints);
|
res = utf8_push_from_codepoints(arena, __mpApp.inputState.text.codePoints);
|
||||||
}
|
}
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef LOG_SUBSYSTEM
|
#undef LOG_SUBSYSTEM
|
||||||
|
|
|
@ -1,152 +1,152 @@
|
||||||
/************************************************************//**
|
/************************************************************//**
|
||||||
*
|
*
|
||||||
* @file: mp_app_internal.h
|
* @file: mp_app_internal.h
|
||||||
* @author: Martin Fouilleul
|
* @author: Martin Fouilleul
|
||||||
* @date: 23/12/2022
|
* @date: 23/12/2022
|
||||||
* @revision:
|
* @revision:
|
||||||
*
|
*
|
||||||
*****************************************************************/
|
*****************************************************************/
|
||||||
#ifndef __MP_APP_INTERNAL_H_
|
#ifndef __MP_APP_INTERNAL_H_
|
||||||
#define __MP_APP_INTERNAL_H_
|
#define __MP_APP_INTERNAL_H_
|
||||||
|
|
||||||
#include"platform.h"
|
#include"platform.h"
|
||||||
#include"ringbuffer.h"
|
#include"ringbuffer.h"
|
||||||
|
|
||||||
#if defined(OS_WIN64) || defined(OS_WIN32)
|
#if defined(OS_WIN64) || defined(OS_WIN32)
|
||||||
#include"win32_app.h"
|
#include"win32_app.h"
|
||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
#include"osx_app.h"
|
#include"osx_app.h"
|
||||||
#else
|
#else
|
||||||
#error "platform not supported yet"
|
#error "platform not supported yet"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Input State
|
// Input State
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
typedef struct mp_key_utf8
|
typedef struct mp_key_utf8
|
||||||
{
|
{
|
||||||
u8 labelLen;
|
u8 labelLen;
|
||||||
char label[8];
|
char label[8];
|
||||||
} mp_key_utf8;
|
} mp_key_utf8;
|
||||||
|
|
||||||
typedef struct mp_key_state
|
typedef struct mp_key_state
|
||||||
{
|
{
|
||||||
u64 lastUpdate;
|
u64 lastUpdate;
|
||||||
u32 transitionCounter;
|
u32 transitionCounter;
|
||||||
bool down;
|
bool down;
|
||||||
bool clicked;
|
bool clicked;
|
||||||
bool doubleClicked;
|
bool doubleClicked;
|
||||||
|
|
||||||
} mp_key_state;
|
} mp_key_state;
|
||||||
|
|
||||||
typedef struct mp_keyboard_state
|
typedef struct mp_keyboard_state
|
||||||
{
|
{
|
||||||
mp_key_state keys[MP_KEY_COUNT];
|
mp_key_state keys[MP_KEY_COUNT];
|
||||||
mp_key_mods mods;
|
mp_key_mods mods;
|
||||||
} mp_keyboard_state;
|
} mp_keyboard_state;
|
||||||
|
|
||||||
typedef struct mp_mouse_state
|
typedef struct mp_mouse_state
|
||||||
{
|
{
|
||||||
u64 lastUpdate;
|
u64 lastUpdate;
|
||||||
bool posValid;
|
bool posValid;
|
||||||
vec2 pos;
|
vec2 pos;
|
||||||
vec2 delta;
|
vec2 delta;
|
||||||
vec2 wheel;
|
vec2 wheel;
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
mp_key_state buttons[MP_MOUSE_BUTTON_COUNT];
|
mp_key_state buttons[MP_MOUSE_BUTTON_COUNT];
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
mp_key_state left;
|
mp_key_state left;
|
||||||
mp_key_state right;
|
mp_key_state right;
|
||||||
mp_key_state middle;
|
mp_key_state middle;
|
||||||
mp_key_state ext1;
|
mp_key_state ext1;
|
||||||
mp_key_state ext2;
|
mp_key_state ext2;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
} mp_mouse_state;
|
} mp_mouse_state;
|
||||||
|
|
||||||
enum { MP_INPUT_TEXT_BACKING_SIZE = 64 };
|
enum { MP_INPUT_TEXT_BACKING_SIZE = 64 };
|
||||||
|
|
||||||
typedef struct mp_text_state
|
typedef struct mp_text_state
|
||||||
{
|
{
|
||||||
u64 lastUpdate;
|
u64 lastUpdate;
|
||||||
utf32 backing[MP_INPUT_TEXT_BACKING_SIZE];
|
utf32 backing[MP_INPUT_TEXT_BACKING_SIZE];
|
||||||
str32 codePoints;
|
str32 codePoints;
|
||||||
} mp_text_state;
|
} mp_text_state;
|
||||||
|
|
||||||
typedef struct mp_input_state
|
typedef struct mp_input_state
|
||||||
{
|
{
|
||||||
u64 frameCounter;
|
u64 frameCounter;
|
||||||
mp_keyboard_state keyboard;
|
mp_keyboard_state keyboard;
|
||||||
mp_mouse_state mouse;
|
mp_mouse_state mouse;
|
||||||
mp_text_state text;
|
mp_text_state text;
|
||||||
} mp_input_state;
|
} mp_input_state;
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Window structure
|
// Window structure
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
typedef struct mp_frame_stats
|
typedef struct mp_frame_stats
|
||||||
{
|
{
|
||||||
f64 start;
|
f64 start;
|
||||||
f64 workTime;
|
f64 workTime;
|
||||||
f64 remainingTime;
|
f64 remainingTime;
|
||||||
f64 targetFramePeriod;
|
f64 targetFramePeriod;
|
||||||
} mp_frame_stats;
|
} mp_frame_stats;
|
||||||
|
|
||||||
typedef struct mp_window_data
|
typedef struct mp_window_data
|
||||||
{
|
{
|
||||||
list_elt freeListElt;
|
list_elt freeListElt;
|
||||||
u32 generation;
|
u32 generation;
|
||||||
|
|
||||||
mp_rect contentRect;
|
mp_rect contentRect;
|
||||||
mp_rect frameRect;
|
mp_rect frameRect;
|
||||||
mp_window_style style;
|
mp_window_style style;
|
||||||
|
|
||||||
bool shouldClose; //TODO could be in status flags
|
bool shouldClose; //TODO could be in status flags
|
||||||
bool hidden;
|
bool hidden;
|
||||||
bool minimized;
|
bool minimized;
|
||||||
|
|
||||||
MP_PLATFORM_WINDOW_DATA
|
MP_PLATFORM_WINDOW_DATA
|
||||||
} mp_window_data;
|
} mp_window_data;
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Global App State
|
// Global App State
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
enum { MP_APP_MAX_WINDOWS = 128 };
|
enum { MP_APP_MAX_WINDOWS = 128 };
|
||||||
|
|
||||||
typedef struct mp_app
|
typedef struct mp_app
|
||||||
{
|
{
|
||||||
bool init;
|
bool init;
|
||||||
bool shouldQuit;
|
bool shouldQuit;
|
||||||
bool minimized;
|
bool minimized;
|
||||||
|
|
||||||
str8 pendingPathDrop;
|
str8 pendingPathDrop;
|
||||||
mem_arena eventArena;
|
mem_arena eventArena;
|
||||||
|
|
||||||
ringbuffer eventQueue;
|
ringbuffer eventQueue;
|
||||||
|
|
||||||
mp_frame_stats frameStats;
|
mp_frame_stats frameStats;
|
||||||
|
|
||||||
mp_window_data windowPool[MP_APP_MAX_WINDOWS];
|
mp_window_data windowPool[MP_APP_MAX_WINDOWS];
|
||||||
list_info windowFreeList;
|
list_info windowFreeList;
|
||||||
|
|
||||||
mp_live_resize_callback liveResizeCallback;
|
mp_live_resize_callback liveResizeCallback;
|
||||||
void* liveResizeData;
|
void* liveResizeData;
|
||||||
|
|
||||||
mp_input_state inputState;
|
mp_input_state inputState;
|
||||||
|
|
||||||
mp_key_utf8 keyLabels[256];
|
mp_key_utf8 keyLabels[512];
|
||||||
int keyCodes[256];
|
int keyCodes[512];
|
||||||
int nativeKeys[MP_KEY_COUNT];
|
int nativeKeys[MP_KEY_COUNT];
|
||||||
|
|
||||||
MP_PLATFORM_APP_DATA
|
MP_PLATFORM_APP_DATA
|
||||||
} mp_app;
|
} mp_app;
|
||||||
|
|
||||||
|
|
||||||
#endif // __MP_APP_INTERNAL_H_
|
#endif // __MP_APP_INTERNAL_H_
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
/************************************************************//**
|
/************************************************************//**
|
||||||
*
|
*
|
||||||
* @file: osx_gles_surface.cpp
|
* @file: osx_gles_surface.cpp
|
||||||
* @author: Martin Fouilleul
|
* @author: Martin Fouilleul
|
||||||
* @date: 18/08/2022
|
* @date: 18/08/2022
|
||||||
* @revision:
|
* @revision:
|
||||||
*
|
*
|
||||||
*****************************************************************/
|
*****************************************************************/
|
||||||
//#include<Cocoa/Cocoa.h>
|
//#include<Cocoa/Cocoa.h>
|
||||||
//#include <Foundation/Foundation.h>
|
//#include <Foundation/Foundation.h>
|
||||||
#include <QuartzCore/QuartzCore.h>
|
#include <QuartzCore/QuartzCore.h>
|
||||||
|
|
||||||
#include<GLES3/gl32.h>
|
#include<GLES3/gl3.h>
|
||||||
#define EGL_EGLEXT_PROTOTYPES
|
#define EGL_EGLEXT_PROTOTYPES
|
||||||
#include<EGL/egl.h>
|
#include<EGL/egl.h>
|
||||||
#include<EGL/eglext.h>
|
#include<EGL/eglext.h>
|
||||||
|
|
||||||
#include"graphics_internal.h"
|
#include"graphics_internal.h"
|
||||||
|
|
||||||
typedef struct mg_gles_surface
|
typedef struct mg_gles_surface
|
||||||
{
|
{
|
||||||
mg_surface_data interface;
|
mg_surface_data interface;
|
||||||
|
|
||||||
NSView* view;
|
NSView* view;
|
||||||
CALayer* layer;
|
CALayer* layer;
|
||||||
EGLDisplay eglDisplay;
|
EGLDisplay eglDisplay;
|
||||||
EGLConfig eglConfig;
|
EGLConfig eglConfig;
|
||||||
EGLContext eglContext;
|
EGLContext eglContext;
|
||||||
EGLSurface eglSurface;
|
EGLSurface eglSurface;
|
||||||
EGLint numConfigs;
|
EGLint numConfigs;
|
||||||
|
|
||||||
} mg_gles_surface;
|
} mg_gles_surface;
|
||||||
|
|
|
@ -1,184 +1,184 @@
|
||||||
/************************************************************//**
|
/************************************************************//**
|
||||||
*
|
*
|
||||||
* @file: osx_gles_surface.cpp
|
* @file: osx_gles_surface.cpp
|
||||||
* @author: Martin Fouilleul
|
* @author: Martin Fouilleul
|
||||||
* @date: 18/08/2022
|
* @date: 18/08/2022
|
||||||
* @revision:
|
* @revision:
|
||||||
*
|
*
|
||||||
*****************************************************************/
|
*****************************************************************/
|
||||||
//#include<Cocoa/Cocoa.h>
|
//#include<Cocoa/Cocoa.h>
|
||||||
//#include <Foundation/Foundation.h>
|
//#include <Foundation/Foundation.h>
|
||||||
#include <QuartzCore/QuartzCore.h>
|
#include <QuartzCore/QuartzCore.h>
|
||||||
|
|
||||||
#include<GLES3/gl32.h>
|
#include<GLES3/gl3.h>
|
||||||
#define EGL_EGLEXT_PROTOTYPES
|
#define EGL_EGLEXT_PROTOTYPES
|
||||||
#include<EGL/egl.h>
|
#include<EGL/egl.h>
|
||||||
#include<EGL/eglext.h>
|
#include<EGL/eglext.h>
|
||||||
|
|
||||||
#include"graphics_internal.h"
|
#include"graphics_internal.h"
|
||||||
#include"osx_gles_surface.h"
|
#include"osx_gles_surface.h"
|
||||||
|
|
||||||
|
|
||||||
void mg_gles_surface_destroy(mg_surface_data* interface)
|
void mg_gles_surface_destroy(mg_surface_data* interface)
|
||||||
{
|
{
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
//TODO
|
//TODO
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_gles_surface_prepare(mg_surface_data* interface)
|
void mg_gles_surface_prepare(mg_surface_data* interface)
|
||||||
{
|
{
|
||||||
mg_gles_surface* surface = (mg_gles_surface*)interface;
|
mg_gles_surface* surface = (mg_gles_surface*)interface;
|
||||||
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
|
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_gles_surface_present(mg_surface_data* interface)
|
void mg_gles_surface_present(mg_surface_data* interface)
|
||||||
{
|
{
|
||||||
|
|
||||||
//TODO: eglSwapBuffers seem to never block in macOS (ie eglSwapInterval doesn't seem to have any effect)
|
//TODO: eglSwapBuffers seem to never block in macOS (ie eglSwapInterval doesn't seem to have any effect)
|
||||||
// We need to use a CVDisplayLink to time this if we want surface present to block
|
// We need to use a CVDisplayLink to time this if we want surface present to block
|
||||||
|
|
||||||
mg_gles_surface* surface = (mg_gles_surface*)interface;
|
mg_gles_surface* surface = (mg_gles_surface*)interface;
|
||||||
eglSwapBuffers(surface->eglDisplay, surface->eglSurface);
|
eglSwapBuffers(surface->eglDisplay, surface->eglSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mg_gles_surface_set_frame(mg_surface_data* interface, mp_rect frame)
|
void mg_gles_surface_set_frame(mg_surface_data* interface, mp_rect frame)
|
||||||
{
|
{
|
||||||
mg_gles_surface* surface = (mg_gles_surface*)interface;
|
mg_gles_surface* surface = (mg_gles_surface*)interface;
|
||||||
f32 scale = surface->layer.contentsScale;
|
f32 scale = surface->layer.contentsScale;
|
||||||
CGRect bounds = (CGRect){{frame.x * scale, frame.y * scale}, {.width = frame.w*scale, .height = frame.h*scale}};
|
CGRect bounds = (CGRect){{frame.x * scale, frame.y * scale}, {.width = frame.w*scale, .height = frame.h*scale}};
|
||||||
[surface->layer setBounds: bounds];
|
[surface->layer setBounds: bounds];
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_rect mg_gles_surface_get_frame(mg_surface_data* interface)
|
mp_rect mg_gles_surface_get_frame(mg_surface_data* interface)
|
||||||
{
|
{
|
||||||
mg_gles_surface* surface = (mg_gles_surface*)interface;
|
mg_gles_surface* surface = (mg_gles_surface*)interface;
|
||||||
f32 scale = surface->layer.contentsScale;
|
f32 scale = surface->layer.contentsScale;
|
||||||
CGRect bounds = [surface->layer bounds];
|
CGRect bounds = [surface->layer bounds];
|
||||||
mp_rect rect = {bounds.origin.x / scale, bounds.origin.y / scale, bounds.size.width / scale, bounds.size.height / scale};
|
mp_rect rect = {bounds.origin.x / scale, bounds.origin.y / scale, bounds.size.width / scale, bounds.size.height / scale};
|
||||||
return(rect);
|
return(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void mg_gles_surface_set_hidden(mg_surface_data* interface, bool hidden)
|
void mg_gles_surface_set_hidden(mg_surface_data* interface, bool hidden)
|
||||||
{
|
{
|
||||||
//TODO: doesn't make sense for an offscreen surface?
|
//TODO: doesn't make sense for an offscreen surface?
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mg_gles_surface_get_hidden(mg_surface_data* interface)
|
bool mg_gles_surface_get_hidden(mg_surface_data* interface)
|
||||||
{
|
{
|
||||||
//TODO: doesn't make sense for an offscreen surface?
|
//TODO: doesn't make sense for an offscreen surface?
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 mg_gles_surface_get_size(mg_surface_data* interface)
|
vec2 mg_gles_surface_get_size(mg_surface_data* interface)
|
||||||
{
|
{
|
||||||
mg_gles_surface* surface = (mg_gles_surface*)interface;
|
mg_gles_surface* surface = (mg_gles_surface*)interface;
|
||||||
CGRect bounds = [surface->layer bounds];
|
CGRect bounds = [surface->layer bounds];
|
||||||
f32 scale = surface->layer.contentsScale;
|
f32 scale = surface->layer.contentsScale;
|
||||||
vec2 res = {bounds.size.width/scale, bounds.size.height/scale};
|
vec2 res = {bounds.size.width/scale, bounds.size.height/scale};
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
mg_surface mg_gles_surface_create_with_view(u32 width, u32 height, NSView* view)
|
mg_surface mg_gles_surface_create_with_view(u32 width, u32 height, NSView* view)
|
||||||
{
|
{
|
||||||
mg_gles_surface* surface = malloc_type(mg_gles_surface);
|
mg_gles_surface* surface = malloc_type(mg_gles_surface);
|
||||||
memset(surface, 0, sizeof(mg_gles_surface));
|
memset(surface, 0, sizeof(mg_gles_surface));
|
||||||
|
|
||||||
surface->interface.backend = MG_BACKEND_GLES;
|
surface->interface.backend = MG_BACKEND_GLES;
|
||||||
surface->interface.destroy = mg_gles_surface_destroy;
|
surface->interface.destroy = mg_gles_surface_destroy;
|
||||||
surface->interface.prepare = mg_gles_surface_prepare;
|
surface->interface.prepare = mg_gles_surface_prepare;
|
||||||
surface->interface.present = mg_gles_surface_present;
|
surface->interface.present = mg_gles_surface_present;
|
||||||
surface->interface.getFrame = mg_gles_surface_get_frame;
|
surface->interface.getFrame = mg_gles_surface_get_frame;
|
||||||
surface->interface.setFrame = mg_gles_surface_set_frame;
|
surface->interface.setFrame = mg_gles_surface_set_frame;
|
||||||
surface->interface.getHidden = mg_gles_surface_get_hidden;
|
surface->interface.getHidden = mg_gles_surface_get_hidden;
|
||||||
surface->interface.setHidden = mg_gles_surface_set_hidden;
|
surface->interface.setHidden = mg_gles_surface_set_hidden;
|
||||||
|
|
||||||
surface->view = view;
|
surface->view = view;
|
||||||
|
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
{
|
{
|
||||||
surface->layer = [[CALayer alloc] init];
|
surface->layer = [[CALayer alloc] init];
|
||||||
[surface->layer retain];
|
[surface->layer retain];
|
||||||
[surface->layer setBounds:CGRectMake(0, 0, width, height)];
|
[surface->layer setBounds:CGRectMake(0, 0, width, height)];
|
||||||
|
|
||||||
if(surface->view)
|
if(surface->view)
|
||||||
{
|
{
|
||||||
[surface->view setWantsLayer: YES];
|
[surface->view setWantsLayer: YES];
|
||||||
surface->view.layer = surface->layer;
|
surface->view.layer = surface->layer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EGLAttrib displayAttribs[] = {
|
EGLAttrib displayAttribs[] = {
|
||||||
//NOTE: we need to explicitly set EGL_PLATFORM_ANGLE_TYPE_ANGLE to EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE, because
|
//NOTE: we need to explicitly set EGL_PLATFORM_ANGLE_TYPE_ANGLE to EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE, because
|
||||||
// EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE defaults to using CGL, and eglSetSwapInterval is broken for this backend
|
// EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE defaults to using CGL, and eglSetSwapInterval is broken for this backend
|
||||||
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE,
|
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE,
|
||||||
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
|
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
|
||||||
EGL_NONE};
|
EGL_NONE};
|
||||||
|
|
||||||
surface->eglDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, (void*)EGL_DEFAULT_DISPLAY, displayAttribs);
|
surface->eglDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, (void*)EGL_DEFAULT_DISPLAY, displayAttribs);
|
||||||
eglInitialize(surface->eglDisplay, NULL, NULL);
|
eglInitialize(surface->eglDisplay, NULL, NULL);
|
||||||
|
|
||||||
EGLint const configAttributes[] = {
|
EGLint const configAttributes[] = {
|
||||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||||
EGL_RED_SIZE, 8,
|
EGL_RED_SIZE, 8,
|
||||||
EGL_GREEN_SIZE, 8,
|
EGL_GREEN_SIZE, 8,
|
||||||
EGL_BLUE_SIZE, 8,
|
EGL_BLUE_SIZE, 8,
|
||||||
EGL_ALPHA_SIZE, 8,
|
EGL_ALPHA_SIZE, 8,
|
||||||
EGL_DEPTH_SIZE, 24,
|
EGL_DEPTH_SIZE, 24,
|
||||||
EGL_STENCIL_SIZE, 8,
|
EGL_STENCIL_SIZE, 8,
|
||||||
EGL_SAMPLE_BUFFERS, 0,
|
EGL_SAMPLE_BUFFERS, 0,
|
||||||
EGL_SAMPLES, EGL_DONT_CARE,
|
EGL_SAMPLES, EGL_DONT_CARE,
|
||||||
EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT,
|
EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT,
|
||||||
EGL_NONE };
|
EGL_NONE };
|
||||||
|
|
||||||
eglChooseConfig(surface->eglDisplay, configAttributes, &surface->eglConfig, 1, &surface->numConfigs);
|
eglChooseConfig(surface->eglDisplay, configAttributes, &surface->eglConfig, 1, &surface->numConfigs);
|
||||||
|
|
||||||
EGLint const surfaceAttributes[] = {EGL_NONE};
|
EGLint const surfaceAttributes[] = {EGL_NONE};
|
||||||
surface->eglSurface = eglCreateWindowSurface(surface->eglDisplay, surface->eglConfig, surface->layer, surfaceAttributes);
|
surface->eglSurface = eglCreateWindowSurface(surface->eglDisplay, surface->eglConfig, surface->layer, surfaceAttributes);
|
||||||
|
|
||||||
eglBindAPI(EGL_OPENGL_ES_API);
|
eglBindAPI(EGL_OPENGL_ES_API);
|
||||||
EGLint contextAttributes[] = {
|
EGLint contextAttributes[] = {
|
||||||
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
|
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
|
||||||
EGL_CONTEXT_MINOR_VERSION_KHR, 0, //NOTE: Angle can't create a GLES 3.1 context on macOS
|
EGL_CONTEXT_MINOR_VERSION_KHR, 0, //NOTE: Angle can't create a GLES 3.1 context on macOS
|
||||||
EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE,
|
EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE,
|
||||||
EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE, EGL_TRUE,
|
EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE, EGL_TRUE,
|
||||||
EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE, EGL_FALSE,
|
EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE, EGL_FALSE,
|
||||||
EGL_NONE};
|
EGL_NONE};
|
||||||
|
|
||||||
surface->eglContext = eglCreateContext(surface->eglDisplay, surface->eglConfig, EGL_NO_CONTEXT, contextAttributes);
|
surface->eglContext = eglCreateContext(surface->eglDisplay, surface->eglConfig, EGL_NO_CONTEXT, contextAttributes);
|
||||||
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
|
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
|
||||||
|
|
||||||
eglSwapInterval(surface->eglDisplay, 1);
|
eglSwapInterval(surface->eglDisplay, 1);
|
||||||
|
|
||||||
mg_surface handle = mg_surface_alloc_handle((mg_surface_data*)surface);
|
mg_surface handle = mg_surface_alloc_handle((mg_surface_data*)surface);
|
||||||
return(handle);
|
return(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
mg_surface mg_gles_surface_create_offscreen(u32 width, u32 height)
|
mg_surface mg_gles_surface_create_offscreen(u32 width, u32 height)
|
||||||
{
|
{
|
||||||
return(mg_gles_surface_create_with_view(width, height, 0));
|
return(mg_gles_surface_create_with_view(width, height, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
mg_surface mg_gles_surface_create_for_window(mp_window window)
|
mg_surface mg_gles_surface_create_for_window(mp_window window)
|
||||||
{
|
{
|
||||||
mg_surface res = mg_surface_nil();
|
mg_surface res = mg_surface_nil();
|
||||||
mp_window_data* windowData = mp_window_ptr_from_handle(window);
|
mp_window_data* windowData = mp_window_ptr_from_handle(window);
|
||||||
if(windowData)
|
if(windowData)
|
||||||
{
|
{
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
{
|
{
|
||||||
NSRect frame = [[windowData->osx.nsWindow contentView] frame];
|
NSRect frame = [[windowData->osx.nsWindow contentView] frame];
|
||||||
NSView* view = [[NSView alloc] initWithFrame: frame];
|
NSView* view = [[NSView alloc] initWithFrame: frame];
|
||||||
|
|
||||||
res = mg_gles_surface_create_with_view(frame.size.width, frame.size.height, view);
|
res = mg_gles_surface_create_with_view(frame.size.width, frame.size.height, view);
|
||||||
|
|
||||||
if(!mg_surface_is_nil(res))
|
if(!mg_surface_is_nil(res))
|
||||||
{
|
{
|
||||||
[[windowData->osx.nsWindow contentView] addSubview: view];
|
[[windowData->osx.nsWindow contentView] addSubview: view];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
1448
src/win32_app.c
1448
src/win32_app.c
File diff suppressed because it is too large
Load Diff
|
@ -6,7 +6,7 @@
|
||||||
* @revision:
|
* @revision:
|
||||||
*
|
*
|
||||||
*****************************************************************/
|
*****************************************************************/
|
||||||
#include<GLES3/gl32.h>
|
#include<GLES3/gl31.h>
|
||||||
#define EGL_EGLEXT_PROTOTYPES
|
#define EGL_EGLEXT_PROTOTYPES
|
||||||
#include<EGL/egl.h>
|
#include<EGL/egl.h>
|
||||||
#include<EGL/eglext.h>
|
#include<EGL/eglext.h>
|
||||||
|
@ -108,7 +108,7 @@ mg_surface mg_gles_surface_create_for_window(mp_window window)
|
||||||
eglBindAPI(EGL_OPENGL_ES_API);
|
eglBindAPI(EGL_OPENGL_ES_API);
|
||||||
EGLint contextAttributes[] = {
|
EGLint contextAttributes[] = {
|
||||||
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
|
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
|
||||||
EGL_CONTEXT_MINOR_VERSION_KHR, 0, //NOTE: Angle can't create a GLES 3.1 context on macOS
|
EGL_CONTEXT_MINOR_VERSION_KHR, 1, //NOTE: Angle can't create a GLES 3.1 context on macOS
|
||||||
EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE,
|
EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE,
|
||||||
EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE, EGL_TRUE,
|
EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE, EGL_TRUE,
|
||||||
EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE, EGL_FALSE,
|
EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE, EGL_FALSE,
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
#ifndef __WIN32_GLES_SURFACE_H_
|
#ifndef __WIN32_GLES_SURFACE_H_
|
||||||
#define __WIN32_GLES_SURFACE_H_
|
#define __WIN32_GLES_SURFACE_H_
|
||||||
|
|
||||||
mg_surface mg_gles_surface_create_for_window(mg_window window);
|
#include"graphics.h"
|
||||||
|
#include"mp_app.h"
|
||||||
|
|
||||||
|
mg_surface mg_gles_surface_create_for_window(mp_window window);
|
||||||
|
|
||||||
#endif // __WIN32_GLES_SURFACE_H_
|
#endif // __WIN32_GLES_SURFACE_H_
|
||||||
|
|
Loading…
Reference in New Issue