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
*.dSYM
bin/*
*.metallib
*.pdb
*.exe
*.ilk
*.vs
*.obj
*.lib
*.dll
*.sln
Debug/*
.DS_Store
*.dSYM
bin/*
*.metallib
*.pdb
*.exe
*.ilk
*.vs
*.obj
*.lib
*.dll
*.sln
Debug/*
src/glsl_shaders.h

View File

@ -1,11 +1,11 @@
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
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 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
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
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 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

View File

@ -1,4 +1,4 @@
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
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

View File

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

View File

@ -1,4 +1,4 @@
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
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

View File

@ -1,3 +1,3 @@
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
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

View File

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

View File

@ -1,3 +1,3 @@
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
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

View File

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

View File

@ -1,44 +1,44 @@
angle install on windows
* need Python3 (can install through win app store)
* need Windows SDK
* 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
* set depot_tools in path env variable through control panel>System and security>system>advanced system settings
* run gclient in a cmd shell
* set DEPOT_TOOLS_WIN_TOOLCHAIN=0
* mkdir angle
* cd angle
* fetch angle
* wait a million years
* fails when running python3 third_party/depot_tools/download_from_google_storage.py ...
-> open DEPS and change third_party/depot_tools with ../depot/tools
* run gclient sync to complete previous step
* gn gen out/Debug
* gn args out/Debug and edit arguments:
angle_enable_vulkan = false
angle_build_tests = false
is_component_build = false
#to get debugging kinda working with renderdoc:
angle_enable_trace = true
angle_enable_annotator_run_time_checks = true
* autoninja -C out/Debug
* wait a while
* link with libEGL.dll.lib and libGLESv2.dll.lib
* put libEGL.dll and libGLESv2.dll in same directory as executable
Debugging
---------
in renderdoc, set env variables
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...)
ANGLE_ENABLE_DEBUG_MARKERS 1 (to turn on debug markers)
angle install on windows
* need Python3 (can install through win app store)
* need Windows SDK
* 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
* set depot_tools in path env variable through control panel>System and security>system>advanced system settings
* run gclient in a cmd shell
* set DEPOT_TOOLS_WIN_TOOLCHAIN=0
* mkdir angle
* cd angle
* fetch angle
* wait a million years
* fails when running python3 third_party/depot_tools/download_from_google_storage.py ...
-> open DEPS and change third_party/depot_tools with ../depot/tools
* run gclient sync to complete previous step
* gn gen out/Debug
* gn args out/Debug and edit arguments:
angle_enable_vulkan = false
angle_build_tests = false
is_component_build = false
#to get debugging kinda working with renderdoc:
angle_enable_trace = true
angle_enable_annotator_run_time_checks = true
* autoninja -C out/Debug
* wait a while
* link with libEGL.dll.lib and libGLESv2.dll.lib
* put libEGL.dll and libGLESv2.dll in same directory as executable
Debugging
---------
in renderdoc, set env variables
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...)
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
from datetime import datetime
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument("inputFiles", nargs="+")
parser.add_argument("-o", "--output")
parser.add_argument("-p", "--prefix")
args = parser.parse_args()
output = open(args.output, "w")
output.write("/*********************************************************************\n")
output.write("*\n")
output.write("*\tfile: %s\n" % os.path.basename(args.output))
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("*\n")
output.write("**********************************************************************/\n")
outSymbol = (os.path.splitext(os.path.basename(args.output))[0]).upper()
output.write("#ifndef __%s_H__\n" % outSymbol)
output.write("#define __%s_H__\n" % outSymbol)
output.write("\n\n")
for fileName in args.inputFiles:
f = open(fileName, "r")
lines = f.read().splitlines()
output.write("//NOTE: string imported from %s\n" % fileName)
stringName = os.path.splitext(os.path.basename(fileName))[0]
output.write(f"const char* {args.prefix}{stringName} = ")
for line in lines:
output.write("\n\"%s\\n\"" % line)
output.write(";\n\n")
f.close()
output.write("#endif // __%s_H__\n" % outSymbol)
output.close()
import os
from datetime import datetime
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument("inputFiles", nargs="+")
parser.add_argument("-o", "--output")
parser.add_argument("-p", "--prefix")
args = parser.parse_args()
output = open(args.output, "w")
output.write("/*********************************************************************\n")
output.write("*\n")
output.write("*\tfile: %s\n" % os.path.basename(args.output))
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("*\n")
output.write("**********************************************************************/\n")
outSymbol = (os.path.splitext(os.path.basename(args.output))[0]).upper()
output.write("#ifndef __%s_H__\n" % outSymbol)
output.write("#define __%s_H__\n" % outSymbol)
output.write("\n\n")
for fileName in args.inputFiles:
f = open(fileName, "r")
lines = f.read().splitlines()
output.write("//NOTE: string imported from %s\n" % fileName)
stringName = os.path.splitext(os.path.basename(fileName))[0]
output.write(f"const char* {args.prefix}{stringName} = ")
for line in lines:
output.write("\n\"%s\\n\"" % line)
output.write(";\n\n")
f.close()
output.write("#endif // __%s_H__\n" % outSymbol)
output.close()

View File

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

View File

@ -1,18 +1,18 @@
/************************************************************//**
*
* @file: egl_surface.h
* @author: Martin Fouilleul
* @date: 28/01/2023
* @revision:
*
*****************************************************************/
#ifndef __EGL_SURFACE_H_
#define __EGL_SURFACE_H_
#include"graphics_internal.h"
#include"mp_app.h"
mg_surface_data* mg_egl_surface_create_for_window(mp_window window);
mg_surface_data* mg_egl_surface_create_remote(u32 width, u32 height);
#endif // __EGL_SURFACE_H_
/************************************************************//**
*
* @file: egl_surface.h
* @author: Martin Fouilleul
* @date: 28/01/2023
* @revision:
*
*****************************************************************/
#ifndef __EGL_SURFACE_H_
#define __EGL_SURFACE_H_
#include"graphics_internal.h"
#include"mp_app.h"
mg_surface_data* mg_egl_surface_create_for_window(mp_window window);
mg_surface_data* mg_egl_surface_create_remote(u32 width, u32 height);
#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
* @note: auto-generated by glapi.py from gl.xml
* @date: 22/022023
*
*********************************************************/
#ifndef __GL_LOADER_H__
#define __GL_LOADER_H__
#include"gl_api.h"
typedef void*(*mg_gl_load_proc)(const char* name);
void mg_gl_load_gl41(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_load_gl43(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_load_gles30(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_load_gles31(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_select_api(mg_gl_api* api);
#endif // __GL_LOADER_H__
/********************************************************
*
* @file: gl_loader.h
* @note: auto-generated by glapi.py from gl.xml
* @date: 22/022023
*
*********************************************************/
#ifndef __GL_LOADER_H__
#define __GL_LOADER_H__
#include"gl_api.h"
typedef void*(*mg_gl_load_proc)(const char* name);
void mg_gl_load_gl41(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_load_gl43(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_load_gles30(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_load_gles31(mg_gl_api* api, mg_gl_load_proc loadProc);
void mg_gl_select_api(mg_gl_api* api);
#endif // __GL_LOADER_H__

View File

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

View File

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

View File

@ -1,13 +1,13 @@
precision mediump float;
out vec2 uv;
void main()
{
float x = float(((uint(gl_VertexID) + 2u) / 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);
uv = vec2(x, y);
}
precision mediump float;
out vec2 uv;
void main()
{
float x = float(((uint(gl_VertexID) + 2u) / 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);
uv = vec2(x, y);
}

View File

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

View File

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

View File

@ -1,242 +1,242 @@
#extension GL_ARB_gpu_shader_int64 : require
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
precision mediump float;
//precision mediump image2D;
layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
vertex elements[];
} vertexBuffer ;
layout(binding = 1) restrict readonly buffer shapeBufferSSBO {
shape elements[];
} shapeBuffer ;
layout(binding = 2) restrict readonly buffer indexBufferSSBO {
uint elements[];
} indexBuffer ;
layout(binding = 3) restrict readonly buffer tileCounterBufferSSBO {
uint elements[];
} tileCounterBuffer ;
layout(binding = 4) restrict readonly buffer tileArrayBufferSSBO {
uint elements[];
} tileArrayBuffer ;
layout(location = 0) uniform uint indexCount;
layout(location = 1) uniform uvec2 tileCount;
layout(location = 2) uniform uint tileSize;
layout(location = 3) uniform uint tileArraySize;
layout(location = 4) uniform vec2 scaling;
layout(location = 5) uniform uint useTexture;
layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;
layout(binding = 1) uniform sampler2D srcTexture;
bool is_top_left(ivec2 a, ivec2 b)
{
return( (a.y == b.y && b.x < a.x)
||(b.y < a.y));
}
//////////////////////////////////////////////////////////////////////////////
//TODO: we should do these computations on 64bits, because otherwise
// we might overflow for values > 2048.
// Unfortunately this is costly.
// Another way is to precompute triangle edges (b - a) in full precision
// once to avoid doing it all the time...
//////////////////////////////////////////////////////////////////////////////
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));
}
int is_clockwise(ivec2 p0, ivec2 p1, ivec2 p2)
{
return((p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x);
}
void main()
{
ivec2 pixelCoord = ivec2(gl_WorkGroupID.xy*uvec2(16, 16) + gl_LocalInvocationID.xy);
uvec2 tileCoord = uvec2(pixelCoord) / tileSize;
uint tileIndex = tileCoord.y * tileCount.x + tileCoord.x;
uint tileCounter = min(tileCounterBuffer.elements[tileIndex], tileArraySize);
const float subPixelFactor = 16.;
ivec2 centerPoint = ivec2((vec2(pixelCoord) + vec2(0.5, 0.5)) * subPixelFactor);
//*
const int sampleCount = 8;
ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(1, 3),
centerPoint + ivec2(-1, -3),
centerPoint + ivec2(5, -1),
centerPoint + ivec2(-3, 5),
centerPoint + ivec2(-5, -5),
centerPoint + ivec2(-7, 1),
centerPoint + ivec2(3, -7),
centerPoint + ivec2(7, 7));
/*/
const int sampleCount = 4;
ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(-2, 6),
centerPoint + ivec2(6, 2),
centerPoint + ivec2(-6, -2),
centerPoint + ivec2(2, -6));
//*/
//DEBUG
/*
{
vec4 fragColor = vec4(0);
if( pixelCoord.x % 16 == 0
||pixelCoord.y % 16 == 0)
{
fragColor = vec4(0, 0, 0, 1);
}
else if(tileCounterBuffer.elements[tileIndex] == 0xffffu)
{
fragColor = vec4(1, 0, 1, 1);
}
else if(tileCounter != 0u)
{
fragColor = vec4(0, 1, 0, 1);
}
else
{
fragColor = vec4(1, 0, 0, 1);
}
imageStore(outTexture, pixelCoord, fragColor);
return;
}
//*/
//----
vec4 sampleColor[sampleCount];
vec4 currentColor[sampleCount];
int currentShapeIndex[sampleCount];
int flipCount[sampleCount];
for(int i=0; i<sampleCount; i++)
{
currentShapeIndex[i] = -1;
flipCount[i] = 0;
sampleColor[i] = vec4(0, 0, 0, 0);
currentColor[i] = vec4(0, 0, 0, 0);
}
for(uint tileArrayIndex=0u; tileArrayIndex < tileCounter; tileArrayIndex++)
{
uint triangleIndex = tileArrayBuffer.elements[tileArraySize * tileIndex + tileArrayIndex];
uint i0 = indexBuffer.elements[triangleIndex];
uint i1 = indexBuffer.elements[triangleIndex+1u];
uint i2 = indexBuffer.elements[triangleIndex+2u];
ivec2 p0 = ivec2((vertexBuffer.elements[i0].pos * scaling) * subPixelFactor);
ivec2 p1 = ivec2((vertexBuffer.elements[i1].pos * scaling) * subPixelFactor);
ivec2 p2 = ivec2((vertexBuffer.elements[i2].pos * scaling) * subPixelFactor);
int shapeIndex = vertexBuffer.elements[i0].shapeIndex;
vec4 color = shapeBuffer.elements[shapeIndex].color;
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));
mat3 uvTransform = mat3(shapeBuffer.elements[shapeIndex].uvTransform[0],
shapeBuffer.elements[shapeIndex].uvTransform[3],
0.,
shapeBuffer.elements[shapeIndex].uvTransform[1],
shapeBuffer.elements[shapeIndex].uvTransform[4],
0.,
shapeBuffer.elements[shapeIndex].uvTransform[2],
shapeBuffer.elements[shapeIndex].uvTransform[5],
1.);
//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
int cw = is_clockwise(p0, p1, p2);
if(cw < 0)
{
uint tmpIndex = i1;
i1 = i2;
i2 = tmpIndex;
ivec2 tmpPoint = p1;
p1 = p2;
p2 = tmpPoint;
}
vec4 cubic0 = vertexBuffer.elements[i0].cubic;
vec4 cubic1 = vertexBuffer.elements[i1].cubic;
vec4 cubic2 = vertexBuffer.elements[i2].cubic;
int bias0 = is_top_left(p1, p2) ? 0 : -1;
int bias1 = is_top_left(p2, p0) ? 0 : -1;
int bias2 = is_top_left(p0, p1) ? 0 : -1;
for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)
{
ivec2 samplePoint = samplePoints[sampleIndex];
if( samplePoint.x < clip.x
|| samplePoint.x > clip.z
|| samplePoint.y < clip.y
|| samplePoint.y > clip.w)
{
continue;
}
int w0 = orient2d(p1, p2, samplePoint);
int w1 = orient2d(p2, p0, samplePoint);
int w2 = orient2d(p0, p1, samplePoint);
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));
float eps = 0.0001;
if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)
{
if(shapeIndex == currentShapeIndex[sampleIndex])
{
flipCount[sampleIndex]++;
}
else
{
if((flipCount[sampleIndex] & 0x01) != 0)
{
sampleColor[sampleIndex] = currentColor[sampleIndex];
}
vec4 nextColor = color;
if(useTexture)
{
vec3 sampleFP = vec3(vec2(samplePoint).xy/(subPixelFactor*2.), 1);
vec2 uv = (uvTransform * sampleFP).xy;
vec4 texColor = texture(srcTexture, uv);
texColor.rgb *= texColor.a;
nextColor *= texColor;
}
currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-nextColor.a) + nextColor;
currentShapeIndex[sampleIndex] = shapeIndex;
flipCount[sampleIndex] = 1;
}
}
}
}
}
vec4 pixelColor = vec4(0);
for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)
{
if((flipCount[sampleIndex] & 0x01) != 0)
{
sampleColor[sampleIndex] = currentColor[sampleIndex];
}
pixelColor += sampleColor[sampleIndex];
}
imageStore(outTexture, pixelCoord, pixelColor/float(sampleCount));
}
#extension GL_ARB_gpu_shader_int64 : require
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
precision mediump float;
//precision mediump image2D;
layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
vertex elements[];
} vertexBuffer ;
layout(binding = 1) restrict readonly buffer shapeBufferSSBO {
shape elements[];
} shapeBuffer ;
layout(binding = 2) restrict readonly buffer indexBufferSSBO {
uint elements[];
} indexBuffer ;
layout(binding = 3) restrict readonly buffer tileCounterBufferSSBO {
uint elements[];
} tileCounterBuffer ;
layout(binding = 4) restrict readonly buffer tileArrayBufferSSBO {
uint elements[];
} tileArrayBuffer ;
layout(location = 0) uniform uint indexCount;
layout(location = 1) uniform uvec2 tileCount;
layout(location = 2) uniform uint tileSize;
layout(location = 3) uniform uint tileArraySize;
layout(location = 4) uniform vec2 scaling;
layout(location = 5) uniform uint useTexture;
layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;
layout(binding = 1) uniform sampler2D srcTexture;
bool is_top_left(ivec2 a, ivec2 b)
{
return( (a.y == b.y && b.x < a.x)
||(b.y < a.y));
}
//////////////////////////////////////////////////////////////////////////////
//TODO: we should do these computations on 64bits, because otherwise
// we might overflow for values > 2048.
// Unfortunately this is costly.
// Another way is to precompute triangle edges (b - a) in full precision
// once to avoid doing it all the time...
//////////////////////////////////////////////////////////////////////////////
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));
}
int is_clockwise(ivec2 p0, ivec2 p1, ivec2 p2)
{
return((p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x);
}
void main()
{
ivec2 pixelCoord = ivec2(gl_WorkGroupID.xy*uvec2(16, 16) + gl_LocalInvocationID.xy);
uvec2 tileCoord = uvec2(pixelCoord) / tileSize;
uint tileIndex = tileCoord.y * tileCount.x + tileCoord.x;
uint tileCounter = min(tileCounterBuffer.elements[tileIndex], tileArraySize);
const float subPixelFactor = 16.;
ivec2 centerPoint = ivec2((vec2(pixelCoord) + vec2(0.5, 0.5)) * subPixelFactor);
//*
const int sampleCount = 8;
ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(1, 3),
centerPoint + ivec2(-1, -3),
centerPoint + ivec2(5, -1),
centerPoint + ivec2(-3, 5),
centerPoint + ivec2(-5, -5),
centerPoint + ivec2(-7, 1),
centerPoint + ivec2(3, -7),
centerPoint + ivec2(7, 7));
/*/
const int sampleCount = 4;
ivec2 samplePoints[sampleCount] = ivec2[sampleCount](centerPoint + ivec2(-2, 6),
centerPoint + ivec2(6, 2),
centerPoint + ivec2(-6, -2),
centerPoint + ivec2(2, -6));
//*/
//DEBUG
/*
{
vec4 fragColor = vec4(0);
if( pixelCoord.x % 16 == 0
||pixelCoord.y % 16 == 0)
{
fragColor = vec4(0, 0, 0, 1);
}
else if(tileCounterBuffer.elements[tileIndex] == 0xffffu)
{
fragColor = vec4(1, 0, 1, 1);
}
else if(tileCounter != 0u)
{
fragColor = vec4(0, 1, 0, 1);
}
else
{
fragColor = vec4(1, 0, 0, 1);
}
imageStore(outTexture, pixelCoord, fragColor);
return;
}
//*/
//----
vec4 sampleColor[sampleCount];
vec4 currentColor[sampleCount];
int currentShapeIndex[sampleCount];
int flipCount[sampleCount];
for(int i=0; i<sampleCount; i++)
{
currentShapeIndex[i] = -1;
flipCount[i] = 0;
sampleColor[i] = vec4(0, 0, 0, 0);
currentColor[i] = vec4(0, 0, 0, 0);
}
for(uint tileArrayIndex=0u; tileArrayIndex < tileCounter; tileArrayIndex++)
{
uint triangleIndex = tileArrayBuffer.elements[tileArraySize * tileIndex + tileArrayIndex];
uint i0 = indexBuffer.elements[triangleIndex];
uint i1 = indexBuffer.elements[triangleIndex+1u];
uint i2 = indexBuffer.elements[triangleIndex+2u];
ivec2 p0 = ivec2((vertexBuffer.elements[i0].pos * scaling) * subPixelFactor);
ivec2 p1 = ivec2((vertexBuffer.elements[i1].pos * scaling) * subPixelFactor);
ivec2 p2 = ivec2((vertexBuffer.elements[i2].pos * scaling) * subPixelFactor);
int shapeIndex = vertexBuffer.elements[i0].shapeIndex;
vec4 color = shapeBuffer.elements[shapeIndex].color;
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));
mat3 uvTransform = mat3(shapeBuffer.elements[shapeIndex].uvTransform[0],
shapeBuffer.elements[shapeIndex].uvTransform[3],
0.,
shapeBuffer.elements[shapeIndex].uvTransform[1],
shapeBuffer.elements[shapeIndex].uvTransform[4],
0.,
shapeBuffer.elements[shapeIndex].uvTransform[2],
shapeBuffer.elements[shapeIndex].uvTransform[5],
1.);
//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
int cw = is_clockwise(p0, p1, p2);
if(cw < 0)
{
uint tmpIndex = i1;
i1 = i2;
i2 = tmpIndex;
ivec2 tmpPoint = p1;
p1 = p2;
p2 = tmpPoint;
}
vec4 cubic0 = vertexBuffer.elements[i0].cubic;
vec4 cubic1 = vertexBuffer.elements[i1].cubic;
vec4 cubic2 = vertexBuffer.elements[i2].cubic;
int bias0 = is_top_left(p1, p2) ? 0 : -1;
int bias1 = is_top_left(p2, p0) ? 0 : -1;
int bias2 = is_top_left(p0, p1) ? 0 : -1;
for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)
{
ivec2 samplePoint = samplePoints[sampleIndex];
if( samplePoint.x < clip.x
|| samplePoint.x > clip.z
|| samplePoint.y < clip.y
|| samplePoint.y > clip.w)
{
continue;
}
int w0 = orient2d(p1, p2, samplePoint);
int w1 = orient2d(p2, p0, samplePoint);
int w2 = orient2d(p0, p1, samplePoint);
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));
float eps = 0.0001;
if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)
{
if(shapeIndex == currentShapeIndex[sampleIndex])
{
flipCount[sampleIndex]++;
}
else
{
if((flipCount[sampleIndex] & 0x01) != 0)
{
sampleColor[sampleIndex] = currentColor[sampleIndex];
}
vec4 nextColor = color;
if(useTexture)
{
vec3 sampleFP = vec3(vec2(samplePoint).xy/(subPixelFactor*2.), 1);
vec2 uv = (uvTransform * sampleFP).xy;
vec4 texColor = texture(srcTexture, uv);
texColor.rgb *= texColor.a;
nextColor *= texColor;
}
currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-nextColor.a) + nextColor;
currentShapeIndex[sampleIndex] = shapeIndex;
flipCount[sampleIndex] = 1;
}
}
}
}
}
vec4 pixelColor = vec4(0);
for(int sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)
{
if((flipCount[sampleIndex] & 0x01) != 0)
{
sampleColor[sampleIndex] = currentColor[sampleIndex];
}
pixelColor += sampleColor[sampleIndex];
}
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;
precision mediump float;
layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
vertex elements[];
} vertexBuffer ;
layout(binding = 1) restrict readonly buffer shapeBufferSSBO {
shape elements[];
} shapeBuffer ;
layout(binding = 2) restrict readonly buffer indexBufferSSBO {
uint elements[];
} indexBuffer ;
layout(binding = 3) coherent readonly restrict buffer tileCounterBufferSSBO {
uint elements[];
} tileCounterBuffer ;
layout(binding = 4) coherent restrict buffer tileArrayBufferSSBO {
uint elements[];
} tileArrayBuffer ;
layout(location = 0) uniform uint indexCount;
layout(location = 1) uniform uvec2 tileCount;
layout(location = 2) uniform uint tileSize;
layout(location = 3) uniform uint tileArraySize;
int get_shape_index(uint tileArrayOffset, uint tileArrayIndex)
{
uint triangleIndex = tileArrayBuffer.elements[tileArrayOffset + tileArrayIndex];
uint i0 = indexBuffer.elements[triangleIndex];
int shapeIndex = vertexBuffer.elements[i0].shapeIndex;
return(shapeIndex);
}
void main()
{
uint tileIndex = gl_WorkGroupID.x;
uint tileArrayOffset = tileArraySize * tileIndex;
uint tileArrayCount = min(tileCounterBuffer.elements[tileIndex], tileArraySize);
for(uint tileArrayIndex=1u; tileArrayIndex < tileArrayCount; tileArrayIndex++)
{
for(uint sortIndex = tileArrayIndex; sortIndex > 0u; sortIndex--)
{
int shapeIndex = get_shape_index(tileArrayOffset, sortIndex);
int prevShapeIndex = get_shape_index(tileArrayOffset, sortIndex-1u);
if(shapeIndex >= prevShapeIndex)
{
break;
}
uint tmp = tileArrayBuffer.elements[tileArrayOffset + sortIndex];
tileArrayBuffer.elements[tileArrayOffset + sortIndex] = tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u];
tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u] = tmp;
}
}
}
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
precision mediump float;
layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
vertex elements[];
} vertexBuffer ;
layout(binding = 1) restrict readonly buffer shapeBufferSSBO {
shape elements[];
} shapeBuffer ;
layout(binding = 2) restrict readonly buffer indexBufferSSBO {
uint elements[];
} indexBuffer ;
layout(binding = 3) coherent readonly restrict buffer tileCounterBufferSSBO {
uint elements[];
} tileCounterBuffer ;
layout(binding = 4) coherent restrict buffer tileArrayBufferSSBO {
uint elements[];
} tileArrayBuffer ;
layout(location = 0) uniform uint indexCount;
layout(location = 1) uniform uvec2 tileCount;
layout(location = 2) uniform uint tileSize;
layout(location = 3) uniform uint tileArraySize;
int get_shape_index(uint tileArrayOffset, uint tileArrayIndex)
{
uint triangleIndex = tileArrayBuffer.elements[tileArrayOffset + tileArrayIndex];
uint i0 = indexBuffer.elements[triangleIndex];
int shapeIndex = vertexBuffer.elements[i0].shapeIndex;
return(shapeIndex);
}
void main()
{
uint tileIndex = gl_WorkGroupID.x;
uint tileArrayOffset = tileArraySize * tileIndex;
uint tileArrayCount = min(tileCounterBuffer.elements[tileIndex], tileArraySize);
for(uint tileArrayIndex=1u; tileArrayIndex < tileArrayCount; tileArrayIndex++)
{
for(uint sortIndex = tileArrayIndex; sortIndex > 0u; sortIndex--)
{
int shapeIndex = get_shape_index(tileArrayOffset, sortIndex);
int prevShapeIndex = get_shape_index(tileArrayOffset, sortIndex-1u);
if(shapeIndex >= prevShapeIndex)
{
break;
}
uint tmp = tileArrayBuffer.elements[tileArrayOffset + sortIndex];
tileArrayBuffer.elements[tileArrayOffset + sortIndex] = tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u];
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;
precision mediump float;
layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
vertex elements[];
} vertexBuffer ;
layout(binding = 1) restrict readonly buffer shapeBufferSSBO {
shape elements[];
} shapeBuffer ;
layout(binding = 2) restrict readonly buffer indexBufferSSBO {
uint elements[];
} indexBuffer ;
layout(binding = 3) coherent restrict buffer tileCounterBufferSSBO {
uint elements[];
} tileCounterBuffer ;
layout(binding = 4) coherent restrict writeonly buffer tileArrayBufferSSBO {
uint elements[];
} tileArrayBuffer ;
layout(location = 0) uniform uint indexCount;
layout(location = 1) uniform uvec2 tileCount;
layout(location = 2) uniform uint tileSize;
layout(location = 3) uniform uint tileArraySize;
layout(location = 4) uniform vec2 scaling;
void main()
{
uint triangleIndex = (gl_WorkGroupID.x*gl_WorkGroupSize.x + gl_LocalInvocationIndex) * 3u;
if(triangleIndex >= indexCount)
{
return;
}
uint i0 = indexBuffer.elements[triangleIndex];
uint i1 = indexBuffer.elements[triangleIndex+1u];
uint i2 = indexBuffer.elements[triangleIndex+2u];
vec2 p0 = vertexBuffer.elements[i0].pos * scaling;
vec2 p1 = vertexBuffer.elements[i1].pos * scaling;
vec2 p2 = vertexBuffer.elements[i2].pos * scaling;
int shapeIndex = vertexBuffer.elements[i0].shapeIndex;
vec4 clip = shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling);
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),
min(max(max(p0.x, p1.x), p2.x), clip.z),
min(max(max(p0.y, p1.y), p2.y), clip.w));
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
// 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 yMin = max(0, box.y);
int xMax = min(box.z, int(tileCount.x) - 1);
int yMax = min(box.w, int(tileCount.y) - 1);
for(int y = yMin; y <= yMax; y++)
{
for(int x = xMin ; x <= xMax; x++)
{
uint tileIndex = uint(y)*tileCount.x + uint(x);
uint tileCounter = atomicAdd(tileCounterBuffer.elements[tileIndex], 1u);
if(tileCounter < tileArraySize)
{
tileArrayBuffer.elements[tileArraySize*tileIndex + tileCounter] = triangleIndex;
}
}
}
}
layout(local_size_x = 512, local_size_y = 1, local_size_z = 1) in;
precision mediump float;
layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
vertex elements[];
} vertexBuffer ;
layout(binding = 1) restrict readonly buffer shapeBufferSSBO {
shape elements[];
} shapeBuffer ;
layout(binding = 2) restrict readonly buffer indexBufferSSBO {
uint elements[];
} indexBuffer ;
layout(binding = 3) coherent restrict buffer tileCounterBufferSSBO {
uint elements[];
} tileCounterBuffer ;
layout(binding = 4) coherent restrict writeonly buffer tileArrayBufferSSBO {
uint elements[];
} tileArrayBuffer ;
layout(location = 0) uniform uint indexCount;
layout(location = 1) uniform uvec2 tileCount;
layout(location = 2) uniform uint tileSize;
layout(location = 3) uniform uint tileArraySize;
layout(location = 4) uniform vec2 scaling;
void main()
{
uint triangleIndex = (gl_WorkGroupID.x*gl_WorkGroupSize.x + gl_LocalInvocationIndex) * 3u;
if(triangleIndex >= indexCount)
{
return;
}
uint i0 = indexBuffer.elements[triangleIndex];
uint i1 = indexBuffer.elements[triangleIndex+1u];
uint i2 = indexBuffer.elements[triangleIndex+2u];
vec2 p0 = vertexBuffer.elements[i0].pos * scaling;
vec2 p1 = vertexBuffer.elements[i1].pos * scaling;
vec2 p2 = vertexBuffer.elements[i2].pos * scaling;
int shapeIndex = vertexBuffer.elements[i0].shapeIndex;
vec4 clip = shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling);
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),
min(max(max(p0.x, p1.x), p2.x), clip.z),
min(max(max(p0.y, p1.y), p2.y), clip.w));
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
// 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 yMin = max(0, box.y);
int xMax = min(box.z, int(tileCount.x) - 1);
int yMax = min(box.w, int(tileCount.y) - 1);
for(int y = yMin; y <= yMax; y++)
{
for(int x = xMin ; x <= xMax; x++)
{
uint tileIndex = uint(y)*tileCount.x + uint(x);
uint tileCounter = atomicAdd(tileCounterBuffer.elements[tileIndex], 1u);
if(tileCounter < tileArraySize)
{
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
* @author: Martin Fouilleul
* @date: 23/01/2023
* @revision:
*
*****************************************************************/
#ifndef __GRAPHICS_H_
#define __GRAPHICS_H_
#include"typedefs.h"
#include"platform.h"
#include"mp_app.h"
//------------------------------------------------------------------------------------------
//NOTE(martin): backends selection
//------------------------------------------------------------------------------------------
typedef enum {
MG_BACKEND_NONE,
MG_BACKEND_METAL,
MG_BACKEND_GL,
MG_BACKEND_GLES,
MG_BACKEND_HOST } mg_backend_id;
//NOTE: these macros are used to select which backend to include when building milepost
// they can be overridden by passing them to the compiler command line
#if defined(OS_MACOS)
#ifndef MG_COMPILE_BACKEND_METAL
#define MG_COMPILE_BACKEND_METAL 1
#endif
#ifndef MG_COMPILE_BACKEND_GLES
#define MG_COMPILE_BACKEND_GLES 1
#endif
#define MG_COMPILE_BACKEND_GL 0
#if MG_COMPILE_BACKEND_METAL
#define MG_BACKEND_DEFAULT MG_BACKEND_METAL
#elif MG_COMPILE_BACKEND_GL
#define MG_BACKEND_DEFAULT MG_BACKEND_GL
#else
#define MG_BACKEND_DEFAULT MG_BACKEND_NONE
#endif
#elif defined(OS_WIN64)
#ifndef MG_COMPILE_BACKEND_GL
#define MG_COMPILE_BACKEND_GL 1
#endif
#ifndef MG_COMPILE_BACKEND_GLES
#define MG_COMPILE_BACKEND_GLES 1
#endif
#if MG_COMPILE_BACKEND_GL
#define MG_BACKEND_DEFAULT MG_BACKEND_GL
#else
#define MG_BACKEND_DEFAULT MG_BACKEND_NONE
#endif
#elif defined(OS_LINUX)
#ifndef MG_COMPILE_BACKEND_GL
#define MG_COMPILE_BACKEND_GL 1
#endif
#endif
//NOTE: these macros are used to select backend-specific APIs to include when using milepost
#ifdef MG_EXPOSE_SURFACE_METAL
#include"mtl_surface.h"
#endif
#ifdef MG_EXPOSE_SURFACE_WGL
#include"wgl_surface.h"
#endif
//TODO: expose nsgl surface when supported, expose egl surface, etc...
//TODO: add MG_INCLUDE_OPENGL/GLES/etc, once we know how we make different gl versions co-exist
MP_API bool mg_is_surface_backend_available(mg_backend_id id);
MP_API bool mg_is_canvas_backend_available(mg_backend_id id);
//------------------------------------------------------------------------------------------
//NOTE(martin): graphics surface
//------------------------------------------------------------------------------------------
typedef struct mg_surface { u64 h; } mg_surface;
MP_API mg_surface mg_surface_nil();
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 void mg_surface_destroy(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_swap_interval(mg_surface surface, int swap);
MP_API vec2 mg_surface_contents_scaling(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 bool mg_surface_get_hidden(mg_surface surface);
MP_API void mg_surface_set_hidden(mg_surface surface, bool hidden);
//NOTE(martin): surface sharing
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_host(mp_window window);
MP_API mg_surface_id mg_surface_remote_id(mg_surface surface);
MP_API void mg_surface_host_connect(mg_surface surface, mg_surface_id remoteId);
//------------------------------------------------------------------------------------------
//NOTE(martin): graphics canvas structs
//------------------------------------------------------------------------------------------
typedef struct mg_canvas { u64 h; } mg_canvas;
typedef struct mg_font { u64 h; } mg_font;
typedef struct mg_image { u64 h; } mg_image;
typedef struct mg_mat2x3
{
f32 m[6];
} mg_mat2x3;
typedef struct mg_color
{
union
{
struct
{
f32 r;
f32 g;
f32 b;
f32 a;
};
f32 c[4];
};
} mg_color;
typedef enum {MG_JOINT_MITER = 0,
MG_JOINT_BEVEL,
MG_JOINT_NONE } mg_joint_type;
typedef enum {MG_CAP_NONE = 0,
MG_CAP_SQUARE } mg_cap_type;
typedef struct mg_font_extents
{
f32 ascent; // the extent above the baseline (by convention a positive value extends above the baseline)
f32 descent; // the extent below the baseline (by convention, positive value extends below the baseline)
f32 leading; // spacing between one row's descent and the next row's ascent
f32 xHeight; // height of the lower case letter 'x'
f32 capHeight; // height of the upper case letter 'M'
f32 width; // maximum width of the font
} mg_font_extents;
typedef struct mg_text_extents
{
f32 xBearing;
f32 yBearing;
f32 width;
f32 height;
f32 xAdvance;
f32 yAdvance;
} mg_text_extents;
//------------------------------------------------------------------------------------------
//NOTE(martin): graphics canvas
//------------------------------------------------------------------------------------------
MP_API mg_canvas mg_canvas_nil();
MP_API bool mg_canvas_is_nil(mg_canvas canvas);
MP_API mg_canvas mg_canvas_create(mg_surface surface);
MP_API void mg_canvas_destroy(mg_canvas canvas);
MP_API mg_canvas mg_canvas_set_current(mg_canvas canvas);
MP_API void mg_flush();
//------------------------------------------------------------------------------------------
//NOTE(martin): fonts
//------------------------------------------------------------------------------------------
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 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//
//TODO(martin): add enum error codes
MP_API mg_font_extents mg_font_get_extents(mg_font font);
MP_API mg_font_extents mg_font_get_scaled_extents(mg_font font, f32 emSize);
MP_API f32 mg_font_get_scale_for_em_pixels(mg_font font, f32 emSize);
//NOTE(martin): if you need to process more than one codepoint, first convert your codepoints to glyph indices, then use the
// glyph index versions of the functions, which can take an array of glyph indices.
MP_API str32 mg_font_get_glyph_indices(mg_font font, str32 codePoints, str32 backing);
MP_API str32 mg_font_push_glyph_indices(mg_font font, mem_arena* arena, str32 codePoints);
MP_API u32 mg_font_get_glyph_index(mg_font font, utf32 codePoint);
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 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);
//------------------------------------------------------------------------------------------
//NOTE(martin): images
//------------------------------------------------------------------------------------------
MP_API mg_image mg_image_nil();
MP_API bool mg_image_is_nil(mg_image a);
MP_API mg_image mg_image_create(u32 width, u32 height);
MP_API mg_image mg_image_create_from_rgba8(u32 width, u32 height, u8* pixels);
MP_API mg_image mg_image_create_from_data(str8 data, bool flip);
MP_API mg_image mg_image_create_from_file(str8 path, bool flip);
MP_API 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 vec2 mg_image_size(mg_image image);
//------------------------------------------------------------------------------------------
//NOTE(martin): atlasing
//------------------------------------------------------------------------------------------
//NOTE: rectangle allocator
typedef struct mg_rect_atlas mg_rect_atlas;
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);
void mg_rect_atlas_recycle(mg_rect_atlas* atlas, mp_rect rect);
//NOTE: image atlas helpers
typedef struct mg_image_region
{
mg_image image;
mp_rect rect;
} 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_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);
void mg_image_atlas_recycle(mg_rect_atlas* atlas, mg_image_region imageRgn);
//------------------------------------------------------------------------------------------
//NOTE(martin): transform, viewport and clipping
//------------------------------------------------------------------------------------------
MP_API void mg_viewport(mp_rect viewPort);
MP_API void mg_matrix_push(mg_mat2x3 matrix);
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_pop();
//------------------------------------------------------------------------------------------
//NOTE(martin): graphics attributes setting/getting
//------------------------------------------------------------------------------------------
MP_API void mg_set_color(mg_color color);
MP_API void mg_set_color_rgba(f32 r, f32 g, f32 b, f32 a);
MP_API void mg_set_width(f32 width);
MP_API void mg_set_tolerance(f32 tolerance);
MP_API void mg_set_joint(mg_joint_type joint);
MP_API void mg_set_max_joint_excursion(f32 maxJointExcursion);
MP_API void mg_set_cap(mg_cap_type cap);
MP_API void mg_set_font(mg_font font);
MP_API void mg_set_font_size(f32 size);
MP_API void mg_set_text_flip(bool flip);
MP_API void mg_set_image(mg_image image);
MP_API void mg_set_image_source_region(mp_rect region);
MP_API mg_color mg_get_color();
MP_API f32 mg_get_width();
MP_API f32 mg_get_tolerance();
MP_API mg_joint_type mg_get_joint();
MP_API f32 mg_get_max_joint_excursion();
MP_API mg_cap_type mg_get_cap();
MP_API mg_font mg_get_font();
MP_API f32 mg_get_font_size();
MP_API bool mg_get_text_flip();
//------------------------------------------------------------------------------------------
//NOTE(martin): path construction
//------------------------------------------------------------------------------------------
MP_API vec2 mg_get_position();
MP_API void mg_move_to(f32 x, f32 y);
MP_API void mg_line_to(f32 x, f32 y);
MP_API void mg_quadratic_to(f32 x1, f32 y1, f32 x2, f32 y2);
MP_API void mg_cubic_to(f32 x1, f32 y1, f32 x2, f32 y2, f32 x3, f32 y3);
MP_API void mg_close_path();
MP_API mp_rect mg_glyph_outlines(str32 glyphIndices);
MP_API void mg_codepoints_outlines(str32 string);
MP_API void mg_text_outlines(str8 string);
//------------------------------------------------------------------------------------------
//NOTE(martin): clear/fill/stroke
//------------------------------------------------------------------------------------------
MP_API void mg_clear();
MP_API void mg_fill();
MP_API void mg_stroke();
//------------------------------------------------------------------------------------------
//NOTE(martin): 'fast' shapes primitives
//------------------------------------------------------------------------------------------
MP_API void mg_rectangle_fill(f32 x, f32 y, f32 w, f32 h);
MP_API void mg_rectangle_stroke(f32 x, f32 y, f32 w, f32 h);
MP_API void mg_rounded_rectangle_fill(f32 x, f32 y, f32 w, f32 h, f32 r);
MP_API void mg_rounded_rectangle_stroke(f32 x, f32 y, f32 w, f32 h, f32 r);
MP_API void mg_ellipse_fill(f32 x, f32 y, f32 rx, f32 ry);
MP_API void mg_ellipse_stroke(f32 x, f32 y, f32 rx, f32 ry);
MP_API void mg_circle_fill(f32 x, f32 y, f32 r);
MP_API void mg_circle_stroke(f32 x, f32 y, f32 r);
MP_API void mg_arc(f32 x, f32 y, f32 r, f32 arcAngle, f32 startAngle);
//NOTE: image helpers
MP_API void mg_image_draw(mg_image image, mp_rect rect);
MP_API void mg_image_draw_region(mg_image image, mp_rect srcRegion, mp_rect dstRegion);
#endif //__GRAPHICS_H_
/************************************************************//**
*
* @file: graphics.h
* @author: Martin Fouilleul
* @date: 23/01/2023
* @revision:
*
*****************************************************************/
#ifndef __GRAPHICS_H_
#define __GRAPHICS_H_
#include"typedefs.h"
#include"platform.h"
#include"mp_app.h"
//------------------------------------------------------------------------------------------
//NOTE(martin): backends selection
//------------------------------------------------------------------------------------------
typedef enum {
MG_BACKEND_NONE,
MG_BACKEND_METAL,
MG_BACKEND_GL,
MG_BACKEND_GLES,
MG_BACKEND_HOST } mg_backend_id;
//NOTE: these macros are used to select which backend to include when building milepost
// they can be overridden by passing them to the compiler command line
#if defined(OS_MACOS)
#ifndef MG_COMPILE_BACKEND_METAL
#define MG_COMPILE_BACKEND_METAL 1
#endif
#ifndef MG_COMPILE_BACKEND_GLES
#define MG_COMPILE_BACKEND_GLES 1
#endif
#define MG_COMPILE_BACKEND_GL 0
#if MG_COMPILE_BACKEND_METAL
#define MG_BACKEND_DEFAULT MG_BACKEND_METAL
#elif MG_COMPILE_BACKEND_GL
#define MG_BACKEND_DEFAULT MG_BACKEND_GL
#else
#define MG_BACKEND_DEFAULT MG_BACKEND_NONE
#endif
#elif defined(OS_WIN64)
#ifndef MG_COMPILE_BACKEND_GL
#define MG_COMPILE_BACKEND_GL 1
#endif
#ifndef MG_COMPILE_BACKEND_GLES
#define MG_COMPILE_BACKEND_GLES 1
#endif
#if MG_COMPILE_BACKEND_GL
#define MG_BACKEND_DEFAULT MG_BACKEND_GL
#else
#define MG_BACKEND_DEFAULT MG_BACKEND_NONE
#endif
#elif defined(OS_LINUX)
#ifndef MG_COMPILE_BACKEND_GL
#define MG_COMPILE_BACKEND_GL 1
#endif
#endif
//NOTE: these macros are used to select backend-specific APIs to include when using milepost
#ifdef MG_EXPOSE_SURFACE_METAL
#include"mtl_surface.h"
#endif
#ifdef MG_EXPOSE_SURFACE_WGL
#include"wgl_surface.h"
#endif
//TODO: expose nsgl surface when supported, expose egl surface, etc...
//TODO: add MG_INCLUDE_OPENGL/GLES/etc, once we know how we make different gl versions co-exist
MP_API bool mg_is_surface_backend_available(mg_backend_id id);
MP_API bool mg_is_canvas_backend_available(mg_backend_id id);
//------------------------------------------------------------------------------------------
//NOTE(martin): graphics surface
//------------------------------------------------------------------------------------------
typedef struct mg_surface { u64 h; } mg_surface;
MP_API mg_surface mg_surface_nil();
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 void mg_surface_destroy(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_swap_interval(mg_surface surface, int swap);
MP_API vec2 mg_surface_contents_scaling(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 bool mg_surface_get_hidden(mg_surface surface);
MP_API void mg_surface_set_hidden(mg_surface surface, bool hidden);
//NOTE(martin): surface sharing
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_host(mp_window window);
MP_API mg_surface_id mg_surface_remote_id(mg_surface surface);
MP_API void mg_surface_host_connect(mg_surface surface, mg_surface_id remoteId);
//------------------------------------------------------------------------------------------
//NOTE(martin): graphics canvas structs
//------------------------------------------------------------------------------------------
typedef struct mg_canvas { u64 h; } mg_canvas;
typedef struct mg_font { u64 h; } mg_font;
typedef struct mg_image { u64 h; } mg_image;
typedef struct mg_mat2x3
{
f32 m[6];
} mg_mat2x3;
typedef struct mg_color
{
union
{
struct
{
f32 r;
f32 g;
f32 b;
f32 a;
};
f32 c[4];
};
} mg_color;
typedef enum {MG_JOINT_MITER = 0,
MG_JOINT_BEVEL,
MG_JOINT_NONE } mg_joint_type;
typedef enum {MG_CAP_NONE = 0,
MG_CAP_SQUARE } mg_cap_type;
typedef struct mg_font_extents
{
f32 ascent; // the extent above the baseline (by convention a positive value extends above the baseline)
f32 descent; // the extent below the baseline (by convention, positive value extends below the baseline)
f32 leading; // spacing between one row's descent and the next row's ascent
f32 xHeight; // height of the lower case letter 'x'
f32 capHeight; // height of the upper case letter 'M'
f32 width; // maximum width of the font
} mg_font_extents;
typedef struct mg_text_extents
{
f32 xBearing;
f32 yBearing;
f32 width;
f32 height;
f32 xAdvance;
f32 yAdvance;
} mg_text_extents;
//------------------------------------------------------------------------------------------
//NOTE(martin): graphics canvas
//------------------------------------------------------------------------------------------
MP_API mg_canvas mg_canvas_nil();
MP_API bool mg_canvas_is_nil(mg_canvas canvas);
MP_API mg_canvas mg_canvas_create(mg_surface surface);
MP_API void mg_canvas_destroy(mg_canvas canvas);
MP_API mg_canvas mg_canvas_set_current(mg_canvas canvas);
MP_API void mg_flush();
//------------------------------------------------------------------------------------------
//NOTE(martin): fonts
//------------------------------------------------------------------------------------------
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 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//
//TODO(martin): add enum error codes
MP_API mg_font_extents mg_font_get_extents(mg_font font);
MP_API mg_font_extents mg_font_get_scaled_extents(mg_font font, f32 emSize);
MP_API f32 mg_font_get_scale_for_em_pixels(mg_font font, f32 emSize);
//NOTE(martin): if you need to process more than one codepoint, first convert your codepoints to glyph indices, then use the
// glyph index versions of the functions, which can take an array of glyph indices.
MP_API str32 mg_font_get_glyph_indices(mg_font font, str32 codePoints, str32 backing);
MP_API str32 mg_font_push_glyph_indices(mg_font font, mem_arena* arena, str32 codePoints);
MP_API u32 mg_font_get_glyph_index(mg_font font, utf32 codePoint);
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 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);
//------------------------------------------------------------------------------------------
//NOTE(martin): images
//------------------------------------------------------------------------------------------
MP_API mg_image mg_image_nil();
MP_API bool mg_image_is_nil(mg_image a);
MP_API mg_image mg_image_create(u32 width, u32 height);
MP_API mg_image mg_image_create_from_rgba8(u32 width, u32 height, u8* pixels);
MP_API mg_image mg_image_create_from_data(str8 data, bool flip);
MP_API mg_image mg_image_create_from_file(str8 path, bool flip);
MP_API 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 vec2 mg_image_size(mg_image image);
//------------------------------------------------------------------------------------------
//NOTE(martin): atlasing
//------------------------------------------------------------------------------------------
//NOTE: rectangle allocator
typedef struct mg_rect_atlas mg_rect_atlas;
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);
void mg_rect_atlas_recycle(mg_rect_atlas* atlas, mp_rect rect);
//NOTE: image atlas helpers
typedef struct mg_image_region
{
mg_image image;
mp_rect rect;
} 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_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);
void mg_image_atlas_recycle(mg_rect_atlas* atlas, mg_image_region imageRgn);
//------------------------------------------------------------------------------------------
//NOTE(martin): transform, viewport and clipping
//------------------------------------------------------------------------------------------
MP_API void mg_viewport(mp_rect viewPort);
MP_API void mg_matrix_push(mg_mat2x3 matrix);
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_pop();
//------------------------------------------------------------------------------------------
//NOTE(martin): graphics attributes setting/getting
//------------------------------------------------------------------------------------------
MP_API void mg_set_color(mg_color color);
MP_API void mg_set_color_rgba(f32 r, f32 g, f32 b, f32 a);
MP_API void mg_set_width(f32 width);
MP_API void mg_set_tolerance(f32 tolerance);
MP_API void mg_set_joint(mg_joint_type joint);
MP_API void mg_set_max_joint_excursion(f32 maxJointExcursion);
MP_API void mg_set_cap(mg_cap_type cap);
MP_API void mg_set_font(mg_font font);
MP_API void mg_set_font_size(f32 size);
MP_API void mg_set_text_flip(bool flip);
MP_API void mg_set_image(mg_image image);
MP_API void mg_set_image_source_region(mp_rect region);
MP_API mg_color mg_get_color();
MP_API f32 mg_get_width();
MP_API f32 mg_get_tolerance();
MP_API mg_joint_type mg_get_joint();
MP_API f32 mg_get_max_joint_excursion();
MP_API mg_cap_type mg_get_cap();
MP_API mg_font mg_get_font();
MP_API f32 mg_get_font_size();
MP_API bool mg_get_text_flip();
//------------------------------------------------------------------------------------------
//NOTE(martin): path construction
//------------------------------------------------------------------------------------------
MP_API vec2 mg_get_position();
MP_API void mg_move_to(f32 x, f32 y);
MP_API void mg_line_to(f32 x, f32 y);
MP_API void mg_quadratic_to(f32 x1, f32 y1, f32 x2, f32 y2);
MP_API void mg_cubic_to(f32 x1, f32 y1, f32 x2, f32 y2, f32 x3, f32 y3);
MP_API void mg_close_path();
MP_API mp_rect mg_glyph_outlines(str32 glyphIndices);
MP_API void mg_codepoints_outlines(str32 string);
MP_API void mg_text_outlines(str8 string);
//------------------------------------------------------------------------------------------
//NOTE(martin): clear/fill/stroke
//------------------------------------------------------------------------------------------
MP_API void mg_clear();
MP_API void mg_fill();
MP_API void mg_stroke();
//------------------------------------------------------------------------------------------
//NOTE(martin): 'fast' shapes primitives
//------------------------------------------------------------------------------------------
MP_API void mg_rectangle_fill(f32 x, f32 y, f32 w, f32 h);
MP_API void mg_rectangle_stroke(f32 x, f32 y, f32 w, f32 h);
MP_API void mg_rounded_rectangle_fill(f32 x, f32 y, f32 w, f32 h, f32 r);
MP_API void mg_rounded_rectangle_stroke(f32 x, f32 y, f32 w, f32 h, f32 r);
MP_API void mg_ellipse_fill(f32 x, f32 y, f32 rx, f32 ry);
MP_API void mg_ellipse_stroke(f32 x, f32 y, f32 rx, f32 ry);
MP_API void mg_circle_fill(f32 x, f32 y, f32 r);
MP_API void mg_circle_stroke(f32 x, f32 y, f32 r);
MP_API void mg_arc(f32 x, f32 y, f32 r, f32 arcAngle, f32 startAngle);
//NOTE: image helpers
MP_API void mg_image_draw(mg_image image, mp_rect rect);
MP_API void mg_image_draw_region(mg_image image, mp_rect srcRegion, mp_rect dstRegion);
#endif //__GRAPHICS_H_

View File

@ -1,143 +1,143 @@
/************************************************************//**
*
* @file: graphics_internal.h
* @author: Martin Fouilleul
* @date: 23/01/2023
* @revision:
*
*****************************************************************/
#ifndef __GRAPHICS_INTERNAL_H_
#define __GRAPHICS_INTERNAL_H_
#include"graphics.h"
#include"mp_app_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
//---------------------------------------------------------------
// surface interface
//---------------------------------------------------------------
typedef struct mg_surface_data mg_surface_data;
typedef void (*mg_surface_destroy_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_swap_interval_proc)(mg_surface_data* surface, int swap);
typedef vec2 (*mg_surface_contents_scaling_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 bool (*mg_surface_get_hidden_proc)(mg_surface_data* surface);
typedef void (*mg_surface_set_hidden_proc)(mg_surface_data* surface, bool hidden);
typedef void* (*mg_surface_native_layer_proc)(mg_surface_data* surface);
typedef mg_surface_id (*mg_surface_remote_id_proc)(mg_surface_data* surface);
typedef void (*mg_surface_host_connect_proc)(mg_surface_data* surface, mg_surface_id remoteId);
typedef struct mg_surface_data
{
mg_backend_id backend;
mp_layer layer;
mg_surface_destroy_proc destroy;
mg_surface_prepare_proc prepare;
mg_surface_present_proc present;
mg_surface_swap_interval_proc swapInterval;
mg_surface_contents_scaling_proc contentsScaling;
mg_surface_get_frame_proc getFrame;
mg_surface_set_frame_proc setFrame;
mg_surface_get_hidden_proc getHidden;
mg_surface_set_hidden_proc setHidden;
mg_surface_native_layer_proc nativeLayer;
mg_surface_remote_id_proc remoteID;
mg_surface_host_connect_proc hostConnect;
} mg_surface_data;
mg_surface mg_surface_alloc_handle(mg_surface_data* surface);
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_remote(mg_surface_data* surface, u32 width, u32 height);
void mg_surface_init_host(mg_surface_data* surface, mp_window_data* window);
void mg_surface_cleanup(mg_surface_data* surface);
void* mg_surface_native_layer(mg_surface surface);
//---------------------------------------------------------------
// canvas backend interface
//---------------------------------------------------------------
typedef struct mg_image_data
{
list_elt listElt;
u32 generation;
vec2 size;
} mg_image_data;
typedef struct mg_vertex_layout
{
u32 maxVertexCount;
u32 maxIndexCount;
char* posBuffer;
u32 posStride;
char* cubicBuffer;
u32 cubicStride;
char* uvTransformBuffer;
u32 uvTransformStride;
char* colorBuffer;
u32 colorStride;
char* shapeIndexBuffer;
u32 shapeIndexStride;
char* clipBuffer;
u32 clipStride;
char* indexBuffer;
u32 indexStride;
} mg_vertex_layout;
typedef struct mg_canvas_backend mg_canvas_backend;
typedef void (*mg_canvas_backend_destroy_proc)(mg_canvas_backend* backend);
typedef void (*mg_canvas_backend_begin_proc)(mg_canvas_backend* backend);
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_draw_batch_proc)(mg_canvas_backend* backend,
mg_image_data* imageData,
u32 vertexCount,
u32 shapeCount,
u32 indexCount);
typedef mg_image_data* (*mg_canvas_backend_image_create_proc)(mg_canvas_backend* backend, vec2 size);
typedef void (*mg_canvas_backend_image_destroy_proc)(mg_canvas_backend* backend, mg_image_data* image);
typedef void (*mg_canvas_backend_image_upload_region_proc)(mg_canvas_backend* backend,
mg_image_data* image,
mp_rect region,
u8* pixels);
typedef struct mg_canvas_backend
{
mg_vertex_layout vertexLayout;
mg_canvas_backend_destroy_proc destroy;
mg_canvas_backend_begin_proc begin;
mg_canvas_backend_end_proc end;
mg_canvas_backend_clear_proc clear;
mg_canvas_backend_draw_batch_proc drawBatch;
mg_canvas_backend_image_create_proc imageCreate;
mg_canvas_backend_image_destroy_proc imageDestroy;
mg_canvas_backend_image_upload_region_proc imageUploadRegion;
} mg_canvas_backend;
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__GRAPHICS_INTERNAL_H_
/************************************************************//**
*
* @file: graphics_internal.h
* @author: Martin Fouilleul
* @date: 23/01/2023
* @revision:
*
*****************************************************************/
#ifndef __GRAPHICS_INTERNAL_H_
#define __GRAPHICS_INTERNAL_H_
#include"graphics.h"
#include"mp_app_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
//---------------------------------------------------------------
// surface interface
//---------------------------------------------------------------
typedef struct mg_surface_data mg_surface_data;
typedef void (*mg_surface_destroy_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_swap_interval_proc)(mg_surface_data* surface, int swap);
typedef vec2 (*mg_surface_contents_scaling_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 bool (*mg_surface_get_hidden_proc)(mg_surface_data* surface);
typedef void (*mg_surface_set_hidden_proc)(mg_surface_data* surface, bool hidden);
typedef void* (*mg_surface_native_layer_proc)(mg_surface_data* surface);
typedef mg_surface_id (*mg_surface_remote_id_proc)(mg_surface_data* surface);
typedef void (*mg_surface_host_connect_proc)(mg_surface_data* surface, mg_surface_id remoteId);
typedef struct mg_surface_data
{
mg_backend_id backend;
mp_layer layer;
mg_surface_destroy_proc destroy;
mg_surface_prepare_proc prepare;
mg_surface_present_proc present;
mg_surface_swap_interval_proc swapInterval;
mg_surface_contents_scaling_proc contentsScaling;
mg_surface_get_frame_proc getFrame;
mg_surface_set_frame_proc setFrame;
mg_surface_get_hidden_proc getHidden;
mg_surface_set_hidden_proc setHidden;
mg_surface_native_layer_proc nativeLayer;
mg_surface_remote_id_proc remoteID;
mg_surface_host_connect_proc hostConnect;
} mg_surface_data;
mg_surface mg_surface_alloc_handle(mg_surface_data* surface);
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_remote(mg_surface_data* surface, u32 width, u32 height);
void mg_surface_init_host(mg_surface_data* surface, mp_window_data* window);
void mg_surface_cleanup(mg_surface_data* surface);
void* mg_surface_native_layer(mg_surface surface);
//---------------------------------------------------------------
// canvas backend interface
//---------------------------------------------------------------
typedef struct mg_image_data
{
list_elt listElt;
u32 generation;
vec2 size;
} mg_image_data;
typedef struct mg_vertex_layout
{
u32 maxVertexCount;
u32 maxIndexCount;
char* posBuffer;
u32 posStride;
char* cubicBuffer;
u32 cubicStride;
char* uvTransformBuffer;
u32 uvTransformStride;
char* colorBuffer;
u32 colorStride;
char* shapeIndexBuffer;
u32 shapeIndexStride;
char* clipBuffer;
u32 clipStride;
char* indexBuffer;
u32 indexStride;
} mg_vertex_layout;
typedef struct mg_canvas_backend mg_canvas_backend;
typedef void (*mg_canvas_backend_destroy_proc)(mg_canvas_backend* backend);
typedef void (*mg_canvas_backend_begin_proc)(mg_canvas_backend* backend);
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_draw_batch_proc)(mg_canvas_backend* backend,
mg_image_data* imageData,
u32 vertexCount,
u32 shapeCount,
u32 indexCount);
typedef mg_image_data* (*mg_canvas_backend_image_create_proc)(mg_canvas_backend* backend, vec2 size);
typedef void (*mg_canvas_backend_image_destroy_proc)(mg_canvas_backend* backend, mg_image_data* image);
typedef void (*mg_canvas_backend_image_upload_region_proc)(mg_canvas_backend* backend,
mg_image_data* image,
mp_rect region,
u8* pixels);
typedef struct mg_canvas_backend
{
mg_vertex_layout vertexLayout;
mg_canvas_backend_destroy_proc destroy;
mg_canvas_backend_begin_proc begin;
mg_canvas_backend_end_proc end;
mg_canvas_backend_clear_proc clear;
mg_canvas_backend_draw_batch_proc drawBatch;
mg_canvas_backend_image_create_proc imageCreate;
mg_canvas_backend_image_destroy_proc imageDestroy;
mg_canvas_backend_image_upload_region_proc imageUploadRegion;
} mg_canvas_backend;
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__GRAPHICS_INTERNAL_H_

View File

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

View File

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

View File

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

View File

@ -1,407 +1,407 @@
/************************************************************//**
*
* @file: mp_app_internal.c
* @author: Martin Fouilleul
* @date: 23/12/2022
* @revision:
*
*****************************************************************/
#include"mp_app_internal.h"
#define LOG_SUBSYSTEM "Application"
mp_app __mpApp = {0};
//---------------------------------------------------------------
// Window handles
//---------------------------------------------------------------
void mp_init_window_handles()
{
ListInit(&__mpApp.windowFreeList);
for(int i=0; i<MP_APP_MAX_WINDOWS; i++)
{
__mpApp.windowPool[i].generation = 1;
ListAppend(&__mpApp.windowFreeList, &__mpApp.windowPool[i].freeListElt);
}
}
bool mp_window_handle_is_null(mp_window window)
{
return(window.h == 0);
}
mp_window mp_window_null_handle()
{
return((mp_window){.h = 0});
}
mp_window_data* mp_window_alloc()
{
return(ListPopEntry(&__mpApp.windowFreeList, mp_window_data, freeListElt));
}
mp_window_data* mp_window_ptr_from_handle(mp_window handle)
{
u32 index = handle.h>>32;
u32 generation = handle.h & 0xffffffff;
if(index >= MP_APP_MAX_WINDOWS)
{
return(0);
}
mp_window_data* window = &__mpApp.windowPool[index];
if(window->generation != generation)
{
return(0);
}
else
{
return(window);
}
}
mp_window mp_window_handle_from_ptr(mp_window_data* window)
{
DEBUG_ASSERT( (window - __mpApp.windowPool) >= 0
&& (window - __mpApp.windowPool) < MP_APP_MAX_WINDOWS);
u64 h = ((u64)(window - __mpApp.windowPool))<<32
| ((u64)window->generation);
return((mp_window){h});
}
void mp_window_recycle_ptr(mp_window_data* window)
{
window->generation++;
ListPush(&__mpApp.windowFreeList, &window->freeListElt);
}
//---------------------------------------------------------------
// Init
//---------------------------------------------------------------
static void mp_init_common()
{
mp_init_window_handles();
ringbuffer_init(&__mpApp.eventQueue, 16);
}
static void mp_terminate_common()
{
ringbuffer_cleanup(&__mpApp.eventQueue);
}
//---------------------------------------------------------------
// Event handling
//---------------------------------------------------------------
void mp_queue_event(mp_event* event)
{
if(ringbuffer_write_available(&__mpApp.eventQueue) < sizeof(mp_event))
{
LOG_ERROR("event queue full\n");
}
else
{
u32 written = ringbuffer_write(&__mpApp.eventQueue, sizeof(mp_event), (u8*)event);
DEBUG_ASSERT(written == sizeof(mp_event));
}
}
bool mp_next_event(mp_event* event)
{
//NOTE pop and return event from queue
if(ringbuffer_read_available(&__mpApp.eventQueue) >= sizeof(mp_event))
{
u64 read = ringbuffer_read(&__mpApp.eventQueue, sizeof(mp_event), (u8*)event);
DEBUG_ASSERT(read == sizeof(mp_event));
return(true);
}
else
{
return(false);
}
}
//---------------------------------------------------------------
// Input state updating
//---------------------------------------------------------------
static void mp_update_key_state(mp_key_state* key, mp_key_action action)
{
u64 frameCounter = __mpApp.inputState.frameCounter;
if(key->lastUpdate != frameCounter)
{
key->transitionCount = 0;
key->repeatCount = 0;
key->sysClicked = false;
key->sysDoubleClicked = false;
key->lastUpdate = frameCounter;
}
switch(action)
{
case MP_KEY_PRESS:
{
if(!key->down)
{
key->transitionCount++;
}
key->down = true;
} break;
case MP_KEY_REPEAT:
{
key->repeatCount++;
key->down = true;
} break;
case MP_KEY_RELEASE:
{
if(key->down)
{
key->transitionCount++;
}
key->down = false;
} break;
default:
break;
}
}
static void mp_update_mouse_move(f32 x, f32 y, f32 deltaX, f32 deltaY)
{
u64 frameCounter = __mpApp.inputState.frameCounter;
mp_mouse_state* mouse = &__mpApp.inputState.mouse;
if(mouse->lastUpdate != frameCounter)
{
mouse->delta = (vec2){0, 0};
mouse->wheel = (vec2){0, 0};
mouse->lastUpdate = frameCounter;
}
mouse->pos = (vec2){x, y};
mouse->delta.x += deltaX;
mouse->delta.y += deltaY;
}
static void mp_update_mouse_wheel(f32 deltaX, f32 deltaY)
{
u64 frameCounter = __mpApp.inputState.frameCounter;
mp_mouse_state* mouse = &__mpApp.inputState.mouse;
if(mouse->lastUpdate != frameCounter)
{
mouse->delta = (vec2){0, 0};
mouse->wheel = (vec2){0, 0};
mouse->lastUpdate = frameCounter;
}
mouse->wheel.x += deltaX;
mouse->wheel.y += deltaY;
}
static void mp_update_text(utf32 codepoint)
{
u64 frameCounter = __mpApp.inputState.frameCounter;
mp_text_state* text = &__mpApp.inputState.text;
if(text->lastUpdate != frameCounter)
{
text->codePoints.len = 0;
text->lastUpdate = frameCounter;
}
text->codePoints.ptr = text->backing;
if(text->codePoints.len < MP_INPUT_TEXT_BACKING_SIZE)
{
text->codePoints.ptr[text->codePoints.len] = codepoint;
text->codePoints.len++;
}
else
{
LOG_WARNING("too many input codepoints per frame, dropping input");
}
}
//--------------------------------------------------------------------
// Input state polling
//--------------------------------------------------------------------
mp_key_state mp_key_get_state(mp_key_code key)
{
mp_key_state state = {0};
if(key <= MP_KEY_COUNT)
{
state = __mpApp.inputState.keyboard.keys[key];
}
return(state);
}
mp_key_state mp_mouse_button_get_state(mp_mouse_button button)
{
mp_key_state state = {0};
if(button <= MP_MOUSE_BUTTON_COUNT)
{
state = __mpApp.inputState.mouse.buttons[button];
}
return(state);
}
int mp_key_state_press_count(mp_key_state* key)
{
int count = 0;
if(key->lastUpdate == __mpApp.inputState.frameCounter)
{
count = key->transitionCount / 2;
if(key->down)
{
//NOTE: add one if state is down transition count is odd
count += (key->transitionCount & 0x01);
}
}
return(count);
}
int mp_key_state_release_count(mp_key_state* key)
{
int count = 0;
if(key->lastUpdate == __mpApp.inputState.frameCounter)
{
count = key->transitionCount / 2;
if(!key->down)
{
//NOTE: add one if state is up and transition count is odd
count += (key->transitionCount & 0x01);
}
}
return(count);
}
int mp_key_state_repeat_count(mp_key_state* key)
{
int count = 0;
if(key->lastUpdate == __mpApp.inputState.frameCounter)
{
count = key->repeatCount;
}
return(count);
}
bool mp_key_down(mp_key_code key)
{
mp_key_state state = mp_key_get_state(key);
return(state.down);
}
int mp_key_pressed(mp_key_code key)
{
mp_key_state state = mp_key_get_state(key);
int res = mp_key_state_press_count(&state);
return(res);
}
int mp_key_released(mp_key_code key)
{
mp_key_state state = mp_key_get_state(key);
int res = mp_key_state_release_count(&state);
return(res);
}
int mp_key_repeated(mp_key_code key)
{
mp_key_state state = mp_key_get_state(key);
int res = mp_key_state_repeat_count(&state);
return(res);
}
bool mp_mouse_down(mp_mouse_button button)
{
mp_key_state state = mp_mouse_button_get_state(button);
return(state.down);
}
int mp_mouse_pressed(mp_mouse_button button)
{
mp_key_state state = mp_mouse_button_get_state(button);
int res = mp_key_state_press_count(&state);
return(res);
}
int mp_mouse_released(mp_mouse_button button)
{
mp_key_state state = mp_mouse_button_get_state(button);
int res = mp_key_state_release_count(&state);
return(res);
}
bool mp_mouse_clicked(mp_mouse_button button)
{
mp_key_state state = mp_mouse_button_get_state(button);
bool clicked = state.sysClicked && (state.lastUpdate == __mpApp.inputState.frameCounter);
return(clicked);
}
bool mp_mouse_double_clicked(mp_mouse_button button)
{
mp_key_state state = mp_mouse_button_get_state(button);
bool doubleClicked = state.sysClicked && (state.lastUpdate == __mpApp.inputState.frameCounter);
return(doubleClicked);
}
mp_keymod_flags mp_key_mods()
{
return(__mpApp.inputState.keyboard.mods);
}
vec2 mp_mouse_position()
{
return(__mpApp.inputState.mouse.pos);
}
vec2 mp_mouse_delta()
{
if(__mpApp.inputState.mouse.lastUpdate == __mpApp.inputState.frameCounter)
{
return(__mpApp.inputState.mouse.delta);
}
else
{
return((vec2){0, 0});
}
}
vec2 mp_mouse_wheel()
{
if(__mpApp.inputState.mouse.lastUpdate == __mpApp.inputState.frameCounter)
{
return(__mpApp.inputState.mouse.wheel);
}
else
{
return((vec2){0, 0});
}
}
str32 mp_input_text_utf32(mem_arena* arena)
{
str32 res = {0};
if(__mpApp.inputState.text.lastUpdate == __mpApp.inputState.frameCounter)
{
res = str32_push_copy(arena, __mpApp.inputState.text.codePoints);
}
return(res);
}
str8 mp_input_text_utf8(mem_arena* arena)
{
str8 res = {0};
if(__mpApp.inputState.text.lastUpdate == __mpApp.inputState.frameCounter)
{
res = utf8_push_from_codepoints(arena, __mpApp.inputState.text.codePoints);
}
return(res);
}
#undef LOG_SUBSYSTEM
/************************************************************//**
*
* @file: mp_app_internal.c
* @author: Martin Fouilleul
* @date: 23/12/2022
* @revision:
*
*****************************************************************/
#include"mp_app_internal.h"
#define LOG_SUBSYSTEM "Application"
mp_app __mpApp = {0};
//---------------------------------------------------------------
// Window handles
//---------------------------------------------------------------
void mp_init_window_handles()
{
ListInit(&__mpApp.windowFreeList);
for(int i=0; i<MP_APP_MAX_WINDOWS; i++)
{
__mpApp.windowPool[i].generation = 1;
ListAppend(&__mpApp.windowFreeList, &__mpApp.windowPool[i].freeListElt);
}
}
bool mp_window_handle_is_null(mp_window window)
{
return(window.h == 0);
}
mp_window mp_window_null_handle()
{
return((mp_window){.h = 0});
}
mp_window_data* mp_window_alloc()
{
return(ListPopEntry(&__mpApp.windowFreeList, mp_window_data, freeListElt));
}
mp_window_data* mp_window_ptr_from_handle(mp_window handle)
{
u32 index = handle.h>>32;
u32 generation = handle.h & 0xffffffff;
if(index >= MP_APP_MAX_WINDOWS)
{
return(0);
}
mp_window_data* window = &__mpApp.windowPool[index];
if(window->generation != generation)
{
return(0);
}
else
{
return(window);
}
}
mp_window mp_window_handle_from_ptr(mp_window_data* window)
{
DEBUG_ASSERT( (window - __mpApp.windowPool) >= 0
&& (window - __mpApp.windowPool) < MP_APP_MAX_WINDOWS);
u64 h = ((u64)(window - __mpApp.windowPool))<<32
| ((u64)window->generation);
return((mp_window){h});
}
void mp_window_recycle_ptr(mp_window_data* window)
{
window->generation++;
ListPush(&__mpApp.windowFreeList, &window->freeListElt);
}
//---------------------------------------------------------------
// Init
//---------------------------------------------------------------
static void mp_init_common()
{
mp_init_window_handles();
ringbuffer_init(&__mpApp.eventQueue, 16);
}
static void mp_terminate_common()
{
ringbuffer_cleanup(&__mpApp.eventQueue);
}
//---------------------------------------------------------------
// Event handling
//---------------------------------------------------------------
void mp_queue_event(mp_event* event)
{
if(ringbuffer_write_available(&__mpApp.eventQueue) < sizeof(mp_event))
{
LOG_ERROR("event queue full\n");
}
else
{
u32 written = ringbuffer_write(&__mpApp.eventQueue, sizeof(mp_event), (u8*)event);
DEBUG_ASSERT(written == sizeof(mp_event));
}
}
bool mp_next_event(mp_event* event)
{
//NOTE pop and return event from queue
if(ringbuffer_read_available(&__mpApp.eventQueue) >= sizeof(mp_event))
{
u64 read = ringbuffer_read(&__mpApp.eventQueue, sizeof(mp_event), (u8*)event);
DEBUG_ASSERT(read == sizeof(mp_event));
return(true);
}
else
{
return(false);
}
}
//---------------------------------------------------------------
// Input state updating
//---------------------------------------------------------------
static void mp_update_key_state(mp_key_state* key, mp_key_action action)
{
u64 frameCounter = __mpApp.inputState.frameCounter;
if(key->lastUpdate != frameCounter)
{
key->transitionCount = 0;
key->repeatCount = 0;
key->sysClicked = false;
key->sysDoubleClicked = false;
key->lastUpdate = frameCounter;
}
switch(action)
{
case MP_KEY_PRESS:
{
if(!key->down)
{
key->transitionCount++;
}
key->down = true;
} break;
case MP_KEY_REPEAT:
{
key->repeatCount++;
key->down = true;
} break;
case MP_KEY_RELEASE:
{
if(key->down)
{
key->transitionCount++;
}
key->down = false;
} break;
default:
break;
}
}
static void mp_update_mouse_move(f32 x, f32 y, f32 deltaX, f32 deltaY)
{
u64 frameCounter = __mpApp.inputState.frameCounter;
mp_mouse_state* mouse = &__mpApp.inputState.mouse;
if(mouse->lastUpdate != frameCounter)
{
mouse->delta = (vec2){0, 0};
mouse->wheel = (vec2){0, 0};
mouse->lastUpdate = frameCounter;
}
mouse->pos = (vec2){x, y};
mouse->delta.x += deltaX;
mouse->delta.y += deltaY;
}
static void mp_update_mouse_wheel(f32 deltaX, f32 deltaY)
{
u64 frameCounter = __mpApp.inputState.frameCounter;
mp_mouse_state* mouse = &__mpApp.inputState.mouse;
if(mouse->lastUpdate != frameCounter)
{
mouse->delta = (vec2){0, 0};
mouse->wheel = (vec2){0, 0};
mouse->lastUpdate = frameCounter;
}
mouse->wheel.x += deltaX;
mouse->wheel.y += deltaY;
}
static void mp_update_text(utf32 codepoint)
{
u64 frameCounter = __mpApp.inputState.frameCounter;
mp_text_state* text = &__mpApp.inputState.text;
if(text->lastUpdate != frameCounter)
{
text->codePoints.len = 0;
text->lastUpdate = frameCounter;
}
text->codePoints.ptr = text->backing;
if(text->codePoints.len < MP_INPUT_TEXT_BACKING_SIZE)
{
text->codePoints.ptr[text->codePoints.len] = codepoint;
text->codePoints.len++;
}
else
{
LOG_WARNING("too many input codepoints per frame, dropping input");
}
}
//--------------------------------------------------------------------
// Input state polling
//--------------------------------------------------------------------
mp_key_state mp_key_get_state(mp_key_code key)
{
mp_key_state state = {0};
if(key <= MP_KEY_COUNT)
{
state = __mpApp.inputState.keyboard.keys[key];
}
return(state);
}
mp_key_state mp_mouse_button_get_state(mp_mouse_button button)
{
mp_key_state state = {0};
if(button <= MP_MOUSE_BUTTON_COUNT)
{
state = __mpApp.inputState.mouse.buttons[button];
}
return(state);
}
int mp_key_state_press_count(mp_key_state* key)
{
int count = 0;
if(key->lastUpdate == __mpApp.inputState.frameCounter)
{
count = key->transitionCount / 2;
if(key->down)
{
//NOTE: add one if state is down transition count is odd
count += (key->transitionCount & 0x01);
}
}
return(count);
}
int mp_key_state_release_count(mp_key_state* key)
{
int count = 0;
if(key->lastUpdate == __mpApp.inputState.frameCounter)
{
count = key->transitionCount / 2;
if(!key->down)
{
//NOTE: add one if state is up and transition count is odd
count += (key->transitionCount & 0x01);
}
}
return(count);
}
int mp_key_state_repeat_count(mp_key_state* key)
{
int count = 0;
if(key->lastUpdate == __mpApp.inputState.frameCounter)
{
count = key->repeatCount;
}
return(count);
}
bool mp_key_down(mp_key_code key)
{
mp_key_state state = mp_key_get_state(key);
return(state.down);
}
int mp_key_pressed(mp_key_code key)
{
mp_key_state state = mp_key_get_state(key);
int res = mp_key_state_press_count(&state);
return(res);
}
int mp_key_released(mp_key_code key)
{
mp_key_state state = mp_key_get_state(key);
int res = mp_key_state_release_count(&state);
return(res);
}
int mp_key_repeated(mp_key_code key)
{
mp_key_state state = mp_key_get_state(key);
int res = mp_key_state_repeat_count(&state);
return(res);
}
bool mp_mouse_down(mp_mouse_button button)
{
mp_key_state state = mp_mouse_button_get_state(button);
return(state.down);
}
int mp_mouse_pressed(mp_mouse_button button)
{
mp_key_state state = mp_mouse_button_get_state(button);
int res = mp_key_state_press_count(&state);
return(res);
}
int mp_mouse_released(mp_mouse_button button)
{
mp_key_state state = mp_mouse_button_get_state(button);
int res = mp_key_state_release_count(&state);
return(res);
}
bool mp_mouse_clicked(mp_mouse_button button)
{
mp_key_state state = mp_mouse_button_get_state(button);
bool clicked = state.sysClicked && (state.lastUpdate == __mpApp.inputState.frameCounter);
return(clicked);
}
bool mp_mouse_double_clicked(mp_mouse_button button)
{
mp_key_state state = mp_mouse_button_get_state(button);
bool doubleClicked = state.sysClicked && (state.lastUpdate == __mpApp.inputState.frameCounter);
return(doubleClicked);
}
mp_keymod_flags mp_key_mods()
{
return(__mpApp.inputState.keyboard.mods);
}
vec2 mp_mouse_position()
{
return(__mpApp.inputState.mouse.pos);
}
vec2 mp_mouse_delta()
{
if(__mpApp.inputState.mouse.lastUpdate == __mpApp.inputState.frameCounter)
{
return(__mpApp.inputState.mouse.delta);
}
else
{
return((vec2){0, 0});
}
}
vec2 mp_mouse_wheel()
{
if(__mpApp.inputState.mouse.lastUpdate == __mpApp.inputState.frameCounter)
{
return(__mpApp.inputState.mouse.wheel);
}
else
{
return((vec2){0, 0});
}
}
str32 mp_input_text_utf32(mem_arena* arena)
{
str32 res = {0};
if(__mpApp.inputState.text.lastUpdate == __mpApp.inputState.frameCounter)
{
res = str32_push_copy(arena, __mpApp.inputState.text.codePoints);
}
return(res);
}
str8 mp_input_text_utf8(mem_arena* arena)
{
str8 res = {0};
if(__mpApp.inputState.text.lastUpdate == __mpApp.inputState.frameCounter)
{
res = utf8_push_from_codepoints(arena, __mpApp.inputState.text.codePoints);
}
return(res);
}
#undef LOG_SUBSYSTEM

View File

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

View File

@ -1,154 +1,154 @@
/************************************************************//**
*
* @file: mp_app_internal.h
* @author: Martin Fouilleul
* @date: 23/12/2022
* @revision:
*
*****************************************************************/
#ifndef __MP_APP_INTERNAL_H_
#define __MP_APP_INTERNAL_H_
#include"mp_app.h"
#include"platform.h"
#include"ringbuffer.h"
#if defined(OS_WIN64) || defined(OS_WIN32)
#include"win32_app.h"
#elif defined(OS_MACOS)
#include"osx_app.h"
#else
#error "platform not supported yet"
#endif
//---------------------------------------------------------------
// Input State
//---------------------------------------------------------------
typedef struct mp_key_utf8
{
u8 labelLen;
char label[8];
} mp_key_utf8;
typedef struct mp_key_state
{
u64 lastUpdate;
u32 transitionCount;
u32 repeatCount;
bool down;
bool sysClicked;
bool sysDoubleClicked;
} mp_key_state;
typedef struct mp_keyboard_state
{
mp_key_state keys[MP_KEY_COUNT];
mp_keymod_flags mods;
} mp_keyboard_state;
typedef struct mp_mouse_state
{
u64 lastUpdate;
bool posValid;
vec2 pos;
vec2 delta;
vec2 wheel;
union
{
mp_key_state buttons[MP_MOUSE_BUTTON_COUNT];
struct
{
mp_key_state left;
mp_key_state right;
mp_key_state middle;
mp_key_state ext1;
mp_key_state ext2;
};
};
} mp_mouse_state;
enum { MP_INPUT_TEXT_BACKING_SIZE = 64 };
typedef struct mp_text_state
{
u64 lastUpdate;
utf32 backing[MP_INPUT_TEXT_BACKING_SIZE];
str32 codePoints;
} mp_text_state;
typedef struct mp_input_state
{
u64 frameCounter;
mp_keyboard_state keyboard;
mp_mouse_state mouse;
mp_text_state text;
} mp_input_state;
//---------------------------------------------------------------
// Window structure
//---------------------------------------------------------------
typedef struct mp_frame_stats
{
f64 start;
f64 workTime;
f64 remainingTime;
f64 targetFramePeriod;
} mp_frame_stats;
typedef struct mp_window_data
{
list_elt freeListElt;
u32 generation;
mp_rect contentRect;
mp_rect frameRect;
mp_window_style style;
bool shouldClose; //TODO could be in status flags
bool hidden;
bool minimized;
MP_PLATFORM_WINDOW_DATA
} mp_window_data;
//---------------------------------------------------------------
// Global App State
//---------------------------------------------------------------
enum { MP_APP_MAX_WINDOWS = 128 };
typedef struct mp_app
{
bool init;
bool shouldQuit;
bool minimized;
str8 pendingPathDrop;
mem_arena eventArena;
ringbuffer eventQueue;
mp_frame_stats frameStats;
mp_window_data windowPool[MP_APP_MAX_WINDOWS];
list_info windowFreeList;
mp_live_resize_callback liveResizeCallback;
void* liveResizeData;
mp_input_state inputState;
mp_key_utf8 keyLabels[512];
int keyCodes[512];
int nativeKeys[MP_KEY_COUNT];
MP_PLATFORM_APP_DATA
} mp_app;
#endif // __MP_APP_INTERNAL_H_
/************************************************************//**
*
* @file: mp_app_internal.h
* @author: Martin Fouilleul
* @date: 23/12/2022
* @revision:
*
*****************************************************************/
#ifndef __MP_APP_INTERNAL_H_
#define __MP_APP_INTERNAL_H_
#include"mp_app.h"
#include"platform.h"
#include"ringbuffer.h"
#if defined(OS_WIN64) || defined(OS_WIN32)
#include"win32_app.h"
#elif defined(OS_MACOS)
#include"osx_app.h"
#else
#error "platform not supported yet"
#endif
//---------------------------------------------------------------
// Input State
//---------------------------------------------------------------
typedef struct mp_key_utf8
{
u8 labelLen;
char label[8];
} mp_key_utf8;
typedef struct mp_key_state
{
u64 lastUpdate;
u32 transitionCount;
u32 repeatCount;
bool down;
bool sysClicked;
bool sysDoubleClicked;
} mp_key_state;
typedef struct mp_keyboard_state
{
mp_key_state keys[MP_KEY_COUNT];
mp_keymod_flags mods;
} mp_keyboard_state;
typedef struct mp_mouse_state
{
u64 lastUpdate;
bool posValid;
vec2 pos;
vec2 delta;
vec2 wheel;
union
{
mp_key_state buttons[MP_MOUSE_BUTTON_COUNT];
struct
{
mp_key_state left;
mp_key_state right;
mp_key_state middle;
mp_key_state ext1;
mp_key_state ext2;
};
};
} mp_mouse_state;
enum { MP_INPUT_TEXT_BACKING_SIZE = 64 };
typedef struct mp_text_state
{
u64 lastUpdate;
utf32 backing[MP_INPUT_TEXT_BACKING_SIZE];
str32 codePoints;
} mp_text_state;
typedef struct mp_input_state
{
u64 frameCounter;
mp_keyboard_state keyboard;
mp_mouse_state mouse;
mp_text_state text;
} mp_input_state;
//---------------------------------------------------------------
// Window structure
//---------------------------------------------------------------
typedef struct mp_frame_stats
{
f64 start;
f64 workTime;
f64 remainingTime;
f64 targetFramePeriod;
} mp_frame_stats;
typedef struct mp_window_data
{
list_elt freeListElt;
u32 generation;
mp_rect contentRect;
mp_rect frameRect;
mp_window_style style;
bool shouldClose; //TODO could be in status flags
bool hidden;
bool minimized;
MP_PLATFORM_WINDOW_DATA
} mp_window_data;
//---------------------------------------------------------------
// Global App State
//---------------------------------------------------------------
enum { MP_APP_MAX_WINDOWS = 128 };
typedef struct mp_app
{
bool init;
bool shouldQuit;
bool minimized;
str8 pendingPathDrop;
mem_arena eventArena;
ringbuffer eventQueue;
mp_frame_stats frameStats;
mp_window_data windowPool[MP_APP_MAX_WINDOWS];
list_info windowFreeList;
mp_live_resize_callback liveResizeCallback;
void* liveResizeData;
mp_input_state inputState;
mp_key_utf8 keyLabels[512];
int keyCodes[512];
int nativeKeys[MP_KEY_COUNT];
MP_PLATFORM_APP_DATA
} mp_app;
#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<simd/simd.h>
#include"mtl_shader.h"
using namespace metal;
struct vs_out
{
float4 pos [[position]];
float2 uv;
};
vertex vs_out VertexShader(ushort vid [[vertex_id]])
{
vs_out out;
out.uv = float2((vid << 1) & 2, vid & 2);
out.pos = float4(out.uv * float2(2, 2) + float2(-1, -1), 0, 1);
return(out);
}
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);
return(tex.sample(smp, i.uv));
}
bool is_top_left(float2 a, float2 b)
{
return( (a.y == b.y && b.x < a.x)
||(b.y < a.y));
}
kernel void BoundingBoxKernel(constant mg_vertex* vertexBuffer [[buffer(0)]],
constant uint* indexBuffer [[buffer(1)]],
constant mg_shape* shapeBuffer [[buffer(2)]],
device mg_triangle_data* triangleArray [[buffer(3)]],
device float4* boxArray [[buffer(4)]],
constant float* contentsScaling [[buffer(5)]],
uint gid [[thread_position_in_grid]])
{
uint triangleIndex = gid;
uint vertexIndex = triangleIndex*3;
uint i0 = indexBuffer[vertexIndex];
uint i1 = indexBuffer[vertexIndex+1];
uint i2 = indexBuffer[vertexIndex+2];
float2 p0 = vertexBuffer[i0].pos * contentsScaling[0];
float2 p1 = vertexBuffer[i1].pos * contentsScaling[0];
float2 p2 = vertexBuffer[i2].pos * contentsScaling[0];
//NOTE(martin): compute triangle bounding box
float2 boxMin = min(min(p0, p1), p2);
float2 boxMax = max(max(p0, p1), p2);
//NOTE(martin): clip bounding box against clip rect
int shapeIndex = vertexBuffer[i0].shapeIndex;
vector_float4 clip = contentsScaling[0]*shapeBuffer[shapeIndex].clip;
//NOTE(martin): intersect with current clip
boxMin = max(boxMin, clip.xy);
boxMax = min(boxMax, clip.zw);
//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
float cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;
if(cw < 0)
{
uint tmpIndex = i1;
i1 = i2;
i2 = tmpIndex;
float2 tmpPoint = p1;
p1 = p2;
p2 = tmpPoint;
}
int bias0 = is_top_left(p1, p2) ? 0 : -1;
int bias1 = is_top_left(p2, p0) ? 0 : -1;
int bias2 = is_top_left(p0, p1) ? 0 : -1;
//NOTE(martin): fill triangle data
boxArray[triangleIndex] = float4(boxMin.x, boxMin.y, boxMax.x, boxMax.y);
triangleArray[triangleIndex].shapeIndex = shapeIndex;
triangleArray[triangleIndex].i0 = i0;
triangleArray[triangleIndex].i1 = i1;
triangleArray[triangleIndex].i2 = i2;
triangleArray[triangleIndex].p0 = p0;
triangleArray[triangleIndex].p1 = p1;
triangleArray[triangleIndex].p2 = p2;
triangleArray[triangleIndex].bias0 = bias0;
triangleArray[triangleIndex].bias1 = bias1;
triangleArray[triangleIndex].bias2 = bias2;
}
kernel void TileKernel(const device float4* boxArray [[buffer(0)]],
device volatile atomic_uint* tileCounters [[buffer(1)]],
device uint* tilesArray [[buffer(2)]],
constant vector_uint2* viewport [[buffer(3)]],
uint gid [[thread_position_in_grid]])
{
uint2 tilesMatrixDim = (*viewport - 1) / RENDERER_TILE_SIZE + 1;
uint nTilesX = tilesMatrixDim.x;
uint nTilesY = tilesMatrixDim.y;
uint triangleIndex = gid;
uint4 box = uint4(floor(boxArray[triangleIndex]))/RENDERER_TILE_SIZE;
uint xMin = max((uint)0, box.x);
uint yMin = max((uint)0, box.y);
uint xMax = min(box.z, nTilesX-1);
uint yMax = min(box.w, nTilesY-1);
for(uint y = yMin; y <= yMax; y++)
{
for(uint x = xMin ; x <= xMax; x++)
{
uint tileIndex = y*nTilesX + x;
device uint* tileBuffer = tilesArray + tileIndex*RENDERER_TILE_BUFFER_SIZE;
uint counter = atomic_fetch_add_explicit(&(tileCounters[tileIndex]), 1, memory_order_relaxed);
tileBuffer[counter] = triangleIndex;
}
}
}
kernel void SortKernel(const device uint* tileCounters [[buffer(0)]],
const device mg_triangle_data* triangleArray [[buffer(1)]],
device uint* tilesArray [[buffer(2)]],
constant vector_uint2* viewport [[buffer(3)]],
uint gid [[thread_position_in_grid]])
{
uint tileIndex = gid;
device uint* tileBuffer = tilesArray + tileIndex*RENDERER_TILE_BUFFER_SIZE;
uint tileBufferSize = tileCounters[tileIndex];
for(int eltIndex=0; eltIndex < (int)tileBufferSize; eltIndex++)
{
uint elt = tileBuffer[eltIndex];
uint eltZIndex = triangleArray[elt].shapeIndex;
int backIndex = eltIndex-1;
for(; backIndex >= 0; backIndex--)
{
uint backElt = tileBuffer[backIndex];
uint backEltZIndex = triangleArray[backElt].shapeIndex;
if(eltZIndex >= backEltZIndex)
{
break;
}
else
{
tileBuffer[backIndex+1] = backElt;
}
}
tileBuffer[backIndex+1] = elt;
}
}
float orient2d(float2 a, float2 b, float2 c)
{
//////////////////////////////////////////////////////////////////////////////////////////
//TODO(martin): FIX this. This is a **horrible** quick hack to fix the precision issues
// arising when a, b, and c are close. But it degrades when a, c, and c
// are big. The proper solution is to change the expression to avoid
// precision loss but I'm too busy/lazy to do it now.
//////////////////////////////////////////////////////////////////////////////////////////
a *= 10;
b *= 10;
c *= 10;
return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
}
kernel void RenderKernel(texture2d<float, access::write> outTexture [[texture(0)]],
texture2d<float> texAtlas [[texture(1)]],
const device mg_vertex* vertexBuffer [[buffer(0)]],
const device mg_shape* shapeBuffer [[buffer(1)]],
device uint* tileCounters [[buffer(2)]],
const device uint* tilesArray [[buffer(3)]],
const device mg_triangle_data* triangleArray [[buffer(4)]],
const device float4* boxArray [[buffer(5)]],
constant vector_float4* clearColor [[buffer(6)]],
constant int* useTexture [[buffer(7)]],
constant float* contentsScaling [[buffer(8)]],
uint2 gid [[thread_position_in_grid]],
uint2 tgid [[threadgroup_position_in_grid]],
uint2 threadsPerThreadgroup [[threads_per_threadgroup]],
uint2 gridSize [[threads_per_grid]])
{
//TODO: guard against thread group size not equal to tile size?
const uint2 tilesMatrixDim = (gridSize - 1) / RENDERER_TILE_SIZE + 1;
// const uint2 tilePos = tgid * threadsPerThreadgroup / RENDERER_TILE_SIZE;
const uint2 tilePos = gid/RENDERER_TILE_SIZE;
const uint tileIndex = tilePos.y * tilesMatrixDim.x + tilePos.x;
const device uint* tileBuffer = tilesArray + tileIndex * RENDERER_TILE_BUFFER_SIZE;
const uint tileBufferSize = tileCounters[tileIndex];
#ifdef RENDERER_DEBUG_TILES
//NOTE(martin): color code debug values and show the tile grid
uint nTileX = tilesMatrixDim.x;
uint nTileY = tilesMatrixDim.y;
if(tilePos.x > nTileX || tilePos.y > nTileY)
{
outTexture.write(float4(0, 1, 1, 1), gid);
return;
}
if((gid.x % RENDERER_TILE_SIZE == 0) || (gid.y % RENDERER_TILE_SIZE == 0))
{
outTexture.write(float4(0, 0, 0, 1), gid);
return;
}
if(tileBufferSize <= 0)
{
outTexture.write(float4(0, 1, 0, 1), gid);
return;
}
else
{
outTexture.write(float4(1, 0, 0, 1), gid);
return;
}
#endif
const float2 sampleOffsets[6] = { float2(5./12, 5./12),
float2(-3./12, 3./12),
float2(1./12, 1./12),
float2(3./12, -1./12),
float2(-5./12, -3./12),
float2(-1./12, -5./12)};
int zIndices[6];
uint flipCounts[6];
float4 pixelColors[6];
float4 nextColors[6];
for(int i=0; i<6; i++)
{
zIndices[i] = -1;
flipCounts[i] = 0;
pixelColors[i] = float4(0, 0, 0, 0);
nextColors[i] = float4(0, 0, 0, 0);
}
for(uint tileBufferIndex=0; tileBufferIndex < tileBufferSize; tileBufferIndex++)
{
float4 box = boxArray[tileBuffer[tileBufferIndex]];
const device mg_triangle_data* triangle = &triangleArray[tileBuffer[tileBufferIndex]];
float2 p0 = triangle->p0;
float2 p1 = triangle->p1;
float2 p2 = triangle->p2;
int bias0 = triangle->bias0;
int bias1 = triangle->bias1;
int bias2 = triangle->bias2;
const device mg_vertex* v0 = &(vertexBuffer[triangle->i0]);
const device mg_vertex* v1 = &(vertexBuffer[triangle->i1]);
const device mg_vertex* v2 = &(vertexBuffer[triangle->i2]);
float4 cubic0 = v0->cubic;
float4 cubic1 = v1->cubic;
float4 cubic2 = v2->cubic;
int shapeIndex = v0->shapeIndex;
float4 color = shapeBuffer[shapeIndex].color;
color.rgb *= color.a;
const device float* uvTransform2x3 = shapeBuffer[shapeIndex].uvTransform;
matrix_float3x3 uvTransform = {{uvTransform2x3[0], uvTransform2x3[3], 0},
{uvTransform2x3[1], uvTransform2x3[4], 0},
{uvTransform2x3[2], uvTransform2x3[5], 1}};
for(int i=0; i<6; i++)
{
float2 samplePoint = (float2)gid + sampleOffsets[i];
//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)
{
continue;
}
float w0 = orient2d(p1, p2, samplePoint);
float w1 = orient2d(p2, p0, samplePoint);
float w2 = orient2d(p0, p1, samplePoint);
if(((int)w0+bias0) >= 0 && ((int)w1+bias1) >= 0 && ((int)w2+bias2) >= 0)
{
float4 cubic = (cubic0*w0 + cubic1*w1 + cubic2*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;
float4 texColor = float4(1, 1, 1, 1);
if(*useTexture)
{
constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear);
texColor = texAtlas.sample(smp, uv);
texColor.rgb *= texColor.a;
}
//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
// flip the sign.
// We should really use another value that always lead to <= 0, but we must
// make sure we never share these vertices with bezier shapes.
// 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
// those triangles.
float eps = 0.0001;
if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)
{
if(shapeIndex == zIndices[i])
{
flipCounts[i]++;
}
else
{
if(flipCounts[i] & 0x01)
{
pixelColors[i] = nextColors[i];
}
float4 nextCol = color*texColor;
nextColors[i] = pixelColors[i]*(1-nextCol.a) +nextCol.a*nextCol;
zIndices[i] = shapeIndex;
flipCounts[i] = 1;
}
}
}
}
}
float4 out = float4(0, 0, 0, 0);
for(int i=0; i<6; i++)
{
if(flipCounts[i] & 0x01)
{
pixelColors[i] = nextColors[i];
}
out += pixelColors[i];
}
out = out/6.;
outTexture.write(out, gid);
}
#include<metal_stdlib>
#include<simd/simd.h>
#include"mtl_shader.h"
using namespace metal;
struct vs_out
{
float4 pos [[position]];
float2 uv;
};
vertex vs_out VertexShader(ushort vid [[vertex_id]])
{
vs_out out;
out.uv = float2((vid << 1) & 2, vid & 2);
out.pos = float4(out.uv * float2(2, 2) + float2(-1, -1), 0, 1);
return(out);
}
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);
return(tex.sample(smp, i.uv));
}
bool is_top_left(float2 a, float2 b)
{
return( (a.y == b.y && b.x < a.x)
||(b.y < a.y));
}
kernel void BoundingBoxKernel(constant mg_vertex* vertexBuffer [[buffer(0)]],
constant uint* indexBuffer [[buffer(1)]],
constant mg_shape* shapeBuffer [[buffer(2)]],
device mg_triangle_data* triangleArray [[buffer(3)]],
device float4* boxArray [[buffer(4)]],
constant float* contentsScaling [[buffer(5)]],
uint gid [[thread_position_in_grid]])
{
uint triangleIndex = gid;
uint vertexIndex = triangleIndex*3;
uint i0 = indexBuffer[vertexIndex];
uint i1 = indexBuffer[vertexIndex+1];
uint i2 = indexBuffer[vertexIndex+2];
float2 p0 = vertexBuffer[i0].pos * contentsScaling[0];
float2 p1 = vertexBuffer[i1].pos * contentsScaling[0];
float2 p2 = vertexBuffer[i2].pos * contentsScaling[0];
//NOTE(martin): compute triangle bounding box
float2 boxMin = min(min(p0, p1), p2);
float2 boxMax = max(max(p0, p1), p2);
//NOTE(martin): clip bounding box against clip rect
int shapeIndex = vertexBuffer[i0].shapeIndex;
vector_float4 clip = contentsScaling[0]*shapeBuffer[shapeIndex].clip;
//NOTE(martin): intersect with current clip
boxMin = max(boxMin, clip.xy);
boxMax = min(boxMax, clip.zw);
//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
float cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;
if(cw < 0)
{
uint tmpIndex = i1;
i1 = i2;
i2 = tmpIndex;
float2 tmpPoint = p1;
p1 = p2;
p2 = tmpPoint;
}
int bias0 = is_top_left(p1, p2) ? 0 : -1;
int bias1 = is_top_left(p2, p0) ? 0 : -1;
int bias2 = is_top_left(p0, p1) ? 0 : -1;
//NOTE(martin): fill triangle data
boxArray[triangleIndex] = float4(boxMin.x, boxMin.y, boxMax.x, boxMax.y);
triangleArray[triangleIndex].shapeIndex = shapeIndex;
triangleArray[triangleIndex].i0 = i0;
triangleArray[triangleIndex].i1 = i1;
triangleArray[triangleIndex].i2 = i2;
triangleArray[triangleIndex].p0 = p0;
triangleArray[triangleIndex].p1 = p1;
triangleArray[triangleIndex].p2 = p2;
triangleArray[triangleIndex].bias0 = bias0;
triangleArray[triangleIndex].bias1 = bias1;
triangleArray[triangleIndex].bias2 = bias2;
}
kernel void TileKernel(const device float4* boxArray [[buffer(0)]],
device volatile atomic_uint* tileCounters [[buffer(1)]],
device uint* tilesArray [[buffer(2)]],
constant vector_uint2* viewport [[buffer(3)]],
uint gid [[thread_position_in_grid]])
{
uint2 tilesMatrixDim = (*viewport - 1) / RENDERER_TILE_SIZE + 1;
uint nTilesX = tilesMatrixDim.x;
uint nTilesY = tilesMatrixDim.y;
uint triangleIndex = gid;
uint4 box = uint4(floor(boxArray[triangleIndex]))/RENDERER_TILE_SIZE;
uint xMin = max((uint)0, box.x);
uint yMin = max((uint)0, box.y);
uint xMax = min(box.z, nTilesX-1);
uint yMax = min(box.w, nTilesY-1);
for(uint y = yMin; y <= yMax; y++)
{
for(uint x = xMin ; x <= xMax; x++)
{
uint tileIndex = y*nTilesX + x;
device uint* tileBuffer = tilesArray + tileIndex*RENDERER_TILE_BUFFER_SIZE;
uint counter = atomic_fetch_add_explicit(&(tileCounters[tileIndex]), 1, memory_order_relaxed);
tileBuffer[counter] = triangleIndex;
}
}
}
kernel void SortKernel(const device uint* tileCounters [[buffer(0)]],
const device mg_triangle_data* triangleArray [[buffer(1)]],
device uint* tilesArray [[buffer(2)]],
constant vector_uint2* viewport [[buffer(3)]],
uint gid [[thread_position_in_grid]])
{
uint tileIndex = gid;
device uint* tileBuffer = tilesArray + tileIndex*RENDERER_TILE_BUFFER_SIZE;
uint tileBufferSize = tileCounters[tileIndex];
for(int eltIndex=0; eltIndex < (int)tileBufferSize; eltIndex++)
{
uint elt = tileBuffer[eltIndex];
uint eltZIndex = triangleArray[elt].shapeIndex;
int backIndex = eltIndex-1;
for(; backIndex >= 0; backIndex--)
{
uint backElt = tileBuffer[backIndex];
uint backEltZIndex = triangleArray[backElt].shapeIndex;
if(eltZIndex >= backEltZIndex)
{
break;
}
else
{
tileBuffer[backIndex+1] = backElt;
}
}
tileBuffer[backIndex+1] = elt;
}
}
float orient2d(float2 a, float2 b, float2 c)
{
//////////////////////////////////////////////////////////////////////////////////////////
//TODO(martin): FIX this. This is a **horrible** quick hack to fix the precision issues
// arising when a, b, and c are close. But it degrades when a, c, and c
// are big. The proper solution is to change the expression to avoid
// precision loss but I'm too busy/lazy to do it now.
//////////////////////////////////////////////////////////////////////////////////////////
a *= 10;
b *= 10;
c *= 10;
return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
}
kernel void RenderKernel(texture2d<float, access::write> outTexture [[texture(0)]],
texture2d<float> texAtlas [[texture(1)]],
const device mg_vertex* vertexBuffer [[buffer(0)]],
const device mg_shape* shapeBuffer [[buffer(1)]],
device uint* tileCounters [[buffer(2)]],
const device uint* tilesArray [[buffer(3)]],
const device mg_triangle_data* triangleArray [[buffer(4)]],
const device float4* boxArray [[buffer(5)]],
constant vector_float4* clearColor [[buffer(6)]],
constant int* useTexture [[buffer(7)]],
constant float* contentsScaling [[buffer(8)]],
uint2 gid [[thread_position_in_grid]],
uint2 tgid [[threadgroup_position_in_grid]],
uint2 threadsPerThreadgroup [[threads_per_threadgroup]],
uint2 gridSize [[threads_per_grid]])
{
//TODO: guard against thread group size not equal to tile size?
const uint2 tilesMatrixDim = (gridSize - 1) / RENDERER_TILE_SIZE + 1;
// const uint2 tilePos = tgid * threadsPerThreadgroup / RENDERER_TILE_SIZE;
const uint2 tilePos = gid/RENDERER_TILE_SIZE;
const uint tileIndex = tilePos.y * tilesMatrixDim.x + tilePos.x;
const device uint* tileBuffer = tilesArray + tileIndex * RENDERER_TILE_BUFFER_SIZE;
const uint tileBufferSize = tileCounters[tileIndex];
#ifdef RENDERER_DEBUG_TILES
//NOTE(martin): color code debug values and show the tile grid
uint nTileX = tilesMatrixDim.x;
uint nTileY = tilesMatrixDim.y;
if(tilePos.x > nTileX || tilePos.y > nTileY)
{
outTexture.write(float4(0, 1, 1, 1), gid);
return;
}
if((gid.x % RENDERER_TILE_SIZE == 0) || (gid.y % RENDERER_TILE_SIZE == 0))
{
outTexture.write(float4(0, 0, 0, 1), gid);
return;
}
if(tileBufferSize <= 0)
{
outTexture.write(float4(0, 1, 0, 1), gid);
return;
}
else
{
outTexture.write(float4(1, 0, 0, 1), gid);
return;
}
#endif
const float2 sampleOffsets[6] = { float2(5./12, 5./12),
float2(-3./12, 3./12),
float2(1./12, 1./12),
float2(3./12, -1./12),
float2(-5./12, -3./12),
float2(-1./12, -5./12)};
int zIndices[6];
uint flipCounts[6];
float4 pixelColors[6];
float4 nextColors[6];
for(int i=0; i<6; i++)
{
zIndices[i] = -1;
flipCounts[i] = 0;
pixelColors[i] = float4(0, 0, 0, 0);
nextColors[i] = float4(0, 0, 0, 0);
}
for(uint tileBufferIndex=0; tileBufferIndex < tileBufferSize; tileBufferIndex++)
{
float4 box = boxArray[tileBuffer[tileBufferIndex]];
const device mg_triangle_data* triangle = &triangleArray[tileBuffer[tileBufferIndex]];
float2 p0 = triangle->p0;
float2 p1 = triangle->p1;
float2 p2 = triangle->p2;
int bias0 = triangle->bias0;
int bias1 = triangle->bias1;
int bias2 = triangle->bias2;
const device mg_vertex* v0 = &(vertexBuffer[triangle->i0]);
const device mg_vertex* v1 = &(vertexBuffer[triangle->i1]);
const device mg_vertex* v2 = &(vertexBuffer[triangle->i2]);
float4 cubic0 = v0->cubic;
float4 cubic1 = v1->cubic;
float4 cubic2 = v2->cubic;
int shapeIndex = v0->shapeIndex;
float4 color = shapeBuffer[shapeIndex].color;
color.rgb *= color.a;
const device float* uvTransform2x3 = shapeBuffer[shapeIndex].uvTransform;
matrix_float3x3 uvTransform = {{uvTransform2x3[0], uvTransform2x3[3], 0},
{uvTransform2x3[1], uvTransform2x3[4], 0},
{uvTransform2x3[2], uvTransform2x3[5], 1}};
for(int i=0; i<6; i++)
{
float2 samplePoint = (float2)gid + sampleOffsets[i];
//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)
{
continue;
}
float w0 = orient2d(p1, p2, samplePoint);
float w1 = orient2d(p2, p0, samplePoint);
float w2 = orient2d(p0, p1, samplePoint);
if(((int)w0+bias0) >= 0 && ((int)w1+bias1) >= 0 && ((int)w2+bias2) >= 0)
{
float4 cubic = (cubic0*w0 + cubic1*w1 + cubic2*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;
float4 texColor = float4(1, 1, 1, 1);
if(*useTexture)
{
constexpr sampler smp(mip_filter::nearest, mag_filter::linear, min_filter::linear);
texColor = texAtlas.sample(smp, uv);
texColor.rgb *= texColor.a;
}
//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
// flip the sign.
// We should really use another value that always lead to <= 0, but we must
// make sure we never share these vertices with bezier shapes.
// 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
// those triangles.
float eps = 0.0001;
if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)
{
if(shapeIndex == zIndices[i])
{
flipCounts[i]++;
}
else
{
if(flipCounts[i] & 0x01)
{
pixelColors[i] = nextColors[i];
}
float4 nextCol = color*texColor;
nextColors[i] = pixelColors[i]*(1-nextCol.a) +nextCol.a*nextCol;
zIndices[i] = shapeIndex;
flipCounts[i] = 1;
}
}
}
}
}
float4 out = float4(0, 0, 0, 0);
for(int i=0; i<6; i++)
{
if(flipCounts[i] & 0x01)
{
pixelColors[i] = nextColors[i];
}
out += pixelColors[i];
}
out = out/6.;
outTexture.write(out, gid);
}

View File

@ -1,254 +1,254 @@
/************************************************************//**
*
* @file: mtl_surface.m
* @author: Martin Fouilleul
* @date: 12/07/2023
* @revision:
*
*****************************************************************/
#import<Metal/Metal.h>
#import <QuartzCore/QuartzCore.h>
#import<QuartzCore/CAMetalLayer.h>
#include<simd/simd.h>
#include"graphics_internal.h"
#include"macro_helpers.h"
#include"osx_app.h"
#define LOG_SUBSYSTEM "Graphics"
static const u32 MP_MTL_MAX_DRAWABLES_IN_FLIGHT = 3;
typedef struct mg_mtl_surface
{
mg_surface_data interface;
// permanent mtl resources
id<MTLDevice> device;
CAMetalLayer* mtlLayer;
id<MTLCommandQueue> commandQueue;
// transient metal resources
id<CAMetalDrawable> drawable;
id<MTLCommandBuffer> commandBuffer;
dispatch_semaphore_t drawableSemaphore;
} mg_mtl_surface;
void mg_mtl_surface_destroy(mg_surface_data* interface)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool
{
[surface->commandQueue release];
[surface->mtlLayer removeFromSuperlayer];
[surface->mtlLayer release];
[surface->device release];
}
//NOTE: we don't use mp_layer_cleanup here, because the CAMetalLayer is taken care off by the surface itself
}
void mg_mtl_surface_acquire_drawable_and_command_buffer(mg_mtl_surface* surface)
{@autoreleasepool{
/*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
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
memory allocated in the GPU is never freed...)
In background the gpu seems to create drawable if none is available instead of actually
blocking on nextDrawable. These drawable never get freed.
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
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
incremented in the presentedHandler of the drawable.
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
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.
//TODO: We should set a reasonable timeout and skip the frame and log an error in case we are stalled
for too long.
*/
dispatch_semaphore_wait(surface->drawableSemaphore, DISPATCH_TIME_FOREVER);
surface->drawable = [surface->mtlLayer nextDrawable];
ASSERT(surface->drawable != nil);
//TODO: make this a weak reference if we use ARC
dispatch_semaphore_t semaphore = surface->drawableSemaphore;
[surface->drawable addPresentedHandler:^(id<MTLDrawable> drawable){
dispatch_semaphore_signal(semaphore);
}];
//NOTE(martin): create a command buffer
surface->commandBuffer = [surface->commandQueue commandBuffer];
[surface->commandBuffer retain];
[surface->drawable retain];
}}
void mg_mtl_surface_prepare(mg_surface_data* interface)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
mg_mtl_surface_acquire_drawable_and_command_buffer(surface);
}
void mg_mtl_surface_present(mg_surface_data* interface)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool
{
//NOTE(martin): present drawable and commit command buffer
[surface->commandBuffer presentDrawable: surface->drawable];
[surface->commandBuffer commit];
[surface->commandBuffer waitUntilCompleted];
//NOTE(martin): acquire next frame resources
[surface->commandBuffer release];
surface->commandBuffer = nil;
[surface->drawable release];
surface->drawable = nil;
}
}
void mg_mtl_surface_swap_interval(mg_surface_data* interface, int swap)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
////////////////////////////////////////////////////////////////
//TODO
////////////////////////////////////////////////////////////////
}
void mg_mtl_surface_set_frame(mg_surface_data* interface, mp_rect frame)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
mg_osx_surface_set_frame(interface, frame);
vec2 scale = mg_osx_surface_contents_scaling(interface);
CGSize drawableSize = (CGSize){.width = frame.w * scale.x, .height = frame.h * scale.y};
surface->mtlLayer.drawableSize = drawableSize;
}
//TODO fix that according to real scaling, depending on the monitor settings
static const f32 MG_MTL_SURFACE_CONTENTS_SCALING = 2;
mg_surface_data* mg_mtl_surface_create_for_window(mp_window window)
{
mg_mtl_surface* surface = 0;
mp_window_data* windowData = mp_window_ptr_from_handle(window);
if(windowData)
{
surface = (mg_mtl_surface*)malloc(sizeof(mg_mtl_surface));
mg_surface_init_for_window((mg_surface_data*)surface, windowData);
//NOTE(martin): setup interface functions
surface->interface.backend = MG_BACKEND_METAL;
surface->interface.destroy = mg_mtl_surface_destroy;
surface->interface.prepare = mg_mtl_surface_prepare;
surface->interface.present = mg_mtl_surface_present;
surface->interface.swapInterval = mg_mtl_surface_swap_interval;
surface->interface.setFrame = mg_mtl_surface_set_frame;
@autoreleasepool
{
surface->drawableSemaphore = dispatch_semaphore_create(MP_MTL_MAX_DRAWABLES_IN_FLIGHT);
//-----------------------------------------------------------
//NOTE(martin): create a mtl device and a mtl layer and
//-----------------------------------------------------------
surface->device = MTLCreateSystemDefaultDevice();
[surface->device retain];
surface->mtlLayer = [CAMetalLayer layer];
[surface->mtlLayer retain];
surface->mtlLayer.device = surface->device;
[surface->mtlLayer setOpaque:NO];
[surface->interface.layer.caLayer addSublayer: (CALayer*)surface->mtlLayer];
//-----------------------------------------------------------
//NOTE(martin): set the size and scaling
//-----------------------------------------------------------
NSRect frame = [[windowData->osx.nsWindow contentView] frame];
CGSize size = frame.size;
surface->mtlLayer.frame = (CGRect){{0, 0}, size};
size.width *= MG_MTL_SURFACE_CONTENTS_SCALING;
size.height *= MG_MTL_SURFACE_CONTENTS_SCALING;
surface->mtlLayer.drawableSize = size;
surface->mtlLayer.contentsScale = MG_MTL_SURFACE_CONTENTS_SCALING;
surface->mtlLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
//NOTE(martin): handling resizing
surface->mtlLayer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable;
surface->mtlLayer.needsDisplayOnBoundsChange = YES;
//-----------------------------------------------------------
//NOTE(martin): create a command queue
//-----------------------------------------------------------
surface->commandQueue = [surface->device newCommandQueue];
[surface->commandQueue retain];
//NOTE(martin): command buffer and drawable are set on demand and at the end of each present() call
surface->drawable = nil;
surface->commandBuffer = nil;
}
}
return((mg_surface_data*)surface);
}
void* mg_mtl_surface_layer(mg_surface surface)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->backend == MG_BACKEND_METAL)
{
mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
return(mtlSurface->mtlLayer);
}
else
{
return(nil);
}
}
void* mg_mtl_surface_drawable(mg_surface surface)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->backend == MG_BACKEND_METAL)
{
mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
return(mtlSurface->drawable);
}
else
{
return(nil);
}
}
void* mg_mtl_surface_command_buffer(mg_surface surface)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->backend == MG_BACKEND_METAL)
{
mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
return(mtlSurface->commandBuffer);
}
else
{
return(nil);
}
}
#undef LOG_SUBSYSTEM
/************************************************************//**
*
* @file: mtl_surface.m
* @author: Martin Fouilleul
* @date: 12/07/2023
* @revision:
*
*****************************************************************/
#import<Metal/Metal.h>
#import <QuartzCore/QuartzCore.h>
#import<QuartzCore/CAMetalLayer.h>
#include<simd/simd.h>
#include"graphics_internal.h"
#include"macro_helpers.h"
#include"osx_app.h"
#define LOG_SUBSYSTEM "Graphics"
static const u32 MP_MTL_MAX_DRAWABLES_IN_FLIGHT = 3;
typedef struct mg_mtl_surface
{
mg_surface_data interface;
// permanent mtl resources
id<MTLDevice> device;
CAMetalLayer* mtlLayer;
id<MTLCommandQueue> commandQueue;
// transient metal resources
id<CAMetalDrawable> drawable;
id<MTLCommandBuffer> commandBuffer;
dispatch_semaphore_t drawableSemaphore;
} mg_mtl_surface;
void mg_mtl_surface_destroy(mg_surface_data* interface)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool
{
[surface->commandQueue release];
[surface->mtlLayer removeFromSuperlayer];
[surface->mtlLayer release];
[surface->device release];
}
//NOTE: we don't use mp_layer_cleanup here, because the CAMetalLayer is taken care off by the surface itself
}
void mg_mtl_surface_acquire_drawable_and_command_buffer(mg_mtl_surface* surface)
{@autoreleasepool{
/*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
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
memory allocated in the GPU is never freed...)
In background the gpu seems to create drawable if none is available instead of actually
blocking on nextDrawable. These drawable never get freed.
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
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
incremented in the presentedHandler of the drawable.
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
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.
//TODO: We should set a reasonable timeout and skip the frame and log an error in case we are stalled
for too long.
*/
dispatch_semaphore_wait(surface->drawableSemaphore, DISPATCH_TIME_FOREVER);
surface->drawable = [surface->mtlLayer nextDrawable];
ASSERT(surface->drawable != nil);
//TODO: make this a weak reference if we use ARC
dispatch_semaphore_t semaphore = surface->drawableSemaphore;
[surface->drawable addPresentedHandler:^(id<MTLDrawable> drawable){
dispatch_semaphore_signal(semaphore);
}];
//NOTE(martin): create a command buffer
surface->commandBuffer = [surface->commandQueue commandBuffer];
[surface->commandBuffer retain];
[surface->drawable retain];
}}
void mg_mtl_surface_prepare(mg_surface_data* interface)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
mg_mtl_surface_acquire_drawable_and_command_buffer(surface);
}
void mg_mtl_surface_present(mg_surface_data* interface)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
@autoreleasepool
{
//NOTE(martin): present drawable and commit command buffer
[surface->commandBuffer presentDrawable: surface->drawable];
[surface->commandBuffer commit];
[surface->commandBuffer waitUntilCompleted];
//NOTE(martin): acquire next frame resources
[surface->commandBuffer release];
surface->commandBuffer = nil;
[surface->drawable release];
surface->drawable = nil;
}
}
void mg_mtl_surface_swap_interval(mg_surface_data* interface, int swap)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
////////////////////////////////////////////////////////////////
//TODO
////////////////////////////////////////////////////////////////
}
void mg_mtl_surface_set_frame(mg_surface_data* interface, mp_rect frame)
{
mg_mtl_surface* surface = (mg_mtl_surface*)interface;
mg_osx_surface_set_frame(interface, frame);
vec2 scale = mg_osx_surface_contents_scaling(interface);
CGSize drawableSize = (CGSize){.width = frame.w * scale.x, .height = frame.h * scale.y};
surface->mtlLayer.drawableSize = drawableSize;
}
//TODO fix that according to real scaling, depending on the monitor settings
static const f32 MG_MTL_SURFACE_CONTENTS_SCALING = 2;
mg_surface_data* mg_mtl_surface_create_for_window(mp_window window)
{
mg_mtl_surface* surface = 0;
mp_window_data* windowData = mp_window_ptr_from_handle(window);
if(windowData)
{
surface = (mg_mtl_surface*)malloc(sizeof(mg_mtl_surface));
mg_surface_init_for_window((mg_surface_data*)surface, windowData);
//NOTE(martin): setup interface functions
surface->interface.backend = MG_BACKEND_METAL;
surface->interface.destroy = mg_mtl_surface_destroy;
surface->interface.prepare = mg_mtl_surface_prepare;
surface->interface.present = mg_mtl_surface_present;
surface->interface.swapInterval = mg_mtl_surface_swap_interval;
surface->interface.setFrame = mg_mtl_surface_set_frame;
@autoreleasepool
{
surface->drawableSemaphore = dispatch_semaphore_create(MP_MTL_MAX_DRAWABLES_IN_FLIGHT);
//-----------------------------------------------------------
//NOTE(martin): create a mtl device and a mtl layer and
//-----------------------------------------------------------
surface->device = MTLCreateSystemDefaultDevice();
[surface->device retain];
surface->mtlLayer = [CAMetalLayer layer];
[surface->mtlLayer retain];
surface->mtlLayer.device = surface->device;
[surface->mtlLayer setOpaque:NO];
[surface->interface.layer.caLayer addSublayer: (CALayer*)surface->mtlLayer];
//-----------------------------------------------------------
//NOTE(martin): set the size and scaling
//-----------------------------------------------------------
NSRect frame = [[windowData->osx.nsWindow contentView] frame];
CGSize size = frame.size;
surface->mtlLayer.frame = (CGRect){{0, 0}, size};
size.width *= MG_MTL_SURFACE_CONTENTS_SCALING;
size.height *= MG_MTL_SURFACE_CONTENTS_SCALING;
surface->mtlLayer.drawableSize = size;
surface->mtlLayer.contentsScale = MG_MTL_SURFACE_CONTENTS_SCALING;
surface->mtlLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
//NOTE(martin): handling resizing
surface->mtlLayer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable;
surface->mtlLayer.needsDisplayOnBoundsChange = YES;
//-----------------------------------------------------------
//NOTE(martin): create a command queue
//-----------------------------------------------------------
surface->commandQueue = [surface->device newCommandQueue];
[surface->commandQueue retain];
//NOTE(martin): command buffer and drawable are set on demand and at the end of each present() call
surface->drawable = nil;
surface->commandBuffer = nil;
}
}
return((mg_surface_data*)surface);
}
void* mg_mtl_surface_layer(mg_surface surface)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->backend == MG_BACKEND_METAL)
{
mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
return(mtlSurface->mtlLayer);
}
else
{
return(nil);
}
}
void* mg_mtl_surface_drawable(mg_surface surface)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->backend == MG_BACKEND_METAL)
{
mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
return(mtlSurface->drawable);
}
else
{
return(nil);
}
}
void* mg_mtl_surface_command_buffer(mg_surface surface)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->backend == MG_BACKEND_METAL)
{
mg_mtl_surface* mtlSurface = (mg_mtl_surface*)surfaceData;
return(mtlSurface->commandBuffer);
}
else
{
return(nil);
}
}
#undef LOG_SUBSYSTEM

View File

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

View File

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

View File

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

View File

@ -1,98 +1,98 @@
/************************************************************//**
*
* @file: debug_log.h
* @author: Martin Fouilleul
* @date: 05/04/2019
* @revision:
*
*****************************************************************/
#ifndef __DEBUG_LOG_H_
#define __DEBUG_LOG_H_
#include<stdio.h>
#include"platform.h"
#include"typedefs.h"
#include"macro_helpers.h"
#ifdef __cplusplus
extern "C" {
#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
// can be adjusted at runtime with LogLevel()
#ifndef LOG_DEFAULT_LEVEL
#define LOG_DEFAULT_LEVEL LOG_LEVEL_WARNING
#endif
//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
#define LOG_DEFAULT_OUTPUT stdout
#endif
//NOTE(martin): LOG_SUBSYSTEM can be defined in each compilation unit to associate it with a subsystem, like this:
// #define LOG_SUBSYSTEM "name"
typedef enum { LOG_LEVEL_ERROR,
LOG_LEVEL_WARNING,
LOG_LEVEL_MESSAGE,
LOG_LEVEL_DEBUG,
LOG_LEVEL_COUNT } log_level;
MP_API void LogGeneric(log_level level,
const char* subsystem,
const char* functionName,
const char* fileName,
u32 line,
const char* msg,
...);
MP_API void LogOutput(FILE* output);
MP_API void LogLevel(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_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
// error logging is always compiled
#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__ )
#if defined(LOG_COMPILE_MESSAGE) || defined(LOG_COMPILE_DEBUG)
#define LOG_MESSAGE(msg, ...) LOG_GENERIC(LOG_LEVEL_MESSAGE, __FUNCTION__, __FILE__, __LINE__, msg, ##__VA_ARGS__ )
#if defined(LOG_COMPILE_DEBUG)
#define LOG_DEBUG(msg, ...) LOG_GENERIC(LOG_LEVEL_DEBUG, __FUNCTION__, __FILE__, __LINE__, msg, ##__VA_ARGS__ )
#else
#define LOG_DEBUG(msg, ...)
#endif
#else
#define LOG_MESSAGE(msg, ...)
#define LOG_DEBUG(msg, ...)
#endif
#else
#define LOG_WARNING(msg, ...)
#define LOG_MESSAGE(msg, ...)
#define LOG_DEBUG(msg, ...)
#endif
#ifndef NO_ASSERT
#include<assert.h>
#define _ASSERT_(x, msg) assert(x && msg)
#define ASSERT(x, ...) _ASSERT_(x, #__VA_ARGS__)
#ifdef DEBUG
#define DEBUG_ASSERT(x, ...) ASSERT(x, ##__VA_ARGS__ )
#else
#define DEBUG_ASSERT(x, ...)
#endif
#else
#define ASSERT(x, ...)
#define DEBUG_ASSERT(x, ...)
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__DEBUG_LOG_H_
/************************************************************//**
*
* @file: debug_log.h
* @author: Martin Fouilleul
* @date: 05/04/2019
* @revision:
*
*****************************************************************/
#ifndef __DEBUG_LOG_H_
#define __DEBUG_LOG_H_
#include<stdio.h>
#include"platform.h"
#include"typedefs.h"
#include"macro_helpers.h"
#ifdef __cplusplus
extern "C" {
#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
// can be adjusted at runtime with LogLevel()
#ifndef LOG_DEFAULT_LEVEL
#define LOG_DEFAULT_LEVEL LOG_LEVEL_WARNING
#endif
//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
#define LOG_DEFAULT_OUTPUT stdout
#endif
//NOTE(martin): LOG_SUBSYSTEM can be defined in each compilation unit to associate it with a subsystem, like this:
// #define LOG_SUBSYSTEM "name"
typedef enum { LOG_LEVEL_ERROR,
LOG_LEVEL_WARNING,
LOG_LEVEL_MESSAGE,
LOG_LEVEL_DEBUG,
LOG_LEVEL_COUNT } log_level;
MP_API void LogGeneric(log_level level,
const char* subsystem,
const char* functionName,
const char* fileName,
u32 line,
const char* msg,
...);
MP_API void LogOutput(FILE* output);
MP_API void LogLevel(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_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
// error logging is always compiled
#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__ )
#if defined(LOG_COMPILE_MESSAGE) || defined(LOG_COMPILE_DEBUG)
#define LOG_MESSAGE(msg, ...) LOG_GENERIC(LOG_LEVEL_MESSAGE, __FUNCTION__, __FILE__, __LINE__, msg, ##__VA_ARGS__ )
#if defined(LOG_COMPILE_DEBUG)
#define LOG_DEBUG(msg, ...) LOG_GENERIC(LOG_LEVEL_DEBUG, __FUNCTION__, __FILE__, __LINE__, msg, ##__VA_ARGS__ )
#else
#define LOG_DEBUG(msg, ...)
#endif
#else
#define LOG_MESSAGE(msg, ...)
#define LOG_DEBUG(msg, ...)
#endif
#else
#define LOG_WARNING(msg, ...)
#define LOG_MESSAGE(msg, ...)
#define LOG_DEBUG(msg, ...)
#endif
#ifndef NO_ASSERT
#include<assert.h>
#define _ASSERT_(x, msg) assert(x && msg)
#define ASSERT(x, ...) _ASSERT_(x, #__VA_ARGS__)
#ifdef DEBUG
#define DEBUG_ASSERT(x, ...) ASSERT(x, ##__VA_ARGS__ )
#else
#define DEBUG_ASSERT(x, ...)
#endif
#else
#define ASSERT(x, ...)
#define DEBUG_ASSERT(x, ...)
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__DEBUG_LOG_H_

View File

@ -1,29 +1,29 @@
/************************************************************//**
*
* @file: hash.h
* @author: Martin Fouilleul
* @date: 08/08/2022
* @revision:
*
*****************************************************************/
#ifndef __HASH_H_
#define __HASH_H_
#include"typedefs.h"
#include"strings.h"
#ifdef __cplusplus
extern "C" {
#endif
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_string(str8 string);
MP_API u64 mp_hash_aes_string_seed(str8 string, u64 seed);
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__HASH_H_
/************************************************************//**
*
* @file: hash.h
* @author: Martin Fouilleul
* @date: 08/08/2022
* @revision:
*
*****************************************************************/
#ifndef __HASH_H_
#define __HASH_H_
#include"typedefs.h"
#include"strings.h"
#ifdef __cplusplus
extern "C" {
#endif
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_string(str8 string);
MP_API u64 mp_hash_aes_string_seed(str8 string, u64 seed);
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__HASH_H_

View File

@ -1,106 +1,106 @@
/************************************************************//**
*
* @file: memory.h
* @author: Martin Fouilleul
* @date: 24/10/2019
* @revision:
*
*****************************************************************/
#ifndef __MEMORY_H_
#define __MEMORY_H_
#include"typedefs.h"
#include"lists.h"
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------------------
//NOTE(martin): base allocator
//--------------------------------------------------------------------------------
typedef void*(*mem_reserve_function)(void* context, u64 size);
typedef void(*mem_modify_function)(void* context, void* ptr, u64 size);
typedef struct mem_base_allocator
{
mem_reserve_function reserve;
mem_modify_function commit;
mem_modify_function decommit;
mem_modify_function release;
void* context;
} mem_base_allocator;
MP_API mem_base_allocator* mem_base_allocator_default();
#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_decommit(base, ptr, size) base->decommit(base->context, ptr, size)
#define mem_base_release(base, ptr, size) base->release(base->context, ptr, size)
//--------------------------------------------------------------------------------
//NOTE(martin): memory arena
//--------------------------------------------------------------------------------
typedef struct mem_arena
{
mem_base_allocator* base;
char* ptr;
u64 offset;
u64 committed;
u64 cap;
} mem_arena;
typedef struct mem_arena_options
{
mem_base_allocator* base;
u64 reserve;
} mem_arena_options;
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_release(mem_arena* arena);
MP_API void* mem_arena_alloc(mem_arena* arena, u64 size);
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_array(arena, type, count) ((type*)mem_arena_alloc(arena, sizeof(type)*(count)))
//--------------------------------------------------------------------------------
//NOTE(martin): memory pool
//--------------------------------------------------------------------------------
typedef struct mem_pool
{
mem_arena arena;
list_info freeList;
u64 blockSize;
} mem_pool;
typedef struct mem_pool_options
{
mem_base_allocator* base;
u64 reserve;
} mem_pool_options;
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_release(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_clear(mem_pool* pool);
#define mem_pool_alloc_type(arena, type) ((type*)mem_pool_alloc(arena))
//--------------------------------------------------------------------------------
//NOTE(martin): per-thread implicit scratch arena
//--------------------------------------------------------------------------------
MP_API void mem_scratch_clear();
MP_API mem_arena* mem_scratch();
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__MEMORY_H_
/************************************************************//**
*
* @file: memory.h
* @author: Martin Fouilleul
* @date: 24/10/2019
* @revision:
*
*****************************************************************/
#ifndef __MEMORY_H_
#define __MEMORY_H_
#include"typedefs.h"
#include"lists.h"
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------------------
//NOTE(martin): base allocator
//--------------------------------------------------------------------------------
typedef void*(*mem_reserve_function)(void* context, u64 size);
typedef void(*mem_modify_function)(void* context, void* ptr, u64 size);
typedef struct mem_base_allocator
{
mem_reserve_function reserve;
mem_modify_function commit;
mem_modify_function decommit;
mem_modify_function release;
void* context;
} mem_base_allocator;
MP_API mem_base_allocator* mem_base_allocator_default();
#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_decommit(base, ptr, size) base->decommit(base->context, ptr, size)
#define mem_base_release(base, ptr, size) base->release(base->context, ptr, size)
//--------------------------------------------------------------------------------
//NOTE(martin): memory arena
//--------------------------------------------------------------------------------
typedef struct mem_arena
{
mem_base_allocator* base;
char* ptr;
u64 offset;
u64 committed;
u64 cap;
} mem_arena;
typedef struct mem_arena_options
{
mem_base_allocator* base;
u64 reserve;
} mem_arena_options;
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_release(mem_arena* arena);
MP_API void* mem_arena_alloc(mem_arena* arena, u64 size);
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_array(arena, type, count) ((type*)mem_arena_alloc(arena, sizeof(type)*(count)))
//--------------------------------------------------------------------------------
//NOTE(martin): memory pool
//--------------------------------------------------------------------------------
typedef struct mem_pool
{
mem_arena arena;
list_info freeList;
u64 blockSize;
} mem_pool;
typedef struct mem_pool_options
{
mem_base_allocator* base;
u64 reserve;
} mem_pool_options;
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_release(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_clear(mem_pool* pool);
#define mem_pool_alloc_type(arena, type) ((type*)mem_pool_alloc(arena))
//--------------------------------------------------------------------------------
//NOTE(martin): per-thread implicit scratch arena
//--------------------------------------------------------------------------------
MP_API void mem_scratch_clear();
MP_API mem_arena* mem_scratch();
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__MEMORY_H_

View File

@ -1,113 +1,113 @@
/************************************************************//**
*
* @file: strings.h
* @author: Martin Fouilleul
* @date: 29/05/2021
* @revision:
*
*****************************************************************/
#ifndef __STRINGS_H_
#define __STRINGS_H_
#include"typedefs.h"
#include"lists.h"
#include"memory.h"
#ifdef __cplusplus
extern "C" {
#endif
//----------------------------------------------------------------------------------
// string slices as values
//----------------------------------------------------------------------------------
typedef struct str8
{
u64 len;
char* ptr;
} str8;
#define str8_lit(s) ((str8){.len = sizeof(s)-1, .ptr = (char*)(s)})
#define str8_unbox(s) (int)((s).len), ((s).ptr)
MP_API str8 str8_from_buffer(u64 len, char* buffer);
MP_API str8 str8_from_cstring(char* str);
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_cstring(mem_arena* arena, const char* str);
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_pushfv(mem_arena* arena, const char* format, va_list args);
MP_API str8 str8_pushf(mem_arena* arena, const char* format, ...);
MP_API int str8_cmp(str8 s1, str8 s2);
MP_API char* str8_to_cstring(mem_arena* arena, str8 string);
//----------------------------------------------------------------------------------
// string lists
//----------------------------------------------------------------------------------
typedef struct str8_elt
{
list_elt listElt;
str8 string;
} str8_elt;
typedef struct str8_list
{
list_info list;
u64 eltCount;
u64 len;
} str8_list;
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 str8 str8_list_join(mem_arena* arena, str8_list list);
MP_API str8_list str8_split(mem_arena* arena, str8 str, str8_list separators);
//----------------------------------------------------------------------------------
// u32 strings
//----------------------------------------------------------------------------------
typedef struct str32
{
u64 len;
u32* ptr;
} str32;
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_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_slice(mem_arena* arena, str32 s, u64 start, u64 end);
typedef struct str32_elt
{
list_elt listElt;
str32 string;
} str32_elt;
typedef struct str32_list
{
list_info list;
u64 eltCount;
u64 len;
} str32_list;
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_list str32_split(mem_arena* arena, str32 str, str32_list separators);
//----------------------------------------------------------------------------------
// Paths helpers
//----------------------------------------------------------------------------------
MP_API str8 mp_path_directory(str8 fullPath);
MP_API str8 mp_path_base_name(str8 fullPath);
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__STRINGS_H_
/************************************************************//**
*
* @file: strings.h
* @author: Martin Fouilleul
* @date: 29/05/2021
* @revision:
*
*****************************************************************/
#ifndef __STRINGS_H_
#define __STRINGS_H_
#include"typedefs.h"
#include"lists.h"
#include"memory.h"
#ifdef __cplusplus
extern "C" {
#endif
//----------------------------------------------------------------------------------
// string slices as values
//----------------------------------------------------------------------------------
typedef struct str8
{
u64 len;
char* ptr;
} str8;
#define str8_lit(s) ((str8){.len = sizeof(s)-1, .ptr = (char*)(s)})
#define str8_unbox(s) (int)((s).len), ((s).ptr)
MP_API str8 str8_from_buffer(u64 len, char* buffer);
MP_API str8 str8_from_cstring(char* str);
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_cstring(mem_arena* arena, const char* str);
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_pushfv(mem_arena* arena, const char* format, va_list args);
MP_API str8 str8_pushf(mem_arena* arena, const char* format, ...);
MP_API int str8_cmp(str8 s1, str8 s2);
MP_API char* str8_to_cstring(mem_arena* arena, str8 string);
//----------------------------------------------------------------------------------
// string lists
//----------------------------------------------------------------------------------
typedef struct str8_elt
{
list_elt listElt;
str8 string;
} str8_elt;
typedef struct str8_list
{
list_info list;
u64 eltCount;
u64 len;
} str8_list;
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 str8 str8_list_join(mem_arena* arena, str8_list list);
MP_API str8_list str8_split(mem_arena* arena, str8 str, str8_list separators);
//----------------------------------------------------------------------------------
// u32 strings
//----------------------------------------------------------------------------------
typedef struct str32
{
u64 len;
u32* ptr;
} str32;
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_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_slice(mem_arena* arena, str32 s, u64 start, u64 end);
typedef struct str32_elt
{
list_elt listElt;
str32 string;
} str32_elt;
typedef struct str32_list
{
list_info list;
u64 eltCount;
u64 len;
} str32_list;
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_list str32_split(mem_arena* arena, str32 str, str32_list separators);
//----------------------------------------------------------------------------------
// Paths helpers
//----------------------------------------------------------------------------------
MP_API str8 mp_path_directory(str8 fullPath);
MP_API str8 mp_path_base_name(str8 fullPath);
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__STRINGS_H_

View File

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

View File

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

View File

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

View File

@ -1,16 +1,16 @@
/************************************************************//**
*
* @file: wgl_surface.c
* @author: Martin Fouilleul
* @date: 28/01/2023
* @revision:
*
*****************************************************************/
#ifndef __WGL_SURFACE_H_
#define __WGL_SURFACE_H_
#include"graphics_internal.h"
mg_surface_data* mg_wgl_surface_create_for_window(mp_window window);
#endif // __WIN32_GL_SURFACE_H_
/************************************************************//**
*
* @file: wgl_surface.c
* @author: Martin Fouilleul
* @date: 28/01/2023
* @revision:
*
*****************************************************************/
#ifndef __WGL_SURFACE_H_
#define __WGL_SURFACE_H_
#include"graphics_internal.h"
mg_surface_data* mg_wgl_surface_create_for_window(mp_window window);
#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 $
// $author: Martin Fouilleul $
// $date: 20/12/2022 $
// $revision: $
// $note: (C) 2022 by Martin Fouilleul - all rights reserved $
//
//*****************************************************************
#ifndef __WIN32_APP_H_
#define __WIN32_APP_H_
#include"mp_app.h"
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#include<windows.h>
typedef struct win32_window_data
{
HWND hWnd;
} win32_window_data;
typedef struct mp_layer
{
HWND hWnd;
} mp_layer;
#define MP_PLATFORM_WINDOW_DATA win32_window_data win32;
typedef struct win32_app_data
{
u32 savedConsoleCodePage;
int mouseCaptureMask;
bool mouseTracked;
} win32_app_data;
#define MP_PLATFORM_APP_DATA win32_app_data win32;
#endif __WIN32_APP_H_
//*****************************************************************
//
// $file: win32_app.h $
// $author: Martin Fouilleul $
// $date: 20/12/2022 $
// $revision: $
// $note: (C) 2022 by Martin Fouilleul - all rights reserved $
//
//*****************************************************************
#ifndef __WIN32_APP_H_
#define __WIN32_APP_H_
#include"mp_app.h"
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#include<windows.h>
typedef struct win32_window_data
{
HWND hWnd;
} win32_window_data;
typedef struct mp_layer
{
HWND hWnd;
} mp_layer;
#define MP_PLATFORM_WINDOW_DATA win32_window_data win32;
typedef struct win32_app_data
{
u32 savedConsoleCodePage;
int mouseCaptureMask;
bool mouseTracked;
} win32_app_data;
#define MP_PLATFORM_APP_DATA win32_app_data win32;
#endif __WIN32_APP_H_