end of line renormalization

This commit is contained in:
Martin Fouilleul 2023-03-05 16:05:43 +01:00
parent 4359bdaa3c
commit 592f4cdecd
52 changed files with 26512 additions and 26512 deletions

30
.gitignore vendored
View File

@ -1,16 +1,16 @@
.DS_Store .DS_Store
*.dSYM *.dSYM
bin/* bin/*
*.metallib *.metallib
*.pdb *.pdb
*.exe *.exe
*.ilk *.ilk
*.vs *.vs
*.obj *.obj
*.lib *.lib
*.dll *.dll
*.sln *.sln
Debug/* Debug/*
src/glsl_shaders.h src/glsl_shaders.h

View File

@ -1,11 +1,11 @@
if not exist bin mkdir bin if not exist bin mkdir bin
set glsl_shaders=src\glsl_shaders\common.glsl src\glsl_shaders\blit_vertex.glsl src\glsl_shaders\blit_fragment.glsl src\glsl_shaders\clear_counters.glsl src\glsl_shaders\tile.glsl src\glsl_shaders\sort.glsl src\glsl_shaders\draw.glsl set glsl_shaders=src\glsl_shaders\common.glsl src\glsl_shaders\blit_vertex.glsl src\glsl_shaders\blit_fragment.glsl src\glsl_shaders\clear_counters.glsl src\glsl_shaders\tile.glsl src\glsl_shaders\sort.glsl src\glsl_shaders\draw.glsl
call python3 scripts\embed_text.py %glsl_shaders% --prefix=glsl_ --output src\glsl_shaders.h call python3 scripts\embed_text.py %glsl_shaders% --prefix=glsl_ --output src\glsl_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
set LIBS=user32.lib opengl32.lib gdi32.lib shcore.lib delayimp.lib dwmapi.lib /LIBPATH:./bin libEGL.dll.lib libGLESv2.dll.lib /DELAYLOAD:libEGL.dll /DELAYLOAD:libGLESv2.dll set LIBS=user32.lib opengl32.lib gdi32.lib shcore.lib delayimp.lib dwmapi.lib /LIBPATH:./bin libEGL.dll.lib libGLESv2.dll.lib /DELAYLOAD:libEGL.dll /DELAYLOAD:libGLESv2.dll
cl /we4013 /Zi /Zc:preprocessor /DMP_BUILD_DLL /std:c11 %INCLUDES% src/milepost.c /Fo:bin/milepost.o /LD /link %LIBS% /OUT:bin/milepost.dll /IMPLIB:bin/milepost.dll.lib cl /we4013 /Zi /Zc:preprocessor /DMP_BUILD_DLL /std:c11 %INCLUDES% src/milepost.c /Fo:bin/milepost.o /LD /link %LIBS% /OUT:bin/milepost.dll /IMPLIB:bin/milepost.dll.lib

View File

@ -1,4 +1,4 @@
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.dll.lib /out:../../bin/example_canvas.exe cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /out:../../bin/example_canvas.exe

View File

@ -1,223 +1,223 @@
/************************************************************//** /************************************************************//**
* *
* @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>
#include<errno.h> #include<errno.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"
#define LOG_SUBSYSTEM "Main" #define LOG_SUBSYSTEM "Main"
mg_font create_font() mg_font create_font()
{ {
//NOTE(martin): create font //NOTE(martin): create font
str8 fontPath = mp_app_get_resource_path(mem_scratch(), "../resources/OpenSansLatinSubset.ttf"); str8 fontPath = mp_app_get_resource_path(mem_scratch(), "../resources/OpenSansLatinSubset.ttf");
char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath); char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath);
FILE* fontFile = fopen(fontPathCString, "r"); FILE* fontFile = fopen(fontPathCString, "r");
if(!fontFile) if(!fontFile)
{ {
LOG_ERROR("Could not load font file '%s': %s\n", fontPathCString, strerror(errno)); LOG_ERROR("Could not load font file '%s': %s\n", fontPathCString, strerror(errno));
return(mg_font_nil()); return(mg_font_nil());
} }
unsigned char* fontData = 0; unsigned char* fontData = 0;
fseek(fontFile, 0, SEEK_END); fseek(fontFile, 0, SEEK_END);
u32 fontDataSize = ftell(fontFile); u32 fontDataSize = ftell(fontFile);
rewind(fontFile); rewind(fontFile);
fontData = (unsigned char*)malloc(fontDataSize); fontData = (unsigned char*)malloc(fontDataSize);
fread(fontData, 1, fontDataSize, fontFile); fread(fontData, 1, fontDataSize, fontFile);
fclose(fontFile); fclose(fontFile);
unicode_range ranges[5] = {UNICODE_RANGE_BASIC_LATIN, unicode_range ranges[5] = {UNICODE_RANGE_BASIC_LATIN,
UNICODE_RANGE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT, UNICODE_RANGE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT,
UNICODE_RANGE_LATIN_EXTENDED_A, UNICODE_RANGE_LATIN_EXTENDED_A,
UNICODE_RANGE_LATIN_EXTENDED_B, UNICODE_RANGE_LATIN_EXTENDED_B,
UNICODE_RANGE_SPECIALS}; UNICODE_RANGE_SPECIALS};
mg_font font = mg_font_create_from_memory(fontDataSize, fontData, 5, ranges); mg_font font = mg_font_create_from_memory(fontDataSize, fontData, 5, ranges);
free(fontData); free(fontData);
return(font); return(font);
} }
int main() int main()
{ {
LogLevel(LOG_LEVEL_WARNING); LogLevel(LOG_LEVEL_WARNING);
mp_init(); mp_init();
mp_clock_init(); //TODO put that in mp_init()? mp_clock_init(); //TODO put that in mp_init()?
mp_rect windowRect = {.x = 100, .y = 100, .w = 810, .h = 610}; mp_rect windowRect = {.x = 100, .y = 100, .w = 810, .h = 610};
mp_window window = mp_window_create(windowRect, "test", 0); mp_window window = mp_window_create(windowRect, "test", 0);
mp_rect contentRect = mp_window_get_content_rect(window); mp_rect contentRect = mp_window_get_content_rect(window);
//NOTE: create surface //NOTE: create surface
mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT); mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT);
mg_surface_swap_interval(surface, 0); mg_surface_swap_interval(surface, 0);
//TODO: create canvas //TODO: create canvas
mg_canvas canvas = mg_canvas_create(surface); mg_canvas canvas = mg_canvas_create(surface);
if(mg_canvas_is_nil(canvas)) if(mg_canvas_is_nil(canvas))
{ {
printf("Error: couldn't create canvas\n"); printf("Error: couldn't create canvas\n");
return(-1); return(-1);
} }
mg_font font = create_font(); mg_font font = create_font();
// start app // start app
mp_window_bring_to_front(window); mp_window_bring_to_front(window);
mp_window_focus(window); mp_window_focus(window);
f32 x = 400, y = 300; f32 x = 400, y = 300;
f32 speed = 0; f32 speed = 0;
f32 dx = speed, dy = speed; f32 dx = speed, dy = speed;
f64 frameTime = 0; f64 frameTime = 0;
while(!mp_should_quit()) while(!mp_should_quit())
{ {
f64 startTime = mp_get_time(MP_CLOCK_MONOTONIC); f64 startTime = mp_get_time(MP_CLOCK_MONOTONIC);
mp_pump_events(0); mp_pump_events(0);
mp_event event = {0}; mp_event event = {0};
while(mp_next_event(&event)) while(mp_next_event(&event))
{ {
switch(event.type) switch(event.type)
{ {
case MP_EVENT_WINDOW_CLOSE: case MP_EVENT_WINDOW_CLOSE:
{ {
mp_request_quit(); mp_request_quit();
} break; } break;
case MP_EVENT_KEYBOARD_KEY: case MP_EVENT_KEYBOARD_KEY:
{ {
if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT) if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT)
{ {
if(event.key.code == MP_KEY_LEFT) if(event.key.code == MP_KEY_LEFT)
{ {
if(x - 200 > 0) if(x - 200 > 0)
{ {
x-=5; x-=5;
} }
} }
else if(event.key.code == MP_KEY_RIGHT) else if(event.key.code == MP_KEY_RIGHT)
{ {
if(x + 200 < contentRect.w) if(x + 200 < contentRect.w)
{ {
x+=5; x+=5;
} }
} }
else if(event.key.code == MP_KEY_UP) else if(event.key.code == MP_KEY_UP)
{ {
if(y + 200 < contentRect.h) if(y + 200 < contentRect.h)
{ {
y+=5; y+=5;
} }
} }
else if(event.key.code == MP_KEY_DOWN) else if(event.key.code == MP_KEY_DOWN)
{ {
if(y - 200 > 0) if(y - 200 > 0)
{ {
y-=5; y-=5;
} }
} }
//*/ //*/
} }
} break; } break;
default: default:
break; break;
} }
} }
if(x-200 < 0) if(x-200 < 0)
{ {
x = 200; x = 200;
dx = speed; dx = speed;
} }
if(x+200 > contentRect.w) if(x+200 > contentRect.w)
{ {
x = contentRect.w - 200; x = contentRect.w - 200;
dx = -speed; dx = -speed;
} }
if(y-200 < 0) if(y-200 < 0)
{ {
y = 200; y = 200;
dy = speed; dy = speed;
} }
if(y+200 > contentRect.h) if(y+200 > contentRect.h)
{ {
y = contentRect.h - 200; y = contentRect.h - 200;
dy = -speed; dy = -speed;
} }
x += dx; x += dx;
y += dy; y += dy;
mg_surface_prepare(surface); mg_surface_prepare(surface);
// background // background
mg_set_color_rgba(0, 1, 1, 1); mg_set_color_rgba(0, 1, 1, 1);
mg_clear(); mg_clear();
// head // head
mg_set_color_rgba(1, 1, 0, 1); mg_set_color_rgba(1, 1, 0, 1);
mg_circle_fill(x, y, 200); mg_circle_fill(x, y, 200);
// smile // smile
f32 frown = frameTime > 0.033 ? 100 : 0; f32 frown = frameTime > 0.033 ? 100 : 0;
mg_set_color_rgba(0, 0, 0, 1); mg_set_color_rgba(0, 0, 0, 1);
mg_set_width(20); mg_set_width(20);
mg_move_to(x-100, y-100); mg_move_to(x-100, y-100);
mg_cubic_to(x-50, y-150+frown, x+50, y-150+frown, x+100, y-100); mg_cubic_to(x-50, y-150+frown, x+50, y-150+frown, x+100, y-100);
mg_stroke(); mg_stroke();
// eyes // eyes
mg_ellipse_fill(x-70, y+50, 30, 50); mg_ellipse_fill(x-70, y+50, 30, 50);
mg_ellipse_fill(x+70, y+50, 30, 50); mg_ellipse_fill(x+70, y+50, 30, 50);
// text // text
mg_set_color_rgba(0, 0, 1, 1); mg_set_color_rgba(0, 0, 1, 1);
mg_set_font(font); mg_set_font(font);
mg_set_font_size(12); mg_set_font_size(12);
mg_move_to(50, 50); mg_move_to(50, 50);
str8 text = str8_pushf(mem_scratch(), str8 text = str8_pushf(mem_scratch(),
"Milepost vector graphics test program (frame time = %fs, fps = %f)...", "Milepost vector graphics test program (frame time = %fs, fps = %f)...",
frameTime, frameTime,
1./frameTime); 1./frameTime);
mg_text_outlines(text); mg_text_outlines(text);
mg_fill(); mg_fill();
printf("Milepost vector graphics test program (frame time = %fs, fps = %f)...\n", printf("Milepost vector graphics test program (frame time = %fs, fps = %f)...\n",
frameTime, frameTime,
1./frameTime); 1./frameTime);
mg_flush(); mg_flush();
mg_surface_present(surface); mg_surface_present(surface);
mem_arena_clear(mem_scratch()); mem_arena_clear(mem_scratch());
frameTime = mp_get_time(MP_CLOCK_MONOTONIC) - startTime; frameTime = mp_get_time(MP_CLOCK_MONOTONIC) - startTime;
} }
mg_font_destroy(font); mg_font_destroy(font);
mg_canvas_destroy(canvas); mg_canvas_destroy(canvas);
mg_surface_destroy(surface); mg_surface_destroy(surface);
mp_window_destroy(window); mp_window_destroy(window);
mp_terminate(); mp_terminate();
return(0); return(0);
} }

View File

@ -1,4 +1,4 @@
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext
cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /out:../../bin/perf_text.exe cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /out:../../bin/perf_text.exe

View File

@ -1,3 +1,3 @@
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext
cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /out:../../bin/example_gl_triangle.exe cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /out:../../bin/example_gl_triangle.exe

View File

@ -1,165 +1,165 @@
/************************************************************//** /************************************************************//**
* *
* @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>
#define MG_INCLUDE_GL_API #define MG_INCLUDE_GL_API
#include"milepost.h" #include"milepost.h"
#define LOG_SUBSYSTEM "Main" #define LOG_SUBSYSTEM "Main"
unsigned int program; unsigned int program;
const char* vshaderSource = const char* vshaderSource =
"#version 430\n" "#version 430\n"
"attribute vec4 vPosition;\n" "attribute vec4 vPosition;\n"
"uniform mat4 transform;\n" "uniform mat4 transform;\n"
"void main()\n" "void main()\n"
"{\n" "{\n"
" gl_Position = transform*vPosition;\n" " gl_Position = transform*vPosition;\n"
"}\n"; "}\n";
const char* fshaderSource = const char* fshaderSource =
"#version 430\n" "#version 430\n"
"precision mediump float;\n" "precision mediump float;\n"
"void main()\n" "void main()\n"
"{\n" "{\n"
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n"; "}\n";
void compile_shader(GLuint shader, const char* source) void compile_shader(GLuint shader, const char* source)
{ {
glShaderSource(shader, 1, &source, 0); glShaderSource(shader, 1, &source, 0);
glCompileShader(shader); glCompileShader(shader);
int err = glGetError(); int err = glGetError();
if(err) if(err)
{ {
printf("gl error: %i\n", err); printf("gl error: %i\n", err);
} }
int status = 0; int status = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status); glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if(!status) if(!status)
{ {
char buffer[256]; char buffer[256];
int size = 0; int size = 0;
glGetShaderInfoLog(shader, 256, &size, buffer); glGetShaderInfoLog(shader, 256, &size, buffer);
printf("shader error: %.*s\n", size, buffer); printf("shader error: %.*s\n", size, buffer);
} }
} }
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
mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_GL); mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_GL);
//NOTE: init shader and gl state //NOTE: init shader and gl state
mg_surface_prepare(surface); mg_surface_prepare(surface);
GLuint vao; GLuint vao;
glGenVertexArrays(1, &vao); glGenVertexArrays(1, &vao);
glBindVertexArray(vao); glBindVertexArray(vao);
GLuint vertexBuffer; GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer); glGenBuffers(1, &vertexBuffer);
GLfloat vertices[] = { GLfloat vertices[] = {
-0.866/2, -0.5/2, 0, 0.866/2, -0.5/2, 0, 0, 0.5, 0}; -0.866/2, -0.5/2, 0, 0.866/2, -0.5/2, 0, 0, 0.5, 0};
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
unsigned int vshader = glCreateShader(GL_VERTEX_SHADER); unsigned int vshader = glCreateShader(GL_VERTEX_SHADER);
unsigned int fshader = glCreateShader(GL_FRAGMENT_SHADER); unsigned int fshader = glCreateShader(GL_FRAGMENT_SHADER);
program = glCreateProgram(); program = glCreateProgram();
compile_shader(vshader, vshaderSource); compile_shader(vshader, vshaderSource);
compile_shader(fshader, fshaderSource); compile_shader(fshader, fshaderSource);
glAttachShader(program, vshader); glAttachShader(program, vshader);
glAttachShader(program, fshader); glAttachShader(program, fshader);
glLinkProgram(program); glLinkProgram(program);
int status = 0; int status = 0;
glGetProgramiv(program, GL_LINK_STATUS, &status); glGetProgramiv(program, GL_LINK_STATUS, &status);
if(!status) if(!status)
{ {
char buffer[256]; char buffer[256];
int size = 0; int size = 0;
glGetProgramInfoLog(program, 256, &size, buffer); glGetProgramInfoLog(program, 256, &size, buffer);
printf("link error: %.*s\n", size, buffer); printf("link error: %.*s\n", size, buffer);
} }
glUseProgram(program); glUseProgram(program);
mp_window_bring_to_front(window); mp_window_bring_to_front(window);
// mp_window_focus(window); // mp_window_focus(window);
while(!mp_should_quit()) while(!mp_should_quit())
{ {
mp_pump_events(0); mp_pump_events(0);
mp_event event = {0}; mp_event event = {0};
while(mp_next_event(&event)) while(mp_next_event(&event))
{ {
switch(event.type) switch(event.type)
{ {
case MP_EVENT_WINDOW_CLOSE: case MP_EVENT_WINDOW_CLOSE:
{ {
mp_request_quit(); mp_request_quit();
} break; } break;
default: default:
break; break;
} }
} }
mg_surface_prepare(surface); mg_surface_prepare(surface);
glClearColor(0.3, 0.3, 1, 1); glClearColor(0.3, 0.3, 1, 1);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
static float alpha = 0; static float alpha = 0;
//f32 aspect = frameSize.x/frameSize.y; //f32 aspect = frameSize.x/frameSize.y;
f32 aspect = 800/(f32)600; f32 aspect = 800/(f32)600;
GLfloat matrix[] = {cosf(alpha)/aspect, sinf(alpha), 0, 0, GLfloat matrix[] = {cosf(alpha)/aspect, sinf(alpha), 0, 0,
-sinf(alpha)/aspect, cosf(alpha), 0, 0, -sinf(alpha)/aspect, cosf(alpha), 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 1}; 0, 0, 0, 1};
alpha += 2*M_PI/120; alpha += 2*M_PI/120;
glUniformMatrix4fv(0, 1, false, matrix); glUniformMatrix4fv(0, 1, false, matrix);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
mg_surface_present(surface); mg_surface_present(surface);
} }
mp_terminate(); mp_terminate();
return(0); return(0);
} }

View File

@ -1,3 +1,3 @@
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.dll.lib /out:../../bin/example_gles_triangle.exe cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /out:../../bin/example_gles_triangle.exe

View File

@ -1,164 +1,164 @@
/************************************************************//** /************************************************************//**
* *
* @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>
#define MG_INCLUDE_GL_API 1 #define MG_INCLUDE_GL_API 1
#include"milepost.h" #include"milepost.h"
#define LOG_SUBSYSTEM "Main" #define LOG_SUBSYSTEM "Main"
unsigned int program; unsigned int program;
const char* vshaderSource = const char* vshaderSource =
//"#version 320 es\n" //"#version 320 es\n"
"attribute vec4 vPosition;\n" "attribute vec4 vPosition;\n"
"uniform mat4 transform;\n" "uniform mat4 transform;\n"
"void main()\n" "void main()\n"
"{\n" "{\n"
" gl_Position = transform*vPosition;\n" " gl_Position = transform*vPosition;\n"
"}\n"; "}\n";
const char* fshaderSource = const char* fshaderSource =
//"#version 320 es\n" //"#version 320 es\n"
"precision mediump float;\n" "precision mediump float;\n"
"void main()\n" "void main()\n"
"{\n" "{\n"
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n"; "}\n";
void compile_shader(GLuint shader, const char* source) void compile_shader(GLuint shader, const char* source)
{ {
glShaderSource(shader, 1, &source, 0); glShaderSource(shader, 1, &source, 0);
glCompileShader(shader); glCompileShader(shader);
int err = glGetError(); int err = glGetError();
if(err) if(err)
{ {
printf("gl error: %i\n", err); printf("gl error: %i\n", err);
} }
int status = 0; int status = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status); glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if(!status) if(!status)
{ {
char buffer[256]; char buffer[256];
int size = 0; int size = 0;
glGetShaderInfoLog(shader, 256, &size, buffer); glGetShaderInfoLog(shader, 256, &size, buffer);
printf("shader error: %.*s\n", size, buffer); printf("shader error: %.*s\n", size, buffer);
} }
} }
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
mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_GLES); mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_GLES);
mg_surface_prepare(surface); mg_surface_prepare(surface);
//NOTE: init shader and gl state //NOTE: init shader and gl state
GLuint vao; GLuint vao;
glGenVertexArrays(1, &vao); glGenVertexArrays(1, &vao);
glBindVertexArray(vao); glBindVertexArray(vao);
GLuint vertexBuffer; GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer); glGenBuffers(1, &vertexBuffer);
GLfloat vertices[] = { GLfloat vertices[] = {
-0.866/2, -0.5/2, 0, 0.866/2, -0.5/2, 0, 0, 0.5, 0}; -0.866/2, -0.5/2, 0, 0.866/2, -0.5/2, 0, 0, 0.5, 0};
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
unsigned int vshader = glCreateShader(GL_VERTEX_SHADER); unsigned int vshader = glCreateShader(GL_VERTEX_SHADER);
unsigned int fshader = glCreateShader(GL_FRAGMENT_SHADER); unsigned int fshader = glCreateShader(GL_FRAGMENT_SHADER);
program = glCreateProgram(); program = glCreateProgram();
compile_shader(vshader, vshaderSource); compile_shader(vshader, vshaderSource);
compile_shader(fshader, fshaderSource); compile_shader(fshader, fshaderSource);
glAttachShader(program, vshader); glAttachShader(program, vshader);
glAttachShader(program, fshader); glAttachShader(program, fshader);
glLinkProgram(program); glLinkProgram(program);
int status = 0; int status = 0;
glGetProgramiv(program, GL_LINK_STATUS, &status); glGetProgramiv(program, GL_LINK_STATUS, &status);
if(!status) if(!status)
{ {
char buffer[256]; char buffer[256];
int size = 0; int size = 0;
glGetProgramInfoLog(program, 256, &size, buffer); glGetProgramInfoLog(program, 256, &size, buffer);
printf("link error: %.*s\n", size, buffer); printf("link error: %.*s\n", size, buffer);
} }
glUseProgram(program); glUseProgram(program);
mp_window_bring_to_front(window); mp_window_bring_to_front(window);
// mp_window_focus(window); // mp_window_focus(window);
while(!mp_should_quit()) while(!mp_should_quit())
{ {
mp_pump_events(0); mp_pump_events(0);
mp_event event = {0}; mp_event event = {0};
while(mp_next_event(&event)) while(mp_next_event(&event))
{ {
switch(event.type) switch(event.type)
{ {
case MP_EVENT_WINDOW_CLOSE: case MP_EVENT_WINDOW_CLOSE:
{ {
mp_request_quit(); mp_request_quit();
} break; } break;
default: default:
break; break;
} }
} }
mg_surface_prepare(surface); mg_surface_prepare(surface);
glClearColor(0.3, 0.3, 1, 1); glClearColor(0.3, 0.3, 1, 1);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
static float alpha = 0; static float alpha = 0;
//f32 aspect = frameSize.x/frameSize.y; //f32 aspect = frameSize.x/frameSize.y;
f32 aspect = 800/(f32)600; f32 aspect = 800/(f32)600;
GLfloat matrix[] = {cosf(alpha)/aspect, sinf(alpha), 0, 0, GLfloat matrix[] = {cosf(alpha)/aspect, sinf(alpha), 0, 0,
-sinf(alpha)/aspect, cosf(alpha), 0, 0, -sinf(alpha)/aspect, cosf(alpha), 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 1}; 0, 0, 0, 1};
alpha += 2*M_PI/120; alpha += 2*M_PI/120;
glUniformMatrix4fv(0, 1, false, matrix); glUniformMatrix4fv(0, 1, false, matrix);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
mg_surface_present(surface); mg_surface_present(surface);
} }
mp_terminate(); mp_terminate();
return(0); return(0);
} }

View File

@ -1,44 +1,44 @@
angle install on windows angle install on windows
* need Python3 (can install through win app store) * need Python3 (can install through win app store)
* need Windows SDK * need Windows SDK
* clone depot_tools git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git * clone depot_tools git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
or download and unzip bundle at https://storage.googleapis.com/chrome-infra/depot_tools.zip or download and unzip bundle at https://storage.googleapis.com/chrome-infra/depot_tools.zip
* set depot_tools in path env variable through control panel>System and security>system>advanced system settings * set depot_tools in path env variable through control panel>System and security>system>advanced system settings
* run gclient in a cmd shell * run gclient in a cmd shell
* set DEPOT_TOOLS_WIN_TOOLCHAIN=0 * set DEPOT_TOOLS_WIN_TOOLCHAIN=0
* mkdir angle * mkdir angle
* cd angle * cd angle
* fetch angle * fetch angle
* wait a million years * wait a million years
* fails when running python3 third_party/depot_tools/download_from_google_storage.py ... * fails when running python3 third_party/depot_tools/download_from_google_storage.py ...
-> open DEPS and change third_party/depot_tools with ../depot/tools -> open DEPS and change third_party/depot_tools with ../depot/tools
* run gclient sync to complete previous step * run gclient sync to complete previous step
* gn gen out/Debug * gn gen out/Debug
* gn args out/Debug and edit arguments: * gn args out/Debug and edit arguments:
angle_enable_vulkan = false angle_enable_vulkan = false
angle_build_tests = false angle_build_tests = false
is_component_build = false is_component_build = false
#to get debugging kinda working with renderdoc: #to get debugging kinda working with renderdoc:
angle_enable_trace = true angle_enable_trace = true
angle_enable_annotator_run_time_checks = true angle_enable_annotator_run_time_checks = true
* autoninja -C out/Debug * autoninja -C out/Debug
* wait a while * wait a while
* link with libEGL.dll.lib and libGLESv2.dll.lib * link with libEGL.dll.lib and libGLESv2.dll.lib
* put libEGL.dll and libGLESv2.dll in same directory as executable * put libEGL.dll and libGLESv2.dll in same directory as executable
Debugging Debugging
--------- ---------
in renderdoc, set env variables in renderdoc, set env variables
RENDERDOC_HOOK_EGL 0 (if you want to trace underlying native API) RENDERDOC_HOOK_EGL 0 (if you want to trace underlying native API)
RENDERDOC_HOOK_EGL 1 (if you want to trace EGL calls. You also need to put libEGL in the renderdoc folder so it's found when capturing stuff. Unfortunately though, that seems to provoke crashes...) RENDERDOC_HOOK_EGL 1 (if you want to trace EGL calls. You also need to put libEGL in the renderdoc folder so it's found when capturing stuff. Unfortunately though, that seems to provoke crashes...)
ANGLE_ENABLE_DEBUG_MARKERS 1 (to turn on debug markers) ANGLE_ENABLE_DEBUG_MARKERS 1 (to turn on debug markers)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +1,44 @@
import os import os
from datetime import datetime from datetime import datetime
from argparse import ArgumentParser from argparse import ArgumentParser
parser = ArgumentParser() parser = ArgumentParser()
parser.add_argument("inputFiles", nargs="+") parser.add_argument("inputFiles", nargs="+")
parser.add_argument("-o", "--output") parser.add_argument("-o", "--output")
parser.add_argument("-p", "--prefix") parser.add_argument("-p", "--prefix")
args = parser.parse_args() args = parser.parse_args()
output = open(args.output, "w") output = open(args.output, "w")
output.write("/*********************************************************************\n") output.write("/*********************************************************************\n")
output.write("*\n") output.write("*\n")
output.write("*\tfile: %s\n" % os.path.basename(args.output)) output.write("*\tfile: %s\n" % os.path.basename(args.output))
output.write("*\tnote: string literals auto-generated by embed_text.py\n") output.write("*\tnote: string literals auto-generated by embed_text.py\n")
output.write("*\tdate: %s\n" % datetime.now().strftime("%d/%m%Y")) output.write("*\tdate: %s\n" % datetime.now().strftime("%d/%m%Y"))
output.write("*\n") output.write("*\n")
output.write("**********************************************************************/\n") output.write("**********************************************************************/\n")
outSymbol = (os.path.splitext(os.path.basename(args.output))[0]).upper() outSymbol = (os.path.splitext(os.path.basename(args.output))[0]).upper()
output.write("#ifndef __%s_H__\n" % outSymbol) output.write("#ifndef __%s_H__\n" % outSymbol)
output.write("#define __%s_H__\n" % outSymbol) output.write("#define __%s_H__\n" % outSymbol)
output.write("\n\n") output.write("\n\n")
for fileName in args.inputFiles: for fileName in args.inputFiles:
f = open(fileName, "r") f = open(fileName, "r")
lines = f.read().splitlines() lines = f.read().splitlines()
output.write("//NOTE: string imported from %s\n" % fileName) output.write("//NOTE: string imported from %s\n" % fileName)
stringName = os.path.splitext(os.path.basename(fileName))[0] stringName = os.path.splitext(os.path.basename(fileName))[0]
output.write(f"const char* {args.prefix}{stringName} = ") output.write(f"const char* {args.prefix}{stringName} = ")
for line in lines: for line in lines:
output.write("\n\"%s\\n\"" % line) output.write("\n\"%s\\n\"" % line)
output.write(";\n\n") output.write(";\n\n")
f.close() f.close()
output.write("#endif // __%s_H__\n" % outSymbol) output.write("#endif // __%s_H__\n" % outSymbol)
output.close() output.close()

View File

@ -1,175 +1,175 @@
/************************************************************//** /************************************************************//**
* *
* @file: egl_surface.cpp * @file: egl_surface.cpp
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 17/02/2023 * @date: 17/02/2023
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#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"mp_app_internal.h" #include"mp_app_internal.h"
#include"graphics_internal.h" #include"graphics_internal.h"
#include"gl_loader.h" #include"gl_loader.h"
#if OS_MACOS #if OS_MACOS
//NOTE: EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE on osx defaults to CGL backend, which doesn't handle SwapInterval correctly //NOTE: EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE on osx defaults to CGL backend, which doesn't handle SwapInterval correctly
#define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE #define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE
//NOTE: hardcode GLES versions for now //NOTE: hardcode GLES versions for now
//TODO: use version hints, once we have all api versions correctly categorized by glapi.py //TODO: use version hints, once we have all api versions correctly categorized by glapi.py
#define MG_GLES_VERSION_MAJOR 3 #define MG_GLES_VERSION_MAJOR 3
#define MG_GLES_VERSION_MINOR 0 #define MG_GLES_VERSION_MINOR 0
#define mg_gl_load_gles mg_gl_load_gles30 #define mg_gl_load_gles mg_gl_load_gles30
#else #else
#define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE #define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE
#define MG_GLES_VERSION_MAJOR 3 #define MG_GLES_VERSION_MAJOR 3
#define MG_GLES_VERSION_MINOR 1 #define MG_GLES_VERSION_MINOR 1
#define mg_gl_load_gles mg_gl_load_gles31 #define mg_gl_load_gles mg_gl_load_gles31
#endif #endif
typedef struct mg_egl_surface typedef struct mg_egl_surface
{ {
mg_surface_data interface; mg_surface_data interface;
EGLDisplay eglDisplay; EGLDisplay eglDisplay;
EGLConfig eglConfig; EGLConfig eglConfig;
EGLContext eglContext; EGLContext eglContext;
EGLSurface eglSurface; EGLSurface eglSurface;
mg_gl_api api; mg_gl_api api;
} mg_egl_surface; } mg_egl_surface;
void mg_egl_surface_destroy(mg_surface_data* interface) void mg_egl_surface_destroy(mg_surface_data* interface)
{ {
mg_egl_surface* surface = (mg_egl_surface*)interface; mg_egl_surface* surface = (mg_egl_surface*)interface;
if(&surface->api == mg_gl_get_api()) if(&surface->api == mg_gl_get_api())
{ {
mg_gl_select_api(0); mg_gl_select_api(0);
} }
if(eglGetCurrentContext() == surface->eglContext) if(eglGetCurrentContext() == surface->eglContext)
{ {
eglMakeCurrent(surface->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglMakeCurrent(surface->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
} }
eglDestroyContext(surface->eglDisplay, surface->eglContext); eglDestroyContext(surface->eglDisplay, surface->eglContext);
eglDestroySurface(surface->eglDisplay, surface->eglSurface); eglDestroySurface(surface->eglDisplay, surface->eglSurface);
mg_surface_cleanup((mg_surface_data*)surface); mg_surface_cleanup((mg_surface_data*)surface);
free(surface); free(surface);
} }
void mg_egl_surface_prepare(mg_surface_data* interface) void mg_egl_surface_prepare(mg_surface_data* interface)
{ {
mg_egl_surface* surface = (mg_egl_surface*)interface; mg_egl_surface* surface = (mg_egl_surface*)interface;
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext); eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
mg_gl_select_api(&surface->api); mg_gl_select_api(&surface->api);
} }
void mg_egl_surface_present(mg_surface_data* interface) void mg_egl_surface_present(mg_surface_data* interface)
{ {
mg_egl_surface* surface = (mg_egl_surface*)interface; mg_egl_surface* surface = (mg_egl_surface*)interface;
eglSwapBuffers(surface->eglDisplay, surface->eglSurface); eglSwapBuffers(surface->eglDisplay, surface->eglSurface);
} }
void mg_egl_surface_swap_interval(mg_surface_data* interface, int swap) void mg_egl_surface_swap_interval(mg_surface_data* interface, int swap)
{ {
mg_egl_surface* surface = (mg_egl_surface*)interface; mg_egl_surface* surface = (mg_egl_surface*)interface;
eglSwapInterval(surface->eglDisplay, swap); eglSwapInterval(surface->eglDisplay, swap);
} }
void mg_egl_surface_init(mg_egl_surface* surface) void mg_egl_surface_init(mg_egl_surface* surface)
{ {
void* nativeLayer = surface->interface.nativeLayer((mg_surface_data*)surface); void* nativeLayer = surface->interface.nativeLayer((mg_surface_data*)surface);
surface->interface.backend = MG_BACKEND_GLES; surface->interface.backend = MG_BACKEND_GLES;
surface->interface.destroy = mg_egl_surface_destroy; surface->interface.destroy = mg_egl_surface_destroy;
surface->interface.prepare = mg_egl_surface_prepare; surface->interface.prepare = mg_egl_surface_prepare;
surface->interface.present = mg_egl_surface_present; surface->interface.present = mg_egl_surface_present;
surface->interface.swapInterval = mg_egl_surface_swap_interval; surface->interface.swapInterval = mg_egl_surface_swap_interval;
EGLAttrib displayAttribs[] = { EGLAttrib displayAttribs[] = {
EGL_PLATFORM_ANGLE_TYPE_ANGLE, MG_EGL_PLATFORM_ANGLE_TYPE, EGL_PLATFORM_ANGLE_TYPE_ANGLE, MG_EGL_PLATFORM_ANGLE_TYPE,
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 };
int numConfigs = 0; int numConfigs = 0;
eglChooseConfig(surface->eglDisplay, configAttributes, &surface->eglConfig, 1, &numConfigs); eglChooseConfig(surface->eglDisplay, configAttributes, &surface->eglConfig, 1, &numConfigs);
EGLint const surfaceAttributes[] = {EGL_NONE}; EGLint const surfaceAttributes[] = {EGL_NONE};
surface->eglSurface = eglCreateWindowSurface(surface->eglDisplay, surface->eglSurface = eglCreateWindowSurface(surface->eglDisplay,
surface->eglConfig, surface->eglConfig,
nativeLayer, nativeLayer,
surfaceAttributes); surfaceAttributes);
eglBindAPI(EGL_OPENGL_ES_API); eglBindAPI(EGL_OPENGL_ES_API);
EGLint contextAttributes[] = { EGLint contextAttributes[] = {
EGL_CONTEXT_MAJOR_VERSION_KHR, MG_GLES_VERSION_MAJOR, EGL_CONTEXT_MAJOR_VERSION_KHR, MG_GLES_VERSION_MAJOR,
EGL_CONTEXT_MINOR_VERSION_KHR, MG_GLES_VERSION_MINOR, EGL_CONTEXT_MINOR_VERSION_KHR, MG_GLES_VERSION_MINOR,
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);
mg_gl_load_gles(&surface->api, (mg_gl_load_proc)eglGetProcAddress); mg_gl_load_gles(&surface->api, (mg_gl_load_proc)eglGetProcAddress);
eglSwapInterval(surface->eglDisplay, 1); eglSwapInterval(surface->eglDisplay, 1);
} }
mg_surface_data* mg_egl_surface_create_remote(u32 width, u32 height) mg_surface_data* mg_egl_surface_create_remote(u32 width, u32 height)
{ {
mg_egl_surface* surface = 0; mg_egl_surface* surface = 0;
surface = malloc_type(mg_egl_surface); surface = malloc_type(mg_egl_surface);
if(surface) if(surface)
{ {
memset(surface, 0, sizeof(mg_egl_surface)); memset(surface, 0, sizeof(mg_egl_surface));
mg_surface_init_remote((mg_surface_data*)surface, width, height); mg_surface_init_remote((mg_surface_data*)surface, width, height);
mg_egl_surface_init(surface); mg_egl_surface_init(surface);
} }
return((mg_surface_data*)surface); return((mg_surface_data*)surface);
} }
mg_surface_data* mg_egl_surface_create_for_window(mp_window window) mg_surface_data* mg_egl_surface_create_for_window(mp_window window)
{ {
mg_egl_surface* surface = 0; mg_egl_surface* surface = 0;
mp_window_data* windowData = mp_window_ptr_from_handle(window); mp_window_data* windowData = mp_window_ptr_from_handle(window);
if(windowData) if(windowData)
{ {
surface = malloc_type(mg_egl_surface); surface = malloc_type(mg_egl_surface);
if(surface) if(surface)
{ {
memset(surface, 0, sizeof(mg_egl_surface)); memset(surface, 0, sizeof(mg_egl_surface));
mg_surface_init_for_window((mg_surface_data*)surface, windowData); mg_surface_init_for_window((mg_surface_data*)surface, windowData);
mg_egl_surface_init(surface); mg_egl_surface_init(surface);
} }
} }
return((mg_surface_data*)surface); return((mg_surface_data*)surface);
} }

View File

@ -1,18 +1,18 @@
/************************************************************//** /************************************************************//**
* *
* @file: egl_surface.h * @file: egl_surface.h
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 28/01/2023 * @date: 28/01/2023
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#ifndef __EGL_SURFACE_H_ #ifndef __EGL_SURFACE_H_
#define __EGL_SURFACE_H_ #define __EGL_SURFACE_H_
#include"graphics_internal.h" #include"graphics_internal.h"
#include"mp_app.h" #include"mp_app.h"
mg_surface_data* mg_egl_surface_create_for_window(mp_window window); mg_surface_data* mg_egl_surface_create_for_window(mp_window window);
mg_surface_data* mg_egl_surface_create_remote(u32 width, u32 height); mg_surface_data* mg_egl_surface_create_remote(u32 width, u32 height);
#endif // __EGL_SURFACE_H_ #endif // __EGL_SURFACE_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +1,22 @@
/******************************************************** /********************************************************
* *
* @file: gl_loader.h * @file: gl_loader.h
* @note: auto-generated by glapi.py from gl.xml * @note: auto-generated by glapi.py from gl.xml
* @date: 22/022023 * @date: 22/022023
* *
*********************************************************/ *********************************************************/
#ifndef __GL_LOADER_H__ #ifndef __GL_LOADER_H__
#define __GL_LOADER_H__ #define __GL_LOADER_H__
#include"gl_api.h" #include"gl_api.h"
typedef void*(*mg_gl_load_proc)(const char* name); typedef void*(*mg_gl_load_proc)(const char* name);
void mg_gl_load_gl41(mg_gl_api* api, mg_gl_load_proc loadProc); void mg_gl_load_gl41(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_load_gl43(mg_gl_api* api, mg_gl_load_proc loadProc); void mg_gl_load_gl43(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_load_gles30(mg_gl_api* api, mg_gl_load_proc loadProc); void mg_gl_load_gles30(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_load_gles31(mg_gl_api* api, mg_gl_load_proc loadProc); void mg_gl_load_gles31(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_select_api(mg_gl_api* api); void mg_gl_select_api(mg_gl_api* api);
#endif // __GL_LOADER_H__ #endif // __GL_LOADER_H__

View File

@ -1,467 +1,467 @@
/********************************************************************* /*********************************************************************
* *
* file: glsl_shaders.h * file: glsl_shaders.h
* note: string literals auto-generated by embed_text.py * note: string literals auto-generated by embed_text.py
* date: 03/032023 * date: 03/032023
* *
**********************************************************************/ **********************************************************************/
#ifndef __GLSL_SHADERS_H__ #ifndef __GLSL_SHADERS_H__
#define __GLSL_SHADERS_H__ #define __GLSL_SHADERS_H__
//NOTE: string imported from src\glsl_shaders\common.glsl //NOTE: string imported from src\glsl_shaders\common.glsl
const char* glsl_common = const char* glsl_common =
"\n" "\n"
"layout(std430) buffer;\n" "layout(std430) buffer;\n"
"\n" "\n"
"struct vertex {\n" "struct vertex {\n"
" vec4 cubic;\n" " vec4 cubic;\n"
" vec2 pos;\n" " vec2 pos;\n"
" int shapeIndex;\n" " int shapeIndex;\n"
"};\n" "};\n"
"\n" "\n"
"struct shape {\n" "struct shape {\n"
" vec4 color;\n" " vec4 color;\n"
" vec4 clip;\n" " vec4 clip;\n"
" float uvTransform[6];\n" " float uvTransform[6];\n"
"};\n"; "};\n";
//NOTE: string imported from src\glsl_shaders\blit_vertex.glsl //NOTE: string imported from src\glsl_shaders\blit_vertex.glsl
const char* glsl_blit_vertex = const char* glsl_blit_vertex =
"\n" "\n"
"precision mediump float;\n" "precision mediump float;\n"
"\n" "\n"
"out vec2 uv;\n" "out vec2 uv;\n"
"\n" "\n"
"void main()\n" "void main()\n"
"{\n" "{\n"
" float x = float(((uint(gl_VertexID) + 2u) / 3u)%2u);\n" " float x = float(((uint(gl_VertexID) + 2u) / 3u)%2u);\n"
" float y = float(((uint(gl_VertexID) + 1u) / 3u)%2u);\n" " float y = float(((uint(gl_VertexID) + 1u) / 3u)%2u);\n"
"\n" "\n"
" gl_Position = vec4(-1.0f + x*2.0f, -1.0f+y*2.0f, 0.0f, 1.0f);\n" " gl_Position = vec4(-1.0f + x*2.0f, -1.0f+y*2.0f, 0.0f, 1.0f);\n"
" uv = vec2(x, y);\n" " uv = vec2(x, y);\n"
"}\n"; "}\n";
//NOTE: string imported from src\glsl_shaders\blit_fragment.glsl //NOTE: string imported from src\glsl_shaders\blit_fragment.glsl
const char* glsl_blit_fragment = const char* glsl_blit_fragment =
"\n" "\n"
"precision mediump float;\n" "precision mediump float;\n"
"\n" "\n"
"in vec2 uv;\n" "in vec2 uv;\n"
"out vec4 fragColor;\n" "out vec4 fragColor;\n"
"\n" "\n"
"layout(location=0) uniform sampler2D tex;\n" "layout(location=0) uniform sampler2D tex;\n"
"\n" "\n"
"void main()\n" "void main()\n"
"{\n" "{\n"
" fragColor = texture(tex, uv);\n" " fragColor = texture(tex, uv);\n"
"}\n"; "}\n";
//NOTE: string imported from src\glsl_shaders\clear_counters.glsl //NOTE: string imported from src\glsl_shaders\clear_counters.glsl
const char* glsl_clear_counters = const char* glsl_clear_counters =
"\n" "\n"
"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n" "\n"
"precision mediump float;\n" "precision mediump float;\n"
"layout(std430) buffer;\n" "layout(std430) buffer;\n"
"\n" "\n"
"layout(binding = 0) coherent restrict writeonly buffer tileCounterBufferSSBO {\n" "layout(binding = 0) coherent restrict writeonly buffer tileCounterBufferSSBO {\n"
" uint elements[];\n" " uint elements[];\n"
"} tileCounterBuffer ;\n" "} tileCounterBuffer ;\n"
"\n" "\n"
"void main()\n" "void main()\n"
"{\n" "{\n"
" uint tileIndex = gl_WorkGroupID.x;\n" " uint tileIndex = gl_WorkGroupID.x;\n"
" tileCounterBuffer.elements[tileIndex] = 0u;\n" " tileCounterBuffer.elements[tileIndex] = 0u;\n"
"}\n"; "}\n";
//NOTE: string imported from src\glsl_shaders\tile.glsl //NOTE: string imported from src\glsl_shaders\tile.glsl
const char* glsl_tile = const char* glsl_tile =
"\n" "\n"
"layout(local_size_x = 512, local_size_y = 1, local_size_z = 1) in;\n" "layout(local_size_x = 512, local_size_y = 1, local_size_z = 1) in;\n"
"\n" "\n"
"precision mediump float;\n" "precision mediump float;\n"
"\n" "\n"
"layout(binding = 0) restrict readonly buffer vertexBufferSSBO {\n" "layout(binding = 0) restrict readonly buffer vertexBufferSSBO {\n"
" vertex elements[];\n" " vertex elements[];\n"
"} vertexBuffer ;\n" "} vertexBuffer ;\n"
"\n" "\n"
"layout(binding = 1) restrict readonly buffer shapeBufferSSBO {\n" "layout(binding = 1) restrict readonly buffer shapeBufferSSBO {\n"
" shape elements[];\n" " shape elements[];\n"
"} shapeBuffer ;\n" "} shapeBuffer ;\n"
"\n" "\n"
"layout(binding = 2) restrict readonly buffer indexBufferSSBO {\n" "layout(binding = 2) restrict readonly buffer indexBufferSSBO {\n"
" uint elements[];\n" " uint elements[];\n"
"} indexBuffer ;\n" "} indexBuffer ;\n"
"\n" "\n"
"layout(binding = 3) coherent restrict buffer tileCounterBufferSSBO {\n" "layout(binding = 3) coherent restrict buffer tileCounterBufferSSBO {\n"
" uint elements[];\n" " uint elements[];\n"
"} tileCounterBuffer ;\n" "} tileCounterBuffer ;\n"
"\n" "\n"
"layout(binding = 4) coherent restrict writeonly buffer tileArrayBufferSSBO {\n" "layout(binding = 4) coherent restrict writeonly buffer tileArrayBufferSSBO {\n"
" uint elements[];\n" " uint elements[];\n"
"} tileArrayBuffer ;\n" "} tileArrayBuffer ;\n"
"\n" "\n"
"layout(location = 0) uniform uint indexCount;\n" "layout(location = 0) uniform uint indexCount;\n"
"layout(location = 1) uniform uvec2 tileCount;\n" "layout(location = 1) uniform uvec2 tileCount;\n"
"layout(location = 2) uniform uint tileSize;\n" "layout(location = 2) uniform uint tileSize;\n"
"layout(location = 3) uniform uint tileArraySize;\n" "layout(location = 3) uniform uint tileArraySize;\n"
"layout(location = 4) uniform vec2 scaling;\n" "layout(location = 4) uniform vec2 scaling;\n"
"\n" "\n"
"void main()\n" "void main()\n"
"{\n" "{\n"
" uint triangleIndex = (gl_WorkGroupID.x*gl_WorkGroupSize.x + gl_LocalInvocationIndex) * 3u;\n" " uint triangleIndex = (gl_WorkGroupID.x*gl_WorkGroupSize.x + gl_LocalInvocationIndex) * 3u;\n"
" if(triangleIndex >= indexCount)\n" " if(triangleIndex >= indexCount)\n"
" {\n" " {\n"
" return;\n" " return;\n"
" }\n" " }\n"
"\n" "\n"
" uint i0 = indexBuffer.elements[triangleIndex];\n" " uint i0 = indexBuffer.elements[triangleIndex];\n"
" uint i1 = indexBuffer.elements[triangleIndex+1u];\n" " uint i1 = indexBuffer.elements[triangleIndex+1u];\n"
" uint i2 = indexBuffer.elements[triangleIndex+2u];\n" " uint i2 = indexBuffer.elements[triangleIndex+2u];\n"
"\n" "\n"
" vec2 p0 = vertexBuffer.elements[i0].pos * scaling;\n" " vec2 p0 = vertexBuffer.elements[i0].pos * scaling;\n"
" vec2 p1 = vertexBuffer.elements[i1].pos * scaling;\n" " vec2 p1 = vertexBuffer.elements[i1].pos * scaling;\n"
" vec2 p2 = vertexBuffer.elements[i2].pos * scaling;\n" " vec2 p2 = vertexBuffer.elements[i2].pos * scaling;\n"
"\n" "\n"
" int shapeIndex = vertexBuffer.elements[i0].shapeIndex;\n" " int shapeIndex = vertexBuffer.elements[i0].shapeIndex;\n"
" vec4 clip = shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling);\n" " vec4 clip = shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling);\n"
"\n" "\n"
" vec4 fbox = vec4(max(min(min(p0.x, p1.x), p2.x), clip.x),\n" " vec4 fbox = vec4(max(min(min(p0.x, p1.x), p2.x), clip.x),\n"
" max(min(min(p0.y, p1.y), p2.y), clip.y),\n" " max(min(min(p0.y, p1.y), p2.y), clip.y),\n"
" min(max(max(p0.x, p1.x), p2.x), clip.z),\n" " min(max(max(p0.x, p1.x), p2.x), clip.z),\n"
" min(max(max(p0.y, p1.y), p2.y), clip.w));\n" " min(max(max(p0.y, p1.y), p2.y), clip.w));\n"
"\n" "\n"
" ivec4 box = ivec4(floor(fbox))/int(tileSize);\n" " ivec4 box = ivec4(floor(fbox))/int(tileSize);\n"
"\n" "\n"
" //NOTE(martin): it's importat to do the computation with signed int, so that we can have negative xMax/yMax\n" " //NOTE(martin): it's importat to do the computation with signed int, so that we can have negative xMax/yMax\n"
" // otherwise all triangles on the left or below the x/y axis are attributed to tiles on row/column 0.\n" " // otherwise all triangles on the left or below the x/y axis are attributed to tiles on row/column 0.\n"
" int xMin = max(0, box.x);\n" " int xMin = max(0, box.x);\n"
" int yMin = max(0, box.y);\n" " int yMin = max(0, box.y);\n"
" int xMax = min(box.z, int(tileCount.x) - 1);\n" " int xMax = min(box.z, int(tileCount.x) - 1);\n"
" int yMax = min(box.w, int(tileCount.y) - 1);\n" " int yMax = min(box.w, int(tileCount.y) - 1);\n"
"\n" "\n"
" for(int y = yMin; y <= yMax; y++)\n" " for(int y = yMin; y <= yMax; y++)\n"
" {\n" " {\n"
" for(int x = xMin ; x <= xMax; x++)\n" " for(int x = xMin ; x <= xMax; x++)\n"
" {\n" " {\n"
" uint tileIndex = uint(y)*tileCount.x + uint(x);\n" " uint tileIndex = uint(y)*tileCount.x + uint(x);\n"
" uint tileCounter = atomicAdd(tileCounterBuffer.elements[tileIndex], 1u);\n" " uint tileCounter = atomicAdd(tileCounterBuffer.elements[tileIndex], 1u);\n"
" if(tileCounter < tileArraySize)\n" " if(tileCounter < tileArraySize)\n"
" {\n" " {\n"
" tileArrayBuffer.elements[tileArraySize*tileIndex + tileCounter] = triangleIndex;\n" " tileArrayBuffer.elements[tileArraySize*tileIndex + tileCounter] = triangleIndex;\n"
" }\n" " }\n"
" }\n" " }\n"
" }\n" " }\n"
"}\n"; "}\n";
//NOTE: string imported from src\glsl_shaders\sort.glsl //NOTE: string imported from src\glsl_shaders\sort.glsl
const char* glsl_sort = const char* glsl_sort =
"\n" "\n"
"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n" "\n"
"precision mediump float;\n" "precision mediump float;\n"
"\n" "\n"
"layout(binding = 0) restrict readonly buffer vertexBufferSSBO {\n" "layout(binding = 0) restrict readonly buffer vertexBufferSSBO {\n"
" vertex elements[];\n" " vertex elements[];\n"
"} vertexBuffer ;\n" "} vertexBuffer ;\n"
"\n" "\n"
"layout(binding = 1) restrict readonly buffer shapeBufferSSBO {\n" "layout(binding = 1) restrict readonly buffer shapeBufferSSBO {\n"
" shape elements[];\n" " shape elements[];\n"
"} shapeBuffer ;\n" "} shapeBuffer ;\n"
"\n" "\n"
"layout(binding = 2) restrict readonly buffer indexBufferSSBO {\n" "layout(binding = 2) restrict readonly buffer indexBufferSSBO {\n"
" uint elements[];\n" " uint elements[];\n"
"} indexBuffer ;\n" "} indexBuffer ;\n"
"\n" "\n"
"layout(binding = 3) coherent readonly restrict buffer tileCounterBufferSSBO {\n" "layout(binding = 3) coherent readonly restrict buffer tileCounterBufferSSBO {\n"
" uint elements[];\n" " uint elements[];\n"
"} tileCounterBuffer ;\n" "} tileCounterBuffer ;\n"
"\n" "\n"
"layout(binding = 4) coherent restrict buffer tileArrayBufferSSBO {\n" "layout(binding = 4) coherent restrict buffer tileArrayBufferSSBO {\n"
" uint elements[];\n" " uint elements[];\n"
"} tileArrayBuffer ;\n" "} tileArrayBuffer ;\n"
"\n" "\n"
"layout(location = 0) uniform uint indexCount;\n" "layout(location = 0) uniform uint indexCount;\n"
"layout(location = 1) uniform uvec2 tileCount;\n" "layout(location = 1) uniform uvec2 tileCount;\n"
"layout(location = 2) uniform uint tileSize;\n" "layout(location = 2) uniform uint tileSize;\n"
"layout(location = 3) uniform uint tileArraySize;\n" "layout(location = 3) uniform uint tileArraySize;\n"
"\n" "\n"
"int get_shape_index(uint tileArrayOffset, uint tileArrayIndex)\n" "int get_shape_index(uint tileArrayOffset, uint tileArrayIndex)\n"
"{\n" "{\n"
" uint triangleIndex = tileArrayBuffer.elements[tileArrayOffset + tileArrayIndex];\n" " uint triangleIndex = tileArrayBuffer.elements[tileArrayOffset + tileArrayIndex];\n"
" uint i0 = indexBuffer.elements[triangleIndex];\n" " uint i0 = indexBuffer.elements[triangleIndex];\n"
" int shapeIndex = vertexBuffer.elements[i0].shapeIndex;\n" " int shapeIndex = vertexBuffer.elements[i0].shapeIndex;\n"
" return(shapeIndex);\n" " return(shapeIndex);\n"
"}\n" "}\n"
"\n" "\n"
"void main()\n" "void main()\n"
"{\n" "{\n"
" uint tileIndex = gl_WorkGroupID.x;\n" " uint tileIndex = gl_WorkGroupID.x;\n"
" uint tileArrayOffset = tileArraySize * tileIndex;\n" " uint tileArrayOffset = tileArraySize * tileIndex;\n"
" uint tileArrayCount = min(tileCounterBuffer.elements[tileIndex], tileArraySize);\n" " uint tileArrayCount = min(tileCounterBuffer.elements[tileIndex], tileArraySize);\n"
"\n" "\n"
" for(uint tileArrayIndex=1u; tileArrayIndex < tileArrayCount; tileArrayIndex++)\n" " for(uint tileArrayIndex=1u; tileArrayIndex < tileArrayCount; tileArrayIndex++)\n"
" {\n" " {\n"
" for(uint sortIndex = tileArrayIndex; sortIndex > 0u; sortIndex--)\n" " for(uint sortIndex = tileArrayIndex; sortIndex > 0u; sortIndex--)\n"
" {\n" " {\n"
" int shapeIndex = get_shape_index(tileArrayOffset, sortIndex);\n" " int shapeIndex = get_shape_index(tileArrayOffset, sortIndex);\n"
" int prevShapeIndex = get_shape_index(tileArrayOffset, sortIndex-1u);\n" " int prevShapeIndex = get_shape_index(tileArrayOffset, sortIndex-1u);\n"
"\n" "\n"
" if(shapeIndex >= prevShapeIndex)\n" " if(shapeIndex >= prevShapeIndex)\n"
" {\n" " {\n"
" break;\n" " break;\n"
" }\n" " }\n"
" uint tmp = tileArrayBuffer.elements[tileArrayOffset + sortIndex];\n" " uint tmp = tileArrayBuffer.elements[tileArrayOffset + sortIndex];\n"
" tileArrayBuffer.elements[tileArrayOffset + sortIndex] = tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u];\n" " tileArrayBuffer.elements[tileArrayOffset + sortIndex] = tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u];\n"
" tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u] = tmp;\n" " tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u] = tmp;\n"
" }\n" " }\n"
" }\n" " }\n"
"}\n"; "}\n";
//NOTE: string imported from src\glsl_shaders\draw.glsl //NOTE: string imported from src\glsl_shaders\draw.glsl
const char* glsl_draw = const char* glsl_draw =
"\n" "\n"
"#extension GL_ARB_gpu_shader_int64 : require\n" "#extension GL_ARB_gpu_shader_int64 : require\n"
"layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;\n" "layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;\n"
"\n" "\n"
"precision mediump float;\n" "precision mediump float;\n"
"//precision mediump image2D;\n" "//precision mediump image2D;\n"
"\n" "\n"
"layout(binding = 0) restrict readonly buffer vertexBufferSSBO {\n" "layout(binding = 0) restrict readonly buffer vertexBufferSSBO {\n"
" vertex elements[];\n" " vertex elements[];\n"
"} vertexBuffer ;\n" "} vertexBuffer ;\n"
"\n" "\n"
"layout(binding = 1) restrict readonly buffer shapeBufferSSBO {\n" "layout(binding = 1) restrict readonly buffer shapeBufferSSBO {\n"
" shape elements[];\n" " shape elements[];\n"
"} shapeBuffer ;\n" "} shapeBuffer ;\n"
"\n" "\n"
"layout(binding = 2) restrict readonly buffer indexBufferSSBO {\n" "layout(binding = 2) restrict readonly buffer indexBufferSSBO {\n"
" uint elements[];\n" " uint elements[];\n"
"} indexBuffer ;\n" "} indexBuffer ;\n"
"\n" "\n"
"layout(binding = 3) restrict readonly buffer tileCounterBufferSSBO {\n" "layout(binding = 3) restrict readonly buffer tileCounterBufferSSBO {\n"
" uint elements[];\n" " uint elements[];\n"
"} tileCounterBuffer ;\n" "} tileCounterBuffer ;\n"
"\n" "\n"
"layout(binding = 4) restrict readonly buffer tileArrayBufferSSBO {\n" "layout(binding = 4) restrict readonly buffer tileArrayBufferSSBO {\n"
" uint elements[];\n" " uint elements[];\n"
"} tileArrayBuffer ;\n" "} tileArrayBuffer ;\n"
"\n" "\n"
"layout(location = 0) uniform uint indexCount;\n" "layout(location = 0) uniform uint indexCount;\n"
"layout(location = 1) uniform uvec2 tileCount;\n" "layout(location = 1) uniform uvec2 tileCount;\n"
"layout(location = 2) uniform uint tileSize;\n" "layout(location = 2) uniform uint tileSize;\n"
"layout(location = 3) uniform uint tileArraySize;\n" "layout(location = 3) uniform uint tileArraySize;\n"
"layout(location = 4) uniform vec2 scaling;\n" "layout(location = 4) uniform vec2 scaling;\n"
"layout(location = 5) uniform uint useTexture;\n" "layout(location = 5) uniform uint useTexture;\n"
"\n" "\n"
"layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;\n" "layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;\n"
"\n" "\n"
"layout(binding = 1) uniform sampler2D srcTexture;\n" "layout(binding = 1) uniform sampler2D srcTexture;\n"
"\n" "\n"
"\n" "\n"
"bool is_top_left(ivec2 a, ivec2 b)\n" "bool is_top_left(ivec2 a, ivec2 b)\n"
"{\n" "{\n"
" return( (a.y == b.y && b.x < a.x)\n" " return( (a.y == b.y && b.x < a.x)\n"
" ||(b.y < a.y));\n" " ||(b.y < a.y));\n"
"}\n" "}\n"
"\n" "\n"
"//////////////////////////////////////////////////////////////////////////////\n" "//////////////////////////////////////////////////////////////////////////////\n"
"//TODO: we should do these computations on 64bits, because otherwise\n" "//TODO: we should do these computations on 64bits, because otherwise\n"
"// we might overflow for values > 2048.\n" "// we might overflow for values > 2048.\n"
"// Unfortunately this is costly.\n" "// Unfortunately this is costly.\n"
"// Another way is to precompute triangle edges (b - a) in full precision\n" "// Another way is to precompute triangle edges (b - a) in full precision\n"
"// once to avoid doing it all the time...\n" "// once to avoid doing it all the time...\n"
"//////////////////////////////////////////////////////////////////////////////\n" "//////////////////////////////////////////////////////////////////////////////\n"
"int orient2d(ivec2 a, ivec2 b, ivec2 p)\n" "int orient2d(ivec2 a, ivec2 b, ivec2 p)\n"
"{\n" "{\n"
" return((b.x-a.x)*(p.y-a.y) - (b.y-a.y)*(p.x-a.x));\n" " return((b.x-a.x)*(p.y-a.y) - (b.y-a.y)*(p.x-a.x));\n"
"}\n" "}\n"
"\n" "\n"
"int is_clockwise(ivec2 p0, ivec2 p1, ivec2 p2)\n" "int is_clockwise(ivec2 p0, ivec2 p1, ivec2 p2)\n"
"{\n" "{\n"
" return((p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x);\n" " return((p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x);\n"
"}\n" "}\n"
"\n" "\n"
"void main()\n" "void main()\n"
"{\n" "{\n"
" ivec2 pixelCoord = ivec2(gl_WorkGroupID.xy*uvec2(16, 16) + gl_LocalInvocationID.xy);\n" " ivec2 pixelCoord = ivec2(gl_WorkGroupID.xy*uvec2(16, 16) + gl_LocalInvocationID.xy);\n"
" uvec2 tileCoord = uvec2(pixelCoord) / tileSize;\n" " uvec2 tileCoord = uvec2(pixelCoord) / tileSize;\n"
" uint tileIndex = tileCoord.y * tileCount.x + tileCoord.x;\n" " uint tileIndex = tileCoord.y * tileCount.x + tileCoord.x;\n"
" uint tileCounter = min(tileCounterBuffer.elements[tileIndex], tileArraySize);\n" " uint tileCounter = min(tileCounterBuffer.elements[tileIndex], tileArraySize);\n"
"\n" "\n"
" const float subPixelFactor = 16.;\n" " const float subPixelFactor = 16.;\n"
" ivec2 centerPoint = ivec2((vec2(pixelCoord) + vec2(0.5, 0.5)) * subPixelFactor);\n" " ivec2 centerPoint = ivec2((vec2(pixelCoord) + vec2(0.5, 0.5)) * subPixelFactor);\n"
"\n" "\n"
"//*\n" "//*\n"
" const int sampleCount = 8;\n" " const int sampleCount = 8;\n"
" ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(1, 3),\n" " ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(1, 3),\n"
" centerPoint + ivec2(-1, -3),\n" " centerPoint + ivec2(-1, -3),\n"
" centerPoint + ivec2(5, -1),\n" " centerPoint + ivec2(5, -1),\n"
" centerPoint + ivec2(-3, 5),\n" " centerPoint + ivec2(-3, 5),\n"
" centerPoint + ivec2(-5, -5),\n" " centerPoint + ivec2(-5, -5),\n"
" centerPoint + ivec2(-7, 1),\n" " centerPoint + ivec2(-7, 1),\n"
" centerPoint + ivec2(3, -7),\n" " centerPoint + ivec2(3, -7),\n"
" centerPoint + ivec2(7, 7));\n" " centerPoint + ivec2(7, 7));\n"
"/*/\n" "/*/\n"
" const int sampleCount = 4;\n" " const int sampleCount = 4;\n"
" ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(-2, 6),\n" " ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(-2, 6),\n"
" centerPoint + ivec2(6, 2),\n" " centerPoint + ivec2(6, 2),\n"
" centerPoint + ivec2(-6, -2),\n" " centerPoint + ivec2(-6, -2),\n"
" centerPoint + ivec2(2, -6));\n" " centerPoint + ivec2(2, -6));\n"
"//*/\n" "//*/\n"
" //DEBUG\n" " //DEBUG\n"
"/*\n" "/*\n"
" {\n" " {\n"
" vec4 fragColor = vec4(0);\n" " vec4 fragColor = vec4(0);\n"
"\n" "\n"
" if( pixelCoord.x % 16 == 0\n" " if( pixelCoord.x % 16 == 0\n"
" ||pixelCoord.y % 16 == 0)\n" " ||pixelCoord.y % 16 == 0)\n"
" {\n" " {\n"
" fragColor = vec4(0, 0, 0, 1);\n" " fragColor = vec4(0, 0, 0, 1);\n"
" }\n" " }\n"
" else if(tileCounterBuffer.elements[tileIndex] == 0xffffu)\n" " else if(tileCounterBuffer.elements[tileIndex] == 0xffffu)\n"
" {\n" " {\n"
" fragColor = vec4(1, 0, 1, 1);\n" " fragColor = vec4(1, 0, 1, 1);\n"
" }\n" " }\n"
" else if(tileCounter != 0u)\n" " else if(tileCounter != 0u)\n"
" {\n" " {\n"
" fragColor = vec4(0, 1, 0, 1);\n" " fragColor = vec4(0, 1, 0, 1);\n"
" }\n" " }\n"
" else\n" " else\n"
" {\n" " {\n"
" fragColor = vec4(1, 0, 0, 1);\n" " fragColor = vec4(1, 0, 0, 1);\n"
" }\n" " }\n"
" imageStore(outTexture, pixelCoord, fragColor);\n" " imageStore(outTexture, pixelCoord, fragColor);\n"
" return;\n" " return;\n"
" }\n" " }\n"
"//*/\n" "//*/\n"
" //----\n" " //----\n"
"\n" "\n"
" vec4 sampleColor[sampleCount];\n" " vec4 sampleColor[sampleCount];\n"
" vec4 currentColor[sampleCount];\n" " vec4 currentColor[sampleCount];\n"
" int currentShapeIndex[sampleCount];\n" " int currentShapeIndex[sampleCount];\n"
" int flipCount[sampleCount];\n" " int flipCount[sampleCount];\n"
"\n" "\n"
" for(int i=0; i<sampleCount; i++)\n" " for(int i=0; i<sampleCount; i++)\n"
" {\n" " {\n"
" currentShapeIndex[i] = -1;\n" " currentShapeIndex[i] = -1;\n"
" flipCount[i] = 0;\n" " flipCount[i] = 0;\n"
" sampleColor[i] = vec4(0, 0, 0, 0);\n" " sampleColor[i] = vec4(0, 0, 0, 0);\n"
" currentColor[i] = vec4(0, 0, 0, 0);\n" " currentColor[i] = vec4(0, 0, 0, 0);\n"
" }\n" " }\n"
"\n" "\n"
" for(uint tileArrayIndex=0u; tileArrayIndex < tileCounter; tileArrayIndex++)\n" " for(uint tileArrayIndex=0u; tileArrayIndex < tileCounter; tileArrayIndex++)\n"
" {\n" " {\n"
" uint triangleIndex = tileArrayBuffer.elements[tileArraySize * tileIndex + tileArrayIndex];\n" " uint triangleIndex = tileArrayBuffer.elements[tileArraySize * tileIndex + tileArrayIndex];\n"
"\n" "\n"
" uint i0 = indexBuffer.elements[triangleIndex];\n" " uint i0 = indexBuffer.elements[triangleIndex];\n"
" uint i1 = indexBuffer.elements[triangleIndex+1u];\n" " uint i1 = indexBuffer.elements[triangleIndex+1u];\n"
" uint i2 = indexBuffer.elements[triangleIndex+2u];\n" " uint i2 = indexBuffer.elements[triangleIndex+2u];\n"
"\n" "\n"
" ivec2 p0 = ivec2((vertexBuffer.elements[i0].pos * scaling) * subPixelFactor);\n" " ivec2 p0 = ivec2((vertexBuffer.elements[i0].pos * scaling) * subPixelFactor);\n"
" ivec2 p1 = ivec2((vertexBuffer.elements[i1].pos * scaling) * subPixelFactor);\n" " ivec2 p1 = ivec2((vertexBuffer.elements[i1].pos * scaling) * subPixelFactor);\n"
" ivec2 p2 = ivec2((vertexBuffer.elements[i2].pos * scaling) * subPixelFactor);\n" " ivec2 p2 = ivec2((vertexBuffer.elements[i2].pos * scaling) * subPixelFactor);\n"
"\n" "\n"
" int shapeIndex = vertexBuffer.elements[i0].shapeIndex;\n" " int shapeIndex = vertexBuffer.elements[i0].shapeIndex;\n"
" vec4 color = shapeBuffer.elements[shapeIndex].color;\n" " vec4 color = shapeBuffer.elements[shapeIndex].color;\n"
" color.rgb *= color.a;\n" " color.rgb *= color.a;\n"
"\n" "\n"
" ivec4 clip = ivec4(round((shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling) + vec4(0.5, 0.5, 0.5, 0.5)) * subPixelFactor));\n" " ivec4 clip = ivec4(round((shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling) + vec4(0.5, 0.5, 0.5, 0.5)) * subPixelFactor));\n"
"\n" "\n"
" mat3 uvTransform = mat3(shapeBuffer.elements[shapeIndex].uvTransform[0],\n" " mat3 uvTransform = mat3(shapeBuffer.elements[shapeIndex].uvTransform[0],\n"
" shapeBuffer.elements[shapeIndex].uvTransform[3],\n" " shapeBuffer.elements[shapeIndex].uvTransform[3],\n"
" 0.,\n" " 0.,\n"
" shapeBuffer.elements[shapeIndex].uvTransform[1],\n" " shapeBuffer.elements[shapeIndex].uvTransform[1],\n"
" shapeBuffer.elements[shapeIndex].uvTransform[4],\n" " shapeBuffer.elements[shapeIndex].uvTransform[4],\n"
" 0.,\n" " 0.,\n"
" shapeBuffer.elements[shapeIndex].uvTransform[2],\n" " shapeBuffer.elements[shapeIndex].uvTransform[2],\n"
" shapeBuffer.elements[shapeIndex].uvTransform[5],\n" " shapeBuffer.elements[shapeIndex].uvTransform[5],\n"
" 1.);\n" " 1.);\n"
"\n" "\n"
" //NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge\n" " //NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge\n"
" int cw = is_clockwise(p0, p1, p2);\n" " int cw = is_clockwise(p0, p1, p2);\n"
" if(cw < 0)\n" " if(cw < 0)\n"
" {\n" " {\n"
" uint tmpIndex = i1;\n" " uint tmpIndex = i1;\n"
" i1 = i2;\n" " i1 = i2;\n"
" i2 = tmpIndex;\n" " i2 = tmpIndex;\n"
"\n" "\n"
" ivec2 tmpPoint = p1;\n" " ivec2 tmpPoint = p1;\n"
" p1 = p2;\n" " p1 = p2;\n"
" p2 = tmpPoint;\n" " p2 = tmpPoint;\n"
" }\n" " }\n"
"\n" "\n"
" vec4 cubic0 = vertexBuffer.elements[i0].cubic;\n" " vec4 cubic0 = vertexBuffer.elements[i0].cubic;\n"
" vec4 cubic1 = vertexBuffer.elements[i1].cubic;\n" " vec4 cubic1 = vertexBuffer.elements[i1].cubic;\n"
" vec4 cubic2 = vertexBuffer.elements[i2].cubic;\n" " vec4 cubic2 = vertexBuffer.elements[i2].cubic;\n"
"\n" "\n"
" int bias0 = is_top_left(p1, p2) ? 0 : -1;\n" " int bias0 = is_top_left(p1, p2) ? 0 : -1;\n"
" int bias1 = is_top_left(p2, p0) ? 0 : -1;\n" " int bias1 = is_top_left(p2, p0) ? 0 : -1;\n"
" int bias2 = is_top_left(p0, p1) ? 0 : -1;\n" " int bias2 = is_top_left(p0, p1) ? 0 : -1;\n"
"\n" "\n"
" for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)\n" " for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)\n"
" {\n" " {\n"
" ivec2 samplePoint = samplePoints[sampleIndex];\n" " ivec2 samplePoint = samplePoints[sampleIndex];\n"
"\n" "\n"
" if( samplePoint.x < clip.x\n" " if( samplePoint.x < clip.x\n"
" || samplePoint.x > clip.z\n" " || samplePoint.x > clip.z\n"
" || samplePoint.y < clip.y\n" " || samplePoint.y < clip.y\n"
" || samplePoint.y > clip.w)\n" " || samplePoint.y > clip.w)\n"
" {\n" " {\n"
" continue;\n" " continue;\n"
" }\n" " }\n"
"\n" "\n"
" int w0 = orient2d(p1, p2, samplePoint);\n" " int w0 = orient2d(p1, p2, samplePoint);\n"
" int w1 = orient2d(p2, p0, samplePoint);\n" " int w1 = orient2d(p2, p0, samplePoint);\n"
" int w2 = orient2d(p0, p1, samplePoint);\n" " int w2 = orient2d(p0, p1, samplePoint);\n"
"\n" "\n"
" if((w0+bias0) >= 0 && (w1+bias1) >= 0 && (w2+bias2) >= 0)\n" " if((w0+bias0) >= 0 && (w1+bias1) >= 0 && (w2+bias2) >= 0)\n"
" {\n" " {\n"
" vec4 cubic = (cubic0*float(w0) + cubic1*float(w1) + cubic2*float(w2))/(float(w0)+float(w1)+float(w2));\n" " vec4 cubic = (cubic0*float(w0) + cubic1*float(w1) + cubic2*float(w2))/(float(w0)+float(w1)+float(w2));\n"
"\n" "\n"
" float eps = 0.0001;\n" " float eps = 0.0001;\n"
" if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)\n" " if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)\n"
" {\n" " {\n"
" if(shapeIndex == currentShapeIndex[sampleIndex])\n" " if(shapeIndex == currentShapeIndex[sampleIndex])\n"
" {\n" " {\n"
" flipCount[sampleIndex]++;\n" " flipCount[sampleIndex]++;\n"
" }\n" " }\n"
" else\n" " else\n"
" {\n" " {\n"
" if((flipCount[sampleIndex] & 0x01) != 0)\n" " if((flipCount[sampleIndex] & 0x01) != 0)\n"
" {\n" " {\n"
" sampleColor[sampleIndex] = currentColor[sampleIndex];\n" " sampleColor[sampleIndex] = currentColor[sampleIndex];\n"
" }\n" " }\n"
"\n" "\n"
" vec4 nextColor = color;\n" " vec4 nextColor = color;\n"
" if(useTexture)\n" " if(useTexture)\n"
" {\n" " {\n"
" vec3 sampleFP = vec3(vec2(samplePoint).xy/(subPixelFactor*2.), 1);\n" " vec3 sampleFP = vec3(vec2(samplePoint).xy/(subPixelFactor*2.), 1);\n"
" vec2 uv = (uvTransform * sampleFP).xy;\n" " vec2 uv = (uvTransform * sampleFP).xy;\n"
" vec4 texColor = texture(srcTexture, uv);\n" " vec4 texColor = texture(srcTexture, uv);\n"
" texColor.rgb *= texColor.a;\n" " texColor.rgb *= texColor.a;\n"
" nextColor *= texColor;\n" " nextColor *= texColor;\n"
" }\n" " }\n"
" currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-nextColor.a) + nextColor;\n" " currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-nextColor.a) + nextColor;\n"
" currentShapeIndex[sampleIndex] = shapeIndex;\n" " currentShapeIndex[sampleIndex] = shapeIndex;\n"
" flipCount[sampleIndex] = 1;\n" " flipCount[sampleIndex] = 1;\n"
" }\n" " }\n"
" }\n" " }\n"
" }\n" " }\n"
" }\n" " }\n"
" }\n" " }\n"
" vec4 pixelColor = vec4(0);\n" " vec4 pixelColor = vec4(0);\n"
" for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)\n" " for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)\n"
" {\n" " {\n"
" if((flipCount[sampleIndex] & 0x01) != 0)\n" " if((flipCount[sampleIndex] & 0x01) != 0)\n"
" {\n" " {\n"
" sampleColor[sampleIndex] = currentColor[sampleIndex];\n" " sampleColor[sampleIndex] = currentColor[sampleIndex];\n"
" }\n" " }\n"
" pixelColor += sampleColor[sampleIndex];\n" " pixelColor += sampleColor[sampleIndex];\n"
" }\n" " }\n"
"\n" "\n"
" imageStore(outTexture, pixelCoord, pixelColor/float(sampleCount));\n" " imageStore(outTexture, pixelCoord, pixelColor/float(sampleCount));\n"
"}\n"; "}\n";
#endif // __GLSL_SHADERS_H__ #endif // __GLSL_SHADERS_H__

View File

@ -1,12 +1,12 @@
precision mediump float; precision mediump float;
in vec2 uv; in vec2 uv;
out vec4 fragColor; out vec4 fragColor;
layout(location=0) uniform sampler2D tex; layout(location=0) uniform sampler2D tex;
void main() void main()
{ {
fragColor = texture(tex, uv); fragColor = texture(tex, uv);
} }

View File

@ -1,13 +1,13 @@
precision mediump float; precision mediump float;
out vec2 uv; out vec2 uv;
void main() void main()
{ {
float x = float(((uint(gl_VertexID) + 2u) / 3u)%2u); float x = float(((uint(gl_VertexID) + 2u) / 3u)%2u);
float y = float(((uint(gl_VertexID) + 1u) / 3u)%2u); float y = float(((uint(gl_VertexID) + 1u) / 3u)%2u);
gl_Position = vec4(-1.0f + x*2.0f, -1.0f+y*2.0f, 0.0f, 1.0f); gl_Position = vec4(-1.0f + x*2.0f, -1.0f+y*2.0f, 0.0f, 1.0f);
uv = vec2(x, y); uv = vec2(x, y);
} }

View File

@ -1,15 +1,15 @@
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
precision mediump float; precision mediump float;
layout(std430) buffer; layout(std430) buffer;
layout(binding = 0) coherent restrict writeonly buffer tileCounterBufferSSBO { layout(binding = 0) coherent restrict writeonly buffer tileCounterBufferSSBO {
uint elements[]; uint elements[];
} tileCounterBuffer ; } tileCounterBuffer ;
void main() void main()
{ {
uint tileIndex = gl_WorkGroupID.x; uint tileIndex = gl_WorkGroupID.x;
tileCounterBuffer.elements[tileIndex] = 0u; tileCounterBuffer.elements[tileIndex] = 0u;
} }

View File

@ -1,14 +1,14 @@
layout(std430) buffer; layout(std430) buffer;
struct vertex { struct vertex {
vec4 cubic; vec4 cubic;
vec2 pos; vec2 pos;
int shapeIndex; int shapeIndex;
}; };
struct shape { struct shape {
vec4 color; vec4 color;
vec4 clip; vec4 clip;
float uvTransform[6]; float uvTransform[6];
}; };

View File

@ -1,242 +1,242 @@
#extension GL_ARB_gpu_shader_int64 : require #extension GL_ARB_gpu_shader_int64 : require
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
precision mediump float; precision mediump float;
//precision mediump image2D; //precision mediump image2D;
layout(binding = 0) restrict readonly buffer vertexBufferSSBO { layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
vertex elements[]; vertex elements[];
} vertexBuffer ; } vertexBuffer ;
layout(binding = 1) restrict readonly buffer shapeBufferSSBO { layout(binding = 1) restrict readonly buffer shapeBufferSSBO {
shape elements[]; shape elements[];
} shapeBuffer ; } shapeBuffer ;
layout(binding = 2) restrict readonly buffer indexBufferSSBO { layout(binding = 2) restrict readonly buffer indexBufferSSBO {
uint elements[]; uint elements[];
} indexBuffer ; } indexBuffer ;
layout(binding = 3) restrict readonly buffer tileCounterBufferSSBO { layout(binding = 3) restrict readonly buffer tileCounterBufferSSBO {
uint elements[]; uint elements[];
} tileCounterBuffer ; } tileCounterBuffer ;
layout(binding = 4) restrict readonly buffer tileArrayBufferSSBO { layout(binding = 4) restrict readonly buffer tileArrayBufferSSBO {
uint elements[]; uint elements[];
} tileArrayBuffer ; } tileArrayBuffer ;
layout(location = 0) uniform uint indexCount; layout(location = 0) uniform uint indexCount;
layout(location = 1) uniform uvec2 tileCount; layout(location = 1) uniform uvec2 tileCount;
layout(location = 2) uniform uint tileSize; layout(location = 2) uniform uint tileSize;
layout(location = 3) uniform uint tileArraySize; layout(location = 3) uniform uint tileArraySize;
layout(location = 4) uniform vec2 scaling; layout(location = 4) uniform vec2 scaling;
layout(location = 5) uniform uint useTexture; layout(location = 5) uniform uint useTexture;
layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture; layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;
layout(binding = 1) uniform sampler2D srcTexture; layout(binding = 1) uniform sampler2D srcTexture;
bool is_top_left(ivec2 a, ivec2 b) bool is_top_left(ivec2 a, ivec2 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));
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
//TODO: we should do these computations on 64bits, because otherwise //TODO: we should do these computations on 64bits, because otherwise
// we might overflow for values > 2048. // we might overflow for values > 2048.
// Unfortunately this is costly. // Unfortunately this is costly.
// Another way is to precompute triangle edges (b - a) in full precision // Another way is to precompute triangle edges (b - a) in full precision
// once to avoid doing it all the time... // once to avoid doing it all the time...
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
int orient2d(ivec2 a, ivec2 b, ivec2 p) int orient2d(ivec2 a, ivec2 b, ivec2 p)
{ {
return((b.x-a.x)*(p.y-a.y) - (b.y-a.y)*(p.x-a.x)); return((b.x-a.x)*(p.y-a.y) - (b.y-a.y)*(p.x-a.x));
} }
int is_clockwise(ivec2 p0, ivec2 p1, ivec2 p2) int is_clockwise(ivec2 p0, ivec2 p1, ivec2 p2)
{ {
return((p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x); return((p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x);
} }
void main() void main()
{ {
ivec2 pixelCoord = ivec2(gl_WorkGroupID.xy*uvec2(16, 16) + gl_LocalInvocationID.xy); ivec2 pixelCoord = ivec2(gl_WorkGroupID.xy*uvec2(16, 16) + gl_LocalInvocationID.xy);
uvec2 tileCoord = uvec2(pixelCoord) / tileSize; uvec2 tileCoord = uvec2(pixelCoord) / tileSize;
uint tileIndex = tileCoord.y * tileCount.x + tileCoord.x; uint tileIndex = tileCoord.y * tileCount.x + tileCoord.x;
uint tileCounter = min(tileCounterBuffer.elements[tileIndex], tileArraySize); uint tileCounter = min(tileCounterBuffer.elements[tileIndex], tileArraySize);
const float subPixelFactor = 16.; const float subPixelFactor = 16.;
ivec2 centerPoint = ivec2((vec2(pixelCoord) + vec2(0.5, 0.5)) * subPixelFactor); ivec2 centerPoint = ivec2((vec2(pixelCoord) + vec2(0.5, 0.5)) * subPixelFactor);
//* //*
const int sampleCount = 8; const int sampleCount = 8;
ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(1, 3), ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(1, 3),
centerPoint + ivec2(-1, -3), centerPoint + ivec2(-1, -3),
centerPoint + ivec2(5, -1), centerPoint + ivec2(5, -1),
centerPoint + ivec2(-3, 5), centerPoint + ivec2(-3, 5),
centerPoint + ivec2(-5, -5), centerPoint + ivec2(-5, -5),
centerPoint + ivec2(-7, 1), centerPoint + ivec2(-7, 1),
centerPoint + ivec2(3, -7), centerPoint + ivec2(3, -7),
centerPoint + ivec2(7, 7)); centerPoint + ivec2(7, 7));
/*/ /*/
const int sampleCount = 4; const int sampleCount = 4;
ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(-2, 6), ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(-2, 6),
centerPoint + ivec2(6, 2), centerPoint + ivec2(6, 2),
centerPoint + ivec2(-6, -2), centerPoint + ivec2(-6, -2),
centerPoint + ivec2(2, -6)); centerPoint + ivec2(2, -6));
//*/ //*/
//DEBUG //DEBUG
/* /*
{ {
vec4 fragColor = vec4(0); vec4 fragColor = vec4(0);
if( pixelCoord.x % 16 == 0 if( pixelCoord.x % 16 == 0
||pixelCoord.y % 16 == 0) ||pixelCoord.y % 16 == 0)
{ {
fragColor = vec4(0, 0, 0, 1); fragColor = vec4(0, 0, 0, 1);
} }
else if(tileCounterBuffer.elements[tileIndex] == 0xffffu) else if(tileCounterBuffer.elements[tileIndex] == 0xffffu)
{ {
fragColor = vec4(1, 0, 1, 1); fragColor = vec4(1, 0, 1, 1);
} }
else if(tileCounter != 0u) else if(tileCounter != 0u)
{ {
fragColor = vec4(0, 1, 0, 1); fragColor = vec4(0, 1, 0, 1);
} }
else else
{ {
fragColor = vec4(1, 0, 0, 1); fragColor = vec4(1, 0, 0, 1);
} }
imageStore(outTexture, pixelCoord, fragColor); imageStore(outTexture, pixelCoord, fragColor);
return; return;
} }
//*/ //*/
//---- //----
vec4 sampleColor[sampleCount]; vec4 sampleColor[sampleCount];
vec4 currentColor[sampleCount]; vec4 currentColor[sampleCount];
int currentShapeIndex[sampleCount]; int currentShapeIndex[sampleCount];
int flipCount[sampleCount]; int flipCount[sampleCount];
for(int i=0; i<sampleCount; i++) for(int i=0; i<sampleCount; i++)
{ {
currentShapeIndex[i] = -1; currentShapeIndex[i] = -1;
flipCount[i] = 0; flipCount[i] = 0;
sampleColor[i] = vec4(0, 0, 0, 0); sampleColor[i] = vec4(0, 0, 0, 0);
currentColor[i] = vec4(0, 0, 0, 0); currentColor[i] = vec4(0, 0, 0, 0);
} }
for(uint tileArrayIndex=0u; tileArrayIndex < tileCounter; tileArrayIndex++) for(uint tileArrayIndex=0u; tileArrayIndex < tileCounter; tileArrayIndex++)
{ {
uint triangleIndex = tileArrayBuffer.elements[tileArraySize * tileIndex + tileArrayIndex]; uint triangleIndex = tileArrayBuffer.elements[tileArraySize * tileIndex + tileArrayIndex];
uint i0 = indexBuffer.elements[triangleIndex]; uint i0 = indexBuffer.elements[triangleIndex];
uint i1 = indexBuffer.elements[triangleIndex+1u]; uint i1 = indexBuffer.elements[triangleIndex+1u];
uint i2 = indexBuffer.elements[triangleIndex+2u]; uint i2 = indexBuffer.elements[triangleIndex+2u];
ivec2 p0 = ivec2((vertexBuffer.elements[i0].pos * scaling) * subPixelFactor); ivec2 p0 = ivec2((vertexBuffer.elements[i0].pos * scaling) * subPixelFactor);
ivec2 p1 = ivec2((vertexBuffer.elements[i1].pos * scaling) * subPixelFactor); ivec2 p1 = ivec2((vertexBuffer.elements[i1].pos * scaling) * subPixelFactor);
ivec2 p2 = ivec2((vertexBuffer.elements[i2].pos * scaling) * subPixelFactor); ivec2 p2 = ivec2((vertexBuffer.elements[i2].pos * scaling) * subPixelFactor);
int shapeIndex = vertexBuffer.elements[i0].shapeIndex; int shapeIndex = vertexBuffer.elements[i0].shapeIndex;
vec4 color = shapeBuffer.elements[shapeIndex].color; vec4 color = shapeBuffer.elements[shapeIndex].color;
color.rgb *= color.a; color.rgb *= color.a;
ivec4 clip = ivec4(round((shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling) + vec4(0.5, 0.5, 0.5, 0.5)) * subPixelFactor)); ivec4 clip = ivec4(round((shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling) + vec4(0.5, 0.5, 0.5, 0.5)) * subPixelFactor));
mat3 uvTransform = mat3(shapeBuffer.elements[shapeIndex].uvTransform[0], mat3 uvTransform = mat3(shapeBuffer.elements[shapeIndex].uvTransform[0],
shapeBuffer.elements[shapeIndex].uvTransform[3], shapeBuffer.elements[shapeIndex].uvTransform[3],
0., 0.,
shapeBuffer.elements[shapeIndex].uvTransform[1], shapeBuffer.elements[shapeIndex].uvTransform[1],
shapeBuffer.elements[shapeIndex].uvTransform[4], shapeBuffer.elements[shapeIndex].uvTransform[4],
0., 0.,
shapeBuffer.elements[shapeIndex].uvTransform[2], shapeBuffer.elements[shapeIndex].uvTransform[2],
shapeBuffer.elements[shapeIndex].uvTransform[5], shapeBuffer.elements[shapeIndex].uvTransform[5],
1.); 1.);
//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge //NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
int cw = is_clockwise(p0, p1, p2); int cw = is_clockwise(p0, p1, p2);
if(cw < 0) if(cw < 0)
{ {
uint tmpIndex = i1; uint tmpIndex = i1;
i1 = i2; i1 = i2;
i2 = tmpIndex; i2 = tmpIndex;
ivec2 tmpPoint = p1; ivec2 tmpPoint = p1;
p1 = p2; p1 = p2;
p2 = tmpPoint; p2 = tmpPoint;
} }
vec4 cubic0 = vertexBuffer.elements[i0].cubic; vec4 cubic0 = vertexBuffer.elements[i0].cubic;
vec4 cubic1 = vertexBuffer.elements[i1].cubic; vec4 cubic1 = vertexBuffer.elements[i1].cubic;
vec4 cubic2 = vertexBuffer.elements[i2].cubic; vec4 cubic2 = vertexBuffer.elements[i2].cubic;
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;
for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)
{ {
ivec2 samplePoint = samplePoints[sampleIndex]; ivec2 samplePoint = samplePoints[sampleIndex];
if( samplePoint.x < clip.x if( samplePoint.x < clip.x
|| samplePoint.x > clip.z || samplePoint.x > clip.z
|| samplePoint.y < clip.y || samplePoint.y < clip.y
|| samplePoint.y > clip.w) || samplePoint.y > clip.w)
{ {
continue; continue;
} }
int w0 = orient2d(p1, p2, samplePoint); int w0 = orient2d(p1, p2, samplePoint);
int w1 = orient2d(p2, p0, samplePoint); int w1 = orient2d(p2, p0, samplePoint);
int w2 = orient2d(p0, p1, samplePoint); int w2 = orient2d(p0, p1, samplePoint);
if((w0+bias0) >= 0 && (w1+bias1) >= 0 && (w2+bias2) >= 0) if((w0+bias0) >= 0 && (w1+bias1) >= 0 && (w2+bias2) >= 0)
{ {
vec4 cubic = (cubic0*float(w0) + cubic1*float(w1) + cubic2*float(w2))/(float(w0)+float(w1)+float(w2)); vec4 cubic = (cubic0*float(w0) + cubic1*float(w1) + cubic2*float(w2))/(float(w0)+float(w1)+float(w2));
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(shapeIndex == currentShapeIndex[sampleIndex]) if(shapeIndex == currentShapeIndex[sampleIndex])
{ {
flipCount[sampleIndex]++; flipCount[sampleIndex]++;
} }
else else
{ {
if((flipCount[sampleIndex] & 0x01) != 0) if((flipCount[sampleIndex] & 0x01) != 0)
{ {
sampleColor[sampleIndex] = currentColor[sampleIndex]; sampleColor[sampleIndex] = currentColor[sampleIndex];
} }
vec4 nextColor = color; vec4 nextColor = color;
if(useTexture) if(useTexture)
{ {
vec3 sampleFP = vec3(vec2(samplePoint).xy/(subPixelFactor*2.), 1); vec3 sampleFP = vec3(vec2(samplePoint).xy/(subPixelFactor*2.), 1);
vec2 uv = (uvTransform * sampleFP).xy; vec2 uv = (uvTransform * sampleFP).xy;
vec4 texColor = texture(srcTexture, uv); vec4 texColor = texture(srcTexture, uv);
texColor.rgb *= texColor.a; texColor.rgb *= texColor.a;
nextColor *= texColor; nextColor *= texColor;
} }
currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-nextColor.a) + nextColor; currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-nextColor.a) + nextColor;
currentShapeIndex[sampleIndex] = shapeIndex; currentShapeIndex[sampleIndex] = shapeIndex;
flipCount[sampleIndex] = 1; flipCount[sampleIndex] = 1;
} }
} }
} }
} }
} }
vec4 pixelColor = vec4(0); vec4 pixelColor = vec4(0);
for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)
{ {
if((flipCount[sampleIndex] & 0x01) != 0) if((flipCount[sampleIndex] & 0x01) != 0)
{ {
sampleColor[sampleIndex] = currentColor[sampleIndex]; sampleColor[sampleIndex] = currentColor[sampleIndex];
} }
pixelColor += sampleColor[sampleIndex]; pixelColor += sampleColor[sampleIndex];
} }
imageStore(outTexture, pixelCoord, pixelColor/float(sampleCount)); imageStore(outTexture, pixelCoord, pixelColor/float(sampleCount));
} }

View File

@ -1,61 +1,61 @@
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
precision mediump float; precision mediump float;
layout(binding = 0) restrict readonly buffer vertexBufferSSBO { layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
vertex elements[]; vertex elements[];
} vertexBuffer ; } vertexBuffer ;
layout(binding = 1) restrict readonly buffer shapeBufferSSBO { layout(binding = 1) restrict readonly buffer shapeBufferSSBO {
shape elements[]; shape elements[];
} shapeBuffer ; } shapeBuffer ;
layout(binding = 2) restrict readonly buffer indexBufferSSBO { layout(binding = 2) restrict readonly buffer indexBufferSSBO {
uint elements[]; uint elements[];
} indexBuffer ; } indexBuffer ;
layout(binding = 3) coherent readonly restrict buffer tileCounterBufferSSBO { layout(binding = 3) coherent readonly restrict buffer tileCounterBufferSSBO {
uint elements[]; uint elements[];
} tileCounterBuffer ; } tileCounterBuffer ;
layout(binding = 4) coherent restrict buffer tileArrayBufferSSBO { layout(binding = 4) coherent restrict buffer tileArrayBufferSSBO {
uint elements[]; uint elements[];
} tileArrayBuffer ; } tileArrayBuffer ;
layout(location = 0) uniform uint indexCount; layout(location = 0) uniform uint indexCount;
layout(location = 1) uniform uvec2 tileCount; layout(location = 1) uniform uvec2 tileCount;
layout(location = 2) uniform uint tileSize; layout(location = 2) uniform uint tileSize;
layout(location = 3) uniform uint tileArraySize; layout(location = 3) uniform uint tileArraySize;
int get_shape_index(uint tileArrayOffset, uint tileArrayIndex) int get_shape_index(uint tileArrayOffset, uint tileArrayIndex)
{ {
uint triangleIndex = tileArrayBuffer.elements[tileArrayOffset + tileArrayIndex]; uint triangleIndex = tileArrayBuffer.elements[tileArrayOffset + tileArrayIndex];
uint i0 = indexBuffer.elements[triangleIndex]; uint i0 = indexBuffer.elements[triangleIndex];
int shapeIndex = vertexBuffer.elements[i0].shapeIndex; int shapeIndex = vertexBuffer.elements[i0].shapeIndex;
return(shapeIndex); return(shapeIndex);
} }
void main() void main()
{ {
uint tileIndex = gl_WorkGroupID.x; uint tileIndex = gl_WorkGroupID.x;
uint tileArrayOffset = tileArraySize * tileIndex; uint tileArrayOffset = tileArraySize * tileIndex;
uint tileArrayCount = min(tileCounterBuffer.elements[tileIndex], tileArraySize); uint tileArrayCount = min(tileCounterBuffer.elements[tileIndex], tileArraySize);
for(uint tileArrayIndex=1u; tileArrayIndex < tileArrayCount; tileArrayIndex++) for(uint tileArrayIndex=1u; tileArrayIndex < tileArrayCount; tileArrayIndex++)
{ {
for(uint sortIndex = tileArrayIndex; sortIndex > 0u; sortIndex--) for(uint sortIndex = tileArrayIndex; sortIndex > 0u; sortIndex--)
{ {
int shapeIndex = get_shape_index(tileArrayOffset, sortIndex); int shapeIndex = get_shape_index(tileArrayOffset, sortIndex);
int prevShapeIndex = get_shape_index(tileArrayOffset, sortIndex-1u); int prevShapeIndex = get_shape_index(tileArrayOffset, sortIndex-1u);
if(shapeIndex >= prevShapeIndex) if(shapeIndex >= prevShapeIndex)
{ {
break; break;
} }
uint tmp = tileArrayBuffer.elements[tileArrayOffset + sortIndex]; uint tmp = tileArrayBuffer.elements[tileArrayOffset + sortIndex];
tileArrayBuffer.elements[tileArrayOffset + sortIndex] = tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u]; tileArrayBuffer.elements[tileArrayOffset + sortIndex] = tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u];
tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u] = tmp; tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u] = tmp;
} }
} }
} }

View File

@ -1,77 +1,77 @@
layout(local_size_x = 512, local_size_y = 1, local_size_z = 1) in; layout(local_size_x = 512, local_size_y = 1, local_size_z = 1) in;
precision mediump float; precision mediump float;
layout(binding = 0) restrict readonly buffer vertexBufferSSBO { layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
vertex elements[]; vertex elements[];
} vertexBuffer ; } vertexBuffer ;
layout(binding = 1) restrict readonly buffer shapeBufferSSBO { layout(binding = 1) restrict readonly buffer shapeBufferSSBO {
shape elements[]; shape elements[];
} shapeBuffer ; } shapeBuffer ;
layout(binding = 2) restrict readonly buffer indexBufferSSBO { layout(binding = 2) restrict readonly buffer indexBufferSSBO {
uint elements[]; uint elements[];
} indexBuffer ; } indexBuffer ;
layout(binding = 3) coherent restrict buffer tileCounterBufferSSBO { layout(binding = 3) coherent restrict buffer tileCounterBufferSSBO {
uint elements[]; uint elements[];
} tileCounterBuffer ; } tileCounterBuffer ;
layout(binding = 4) coherent restrict writeonly buffer tileArrayBufferSSBO { layout(binding = 4) coherent restrict writeonly buffer tileArrayBufferSSBO {
uint elements[]; uint elements[];
} tileArrayBuffer ; } tileArrayBuffer ;
layout(location = 0) uniform uint indexCount; layout(location = 0) uniform uint indexCount;
layout(location = 1) uniform uvec2 tileCount; layout(location = 1) uniform uvec2 tileCount;
layout(location = 2) uniform uint tileSize; layout(location = 2) uniform uint tileSize;
layout(location = 3) uniform uint tileArraySize; layout(location = 3) uniform uint tileArraySize;
layout(location = 4) uniform vec2 scaling; layout(location = 4) uniform vec2 scaling;
void main() void main()
{ {
uint triangleIndex = (gl_WorkGroupID.x*gl_WorkGroupSize.x + gl_LocalInvocationIndex) * 3u; uint triangleIndex = (gl_WorkGroupID.x*gl_WorkGroupSize.x + gl_LocalInvocationIndex) * 3u;
if(triangleIndex >= indexCount) if(triangleIndex >= indexCount)
{ {
return; return;
} }
uint i0 = indexBuffer.elements[triangleIndex]; uint i0 = indexBuffer.elements[triangleIndex];
uint i1 = indexBuffer.elements[triangleIndex+1u]; uint i1 = indexBuffer.elements[triangleIndex+1u];
uint i2 = indexBuffer.elements[triangleIndex+2u]; uint i2 = indexBuffer.elements[triangleIndex+2u];
vec2 p0 = vertexBuffer.elements[i0].pos * scaling; vec2 p0 = vertexBuffer.elements[i0].pos * scaling;
vec2 p1 = vertexBuffer.elements[i1].pos * scaling; vec2 p1 = vertexBuffer.elements[i1].pos * scaling;
vec2 p2 = vertexBuffer.elements[i2].pos * scaling; vec2 p2 = vertexBuffer.elements[i2].pos * scaling;
int shapeIndex = vertexBuffer.elements[i0].shapeIndex; int shapeIndex = vertexBuffer.elements[i0].shapeIndex;
vec4 clip = shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling); vec4 clip = shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling);
vec4 fbox = vec4(max(min(min(p0.x, p1.x), p2.x), clip.x), vec4 fbox = vec4(max(min(min(p0.x, p1.x), p2.x), clip.x),
max(min(min(p0.y, p1.y), p2.y), clip.y), max(min(min(p0.y, p1.y), p2.y), clip.y),
min(max(max(p0.x, p1.x), p2.x), clip.z), min(max(max(p0.x, p1.x), p2.x), clip.z),
min(max(max(p0.y, p1.y), p2.y), clip.w)); min(max(max(p0.y, p1.y), p2.y), clip.w));
ivec4 box = ivec4(floor(fbox))/int(tileSize); ivec4 box = ivec4(floor(fbox))/int(tileSize);
//NOTE(martin): it's importat to do the computation with signed int, so that we can have negative xMax/yMax //NOTE(martin): it's importat to do the computation with signed int, so that we can have negative xMax/yMax
// otherwise all triangles on the left or below the x/y axis are attributed to tiles on row/column 0. // otherwise all triangles on the left or below the x/y axis are attributed to tiles on row/column 0.
int xMin = max(0, box.x); int xMin = max(0, box.x);
int yMin = max(0, box.y); int yMin = max(0, box.y);
int xMax = min(box.z, int(tileCount.x) - 1); int xMax = min(box.z, int(tileCount.x) - 1);
int yMax = min(box.w, int(tileCount.y) - 1); int yMax = min(box.w, int(tileCount.y) - 1);
for(int y = yMin; y <= yMax; y++) for(int y = yMin; y <= yMax; y++)
{ {
for(int x = xMin ; x <= xMax; x++) for(int x = xMin ; x <= xMax; x++)
{ {
uint tileIndex = uint(y)*tileCount.x + uint(x); uint tileIndex = uint(y)*tileCount.x + uint(x);
uint tileCounter = atomicAdd(tileCounterBuffer.elements[tileIndex], 1u); uint tileCounter = atomicAdd(tileCounterBuffer.elements[tileIndex], 1u);
if(tileCounter < tileArraySize) if(tileCounter < tileArraySize)
{ {
tileArrayBuffer.elements[tileArraySize*tileIndex + tileCounter] = triangleIndex; tileArrayBuffer.elements[tileArraySize*tileIndex + tileCounter] = triangleIndex;
} }
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,323 +1,323 @@
/************************************************************//** /************************************************************//**
* *
* @file: graphics.h * @file: graphics.h
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 23/01/2023 * @date: 23/01/2023
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#ifndef __GRAPHICS_H_ #ifndef __GRAPHICS_H_
#define __GRAPHICS_H_ #define __GRAPHICS_H_
#include"typedefs.h" #include"typedefs.h"
#include"platform.h" #include"platform.h"
#include"mp_app.h" #include"mp_app.h"
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE(martin): backends selection //NOTE(martin): backends selection
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
typedef enum { typedef enum {
MG_BACKEND_NONE, MG_BACKEND_NONE,
MG_BACKEND_METAL, MG_BACKEND_METAL,
MG_BACKEND_GL, MG_BACKEND_GL,
MG_BACKEND_GLES, MG_BACKEND_GLES,
MG_BACKEND_HOST } mg_backend_id; MG_BACKEND_HOST } mg_backend_id;
//NOTE: these macros are used to select which backend to include when building milepost //NOTE: these macros are used to select which backend to include when building milepost
// they can be overridden by passing them to the compiler command line // they can be overridden by passing them to the compiler command line
#if defined(OS_MACOS) #if defined(OS_MACOS)
#ifndef MG_COMPILE_BACKEND_METAL #ifndef MG_COMPILE_BACKEND_METAL
#define MG_COMPILE_BACKEND_METAL 1 #define MG_COMPILE_BACKEND_METAL 1
#endif #endif
#ifndef MG_COMPILE_BACKEND_GLES #ifndef MG_COMPILE_BACKEND_GLES
#define MG_COMPILE_BACKEND_GLES 1 #define MG_COMPILE_BACKEND_GLES 1
#endif #endif
#define MG_COMPILE_BACKEND_GL 0 #define MG_COMPILE_BACKEND_GL 0
#if MG_COMPILE_BACKEND_METAL #if MG_COMPILE_BACKEND_METAL
#define MG_BACKEND_DEFAULT MG_BACKEND_METAL #define MG_BACKEND_DEFAULT MG_BACKEND_METAL
#elif MG_COMPILE_BACKEND_GL #elif MG_COMPILE_BACKEND_GL
#define MG_BACKEND_DEFAULT MG_BACKEND_GL #define MG_BACKEND_DEFAULT MG_BACKEND_GL
#else #else
#define MG_BACKEND_DEFAULT MG_BACKEND_NONE #define MG_BACKEND_DEFAULT MG_BACKEND_NONE
#endif #endif
#elif defined(OS_WIN64) #elif defined(OS_WIN64)
#ifndef MG_COMPILE_BACKEND_GL #ifndef MG_COMPILE_BACKEND_GL
#define MG_COMPILE_BACKEND_GL 1 #define MG_COMPILE_BACKEND_GL 1
#endif #endif
#ifndef MG_COMPILE_BACKEND_GLES #ifndef MG_COMPILE_BACKEND_GLES
#define MG_COMPILE_BACKEND_GLES 1 #define MG_COMPILE_BACKEND_GLES 1
#endif #endif
#if MG_COMPILE_BACKEND_GL #if MG_COMPILE_BACKEND_GL
#define MG_BACKEND_DEFAULT MG_BACKEND_GL #define MG_BACKEND_DEFAULT MG_BACKEND_GL
#else #else
#define MG_BACKEND_DEFAULT MG_BACKEND_NONE #define MG_BACKEND_DEFAULT MG_BACKEND_NONE
#endif #endif
#elif defined(OS_LINUX) #elif defined(OS_LINUX)
#ifndef MG_COMPILE_BACKEND_GL #ifndef MG_COMPILE_BACKEND_GL
#define MG_COMPILE_BACKEND_GL 1 #define MG_COMPILE_BACKEND_GL 1
#endif #endif
#endif #endif
//NOTE: these macros are used to select backend-specific APIs to include when using milepost //NOTE: these macros are used to select backend-specific APIs to include when using milepost
#ifdef MG_EXPOSE_SURFACE_METAL #ifdef MG_EXPOSE_SURFACE_METAL
#include"mtl_surface.h" #include"mtl_surface.h"
#endif #endif
#ifdef MG_EXPOSE_SURFACE_WGL #ifdef MG_EXPOSE_SURFACE_WGL
#include"wgl_surface.h" #include"wgl_surface.h"
#endif #endif
//TODO: expose nsgl surface when supported, expose egl surface, etc... //TODO: expose nsgl surface when supported, expose egl surface, etc...
//TODO: add MG_INCLUDE_OPENGL/GLES/etc, once we know how we make different gl versions co-exist //TODO: add MG_INCLUDE_OPENGL/GLES/etc, once we know how we make different gl versions co-exist
MP_API bool mg_is_surface_backend_available(mg_backend_id id); MP_API bool mg_is_surface_backend_available(mg_backend_id id);
MP_API bool mg_is_canvas_backend_available(mg_backend_id id); MP_API bool mg_is_canvas_backend_available(mg_backend_id id);
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE(martin): graphics surface //NOTE(martin): graphics surface
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
typedef struct mg_surface { u64 h; } mg_surface; typedef struct mg_surface { u64 h; } mg_surface;
MP_API mg_surface mg_surface_nil(); MP_API mg_surface mg_surface_nil();
MP_API bool mg_surface_is_nil(mg_surface surface); MP_API bool mg_surface_is_nil(mg_surface surface);
MP_API mg_surface mg_surface_create_for_window(mp_window window, mg_backend_id backend); MP_API mg_surface mg_surface_create_for_window(mp_window window, mg_backend_id backend);
MP_API void mg_surface_destroy(mg_surface surface); MP_API void mg_surface_destroy(mg_surface surface);
MP_API void mg_surface_prepare(mg_surface surface); MP_API void mg_surface_prepare(mg_surface surface);
MP_API void mg_surface_present(mg_surface surface); MP_API void mg_surface_present(mg_surface surface);
MP_API void mg_surface_swap_interval(mg_surface surface, int swap); MP_API void mg_surface_swap_interval(mg_surface surface, int swap);
MP_API vec2 mg_surface_contents_scaling(mg_surface surface); MP_API vec2 mg_surface_contents_scaling(mg_surface surface);
MP_API mp_rect mg_surface_get_frame(mg_surface surface); MP_API mp_rect mg_surface_get_frame(mg_surface surface);
MP_API void mg_surface_set_frame(mg_surface surface, mp_rect frame); MP_API void mg_surface_set_frame(mg_surface surface, mp_rect frame);
MP_API bool mg_surface_get_hidden(mg_surface surface); MP_API bool mg_surface_get_hidden(mg_surface surface);
MP_API void mg_surface_set_hidden(mg_surface surface, bool hidden); MP_API void mg_surface_set_hidden(mg_surface surface, bool hidden);
//NOTE(martin): surface sharing //NOTE(martin): surface sharing
typedef u64 mg_surface_id; typedef u64 mg_surface_id;
MP_API mg_surface mg_surface_create_remote(u32 width, u32 height, mg_backend_id backend); MP_API mg_surface mg_surface_create_remote(u32 width, u32 height, mg_backend_id backend);
MP_API mg_surface mg_surface_create_host(mp_window window); MP_API mg_surface mg_surface_create_host(mp_window window);
MP_API mg_surface_id mg_surface_remote_id(mg_surface surface); MP_API mg_surface_id mg_surface_remote_id(mg_surface surface);
MP_API void mg_surface_host_connect(mg_surface surface, mg_surface_id remoteId); MP_API void mg_surface_host_connect(mg_surface surface, mg_surface_id remoteId);
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE(martin): graphics canvas structs //NOTE(martin): graphics canvas structs
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
typedef struct mg_canvas { u64 h; } mg_canvas; typedef struct mg_canvas { u64 h; } mg_canvas;
typedef struct mg_font { u64 h; } mg_font; typedef struct mg_font { u64 h; } mg_font;
typedef struct mg_image { u64 h; } mg_image; typedef struct mg_image { u64 h; } mg_image;
typedef struct mg_mat2x3 typedef struct mg_mat2x3
{ {
f32 m[6]; f32 m[6];
} mg_mat2x3; } mg_mat2x3;
typedef struct mg_color typedef struct mg_color
{ {
union union
{ {
struct struct
{ {
f32 r; f32 r;
f32 g; f32 g;
f32 b; f32 b;
f32 a; f32 a;
}; };
f32 c[4]; f32 c[4];
}; };
} mg_color; } mg_color;
typedef enum {MG_JOINT_MITER = 0, typedef enum {MG_JOINT_MITER = 0,
MG_JOINT_BEVEL, MG_JOINT_BEVEL,
MG_JOINT_NONE } mg_joint_type; MG_JOINT_NONE } mg_joint_type;
typedef enum {MG_CAP_NONE = 0, typedef enum {MG_CAP_NONE = 0,
MG_CAP_SQUARE } mg_cap_type; MG_CAP_SQUARE } mg_cap_type;
typedef struct mg_font_extents typedef struct mg_font_extents
{ {
f32 ascent; // the extent above the baseline (by convention a positive value extends above the baseline) f32 ascent; // the extent above the baseline (by convention a positive value extends above the baseline)
f32 descent; // the extent below the baseline (by convention, positive value extends below the baseline) f32 descent; // the extent below the baseline (by convention, positive value extends below the baseline)
f32 leading; // spacing between one row's descent and the next row's ascent f32 leading; // spacing between one row's descent and the next row's ascent
f32 xHeight; // height of the lower case letter 'x' f32 xHeight; // height of the lower case letter 'x'
f32 capHeight; // height of the upper case letter 'M' f32 capHeight; // height of the upper case letter 'M'
f32 width; // maximum width of the font f32 width; // maximum width of the font
} mg_font_extents; } mg_font_extents;
typedef struct mg_text_extents typedef struct mg_text_extents
{ {
f32 xBearing; f32 xBearing;
f32 yBearing; f32 yBearing;
f32 width; f32 width;
f32 height; f32 height;
f32 xAdvance; f32 xAdvance;
f32 yAdvance; f32 yAdvance;
} mg_text_extents; } mg_text_extents;
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE(martin): graphics canvas //NOTE(martin): graphics canvas
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
MP_API mg_canvas mg_canvas_nil(); MP_API mg_canvas mg_canvas_nil();
MP_API bool mg_canvas_is_nil(mg_canvas canvas); MP_API bool mg_canvas_is_nil(mg_canvas canvas);
MP_API mg_canvas mg_canvas_create(mg_surface surface); MP_API mg_canvas mg_canvas_create(mg_surface surface);
MP_API void mg_canvas_destroy(mg_canvas canvas); MP_API void mg_canvas_destroy(mg_canvas canvas);
MP_API mg_canvas mg_canvas_set_current(mg_canvas canvas); MP_API mg_canvas mg_canvas_set_current(mg_canvas canvas);
MP_API void mg_flush(); MP_API void mg_flush();
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE(martin): fonts //NOTE(martin): fonts
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
MP_API mg_font mg_font_nil(); MP_API mg_font mg_font_nil();
MP_API mg_font mg_font_create_from_memory(u32 size, byte* buffer, u32 rangeCount, unicode_range* ranges); MP_API mg_font mg_font_create_from_memory(u32 size, byte* buffer, u32 rangeCount, unicode_range* ranges);
MP_API void mg_font_destroy(mg_font font); MP_API void mg_font_destroy(mg_font font);
//NOTE(martin): the following int valued functions return -1 if font is invalid or codepoint is not present in font// //NOTE(martin): the following int valued functions return -1 if font is invalid or codepoint is not present in font//
//TODO(martin): add enum error codes //TODO(martin): add enum error codes
MP_API mg_font_extents mg_font_get_extents(mg_font font); MP_API mg_font_extents mg_font_get_extents(mg_font font);
MP_API mg_font_extents mg_font_get_scaled_extents(mg_font font, f32 emSize); MP_API mg_font_extents mg_font_get_scaled_extents(mg_font font, f32 emSize);
MP_API f32 mg_font_get_scale_for_em_pixels(mg_font font, f32 emSize); MP_API f32 mg_font_get_scale_for_em_pixels(mg_font font, f32 emSize);
//NOTE(martin): if you need to process more than one codepoint, first convert your codepoints to glyph indices, then use the //NOTE(martin): if you need to process more than one codepoint, first convert your codepoints to glyph indices, then use the
// glyph index versions of the functions, which can take an array of glyph indices. // glyph index versions of the functions, which can take an array of glyph indices.
MP_API str32 mg_font_get_glyph_indices(mg_font font, str32 codePoints, str32 backing); MP_API str32 mg_font_get_glyph_indices(mg_font font, str32 codePoints, str32 backing);
MP_API str32 mg_font_push_glyph_indices(mg_font font, mem_arena* arena, str32 codePoints); MP_API str32 mg_font_push_glyph_indices(mg_font font, mem_arena* arena, str32 codePoints);
MP_API u32 mg_font_get_glyph_index(mg_font font, utf32 codePoint); MP_API u32 mg_font_get_glyph_index(mg_font font, utf32 codePoint);
MP_API int mg_font_get_codepoint_extents(mg_font font, utf32 codePoint, mg_text_extents* outExtents); MP_API int mg_font_get_codepoint_extents(mg_font font, utf32 codePoint, mg_text_extents* outExtents);
MP_API int mg_font_get_glyph_extents(mg_font font, str32 glyphIndices, mg_text_extents* outExtents); MP_API int mg_font_get_glyph_extents(mg_font font, str32 glyphIndices, mg_text_extents* outExtents);
MP_API mp_rect mg_text_bounding_box_utf32(mg_font font, f32 fontSize, str32 text); MP_API mp_rect mg_text_bounding_box_utf32(mg_font font, f32 fontSize, str32 text);
MP_API mp_rect mg_text_bounding_box(mg_font font, f32 fontSize, str8 text); MP_API mp_rect mg_text_bounding_box(mg_font font, f32 fontSize, str8 text);
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE(martin): images //NOTE(martin): images
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
MP_API mg_image mg_image_nil(); MP_API mg_image mg_image_nil();
MP_API bool mg_image_is_nil(mg_image a); MP_API bool mg_image_is_nil(mg_image a);
MP_API mg_image mg_image_create(u32 width, u32 height); MP_API mg_image mg_image_create(u32 width, u32 height);
MP_API mg_image mg_image_create_from_rgba8(u32 width, u32 height, u8* pixels); MP_API mg_image mg_image_create_from_rgba8(u32 width, u32 height, u8* pixels);
MP_API mg_image mg_image_create_from_data(str8 data, bool flip); MP_API mg_image mg_image_create_from_data(str8 data, bool flip);
MP_API mg_image mg_image_create_from_file(str8 path, bool flip); MP_API mg_image mg_image_create_from_file(str8 path, bool flip);
MP_API void mg_image_destroy(mg_image image); MP_API void mg_image_destroy(mg_image image);
MP_API void mg_image_upload_region_rgba8(mg_image image, mp_rect region, u8* pixels); MP_API void mg_image_upload_region_rgba8(mg_image image, mp_rect region, u8* pixels);
MP_API vec2 mg_image_size(mg_image image); MP_API vec2 mg_image_size(mg_image image);
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE(martin): atlasing //NOTE(martin): atlasing
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE: rectangle allocator //NOTE: rectangle allocator
typedef struct mg_rect_atlas mg_rect_atlas; typedef struct mg_rect_atlas mg_rect_atlas;
mg_rect_atlas* mg_rect_atlas_create(mem_arena* arena, i32 width, i32 height); mg_rect_atlas* mg_rect_atlas_create(mem_arena* arena, i32 width, i32 height);
mp_rect mg_rect_atlas_alloc(mg_rect_atlas* atlas, i32 width, i32 height); mp_rect mg_rect_atlas_alloc(mg_rect_atlas* atlas, i32 width, i32 height);
void mg_rect_atlas_recycle(mg_rect_atlas* atlas, mp_rect rect); void mg_rect_atlas_recycle(mg_rect_atlas* atlas, mp_rect rect);
//NOTE: image atlas helpers //NOTE: image atlas helpers
typedef struct mg_image_region typedef struct mg_image_region
{ {
mg_image image; mg_image image;
mp_rect rect; mp_rect rect;
} mg_image_region; } mg_image_region;
mg_image_region mg_image_atlas_alloc_from_rgba8(mg_rect_atlas* atlas, mg_image backingImage, u32 width, u32 height, u8* pixels); mg_image_region mg_image_atlas_alloc_from_rgba8(mg_rect_atlas* atlas, mg_image backingImage, u32 width, u32 height, u8* pixels);
mg_image_region mg_image_atlas_alloc_from_data(mg_rect_atlas* atlas, mg_image backingImage, str8 data, bool flip); mg_image_region mg_image_atlas_alloc_from_data(mg_rect_atlas* atlas, mg_image backingImage, str8 data, bool flip);
mg_image_region mg_image_atlas_alloc_from_file(mg_rect_atlas* atlas, mg_image backingImage, str8 path, bool flip); mg_image_region mg_image_atlas_alloc_from_file(mg_rect_atlas* atlas, mg_image backingImage, str8 path, bool flip);
void mg_image_atlas_recycle(mg_rect_atlas* atlas, mg_image_region imageRgn); void mg_image_atlas_recycle(mg_rect_atlas* atlas, mg_image_region imageRgn);
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE(martin): transform, viewport and clipping //NOTE(martin): transform, viewport and clipping
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
MP_API void mg_viewport(mp_rect viewPort); MP_API void mg_viewport(mp_rect viewPort);
MP_API void mg_matrix_push(mg_mat2x3 matrix); MP_API void mg_matrix_push(mg_mat2x3 matrix);
MP_API void mg_matrix_pop(); MP_API void mg_matrix_pop();
MP_API void mg_clip_push(f32 x, f32 y, f32 w, f32 h); MP_API void mg_clip_push(f32 x, f32 y, f32 w, f32 h);
MP_API void mg_clip_pop(); MP_API void mg_clip_pop();
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE(martin): graphics attributes setting/getting //NOTE(martin): graphics attributes setting/getting
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
MP_API void mg_set_color(mg_color color); MP_API void mg_set_color(mg_color color);
MP_API void mg_set_color_rgba(f32 r, f32 g, f32 b, f32 a); MP_API void mg_set_color_rgba(f32 r, f32 g, f32 b, f32 a);
MP_API void mg_set_width(f32 width); MP_API void mg_set_width(f32 width);
MP_API void mg_set_tolerance(f32 tolerance); MP_API void mg_set_tolerance(f32 tolerance);
MP_API void mg_set_joint(mg_joint_type joint); MP_API void mg_set_joint(mg_joint_type joint);
MP_API void mg_set_max_joint_excursion(f32 maxJointExcursion); MP_API void mg_set_max_joint_excursion(f32 maxJointExcursion);
MP_API void mg_set_cap(mg_cap_type cap); MP_API void mg_set_cap(mg_cap_type cap);
MP_API void mg_set_font(mg_font font); MP_API void mg_set_font(mg_font font);
MP_API void mg_set_font_size(f32 size); MP_API void mg_set_font_size(f32 size);
MP_API void mg_set_text_flip(bool flip); MP_API void mg_set_text_flip(bool flip);
MP_API void mg_set_image(mg_image image); MP_API void mg_set_image(mg_image image);
MP_API void mg_set_image_source_region(mp_rect region); MP_API void mg_set_image_source_region(mp_rect region);
MP_API mg_color mg_get_color(); MP_API mg_color mg_get_color();
MP_API f32 mg_get_width(); MP_API f32 mg_get_width();
MP_API f32 mg_get_tolerance(); MP_API f32 mg_get_tolerance();
MP_API mg_joint_type mg_get_joint(); MP_API mg_joint_type mg_get_joint();
MP_API f32 mg_get_max_joint_excursion(); MP_API f32 mg_get_max_joint_excursion();
MP_API mg_cap_type mg_get_cap(); MP_API mg_cap_type mg_get_cap();
MP_API mg_font mg_get_font(); MP_API mg_font mg_get_font();
MP_API f32 mg_get_font_size(); MP_API f32 mg_get_font_size();
MP_API bool mg_get_text_flip(); MP_API bool mg_get_text_flip();
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE(martin): path construction //NOTE(martin): path construction
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
MP_API vec2 mg_get_position(); MP_API vec2 mg_get_position();
MP_API void mg_move_to(f32 x, f32 y); MP_API void mg_move_to(f32 x, f32 y);
MP_API void mg_line_to(f32 x, f32 y); MP_API void mg_line_to(f32 x, f32 y);
MP_API void mg_quadratic_to(f32 x1, f32 y1, f32 x2, f32 y2); MP_API void mg_quadratic_to(f32 x1, f32 y1, f32 x2, f32 y2);
MP_API void mg_cubic_to(f32 x1, f32 y1, f32 x2, f32 y2, f32 x3, f32 y3); MP_API void mg_cubic_to(f32 x1, f32 y1, f32 x2, f32 y2, f32 x3, f32 y3);
MP_API void mg_close_path(); MP_API void mg_close_path();
MP_API mp_rect mg_glyph_outlines(str32 glyphIndices); MP_API mp_rect mg_glyph_outlines(str32 glyphIndices);
MP_API void mg_codepoints_outlines(str32 string); MP_API void mg_codepoints_outlines(str32 string);
MP_API void mg_text_outlines(str8 string); MP_API void mg_text_outlines(str8 string);
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE(martin): clear/fill/stroke //NOTE(martin): clear/fill/stroke
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
MP_API void mg_clear(); MP_API void mg_clear();
MP_API void mg_fill(); MP_API void mg_fill();
MP_API void mg_stroke(); MP_API void mg_stroke();
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//NOTE(martin): 'fast' shapes primitives //NOTE(martin): 'fast' shapes primitives
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
MP_API void mg_rectangle_fill(f32 x, f32 y, f32 w, f32 h); MP_API void mg_rectangle_fill(f32 x, f32 y, f32 w, f32 h);
MP_API void mg_rectangle_stroke(f32 x, f32 y, f32 w, f32 h); MP_API void mg_rectangle_stroke(f32 x, f32 y, f32 w, f32 h);
MP_API void mg_rounded_rectangle_fill(f32 x, f32 y, f32 w, f32 h, f32 r); MP_API void mg_rounded_rectangle_fill(f32 x, f32 y, f32 w, f32 h, f32 r);
MP_API void mg_rounded_rectangle_stroke(f32 x, f32 y, f32 w, f32 h, f32 r); MP_API void mg_rounded_rectangle_stroke(f32 x, f32 y, f32 w, f32 h, f32 r);
MP_API void mg_ellipse_fill(f32 x, f32 y, f32 rx, f32 ry); MP_API void mg_ellipse_fill(f32 x, f32 y, f32 rx, f32 ry);
MP_API void mg_ellipse_stroke(f32 x, f32 y, f32 rx, f32 ry); MP_API void mg_ellipse_stroke(f32 x, f32 y, f32 rx, f32 ry);
MP_API void mg_circle_fill(f32 x, f32 y, f32 r); MP_API void mg_circle_fill(f32 x, f32 y, f32 r);
MP_API void mg_circle_stroke(f32 x, f32 y, f32 r); MP_API void mg_circle_stroke(f32 x, f32 y, f32 r);
MP_API void mg_arc(f32 x, f32 y, f32 r, f32 arcAngle, f32 startAngle); MP_API void mg_arc(f32 x, f32 y, f32 r, f32 arcAngle, f32 startAngle);
//NOTE: image helpers //NOTE: image helpers
MP_API void mg_image_draw(mg_image image, mp_rect rect); MP_API void mg_image_draw(mg_image image, mp_rect rect);
MP_API void mg_image_draw_region(mg_image image, mp_rect srcRegion, mp_rect dstRegion); MP_API void mg_image_draw_region(mg_image image, mp_rect srcRegion, mp_rect dstRegion);
#endif //__GRAPHICS_H_ #endif //__GRAPHICS_H_

View File

@ -1,143 +1,143 @@
/************************************************************//** /************************************************************//**
* *
* @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"
#include"mp_app_internal.h" #include"mp_app_internal.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
//--------------------------------------------------------------- //---------------------------------------------------------------
// surface interface // surface interface
//--------------------------------------------------------------- //---------------------------------------------------------------
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 void (*mg_surface_swap_interval_proc)(mg_surface_data* surface, int swap); typedef void (*mg_surface_swap_interval_proc)(mg_surface_data* surface, int swap);
typedef vec2 (*mg_surface_contents_scaling_proc)(mg_surface_data* surface); typedef vec2 (*mg_surface_contents_scaling_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 void* (*mg_surface_native_layer_proc)(mg_surface_data* surface); typedef void* (*mg_surface_native_layer_proc)(mg_surface_data* surface);
typedef mg_surface_id (*mg_surface_remote_id_proc)(mg_surface_data* surface); typedef mg_surface_id (*mg_surface_remote_id_proc)(mg_surface_data* surface);
typedef void (*mg_surface_host_connect_proc)(mg_surface_data* surface, mg_surface_id remoteId); typedef void (*mg_surface_host_connect_proc)(mg_surface_data* surface, mg_surface_id remoteId);
typedef struct mg_surface_data typedef struct mg_surface_data
{ {
mg_backend_id backend; mg_backend_id backend;
mp_layer layer; mp_layer layer;
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_swap_interval_proc swapInterval; mg_surface_swap_interval_proc swapInterval;
mg_surface_contents_scaling_proc contentsScaling; mg_surface_contents_scaling_proc contentsScaling;
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_native_layer_proc nativeLayer; mg_surface_native_layer_proc nativeLayer;
mg_surface_remote_id_proc remoteID; mg_surface_remote_id_proc remoteID;
mg_surface_host_connect_proc hostConnect; mg_surface_host_connect_proc hostConnect;
} 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);
void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window); void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window);
void mg_surface_init_remote(mg_surface_data* surface, u32 width, u32 height); void mg_surface_init_remote(mg_surface_data* surface, u32 width, u32 height);
void mg_surface_init_host(mg_surface_data* surface, mp_window_data* window); void mg_surface_init_host(mg_surface_data* surface, mp_window_data* window);
void mg_surface_cleanup(mg_surface_data* surface); void mg_surface_cleanup(mg_surface_data* surface);
void* mg_surface_native_layer(mg_surface surface); void* mg_surface_native_layer(mg_surface surface);
//--------------------------------------------------------------- //---------------------------------------------------------------
// canvas backend interface // canvas backend interface
//--------------------------------------------------------------- //---------------------------------------------------------------
typedef struct mg_image_data typedef struct mg_image_data
{ {
list_elt listElt; list_elt listElt;
u32 generation; u32 generation;
vec2 size; vec2 size;
} mg_image_data; } mg_image_data;
typedef struct mg_vertex_layout typedef struct mg_vertex_layout
{ {
u32 maxVertexCount; u32 maxVertexCount;
u32 maxIndexCount; u32 maxIndexCount;
char* posBuffer; char* posBuffer;
u32 posStride; u32 posStride;
char* cubicBuffer; char* cubicBuffer;
u32 cubicStride; u32 cubicStride;
char* uvTransformBuffer; char* uvTransformBuffer;
u32 uvTransformStride; u32 uvTransformStride;
char* colorBuffer; char* colorBuffer;
u32 colorStride; u32 colorStride;
char* shapeIndexBuffer; char* shapeIndexBuffer;
u32 shapeIndexStride; u32 shapeIndexStride;
char* clipBuffer; char* clipBuffer;
u32 clipStride; u32 clipStride;
char* 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_begin_proc)(mg_canvas_backend* backend); typedef void (*mg_canvas_backend_begin_proc)(mg_canvas_backend* backend);
typedef void (*mg_canvas_backend_end_proc)(mg_canvas_backend* backend); typedef void (*mg_canvas_backend_end_proc)(mg_canvas_backend* backend);
typedef void (*mg_canvas_backend_clear_proc)(mg_canvas_backend* backend, mg_color clearColor); typedef void (*mg_canvas_backend_clear_proc)(mg_canvas_backend* backend, mg_color clearColor);
typedef void (*mg_canvas_backend_draw_batch_proc)(mg_canvas_backend* backend, typedef void (*mg_canvas_backend_draw_batch_proc)(mg_canvas_backend* backend,
mg_image_data* imageData, mg_image_data* imageData,
u32 vertexCount, u32 vertexCount,
u32 shapeCount, u32 shapeCount,
u32 indexCount); u32 indexCount);
typedef mg_image_data* (*mg_canvas_backend_image_create_proc)(mg_canvas_backend* backend, vec2 size); typedef mg_image_data* (*mg_canvas_backend_image_create_proc)(mg_canvas_backend* backend, vec2 size);
typedef void (*mg_canvas_backend_image_destroy_proc)(mg_canvas_backend* backend, mg_image_data* image); typedef void (*mg_canvas_backend_image_destroy_proc)(mg_canvas_backend* backend, mg_image_data* image);
typedef void (*mg_canvas_backend_image_upload_region_proc)(mg_canvas_backend* backend, typedef void (*mg_canvas_backend_image_upload_region_proc)(mg_canvas_backend* backend,
mg_image_data* image, mg_image_data* image,
mp_rect region, mp_rect region,
u8* pixels); u8* pixels);
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_begin_proc begin; mg_canvas_backend_begin_proc begin;
mg_canvas_backend_end_proc end; mg_canvas_backend_end_proc end;
mg_canvas_backend_clear_proc clear; mg_canvas_backend_clear_proc clear;
mg_canvas_backend_draw_batch_proc drawBatch; mg_canvas_backend_draw_batch_proc drawBatch;
mg_canvas_backend_image_create_proc imageCreate; mg_canvas_backend_image_create_proc imageCreate;
mg_canvas_backend_image_destroy_proc imageDestroy; mg_canvas_backend_image_destroy_proc imageDestroy;
mg_canvas_backend_image_upload_region_proc imageUploadRegion; mg_canvas_backend_image_upload_region_proc imageUploadRegion;
} mg_canvas_backend; } mg_canvas_backend;
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
#endif //__GRAPHICS_INTERNAL_H_ #endif //__GRAPHICS_INTERNAL_H_

View File

@ -1,77 +1,77 @@
/************************************************************//** /************************************************************//**
* *
* @file: milepost.c * @file: milepost.c
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 13/02/2021 * @date: 13/02/2021
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
//--------------------------------------------------------------- //---------------------------------------------------------------
// utilities implementations // utilities implementations
//--------------------------------------------------------------- //---------------------------------------------------------------
#include"util/debug_log.c" #include"util/debug_log.c"
#include"util/memory.c" #include"util/memory.c"
#include"util/strings.c" #include"util/strings.c"
#include"util/utf8.c" #include"util/utf8.c"
#include"util/hash.c" #include"util/hash.c"
#include"util/ringbuffer.c" #include"util/ringbuffer.c"
//--------------------------------------------------------------- //---------------------------------------------------------------
// platform implementations // platform implementations
//--------------------------------------------------------------- //---------------------------------------------------------------
#include"platform.h" #include"platform.h"
#if defined(OS_WIN64) #if defined(OS_WIN64)
#include"platform/win32_base_allocator.c" #include"platform/win32_base_allocator.c"
#include"platform/win32_clock.c" #include"platform/win32_clock.c"
//TODO //TODO
#elif defined(OS_MACOS) #elif defined(OS_MACOS)
#include"platform/unix_base_allocator.c" #include"platform/unix_base_allocator.c"
#include"platform/osx_clock.c" #include"platform/osx_clock.c"
/* /*
#include"platform/unix_rng.c" #include"platform/unix_rng.c"
#include"platform/posix_thread.c" #include"platform/posix_thread.c"
#include"platform/posix_socket.c" #include"platform/posix_socket.c"
*/ */
#elif defined(OS_LINUX) #elif defined(OS_LINUX)
#include"platform/unix_base_allocator.c" #include"platform/unix_base_allocator.c"
#include"platform/linux_clock.c" #include"platform/linux_clock.c"
/* /*
#include"platform/unix_rng.c" #include"platform/unix_rng.c"
#include"platform/posix_thread.c" #include"platform/posix_thread.c"
#include"platform/posix_socket.c" #include"platform/posix_socket.c"
*/ */
#else #else
#error "Unsupported platform" #error "Unsupported platform"
#endif #endif
//--------------------------------------------------------------- //---------------------------------------------------------------
// app/graphics layer // app/graphics layer
//--------------------------------------------------------------- //---------------------------------------------------------------
#if defined(OS_WIN64) #if defined(OS_WIN64)
#include"win32_app.c" #include"win32_app.c"
#include"graphics.c" #include"graphics.c"
#if MG_COMPILE_BACKEND_GL || MG_COMPILE_BACKEND_GLES #if MG_COMPILE_BACKEND_GL || MG_COMPILE_BACKEND_GLES
#include"gl_loader.c" #include"gl_loader.c"
#endif #endif
#if MG_COMPILE_BACKEND_GL #if MG_COMPILE_BACKEND_GL
#include"wgl_surface.c" #include"wgl_surface.c"
#include"gl_canvas.c" #include"gl_canvas.c"
#endif #endif
#if MG_COMPILE_BACKEND_GLES #if MG_COMPILE_BACKEND_GLES
#include"egl_surface.c" #include"egl_surface.c"
#endif #endif
#elif defined(OS_MACOS) #elif defined(OS_MACOS)
//NOTE: macos application layer and graphics backends are defined in milepost.m //NOTE: macos application layer and graphics backends are defined in milepost.m
#else #else
#error "Unsupported platform" #error "Unsupported platform"
#endif #endif
#include"ui.c" #include"ui.c"

View File

@ -1,48 +1,48 @@
/************************************************************//** /************************************************************//**
* *
* @file: milepost.h * @file: milepost.h
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 13/02/2021 * @date: 13/02/2021
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#ifndef __MILEPOST_H_ #ifndef __MILEPOST_H_
#define __MILEPOST_H_ #define __MILEPOST_H_
//---------------------------------------------------------------- //----------------------------------------------------------------
// utility layer // utility layer
//---------------------------------------------------------------- //----------------------------------------------------------------
#include"platform.h" #include"platform.h"
#include"typedefs.h" #include"typedefs.h"
#include"macro_helpers.h" #include"macro_helpers.h"
#include"debug_log.h" #include"debug_log.h"
#include"lists.h" #include"lists.h"
#include"memory.h" #include"memory.h"
#include"strings.h" #include"strings.h"
#include"utf8.h" #include"utf8.h"
#include"hash.h" #include"hash.h"
//---------------------------------------------------------------- //----------------------------------------------------------------
// platform layer // platform layer
//---------------------------------------------------------------- //----------------------------------------------------------------
#include"platform_clock.h" #include"platform_clock.h"
/* /*
#include"platform_rng.h" #include"platform_rng.h"
#include"platform_socket.h" #include"platform_socket.h"
#include"platform_thread.h" #include"platform_thread.h"
*/ */
//---------------------------------------------------------------- //----------------------------------------------------------------
// application/graphics layer // application/graphics layer
//---------------------------------------------------------------- //----------------------------------------------------------------
#include"mp_app.h" #include"mp_app.h"
#include"graphics.h" #include"graphics.h"
#include"ui.h" #include"ui.h"
#ifdef MG_INCLUDE_GL_API #ifdef MG_INCLUDE_GL_API
#include"gl_api.h" #include"gl_api.h"
#endif #endif
//#include"ui.h" //#include"ui.h"
#endif //__MILEPOST_H_ #endif //__MILEPOST_H_

View File

@ -1,29 +1,29 @@
/************************************************************//** /************************************************************//**
* *
* @file: milepost.m * @file: milepost.m
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 13/02/2021 * @date: 13/02/2021
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#include"osx_app.m" #include"osx_app.m"
#include"graphics.c" #include"graphics.c"
#if MG_COMPILE_BACKEND_METAL #if MG_COMPILE_BACKEND_METAL
#include"mtl_surface.m" #include"mtl_surface.m"
#include"mtl_canvas.m" #include"mtl_canvas.m"
#endif #endif
#if MG_COMPILE_BACKEND_GLES #if MG_COMPILE_BACKEND_GLES
#include"gl_loader.c" #include"gl_loader.c"
#include"egl_surface.c" #include"egl_surface.c"
#endif #endif
/* /*
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations" #pragma clang diagnostic ignored "-Wdeprecated-declarations"
#include"osx_gles_surface.m" #include"osx_gles_surface.m"
#pragma clang diagnostic pop #pragma clang diagnostic pop
*/ */
//#include"osx_surface_client.m" //#include"osx_surface_client.m"

View File

@ -1,407 +1,407 @@
/************************************************************//** /************************************************************//**
* *
* @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, mp_key_action action) static void mp_update_key_state(mp_key_state* key, mp_key_action action)
{ {
u64 frameCounter = __mpApp.inputState.frameCounter; u64 frameCounter = __mpApp.inputState.frameCounter;
if(key->lastUpdate != frameCounter) if(key->lastUpdate != frameCounter)
{ {
key->transitionCount = 0; key->transitionCount = 0;
key->repeatCount = 0; key->repeatCount = 0;
key->sysClicked = false; key->sysClicked = false;
key->sysDoubleClicked = false; key->sysDoubleClicked = false;
key->lastUpdate = frameCounter; key->lastUpdate = frameCounter;
} }
switch(action) switch(action)
{ {
case MP_KEY_PRESS: case MP_KEY_PRESS:
{ {
if(!key->down) if(!key->down)
{ {
key->transitionCount++; key->transitionCount++;
} }
key->down = true; key->down = true;
} break; } break;
case MP_KEY_REPEAT: case MP_KEY_REPEAT:
{ {
key->repeatCount++; key->repeatCount++;
key->down = true; key->down = true;
} break; } break;
case MP_KEY_RELEASE: case MP_KEY_RELEASE:
{ {
if(key->down) if(key->down)
{ {
key->transitionCount++; key->transitionCount++;
} }
key->down = false; key->down = false;
} break; } break;
default: default:
break; break;
} }
} }
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_key_get_state(mp_key_code key) mp_key_state mp_key_get_state(mp_key_code key)
{ {
mp_key_state state = {0}; mp_key_state state = {0};
if(key <= MP_KEY_COUNT) if(key <= MP_KEY_COUNT)
{ {
state = __mpApp.inputState.keyboard.keys[key]; state = __mpApp.inputState.keyboard.keys[key];
} }
return(state); return(state);
} }
mp_key_state mp_mouse_button_get_state(mp_mouse_button button) mp_key_state mp_mouse_button_get_state(mp_mouse_button button)
{ {
mp_key_state state = {0}; mp_key_state state = {0};
if(button <= MP_MOUSE_BUTTON_COUNT) if(button <= MP_MOUSE_BUTTON_COUNT)
{ {
state = __mpApp.inputState.mouse.buttons[button]; state = __mpApp.inputState.mouse.buttons[button];
} }
return(state); return(state);
} }
int mp_key_state_press_count(mp_key_state* key) int mp_key_state_press_count(mp_key_state* key)
{ {
int count = 0; int count = 0;
if(key->lastUpdate == __mpApp.inputState.frameCounter) if(key->lastUpdate == __mpApp.inputState.frameCounter)
{ {
count = key->transitionCount / 2; count = key->transitionCount / 2;
if(key->down) if(key->down)
{ {
//NOTE: add one if state is down transition count is odd //NOTE: add one if state is down transition count is odd
count += (key->transitionCount & 0x01); count += (key->transitionCount & 0x01);
} }
} }
return(count); return(count);
} }
int mp_key_state_release_count(mp_key_state* key) int mp_key_state_release_count(mp_key_state* key)
{ {
int count = 0; int count = 0;
if(key->lastUpdate == __mpApp.inputState.frameCounter) if(key->lastUpdate == __mpApp.inputState.frameCounter)
{ {
count = key->transitionCount / 2; count = key->transitionCount / 2;
if(!key->down) if(!key->down)
{ {
//NOTE: add one if state is up and transition count is odd //NOTE: add one if state is up and transition count is odd
count += (key->transitionCount & 0x01); count += (key->transitionCount & 0x01);
} }
} }
return(count); return(count);
} }
int mp_key_state_repeat_count(mp_key_state* key) int mp_key_state_repeat_count(mp_key_state* key)
{ {
int count = 0; int count = 0;
if(key->lastUpdate == __mpApp.inputState.frameCounter) if(key->lastUpdate == __mpApp.inputState.frameCounter)
{ {
count = key->repeatCount; count = key->repeatCount;
} }
return(count); return(count);
} }
bool mp_key_down(mp_key_code key) bool mp_key_down(mp_key_code key)
{ {
mp_key_state state = mp_key_get_state(key); mp_key_state state = mp_key_get_state(key);
return(state.down); return(state.down);
} }
int mp_key_pressed(mp_key_code key) int mp_key_pressed(mp_key_code key)
{ {
mp_key_state state = mp_key_get_state(key); mp_key_state state = mp_key_get_state(key);
int res = mp_key_state_press_count(&state); int res = mp_key_state_press_count(&state);
return(res); return(res);
} }
int mp_key_released(mp_key_code key) int mp_key_released(mp_key_code key)
{ {
mp_key_state state = mp_key_get_state(key); mp_key_state state = mp_key_get_state(key);
int res = mp_key_state_release_count(&state); int res = mp_key_state_release_count(&state);
return(res); return(res);
} }
int mp_key_repeated(mp_key_code key) int mp_key_repeated(mp_key_code key)
{ {
mp_key_state state = mp_key_get_state(key); mp_key_state state = mp_key_get_state(key);
int res = mp_key_state_repeat_count(&state); int res = mp_key_state_repeat_count(&state);
return(res); return(res);
} }
bool mp_mouse_down(mp_mouse_button button) bool mp_mouse_down(mp_mouse_button button)
{ {
mp_key_state state = mp_mouse_button_get_state(button); mp_key_state state = mp_mouse_button_get_state(button);
return(state.down); return(state.down);
} }
int mp_mouse_pressed(mp_mouse_button button) int mp_mouse_pressed(mp_mouse_button button)
{ {
mp_key_state state = mp_mouse_button_get_state(button); mp_key_state state = mp_mouse_button_get_state(button);
int res = mp_key_state_press_count(&state); int res = mp_key_state_press_count(&state);
return(res); return(res);
} }
int mp_mouse_released(mp_mouse_button button) int mp_mouse_released(mp_mouse_button button)
{ {
mp_key_state state = mp_mouse_button_get_state(button); mp_key_state state = mp_mouse_button_get_state(button);
int res = mp_key_state_release_count(&state); int res = mp_key_state_release_count(&state);
return(res); return(res);
} }
bool mp_mouse_clicked(mp_mouse_button button) bool mp_mouse_clicked(mp_mouse_button button)
{ {
mp_key_state state = mp_mouse_button_get_state(button); mp_key_state state = mp_mouse_button_get_state(button);
bool clicked = state.sysClicked && (state.lastUpdate == __mpApp.inputState.frameCounter); bool clicked = state.sysClicked && (state.lastUpdate == __mpApp.inputState.frameCounter);
return(clicked); return(clicked);
} }
bool mp_mouse_double_clicked(mp_mouse_button button) bool mp_mouse_double_clicked(mp_mouse_button button)
{ {
mp_key_state state = mp_mouse_button_get_state(button); mp_key_state state = mp_mouse_button_get_state(button);
bool doubleClicked = state.sysClicked && (state.lastUpdate == __mpApp.inputState.frameCounter); bool doubleClicked = state.sysClicked && (state.lastUpdate == __mpApp.inputState.frameCounter);
return(doubleClicked); return(doubleClicked);
} }
mp_keymod_flags mp_key_mods() mp_keymod_flags mp_key_mods()
{ {
return(__mpApp.inputState.keyboard.mods); return(__mpApp.inputState.keyboard.mods);
} }
vec2 mp_mouse_position() vec2 mp_mouse_position()
{ {
return(__mpApp.inputState.mouse.pos); return(__mpApp.inputState.mouse.pos);
} }
vec2 mp_mouse_delta() vec2 mp_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_mouse_wheel() vec2 mp_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

View File

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

View File

@ -1,154 +1,154 @@
/************************************************************//** /************************************************************//**
* *
* @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"mp_app.h" #include"mp_app.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 transitionCount; u32 transitionCount;
u32 repeatCount; u32 repeatCount;
bool down; bool down;
bool sysClicked; bool sysClicked;
bool sysDoubleClicked; bool sysDoubleClicked;
} 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_keymod_flags mods; mp_keymod_flags 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[512]; mp_key_utf8 keyLabels[512];
int keyCodes[512]; 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_

File diff suppressed because it is too large Load Diff

View File

@ -1,347 +1,347 @@
#include<metal_stdlib> #include<metal_stdlib>
#include<simd/simd.h> #include<simd/simd.h>
#include"mtl_shader.h" #include"mtl_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(tex.sample(smp, i.uv)); return(tex.sample(smp, i.uv));
} }
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)]],
constant mg_shape* shapeBuffer [[buffer(2)]], constant mg_shape* shapeBuffer [[buffer(2)]],
device mg_triangle_data* triangleArray [[buffer(3)]], device mg_triangle_data* triangleArray [[buffer(3)]],
device float4* boxArray [[buffer(4)]], device float4* boxArray [[buffer(4)]],
constant float* contentsScaling [[buffer(5)]], constant float* contentsScaling [[buffer(5)]],
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
int shapeIndex = vertexBuffer[i0].shapeIndex; int shapeIndex = vertexBuffer[i0].shapeIndex;
vector_float4 clip = contentsScaling[0]*shapeBuffer[shapeIndex].clip; vector_float4 clip = contentsScaling[0]*shapeBuffer[shapeIndex].clip;
//NOTE(martin): intersect with current clip //NOTE(martin): intersect with current clip
boxMin = max(boxMin, clip.xy); boxMin = max(boxMin, clip.xy);
boxMax = min(boxMax, clip.zw); boxMax = min(boxMax, clip.zw);
//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].shapeIndex = shapeIndex; triangleArray[triangleIndex].shapeIndex = shapeIndex;
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].shapeIndex; uint eltZIndex = triangleArray[elt].shapeIndex;
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].shapeIndex; uint backEltZIndex = triangleArray[backElt].shapeIndex;
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)]],
const device mg_shape* shapeBuffer [[buffer(1)]], const device mg_shape* shapeBuffer [[buffer(1)]],
device uint* tileCounters [[buffer(2)]], device uint* tileCounters [[buffer(2)]],
const device uint* tilesArray [[buffer(3)]], const device uint* tilesArray [[buffer(3)]],
const device mg_triangle_data* triangleArray [[buffer(4)]], const device mg_triangle_data* triangleArray [[buffer(4)]],
const device float4* boxArray [[buffer(5)]], const device float4* boxArray [[buffer(5)]],
constant vector_float4* clearColor [[buffer(6)]], constant vector_float4* clearColor [[buffer(6)]],
constant int* useTexture [[buffer(7)]], constant int* useTexture [[buffer(7)]],
constant float* contentsScaling [[buffer(8)]], constant float* contentsScaling [[buffer(8)]],
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];
#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 > 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] = float4(0, 0, 0, 0); pixelColors[i] = float4(0, 0, 0, 0);
nextColors[i] = float4(0, 0, 0, 0); nextColors[i] = float4(0, 0, 0, 0);
} }
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;
int shapeIndex = v0->shapeIndex; int shapeIndex = v0->shapeIndex;
float4 color = shapeBuffer[shapeIndex].color; float4 color = shapeBuffer[shapeIndex].color;
color.rgb *= color.a; color.rgb *= color.a;
const device float* uvTransform2x3 = shapeBuffer[shapeIndex].uvTransform; const device float* uvTransform2x3 = shapeBuffer[shapeIndex].uvTransform;
matrix_float3x3 uvTransform = {{uvTransform2x3[0], uvTransform2x3[3], 0}, matrix_float3x3 uvTransform = {{uvTransform2x3[0], uvTransform2x3[3], 0},
{uvTransform2x3[1], uvTransform2x3[4], 0}, {uvTransform2x3[1], uvTransform2x3[4], 0},
{uvTransform2x3[2], uvTransform2x3[5], 1}}; {uvTransform2x3[2], uvTransform2x3[5], 1}};
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);
float2 uv = (uvTransform*(float3(samplePoint.xy/contentsScaling[0], 1))).xy; float2 uv = (uvTransform*(float3(samplePoint.xy/contentsScaling[0], 1))).xy;
float4 texColor = float4(1, 1, 1, 1); float4 texColor = float4(1, 1, 1, 1);
if(*useTexture) if(*useTexture)
{ {
constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear); constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear);
texColor = texAtlas.sample(smp, uv); texColor = texAtlas.sample(smp, uv);
texColor.rgb *= texColor.a; texColor.rgb *= texColor.a;
} }
//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(shapeIndex == zIndices[i]) if(shapeIndex == 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] = shapeIndex; zIndices[i] = shapeIndex;
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 = out/6.; out = out/6.;
outTexture.write(out, gid); outTexture.write(out, gid);
} }

View File

@ -1,254 +1,254 @@
/************************************************************//** /************************************************************//**
* *
* @file: mtl_surface.m * @file: mtl_surface.m
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 12/07/2023 * @date: 12/07/2023
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#import<Metal/Metal.h> #import<Metal/Metal.h>
#import <QuartzCore/QuartzCore.h> #import <QuartzCore/QuartzCore.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"
#define LOG_SUBSYSTEM "Graphics" #define LOG_SUBSYSTEM "Graphics"
static const u32 MP_MTL_MAX_DRAWABLES_IN_FLIGHT = 3; static const u32 MP_MTL_MAX_DRAWABLES_IN_FLIGHT = 3;
typedef struct mg_mtl_surface typedef struct mg_mtl_surface
{ {
mg_surface_data interface; mg_surface_data interface;
// permanent mtl resources // permanent mtl resources
id<MTLDevice> device; id<MTLDevice> device;
CAMetalLayer* mtlLayer; CAMetalLayer* mtlLayer;
id<MTLCommandQueue> commandQueue; id<MTLCommandQueue> commandQueue;
// transient metal resources // transient metal resources
id<CAMetalDrawable> drawable; id<CAMetalDrawable> drawable;
id<MTLCommandBuffer> commandBuffer; id<MTLCommandBuffer> commandBuffer;
dispatch_semaphore_t drawableSemaphore; dispatch_semaphore_t drawableSemaphore;
} mg_mtl_surface; } mg_mtl_surface;
void mg_mtl_surface_destroy(mg_surface_data* interface) void mg_mtl_surface_destroy(mg_surface_data* interface)
{ {
mg_mtl_surface* surface = (mg_mtl_surface*)interface; mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool @autoreleasepool
{ {
[surface->commandQueue release]; [surface->commandQueue release];
[surface->mtlLayer removeFromSuperlayer]; [surface->mtlLayer removeFromSuperlayer];
[surface->mtlLayer release]; [surface->mtlLayer release];
[surface->device release]; [surface->device release];
} }
//NOTE: we don't use mp_layer_cleanup here, because the CAMetalLayer is taken care off by the surface itself //NOTE: we don't use mp_layer_cleanup here, because the CAMetalLayer is taken care off by the surface itself
} }
void mg_mtl_surface_acquire_drawable_and_command_buffer(mg_mtl_surface* surface) void mg_mtl_surface_acquire_drawable_and_command_buffer(mg_mtl_surface* surface)
{@autoreleasepool{ {@autoreleasepool{
/*WARN(martin): this is super important /*WARN(martin): this is super important
When the app is put in the background, it seems that if there are buffers in flight, the drawables to When the app is put in the background, it seems that if there are buffers in flight, the drawables to
can be leaked. This causes the gpu to allocate more and more drawables, until the app crashes. can be leaked. This causes the gpu to allocate more and more drawables, until the app crashes.
(note: the drawable objects themselves are released once the app comes back to the forefront, but the (note: the drawable objects themselves are released once the app comes back to the forefront, but the
memory allocated in the GPU is never freed...) memory allocated in the GPU is never freed...)
In background the gpu seems to create drawable if none is available instead of actually In background the gpu seems to create drawable if none is available instead of actually
blocking on nextDrawable. These drawable never get freed. blocking on nextDrawable. These drawable never get freed.
This is not a problem if our shader is fast enough, since a previous drawable becomes This is not a problem if our shader is fast enough, since a previous drawable becomes
available before we finish the frame. But we want to protect against it anyway available before we finish the frame. But we want to protect against it anyway
The normal blocking mechanism of nextDrawable seems useless, so we implement our own scheme by The normal blocking mechanism of nextDrawable seems useless, so we implement our own scheme by
counting the number of drawables available with a semaphore that gets decremented here and counting the number of drawables available with a semaphore that gets decremented here and
incremented in the presentedHandler of the drawable. incremented in the presentedHandler of the drawable.
Thus we ensure that we don't consume more drawables than we are able to draw. Thus we ensure that we don't consume more drawables than we are able to draw.
//TODO: we _also_ should stop trying to render if we detect that the app is in the background //TODO: we _also_ should stop trying to render if we detect that the app is in the background
or occluded, but we can't count only on this because there is a potential race between the or occluded, but we can't count only on this because there is a potential race between the
notification of background mode and the rendering. notification of background mode and the rendering.
//TODO: We should set a reasonable timeout and skip the frame and log an error in case we are stalled //TODO: We should set a reasonable timeout and skip the frame and log an error in case we are stalled
for too long. for too long.
*/ */
dispatch_semaphore_wait(surface->drawableSemaphore, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(surface->drawableSemaphore, DISPATCH_TIME_FOREVER);
surface->drawable = [surface->mtlLayer nextDrawable]; surface->drawable = [surface->mtlLayer nextDrawable];
ASSERT(surface->drawable != nil); ASSERT(surface->drawable != nil);
//TODO: make this a weak reference if we use ARC //TODO: make this a weak reference if we use ARC
dispatch_semaphore_t semaphore = surface->drawableSemaphore; dispatch_semaphore_t semaphore = surface->drawableSemaphore;
[surface->drawable addPresentedHandler:^(id<MTLDrawable> drawable){ [surface->drawable addPresentedHandler:^(id<MTLDrawable> drawable){
dispatch_semaphore_signal(semaphore); dispatch_semaphore_signal(semaphore);
}]; }];
//NOTE(martin): create a command buffer //NOTE(martin): create a command buffer
surface->commandBuffer = [surface->commandQueue commandBuffer]; surface->commandBuffer = [surface->commandQueue commandBuffer];
[surface->commandBuffer retain]; [surface->commandBuffer retain];
[surface->drawable retain]; [surface->drawable retain];
}} }}
void mg_mtl_surface_prepare(mg_surface_data* interface) void mg_mtl_surface_prepare(mg_surface_data* interface)
{ {
mg_mtl_surface* surface = (mg_mtl_surface*)interface; mg_mtl_surface* surface = (mg_mtl_surface*)interface;
mg_mtl_surface_acquire_drawable_and_command_buffer(surface); mg_mtl_surface_acquire_drawable_and_command_buffer(surface);
} }
void mg_mtl_surface_present(mg_surface_data* interface) void mg_mtl_surface_present(mg_surface_data* interface)
{ {
mg_mtl_surface* surface = (mg_mtl_surface*)interface; mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool @autoreleasepool
{ {
//NOTE(martin): present drawable and commit command buffer //NOTE(martin): present drawable and commit command buffer
[surface->commandBuffer presentDrawable: surface->drawable]; [surface->commandBuffer presentDrawable: surface->drawable];
[surface->commandBuffer commit]; [surface->commandBuffer commit];
[surface->commandBuffer waitUntilCompleted]; [surface->commandBuffer waitUntilCompleted];
//NOTE(martin): acquire next frame resources //NOTE(martin): acquire next frame resources
[surface->commandBuffer release]; [surface->commandBuffer release];
surface->commandBuffer = nil; surface->commandBuffer = nil;
[surface->drawable release]; [surface->drawable release];
surface->drawable = nil; surface->drawable = nil;
} }
} }
void mg_mtl_surface_swap_interval(mg_surface_data* interface, int swap) void mg_mtl_surface_swap_interval(mg_surface_data* interface, int swap)
{ {
mg_mtl_surface* surface = (mg_mtl_surface*)interface; mg_mtl_surface* surface = (mg_mtl_surface*)interface;
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
//TODO //TODO
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
} }
void mg_mtl_surface_set_frame(mg_surface_data* interface, mp_rect frame) void mg_mtl_surface_set_frame(mg_surface_data* interface, mp_rect frame)
{ {
mg_mtl_surface* surface = (mg_mtl_surface*)interface; mg_mtl_surface* surface = (mg_mtl_surface*)interface;
mg_osx_surface_set_frame(interface, frame); mg_osx_surface_set_frame(interface, frame);
vec2 scale = mg_osx_surface_contents_scaling(interface); vec2 scale = mg_osx_surface_contents_scaling(interface);
CGSize drawableSize = (CGSize){.width = frame.w * scale.x, .height = frame.h * scale.y}; CGSize drawableSize = (CGSize){.width = frame.w * scale.x, .height = frame.h * scale.y};
surface->mtlLayer.drawableSize = drawableSize; surface->mtlLayer.drawableSize = drawableSize;
} }
//TODO fix that according to real scaling, depending on the monitor settings //TODO fix that according to real scaling, depending on the monitor settings
static const f32 MG_MTL_SURFACE_CONTENTS_SCALING = 2; static const f32 MG_MTL_SURFACE_CONTENTS_SCALING = 2;
mg_surface_data* mg_mtl_surface_create_for_window(mp_window window) mg_surface_data* mg_mtl_surface_create_for_window(mp_window window)
{ {
mg_mtl_surface* surface = 0; mg_mtl_surface* surface = 0;
mp_window_data* windowData = mp_window_ptr_from_handle(window); mp_window_data* windowData = mp_window_ptr_from_handle(window);
if(windowData) if(windowData)
{ {
surface = (mg_mtl_surface*)malloc(sizeof(mg_mtl_surface)); surface = (mg_mtl_surface*)malloc(sizeof(mg_mtl_surface));
mg_surface_init_for_window((mg_surface_data*)surface, windowData); mg_surface_init_for_window((mg_surface_data*)surface, windowData);
//NOTE(martin): setup interface functions //NOTE(martin): setup interface functions
surface->interface.backend = MG_BACKEND_METAL; surface->interface.backend = MG_BACKEND_METAL;
surface->interface.destroy = mg_mtl_surface_destroy; surface->interface.destroy = mg_mtl_surface_destroy;
surface->interface.prepare = mg_mtl_surface_prepare; surface->interface.prepare = mg_mtl_surface_prepare;
surface->interface.present = mg_mtl_surface_present; surface->interface.present = mg_mtl_surface_present;
surface->interface.swapInterval = mg_mtl_surface_swap_interval; surface->interface.swapInterval = mg_mtl_surface_swap_interval;
surface->interface.setFrame = mg_mtl_surface_set_frame; surface->interface.setFrame = mg_mtl_surface_set_frame;
@autoreleasepool @autoreleasepool
{ {
surface->drawableSemaphore = dispatch_semaphore_create(MP_MTL_MAX_DRAWABLES_IN_FLIGHT); surface->drawableSemaphore = dispatch_semaphore_create(MP_MTL_MAX_DRAWABLES_IN_FLIGHT);
//----------------------------------------------------------- //-----------------------------------------------------------
//NOTE(martin): create a mtl device and a mtl layer and //NOTE(martin): create a mtl device and a mtl layer and
//----------------------------------------------------------- //-----------------------------------------------------------
surface->device = MTLCreateSystemDefaultDevice(); surface->device = MTLCreateSystemDefaultDevice();
[surface->device retain]; [surface->device retain];
surface->mtlLayer = [CAMetalLayer layer]; surface->mtlLayer = [CAMetalLayer layer];
[surface->mtlLayer retain]; [surface->mtlLayer retain];
surface->mtlLayer.device = surface->device; surface->mtlLayer.device = surface->device;
[surface->mtlLayer setOpaque:NO]; [surface->mtlLayer setOpaque:NO];
[surface->interface.layer.caLayer addSublayer: (CALayer*)surface->mtlLayer]; [surface->interface.layer.caLayer addSublayer: (CALayer*)surface->mtlLayer];
//----------------------------------------------------------- //-----------------------------------------------------------
//NOTE(martin): set the size and scaling //NOTE(martin): set the size and scaling
//----------------------------------------------------------- //-----------------------------------------------------------
NSRect frame = [[windowData->osx.nsWindow contentView] frame]; NSRect frame = [[windowData->osx.nsWindow contentView] frame];
CGSize size = frame.size; CGSize size = frame.size;
surface->mtlLayer.frame = (CGRect){{0, 0}, size}; surface->mtlLayer.frame = (CGRect){{0, 0}, size};
size.width *= MG_MTL_SURFACE_CONTENTS_SCALING; size.width *= MG_MTL_SURFACE_CONTENTS_SCALING;
size.height *= MG_MTL_SURFACE_CONTENTS_SCALING; size.height *= MG_MTL_SURFACE_CONTENTS_SCALING;
surface->mtlLayer.drawableSize = size; surface->mtlLayer.drawableSize = size;
surface->mtlLayer.contentsScale = MG_MTL_SURFACE_CONTENTS_SCALING; surface->mtlLayer.contentsScale = MG_MTL_SURFACE_CONTENTS_SCALING;
surface->mtlLayer.pixelFormat = MTLPixelFormatBGRA8Unorm; surface->mtlLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
//NOTE(martin): handling resizing //NOTE(martin): handling resizing
surface->mtlLayer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable; surface->mtlLayer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable;
surface->mtlLayer.needsDisplayOnBoundsChange = YES; surface->mtlLayer.needsDisplayOnBoundsChange = YES;
//----------------------------------------------------------- //-----------------------------------------------------------
//NOTE(martin): create a command queue //NOTE(martin): create a command queue
//----------------------------------------------------------- //-----------------------------------------------------------
surface->commandQueue = [surface->device newCommandQueue]; surface->commandQueue = [surface->device newCommandQueue];
[surface->commandQueue retain]; [surface->commandQueue retain];
//NOTE(martin): command buffer and drawable are set on demand and at the end of each present() call //NOTE(martin): command buffer and drawable are set on demand and at the end of each present() call
surface->drawable = nil; surface->drawable = nil;
surface->commandBuffer = nil; surface->commandBuffer = nil;
} }
} }
return((mg_surface_data*)surface); return((mg_surface_data*)surface);
} }
void* mg_mtl_surface_layer(mg_surface surface) void* mg_mtl_surface_layer(mg_surface surface)
{ {
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_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData; mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
return(mtlSurface->mtlLayer); return(mtlSurface->mtlLayer);
} }
else else
{ {
return(nil); return(nil);
} }
} }
void* mg_mtl_surface_drawable(mg_surface surface) void* mg_mtl_surface_drawable(mg_surface surface)
{ {
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_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData; mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
return(mtlSurface->drawable); return(mtlSurface->drawable);
} }
else else
{ {
return(nil); return(nil);
} }
} }
void* mg_mtl_surface_command_buffer(mg_surface surface) void* mg_mtl_surface_command_buffer(mg_surface surface)
{ {
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_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData; mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
return(mtlSurface->commandBuffer); return(mtlSurface->commandBuffer);
} }
else else
{ {
return(nil); return(nil);
} }
} }
#undef LOG_SUBSYSTEM #undef LOG_SUBSYSTEM

View File

@ -1,93 +1,93 @@
//***************************************************************** //*****************************************************************
// //
// $file: platform.h $ // $file: platform.h $
// $author: Martin Fouilleul $ // $author: Martin Fouilleul $
// $date: 22/12/2022 $ // $date: 22/12/2022 $
// $revision: $ // $revision: $
// $note: (C) 2022 by Martin Fouilleul - all rights reserved $ // $note: (C) 2022 by Martin Fouilleul - all rights reserved $
// //
//***************************************************************** //*****************************************************************
#ifndef __PLATFORM_H_ #ifndef __PLATFORM_H_
#define __PLATFORM_H_ #define __PLATFORM_H_
//----------------------------------------------------------------- //-----------------------------------------------------------------
// Compiler identification // Compiler identification
//----------------------------------------------------------------- //-----------------------------------------------------------------
#if defined(__clang__) #if defined(__clang__)
#define COMPILER_CLANG 1 #define COMPILER_CLANG 1
#if defined(__apple_build_version__) #if defined(__apple_build_version__)
#define COMPILER_CLANG_APPLE 1 #define COMPILER_CLANG_APPLE 1
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define COMPILER_CLANG_CL 1 #define COMPILER_CLANG_CL 1
#endif #endif
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define COMPILER_CL 1 #define COMPILER_CL 1
#elif defined(__GNUC__) #elif defined(__GNUC__)
#define COMPILER_GCC 1 #define COMPILER_GCC 1
#else #else
#error "Can't identify compiler" #error "Can't identify compiler"
#endif #endif
//----------------------------------------------------------------- //-----------------------------------------------------------------
// OS identification // OS identification
//----------------------------------------------------------------- //-----------------------------------------------------------------
#if defined(_WIN64) #if defined(_WIN64)
#define OS_WIN64 1 #define OS_WIN64 1
#elif defined(_WIN32) #elif defined(_WIN32)
#error "Unsupported OS (32bit only version of Windows)" #error "Unsupported OS (32bit only version of Windows)"
#elif defined(__APPLE__) && defined(__MACH__) #elif defined(__APPLE__) && defined(__MACH__)
#define OS_MACOS 1 #define OS_MACOS 1
#elif defined(__gnu_linux__) #elif defined(__gnu_linux__)
#define OS_LINUX 1 #define OS_LINUX 1
#else #else
#error "Can't identify OS" #error "Can't identify OS"
#endif #endif
//----------------------------------------------------------------- //-----------------------------------------------------------------
// Architecture identification // Architecture identification
//----------------------------------------------------------------- //-----------------------------------------------------------------
#if defined(COMPILER_CL) #if defined(COMPILER_CL)
#if defined(_M_AMD64) #if defined(_M_AMD64)
#define ARCH_X64 1 #define ARCH_X64 1
#elif defined(_M_I86) #elif defined(_M_I86)
#define ARCH_X86 1 #define ARCH_X86 1
#elif defined(_M_ARM64) #elif defined(_M_ARM64)
#define ARCH_ARM64 1 #define ARCH_ARM64 1
#elif defined(_M_ARM) #elif defined(_M_ARM)
#define ARCH_ARM32 1 #define ARCH_ARM32 1
#else #else
#error "Can't identify architecture" #error "Can't identify architecture"
#endif #endif
#else #else
#if defined(__x86_64__) #if defined(__x86_64__)
#define ARCH_X64 1 #define ARCH_X64 1
#elif defined(__i386__) #elif defined(__i386__)
#define ARCH_X86 1 #define ARCH_X86 1
#elif defined(__arm__) #elif defined(__arm__)
#define ARCH_ARM32 1 #define ARCH_ARM32 1
#elif defined(__aarch64__) #elif defined(__aarch64__)
#define ARCH_ARM64 1 #define ARCH_ARM64 1
#else #else
#error "Can't identify architecture" #error "Can't identify architecture"
#endif #endif
#endif #endif
//----------------------------------------------------------------- //-----------------------------------------------------------------
// platform helper macros // platform helper macros
//----------------------------------------------------------------- //-----------------------------------------------------------------
#if defined(COMPILER_CL) #if defined(COMPILER_CL)
#if defined(MP_BUILD_DLL) #if defined(MP_BUILD_DLL)
#define MP_API __declspec(dllexport) #define MP_API __declspec(dllexport)
#else #else
#define MP_API __declspec(dllimport) #define MP_API __declspec(dllimport)
#endif #endif
#define mp_thread_local __declspec(thread) #define mp_thread_local __declspec(thread)
#elif defined(COMPILER_GCC) || defined(COMPILER_CLANG) #elif defined(COMPILER_GCC) || defined(COMPILER_CLANG)
#define MP_API #define MP_API
#define mp_thread_local __thread #define mp_thread_local __thread
#endif #endif
#endif // __PLATFORM_H_ #endif // __PLATFORM_H_

View File

@ -1,34 +1,34 @@
/************************************************************//** /************************************************************//**
* *
* @file: platform_clock.h * @file: platform_clock.h
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 07/03/2019 * @date: 07/03/2019
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#ifndef __PLATFORM_CLOCK_H_ #ifndef __PLATFORM_CLOCK_H_
#define __PLATFORM_CLOCK_H_ #define __PLATFORM_CLOCK_H_
#include"typedefs.h" #include"typedefs.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif // __cplusplus #endif // __cplusplus
typedef enum { typedef enum {
MP_CLOCK_MONOTONIC, // clock that increment monotonically MP_CLOCK_MONOTONIC, // clock that increment monotonically
MP_CLOCK_UPTIME, // clock that increment monotonically during uptime MP_CLOCK_UPTIME, // clock that increment monotonically during uptime
MP_CLOCK_DATE // clock that is driven by the platform time MP_CLOCK_DATE // clock that is driven by the platform time
} mp_clock_kind; } mp_clock_kind;
MP_API void mp_clock_init(); // initialize the clock subsystem MP_API void mp_clock_init(); // initialize the clock subsystem
MP_API u64 mp_get_timestamp(mp_clock_kind clock); MP_API u64 mp_get_timestamp(mp_clock_kind clock);
MP_API f64 mp_get_time(mp_clock_kind clock); MP_API f64 mp_get_time(mp_clock_kind clock);
MP_API void mp_sleep_nanoseconds(u64 nanoseconds); // sleep for a given number of nanoseconds MP_API void mp_sleep_nanoseconds(u64 nanoseconds); // sleep for a given number of nanoseconds
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif // __cplusplus #endif // __cplusplus
#endif //__PLATFORM_CLOCK_H_ #endif //__PLATFORM_CLOCK_H_

View File

@ -1,38 +1,38 @@
/************************************************************//** /************************************************************//**
* *
* @file: win32_clock.c * @file: win32_clock.c
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 03/02/2023 * @date: 03/02/2023
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#include<profileapi.h> #include<profileapi.h>
#include"typedefs.h" #include"typedefs.h"
#include"platform_clock.h" #include"platform_clock.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
static u64 __performanceCounterFreq = 0; static u64 __performanceCounterFreq = 0;
void mp_clock_init() void mp_clock_init()
{ {
LARGE_INTEGER freq; LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq); QueryPerformanceFrequency(&freq);
__performanceCounterFreq = freq.QuadPart; __performanceCounterFreq = freq.QuadPart;
} }
f64 mp_get_time(mp_clock_kind clock) f64 mp_get_time(mp_clock_kind clock)
{ {
LARGE_INTEGER counter; LARGE_INTEGER counter;
QueryPerformanceCounter(&counter); QueryPerformanceCounter(&counter);
f64 time = __performanceCounterFreq ? (counter.QuadPart / (f64)__performanceCounterFreq) : 0; f64 time = __performanceCounterFreq ? (counter.QuadPart / (f64)__performanceCounterFreq) : 0;
return(time); return(time);
} }
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View File

@ -1,98 +1,98 @@
/************************************************************//** /************************************************************//**
* *
* @file: debug_log.h * @file: debug_log.h
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 05/04/2019 * @date: 05/04/2019
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#ifndef __DEBUG_LOG_H_ #ifndef __DEBUG_LOG_H_
#define __DEBUG_LOG_H_ #define __DEBUG_LOG_H_
#include<stdio.h> #include<stdio.h>
#include"platform.h" #include"platform.h"
#include"typedefs.h" #include"typedefs.h"
#include"macro_helpers.h" #include"macro_helpers.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
//NOTE(martin): the default logging level can be adjusted by defining LOG_DEFAULT_LEVEL. As the name suggest, it is the default, but it //NOTE(martin): the default logging level can be adjusted by defining LOG_DEFAULT_LEVEL. As the name suggest, it is the default, but it
// can be adjusted at runtime with LogLevel() // can be adjusted at runtime with LogLevel()
#ifndef LOG_DEFAULT_LEVEL #ifndef LOG_DEFAULT_LEVEL
#define LOG_DEFAULT_LEVEL LOG_LEVEL_WARNING #define LOG_DEFAULT_LEVEL LOG_LEVEL_WARNING
#endif #endif
//NOTE(martin): the default output can be adjusted by defining LOG_DEFAULT_OUTPUT. It can be adjusted at runtime with LogOutput() //NOTE(martin): the default output can be adjusted by defining LOG_DEFAULT_OUTPUT. It can be adjusted at runtime with LogOutput()
#ifndef LOG_DEFAULT_OUTPUT #ifndef LOG_DEFAULT_OUTPUT
#define LOG_DEFAULT_OUTPUT stdout #define LOG_DEFAULT_OUTPUT stdout
#endif #endif
//NOTE(martin): LOG_SUBSYSTEM can be defined in each compilation unit to associate it with a subsystem, like this: //NOTE(martin): LOG_SUBSYSTEM can be defined in each compilation unit to associate it with a subsystem, like this:
// #define LOG_SUBSYSTEM "name" // #define LOG_SUBSYSTEM "name"
typedef enum { LOG_LEVEL_ERROR, typedef enum { LOG_LEVEL_ERROR,
LOG_LEVEL_WARNING, LOG_LEVEL_WARNING,
LOG_LEVEL_MESSAGE, LOG_LEVEL_MESSAGE,
LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG,
LOG_LEVEL_COUNT } log_level; LOG_LEVEL_COUNT } log_level;
MP_API void LogGeneric(log_level level, MP_API void LogGeneric(log_level level,
const char* subsystem, const char* subsystem,
const char* functionName, const char* functionName,
const char* fileName, const char* fileName,
u32 line, u32 line,
const char* msg, const char* msg,
...); ...);
MP_API void LogOutput(FILE* output); MP_API void LogOutput(FILE* output);
MP_API void LogLevel(log_level level); MP_API void LogLevel(log_level level);
MP_API void LogFilter(const char* subsystem, log_level level); MP_API void LogFilter(const char* subsystem, log_level level);
#define LOG_GENERIC(level, func, file, line, msg, ...) LogGeneric(level, LOG_SUBSYSTEM, func, file, line, msg, ##__VA_ARGS__ ) #define LOG_GENERIC(level, func, file, line, msg, ...) LogGeneric(level, LOG_SUBSYSTEM, func, file, line, msg, ##__VA_ARGS__ )
#define LOG_ERROR(msg, ...) LOG_GENERIC(LOG_LEVEL_ERROR, __FUNCTION__, __FILE__, __LINE__, msg, ##__VA_ARGS__ ) #define LOG_ERROR(msg, ...) LOG_GENERIC(LOG_LEVEL_ERROR, __FUNCTION__, __FILE__, __LINE__, msg, ##__VA_ARGS__ )
//NOTE(martin): warnings, messages, and debug info can be enabled in debug mode by defining LOG_COMPILE_XXX, XXX being the max desired log level //NOTE(martin): warnings, messages, and debug info can be enabled in debug mode by defining LOG_COMPILE_XXX, XXX being the max desired log level
// error logging is always compiled // error logging is always compiled
#if defined(LOG_COMPILE_WARNING) || defined(LOG_COMPILE_MESSAGE) || defined(LOG_COMPILE_DEBUG) #if defined(LOG_COMPILE_WARNING) || defined(LOG_COMPILE_MESSAGE) || defined(LOG_COMPILE_DEBUG)
#define LOG_WARNING(msg, ...) LOG_GENERIC(LOG_LEVEL_WARNING, __FUNCTION__, __FILE__, __LINE__, msg, ##__VA_ARGS__ ) #define LOG_WARNING(msg, ...) LOG_GENERIC(LOG_LEVEL_WARNING, __FUNCTION__, __FILE__, __LINE__, msg, ##__VA_ARGS__ )
#if defined(LOG_COMPILE_MESSAGE) || defined(LOG_COMPILE_DEBUG) #if defined(LOG_COMPILE_MESSAGE) || defined(LOG_COMPILE_DEBUG)
#define LOG_MESSAGE(msg, ...) LOG_GENERIC(LOG_LEVEL_MESSAGE, __FUNCTION__, __FILE__, __LINE__, msg, ##__VA_ARGS__ ) #define LOG_MESSAGE(msg, ...) LOG_GENERIC(LOG_LEVEL_MESSAGE, __FUNCTION__, __FILE__, __LINE__, msg, ##__VA_ARGS__ )
#if defined(LOG_COMPILE_DEBUG) #if defined(LOG_COMPILE_DEBUG)
#define LOG_DEBUG(msg, ...) LOG_GENERIC(LOG_LEVEL_DEBUG, __FUNCTION__, __FILE__, __LINE__, msg, ##__VA_ARGS__ ) #define LOG_DEBUG(msg, ...) LOG_GENERIC(LOG_LEVEL_DEBUG, __FUNCTION__, __FILE__, __LINE__, msg, ##__VA_ARGS__ )
#else #else
#define LOG_DEBUG(msg, ...) #define LOG_DEBUG(msg, ...)
#endif #endif
#else #else
#define LOG_MESSAGE(msg, ...) #define LOG_MESSAGE(msg, ...)
#define LOG_DEBUG(msg, ...) #define LOG_DEBUG(msg, ...)
#endif #endif
#else #else
#define LOG_WARNING(msg, ...) #define LOG_WARNING(msg, ...)
#define LOG_MESSAGE(msg, ...) #define LOG_MESSAGE(msg, ...)
#define LOG_DEBUG(msg, ...) #define LOG_DEBUG(msg, ...)
#endif #endif
#ifndef NO_ASSERT #ifndef NO_ASSERT
#include<assert.h> #include<assert.h>
#define _ASSERT_(x, msg) assert(x && msg) #define _ASSERT_(x, msg) assert(x && msg)
#define ASSERT(x, ...) _ASSERT_(x, #__VA_ARGS__) #define ASSERT(x, ...) _ASSERT_(x, #__VA_ARGS__)
#ifdef DEBUG #ifdef DEBUG
#define DEBUG_ASSERT(x, ...) ASSERT(x, ##__VA_ARGS__ ) #define DEBUG_ASSERT(x, ...) ASSERT(x, ##__VA_ARGS__ )
#else #else
#define DEBUG_ASSERT(x, ...) #define DEBUG_ASSERT(x, ...)
#endif #endif
#else #else
#define ASSERT(x, ...) #define ASSERT(x, ...)
#define DEBUG_ASSERT(x, ...) #define DEBUG_ASSERT(x, ...)
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
#endif //__DEBUG_LOG_H_ #endif //__DEBUG_LOG_H_

View File

@ -1,29 +1,29 @@
/************************************************************//** /************************************************************//**
* *
* @file: hash.h * @file: hash.h
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 08/08/2022 * @date: 08/08/2022
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#ifndef __HASH_H_ #ifndef __HASH_H_
#define __HASH_H_ #define __HASH_H_
#include"typedefs.h" #include"typedefs.h"
#include"strings.h" #include"strings.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
MP_API u64 mp_hash_aes_u64(u64 x); MP_API u64 mp_hash_aes_u64(u64 x);
MP_API u64 mp_hash_aes_u64_x2(u64 x, u64 y); MP_API u64 mp_hash_aes_u64_x2(u64 x, u64 y);
MP_API u64 mp_hash_aes_string(str8 string); MP_API u64 mp_hash_aes_string(str8 string);
MP_API u64 mp_hash_aes_string_seed(str8 string, u64 seed); MP_API u64 mp_hash_aes_string_seed(str8 string, u64 seed);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
#endif //__HASH_H_ #endif //__HASH_H_

View File

@ -1,106 +1,106 @@
/************************************************************//** /************************************************************//**
* *
* @file: memory.h * @file: memory.h
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 24/10/2019 * @date: 24/10/2019
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#ifndef __MEMORY_H_ #ifndef __MEMORY_H_
#define __MEMORY_H_ #define __MEMORY_H_
#include"typedefs.h" #include"typedefs.h"
#include"lists.h" #include"lists.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
//NOTE(martin): base allocator //NOTE(martin): base allocator
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
typedef void*(*mem_reserve_function)(void* context, u64 size); typedef void*(*mem_reserve_function)(void* context, u64 size);
typedef void(*mem_modify_function)(void* context, void* ptr, u64 size); typedef void(*mem_modify_function)(void* context, void* ptr, u64 size);
typedef struct mem_base_allocator typedef struct mem_base_allocator
{ {
mem_reserve_function reserve; mem_reserve_function reserve;
mem_modify_function commit; mem_modify_function commit;
mem_modify_function decommit; mem_modify_function decommit;
mem_modify_function release; mem_modify_function release;
void* context; void* context;
} mem_base_allocator; } mem_base_allocator;
MP_API mem_base_allocator* mem_base_allocator_default(); MP_API mem_base_allocator* mem_base_allocator_default();
#define mem_base_reserve(base, size) base->reserve(base->context, size) #define mem_base_reserve(base, size) base->reserve(base->context, size)
#define mem_base_commit(base, ptr, size) base->commit(base->context, ptr, size) #define mem_base_commit(base, ptr, size) base->commit(base->context, ptr, size)
#define mem_base_decommit(base, ptr, size) base->decommit(base->context, ptr, size) #define mem_base_decommit(base, ptr, size) base->decommit(base->context, ptr, size)
#define mem_base_release(base, ptr, size) base->release(base->context, ptr, size) #define mem_base_release(base, ptr, size) base->release(base->context, ptr, size)
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
//NOTE(martin): memory arena //NOTE(martin): memory arena
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
typedef struct mem_arena typedef struct mem_arena
{ {
mem_base_allocator* base; mem_base_allocator* base;
char* ptr; char* ptr;
u64 offset; u64 offset;
u64 committed; u64 committed;
u64 cap; u64 cap;
} mem_arena; } mem_arena;
typedef struct mem_arena_options typedef struct mem_arena_options
{ {
mem_base_allocator* base; mem_base_allocator* base;
u64 reserve; u64 reserve;
} mem_arena_options; } mem_arena_options;
MP_API void mem_arena_init(mem_arena* arena); MP_API void mem_arena_init(mem_arena* arena);
MP_API void mem_arena_init_with_options(mem_arena* arena, mem_arena_options* options); MP_API void mem_arena_init_with_options(mem_arena* arena, mem_arena_options* options);
MP_API void mem_arena_release(mem_arena* arena); MP_API void mem_arena_release(mem_arena* arena);
MP_API void* mem_arena_alloc(mem_arena* arena, u64 size); MP_API void* mem_arena_alloc(mem_arena* arena, u64 size);
MP_API void mem_arena_clear(mem_arena* arena); MP_API void mem_arena_clear(mem_arena* arena);
#define mem_arena_alloc_type(arena, type) ((type*)mem_arena_alloc(arena, sizeof(type))) #define mem_arena_alloc_type(arena, type) ((type*)mem_arena_alloc(arena, sizeof(type)))
#define mem_arena_alloc_array(arena, type, count) ((type*)mem_arena_alloc(arena, sizeof(type)*(count))) #define mem_arena_alloc_array(arena, type, count) ((type*)mem_arena_alloc(arena, sizeof(type)*(count)))
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
//NOTE(martin): memory pool //NOTE(martin): memory pool
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
typedef struct mem_pool typedef struct mem_pool
{ {
mem_arena arena; mem_arena arena;
list_info freeList; list_info freeList;
u64 blockSize; u64 blockSize;
} mem_pool; } mem_pool;
typedef struct mem_pool_options typedef struct mem_pool_options
{ {
mem_base_allocator* base; mem_base_allocator* base;
u64 reserve; u64 reserve;
} mem_pool_options; } mem_pool_options;
MP_API void mem_pool_init(mem_pool* pool, u64 blockSize); MP_API void mem_pool_init(mem_pool* pool, u64 blockSize);
MP_API void mem_pool_init_with_options(mem_pool* pool, u64 blockSize, mem_pool_options* options); MP_API void mem_pool_init_with_options(mem_pool* pool, u64 blockSize, mem_pool_options* options);
MP_API void mem_pool_release(mem_pool* pool); MP_API void mem_pool_release(mem_pool* pool);
MP_API void* mem_pool_alloc(mem_pool* pool); MP_API void* mem_pool_alloc(mem_pool* pool);
MP_API void mem_pool_recycle(mem_pool* pool, void* ptr); MP_API void mem_pool_recycle(mem_pool* pool, void* ptr);
MP_API void mem_pool_clear(mem_pool* pool); MP_API void mem_pool_clear(mem_pool* pool);
#define mem_pool_alloc_type(arena, type) ((type*)mem_pool_alloc(arena)) #define mem_pool_alloc_type(arena, type) ((type*)mem_pool_alloc(arena))
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
//NOTE(martin): per-thread implicit scratch arena //NOTE(martin): per-thread implicit scratch arena
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
MP_API void mem_scratch_clear(); MP_API void mem_scratch_clear();
MP_API mem_arena* mem_scratch(); MP_API mem_arena* mem_scratch();
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
#endif //__MEMORY_H_ #endif //__MEMORY_H_

View File

@ -1,113 +1,113 @@
/************************************************************//** /************************************************************//**
* *
* @file: strings.h * @file: strings.h
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 29/05/2021 * @date: 29/05/2021
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#ifndef __STRINGS_H_ #ifndef __STRINGS_H_
#define __STRINGS_H_ #define __STRINGS_H_
#include"typedefs.h" #include"typedefs.h"
#include"lists.h" #include"lists.h"
#include"memory.h" #include"memory.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// string slices as values // string slices as values
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
typedef struct str8 typedef struct str8
{ {
u64 len; u64 len;
char* ptr; char* ptr;
} str8; } str8;
#define str8_lit(s) ((str8){.len = sizeof(s)-1, .ptr = (char*)(s)}) #define str8_lit(s) ((str8){.len = sizeof(s)-1, .ptr = (char*)(s)})
#define str8_unbox(s) (int)((s).len), ((s).ptr) #define str8_unbox(s) (int)((s).len), ((s).ptr)
MP_API str8 str8_from_buffer(u64 len, char* buffer); MP_API str8 str8_from_buffer(u64 len, char* buffer);
MP_API str8 str8_from_cstring(char* str); MP_API str8 str8_from_cstring(char* str);
MP_API str8 str8_slice(str8 s, u64 start, u64 end); MP_API str8 str8_slice(str8 s, u64 start, u64 end);
MP_API str8 str8_push_buffer(mem_arena* arena, u64 len, char* buffer); MP_API str8 str8_push_buffer(mem_arena* arena, u64 len, char* buffer);
MP_API str8 str8_push_cstring(mem_arena* arena, const char* str); MP_API str8 str8_push_cstring(mem_arena* arena, const char* str);
MP_API str8 str8_push_copy(mem_arena* arena, str8 s); MP_API str8 str8_push_copy(mem_arena* arena, str8 s);
MP_API str8 str8_push_slice(mem_arena* arena, str8 s, u64 start, u64 end); MP_API str8 str8_push_slice(mem_arena* arena, str8 s, u64 start, u64 end);
MP_API str8 str8_pushfv(mem_arena* arena, const char* format, va_list args); MP_API str8 str8_pushfv(mem_arena* arena, const char* format, va_list args);
MP_API str8 str8_pushf(mem_arena* arena, const char* format, ...); MP_API str8 str8_pushf(mem_arena* arena, const char* format, ...);
MP_API int str8_cmp(str8 s1, str8 s2); MP_API int str8_cmp(str8 s1, str8 s2);
MP_API char* str8_to_cstring(mem_arena* arena, str8 string); MP_API char* str8_to_cstring(mem_arena* arena, str8 string);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// string lists // string lists
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
typedef struct str8_elt typedef struct str8_elt
{ {
list_elt listElt; list_elt listElt;
str8 string; str8 string;
} str8_elt; } str8_elt;
typedef struct str8_list typedef struct str8_list
{ {
list_info list; list_info list;
u64 eltCount; u64 eltCount;
u64 len; u64 len;
} str8_list; } str8_list;
MP_API void str8_list_push(mem_arena* arena, str8_list* list, str8 str); MP_API void str8_list_push(mem_arena* arena, str8_list* list, str8 str);
MP_API void str8_list_pushf(mem_arena* arena, str8_list* list, const char* format, ...); MP_API void str8_list_pushf(mem_arena* arena, str8_list* list, const char* format, ...);
MP_API str8 str8_list_join(mem_arena* arena, str8_list list); MP_API str8 str8_list_join(mem_arena* arena, str8_list list);
MP_API str8_list str8_split(mem_arena* arena, str8 str, str8_list separators); MP_API str8_list str8_split(mem_arena* arena, str8 str, str8_list separators);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// u32 strings // u32 strings
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
typedef struct str32 typedef struct str32
{ {
u64 len; u64 len;
u32* ptr; u32* ptr;
} str32; } str32;
MP_API str32 str32_from_buffer(u64 len, u32* buffer); MP_API str32 str32_from_buffer(u64 len, u32* buffer);
MP_API str32 str32_slice(str32 s, u64 start, u64 end); MP_API str32 str32_slice(str32 s, u64 start, u64 end);
MP_API str32 str32_push_buffer(mem_arena* arena, u64 len, u32* buffer); MP_API str32 str32_push_buffer(mem_arena* arena, u64 len, u32* buffer);
MP_API str32 str32_push_copy(mem_arena* arena, str32 s); MP_API str32 str32_push_copy(mem_arena* arena, str32 s);
MP_API str32 str32_push_slice(mem_arena* arena, str32 s, u64 start, u64 end); MP_API str32 str32_push_slice(mem_arena* arena, str32 s, u64 start, u64 end);
typedef struct str32_elt typedef struct str32_elt
{ {
list_elt listElt; list_elt listElt;
str32 string; str32 string;
} str32_elt; } str32_elt;
typedef struct str32_list typedef struct str32_list
{ {
list_info list; list_info list;
u64 eltCount; u64 eltCount;
u64 len; u64 len;
} str32_list; } str32_list;
MP_API void str32_list_push(mem_arena* arena, str32_list* list, str32 str); MP_API void str32_list_push(mem_arena* arena, str32_list* list, str32 str);
MP_API str32 str32_list_join(mem_arena* arena, str32_list list); MP_API str32 str32_list_join(mem_arena* arena, str32_list list);
MP_API str32_list str32_split(mem_arena* arena, str32 str, str32_list separators); MP_API str32_list str32_split(mem_arena* arena, str32 str, str32_list separators);
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Paths helpers // Paths helpers
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
MP_API str8 mp_path_directory(str8 fullPath); MP_API str8 mp_path_directory(str8 fullPath);
MP_API str8 mp_path_base_name(str8 fullPath); MP_API str8 mp_path_base_name(str8 fullPath);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
#endif //__STRINGS_H_ #endif //__STRINGS_H_

View File

@ -1,284 +1,284 @@
//***************************************************************** //*****************************************************************
// //
// $file: utf8.c $ // $file: utf8.c $
// $author: Martin Fouilleul $ // $author: Martin Fouilleul $
// $date: 05/11/2016 $ // $date: 05/11/2016 $
// $revision: $ // $revision: $
// $note: (C) 2016 by Martin Fouilleul - all rights reserved $ // $note: (C) 2016 by Martin Fouilleul - all rights reserved $
// //
//***************************************************************** //*****************************************************************
#include"utf8.h" #include"utf8.h"
#include"platform.h" #include"platform.h"
#include<string.h> #include<string.h>
//----------------------------------------------------------------- //-----------------------------------------------------------------
// utf-8 gore // utf-8 gore
//----------------------------------------------------------------- //-----------------------------------------------------------------
const u32 offsetsFromUTF8[6] = { const u32 offsetsFromUTF8[6] = {
0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL }; 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
const char trailingBytesForUTF8[256] = { const char trailingBytesForUTF8[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
}; };
#define utf8_is_start_byte(c) (((c)&0xc0)!=0x80) #define utf8_is_start_byte(c) (((c)&0xc0)!=0x80)
//----------------------------------------------------------------- //-----------------------------------------------------------------
//NOTE: getting sizes / offsets / indices //NOTE: getting sizes / offsets / indices
//----------------------------------------------------------------- //-----------------------------------------------------------------
u32 utf8_size_from_leading_char(char leadingChar) u32 utf8_size_from_leading_char(char leadingChar)
{ {
return(trailingBytesForUTF8[(unsigned int)(unsigned char)leadingChar] + 1); return(trailingBytesForUTF8[(unsigned int)(unsigned char)leadingChar] + 1);
} }
u32 utf8_codepoint_size(utf32 codePoint) u32 utf8_codepoint_size(utf32 codePoint)
{ {
if(codePoint < 0x80) if(codePoint < 0x80)
{ {
return(1); return(1);
} }
if(codePoint < 0x800) if(codePoint < 0x800)
{ {
return(2); return(2);
} }
if(codePoint < 0x10000) if(codePoint < 0x10000)
{ {
return(3); return(3);
} }
if(codePoint < 0x110000) if(codePoint < 0x110000)
{ {
return(4); return(4);
} }
return(0); return(0);
} }
u64 utf8_codepoint_count_for_string(str8 string) u64 utf8_codepoint_count_for_string(str8 string)
{ {
u64 byteOffset = 0; u64 byteOffset = 0;
u64 codePointIndex = 0; u64 codePointIndex = 0;
for(; for(;
(byteOffset < string.len) && (string.ptr[byteOffset] != 0); (byteOffset < string.len) && (string.ptr[byteOffset] != 0);
codePointIndex++) codePointIndex++)
{ {
utf8_dec decode = utf8_decode_at(string, byteOffset); utf8_dec decode = utf8_decode_at(string, byteOffset);
byteOffset += decode.size; byteOffset += decode.size;
} }
return(codePointIndex); return(codePointIndex);
} }
u64 utf8_byte_count_for_codepoints(str32 codePoints) u64 utf8_byte_count_for_codepoints(str32 codePoints)
{ {
//NOTE(martin): return the exact number of bytes taken by the encoded //NOTE(martin): return the exact number of bytes taken by the encoded
// version of codePoints. (ie do not attempt to provision // version of codePoints. (ie do not attempt to provision
// for a zero terminator). // for a zero terminator).
u64 byteCount = 0; u64 byteCount = 0;
for(u64 i=0; i<codePoints.len; i++) for(u64 i=0; i<codePoints.len; i++)
{ {
byteCount += utf8_codepoint_size(codePoints.ptr[i]); byteCount += utf8_codepoint_size(codePoints.ptr[i]);
} }
return(byteCount); return(byteCount);
} }
u64 utf8_next_offset(str8 string, u64 byteOffset) u64 utf8_next_offset(str8 string, u64 byteOffset)
{ {
u64 res = 0; u64 res = 0;
if(byteOffset >= string.len) if(byteOffset >= string.len)
{ {
res = string.len; res = string.len;
} }
else else
{ {
u64 nextOffset = byteOffset + utf8_size_from_leading_char(string.ptr[byteOffset]); u64 nextOffset = byteOffset + utf8_size_from_leading_char(string.ptr[byteOffset]);
res = minimum(nextOffset, string.len); res = minimum(nextOffset, string.len);
} }
return(res); return(res);
} }
u64 utf8_prev_offset(str8 string, u64 byteOffset) u64 utf8_prev_offset(str8 string, u64 byteOffset)
{ {
u64 res = 0; u64 res = 0;
if(byteOffset > string.len) if(byteOffset > string.len)
{ {
res = string.len; res = string.len;
} }
else if(byteOffset) else if(byteOffset)
{ {
byteOffset--; byteOffset--;
while(byteOffset > 0 && !utf8_is_start_byte(string.ptr[byteOffset])) while(byteOffset > 0 && !utf8_is_start_byte(string.ptr[byteOffset]))
{ {
byteOffset--; byteOffset--;
} }
res = byteOffset; res = byteOffset;
} }
return(res); return(res);
} }
//----------------------------------------------------------------- //-----------------------------------------------------------------
//NOTE: encoding / decoding //NOTE: encoding / decoding
//----------------------------------------------------------------- //-----------------------------------------------------------------
utf8_dec utf8_decode_at(str8 string, u64 offset) utf8_dec utf8_decode_at(str8 string, u64 offset)
{ {
//NOTE(martin): get the first codepoint in str, and advance index to the //NOTE(martin): get the first codepoint in str, and advance index to the
// next utf8 character // next utf8 character
//TODO(martin): check for utf-16 surrogate pairs //TODO(martin): check for utf-16 surrogate pairs
utf32 cp = 0; utf32 cp = 0;
u64 sz = 0; u64 sz = 0;
if(offset >= string.len || !string.ptr[offset]) if(offset >= string.len || !string.ptr[offset])
{ {
cp = 0; cp = 0;
sz = 1; sz = 1;
} }
else if( !utf8_is_start_byte(string.ptr[offset])) else if( !utf8_is_start_byte(string.ptr[offset]))
{ {
//NOTE(martin): unexpected continuation or invalid character. //NOTE(martin): unexpected continuation or invalid character.
cp = 0xfffd; cp = 0xfffd;
sz = 1; sz = 1;
} }
else else
{ {
int expectedSize = utf8_size_from_leading_char(string.ptr[offset]); int expectedSize = utf8_size_from_leading_char(string.ptr[offset]);
do do
{ {
/*NOTE(martin): /*NOTE(martin):
we shift 6 bits and add the next byte at each round. we shift 6 bits and add the next byte at each round.
at the end we have our utf8 codepoint, added to the shifted versions at the end we have our utf8 codepoint, added to the shifted versions
of the utf8 leading bits for each encoded byte. These values are of the utf8 leading bits for each encoded byte. These values are
precomputed in offsetsFromUTF8. precomputed in offsetsFromUTF8.
*/ */
unsigned char b = string.ptr[offset]; unsigned char b = string.ptr[offset];
cp <<= 6; cp <<= 6;
cp += b; cp += b;
offset += 1; offset += 1;
sz++; sz++;
if(b == 0xc0 || b == 0xc1 || b >= 0xc5) if(b == 0xc0 || b == 0xc1 || b >= 0xc5)
{ {
//NOTE(martin): invalid byte encountered //NOTE(martin): invalid byte encountered
break; break;
} }
} while( offset < string.len } while( offset < string.len
&& string.ptr[offset] && string.ptr[offset]
&& !utf8_is_start_byte(string.ptr[offset]) && !utf8_is_start_byte(string.ptr[offset])
&& sz < expectedSize); && sz < expectedSize);
if(sz != expectedSize) if(sz != expectedSize)
{ {
//NOTE(martin): if we encountered an error, we return the replacement codepoint U+FFFD //NOTE(martin): if we encountered an error, we return the replacement codepoint U+FFFD
cp = 0xfffd; cp = 0xfffd;
} }
else else
{ {
cp -= offsetsFromUTF8[sz-1]; cp -= offsetsFromUTF8[sz-1];
//NOTE(martin): check for invalid codepoints //NOTE(martin): check for invalid codepoints
if(cp > 0x10ffff || (cp >= 0xd800 && cp <= 0xdfff)) if(cp > 0x10ffff || (cp >= 0xd800 && cp <= 0xdfff))
{ {
cp = 0xfffd; cp = 0xfffd;
} }
} }
} }
utf8_dec res = {.codepoint = cp, .size = sz}; utf8_dec res = {.codepoint = cp, .size = sz};
return(res); return(res);
} }
utf8_dec utf8_decode(str8 string) utf8_dec utf8_decode(str8 string)
{ {
return(utf8_decode_at(string, 0)); return(utf8_decode_at(string, 0));
} }
str8 utf8_encode(char* dest, utf32 codePoint) str8 utf8_encode(char* dest, utf32 codePoint)
{ {
u64 sz = 0; u64 sz = 0;
if (codePoint < 0x80) if (codePoint < 0x80)
{ {
dest[0] = (char)codePoint; dest[0] = (char)codePoint;
sz = 1; sz = 1;
} }
else if (codePoint < 0x800) else if (codePoint < 0x800)
{ {
dest[0] = (codePoint>>6) | 0xC0; dest[0] = (codePoint>>6) | 0xC0;
dest[1] = (codePoint & 0x3F) | 0x80; dest[1] = (codePoint & 0x3F) | 0x80;
sz = 2; sz = 2;
} }
else if (codePoint < 0x10000) else if (codePoint < 0x10000)
{ {
dest[0] = (codePoint>>12) | 0xE0; dest[0] = (codePoint>>12) | 0xE0;
dest[1] = ((codePoint>>6) & 0x3F) | 0x80; dest[1] = ((codePoint>>6) & 0x3F) | 0x80;
dest[2] = (codePoint & 0x3F) | 0x80; dest[2] = (codePoint & 0x3F) | 0x80;
sz = 3; sz = 3;
} }
else if (codePoint < 0x110000) else if (codePoint < 0x110000)
{ {
dest[0] = (codePoint>>18) | 0xF0; dest[0] = (codePoint>>18) | 0xF0;
dest[1] = ((codePoint>>12) & 0x3F) | 0x80; dest[1] = ((codePoint>>12) & 0x3F) | 0x80;
dest[2] = ((codePoint>>6) & 0x3F) | 0x80; dest[2] = ((codePoint>>6) & 0x3F) | 0x80;
dest[3] = (codePoint & 0x3F) | 0x80; dest[3] = (codePoint & 0x3F) | 0x80;
sz = 4; sz = 4;
} }
str8 res = {.len = sz, .ptr = dest}; str8 res = {.len = sz, .ptr = dest};
return(res); return(res);
} }
str32 utf8_to_codepoints(u64 maxCount, utf32* backing, str8 string) str32 utf8_to_codepoints(u64 maxCount, utf32* backing, str8 string)
{ {
u64 codePointIndex = 0; u64 codePointIndex = 0;
u64 byteOffset = 0; u64 byteOffset = 0;
for(; codePointIndex < maxCount && byteOffset < string.len; codePointIndex++) for(; codePointIndex < maxCount && byteOffset < string.len; codePointIndex++)
{ {
utf8_dec decode = utf8_decode_at(string, byteOffset); utf8_dec decode = utf8_decode_at(string, byteOffset);
backing[codePointIndex] = decode.codepoint; backing[codePointIndex] = decode.codepoint;
byteOffset += decode.size; byteOffset += decode.size;
} }
str32 res = {.len = codePointIndex, .ptr = backing}; str32 res = {.len = codePointIndex, .ptr = backing};
return(res); return(res);
} }
str8 utf8_from_codepoints(u64 maxBytes, char* backing, str32 codePoints) str8 utf8_from_codepoints(u64 maxBytes, char* backing, str32 codePoints)
{ {
u64 byteOffset = 0; u64 byteOffset = 0;
for(u64 codePointIndex = 0; (codePointIndex < codePoints.len); codePointIndex++) for(u64 codePointIndex = 0; (codePointIndex < codePoints.len); codePointIndex++)
{ {
utf32 codePoint = codePoints.ptr[codePointIndex]; utf32 codePoint = codePoints.ptr[codePointIndex];
u32 byteCount = utf8_codepoint_size(codePoint); u32 byteCount = utf8_codepoint_size(codePoint);
if(byteOffset + byteCount > maxBytes) if(byteOffset + byteCount > maxBytes)
{ {
break; break;
} }
utf8_encode(backing+byteOffset, codePoint); utf8_encode(backing+byteOffset, codePoint);
byteOffset += byteCount; byteOffset += byteCount;
} }
str8 res = {.len = byteOffset, .ptr = backing}; str8 res = {.len = byteOffset, .ptr = backing};
return(res); return(res);
} }
str32 utf8_push_to_codepoints(mem_arena* arena, str8 string) str32 utf8_push_to_codepoints(mem_arena* arena, str8 string)
{ {
u64 count = utf8_codepoint_count_for_string(string); u64 count = utf8_codepoint_count_for_string(string);
utf32* backing = mem_arena_alloc_array(arena, utf32, count); utf32* backing = mem_arena_alloc_array(arena, utf32, count);
str32 res = utf8_to_codepoints(count, backing, string); str32 res = utf8_to_codepoints(count, backing, string);
return(res); return(res);
} }
str8 utf8_push_from_codepoints(mem_arena* arena, str32 codePoints) str8 utf8_push_from_codepoints(mem_arena* arena, str32 codePoints)
{ {
u64 count = utf8_byte_count_for_codepoints(codePoints); u64 count = utf8_byte_count_for_codepoints(codePoints);
char* backing = mem_arena_alloc_array(arena, char, count); char* backing = mem_arena_alloc_array(arena, char, count);
str8 res = utf8_from_codepoints(count, backing, codePoints); str8 res = utf8_from_codepoints(count, backing, codePoints);
return(res); return(res);
} }
#define UNICODE_RANGE(start, cnt, name) MP_API const unicode_range _cat2_(UNICODE_RANGE_, name) = { .firstCodePoint = start, .count = cnt }; #define UNICODE_RANGE(start, cnt, name) MP_API const unicode_range _cat2_(UNICODE_RANGE_, name) = { .firstCodePoint = start, .count = cnt };
UNICODE_RANGES UNICODE_RANGES
#undef UNICODE_RANGE #undef UNICODE_RANGE

View File

@ -1,201 +1,201 @@
//***************************************************************** //*****************************************************************
// //
// $file: utf8.h $ // $file: utf8.h $
// $author: Martin Fouilleul $ // $author: Martin Fouilleul $
// $date: 05/11/2016 $ // $date: 05/11/2016 $
// $revision: $ // $revision: $
// $note: (C) 2016 by Martin Fouilleul - all rights reserved $ // $note: (C) 2016 by Martin Fouilleul - all rights reserved $
// //
//***************************************************************** //*****************************************************************
#ifndef __UTF8_H_ #ifndef __UTF8_H_
#define __UTF8_H_ #define __UTF8_H_
#include"typedefs.h" #include"typedefs.h"
#include"macro_helpers.h" #include"macro_helpers.h"
#include"strings.h" #include"strings.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef u32 utf32; typedef u32 utf32;
//----------------------------------------------------------------- //-----------------------------------------------------------------
//NOTE: getting sizes / offsets / indices //NOTE: getting sizes / offsets / indices
//----------------------------------------------------------------- //-----------------------------------------------------------------
MP_API u32 utf8_size_from_leading_char(char leadingChar); MP_API u32 utf8_size_from_leading_char(char leadingChar);
MP_API u32 utf8_codepoint_size(utf32 codePoint); MP_API u32 utf8_codepoint_size(utf32 codePoint);
MP_API u64 utf8_codepoint_count_for_string(str8 string); MP_API u64 utf8_codepoint_count_for_string(str8 string);
MP_API u64 utf8_byte_count_for_codepoints(str32 codePoints); MP_API u64 utf8_byte_count_for_codepoints(str32 codePoints);
MP_API u64 utf8_next_offset(str8 string, u64 byteOffset); MP_API u64 utf8_next_offset(str8 string, u64 byteOffset);
MP_API u64 utf8_prev_offset(str8 string, u64 byteOffset); MP_API u64 utf8_prev_offset(str8 string, u64 byteOffset);
//----------------------------------------------------------------- //-----------------------------------------------------------------
//NOTE: encoding / decoding //NOTE: encoding / decoding
//----------------------------------------------------------------- //-----------------------------------------------------------------
typedef struct utf8_dec typedef struct utf8_dec
{ {
utf32 codepoint; //NOTE: decoded codepoint utf32 codepoint; //NOTE: decoded codepoint
u32 size; //NOTE: size of corresponding utf8 sequence u32 size; //NOTE: size of corresponding utf8 sequence
} utf8_dec; } utf8_dec;
MP_API utf8_dec utf8_decode(str8 string); //NOTE: decode a single utf8 sequence at start of string MP_API utf8_dec utf8_decode(str8 string); //NOTE: decode a single utf8 sequence at start of string
MP_API utf8_dec utf8_decode_at(str8 string, u64 offset); //NOTE: decode a single utf8 sequence starting at byte offset MP_API utf8_dec utf8_decode_at(str8 string, u64 offset); //NOTE: decode a single utf8 sequence starting at byte offset
MP_API str8 utf8_encode(char* dst, utf32 codePoint); //NOTE: encode codepoint into backing buffer dst MP_API str8 utf8_encode(char* dst, utf32 codePoint); //NOTE: encode codepoint into backing buffer dst
MP_API str32 utf8_to_codepoints(u64 maxCount, utf32* backing, str8 string); MP_API str32 utf8_to_codepoints(u64 maxCount, utf32* backing, str8 string);
MP_API str8 utf8_from_codepoints(u64 maxBytes, char* backing, str32 codePoints); MP_API str8 utf8_from_codepoints(u64 maxBytes, char* backing, str32 codePoints);
MP_API str32 utf8_push_to_codepoints(mem_arena* arena, str8 string); MP_API str32 utf8_push_to_codepoints(mem_arena* arena, str8 string);
MP_API str8 utf8_push_from_codepoints(mem_arena* arena, str32 codePoints); MP_API str8 utf8_push_from_codepoints(mem_arena* arena, str32 codePoints);
//----------------------------------------------------------------- //-----------------------------------------------------------------
// utf8 range struct and X-macros for defining utf8 ranges // utf8 range struct and X-macros for defining utf8 ranges
//----------------------------------------------------------------- //-----------------------------------------------------------------
typedef struct unicode_range typedef struct unicode_range
{ {
utf32 firstCodePoint; utf32 firstCodePoint;
u32 count; u32 count;
} unicode_range; } unicode_range;
//NOTE(martin): range declared here are defined in utf8.cpp //NOTE(martin): range declared here are defined in utf8.cpp
// they can be used by prefixing them with UTF8_RANGE_, as in 'UTF8_RANGE_BASIC_LATIN' // they can be used by prefixing them with UTF8_RANGE_, as in 'UTF8_RANGE_BASIC_LATIN'
#define UNICODE_RANGES \ #define UNICODE_RANGES \
UNICODE_RANGE(0x0000, 127, BASIC_LATIN) \ UNICODE_RANGE(0x0000, 127, BASIC_LATIN) \
UNICODE_RANGE(0x0080, 127, C1_CONTROLS_AND_LATIN_1_SUPPLEMENT) \ UNICODE_RANGE(0x0080, 127, C1_CONTROLS_AND_LATIN_1_SUPPLEMENT) \
UNICODE_RANGE(0x0100, 127, LATIN_EXTENDED_A) \ UNICODE_RANGE(0x0100, 127, LATIN_EXTENDED_A) \
UNICODE_RANGE(0x0180, 207, LATIN_EXTENDED_B) \ UNICODE_RANGE(0x0180, 207, LATIN_EXTENDED_B) \
UNICODE_RANGE(0x0250, 95, IPA_EXTENSIONS) \ UNICODE_RANGE(0x0250, 95, IPA_EXTENSIONS) \
UNICODE_RANGE(0x02b0, 79, SPACING_MODIFIER_LETTERS) \ UNICODE_RANGE(0x02b0, 79, SPACING_MODIFIER_LETTERS) \
UNICODE_RANGE(0x0300, 111, COMBINING_DIACRITICAL_MARKS) \ UNICODE_RANGE(0x0300, 111, COMBINING_DIACRITICAL_MARKS) \
UNICODE_RANGE(0x0370, 143, GREEK_COPTIC) \ UNICODE_RANGE(0x0370, 143, GREEK_COPTIC) \
UNICODE_RANGE(0x0400, 255, CYRILLIC) \ UNICODE_RANGE(0x0400, 255, CYRILLIC) \
UNICODE_RANGE(0x0500, 47, CYRILLIC_SUPPLEMENT) \ UNICODE_RANGE(0x0500, 47, CYRILLIC_SUPPLEMENT) \
UNICODE_RANGE(0x0530, 95, ARMENIAN) \ UNICODE_RANGE(0x0530, 95, ARMENIAN) \
UNICODE_RANGE(0x0590, 111, HEBREW) \ UNICODE_RANGE(0x0590, 111, HEBREW) \
UNICODE_RANGE(0x0600, 255, ARABIC) \ UNICODE_RANGE(0x0600, 255, ARABIC) \
UNICODE_RANGE(0x0700, 79, SYRIAC) \ UNICODE_RANGE(0x0700, 79, SYRIAC) \
UNICODE_RANGE(0x0780, 63, THAANA) \ UNICODE_RANGE(0x0780, 63, THAANA) \
UNICODE_RANGE(0x0900, 127, DEVANAGARI) \ UNICODE_RANGE(0x0900, 127, DEVANAGARI) \
UNICODE_RANGE(0x0980, 127, BENGALI_ASSAMESE) \ UNICODE_RANGE(0x0980, 127, BENGALI_ASSAMESE) \
UNICODE_RANGE(0x0a00, 127, GURMUKHI) \ UNICODE_RANGE(0x0a00, 127, GURMUKHI) \
UNICODE_RANGE(0x0a80, 127, GUJARATI) \ UNICODE_RANGE(0x0a80, 127, GUJARATI) \
UNICODE_RANGE(0x0b00, 127, ORIYA) \ UNICODE_RANGE(0x0b00, 127, ORIYA) \
UNICODE_RANGE(0x0b80, 127, TAMIL) \ UNICODE_RANGE(0x0b80, 127, TAMIL) \
UNICODE_RANGE(0x0c00, 127, TELUGU) \ UNICODE_RANGE(0x0c00, 127, TELUGU) \
UNICODE_RANGE(0x0c80, 127, KANNADA) \ UNICODE_RANGE(0x0c80, 127, KANNADA) \
UNICODE_RANGE(0x0d00, 255, MALAYALAM) \ UNICODE_RANGE(0x0d00, 255, MALAYALAM) \
UNICODE_RANGE(0x0d80, 127, SINHALA) \ UNICODE_RANGE(0x0d80, 127, SINHALA) \
UNICODE_RANGE(0x0e00, 127, THAI) \ UNICODE_RANGE(0x0e00, 127, THAI) \
UNICODE_RANGE(0x0e80, 127, LAO) \ UNICODE_RANGE(0x0e80, 127, LAO) \
UNICODE_RANGE(0x0f00, 255, TIBETAN) \ UNICODE_RANGE(0x0f00, 255, TIBETAN) \
UNICODE_RANGE(0x1000, 159, MYANMAR) \ UNICODE_RANGE(0x1000, 159, MYANMAR) \
UNICODE_RANGE(0x10a0, 95, GEORGIAN) \ UNICODE_RANGE(0x10a0, 95, GEORGIAN) \
UNICODE_RANGE(0x1100, 255, HANGUL_JAMO) \ UNICODE_RANGE(0x1100, 255, HANGUL_JAMO) \
UNICODE_RANGE(0x1200, 383, ETHIOPIC) \ UNICODE_RANGE(0x1200, 383, ETHIOPIC) \
UNICODE_RANGE(0x13a0, 95, CHEROKEE) \ UNICODE_RANGE(0x13a0, 95, CHEROKEE) \
UNICODE_RANGE(0x1400, 639, UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS) \ UNICODE_RANGE(0x1400, 639, UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS) \
UNICODE_RANGE(0x1680, 31, OGHAM) \ UNICODE_RANGE(0x1680, 31, OGHAM) \
UNICODE_RANGE(0x16a0, 95, RUNIC) \ UNICODE_RANGE(0x16a0, 95, RUNIC) \
UNICODE_RANGE(0x1700, 31, TAGALOG) \ UNICODE_RANGE(0x1700, 31, TAGALOG) \
UNICODE_RANGE(0x1720, 31, HANUNOO) \ UNICODE_RANGE(0x1720, 31, HANUNOO) \
UNICODE_RANGE(0x1740, 31, BUHID) \ UNICODE_RANGE(0x1740, 31, BUHID) \
UNICODE_RANGE(0x1760, 31, TAGBANWA) \ UNICODE_RANGE(0x1760, 31, TAGBANWA) \
UNICODE_RANGE(0x1780, 127, KHMER) \ UNICODE_RANGE(0x1780, 127, KHMER) \
UNICODE_RANGE(0x1800, 175, MONGOLIAN) \ UNICODE_RANGE(0x1800, 175, MONGOLIAN) \
UNICODE_RANGE(0x1900, 79, LIMBU) \ UNICODE_RANGE(0x1900, 79, LIMBU) \
UNICODE_RANGE(0x1950, 47, TAI_LE) \ UNICODE_RANGE(0x1950, 47, TAI_LE) \
UNICODE_RANGE(0x19e0, 31, KHMER_SYMBOLS) \ UNICODE_RANGE(0x19e0, 31, KHMER_SYMBOLS) \
UNICODE_RANGE(0x1d00, 127, PHONETIC_EXTENSIONS) \ UNICODE_RANGE(0x1d00, 127, PHONETIC_EXTENSIONS) \
UNICODE_RANGE(0x1e00, 255, LATIN_EXTENDED_ADDITIONAL) \ UNICODE_RANGE(0x1e00, 255, LATIN_EXTENDED_ADDITIONAL) \
UNICODE_RANGE(0x1f00, 255, GREEK_EXTENDED) \ UNICODE_RANGE(0x1f00, 255, GREEK_EXTENDED) \
UNICODE_RANGE(0x2000, 111, GENERAL_PUNCTUATION) \ UNICODE_RANGE(0x2000, 111, GENERAL_PUNCTUATION) \
UNICODE_RANGE(0x2070, 47, SUPERSCRIPTS_AND_SUBSCRIPTS) \ UNICODE_RANGE(0x2070, 47, SUPERSCRIPTS_AND_SUBSCRIPTS) \
UNICODE_RANGE(0x20a0, 47, CURRENCY_SYMBOLS) \ UNICODE_RANGE(0x20a0, 47, CURRENCY_SYMBOLS) \
UNICODE_RANGE(0x20d0, 47, COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS) \ UNICODE_RANGE(0x20d0, 47, COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS) \
UNICODE_RANGE(0x2100, 79, LETTERLIKE_SYMBOLS) \ UNICODE_RANGE(0x2100, 79, LETTERLIKE_SYMBOLS) \
UNICODE_RANGE(0x2150, 63, NUMBER_FORMS) \ UNICODE_RANGE(0x2150, 63, NUMBER_FORMS) \
UNICODE_RANGE(0x2190, 111, ARROWS) \ UNICODE_RANGE(0x2190, 111, ARROWS) \
UNICODE_RANGE(0x2200, 255, MATHEMATICAL_OPERATORS) \ UNICODE_RANGE(0x2200, 255, MATHEMATICAL_OPERATORS) \
UNICODE_RANGE(0x2300, 255, MISCELLANEOUS_TECHNICAL) \ UNICODE_RANGE(0x2300, 255, MISCELLANEOUS_TECHNICAL) \
UNICODE_RANGE(0x2400, 63, CONTROL_PICTURES) \ UNICODE_RANGE(0x2400, 63, CONTROL_PICTURES) \
UNICODE_RANGE(0x2440, 31, OPTICAL_CHARACTER_RECOGNITION) \ UNICODE_RANGE(0x2440, 31, OPTICAL_CHARACTER_RECOGNITION) \
UNICODE_RANGE(0x2460, 159, ENCLOSED_ALPHANUMERICS) \ UNICODE_RANGE(0x2460, 159, ENCLOSED_ALPHANUMERICS) \
UNICODE_RANGE(0x2500, 127, BOX_DRAWING) \ UNICODE_RANGE(0x2500, 127, BOX_DRAWING) \
UNICODE_RANGE(0x2580, 31, BLOCK_ELEMENTS) \ UNICODE_RANGE(0x2580, 31, BLOCK_ELEMENTS) \
UNICODE_RANGE(0x25a0, 95, GEOMETRIC_SHAPES) \ UNICODE_RANGE(0x25a0, 95, GEOMETRIC_SHAPES) \
UNICODE_RANGE(0x2600, 255, MISCELLANEOUS_SYMBOLS) \ UNICODE_RANGE(0x2600, 255, MISCELLANEOUS_SYMBOLS) \
UNICODE_RANGE(0x2700, 191, DINGBATS) \ UNICODE_RANGE(0x2700, 191, DINGBATS) \
UNICODE_RANGE(0x27c0, 47, MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A) \ UNICODE_RANGE(0x27c0, 47, MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A) \
UNICODE_RANGE(0x27f0, 15, SUPPLEMENTAL_ARROWS_A) \ UNICODE_RANGE(0x27f0, 15, SUPPLEMENTAL_ARROWS_A) \
UNICODE_RANGE(0x2800, 255, BRAILLE_PATTERNS) \ UNICODE_RANGE(0x2800, 255, BRAILLE_PATTERNS) \
UNICODE_RANGE(0x2900, 127, SUPPLEMENTAL_ARROWS_B) \ UNICODE_RANGE(0x2900, 127, SUPPLEMENTAL_ARROWS_B) \
UNICODE_RANGE(0x2980, 127, MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B) \ UNICODE_RANGE(0x2980, 127, MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B) \
UNICODE_RANGE(0x2a00, 255, SUPPLEMENTAL_MATHEMATICAL_OPERATORS) \ UNICODE_RANGE(0x2a00, 255, SUPPLEMENTAL_MATHEMATICAL_OPERATORS) \
UNICODE_RANGE(0x2b00, 255, MISCELLANEOUS_SYMBOLS_AND_ARROWS) \ UNICODE_RANGE(0x2b00, 255, MISCELLANEOUS_SYMBOLS_AND_ARROWS) \
UNICODE_RANGE(0x2e80, 127, CJK_RADICALS_SUPPLEMENT) \ UNICODE_RANGE(0x2e80, 127, CJK_RADICALS_SUPPLEMENT) \
UNICODE_RANGE(0x2f00, 223, KANGXI_RADICALS) \ UNICODE_RANGE(0x2f00, 223, KANGXI_RADICALS) \
UNICODE_RANGE(0x2ff0, 15, IDEOGRAPHIC_DESCRIPTION_CHARACTERS) \ UNICODE_RANGE(0x2ff0, 15, IDEOGRAPHIC_DESCRIPTION_CHARACTERS) \
UNICODE_RANGE(0x3000, 63, CJK_SYMBOLS_AND_PUNCTUATION) \ UNICODE_RANGE(0x3000, 63, CJK_SYMBOLS_AND_PUNCTUATION) \
UNICODE_RANGE(0x3040, 95, HIRAGANA) \ UNICODE_RANGE(0x3040, 95, HIRAGANA) \
UNICODE_RANGE(0x30a0, 95, KATAKANA) \ UNICODE_RANGE(0x30a0, 95, KATAKANA) \
UNICODE_RANGE(0x3100, 47, BOPOMOFO) \ UNICODE_RANGE(0x3100, 47, BOPOMOFO) \
UNICODE_RANGE(0x3130, 95, HANGUL_COMPATIBILITY_JAMO) \ UNICODE_RANGE(0x3130, 95, HANGUL_COMPATIBILITY_JAMO) \
UNICODE_RANGE(0x3190, 15, KANBUN_KUNTEN) \ UNICODE_RANGE(0x3190, 15, KANBUN_KUNTEN) \
UNICODE_RANGE(0x31a0, 31, BOPOMOFO_EXTENDED) \ UNICODE_RANGE(0x31a0, 31, BOPOMOFO_EXTENDED) \
UNICODE_RANGE(0x31f0, 15, KATAKANA_PHONETIC_EXTENSIONS) \ UNICODE_RANGE(0x31f0, 15, KATAKANA_PHONETIC_EXTENSIONS) \
UNICODE_RANGE(0x3200, 255, ENCLOSED_CJK_LETTERS_AND_MONTHS) \ UNICODE_RANGE(0x3200, 255, ENCLOSED_CJK_LETTERS_AND_MONTHS) \
UNICODE_RANGE(0x3300, 255, CJK_COMPATIBILITY) \ UNICODE_RANGE(0x3300, 255, CJK_COMPATIBILITY) \
UNICODE_RANGE(0x3400, 6591, CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A) \ UNICODE_RANGE(0x3400, 6591, CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A) \
UNICODE_RANGE(0x4dc0, 63, YIJING_HEXAGRAM_SYMBOLS) \ UNICODE_RANGE(0x4dc0, 63, YIJING_HEXAGRAM_SYMBOLS) \
UNICODE_RANGE(0x4e00, 20911, CJK_UNIFIED_IDEOGRAPHS) \ UNICODE_RANGE(0x4e00, 20911, CJK_UNIFIED_IDEOGRAPHS) \
UNICODE_RANGE(0xa000, 1167, YI_SYLLABLES) \ UNICODE_RANGE(0xa000, 1167, YI_SYLLABLES) \
UNICODE_RANGE(0xa490, 63, YI_RADICALS) \ UNICODE_RANGE(0xa490, 63, YI_RADICALS) \
UNICODE_RANGE(0xac00, 11183, HANGUL_SYLLABLES) \ UNICODE_RANGE(0xac00, 11183, HANGUL_SYLLABLES) \
UNICODE_RANGE(0xd800, 1023, HIGH_SURROGATE_AREA) \ UNICODE_RANGE(0xd800, 1023, HIGH_SURROGATE_AREA) \
UNICODE_RANGE(0xdc00, 1023, LOW_SURROGATE_AREA) \ UNICODE_RANGE(0xdc00, 1023, LOW_SURROGATE_AREA) \
UNICODE_RANGE(0xe000, 6399, PRIVATE_USE_AREA) \ UNICODE_RANGE(0xe000, 6399, PRIVATE_USE_AREA) \
UNICODE_RANGE(0xf900, 511, CJK_COMPATIBILITY_IDEOGRAPHS) \ UNICODE_RANGE(0xf900, 511, CJK_COMPATIBILITY_IDEOGRAPHS) \
UNICODE_RANGE(0xfb00, 79, ALPHABETIC_PRESENTATION_FORMS) \ UNICODE_RANGE(0xfb00, 79, ALPHABETIC_PRESENTATION_FORMS) \
UNICODE_RANGE(0xfb50, 687, ARABIC_PRESENTATION_FORMS_A) \ UNICODE_RANGE(0xfb50, 687, ARABIC_PRESENTATION_FORMS_A) \
UNICODE_RANGE(0xfe00, 15, VARIATION_SELECTORS) \ UNICODE_RANGE(0xfe00, 15, VARIATION_SELECTORS) \
UNICODE_RANGE(0xfe20, 15, COMBINING_HALF_MARKS) \ UNICODE_RANGE(0xfe20, 15, COMBINING_HALF_MARKS) \
UNICODE_RANGE(0xfe30, 31, CJK_COMPATIBILITY_FORMS) \ UNICODE_RANGE(0xfe30, 31, CJK_COMPATIBILITY_FORMS) \
UNICODE_RANGE(0xfe50, 31, SMALL_FORM_VARIANTS) \ UNICODE_RANGE(0xfe50, 31, SMALL_FORM_VARIANTS) \
UNICODE_RANGE(0xfe70, 143, ARABIC_PRESENTATION_FORMS_B) \ UNICODE_RANGE(0xfe70, 143, ARABIC_PRESENTATION_FORMS_B) \
UNICODE_RANGE(0xff00, 239, HALFWIDTH_AND_FULLWIDTH_FORMS) \ UNICODE_RANGE(0xff00, 239, HALFWIDTH_AND_FULLWIDTH_FORMS) \
UNICODE_RANGE(0xfff0, 15, SPECIALS) \ UNICODE_RANGE(0xfff0, 15, SPECIALS) \
UNICODE_RANGE(0x10000, 127, LINEAR_B_SYLLABARY) \ UNICODE_RANGE(0x10000, 127, LINEAR_B_SYLLABARY) \
UNICODE_RANGE(0x10080, 127, LINEAR_B_IDEOGRAMS) \ UNICODE_RANGE(0x10080, 127, LINEAR_B_IDEOGRAMS) \
UNICODE_RANGE(0x10100, 63, AEGEAN_NUMBERS) \ UNICODE_RANGE(0x10100, 63, AEGEAN_NUMBERS) \
UNICODE_RANGE(0x10300, 47, OLD_ITALIC) \ UNICODE_RANGE(0x10300, 47, OLD_ITALIC) \
UNICODE_RANGE(0x10330, 31, GOTHIC) \ UNICODE_RANGE(0x10330, 31, GOTHIC) \
UNICODE_RANGE(0x10380, 31, UGARITIC) \ UNICODE_RANGE(0x10380, 31, UGARITIC) \
UNICODE_RANGE(0x10400, 79, DESERET) \ UNICODE_RANGE(0x10400, 79, DESERET) \
UNICODE_RANGE(0x10450, 47, SHAVIAN) \ UNICODE_RANGE(0x10450, 47, SHAVIAN) \
UNICODE_RANGE(0x10480, 47, OSMANYA) \ UNICODE_RANGE(0x10480, 47, OSMANYA) \
UNICODE_RANGE(0x10800, 63, CYPRIOT_SYLLABARY) \ UNICODE_RANGE(0x10800, 63, CYPRIOT_SYLLABARY) \
UNICODE_RANGE(0x1d000, 255, BYZANTINE_MUSICAL_SYMBOLS) \ UNICODE_RANGE(0x1d000, 255, BYZANTINE_MUSICAL_SYMBOLS) \
UNICODE_RANGE(0x1d100, 255, MUSICAL_SYMBOLS) \ UNICODE_RANGE(0x1d100, 255, MUSICAL_SYMBOLS) \
UNICODE_RANGE(0x1d300, 95, TAI_XUAN_JING_SYMBOLS) \ UNICODE_RANGE(0x1d300, 95, TAI_XUAN_JING_SYMBOLS) \
UNICODE_RANGE(0x1d400, 1023, MATHEMATICAL_ALPHANUMERIC_SYMBOLS) \ UNICODE_RANGE(0x1d400, 1023, MATHEMATICAL_ALPHANUMERIC_SYMBOLS) \
UNICODE_RANGE(0x20000, 42719, CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B) \ UNICODE_RANGE(0x20000, 42719, CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B) \
UNICODE_RANGE(0x2f800, 543, CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT) \ UNICODE_RANGE(0x2f800, 543, CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT) \
UNICODE_RANGE(0xe0000, 127, TAGS) \ UNICODE_RANGE(0xe0000, 127, TAGS) \
UNICODE_RANGE(0xe0100, 239, VARIATION_SELECTORS_SUPPLEMENT) \ UNICODE_RANGE(0xe0100, 239, VARIATION_SELECTORS_SUPPLEMENT) \
UNICODE_RANGE(0xf0000, 65533, SUPPLEMENTARY_PRIVATE_USE_AREA_A) \ UNICODE_RANGE(0xf0000, 65533, SUPPLEMENTARY_PRIVATE_USE_AREA_A) \
UNICODE_RANGE(0x100000, 65533, SUPPLEMENTARY_PRIVATE_USE_AREA_B) UNICODE_RANGE(0x100000, 65533, SUPPLEMENTARY_PRIVATE_USE_AREA_B)
#define UNICODE_RANGE(start, count, name) \ #define UNICODE_RANGE(start, count, name) \
MP_API extern const unicode_range _cat2_(UNICODE_RANGE_, name); MP_API extern const unicode_range _cat2_(UNICODE_RANGE_, name);
UNICODE_RANGES UNICODE_RANGES
#undef UNICODE_RANGE #undef UNICODE_RANGE
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
#endif //__UTF8_H_ #endif //__UTF8_H_

View File

@ -1,264 +1,264 @@
/************************************************************//** /************************************************************//**
* *
* @file: wgl_surface.c * @file: wgl_surface.c
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 01/08/2022 * @date: 01/08/2022
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#include"win32_app.h" #include"win32_app.h"
#include"graphics_internal.h" #include"graphics_internal.h"
#include"gl_loader.h" #include"gl_loader.h"
#include<GL/wglext.h> #include<GL/wglext.h>
#include"macro_helpers.h" #include"macro_helpers.h"
#define WGL_PROC_LIST \ #define WGL_PROC_LIST \
WGL_PROC(WGLCHOOSEPIXELFORMATARB, wglChoosePixelFormatARB) \ WGL_PROC(WGLCHOOSEPIXELFORMATARB, wglChoosePixelFormatARB) \
WGL_PROC(WGLCREATECONTEXTATTRIBSARB, wglCreateContextAttribsARB) \ WGL_PROC(WGLCREATECONTEXTATTRIBSARB, wglCreateContextAttribsARB) \
WGL_PROC(WGLMAKECONTEXTCURRENTARB, wglMakeContextCurrentARB) \ WGL_PROC(WGLMAKECONTEXTCURRENTARB, wglMakeContextCurrentARB) \
WGL_PROC(WGLSWAPINTERVALEXT, wglSwapIntervalEXT) \ WGL_PROC(WGLSWAPINTERVALEXT, wglSwapIntervalEXT) \
//NOTE: wgl function pointers declarations //NOTE: wgl function pointers declarations
#define WGL_PROC(type, name) _cat3_(PFN, type, PROC) name = 0; #define WGL_PROC(type, name) _cat3_(PFN, type, PROC) name = 0;
WGL_PROC_LIST WGL_PROC_LIST
#undef WGL_PROC #undef WGL_PROC
//NOTE: wgl loader //NOTE: wgl loader
typedef struct wgl_dummy_context typedef struct wgl_dummy_context
{ {
bool init; bool init;
HWND hWnd; HWND hWnd;
HDC hDC; HDC hDC;
HGLRC glContext; HGLRC glContext;
} wgl_dummy_context; } wgl_dummy_context;
static wgl_dummy_context __mgWGLDummyContext = {0}; static wgl_dummy_context __mgWGLDummyContext = {0};
static void wgl_init() static void wgl_init()
{ {
if(!__mgWGLDummyContext.init) if(!__mgWGLDummyContext.init)
{ {
//NOTE: create a dummy window //NOTE: create a dummy window
WNDCLASS windowClass = {.style = CS_OWNDC, WNDCLASS windowClass = {.style = CS_OWNDC,
.lpfnWndProc = DefWindowProc, .lpfnWndProc = DefWindowProc,
.hInstance = GetModuleHandleW(NULL), .hInstance = GetModuleHandleW(NULL),
.lpszClassName = "wgl_helper_window_class", .lpszClassName = "wgl_helper_window_class",
.hCursor = LoadCursor(0, IDC_ARROW)}; .hCursor = LoadCursor(0, IDC_ARROW)};
if(!RegisterClass(&windowClass)) if(!RegisterClass(&windowClass))
{ {
//TODO: error //TODO: error
goto quit; goto quit;
} }
__mgWGLDummyContext.hWnd = CreateWindow("wgl_helper_window_class", __mgWGLDummyContext.hWnd = CreateWindow("wgl_helper_window_class",
"dummy", "dummy",
WS_OVERLAPPEDWINDOW, WS_OVERLAPPEDWINDOW,
0, 0, 100, 100, 0, 0, 100, 100,
0, 0, windowClass.hInstance, 0); 0, 0, windowClass.hInstance, 0);
if(!__mgWGLDummyContext.hWnd) if(!__mgWGLDummyContext.hWnd)
{ {
//TODO: error //TODO: error
goto quit; goto quit;
} }
__mgWGLDummyContext.hDC = GetDC(__mgWGLDummyContext.hWnd); __mgWGLDummyContext.hDC = GetDC(__mgWGLDummyContext.hWnd);
PIXELFORMATDESCRIPTOR pixelFormatDesc = PIXELFORMATDESCRIPTOR pixelFormatDesc =
{ {
sizeof(PIXELFORMATDESCRIPTOR), sizeof(PIXELFORMATDESCRIPTOR),
1, 1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, // Flags PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, // Flags
PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette. PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette.
32, // Colordepth of the framebuffer. 32, // Colordepth of the framebuffer.
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
24, // Number of bits for the depthbuffer 24, // Number of bits for the depthbuffer
8, // Number of bits for the stencilbuffer 8, // Number of bits for the stencilbuffer
0, // Number of Aux buffers in the framebuffer. 0, // Number of Aux buffers in the framebuffer.
PFD_MAIN_PLANE, PFD_MAIN_PLANE,
0, 0,
0, 0, 0 0, 0, 0
}; };
int pixelFormat = ChoosePixelFormat(__mgWGLDummyContext.hDC, &pixelFormatDesc); int pixelFormat = ChoosePixelFormat(__mgWGLDummyContext.hDC, &pixelFormatDesc);
SetPixelFormat(__mgWGLDummyContext.hDC, pixelFormat, &pixelFormatDesc); SetPixelFormat(__mgWGLDummyContext.hDC, pixelFormat, &pixelFormatDesc);
__mgWGLDummyContext.glContext = wglCreateContext(__mgWGLDummyContext.hDC); __mgWGLDummyContext.glContext = wglCreateContext(__mgWGLDummyContext.hDC);
wglMakeCurrent(__mgWGLDummyContext.hDC, __mgWGLDummyContext.glContext); wglMakeCurrent(__mgWGLDummyContext.hDC, __mgWGLDummyContext.glContext);
//NOTE(martin): now load WGL extension functions //NOTE(martin): now load WGL extension functions
#define WGL_PROC(type, name) name = (_cat3_(PFN, type, PROC))wglGetProcAddress( #name ); #define WGL_PROC(type, name) name = (_cat3_(PFN, type, PROC))wglGetProcAddress( #name );
WGL_PROC_LIST WGL_PROC_LIST
#undef WGL_PROC #undef WGL_PROC
__mgWGLDummyContext.init = true; __mgWGLDummyContext.init = true;
} }
else else
{ {
wglMakeCurrent(__mgWGLDummyContext.hDC, __mgWGLDummyContext.glContext); wglMakeCurrent(__mgWGLDummyContext.hDC, __mgWGLDummyContext.glContext);
} }
quit:; quit:;
} }
#undef WGL_PROC_LIST #undef WGL_PROC_LIST
typedef struct mg_wgl_surface typedef struct mg_wgl_surface
{ {
mg_surface_data interface; mg_surface_data interface;
HDC hDC; HDC hDC;
HGLRC glContext; HGLRC glContext;
//NOTE: this may be a bit wasteful to have one api struct per surface, but win32 docs says that loading procs //NOTE: this may be a bit wasteful to have one api struct per surface, but win32 docs says that loading procs
// from different contexts might select different implementations (eg. depending on context version/pixel format) // from different contexts might select different implementations (eg. depending on context version/pixel format)
mg_gl_api api; mg_gl_api api;
} mg_wgl_surface; } mg_wgl_surface;
void mg_wgl_surface_destroy(mg_surface_data* interface) void mg_wgl_surface_destroy(mg_surface_data* interface)
{ {
mg_wgl_surface* surface = (mg_wgl_surface*)interface; mg_wgl_surface* surface = (mg_wgl_surface*)interface;
if(surface->glContext == wglGetCurrentContext()) if(surface->glContext == wglGetCurrentContext())
{ {
wglMakeCurrent(NULL, NULL); wglMakeCurrent(NULL, NULL);
} }
wglDeleteContext(surface->glContext); wglDeleteContext(surface->glContext);
mg_surface_cleanup(interface); mg_surface_cleanup(interface);
free(surface); free(surface);
} }
void mg_wgl_surface_prepare(mg_surface_data* interface) void mg_wgl_surface_prepare(mg_surface_data* interface)
{ {
mg_wgl_surface* surface = (mg_wgl_surface*)interface; mg_wgl_surface* surface = (mg_wgl_surface*)interface;
wglMakeCurrent(surface->hDC, surface->glContext); wglMakeCurrent(surface->hDC, surface->glContext);
mg_gl_select_api(&surface->api); mg_gl_select_api(&surface->api);
} }
void mg_wgl_surface_present(mg_surface_data* interface) void mg_wgl_surface_present(mg_surface_data* interface)
{ {
mg_wgl_surface* surface = (mg_wgl_surface*)interface; mg_wgl_surface* surface = (mg_wgl_surface*)interface;
SwapBuffers(surface->hDC); SwapBuffers(surface->hDC);
} }
void mg_wgl_surface_swap_interval(mg_surface_data* interface, int swap) void mg_wgl_surface_swap_interval(mg_surface_data* interface, int swap)
{ {
mg_wgl_surface* surface = (mg_wgl_surface*)interface; mg_wgl_surface* surface = (mg_wgl_surface*)interface;
wglSwapIntervalEXT(swap); wglSwapIntervalEXT(swap);
} }
void* mg_wgl_get_proc(const char* name) void* mg_wgl_get_proc(const char* name)
{ {
void* p = wglGetProcAddress(name); void* p = wglGetProcAddress(name);
if( p == 0 if( p == 0
|| p == (void*)0x01 || p == (void*)0x01
|| p == (void*)0x02 || p == (void*)0x02
|| p == (void*)0x03 || p == (void*)0x03
|| p == (void*)(-1)) || p == (void*)(-1))
{ {
//TODO: should we avoid re-loading every time? //TODO: should we avoid re-loading every time?
HMODULE module = LoadLibrary("opengl32.dll"); HMODULE module = LoadLibrary("opengl32.dll");
p = (void*)GetProcAddress(module, name); p = (void*)GetProcAddress(module, name);
} }
return(p); return(p);
} }
mg_surface_data* mg_wgl_surface_create_for_window(mp_window window) mg_surface_data* mg_wgl_surface_create_for_window(mp_window window)
{ {
mg_surface* surface = 0; mg_surface* surface = 0;
mp_window_data* windowData = mp_window_ptr_from_handle(window); mp_window_data* windowData = mp_window_ptr_from_handle(window);
if(windowData) if(windowData)
{ {
wgl_init(); wgl_init();
//NOTE: fill surface data and load api //NOTE: fill surface data and load api
mg_wgl_surface* surface = malloc_type(mg_wgl_surface); mg_wgl_surface* surface = malloc_type(mg_wgl_surface);
if(surface) if(surface)
{ {
mg_surface_init_for_window((mg_surface_data*)surface, windowData); mg_surface_init_for_window((mg_surface_data*)surface, windowData);
surface->interface.backend = MG_BACKEND_GL; surface->interface.backend = MG_BACKEND_GL;
surface->interface.destroy = mg_wgl_surface_destroy; surface->interface.destroy = mg_wgl_surface_destroy;
surface->interface.prepare = mg_wgl_surface_prepare; surface->interface.prepare = mg_wgl_surface_prepare;
surface->interface.present = mg_wgl_surface_present; surface->interface.present = mg_wgl_surface_present;
surface->interface.swapInterval = mg_wgl_surface_swap_interval; surface->interface.swapInterval = mg_wgl_surface_swap_interval;
surface->hDC = GetDC(surface->interface.layer.hWnd); surface->hDC = GetDC(surface->interface.layer.hWnd);
//NOTE(martin): create the pixel format and gl context //NOTE(martin): create the pixel format and gl context
PIXELFORMATDESCRIPTOR pixelFormatDesc = PIXELFORMATDESCRIPTOR pixelFormatDesc =
{ {
sizeof(PIXELFORMATDESCRIPTOR), sizeof(PIXELFORMATDESCRIPTOR),
1, 1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, // Flags PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, // Flags
PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette. PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette.
32, // Colordepth of the framebuffer. 32, // Colordepth of the framebuffer.
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
0, 0,
0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
24, // Number of bits for the depthbuffer 24, // Number of bits for the depthbuffer
8, // Number of bits for the stencilbuffer 8, // Number of bits for the stencilbuffer
0, // Number of Aux buffers in the framebuffer. 0, // Number of Aux buffers in the framebuffer.
PFD_MAIN_PLANE, PFD_MAIN_PLANE,
0, 0,
0, 0, 0 0, 0, 0
}; };
int pixelFormatAttrs[] = { int pixelFormatAttrs[] = {
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE, WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE, WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32, WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24, WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8, WGL_STENCIL_BITS_ARB, 8,
0}; 0};
u32 numFormats = 0; u32 numFormats = 0;
int pixelFormat = 0; int pixelFormat = 0;
wglChoosePixelFormatARB(surface->hDC, pixelFormatAttrs, 0, 1, &pixelFormat, &numFormats); wglChoosePixelFormatARB(surface->hDC, pixelFormatAttrs, 0, 1, &pixelFormat, &numFormats);
if(!pixelFormat) if(!pixelFormat)
{ {
//TODO: error //TODO: error
} }
SetPixelFormat(surface->hDC, pixelFormat, &pixelFormatDesc); SetPixelFormat(surface->hDC, pixelFormat, &pixelFormatDesc);
int contextAttrs[] = { int contextAttrs[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 4, WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
WGL_CONTEXT_MINOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 3,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0}; 0};
surface->glContext = wglCreateContextAttribsARB(surface->hDC, __mgWGLDummyContext.glContext, contextAttrs); surface->glContext = wglCreateContextAttribsARB(surface->hDC, __mgWGLDummyContext.glContext, contextAttrs);
if(!surface->glContext) if(!surface->glContext)
{ {
//TODO error //TODO error
int error = GetLastError(); int error = GetLastError();
printf("error: %i\n", error); printf("error: %i\n", error);
} }
//NOTE: make gl context current and load api //NOTE: make gl context current and load api
wglMakeCurrent(surface->hDC, surface->glContext); wglMakeCurrent(surface->hDC, surface->glContext);
wglSwapIntervalEXT(1); wglSwapIntervalEXT(1);
mg_gl_load_gl43(&surface->api, mg_wgl_get_proc); mg_gl_load_gl43(&surface->api, mg_wgl_get_proc);
} }
} }
return((mg_surface_data*)surface); return((mg_surface_data*)surface);
} }

View File

@ -1,16 +1,16 @@
/************************************************************//** /************************************************************//**
* *
* @file: wgl_surface.c * @file: wgl_surface.c
* @author: Martin Fouilleul * @author: Martin Fouilleul
* @date: 28/01/2023 * @date: 28/01/2023
* @revision: * @revision:
* *
*****************************************************************/ *****************************************************************/
#ifndef __WGL_SURFACE_H_ #ifndef __WGL_SURFACE_H_
#define __WGL_SURFACE_H_ #define __WGL_SURFACE_H_
#include"graphics_internal.h" #include"graphics_internal.h"
mg_surface_data* mg_wgl_surface_create_for_window(mp_window window); mg_surface_data* mg_wgl_surface_create_for_window(mp_window window);
#endif // __WIN32_GL_SURFACE_H_ #endif // __WIN32_GL_SURFACE_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +1,43 @@
//***************************************************************** //*****************************************************************
// //
// $file: win32_app.h $ // $file: win32_app.h $
// $author: Martin Fouilleul $ // $author: Martin Fouilleul $
// $date: 20/12/2022 $ // $date: 20/12/2022 $
// $revision: $ // $revision: $
// $note: (C) 2022 by Martin Fouilleul - all rights reserved $ // $note: (C) 2022 by Martin Fouilleul - all rights reserved $
// //
//***************************************************************** //*****************************************************************
#ifndef __WIN32_APP_H_ #ifndef __WIN32_APP_H_
#define __WIN32_APP_H_ #define __WIN32_APP_H_
#include"mp_app.h" #include"mp_app.h"
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#define UNICODE #define UNICODE
#include<windows.h> #include<windows.h>
typedef struct win32_window_data typedef struct win32_window_data
{ {
HWND hWnd; HWND hWnd;
} win32_window_data; } win32_window_data;
typedef struct mp_layer typedef struct mp_layer
{ {
HWND hWnd; HWND hWnd;
} mp_layer; } mp_layer;
#define MP_PLATFORM_WINDOW_DATA win32_window_data win32; #define MP_PLATFORM_WINDOW_DATA win32_window_data win32;
typedef struct win32_app_data typedef struct win32_app_data
{ {
u32 savedConsoleCodePage; u32 savedConsoleCodePage;
int mouseCaptureMask; int mouseCaptureMask;
bool mouseTracked; bool mouseTracked;
} win32_app_data; } win32_app_data;
#define MP_PLATFORM_APP_DATA win32_app_data win32; #define MP_PLATFORM_APP_DATA win32_app_data win32;
#endif __WIN32_APP_H_ #endif __WIN32_APP_H_