[wip, canvas, gl] implementing basic image API

This commit is contained in:
martinfouilleul 2023-02-27 19:25:41 +01:00
parent 5e5f8ac5e7
commit 8f834fa1a5
8 changed files with 127 additions and 21 deletions

View File

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

View File

@ -95,7 +95,7 @@ int main()
mg_matrix_pop(); mg_matrix_pop();
mg_image_draw(image2, (mp_rect){300, 200, 300, 300}); mg_image_draw(image, (mp_rect){300, 200, 300, 300});
mg_flush(); mg_flush();
mg_surface_present(surface); mg_surface_present(surface);

View File

@ -39,6 +39,13 @@ typedef struct mg_gl_canvas_backend
} mg_gl_canvas_backend; } mg_gl_canvas_backend;
typedef struct mg_gl_image
{
mg_image_data interface;
GLuint textureID;
} mg_gl_image;
//NOTE: debugger //NOTE: debugger
typedef struct debug_vertex typedef struct debug_vertex
{ {
@ -66,6 +73,8 @@ enum {
LAYOUT_VEC4_ALIGN = 16, LAYOUT_VEC4_ALIGN = 16,
LAYOUT_INT_SIZE = 4, LAYOUT_INT_SIZE = 4,
LAYOUT_INT_ALIGN = 4, LAYOUT_INT_ALIGN = 4,
LAYOUT_MAT2x3_SIZE = sizeof(float)*6,
LAYOUT_MAT2x3_ALIGN = 4,
LAYOUT_CUBIC_OFFSET = 0, LAYOUT_CUBIC_OFFSET = 0,
LAYOUT_POS_OFFSET = LayoutNext(CUBIC, VEC4, VEC2), LAYOUT_POS_OFFSET = LayoutNext(CUBIC, VEC4, VEC2),
@ -75,9 +84,9 @@ enum {
LAYOUT_COLOR_OFFSET = 0, LAYOUT_COLOR_OFFSET = 0,
LAYOUT_CLIP_OFFSET = LayoutNext(COLOR, VEC4, VEC4), LAYOUT_CLIP_OFFSET = LayoutNext(COLOR, VEC4, VEC4),
LAYOUT_UV_OFFSET = LayoutNext(CLIP, VEC4, VEC2), LAYOUT_UV_TRANSFORM_OFFSET = LayoutNext(CLIP, VEC4, MAT2x3),
LAYOUT_SHAPE_ALIGN = 16, LAYOUT_SHAPE_ALIGN = 16,
LAYOUT_SHAPE_SIZE = LayoutNext(UV, VEC2, SHAPE), LAYOUT_SHAPE_SIZE = LayoutNext(UV_TRANSFORM, MAT2x3, SHAPE),
MG_GL_CANVAS_MAX_BUFFER_LENGTH = 1<<20, MG_GL_CANVAS_MAX_BUFFER_LENGTH = 1<<20,
MG_GL_CANVAS_MAX_SHAPE_BUFFER_SIZE = LAYOUT_SHAPE_SIZE * MG_GL_CANVAS_MAX_BUFFER_LENGTH, MG_GL_CANVAS_MAX_SHAPE_BUFFER_SIZE = LAYOUT_SHAPE_SIZE * MG_GL_CANVAS_MAX_BUFFER_LENGTH,
@ -108,8 +117,8 @@ void mg_gl_canvas_update_vertex_layout(mg_gl_canvas_backend* backend)
.colorStride = LAYOUT_SHAPE_SIZE, .colorStride = LAYOUT_SHAPE_SIZE,
.clipBuffer = backend->shapeMapping + LAYOUT_CLIP_OFFSET, .clipBuffer = backend->shapeMapping + LAYOUT_CLIP_OFFSET,
.clipStride = LAYOUT_SHAPE_SIZE, .clipStride = LAYOUT_SHAPE_SIZE,
.uvBuffer = backend->shapeMapping + LAYOUT_UV_OFFSET, .uvTransformBuffer = backend->shapeMapping + LAYOUT_UV_TRANSFORM_OFFSET,
.uvStride = LAYOUT_SHAPE_SIZE, .uvTransformStride = LAYOUT_SHAPE_SIZE,
.indexBuffer = backend->indexMapping, .indexBuffer = backend->indexMapping,
.indexStride = LAYOUT_INT_SIZE}; .indexStride = LAYOUT_INT_SIZE};
@ -147,7 +156,7 @@ void mg_gl_canvas_clear(mg_canvas_backend* interface, mg_color clearColor)
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
} }
void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 shapeCount, u32 vertexCount, u32 indexCount) void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* imageInterface, u32 shapeCount, u32 vertexCount, u32 indexCount)
{ {
mg_gl_canvas_backend* backend = (mg_gl_canvas_backend*)interface; mg_gl_canvas_backend* backend = (mg_gl_canvas_backend*)interface;
@ -213,6 +222,19 @@ void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, u32 shapeCount, u32 v
glUniform1ui(3, tileArrayLength); glUniform1ui(3, tileArrayLength);
glUniform2f(4, contentsScaling.x, contentsScaling.y); glUniform2f(4, contentsScaling.x, contentsScaling.y);
if(imageInterface)
{
//TODO: make sure this image belongs to that context
mg_gl_image* image = (mg_gl_image*)imageInterface;
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, image->textureID);
glUniform1ui(5, 1);
}
else
{
glUniform1ui(5, 0);
}
glDispatchCompute(tileCountX, tileCountY, 1); glDispatchCompute(tileCountX, tileCountY, 1);
//NOTE: now blit out texture to surface //NOTE: now blit out texture to surface
@ -248,9 +270,41 @@ void mg_gl_canvas_destroy(mg_canvas_backend* interface)
free(backend); free(backend);
} }
void mg_gl_canvas_atlas_upload(mg_canvas_backend* interface, mp_rect rect, u8* bytes) mg_image_data* mg_gl_canvas_image_create(mg_canvas_backend* interface, vec2 size)
{ {
//TODO mg_gl_image* image = 0;
image = malloc_type(mg_gl_image);
if(image)
{
glGenTextures(1, &image->textureID);
glBindTexture(GL_TEXTURE_2D, image->textureID);
// glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, size.x, size.y);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
image->interface.size = size;
}
return((mg_image_data*)image);
}
void mg_gl_canvas_image_destroy(mg_canvas_backend* interface, mg_image_data* imageInterface)
{
//TODO: check that this image belongs to this context
mg_gl_image* image = (mg_gl_image*)imageInterface;
glDeleteTextures(1, &image->textureID);
free(image);
}
void mg_gl_canvas_image_upload_region(mg_canvas_backend* interface,
mg_image_data* imageInterface,
mp_rect region,
u8* pixels)
{
//TODO: check that this image belongs to this context
mg_gl_image* image = (mg_gl_image*)imageInterface;
glBindTexture(GL_TEXTURE_2D, image->textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, region.w, region.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
} }
static int mg_gl_compile_shader(const char* name, GLuint shader, const char* source) static int mg_gl_compile_shader(const char* name, GLuint shader, const char* source)
@ -375,7 +429,9 @@ mg_canvas_backend* mg_gl_canvas_create(mg_surface surface)
backend->interface.end = mg_gl_canvas_end; backend->interface.end = mg_gl_canvas_end;
backend->interface.clear = mg_gl_canvas_clear; backend->interface.clear = mg_gl_canvas_clear;
backend->interface.drawBatch = mg_gl_canvas_draw_batch; backend->interface.drawBatch = mg_gl_canvas_draw_batch;
backend->interface.atlasUpload = mg_gl_canvas_atlas_upload; backend->interface.imageCreate = mg_gl_canvas_image_create;
backend->interface.imageDestroy = mg_gl_canvas_image_destroy;
backend->interface.imageUploadRegion = mg_gl_canvas_image_upload_region;
mg_surface_prepare(surface); mg_surface_prepare(surface);

View File

@ -2,7 +2,7 @@
* *
* file: glsl_shaders.h * file: glsl_shaders.h
* note: string literals auto-generated by embed_text.py * note: string literals auto-generated by embed_text.py
* date: 22/022023 * date: 27/022023
* *
**********************************************************************/ **********************************************************************/
#ifndef __GLSL_SHADERS_H__ #ifndef __GLSL_SHADERS_H__
@ -23,7 +23,7 @@ const char* glsl_common =
"struct shape {\n" "struct shape {\n"
" vec4 color;\n" " vec4 color;\n"
" vec4 clip;\n" " vec4 clip;\n"
" vec2 uv;\n" " float uvTransform[6];\n"
"};\n"; "};\n";
//NOTE: string imported from src\glsl_shaders\blit_vertex.glsl //NOTE: string imported from src\glsl_shaders\blit_vertex.glsl
@ -253,9 +253,13 @@ const char* glsl_draw =
"layout(location = 2) uniform uint tileSize;\n" "layout(location = 2) uniform uint tileSize;\n"
"layout(location = 3) uniform uint tileArraySize;\n" "layout(location = 3) uniform uint tileArraySize;\n"
"layout(location = 4) uniform vec2 scaling;\n" "layout(location = 4) uniform vec2 scaling;\n"
"layout(location = 5) uniform uint useTexture;\n"
"\n" "\n"
"layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;\n" "layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;\n"
"\n" "\n"
"layout(binding = 1) uniform sampler2D srcTexture;\n"
"\n"
"\n"
"bool is_top_left(ivec2 a, ivec2 b)\n" "bool is_top_left(ivec2 a, ivec2 b)\n"
"{\n" "{\n"
" return( (a.y == b.y && b.x < a.x)\n" " return( (a.y == b.y && b.x < a.x)\n"
@ -363,6 +367,16 @@ const char* glsl_draw =
" vec4 color = shapeBuffer.elements[shapeIndex].color;\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" " ivec4 clip = ivec4(round((shapeBuffer.elements[shapeIndex].clip * vec4(scaling, scaling) + vec4(0.5, 0.5, 0.5, 0.5)) * subPixelFactor));\n"
"\n" "\n"
" mat3 uvTransform = mat3(shapeBuffer.elements[shapeIndex].uvTransform[0],\n"
" 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" " //NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge\n"
" int cw = is_clockwise(p0, p1, p2);\n" " int cw = is_clockwise(p0, p1, p2);\n"
" if(cw < 0)\n" " if(cw < 0)\n"
@ -417,7 +431,15 @@ const char* glsl_draw =
" {\n" " {\n"
" sampleColor[sampleIndex] = currentColor[sampleIndex];\n" " sampleColor[sampleIndex] = currentColor[sampleIndex];\n"
" }\n" " }\n"
" currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-color.a) + color.a*color;\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"
" nextColor *= texture(srcTexture, uv);\n"
" }\n"
" currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-nextColor.a) + nextColor.a*nextColor;\n"
" currentShapeIndex[sampleIndex] = shapeIndex;\n" " currentShapeIndex[sampleIndex] = shapeIndex;\n"
" flipCount[sampleIndex] = 1;\n" " flipCount[sampleIndex] = 1;\n"
" }\n" " }\n"

View File

@ -10,5 +10,5 @@ struct vertex {
struct shape { struct shape {
vec4 color; vec4 color;
vec4 clip; vec4 clip;
vec2 uv; float uvTransform[6];
}; };

View File

@ -30,9 +30,13 @@ layout(location = 1) uniform uvec2 tileCount;
layout(location = 2) uniform uint tileSize; layout(location = 2) uniform uint tileSize;
layout(location = 3) uniform uint tileArraySize; layout(location = 3) uniform uint tileArraySize;
layout(location = 4) uniform vec2 scaling; layout(location = 4) uniform vec2 scaling;
layout(location = 5) uniform uint useTexture;
layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture; layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;
layout(binding = 1) uniform sampler2D srcTexture;
bool is_top_left(ivec2 a, ivec2 b) bool is_top_left(ivec2 a, ivec2 b)
{ {
return( (a.y == b.y && b.x < a.x) return( (a.y == b.y && b.x < a.x)
@ -140,6 +144,16 @@ void main()
vec4 color = shapeBuffer.elements[shapeIndex].color; 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)); 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 //NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
int cw = is_clockwise(p0, p1, p2); int cw = is_clockwise(p0, p1, p2);
if(cw < 0) if(cw < 0)
@ -194,7 +208,15 @@ void main()
{ {
sampleColor[sampleIndex] = currentColor[sampleIndex]; sampleColor[sampleIndex] = currentColor[sampleIndex];
} }
currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-color.a) + color.a*color;
vec4 nextColor = color;
if(useTexture)
{
vec3 sampleFP = vec3(vec2(samplePoint).xy/(subPixelFactor*2.), 1);
vec2 uv = (uvTransform * sampleFP).xy;
nextColor *= texture(srcTexture, uv);
}
currentColor[sampleIndex] = sampleColor[sampleIndex]*(1.-nextColor.a) + nextColor.a*nextColor;
currentShapeIndex[sampleIndex] = shapeIndex; currentShapeIndex[sampleIndex] = shapeIndex;
flipCount[sampleIndex] = 1; flipCount[sampleIndex] = 1;
} }

View File

@ -2749,6 +2749,9 @@ mg_canvas mg_canvas_create(mg_surface surface)
canvas = mg_canvas_alloc_handle(canvasData); canvas = mg_canvas_alloc_handle(canvasData);
mg_canvas_set_current(canvas); mg_canvas_set_current(canvas);
//TODO: move that in mg_canvas_set_current() if needed?
mg_surface_prepare(surface);
} }
} }
return(canvas); return(canvas);

View File

@ -94,13 +94,19 @@ typedef void (*mg_canvas_backend_destroy_proc)(mg_canvas_backend* backend);
typedef void (*mg_canvas_backend_begin_proc)(mg_canvas_backend* backend); typedef void (*mg_canvas_backend_begin_proc)(mg_canvas_backend* backend);
typedef void (*mg_canvas_backend_end_proc)(mg_canvas_backend* backend); typedef void (*mg_canvas_backend_end_proc)(mg_canvas_backend* backend);
typedef void (*mg_canvas_backend_clear_proc)(mg_canvas_backend* backend, mg_color clearColor); typedef void (*mg_canvas_backend_clear_proc)(mg_canvas_backend* backend, mg_color clearColor);
typedef void (*mg_canvas_backend_draw_batch_proc)(mg_canvas_backend* backend, mg_image_data* imageData, u32 vertexCount, u32 shapeCount, u32 indexCount); typedef void (*mg_canvas_backend_draw_batch_proc)(mg_canvas_backend* backend,
mg_image_data* imageData,
u32 vertexCount,
u32 shapeCount,
u32 indexCount);
typedef void (*mg_canvas_backend_atlas_upload_proc)(mg_canvas_backend* backend, mp_rect rect, u8* bytes);
typedef mg_image_data* (*mg_canvas_backend_image_create_proc)(mg_canvas_backend* backend, vec2 size); typedef mg_image_data* (*mg_canvas_backend_image_create_proc)(mg_canvas_backend* backend, vec2 size);
typedef void (*mg_canvas_backend_image_destroy_proc)(mg_canvas_backend* backend, mg_image_data* image); typedef void (*mg_canvas_backend_image_destroy_proc)(mg_canvas_backend* backend, mg_image_data* image);
typedef void (*mg_canvas_backend_image_upload_region_proc)(mg_canvas_backend* backend, mg_image_data* image, mp_rect region, u8* pixels); 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 typedef struct mg_canvas_backend
{ {
@ -115,9 +121,6 @@ typedef struct mg_canvas_backend
mg_canvas_backend_image_create_proc imageCreate; mg_canvas_backend_image_create_proc imageCreate;
mg_canvas_backend_image_destroy_proc imageDestroy; mg_canvas_backend_image_destroy_proc imageDestroy;
mg_canvas_backend_image_upload_region_proc imageUploadRegion; mg_canvas_backend_image_upload_region_proc imageUploadRegion;
mg_canvas_backend_atlas_upload_proc atlasUpload;
} mg_canvas_backend; } mg_canvas_backend;
#ifdef __cplusplus #ifdef __cplusplus