[Clean canvas/shaders]
- Simplified shader names, prefix embedded strings by "glsl_" - Extracted shader compilation in common function - Add shader version string and common structs in canvas code rather than in every shader file - Renamed zIndex with shapeIndex everywhere
This commit is contained in:
parent
4a8c77f023
commit
4e816a838b
|
@ -1,8 +1,9 @@
|
|||
|
||||
if not exist bin mkdir bin
|
||||
|
||||
set gles_shaders=src\gles_canvas_shaders\gles_canvas_blit_vertex.glsl src\gles_canvas_shaders\gles_canvas_blit_fragment.glsl src\gles_canvas_shaders\gles_canvas_clear_counters.glsl src\gles_canvas_shaders\gles_canvas_tile.glsl src\gles_canvas_shaders\gles_canvas_sort.glsl src\gles_canvas_shaders\gles_canvas_draw.glsl
|
||||
call python scripts\embed_text.py %gles_shaders% --output src\gles_canvas_shaders.h
|
||||
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
|
||||
cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GL /std:c11 %INCLUDES% /c /Fo:bin/milepost.obj src/milepost.c
|
||||
|
|
|
@ -5,6 +5,7 @@ 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()
|
||||
|
||||
|
@ -30,7 +31,7 @@ for fileName in args.inputFiles:
|
|||
output.write("//NOTE: string imported from %s\n" % fileName)
|
||||
|
||||
stringName = os.path.splitext(os.path.basename(fileName))[0]
|
||||
output.write("const char* %s = " % stringName)
|
||||
output.write(f"const char* {args.prefix}{stringName} = ")
|
||||
|
||||
for line in lines:
|
||||
output.write("\n\"%s\\n\"" % line)
|
||||
|
|
223
src/gl_canvas.c
223
src/gl_canvas.c
|
@ -8,7 +8,7 @@
|
|||
*****************************************************************/
|
||||
#include"graphics_internal.h"
|
||||
#include"macro_helpers.h"
|
||||
#include"gles_canvas_shaders.h"
|
||||
#include"glsl_shaders.h"
|
||||
|
||||
#define LOG_SUBSYSTEM "Graphics"
|
||||
|
||||
|
@ -53,7 +53,7 @@ typedef struct debug_vertex
|
|||
{
|
||||
vec4 cubic;
|
||||
vec2 pos;
|
||||
int zIndex;
|
||||
int shapeIndex;
|
||||
u8 pad[4];
|
||||
} debug_vertex;
|
||||
|
||||
|
@ -110,8 +110,8 @@ void mg_gl_canvas_update_vertex_layout(mg_gl_canvas_backend* backend)
|
|||
.posStride = LAYOUT_VERTEX_SIZE,
|
||||
.cubicBuffer = backend->vertexMapping + LAYOUT_CUBIC_OFFSET,
|
||||
.cubicStride = LAYOUT_VERTEX_SIZE,
|
||||
.zIndexBuffer = backend->vertexMapping + LAYOUT_ZINDEX_OFFSET,
|
||||
.zIndexStride = LAYOUT_VERTEX_SIZE,
|
||||
.shapeIndexBuffer = backend->vertexMapping + LAYOUT_ZINDEX_OFFSET,
|
||||
.shapeIndexStride = LAYOUT_VERTEX_SIZE,
|
||||
|
||||
.colorBuffer = backend->shapeMapping + LAYOUT_COLOR_OFFSET,
|
||||
.colorStride = LAYOUT_SHAPE_SIZE,
|
||||
|
@ -263,16 +263,14 @@ void mg_gl_canvas_atlas_upload(mg_canvas_backend* interface, mp_rect rect, u8* b
|
|||
//TODO
|
||||
}
|
||||
|
||||
static void mg_gl_compile_shader(GLuint shader, const char* source)
|
||||
static int mg_gl_compile_shader(const char* name, GLuint shader, const char* source)
|
||||
{
|
||||
glShaderSource(shader, 1, &source, 0);
|
||||
glCompileShader(shader);
|
||||
int res = 0;
|
||||
|
||||
int err = glGetError();
|
||||
if(err)
|
||||
{
|
||||
printf("gl error: %i\n", err);
|
||||
}
|
||||
const char* sources[3] = {"#version 430", glsl_common, source};
|
||||
|
||||
glShaderSource(shader, 3, sources, 0);
|
||||
glCompileShader(shader);
|
||||
|
||||
int status = 0;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||
|
@ -281,10 +279,93 @@ static void mg_gl_compile_shader(GLuint shader, const char* source)
|
|||
char buffer[256];
|
||||
int size = 0;
|
||||
glGetShaderInfoLog(shader, 256, &size, buffer);
|
||||
printf("shader error: %.*s\n", size, buffer);
|
||||
printf("Shader compile error (%s): %.*s\n", name, size, buffer);
|
||||
res = -1;
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
static int mg_gl_canvas_compile_compute_program_named(const char* name, const char* source, GLuint* outProgram)
|
||||
{
|
||||
int res = 0;
|
||||
*outProgram = 0;
|
||||
|
||||
GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
|
||||
GLuint program = glCreateProgram();
|
||||
|
||||
res |= mg_gl_compile_shader(name, shader, source);
|
||||
|
||||
if(!res)
|
||||
{
|
||||
glAttachShader(program, shader);
|
||||
glLinkProgram(program);
|
||||
|
||||
int status = 0;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
if(!status)
|
||||
{
|
||||
char buffer[256];
|
||||
int size = 0;
|
||||
glGetProgramInfoLog(program, 256, &size, buffer);
|
||||
LOG_ERROR("Shader link error (%s): %.*s\n", name, size, buffer);
|
||||
|
||||
res = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*outProgram = program;
|
||||
}
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
int mg_gl_canvas_compile_render_program_named(const char* progName,
|
||||
const char* vertexName,
|
||||
const char* fragmentName,
|
||||
const char* vertexSrc,
|
||||
const char* fragmentSrc,
|
||||
GLuint* outProgram)
|
||||
{
|
||||
int res = 0;
|
||||
*outProgram = 0;
|
||||
|
||||
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
GLuint program = glCreateProgram();
|
||||
|
||||
res |= mg_gl_compile_shader(vertexName, vertexShader, vertexSrc);
|
||||
res |= mg_gl_compile_shader(fragmentName, fragmentShader, fragmentSrc);
|
||||
|
||||
if(!res)
|
||||
{
|
||||
glAttachShader(program, vertexShader);
|
||||
glAttachShader(program, fragmentShader);
|
||||
glLinkProgram(program);
|
||||
|
||||
int status = 0;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
if(!status)
|
||||
{
|
||||
char buffer[256];
|
||||
int size = 0;
|
||||
glGetProgramInfoLog(program, 256, &size, buffer);
|
||||
LOG_ERROR("Shader link error (%s): %.*s\n", progName, size, buffer);
|
||||
res = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*outProgram = program;
|
||||
}
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
#define mg_gl_canvas_compile_compute_program(src, out) \
|
||||
mg_gl_canvas_compile_compute_program_named(#src, src, out)
|
||||
|
||||
#define mg_gl_canvas_compile_render_program(progName, shaderSrc, vertexSrc, out) \
|
||||
mg_gl_canvas_compile_render_program_named(progName, #shaderSrc, #vertexSrc, shaderSrc, vertexSrc, out)
|
||||
|
||||
mg_canvas_backend* mg_gl_canvas_create(mg_surface surface)
|
||||
{
|
||||
mg_gl_canvas_backend* backend = 0;
|
||||
|
@ -343,116 +424,12 @@ mg_canvas_backend* mg_gl_canvas_create(mg_surface surface)
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
//NOTE: create clear program
|
||||
{
|
||||
GLuint clearShader = glCreateShader(GL_COMPUTE_SHADER);
|
||||
backend->clearCounterProgram = glCreateProgram();
|
||||
|
||||
mg_gl_compile_shader(clearShader, gles_canvas_clear_counters);
|
||||
|
||||
glAttachShader(backend->clearCounterProgram, clearShader);
|
||||
glLinkProgram(backend->clearCounterProgram);
|
||||
|
||||
int status = 0;
|
||||
glGetProgramiv(backend->clearCounterProgram, GL_LINK_STATUS, &status);
|
||||
if(!status)
|
||||
{
|
||||
char buffer[256];
|
||||
int size = 0;
|
||||
glGetProgramInfoLog(backend->clearCounterProgram, 256, &size, buffer);
|
||||
printf("link error in gl_canvas_clear_counters: %.*s\n", size, buffer);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
//NOTE: create tile program
|
||||
{
|
||||
GLuint tileShader = glCreateShader(GL_COMPUTE_SHADER);
|
||||
backend->tileProgram = glCreateProgram();
|
||||
|
||||
mg_gl_compile_shader(tileShader, gles_canvas_tile);
|
||||
|
||||
glAttachShader(backend->tileProgram, tileShader);
|
||||
glLinkProgram(backend->tileProgram);
|
||||
|
||||
int status = 0;
|
||||
glGetProgramiv(backend->tileProgram, GL_LINK_STATUS, &status);
|
||||
if(!status)
|
||||
{
|
||||
char buffer[256];
|
||||
int size = 0;
|
||||
glGetProgramInfoLog(backend->tileProgram, 256, &size, buffer);
|
||||
printf("link error in gl_canvas_tile: %.*s\n", size, buffer);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
//NOTE: create sort program
|
||||
{
|
||||
GLuint sortShader = glCreateShader(GL_COMPUTE_SHADER);
|
||||
backend->sortProgram = glCreateProgram();
|
||||
|
||||
mg_gl_compile_shader(sortShader, gles_canvas_sort);
|
||||
|
||||
glAttachShader(backend->sortProgram, sortShader);
|
||||
glLinkProgram(backend->sortProgram);
|
||||
|
||||
int status = 0;
|
||||
glGetProgramiv(backend->sortProgram, GL_LINK_STATUS, &status);
|
||||
if(!status)
|
||||
{
|
||||
char buffer[256];
|
||||
int size = 0;
|
||||
glGetProgramInfoLog(backend->sortProgram, 256, &size, buffer);
|
||||
printf("link error gl_canvas_sort: %.*s\n", size, buffer);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: create draw program
|
||||
{
|
||||
GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
|
||||
backend->drawProgram = glCreateProgram();
|
||||
|
||||
mg_gl_compile_shader(shader, gles_canvas_draw);
|
||||
|
||||
glAttachShader(backend->drawProgram, shader);
|
||||
glLinkProgram(backend->drawProgram);
|
||||
|
||||
int status = 0;
|
||||
glGetProgramiv(backend->drawProgram, GL_LINK_STATUS, &status);
|
||||
if(!status)
|
||||
{
|
||||
char buffer[256];
|
||||
int size = 0;
|
||||
glGetProgramInfoLog(backend->drawProgram, 256, &size, buffer);
|
||||
printf("link error gl_canvas_draw: %.*s\n", size, buffer);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: create blit program
|
||||
{
|
||||
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
backend->blitProgram = glCreateProgram();
|
||||
|
||||
mg_gl_compile_shader(vertexShader, gles_canvas_blit_vertex);
|
||||
mg_gl_compile_shader(fragmentShader, gles_canvas_blit_fragment);
|
||||
|
||||
glAttachShader(backend->blitProgram, vertexShader);
|
||||
glAttachShader(backend->blitProgram, fragmentShader);
|
||||
glLinkProgram(backend->blitProgram);
|
||||
|
||||
int status = 0;
|
||||
glGetProgramiv(backend->blitProgram, GL_LINK_STATUS, &status);
|
||||
if(!status)
|
||||
{
|
||||
char buffer[256];
|
||||
int size = 0;
|
||||
glGetProgramInfoLog(backend->blitProgram, 256, &size, buffer);
|
||||
printf("link error gl_canvas_blit: %.*s\n", size, buffer);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
//NOTE: create programs
|
||||
mg_gl_canvas_compile_compute_program(glsl_clear_counters, &backend->clearCounterProgram);
|
||||
mg_gl_canvas_compile_compute_program(glsl_tile, &backend->tileProgram);
|
||||
mg_gl_canvas_compile_compute_program(glsl_sort, &backend->sortProgram);
|
||||
mg_gl_canvas_compile_compute_program(glsl_draw, &backend->drawProgram);
|
||||
mg_gl_canvas_compile_render_program("blit", glsl_blit_vertex, glsl_blit_fragment, &backend->blitProgram);
|
||||
|
||||
backend->vertexMapping = malloc_array(char, 1<<30);
|
||||
backend->shapeMapping = malloc_array(char, 1<<30);
|
||||
|
|
|
@ -1,451 +0,0 @@
|
|||
/************************************************************//**
|
||||
*
|
||||
* @file: gles_canvas.c
|
||||
* @author: Martin Fouilleul
|
||||
* @date: 29/01/2023
|
||||
* @revision:
|
||||
*
|
||||
*****************************************************************/
|
||||
#include"graphics_internal.h"
|
||||
#include"macro_helpers.h"
|
||||
#include"gles_canvas_shaders.h"
|
||||
|
||||
#define LOG_SUBSYSTEM "Graphics"
|
||||
|
||||
typedef struct mg_gles_canvas_backend
|
||||
{
|
||||
mg_canvas_backend interface;
|
||||
mg_surface surface;
|
||||
|
||||
GLint dummyVertexBuffer;
|
||||
GLint vertexBuffer;
|
||||
GLint indexBuffer;
|
||||
GLint tileCounterBuffer;
|
||||
GLint tileArrayBuffer;
|
||||
GLint clearCounterProgram;
|
||||
GLint tileProgram;
|
||||
GLint sortProgram;
|
||||
GLint drawProgram;
|
||||
GLint blitProgram;
|
||||
|
||||
GLint outTexture;
|
||||
|
||||
char* indexMapping;
|
||||
char* vertexMapping;
|
||||
|
||||
} mg_gles_canvas_backend;
|
||||
|
||||
mg_gles_surface* mg_gles_canvas_get_surface(mg_gles_canvas_backend* canvas)
|
||||
{
|
||||
mg_gles_surface* res = 0;
|
||||
mg_surface_data* data = mg_surface_data_from_handle(canvas->surface);
|
||||
if(data && data->backend == MG_BACKEND_GLES)
|
||||
{
|
||||
res = (mg_gles_surface*)data;
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
//NOTE: debugger
|
||||
typedef struct debug_vertex
|
||||
{
|
||||
vec2 pos;
|
||||
vec2 uv;
|
||||
vec4 cubic;
|
||||
vec4 color;
|
||||
vec4 clip;
|
||||
int zIndex;
|
||||
u8 align2[12];
|
||||
} debug_vertex;
|
||||
|
||||
|
||||
#define LayoutNext(prevName, prevType, nextType) \
|
||||
AlignUpOnPow2(_cat3_(LAYOUT_, prevName, _OFFSET)+_cat3_(LAYOUT_, prevType, _SIZE), _cat3_(LAYOUT_, nextType, _ALIGN))
|
||||
|
||||
enum {
|
||||
LAYOUT_VEC2_SIZE = 8,
|
||||
LAYOUT_VEC2_ALIGN = 8,
|
||||
LAYOUT_VEC4_SIZE = 16,
|
||||
LAYOUT_VEC4_ALIGN = 16,
|
||||
LAYOUT_INT_SIZE = 4,
|
||||
LAYOUT_INT_ALIGN = 4,
|
||||
|
||||
LAYOUT_POS_OFFSET = 0,
|
||||
LAYOUT_UV_OFFSET = LayoutNext(POS, VEC2, VEC2),
|
||||
LAYOUT_CUBIC_OFFSET = LayoutNext(UV, VEC2, VEC4),
|
||||
LAYOUT_COLOR_OFFSET = LayoutNext(CUBIC, VEC4, VEC4),
|
||||
LAYOUT_CLIP_OFFSET = LayoutNext(COLOR, VEC4, VEC4),
|
||||
LAYOUT_ZINDEX_OFFSET = LayoutNext(CLIP, VEC4, INT),
|
||||
|
||||
LAYOUT_VERTEX_ALIGN = 16,
|
||||
LAYOUT_VERTEX_SIZE = LayoutNext(ZINDEX, INT, VERTEX),
|
||||
};
|
||||
|
||||
enum {
|
||||
MG_GLES_CANVAS_DEFAULT_BUFFER_LENGTH = 1<<20,
|
||||
MG_GLES_CANVAS_VERTEX_BUFFER_SIZE = MG_GLES_CANVAS_DEFAULT_BUFFER_LENGTH * LAYOUT_VERTEX_SIZE,
|
||||
MG_GLES_CANVAS_INDEX_BUFFER_SIZE = MG_GLES_CANVAS_DEFAULT_BUFFER_LENGTH * LAYOUT_INT_SIZE,
|
||||
MG_GLES_CANVAS_TILE_COUNTER_BUFFER_SIZE = 65536,
|
||||
MG_GLES_CANVAS_TILE_ARRAY_SIZE = sizeof(int)*4096,
|
||||
MG_GLES_CANVAS_TILE_ARRAY_BUFFER_SIZE = MG_GLES_CANVAS_TILE_COUNTER_BUFFER_SIZE * MG_GLES_CANVAS_TILE_ARRAY_SIZE,
|
||||
};
|
||||
|
||||
void mg_gles_canvas_update_vertex_layout(mg_gles_canvas_backend* backend)
|
||||
{
|
||||
backend->interface.vertexLayout = (mg_vertex_layout){
|
||||
.maxVertexCount = MG_GLES_CANVAS_DEFAULT_BUFFER_LENGTH,
|
||||
.maxIndexCount = MG_GLES_CANVAS_DEFAULT_BUFFER_LENGTH,
|
||||
.posBuffer = backend->vertexMapping + LAYOUT_POS_OFFSET,
|
||||
.posStride = LAYOUT_VERTEX_SIZE,
|
||||
.cubicBuffer = backend->vertexMapping + LAYOUT_CUBIC_OFFSET,
|
||||
.cubicStride = LAYOUT_VERTEX_SIZE,
|
||||
.uvBuffer = backend->vertexMapping + LAYOUT_UV_OFFSET,
|
||||
.uvStride = LAYOUT_VERTEX_SIZE,
|
||||
.colorBuffer = backend->vertexMapping + LAYOUT_COLOR_OFFSET,
|
||||
.colorStride = LAYOUT_VERTEX_SIZE,
|
||||
.clipBuffer = backend->vertexMapping + LAYOUT_CLIP_OFFSET,
|
||||
.clipStride = LAYOUT_VERTEX_SIZE,
|
||||
.zIndexBuffer = backend->vertexMapping + LAYOUT_ZINDEX_OFFSET,
|
||||
.zIndexStride = LAYOUT_VERTEX_SIZE,
|
||||
.indexBuffer = backend->indexMapping,
|
||||
.indexStride = LAYOUT_INT_SIZE};
|
||||
}
|
||||
|
||||
void mg_gles_send_buffers(mg_gles_canvas_backend* backend, int vertexCount, int indexCount)
|
||||
{
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->vertexBuffer);
|
||||
glBufferData(GL_SHADER_STORAGE_BUFFER, LAYOUT_VERTEX_SIZE*vertexCount, backend->vertexMapping, GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->indexBuffer);
|
||||
glBufferData(GL_SHADER_STORAGE_BUFFER, LAYOUT_INT_SIZE*indexCount, backend->indexMapping, GL_DYNAMIC_DRAW);
|
||||
}
|
||||
void mg_gles_canvas_begin(mg_canvas_backend* interface)
|
||||
{
|
||||
mg_gles_canvas_backend* backend = (mg_gles_canvas_backend*)interface;
|
||||
mg_gles_surface* surface = mg_gles_canvas_get_surface(backend);
|
||||
if(!surface)
|
||||
{
|
||||
return;
|
||||
}
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
void mg_gles_canvas_end(mg_canvas_backend* interface)
|
||||
{
|
||||
//NOTE: nothing to do here...
|
||||
}
|
||||
|
||||
void mg_gles_canvas_clear(mg_canvas_backend* interface, mg_color clearColor)
|
||||
{
|
||||
mg_gles_canvas_backend* backend = (mg_gles_canvas_backend*)interface;
|
||||
mg_gles_surface* surface = mg_gles_canvas_get_surface(backend);
|
||||
if(!surface)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void mg_gles_canvas_draw_batch(mg_canvas_backend* interface, u32 vertexCount, u32 indexCount)
|
||||
{
|
||||
mg_gles_canvas_backend* backend = (mg_gles_canvas_backend*)interface;
|
||||
mg_gles_surface* surface = mg_gles_canvas_get_surface(backend);
|
||||
if(!surface)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*NOTE: if we want debug_vertex while debugging, the following ensures the struct def doesn't get stripped away
|
||||
debug_vertex vertex;
|
||||
printf("foo %p\n", &vertex);
|
||||
//*/
|
||||
mg_gles_send_buffers(backend, vertexCount, indexCount);
|
||||
|
||||
mp_rect frame = mg_surface_get_frame(backend->surface);
|
||||
|
||||
const int tileSize = 16;
|
||||
const int tileCountX = (frame.w + tileSize - 1)/tileSize;
|
||||
const int tileCountY = (frame.h + tileSize - 1)/tileSize;
|
||||
const int tileArraySize = MG_GLES_CANVAS_TILE_ARRAY_SIZE;
|
||||
|
||||
//TODO: ensure there's enough space in tile buffer
|
||||
|
||||
//NOTE: first clear counters
|
||||
glUseProgram(backend->clearCounterProgram);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->tileCounterBuffer);
|
||||
glDispatchCompute(tileCountX*tileCountY, 1, 1);
|
||||
|
||||
//NOTE: we first distribute triangles into tiles:
|
||||
|
||||
glUseProgram(backend->tileProgram);
|
||||
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->vertexBuffer);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->indexBuffer);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->tileCounterBuffer);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->tileArrayBuffer);
|
||||
|
||||
glUniform1ui(0, indexCount);
|
||||
glUniform2ui(1, tileCountX, tileCountY);
|
||||
glUniform1ui(2, tileSize);
|
||||
glUniform1ui(3, tileArraySize);
|
||||
|
||||
u32 threadCount = indexCount/3;
|
||||
glDispatchCompute((threadCount + 255)/256, 1, 1);
|
||||
|
||||
//NOTE: next we sort triangles in each tile
|
||||
glUseProgram(backend->sortProgram);
|
||||
/*
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->vertexBuffer);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->indexBuffer);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->tileCounterBuffer);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->tileArrayBuffer);
|
||||
*/
|
||||
glUniform1ui(0, indexCount);
|
||||
glUniform2ui(1, tileCountX, tileCountY);
|
||||
glUniform1ui(2, tileSize);
|
||||
glUniform1ui(3, tileArraySize);
|
||||
|
||||
glDispatchCompute(tileCountX * tileCountY, 1, 1);
|
||||
|
||||
//TODO: then we fire the fragment shader that will select only triangles in its tile
|
||||
// glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
|
||||
glUseProgram(backend->drawProgram);
|
||||
/*
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, backend->vertexBuffer);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, backend->indexBuffer);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, backend->tileCounterBuffer);
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, backend->tileArrayBuffer);
|
||||
*/
|
||||
glBindImageTexture(0, backend->outTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
|
||||
|
||||
glUniform1ui(0, indexCount);
|
||||
glUniform2ui(1, tileCountX, tileCountY);
|
||||
glUniform1ui(2, tileSize);
|
||||
glUniform1ui(3, tileArraySize);
|
||||
|
||||
glDispatchCompute(tileCountX, tileCountY, 1);
|
||||
|
||||
//NOTE: now blit out texture to surface
|
||||
glUseProgram(backend->blitProgram);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, backend->dummyVertexBuffer);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, backend->outTexture);
|
||||
glUniform1i(0, 0);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
|
||||
mg_gles_canvas_update_vertex_layout(backend);
|
||||
}
|
||||
|
||||
void mg_gles_canvas_destroy(mg_canvas_backend* interface)
|
||||
{
|
||||
mg_gles_canvas_backend* backend = (mg_gles_canvas_backend*)interface;
|
||||
|
||||
//TODO
|
||||
}
|
||||
|
||||
void mg_gles_canvas_atlas_upload(mg_canvas_backend* interface, mp_rect rect, u8* bytes)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
static void mg_gles_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);
|
||||
}
|
||||
}
|
||||
|
||||
mg_canvas_backend* mg_gles_canvas_create(mg_surface surface)
|
||||
{
|
||||
mg_gles_canvas_backend* backend = 0;
|
||||
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
|
||||
if(surfaceData && surfaceData->backend == MG_BACKEND_GLES)
|
||||
{
|
||||
mg_gles_surface* glesSurface = (mg_gles_surface*)surfaceData;
|
||||
|
||||
backend = malloc_type(mg_gles_canvas_backend);
|
||||
memset(backend, 0, sizeof(mg_gles_canvas_backend));
|
||||
backend->surface = surface;
|
||||
|
||||
//NOTE(martin): setup interface functions
|
||||
backend->interface.destroy = mg_gles_canvas_destroy;
|
||||
backend->interface.begin = mg_gles_canvas_begin;
|
||||
backend->interface.end = mg_gles_canvas_end;
|
||||
backend->interface.clear = mg_gles_canvas_clear;
|
||||
backend->interface.drawBatch = mg_gles_canvas_draw_batch;
|
||||
backend->interface.atlasUpload = mg_gles_canvas_atlas_upload;
|
||||
|
||||
mg_surface_prepare(surface);
|
||||
|
||||
GLuint vao;
|
||||
glGenVertexArrays(1, &vao);
|
||||
glBindVertexArray(vao);
|
||||
|
||||
glGenBuffers(1, &backend->vertexBuffer);
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->vertexBuffer);
|
||||
// glBufferData(GL_SHADER_STORAGE_BUFFER, MG_GLES_CANVAS_VERTEX_BUFFER_SIZE, 0, GL_DYNAMIC_DRAW);
|
||||
|
||||
glGenBuffers(1, &backend->indexBuffer);
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->indexBuffer);
|
||||
// glBufferData(GL_SHADER_STORAGE_BUFFER, MG_GLES_CANVAS_INDEX_BUFFER_SIZE, 0, GL_DYNAMIC_DRAW);
|
||||
|
||||
glGenBuffers(1, &backend->tileCounterBuffer);
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->tileCounterBuffer);
|
||||
glBufferData(GL_SHADER_STORAGE_BUFFER, MG_GLES_CANVAS_TILE_COUNTER_BUFFER_SIZE, 0, GL_DYNAMIC_COPY);
|
||||
|
||||
glGenBuffers(1, &backend->tileArrayBuffer);
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->tileArrayBuffer);
|
||||
glBufferData(GL_SHADER_STORAGE_BUFFER, MG_GLES_CANVAS_TILE_ARRAY_BUFFER_SIZE, 0, GL_DYNAMIC_COPY);
|
||||
|
||||
glGenBuffers(1, &backend->dummyVertexBuffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, backend->dummyVertexBuffer);
|
||||
|
||||
mp_rect frame = mg_surface_get_frame(backend->surface);
|
||||
glGenTextures(1, &backend->outTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, backend->outTexture);
|
||||
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, frame.w, frame.h);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
//NOTE: create clear program
|
||||
{
|
||||
GLuint clearShader = glCreateShader(GL_COMPUTE_SHADER);
|
||||
backend->clearCounterProgram = glCreateProgram();
|
||||
|
||||
mg_gles_compile_shader(clearShader, gles_canvas_clear_counters);
|
||||
|
||||
glAttachShader(backend->clearCounterProgram, clearShader);
|
||||
glLinkProgram(backend->clearCounterProgram);
|
||||
|
||||
int status = 0;
|
||||
glGetProgramiv(backend->clearCounterProgram, GL_LINK_STATUS, &status);
|
||||
if(!status)
|
||||
{
|
||||
char buffer[256];
|
||||
int size = 0;
|
||||
glGetProgramInfoLog(backend->clearCounterProgram, 256, &size, buffer);
|
||||
printf("link error in gl_canvas_clear_counters: %.*s\n", size, buffer);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
//NOTE: create tile program
|
||||
{
|
||||
GLuint tileShader = glCreateShader(GL_COMPUTE_SHADER);
|
||||
backend->tileProgram = glCreateProgram();
|
||||
|
||||
mg_gles_compile_shader(tileShader, gles_canvas_tile);
|
||||
|
||||
glAttachShader(backend->tileProgram, tileShader);
|
||||
glLinkProgram(backend->tileProgram);
|
||||
|
||||
int status = 0;
|
||||
glGetProgramiv(backend->tileProgram, GL_LINK_STATUS, &status);
|
||||
if(!status)
|
||||
{
|
||||
char buffer[256];
|
||||
int size = 0;
|
||||
glGetProgramInfoLog(backend->tileProgram, 256, &size, buffer);
|
||||
printf("link error in gl_canvas_tile: %.*s\n", size, buffer);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
//NOTE: create sort program
|
||||
{
|
||||
GLuint sortShader = glCreateShader(GL_COMPUTE_SHADER);
|
||||
backend->sortProgram = glCreateProgram();
|
||||
|
||||
mg_gles_compile_shader(sortShader, gles_canvas_sort);
|
||||
|
||||
glAttachShader(backend->sortProgram, sortShader);
|
||||
glLinkProgram(backend->sortProgram);
|
||||
|
||||
int status = 0;
|
||||
glGetProgramiv(backend->sortProgram, GL_LINK_STATUS, &status);
|
||||
if(!status)
|
||||
{
|
||||
char buffer[256];
|
||||
int size = 0;
|
||||
glGetProgramInfoLog(backend->sortProgram, 256, &size, buffer);
|
||||
printf("link error gl_canvas_sort: %.*s\n", size, buffer);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: create draw program
|
||||
{
|
||||
GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
|
||||
backend->drawProgram = glCreateProgram();
|
||||
|
||||
mg_gles_compile_shader(shader, gles_canvas_draw);
|
||||
|
||||
glAttachShader(backend->drawProgram, shader);
|
||||
glLinkProgram(backend->drawProgram);
|
||||
|
||||
int status = 0;
|
||||
glGetProgramiv(backend->drawProgram, GL_LINK_STATUS, &status);
|
||||
if(!status)
|
||||
{
|
||||
char buffer[256];
|
||||
int size = 0;
|
||||
glGetProgramInfoLog(backend->drawProgram, 256, &size, buffer);
|
||||
printf("link error gl_canvas_draw: %.*s\n", size, buffer);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: create blit program
|
||||
{
|
||||
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
backend->blitProgram = glCreateProgram();
|
||||
|
||||
mg_gles_compile_shader(vertexShader, gles_canvas_blit_vertex);
|
||||
mg_gles_compile_shader(fragmentShader, gles_canvas_blit_fragment);
|
||||
|
||||
glAttachShader(backend->blitProgram, vertexShader);
|
||||
glAttachShader(backend->blitProgram, fragmentShader);
|
||||
glLinkProgram(backend->blitProgram);
|
||||
|
||||
int status = 0;
|
||||
glGetProgramiv(backend->blitProgram, GL_LINK_STATUS, &status);
|
||||
if(!status)
|
||||
{
|
||||
char buffer[256];
|
||||
int size = 0;
|
||||
glGetProgramInfoLog(backend->blitProgram, 256, &size, buffer);
|
||||
printf("link error gl_canvas_blit: %.*s\n", size, buffer);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
backend->vertexMapping = malloc_array(char, 1<<30);
|
||||
backend->indexMapping = malloc_array(char, 1<<30);
|
||||
|
||||
mg_gles_canvas_update_vertex_layout(backend);
|
||||
}
|
||||
|
||||
return((mg_canvas_backend*)backend);
|
||||
}
|
||||
|
||||
|
||||
#undef LOG_SUBSYSTEM
|
|
@ -0,0 +1,441 @@
|
|||
/*********************************************************************
|
||||
*
|
||||
* file: glsl_shaders.h
|
||||
* note: string literals auto-generated by embed_text.py
|
||||
* date: 09/022023
|
||||
*
|
||||
**********************************************************************/
|
||||
#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"
|
||||
" vec2 uv;\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"
|
||||
"\n"
|
||||
"layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;\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"
|
||||
" ivec4 clip = ivec4(round((shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling) + vec4(0.5, 0.5, 0.5, 0.5)) * subPixelFactor));\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"
|
||||
" currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-color.a) + color.a*color;\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__
|
|
@ -1,4 +1,3 @@
|
|||
#version 430
|
||||
|
||||
precision mediump float;
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
#version 430
|
||||
|
||||
precision mediump float;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#version 430
|
||||
|
||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
precision mediump float;
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
layout(std430) buffer;
|
||||
|
||||
struct vertex {
|
||||
vec4 cubic;
|
||||
vec2 pos;
|
||||
int shapeIndex;
|
||||
};
|
||||
|
||||
struct shape {
|
||||
vec4 color;
|
||||
vec4 clip;
|
||||
vec2 uv;
|
||||
};
|
|
@ -1,24 +1,10 @@
|
|||
#version 430
|
||||
|
||||
#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(std430) buffer;
|
||||
|
||||
struct vertex {
|
||||
vec4 cubic;
|
||||
vec2 pos;
|
||||
int zIndex;
|
||||
};
|
||||
|
||||
struct shape {
|
||||
vec4 color;
|
||||
vec4 clip;
|
||||
vec2 uv;
|
||||
};
|
||||
|
||||
layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
|
||||
vertex elements[];
|
||||
} vertexBuffer ;
|
||||
|
@ -127,12 +113,12 @@ void main()
|
|||
|
||||
vec4 sampleColor[sampleCount];
|
||||
vec4 currentColor[sampleCount];
|
||||
int currentZIndex[sampleCount];
|
||||
int currentShapeIndex[sampleCount];
|
||||
int flipCount[sampleCount];
|
||||
|
||||
for(int i=0; i<sampleCount; i++)
|
||||
{
|
||||
currentZIndex[i] = -1;
|
||||
currentShapeIndex[i] = -1;
|
||||
flipCount[i] = 0;
|
||||
sampleColor[i] = vec4(0, 0, 0, 0);
|
||||
currentColor[i] = vec4(0, 0, 0, 0);
|
||||
|
@ -150,9 +136,9 @@ void main()
|
|||
ivec2 p1 = ivec2((vertexBuffer.elements[i1].pos * scaling) * subPixelFactor);
|
||||
ivec2 p2 = ivec2((vertexBuffer.elements[i2].pos * scaling) * subPixelFactor);
|
||||
|
||||
int zIndex = vertexBuffer.elements[i0].zIndex;
|
||||
vec4 color = shapeBuffer.elements[zIndex].color;
|
||||
ivec4 clip = ivec4(round((shapeBuffer.elements[zIndex].clip * vec4(scaling, scaling) + vec4(0.5, 0.5, 0.5, 0.5)) * subPixelFactor));
|
||||
int shapeIndex = vertexBuffer.elements[i0].shapeIndex;
|
||||
vec4 color = shapeBuffer.elements[shapeIndex].color;
|
||||
ivec4 clip = ivec4(round((shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling) + vec4(0.5, 0.5, 0.5, 0.5)) * subPixelFactor));
|
||||
|
||||
//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
|
||||
int cw = is_clockwise(p0, p1, p2);
|
||||
|
@ -198,7 +184,7 @@ void main()
|
|||
float eps = 0.0001;
|
||||
if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)
|
||||
{
|
||||
if(zIndex == currentZIndex[sampleIndex])
|
||||
if(shapeIndex == currentShapeIndex[sampleIndex])
|
||||
{
|
||||
flipCount[sampleIndex]++;
|
||||
}
|
||||
|
@ -209,7 +195,7 @@ void main()
|
|||
sampleColor[sampleIndex] = currentColor[sampleIndex];
|
||||
}
|
||||
currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-color.a) + color.a*color;
|
||||
currentZIndex[sampleIndex] = zIndex;
|
||||
currentShapeIndex[sampleIndex] = shapeIndex;
|
||||
flipCount[sampleIndex] = 1;
|
||||
}
|
||||
}
|
|
@ -1,20 +1,7 @@
|
|||
#version 430
|
||||
|
||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
precision mediump float;
|
||||
layout(std430) buffer;
|
||||
|
||||
struct vertex {
|
||||
vec4 cubic;
|
||||
vec2 pos;
|
||||
int zIndex;
|
||||
};
|
||||
|
||||
struct shape {
|
||||
vec4 color;
|
||||
vec4 clip;
|
||||
vec2 uv;
|
||||
};
|
||||
|
||||
layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
|
||||
vertex elements[];
|
||||
|
@ -41,12 +28,12 @@ layout(location = 1) uniform uvec2 tileCount;
|
|||
layout(location = 2) uniform uint tileSize;
|
||||
layout(location = 3) uniform uint tileArraySize;
|
||||
|
||||
int get_zindex(uint tileArrayOffset, uint tileArrayIndex)
|
||||
int get_shape_index(uint tileArrayOffset, uint tileArrayIndex)
|
||||
{
|
||||
uint triangleIndex = tileArrayBuffer.elements[tileArrayOffset + tileArrayIndex];
|
||||
uint i0 = indexBuffer.elements[triangleIndex];
|
||||
int zIndex = vertexBuffer.elements[i0].zIndex;
|
||||
return(zIndex);
|
||||
int shapeIndex = vertexBuffer.elements[i0].shapeIndex;
|
||||
return(shapeIndex);
|
||||
}
|
||||
|
||||
void main()
|
||||
|
@ -59,10 +46,10 @@ void main()
|
|||
{
|
||||
for(uint sortIndex = tileArrayIndex; sortIndex > 0u; sortIndex--)
|
||||
{
|
||||
int zIndex = get_zindex(tileArrayOffset, sortIndex);
|
||||
int prevZIndex = get_zindex(tileArrayOffset, sortIndex-1u);
|
||||
int shapeIndex = get_shape_index(tileArrayOffset, sortIndex);
|
||||
int prevShapeIndex = get_shape_index(tileArrayOffset, sortIndex-1u);
|
||||
|
||||
if(zIndex >= prevZIndex)
|
||||
if(shapeIndex >= prevShapeIndex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -71,20 +58,4 @@ void main()
|
|||
tileArrayBuffer.elements[tileArrayOffset + sortIndex - 1u] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
//DEBUG
|
||||
/*
|
||||
int prevZIndex = -1;
|
||||
for(uint tileArrayIndex=1u; tileArrayIndex < tileArrayCount; tileArrayIndex++)
|
||||
{
|
||||
int zIndex = get_zindex(tileArrayOffset, tileArrayIndex);
|
||||
|
||||
if(zIndex < prevZIndex)
|
||||
{
|
||||
tileCounterBuffer.elements[tileIndex] = 0xffffu;
|
||||
break;
|
||||
}
|
||||
prevZIndex = zIndex;
|
||||
}
|
||||
//*/
|
||||
}
|
|
@ -1,20 +1,7 @@
|
|||
#version 430
|
||||
|
||||
layout(local_size_x = 512, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
precision mediump float;
|
||||
layout(std430) buffer;
|
||||
|
||||
struct vertex {
|
||||
vec4 cubic;
|
||||
vec2 pos;
|
||||
int zIndex;
|
||||
};
|
||||
|
||||
struct shape {
|
||||
vec4 color;
|
||||
vec4 clip;
|
||||
vec2 uv;
|
||||
};
|
||||
|
||||
layout(binding = 0) restrict readonly buffer vertexBufferSSBO {
|
||||
vertex elements[];
|
||||
|
@ -58,7 +45,7 @@ void main()
|
|||
vec2 p1 = vertexBuffer.elements[i1].pos * scaling;
|
||||
vec2 p2 = vertexBuffer.elements[i2].pos * scaling;
|
||||
|
||||
int shapeIndex = vertexBuffer.elements[i0].zIndex;
|
||||
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),
|
236
src/graphics.c
236
src/graphics.c
|
@ -447,17 +447,17 @@ void mg_path_push_element(mg_canvas_data* canvas, mg_path_elt elt)
|
|||
|
||||
/////////////////////////////////////// WIP /////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void mg_reset_z_index(mg_canvas_data* canvas)
|
||||
void mg_reset_shape_index(mg_canvas_data* canvas)
|
||||
{
|
||||
canvas->nextZIndex = 1;
|
||||
canvas->nextShapeIndex = 0;
|
||||
}
|
||||
|
||||
u32 mg_next_shape_textured(mg_canvas_data* canvas, vec2 uv, mg_color color)
|
||||
{
|
||||
//TODO: push color, uv, clip
|
||||
|
||||
int index = canvas->nextZIndex;
|
||||
canvas->nextZIndex++;
|
||||
int index = canvas->nextShapeIndex;
|
||||
canvas->nextShapeIndex++;
|
||||
|
||||
mp_rect clip = {canvas->clip.x,
|
||||
canvas->clip.y,
|
||||
|
@ -496,16 +496,16 @@ int* mg_reserve_indices(mg_canvas_data* canvas, u32 indexCount)
|
|||
return(base);
|
||||
}
|
||||
|
||||
void mg_push_vertex(mg_canvas_data* canvas, vec2 pos, vec4 cubic, u64 zIndex)
|
||||
void mg_push_vertex(mg_canvas_data* canvas, vec2 pos, vec4 cubic, u64 shapeIndex)
|
||||
{
|
||||
mg_vertex_layout* layout = &canvas->backend->vertexLayout;
|
||||
DEBUG_ASSERT(canvas->vertexCount < layout->maxVertexCount);
|
||||
|
||||
u32 offset = canvas->vertexCount;
|
||||
u32 index = canvas->vertexCount;
|
||||
|
||||
*(vec2*)(((char*)layout->posBuffer) + offset*layout->posStride) = pos;
|
||||
*(vec4*)(((char*)layout->cubicBuffer) + offset*layout->cubicStride) = cubic;
|
||||
*(u32*)(((char*)layout->zIndexBuffer) + offset*layout->zIndexStride) = zIndex;
|
||||
*(vec2*)(((char*)layout->posBuffer) + index*layout->posStride) = pos;
|
||||
*(vec4*)(((char*)layout->cubicBuffer) + index*layout->cubicStride) = cubic;
|
||||
*(u32*)(((char*)layout->shapeIndexBuffer) + index*layout->shapeIndexStride) = shapeIndex;
|
||||
|
||||
canvas->vertexCount++;
|
||||
}
|
||||
|
@ -513,11 +513,11 @@ void mg_push_vertex(mg_canvas_data* canvas, vec2 pos, vec4 cubic, u64 zIndex)
|
|||
// Path Filling
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
//NOTE(martin): forward declarations
|
||||
void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_color color);
|
||||
void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 shapeIndex, mg_color color);
|
||||
|
||||
//NOTE(martin): quadratics filling
|
||||
|
||||
void mg_render_fill_quadratic(mg_canvas_data* canvas, vec2 p[3], u32 zIndex, mg_color color)
|
||||
void mg_render_fill_quadratic(mg_canvas_data* canvas, vec2 p[3], u32 shapeIndex, mg_color color)
|
||||
{
|
||||
u32 baseIndex = mg_vertices_base_index(canvas);
|
||||
|
||||
|
@ -526,17 +526,17 @@ void mg_render_fill_quadratic(mg_canvas_data* canvas, vec2 p[3], u32 zIndex, mg_
|
|||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p[0].x, p[0].y}),
|
||||
(vec4){0, 0, 0, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p[1].x, p[1].y}),
|
||||
(vec4){0.5, 0, 0.5, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p[2].x, p[2].y}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
indices[0] = baseIndex + 0;
|
||||
indices[1] = baseIndex + 1;
|
||||
|
@ -545,7 +545,7 @@ void mg_render_fill_quadratic(mg_canvas_data* canvas, vec2 p[3], u32 zIndex, mg_
|
|||
|
||||
//NOTE(martin): cubic filling
|
||||
|
||||
void mg_split_and_fill_cubic(mg_canvas_data* canvas, vec2 p[4], f32 tSplit, u32 zIndex, mg_color color)
|
||||
void mg_split_and_fill_cubic(mg_canvas_data* canvas, vec2 p[4], f32 tSplit, u32 shapeIndex, mg_color color)
|
||||
{
|
||||
int subVertexCount = 0;
|
||||
int subIndexCount = 0;
|
||||
|
@ -580,29 +580,29 @@ void mg_split_and_fill_cubic(mg_canvas_data* canvas, vec2 p[4], f32 tSplit, u32
|
|||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p[0].x, p[0].y}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){split.x, split.y}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p[3].x, p[3].y}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
indices[0] = baseIndex + 0;
|
||||
indices[1] = baseIndex + 1;
|
||||
indices[2] = baseIndex + 2;
|
||||
|
||||
mg_render_fill_cubic(canvas, subPointsLow, zIndex, color);
|
||||
mg_render_fill_cubic(canvas, subPointsHigh, zIndex, color);
|
||||
mg_render_fill_cubic(canvas, subPointsLow, shapeIndex, color);
|
||||
mg_render_fill_cubic(canvas, subPointsHigh, shapeIndex, color);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_color color)
|
||||
void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 shapeIndex, mg_color color)
|
||||
{
|
||||
LOG_DEBUG("graphics render fill cubic\n");
|
||||
|
||||
|
@ -674,7 +674,7 @@ void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_colo
|
|||
{1.5*p[1].x - 0.5*p[0].x, 1.5*p[1].y - 0.5*p[0].y},
|
||||
p[3]};
|
||||
|
||||
mg_render_fill_quadratic(canvas, quadControlPoints, zIndex, color);
|
||||
mg_render_fill_quadratic(canvas, quadControlPoints, shapeIndex, color);
|
||||
return;
|
||||
}
|
||||
else if( (discrFactor2 > 0 && d1 != 0)
|
||||
|
@ -743,13 +743,13 @@ void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_colo
|
|||
if(sd != 0 && td/sd < 0.99 && td/sd > 0.01)
|
||||
{
|
||||
LOG_DEBUG("split curve at first double point\n");
|
||||
mg_split_and_fill_cubic(canvas, p, td/sd, zIndex, color);
|
||||
mg_split_and_fill_cubic(canvas, p, td/sd, shapeIndex, color);
|
||||
return;
|
||||
}
|
||||
if(se != 0 && te/se < 0.99 && te/se > 0.01)
|
||||
{
|
||||
LOG_DEBUG("split curve at second double point\n");
|
||||
mg_split_and_fill_cubic(canvas, p, te/se, zIndex, color);
|
||||
mg_split_and_fill_cubic(canvas, p, te/se, shapeIndex, color);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -959,7 +959,7 @@ void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_colo
|
|||
vec2 pos = mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[i]]);
|
||||
vec4 cubic = testCoords[orderedHullIndices[i]];
|
||||
cubic.w = outsideTest;
|
||||
mg_push_vertex(canvas, pos, cubic, zIndex);
|
||||
mg_push_vertex(canvas, pos, cubic, shapeIndex);
|
||||
|
||||
indices[i] = baseIndex + i;
|
||||
}
|
||||
|
@ -989,32 +989,32 @@ void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_colo
|
|||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[0]]),
|
||||
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[0]]), outsideTest1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[1]]),
|
||||
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[1]]), outsideTest1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[2]]),
|
||||
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[2]]), outsideTest1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[0]]),
|
||||
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[0]]), outsideTest2},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[2]]),
|
||||
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[2]]), outsideTest2},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[3]]),
|
||||
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[3]]), outsideTest2},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
indices[0] = baseIndex + 0;
|
||||
indices[1] = baseIndex + 1;
|
||||
|
@ -1040,7 +1040,7 @@ void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_colo
|
|||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, p[orderedHullIndices[i]]),
|
||||
(vec4){vec4_expand_xyz(testCoords[orderedHullIndices[i]]), outsideTest},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
}
|
||||
|
||||
indices[0] = baseIndex + 0;
|
||||
|
@ -1054,7 +1054,7 @@ void mg_render_fill_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_colo
|
|||
|
||||
//NOTE(martin): global path fill
|
||||
|
||||
void mg_render_fill(mg_canvas_data* canvas, mg_path_elt* elements, mg_path_descriptor* path, u32 zIndex, mg_color color)
|
||||
void mg_render_fill(mg_canvas_data* canvas, mg_path_elt* elements, mg_path_descriptor* path, u32 shapeIndex, mg_color color)
|
||||
{
|
||||
u32 eltCount = path->count;
|
||||
vec2 startPoint = path->startPoint;
|
||||
|
@ -1084,14 +1084,14 @@ void mg_render_fill(mg_canvas_data* canvas, mg_path_elt* elements, mg_path_descr
|
|||
|
||||
case MG_PATH_QUADRATIC:
|
||||
{
|
||||
mg_render_fill_quadratic(canvas, controlPoints, zIndex, color);
|
||||
mg_render_fill_quadratic(canvas, controlPoints, shapeIndex, color);
|
||||
endPoint = controlPoints[2];
|
||||
|
||||
} break;
|
||||
|
||||
case MG_PATH_CUBIC:
|
||||
{
|
||||
mg_render_fill_cubic(canvas, controlPoints, zIndex, color);
|
||||
mg_render_fill_cubic(canvas, controlPoints, shapeIndex, color);
|
||||
endPoint = controlPoints[3];
|
||||
} break;
|
||||
}
|
||||
|
@ -1109,7 +1109,7 @@ void mg_render_fill(mg_canvas_data* canvas, mg_path_elt* elements, mg_path_descr
|
|||
|
||||
for(int i=0; i<3; i++)
|
||||
{
|
||||
mg_push_vertex(canvas, pos[i], cubic, zIndex);
|
||||
mg_push_vertex(canvas, pos[i], cubic, shapeIndex);
|
||||
indices[i] = baseIndex + i;
|
||||
}
|
||||
|
||||
|
@ -1121,7 +1121,7 @@ void mg_render_fill(mg_canvas_data* canvas, mg_path_elt* elements, mg_path_descr
|
|||
// Path Stroking
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
|
||||
void mg_render_stroke_line(mg_canvas_data* canvas, vec2 p[2], u32 zIndex, mg_attributes* attributes)
|
||||
void mg_render_stroke_line(mg_canvas_data* canvas, vec2 p[2], u32 shapeIndex, mg_attributes* attributes)
|
||||
{
|
||||
//NOTE(martin): get normals multiplied by halfWidth
|
||||
f32 halfW = attributes->width/2;
|
||||
|
@ -1141,22 +1141,22 @@ void mg_render_stroke_line(mg_canvas_data* canvas, vec2 p[2], u32 zIndex, mg_att
|
|||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p[0].x + n0.x, p[0].y + n0.y}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p[1].x + n0.x, p[1].y + n0.y}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p[1].x - n0.x, p[1].y - n0.y}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p[0].x - n0.x, p[0].y - n0.y}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
indices[0] = baseIndex;
|
||||
indices[1] = baseIndex + 1;
|
||||
|
@ -1282,7 +1282,7 @@ void mg_quadratic_split(vec2 p[3], f32 t, vec2 outLeft[3], vec2 outRight[3])
|
|||
}
|
||||
|
||||
|
||||
void mg_render_stroke_quadratic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_attributes* attributes)
|
||||
void mg_render_stroke_quadratic(mg_canvas_data* canvas, vec2 p[4], u32 shapeIndex, mg_attributes* attributes)
|
||||
{
|
||||
#define CHECK_SAMPLE_COUNT 5
|
||||
f32 checkSamples[CHECK_SAMPLE_COUNT] = {1./6, 2./6, 3./6, 4./6, 5./6};
|
||||
|
@ -1336,17 +1336,17 @@ void mg_render_stroke_quadratic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, m
|
|||
vec2 splitLeft[3];
|
||||
vec2 splitRight[3];
|
||||
mg_quadratic_split(p, maxOvershootParameter, splitLeft, splitRight);
|
||||
mg_render_stroke_quadratic(canvas, splitLeft, zIndex, attributes);
|
||||
mg_render_stroke_quadratic(canvas, splitRight, zIndex, attributes);
|
||||
mg_render_stroke_quadratic(canvas, splitLeft, shapeIndex, attributes);
|
||||
mg_render_stroke_quadratic(canvas, splitRight, shapeIndex, attributes);
|
||||
}
|
||||
else
|
||||
{
|
||||
//NOTE(martin): push the actual fill commands for the offset contour
|
||||
|
||||
u32 zIndex = mg_next_shape(canvas, attributes->color);
|
||||
u32 shapeIndex = mg_next_shape(canvas, attributes->color);
|
||||
|
||||
mg_render_fill_quadratic(canvas, positiveOffsetHull, zIndex, attributes->color);
|
||||
mg_render_fill_quadratic(canvas, negativeOffsetHull, zIndex, attributes->color);
|
||||
mg_render_fill_quadratic(canvas, positiveOffsetHull, shapeIndex, attributes->color);
|
||||
mg_render_fill_quadratic(canvas, negativeOffsetHull, shapeIndex, attributes->color);
|
||||
|
||||
//NOTE(martin): add base triangles
|
||||
u32 baseIndex = mg_vertices_base_index(canvas);
|
||||
|
@ -1355,22 +1355,22 @@ void mg_render_stroke_quadratic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, m
|
|||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, positiveOffsetHull[0]),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, positiveOffsetHull[2]),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, negativeOffsetHull[2]),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, negativeOffsetHull[0]),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
indices[0] = baseIndex + 0;
|
||||
indices[1] = baseIndex + 1;
|
||||
|
@ -1436,7 +1436,7 @@ void mg_cubic_split(vec2 p[4], f32 t, vec2 outLeft[4], vec2 outRight[4])
|
|||
outRight[3] = p[3];
|
||||
}
|
||||
|
||||
void mg_render_stroke_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_attributes* attributes)
|
||||
void mg_render_stroke_cubic(mg_canvas_data* canvas, vec2 p[4], u32 shapeIndex, mg_attributes* attributes)
|
||||
{
|
||||
#define CHECK_SAMPLE_COUNT 5
|
||||
f32 checkSamples[CHECK_SAMPLE_COUNT] = {1./6, 2./6, 3./6, 4./6, 5./6};
|
||||
|
@ -1490,18 +1490,18 @@ void mg_render_stroke_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_at
|
|||
vec2 splitLeft[4];
|
||||
vec2 splitRight[4];
|
||||
mg_cubic_split(p, maxOvershootParameter, splitLeft, splitRight);
|
||||
mg_render_stroke_cubic(canvas, splitLeft, zIndex, attributes);
|
||||
mg_render_stroke_cubic(canvas, splitRight, zIndex, attributes);
|
||||
mg_render_stroke_cubic(canvas, splitLeft, shapeIndex, attributes);
|
||||
mg_render_stroke_cubic(canvas, splitRight, shapeIndex, attributes);
|
||||
|
||||
//TODO: render joint between the split curves
|
||||
}
|
||||
else
|
||||
{
|
||||
//NOTE(martin): push the actual fill commands for the offset contour
|
||||
u32 zIndex = mg_next_shape(canvas, attributes->color);
|
||||
u32 shapeIndex = mg_next_shape(canvas, attributes->color);
|
||||
|
||||
mg_render_fill_cubic(canvas, positiveOffsetHull, zIndex, attributes->color);
|
||||
mg_render_fill_cubic(canvas, negativeOffsetHull, zIndex, attributes->color);
|
||||
mg_render_fill_cubic(canvas, positiveOffsetHull, shapeIndex, attributes->color);
|
||||
mg_render_fill_cubic(canvas, negativeOffsetHull, shapeIndex, attributes->color);
|
||||
|
||||
//NOTE(martin): add base triangles
|
||||
u32 baseIndex = mg_vertices_base_index(canvas);
|
||||
|
@ -1511,22 +1511,22 @@ void mg_render_stroke_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_at
|
|||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, positiveOffsetHull[0]),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, positiveOffsetHull[3]),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, negativeOffsetHull[3]),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, negativeOffsetHull[0]),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
indices[0] = baseIndex + 0;
|
||||
indices[1] = baseIndex + 1;
|
||||
|
@ -1551,7 +1551,7 @@ void mg_stroke_cap(mg_canvas_data* canvas, vec2 p0, vec2 direction, mg_attribute
|
|||
vec2 m0 = {alpha*direction.x,
|
||||
alpha*direction.y};
|
||||
|
||||
u32 zIndex = mg_next_shape(canvas, attributes->color);
|
||||
u32 shapeIndex = mg_next_shape(canvas, attributes->color);
|
||||
|
||||
u32 baseIndex = mg_vertices_base_index(canvas);
|
||||
i32* indices = mg_reserve_indices(canvas, 6);
|
||||
|
@ -1559,22 +1559,22 @@ void mg_stroke_cap(mg_canvas_data* canvas, vec2 p0, vec2 direction, mg_attribute
|
|||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p0.x + n0.x, p0.y + n0.y}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p0.x + n0.x + m0.x, p0.y + n0.y + m0.y}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p0.x - n0.x + m0.x, p0.y - n0.y + m0.y}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p0.x - n0.x, p0.y - n0.y}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
indices[0] = baseIndex;
|
||||
indices[1] = baseIndex + 1;
|
||||
|
@ -1613,7 +1613,7 @@ void mg_stroke_joint(mg_canvas_data* canvas,
|
|||
n1.y *= -1;
|
||||
}
|
||||
|
||||
u32 zIndex = mg_next_shape(canvas, attributes->color);
|
||||
u32 shapeIndex = mg_next_shape(canvas, attributes->color);
|
||||
|
||||
//NOTE(martin): use the same code as hull offset to find mitter point...
|
||||
/*NOTE(martin): let vector u = (n0+n1) and vector v = pIntersect - p1
|
||||
|
@ -1639,22 +1639,22 @@ void mg_stroke_joint(mg_canvas_data* canvas,
|
|||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, p0),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p0.x + n0.x*halfW, p0.y + n0.y*halfW}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, mitterPoint),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p0.x + n1.x*halfW, p0.y + n1.y*halfW}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
indices[0] = baseIndex;
|
||||
indices[1] = baseIndex + 1;
|
||||
|
@ -1672,17 +1672,17 @@ void mg_stroke_joint(mg_canvas_data* canvas,
|
|||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, p0),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p0.x + n0.x*halfW, p0.y + n0.y*halfW}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
mg_push_vertex(canvas,
|
||||
mg_mat2x3_mul(canvas->transform, (vec2){p0.x + n1.x*halfW, p0.y + n1.y*halfW}),
|
||||
(vec4){1, 1, 1, 1},
|
||||
zIndex);
|
||||
shapeIndex);
|
||||
|
||||
DEBUG_ASSERT(!isnan(n0.x) && !isnan(n0.y) && !isnan(n1.x) && !isnan(n1.y));
|
||||
|
||||
|
@ -1702,22 +1702,22 @@ void mg_render_stroke_element(mg_canvas_data* canvas,
|
|||
{
|
||||
vec2 controlPoints[4] = {currentPoint, element->p[0], element->p[1], element->p[2]};
|
||||
int endPointIndex = 0;
|
||||
u32 zIndex = mg_next_shape(canvas, attributes->color);
|
||||
u32 shapeIndex = mg_next_shape(canvas, attributes->color);
|
||||
|
||||
switch(element->type)
|
||||
{
|
||||
case MG_PATH_LINE:
|
||||
mg_render_stroke_line(canvas, controlPoints, zIndex, attributes);
|
||||
mg_render_stroke_line(canvas, controlPoints, shapeIndex, attributes);
|
||||
endPointIndex = 1;
|
||||
break;
|
||||
|
||||
case MG_PATH_QUADRATIC:
|
||||
mg_render_stroke_quadratic(canvas, controlPoints, zIndex, attributes);
|
||||
mg_render_stroke_quadratic(canvas, controlPoints, shapeIndex, attributes);
|
||||
endPointIndex = 2;
|
||||
break;
|
||||
|
||||
case MG_PATH_CUBIC:
|
||||
mg_render_stroke_cubic(canvas, controlPoints, zIndex, attributes);
|
||||
mg_render_stroke_cubic(canvas, controlPoints, shapeIndex, attributes);
|
||||
endPointIndex = 3;
|
||||
break;
|
||||
|
||||
|
@ -1835,7 +1835,7 @@ void mg_render_rectangle_fill(mg_canvas_data* canvas, mp_rect rect, mg_attribute
|
|||
u32 baseIndex = mg_vertices_base_index(canvas);
|
||||
i32* indices = mg_reserve_indices(canvas, 6);
|
||||
|
||||
u32 zIndex = mg_next_shape(canvas, attributes->color);
|
||||
u32 shapeIndex = mg_next_shape(canvas, attributes->color);
|
||||
|
||||
vec2 points[4] = {{rect.x, rect.y},
|
||||
{rect.x + rect.w, rect.y},
|
||||
|
@ -1846,7 +1846,7 @@ void mg_render_rectangle_fill(mg_canvas_data* canvas, mp_rect rect, mg_attribute
|
|||
for(int i=0; i<4; i++)
|
||||
{
|
||||
vec2 pos = mg_mat2x3_mul(canvas->transform, points[i]);
|
||||
mg_push_vertex(canvas, pos, cubic, zIndex);
|
||||
mg_push_vertex(canvas, pos, cubic, shapeIndex);
|
||||
}
|
||||
indices[0] = baseIndex + 0;
|
||||
indices[1] = baseIndex + 1;
|
||||
|
@ -1858,11 +1858,11 @@ void mg_render_rectangle_fill(mg_canvas_data* canvas, mp_rect rect, mg_attribute
|
|||
|
||||
void mg_render_rectangle_stroke(mg_canvas_data* canvas, mp_rect rect, mg_attributes* attributes)
|
||||
{
|
||||
//NOTE(martin): stroke a rectangle by fill two scaled rectangles with the same zIndex.
|
||||
//NOTE(martin): stroke a rectangle by fill two scaled rectangles with the same shapeIndex.
|
||||
u32 baseIndex = mg_vertices_base_index(canvas);
|
||||
i32* indices = mg_reserve_indices(canvas, 12);
|
||||
|
||||
u32 zIndex = mg_next_shape(canvas, attributes->color);
|
||||
u32 shapeIndex = mg_next_shape(canvas, attributes->color);
|
||||
|
||||
//NOTE(martin): limit stroke width to the minimum dimension of the rectangle
|
||||
f32 width = minimum(attributes->width, minimum(rect.w, rect.h));
|
||||
|
@ -1882,13 +1882,13 @@ void mg_render_rectangle_stroke(mg_canvas_data* canvas, mp_rect rect, mg_attribu
|
|||
for(int i=0; i<4; i++)
|
||||
{
|
||||
vec2 pos = mg_mat2x3_mul(canvas->transform, outerPoints[i]);
|
||||
mg_push_vertex(canvas, pos, cubic, zIndex);
|
||||
mg_push_vertex(canvas, pos, cubic, shapeIndex);
|
||||
}
|
||||
|
||||
for(int i=0; i<4; i++)
|
||||
{
|
||||
vec2 pos = mg_mat2x3_mul(canvas->transform, innerPoints[i]);
|
||||
mg_push_vertex(canvas, pos, cubic, zIndex);
|
||||
mg_push_vertex(canvas, pos, cubic, shapeIndex);
|
||||
}
|
||||
|
||||
indices[0] = baseIndex + 0;
|
||||
|
@ -1905,7 +1905,7 @@ void mg_render_rectangle_stroke(mg_canvas_data* canvas, mp_rect rect, mg_attribu
|
|||
indices[11] = baseIndex + 7;
|
||||
}
|
||||
|
||||
void mg_render_fill_arc_corner(mg_canvas_data* canvas, f32 x, f32 y, f32 rx, f32 ry, u32 zIndex, mg_color color)
|
||||
void mg_render_fill_arc_corner(mg_canvas_data* canvas, f32 x, f32 y, f32 rx, f32 ry, u32 shapeIndex, mg_color color)
|
||||
{
|
||||
//NOTE(martin): draw a precomputed arc corner, using a bezier approximation
|
||||
u32 baseIndex = mg_vertices_base_index(canvas);
|
||||
|
@ -1927,7 +1927,7 @@ void mg_render_fill_arc_corner(mg_canvas_data* canvas, f32 x, f32 y, f32 rx, f32
|
|||
for(int i=0; i<4; i++)
|
||||
{
|
||||
vec2 pos = mg_mat2x3_mul(canvas->transform, points[i]);
|
||||
mg_push_vertex(canvas, pos, cubics[i], zIndex);
|
||||
mg_push_vertex(canvas, pos, cubics[i], shapeIndex);
|
||||
}
|
||||
indices[0] = baseIndex + 0;
|
||||
indices[1] = baseIndex + 1;
|
||||
|
@ -1940,7 +1940,7 @@ void mg_render_fill_arc_corner(mg_canvas_data* canvas, f32 x, f32 y, f32 rx, f32
|
|||
void mg_render_rounded_rectangle_fill_with_z_index(mg_canvas_data* canvas,
|
||||
mg_rounded_rect rect,
|
||||
mg_attributes* attributes,
|
||||
u32 zIndex)
|
||||
u32 shapeIndex)
|
||||
{
|
||||
//NOTE(martin): draw a rounded rectangle by drawing a normal rectangle and 4 corners,
|
||||
// approximating an arc by a precomputed bezier curve
|
||||
|
@ -1963,7 +1963,7 @@ void mg_render_rounded_rectangle_fill_with_z_index(mg_canvas_data* canvas,
|
|||
for(int i=0; i<8; i++)
|
||||
{
|
||||
vec2 pos = mg_mat2x3_mul(canvas->transform, points[i]);
|
||||
mg_push_vertex(canvas, pos, cubic, zIndex);
|
||||
mg_push_vertex(canvas, pos, cubic, shapeIndex);
|
||||
}
|
||||
|
||||
static const i32 fanIndices[18] = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7 }; // inner fan
|
||||
|
@ -1972,10 +1972,10 @@ void mg_render_rounded_rectangle_fill_with_z_index(mg_canvas_data* canvas,
|
|||
indices[i] = fanIndices[i] + baseIndex;
|
||||
}
|
||||
|
||||
mg_render_fill_arc_corner(canvas, rect.x, rect.y, rect.r, rect.r, zIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y, -rect.r, rect.r, zIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y + rect.h, -rect.r, -rect.r, zIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x, rect.y + rect.h, rect.r, -rect.r, zIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x, rect.y, rect.r, rect.r, shapeIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y, -rect.r, rect.r, shapeIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y + rect.h, -rect.r, -rect.r, shapeIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x, rect.y + rect.h, rect.r, -rect.r, shapeIndex, attributes->color);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1983,30 +1983,30 @@ void mg_render_rounded_rectangle_fill(mg_canvas_data* canvas,
|
|||
mg_rounded_rect rect,
|
||||
mg_attributes* attributes)
|
||||
{
|
||||
u32 zIndex = mg_next_shape(canvas, attributes->color);
|
||||
mg_render_rounded_rectangle_fill_with_z_index(canvas, rect, attributes, zIndex);
|
||||
u32 shapeIndex = mg_next_shape(canvas, attributes->color);
|
||||
mg_render_rounded_rectangle_fill_with_z_index(canvas, rect, attributes, shapeIndex);
|
||||
}
|
||||
|
||||
void mg_render_rounded_rectangle_stroke(mg_canvas_data* canvas,
|
||||
mg_rounded_rect rect,
|
||||
mg_attributes* attributes)
|
||||
{
|
||||
//NOTE(martin): stroke rounded rectangle by filling two scaled rounded rectangles with the same zIndex
|
||||
//NOTE(martin): stroke rounded rectangle by filling two scaled rounded rectangles with the same shapeIndex
|
||||
f32 width = minimum(attributes->width, minimum(rect.w, rect.h));
|
||||
f32 halfW = width/2;
|
||||
|
||||
mg_rounded_rect inner = {rect.x + halfW, rect.y + halfW, rect.w - width, rect.h - width, rect.r - halfW};
|
||||
mg_rounded_rect outer = {rect.x - halfW, rect.y - halfW, rect.w + width, rect.h + width, rect.r + halfW};
|
||||
|
||||
u32 zIndex = mg_next_shape(canvas, attributes->color);
|
||||
mg_render_rounded_rectangle_fill_with_z_index(canvas, outer, attributes, zIndex);
|
||||
mg_render_rounded_rectangle_fill_with_z_index(canvas, inner, attributes, zIndex);
|
||||
u32 shapeIndex = mg_next_shape(canvas, attributes->color);
|
||||
mg_render_rounded_rectangle_fill_with_z_index(canvas, outer, attributes, shapeIndex);
|
||||
mg_render_rounded_rectangle_fill_with_z_index(canvas, inner, attributes, shapeIndex);
|
||||
}
|
||||
|
||||
void mg_render_ellipse_fill_with_z_index(mg_canvas_data* canvas,
|
||||
mp_rect rect,
|
||||
mg_attributes* attributes,
|
||||
u32 zIndex)
|
||||
u32 shapeIndex)
|
||||
{
|
||||
//NOTE(martin): draw a filled ellipse by drawing a diamond and 4 corners,
|
||||
// approximating an arc by a precomputed bezier curve
|
||||
|
@ -2027,7 +2027,7 @@ void mg_render_ellipse_fill_with_z_index(mg_canvas_data* canvas,
|
|||
for(int i=0; i<4; i++)
|
||||
{
|
||||
vec2 pos = mg_mat2x3_mul(canvas->transform, points[i]);
|
||||
mg_push_vertex(canvas, pos, cubic, zIndex);
|
||||
mg_push_vertex(canvas, pos, cubic, shapeIndex);
|
||||
}
|
||||
|
||||
indices[0] = baseIndex + 0;
|
||||
|
@ -2037,30 +2037,30 @@ void mg_render_ellipse_fill_with_z_index(mg_canvas_data* canvas,
|
|||
indices[4] = baseIndex + 2;
|
||||
indices[5] = baseIndex + 3;
|
||||
|
||||
mg_render_fill_arc_corner(canvas, rect.x, rect.y, rx, ry, zIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y, -rx, ry, zIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y + rect.h, -rx, -ry, zIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x, rect.y + rect.h, rx, -ry, zIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x, rect.y, rx, ry, shapeIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y, -rx, ry, shapeIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x + rect.w, rect.y + rect.h, -rx, -ry, shapeIndex, attributes->color);
|
||||
mg_render_fill_arc_corner(canvas, rect.x, rect.y + rect.h, rx, -ry, shapeIndex, attributes->color);
|
||||
}
|
||||
|
||||
void mg_render_ellipse_fill(mg_canvas_data* canvas, mp_rect rect, mg_attributes* attributes)
|
||||
{
|
||||
u32 zIndex = mg_next_shape(canvas, attributes->color);
|
||||
mg_render_ellipse_fill_with_z_index(canvas, rect, attributes, zIndex);
|
||||
u32 shapeIndex = mg_next_shape(canvas, attributes->color);
|
||||
mg_render_ellipse_fill_with_z_index(canvas, rect, attributes, shapeIndex);
|
||||
}
|
||||
|
||||
void mg_render_ellipse_stroke(mg_canvas_data* canvas, mp_rect rect, mg_attributes* attributes)
|
||||
{
|
||||
//NOTE(martin): stroke by filling two scaled ellipsis with the same zIndex
|
||||
//NOTE(martin): stroke by filling two scaled ellipsis with the same shapeIndex
|
||||
f32 width = minimum(attributes->width, minimum(rect.w, rect.h));
|
||||
f32 halfW = width/2;
|
||||
|
||||
mp_rect inner = {rect.x + halfW, rect.y + halfW, rect.w - width, rect.h - width};
|
||||
mp_rect outer = {rect.x - halfW, rect.y - halfW, rect.w + width, rect.h + width};
|
||||
|
||||
u32 zIndex = mg_next_shape(canvas, attributes->color);
|
||||
mg_render_ellipse_fill_with_z_index(canvas, outer, attributes, zIndex);
|
||||
mg_render_ellipse_fill_with_z_index(canvas, inner, attributes, zIndex);
|
||||
u32 shapeIndex = mg_next_shape(canvas, attributes->color);
|
||||
mg_render_ellipse_fill_with_z_index(canvas, outer, attributes, shapeIndex);
|
||||
mg_render_ellipse_fill_with_z_index(canvas, inner, attributes, shapeIndex);
|
||||
}
|
||||
|
||||
void mg_render_image(mg_canvas_data* canvas, mg_image image, mp_rect rect)
|
||||
|
@ -2076,7 +2076,7 @@ void mg_render_image(mg_canvas_data* canvas, mg_image image, mp_rect rect)
|
|||
u32 baseIndex = mg_vertices_base_index(canvas);
|
||||
i32* indices = mg_reserve_indices(canvas, 6);
|
||||
|
||||
u32 zIndex = mg_next_shape(canvas, attributes->color);
|
||||
u32 shapeIndex = mg_next_shape(canvas, attributes->color);
|
||||
|
||||
vec2 points[4] = {{rect.x, rect.y},
|
||||
{rect.x + rect.w, rect.y},
|
||||
|
@ -2096,7 +2096,7 @@ void mg_render_image(mg_canvas_data* canvas, mg_image image, mp_rect rect)
|
|||
vec2 transformedUV = {uv[i].x / MG_ATLAS_SIZE, uv[i].y / MG_ATLAS_SIZE};
|
||||
|
||||
vec2 pos = mg_mat2x3_mul(canvas->transform, points[i]);
|
||||
mg_push_textured_vertex(canvas, pos, cubic, transformedUV, color, zIndex);
|
||||
mg_push_textured_vertex(canvas, pos, cubic, transformedUV, color, shapeIndex);
|
||||
}
|
||||
indices[0] = baseIndex + 0;
|
||||
indices[1] = baseIndex + 1;
|
||||
|
@ -2660,7 +2660,7 @@ mg_canvas mg_canvas_create(mg_surface surface)
|
|||
canvasData->primitiveCount = 0;
|
||||
canvasData->path.startIndex = 0;
|
||||
canvasData->path.count = 0;
|
||||
canvasData->nextZIndex = 1;
|
||||
canvasData->nextShapeIndex = 1;
|
||||
canvasData->attributes.color = (mg_color){0, 0, 0, 1};
|
||||
canvasData->attributes.tolerance = 1;
|
||||
canvasData->attributes.width = 10;
|
||||
|
@ -2824,9 +2824,9 @@ void mg_flush_batch(mg_canvas_data* canvas)
|
|||
{
|
||||
if(canvas->backend && canvas->backend->drawBatch)
|
||||
{
|
||||
canvas->backend->drawBatch(canvas->backend, canvas->nextZIndex, canvas->vertexCount, canvas->indexCount);
|
||||
canvas->backend->drawBatch(canvas->backend, canvas->nextShapeIndex, canvas->vertexCount, canvas->indexCount);
|
||||
}
|
||||
mg_reset_z_index(canvas);
|
||||
mg_reset_shape_index(canvas);
|
||||
canvas->vertexCount = 0;
|
||||
canvas->indexCount = 0;
|
||||
}
|
||||
|
@ -2843,7 +2843,7 @@ void mg_flush_commands(int primitiveCount, mg_primitive* primitives, mg_path_elt
|
|||
|
||||
u32 nextIndex = 0;
|
||||
|
||||
mg_reset_z_index(canvas);
|
||||
mg_reset_shape_index(canvas);
|
||||
canvas->transform = (mg_mat2x3){1, 0, 0,
|
||||
0, 1, 0};
|
||||
canvas->clip = (mp_rect){-FLT_MAX/2, -FLT_MAX/2, FLT_MAX, FLT_MAX};
|
||||
|
@ -2881,11 +2881,11 @@ void mg_flush_commands(int primitiveCount, mg_primitive* primitives, mg_path_elt
|
|||
|
||||
case MG_CMD_FILL:
|
||||
{
|
||||
u32 zIndex = mg_next_shape(canvas, primitive->attributes.color);
|
||||
u32 shapeIndex = mg_next_shape(canvas, primitive->attributes.color);
|
||||
mg_render_fill(canvas,
|
||||
pathElements + primitive->path.startIndex,
|
||||
&primitive->path,
|
||||
zIndex,
|
||||
shapeIndex,
|
||||
primitive->attributes.color);
|
||||
} break;
|
||||
|
||||
|
|
|
@ -212,8 +212,8 @@ typedef struct mg_vertex_layout
|
|||
char* colorBuffer;
|
||||
u32 colorStride;
|
||||
|
||||
char* zIndexBuffer;
|
||||
u32 zIndexStride;
|
||||
char* shapeIndexBuffer;
|
||||
u32 shapeIndexStride;
|
||||
|
||||
char* clipBuffer;
|
||||
u32 clipStride;
|
||||
|
@ -268,7 +268,7 @@ typedef struct mg_canvas_data
|
|||
mp_rect clipStack[MG_CLIP_STACK_MAX_DEPTH];
|
||||
u32 clipStackSize;
|
||||
|
||||
u32 nextZIndex;
|
||||
u32 nextShapeIndex;
|
||||
u32 primitiveCount;
|
||||
mg_primitive primitives[MG_MAX_PRIMITIVE_COUNT];
|
||||
|
||||
|
|
20
todo.txt
20
todo.txt
|
@ -2,7 +2,7 @@
|
|||
Overview
|
||||
--------
|
||||
[x] Pan/Zoom on text example
|
||||
[ ] Clean+Fixes of canvas code and examples
|
||||
[.] Clean+Fixes of canvas code and examples
|
||||
[ ] Make backend selection easier
|
||||
|
||||
[ ] Image API and backend
|
||||
|
@ -10,7 +10,7 @@ Overview
|
|||
[ ] Baked fonts?
|
||||
|
||||
[ ] Allow different versions of GL to co-exist
|
||||
[ ] Backport canvas to GLES
|
||||
[?] Backport canvas to GLES
|
||||
|
||||
[ ] Delegated drawing API+Impl
|
||||
|
||||
|
@ -18,16 +18,24 @@ Clean+Fixes
|
|||
-----------
|
||||
[ ] Clean canvas code
|
||||
[ ] make zIndex implicit when calling push_vertex
|
||||
[ ] rename zIndex with "shapeIndex" everywhere
|
||||
[x] rename zIndex with "shapeIndex" everywhere
|
||||
[ ] remove color args in functions that don't need it anymore
|
||||
|
||||
[ ] Clean shaders (folder/filenames, version string, debug flags, ...)
|
||||
[ ] Rename MG_GL_CANVAS_TILE_ARRAY_SIZE/LENGTH unambiguously and make it consistent between C and glsl code
|
||||
|
||||
[x] Fix resource loading path in examples (to load font relative to executable)
|
||||
[.] Clean shaders (folder/filenames, version string, debug flags, ...)
|
||||
[x] Simplify shader names, prefix embedded strings by "glsl_"
|
||||
[x] Extract shader compilation in a function
|
||||
[x] Add version strings/common structs in canvas code (maybe revisit later when we have multiple versions, but ok for now)
|
||||
[!] Check return of compilation and decide how to handle error more cleanly
|
||||
|
||||
[!] Clean-up context on error and set error flags in handle
|
||||
|
||||
[ ] Make surface backend and canvas backend compile-time and run-time selections easier
|
||||
[ ] GL loader: allow using different GL versions (eg using a desktop GL surface and a GLES surface in the same app).
|
||||
[ ] Clean up surface backend and canvas backend compile-time and run-time selections
|
||||
|
||||
Bug hunt
|
||||
--------
|
||||
[!] Investigate artifact when shifting positions of vertices by (0.5, 0.5) before multiplying
|
||||
by subpixel precision and truncating... -> ie sampling at the middle of pixels vs at integer coordinates...
|
||||
> seems to happen on tile boundaries
|
||||
|
|
Loading…
Reference in New Issue