From d4bceba7e93a066608ad947024ce08a4571ff674 Mon Sep 17 00:00:00 2001 From: Martin Fouilleul Date: Tue, 28 Feb 2023 13:16:36 +0100 Subject: [PATCH] [canvas] basic image atlas API --- examples/{image => atlas}/build.bat | 2 +- examples/{image => atlas}/build.sh | 2 +- examples/atlas/main.c | 100 ++++++++ examples/texture/build.bat | 4 + examples/texture/build.sh | 11 + examples/{image => texture}/main.c | 22 +- src/gl_canvas.c | 62 ++--- src/graphics.c | 384 ++++++++++++++++++++++------ src/graphics.h | 122 +++++---- src/graphics_internal.h | 20 +- src/mtl_canvas.m | 56 ++-- 11 files changed, 575 insertions(+), 210 deletions(-) rename examples/{image => atlas}/build.bat (71%) rename examples/{image => atlas}/build.sh (78%) create mode 100644 examples/atlas/main.c create mode 100644 examples/texture/build.bat create mode 100755 examples/texture/build.sh rename examples/{image => texture}/main.c (75%) diff --git a/examples/image/build.bat b/examples/atlas/build.bat similarity index 71% rename from examples/image/build.bat rename to examples/atlas/build.bat index a2f39d7..f9bd5cc 100644 --- a/examples/image/build.bat +++ b/examples/atlas/build.bat @@ -1,4 +1,4 @@ set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers -cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /out:../../bin/example_image.exe +cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /out:../../bin/example_atlas.exe diff --git a/examples/image/build.sh b/examples/atlas/build.sh similarity index 78% rename from examples/image/build.sh rename to examples/atlas/build.sh index 1e71bf2..9b7b41b 100755 --- a/examples/image/build.sh +++ b/examples/atlas/build.sh @@ -8,4 +8,4 @@ INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app" LIBS="-L$BINDIR -lmilepost" FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG" -clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_image main.c +clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_atlas main.c diff --git a/examples/atlas/main.c b/examples/atlas/main.c new file mode 100644 index 0000000..6eef148 --- /dev/null +++ b/examples/atlas/main.c @@ -0,0 +1,100 @@ +/************************************************************//** +* +* @file: main.cpp +* @author: Martin Fouilleul +* @date: 30/07/2022 +* @revision: +* +*****************************************************************/ +#include +#include +#include + +#define _USE_MATH_DEFINES //NOTE: necessary for MSVC +#include + +#include"milepost.h" + +#define LOG_SUBSYSTEM "Main" + +int main() +{ + LogLevel(LOG_LEVEL_WARNING); + + mp_init(); + mp_clock_init(); //TODO put that in mp_init()? + + mp_rect windowRect = {.x = 100, .y = 100, .w = 810, .h = 610}; + mp_window window = mp_window_create(windowRect, "test", 0); + + mp_rect contentRect = mp_window_get_content_rect(window); + + //NOTE: create surface + mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT); + mg_surface_swap_interval(surface, 0); + + //NOTE: create canvas + mg_canvas canvas = mg_canvas_create(surface); + if(mg_canvas_is_nil(canvas)) + { + printf("Error: couldn't create canvas\n"); + return(-1); + } + + //NOTE: create atlas + str8 path1 = mp_app_get_resource_path(mem_scratch(), "../resources/triceratops.png"); + str8 path2 = mp_app_get_resource_path(mem_scratch(), "../resources/Top512.png"); + + mg_image_atlas atlas = mg_image_atlas_create(16000, 16000); + mg_image image1 = mg_image_upload_from_file(atlas, path1, true); + mg_image image2 = mg_image_upload_from_file(atlas, path2, true); + + // start app + mp_window_bring_to_front(window); + mp_window_focus(window); + + while(!mp_should_quit()) + { + mp_pump_events(0); + mp_event event = {0}; + while(mp_next_event(&event)) + { + switch(event.type) + { + case MP_EVENT_WINDOW_CLOSE: + { + mp_request_quit(); + } break; + + default: + break; + } + } + + mg_surface_prepare(surface); + + mg_set_color_rgba(0, 1, 1, 1); + mg_clear(); + + mg_set_color_rgba(1, 1, 1, 1); + + mg_image_draw(image1, (mp_rect){100, 100, 300, 300}); + mg_image_draw(image2, (mp_rect){300, 200, 300, 300}); + + mg_flush(); + mg_surface_present(surface); + + mem_arena_clear(mem_scratch()); + } + + mg_image_recycle(image1); + mg_image_recycle(image2); + mg_image_atlas_destroy(atlas); + mg_canvas_destroy(canvas); + mg_surface_destroy(surface); + mp_window_destroy(window); + + mp_terminate(); + + return(0); +} diff --git a/examples/texture/build.bat b/examples/texture/build.bat new file mode 100644 index 0000000..61ef4a8 --- /dev/null +++ b/examples/texture/build.bat @@ -0,0 +1,4 @@ + +set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers + +cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /out:../../bin/example_texture.exe diff --git a/examples/texture/build.sh b/examples/texture/build.sh new file mode 100755 index 0000000..5d82fc6 --- /dev/null +++ b/examples/texture/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +BINDIR=../../bin +RESDIR=../../resources +SRCDIR=../../src + +INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app" +LIBS="-L$BINDIR -lmilepost" +FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG" + +clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_texture main.c diff --git a/examples/image/main.c b/examples/texture/main.c similarity index 75% rename from examples/image/main.c rename to examples/texture/main.c index 329e09b..e0475b1 100644 --- a/examples/image/main.c +++ b/examples/texture/main.c @@ -41,14 +41,14 @@ int main() return(-1); } - //NOTE: create image - str8 imagePath = mp_app_get_resource_path(mem_scratch(), "../resources/triceratops.png"); - mg_image image = mg_image_create_from_file(imagePath, true); - vec2 imageSize = mg_image_size(image); + //NOTE: create texture + str8 texturePath = mp_app_get_resource_path(mem_scratch(), "../resources/triceratops.png"); + mg_texture texture = mg_texture_create_from_file(texturePath, true); + vec2 textureSize = mg_texture_size(texture); - str8 imagePath2 = mp_app_get_resource_path(mem_scratch(), "../resources/Top512.png"); - mg_image image2 = mg_image_create_from_file(imagePath2, true); - vec2 imageSize2 = mg_image_size(image2); + str8 texturePath2 = mp_app_get_resource_path(mem_scratch(), "../resources/Top512.png"); + mg_texture texture2 = mg_texture_create_from_file(texturePath2, true); + vec2 textureSize2 = mg_texture_size(texture2); // start app mp_window_bring_to_front(window); @@ -82,8 +82,8 @@ int main() mg_matrix_push((mg_mat2x3){0.707, -0.707, 200, 0.707, 0.707, 100}); - mg_set_image(image); - mg_set_image_source_region((mp_rect){500, 500, 2000, 1400}); + mg_set_texture(texture); + mg_set_texture_source_region((mp_rect){500, 500, 2000, 1400}); mg_move_to(0, 0); mg_line_to(200, 0); @@ -95,7 +95,7 @@ int main() mg_matrix_pop(); - mg_image_draw(image2, (mp_rect){300, 200, 300, 300}); + mg_texture_draw(texture2, (mp_rect){300, 200, 300, 300}); mg_flush(); mg_surface_present(surface); @@ -103,7 +103,7 @@ int main() mem_arena_clear(mem_scratch()); } - mg_image_destroy(image); + mg_texture_destroy(texture); mg_canvas_destroy(canvas); mg_surface_destroy(surface); mp_window_destroy(window); diff --git a/src/gl_canvas.c b/src/gl_canvas.c index 5147827..d562274 100644 --- a/src/gl_canvas.c +++ b/src/gl_canvas.c @@ -39,12 +39,12 @@ typedef struct mg_gl_canvas_backend } mg_gl_canvas_backend; -typedef struct mg_gl_image +typedef struct mg_gl_texture { - mg_image_data interface; + mg_texture_data interface; GLuint textureID; -} mg_gl_image; +} mg_gl_texture; //NOTE: debugger typedef struct debug_vertex @@ -156,7 +156,7 @@ void mg_gl_canvas_clear(mg_canvas_backend* interface, mg_color clearColor) glClear(GL_COLOR_BUFFER_BIT); } -void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* imageInterface, u32 shapeCount, u32 vertexCount, u32 indexCount) +void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, mg_texture_data* textureInterface, u32 shapeCount, u32 vertexCount, u32 indexCount) { mg_gl_canvas_backend* backend = (mg_gl_canvas_backend*)interface; @@ -214,7 +214,7 @@ void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* imageI //NOTE: then we fire the drawing shader that will select only triangles in its tile glUseProgram(backend->drawProgram); - glBindImageTexture(0, backend->outTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8); + glBindTextureTexture(0, backend->outTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8); glUniform1ui(0, indexCount); glUniform2ui(1, tileCountX, tileCountY); @@ -222,12 +222,12 @@ void mg_gl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* imageI glUniform1ui(3, tileArrayLength); glUniform2f(4, contentsScaling.x, contentsScaling.y); - if(imageInterface) + if(textureInterface) { - //TODO: make sure this image belongs to that context - mg_gl_image* image = (mg_gl_image*)imageInterface; + //TODO: make sure this texture belongs to that context + mg_gl_texture* texture = (mg_gl_texture*)textureInterface; glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, image->textureID); + glBindTexture(GL_TEXTURE_2D, texture->textureID); glUniform1ui(5, 1); } else @@ -270,41 +270,41 @@ void mg_gl_canvas_destroy(mg_canvas_backend* interface) free(backend); } -mg_image_data* mg_gl_canvas_image_create(mg_canvas_backend* interface, vec2 size) +mg_texture_data* mg_gl_canvas_texture_create(mg_canvas_backend* interface, vec2 size) { - mg_gl_image* image = 0; + mg_gl_texture* texture = 0; - image = malloc_type(mg_gl_image); - if(image) + texture = malloc_type(mg_gl_texture); + if(texture) { - glGenTextures(1, &image->textureID); - glBindTexture(GL_TEXTURE_2D, image->textureID); + glGenTextures(1, &texture->textureID); + glBindTexture(GL_TEXTURE_2D, texture->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; + texture->interface.size = size; } - return((mg_image_data*)image); + return((mg_texture_data*)texture); } -void mg_gl_canvas_image_destroy(mg_canvas_backend* interface, mg_image_data* imageInterface) +void mg_gl_canvas_texture_destroy(mg_canvas_backend* interface, mg_texture_data* textureInterface) { - //TODO: check that this image belongs to this context - mg_gl_image* image = (mg_gl_image*)imageInterface; - glDeleteTextures(1, &image->textureID); - free(image); + //TODO: check that this texture belongs to this context + mg_gl_texture* texture = (mg_gl_texture*)textureInterface; + glDeleteTextures(1, &texture->textureID); + free(texture); } -void mg_gl_canvas_image_upload_region(mg_canvas_backend* interface, - mg_image_data* imageInterface, +void mg_gl_canvas_texture_upload_region(mg_canvas_backend* interface, + mg_texture_data* textureInterface, 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); + //TODO: check that this texture belongs to this context + mg_gl_texture* texture = (mg_gl_texture*)textureInterface; + glBindTexture(GL_TEXTURE_2D, texture->textureID); + glTexTexture2D(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) @@ -429,9 +429,9 @@ mg_canvas_backend* mg_gl_canvas_create(mg_surface surface) backend->interface.end = mg_gl_canvas_end; backend->interface.clear = mg_gl_canvas_clear; backend->interface.drawBatch = mg_gl_canvas_draw_batch; - 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; + backend->interface.textureCreate = mg_gl_canvas_texture_create; + backend->interface.textureDestroy = mg_gl_canvas_texture_destroy; + backend->interface.textureUploadRegion = mg_gl_canvas_texture_upload_region; mg_surface_prepare(surface); diff --git a/src/graphics.c b/src/graphics.c index a96832f..327aaa7 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -56,7 +56,7 @@ typedef struct mg_attributes mg_font font; f32 fontSize; - mg_image image; + mg_texture texture; mp_rect srcRegion; mg_mat2x3 transform; @@ -123,7 +123,7 @@ typedef struct mg_glyph_data enum { MG_STREAM_MAX_COUNT = 128, - MG_IMAGE_MAX_COUNT = 128 + MG_TEXTURE_MAX_COUNT = 128 }; enum @@ -152,6 +152,8 @@ typedef struct mg_font_data } mg_font_data; typedef struct mg_canvas_data mg_canvas_data; +typedef struct mg_image_data mg_image_data; +typedef struct mg_image_atlas_data mg_image_atlas_data; typedef struct mg_resource_slot { @@ -160,7 +162,9 @@ typedef struct mg_resource_slot union { mg_surface_data* surface; + mg_texture_data* texture; mg_image_data* image; + mg_image_atlas_data* atlas; mg_canvas_data* canvas; mg_font_data* font; //... @@ -217,6 +221,8 @@ typedef struct mg_canvas_data u32 primitiveCount; mg_primitive primitives[MG_MAX_PRIMITIVE_COUNT]; + mg_resource_pool texturePool; + mg_resource_pool imageAtlasPool; mg_resource_pool imagePool; /* @@ -228,7 +234,7 @@ typedef struct mg_canvas_data //NOTE: these are used at render time mp_rect clip; mg_mat2x3 transform; - mg_image image; + mg_texture texture; mp_rect srcRegion; vec4 shapeExtents; @@ -389,33 +395,33 @@ mg_canvas_data* mg_canvas_data_from_handle(mg_canvas canvas) } //------------------------------------------------------------------------ -// image handles +// texture handles //------------------------------------------------------------------------ -mg_image mg_image_nil() { return((mg_image){.h = 0}); } -bool mg_image_is_nil(mg_image image) { return(image.h == 0); } +mg_texture mg_texture_nil() { return((mg_texture){.h = 0}); } +bool mg_texture_is_nil(mg_texture texture) { return(texture.h == 0); } -mg_image mg_image_alloc_handle(mg_canvas_data* canvas, mg_image_data* image) +mg_texture mg_texture_alloc_handle(mg_canvas_data* canvas, mg_texture_data* texture) { - mg_resource_slot* slot = mg_resource_slot_alloc(&canvas->imagePool); + mg_resource_slot* slot = mg_resource_slot_alloc(&canvas->texturePool); if(!slot) { LOG_ERROR("no more canvas slots\n"); - return(mg_image_nil()); + return(mg_texture_nil()); } - slot->image = image; - u64 h = mg_resource_handle_from_slot(&canvas->imagePool, slot); - mg_image handle = {h}; + slot->texture = texture; + u64 h = mg_resource_handle_from_slot(&canvas->texturePool, slot); + mg_texture handle = {h}; return(handle); } -mg_image_data* mg_image_data_from_handle(mg_canvas_data* canvas, mg_image handle) +mg_texture_data* mg_texture_data_from_handle(mg_canvas_data* canvas, mg_texture handle) { - mg_image_data* data = 0; - mg_resource_slot* slot = mg_resource_slot_from_handle(&canvas->imagePool, handle.h); + mg_texture_data* data = 0; + mg_resource_slot* slot = mg_resource_slot_from_handle(&canvas->texturePool, handle.h); if(slot) { - data = slot->image; + data = slot->texture; } return(data); } @@ -769,7 +775,7 @@ void mg_finalize_shape(mg_canvas_data* canvas) if(canvas->nextShapeIndex) { //NOTE: set shape's uv transform for the _current_ shape - vec2 texSize = mg_image_size(canvas->image); + vec2 texSize = mg_texture_size(canvas->texture); mp_rect srcRegion = canvas->srcRegion; @@ -2853,13 +2859,13 @@ void mg_do_clip_push(mg_canvas_data* canvas, mp_rect clip) mg_clip_stack_push(canvas, r); } -void mg_draw_batch(mg_canvas_data* canvas, mg_image_data* image) +void mg_draw_batch(mg_canvas_data* canvas, mg_texture_data* texture) { mg_finalize_shape(canvas); if(canvas->backend && canvas->backend->drawBatch && canvas->indexCount) { - canvas->backend->drawBatch(canvas->backend, image, canvas->nextShapeIndex, canvas->vertexCount, canvas->indexCount); + canvas->backend->drawBatch(canvas->backend, texture, canvas->nextShapeIndex, canvas->vertexCount, canvas->indexCount); } mg_reset_shape_index(canvas); @@ -2883,7 +2889,7 @@ void mg_flush_commands(int primitiveCount, mg_primitive* primitives, mg_path_elt canvas->clip = (mp_rect){-FLT_MAX/2, -FLT_MAX/2, FLT_MAX, FLT_MAX}; - canvas->image = mg_image_nil(); + canvas->texture = mg_texture_nil(); canvas->backend->begin(canvas->backend); @@ -2897,11 +2903,11 @@ void mg_flush_commands(int primitiveCount, mg_primitive* primitives, mg_path_elt mg_primitive* primitive = &(primitives[nextIndex]); nextIndex++; - if(i && primitive->attributes.image.h != canvas->image.h) + if(i && primitive->attributes.texture.h != canvas->texture.h) { - mg_image_data* imageData = mg_image_data_from_handle(canvas, canvas->image); - mg_draw_batch(canvas, imageData); - canvas->image = primitive->attributes.image; + mg_texture_data* textureData = mg_texture_data_from_handle(canvas, canvas->texture); + mg_draw_batch(canvas, textureData); + canvas->texture = primitive->attributes.texture; } switch(primitive->cmd) @@ -2990,8 +2996,8 @@ void mg_flush_commands(int primitiveCount, mg_primitive* primitives, mg_path_elt } exit_command_loop: ; - mg_image_data* imageData = mg_image_data_from_handle(canvas, canvas->image); - mg_draw_batch(canvas, imageData); + mg_texture_data* textureData = mg_texture_data_from_handle(canvas, canvas->texture); + mg_draw_batch(canvas, textureData); canvas->backend->end(canvas->backend); @@ -3148,18 +3154,18 @@ void mg_set_text_flip(bool flip) } } -void mg_set_image(mg_image image) +void mg_set_texture(mg_texture texture) { mg_canvas_data* canvas = __mgCurrentCanvas; if(canvas) { - canvas->attributes.image = image; - vec2 size = mg_image_size(image); + canvas->attributes.texture = texture; + vec2 size = mg_texture_size(texture); canvas->attributes.srcRegion = (mp_rect){0, 0, size.x, size.y}; } } -void mg_set_image_source_region(mp_rect region) +void mg_set_texture_source_region(mp_rect region) { mg_canvas_data* canvas = __mgCurrentCanvas; if(canvas) @@ -3628,37 +3634,37 @@ void mg_arc(f32 x, f32 y, f32 r, f32 arcAngle, f32 startAngle) } //------------------------------------------------------------------------------------------ -//NOTE(martin): images +//NOTE(martin): textures //------------------------------------------------------------------------------------------ -MP_API mg_image mg_image_create(u32 width, u32 height) +mg_texture mg_texture_create(u32 width, u32 height) { - mg_image image = mg_image_nil(); + mg_texture texture = mg_texture_nil(); mg_canvas_data* canvas = __mgCurrentCanvas; if(canvas) { - mg_image_data* imageData = canvas->backend->imageCreate(canvas->backend, (vec2){width, height}); - if(imageData) + mg_texture_data* textureData = canvas->backend->textureCreate(canvas->backend, (vec2){width, height}); + if(textureData) { - image = mg_image_alloc_handle(canvas, imageData); + texture = mg_texture_alloc_handle(canvas, textureData); } } - return(image); + return(texture); } -MP_API mg_image mg_image_create_from_rgba8(u32 width, u32 height, u8* pixels) +mg_texture mg_texture_create_from_rgba8(u32 width, u32 height, u8* pixels) { - mg_image image = mg_image_create(width, height); - if(!mg_image_is_nil(image)) + mg_texture texture = mg_texture_create(width, height); + if(!mg_texture_is_nil(texture)) { - mg_image_upload_region_rgba8(image, (mp_rect){0, 0, width, height}, pixels); + mg_texture_upload_region_rgba8(texture, (mp_rect){0, 0, width, height}, pixels); } - return(image); + return(texture); } -MP_API mg_image mg_image_create_from_data(str8 data, bool flip) +mg_texture mg_texture_create_from_data(str8 data, bool flip) { - mg_image image = mg_image_nil(); + mg_texture texture = mg_texture_nil(); int width, height, channels; stbi_set_flip_vertically_on_load(flip ? 1 : 0); @@ -3666,15 +3672,15 @@ MP_API mg_image mg_image_create_from_data(str8 data, bool flip) if(pixels) { - image = mg_image_create_from_rgba8(width, height, pixels); + texture = mg_texture_create_from_rgba8(width, height, pixels); free(pixels); } - return(image); + return(texture); } -MP_API mg_image mg_image_create_from_file(str8 path, bool flip) +mg_texture mg_texture_create_from_file(str8 path, bool flip) { - mg_image image = mg_image_nil(); + mg_texture texture = mg_texture_nil(); int width, height, channels; const char* cpath = str8_to_cstring(mem_scratch(), path); @@ -3683,85 +3689,85 @@ MP_API mg_image mg_image_create_from_file(str8 path, bool flip) u8* pixels = stbi_load(cpath, &width, &height, &channels, 4); if(pixels) { - image = mg_image_create_from_rgba8(width, height, pixels); + texture = mg_texture_create_from_rgba8(width, height, pixels); free(pixels); } - return(image); + return(texture); } -MP_API void mg_image_destroy(mg_image image) +void mg_texture_destroy(mg_texture texture) { mg_canvas_data* canvas = __mgCurrentCanvas; if(canvas) { - mg_image_data* imageData = mg_image_data_from_handle(canvas, image); - if(imageData) + mg_texture_data* textureData = mg_texture_data_from_handle(canvas, texture); + if(textureData) { - canvas->backend->imageDestroy(canvas->backend, imageData); - mg_resource_handle_recycle(&canvas->imagePool, image.h); + canvas->backend->textureDestroy(canvas->backend, textureData); + mg_resource_handle_recycle(&canvas->texturePool, texture.h); } } } -MP_API void mg_image_upload_region_rgba8(mg_image image, mp_rect region, u8* pixels) +void mg_texture_upload_region_rgba8(mg_texture texture, mp_rect region, u8* pixels) { mg_canvas_data* canvas = __mgCurrentCanvas; if(canvas) { - mg_image_data* imageData = mg_image_data_from_handle(canvas, image); - if(imageData) + mg_texture_data* textureData = mg_texture_data_from_handle(canvas, texture); + if(textureData) { - canvas->backend->imageUploadRegion(canvas->backend, imageData, region, pixels); + canvas->backend->textureUploadRegion(canvas->backend, textureData, region, pixels); } } } -MP_API vec2 mg_image_size(mg_image image) +vec2 mg_texture_size(mg_texture texture) { vec2 res = {0}; mg_canvas_data* canvas = __mgCurrentCanvas; if(canvas) { - mg_image_data* imageData = mg_image_data_from_handle(canvas, image); - if(imageData) + mg_texture_data* textureData = mg_texture_data_from_handle(canvas, texture); + if(textureData) { - res = imageData->size; + res = textureData->size; } } return(res); } -MP_API void mg_image_draw_region(mg_image image, mp_rect srcRegion, mp_rect dstRegion) +void mg_texture_draw_region(mg_texture texture, mp_rect srcRegion, mp_rect dstRegion) { mg_canvas_data* canvas = __mgCurrentCanvas; if(canvas) { - mg_image oldImage = canvas->attributes.image; + mg_texture oldTexture = canvas->attributes.texture; mp_rect oldSrcRegion = canvas->attributes.srcRegion; mg_color oldColor = canvas->attributes.color; - canvas->attributes.image = image; + canvas->attributes.texture = texture; canvas->attributes.srcRegion = srcRegion; canvas->attributes.color = (mg_color){1, 1, 1, 1}; mg_push_command(canvas, (mg_primitive){.cmd = MG_CMD_RECT_FILL, .rect = dstRegion}); - canvas->attributes.image = oldImage; + canvas->attributes.texture = oldTexture; canvas->attributes.srcRegion = oldSrcRegion; canvas->attributes.color = oldColor; } } -MP_API void mg_image_draw_region_rounded(mg_image image, mp_rect srcRegion, mp_rect dstRegion, f32 roundness) +void mg_texture_draw_region_rounded(mg_texture texture, mp_rect srcRegion, mp_rect dstRegion, f32 roundness) { mg_canvas_data* canvas = __mgCurrentCanvas; if(canvas) { - mg_image oldImage = canvas->attributes.image; + mg_texture oldTexture = canvas->attributes.texture; mp_rect oldSrcRegion = canvas->attributes.srcRegion; mg_color oldColor = canvas->attributes.color; - canvas->attributes.image = image; + canvas->attributes.texture = texture; canvas->attributes.srcRegion = srcRegion; canvas->attributes.color = (mg_color){1, 1, 1, 1}; @@ -3772,16 +3778,242 @@ MP_API void mg_image_draw_region_rounded(mg_image image, mp_rect srcRegion, mp_r } } -MP_API void mg_image_draw(mg_image image, mp_rect rect) +void mg_texture_draw(mg_texture texture, mp_rect rect) { - vec2 size = mg_image_size(image); - mg_image_draw_region(image, (mp_rect){0, 0, size.x, size.y}, rect); + vec2 size = mg_texture_size(texture); + mg_texture_draw_region(texture, (mp_rect){0, 0, size.x, size.y}, rect); } -MP_API void mg_image_draw_rounded(mg_image image, mp_rect rect, f32 roundness) +void mg_texture_draw_rounded(mg_texture texture, mp_rect rect, f32 roundness) { - vec2 size = mg_image_size(image); - mg_image_draw_region_rounded(image, (mp_rect){0, 0, size.x, size.y}, rect, roundness); + vec2 size = mg_texture_size(texture); + mg_texture_draw_region_rounded(texture, (mp_rect){0, 0, size.x, size.y}, rect, roundness); } + +//------------------------------------------------------------------------------------------ +//NOTE(martin): image atlas +//------------------------------------------------------------------------------------------ + +mg_image_atlas mg_image_atlas_nil(){ return((mg_image_atlas){.h = 0}); } +bool mg_image_atlas_is_nil(mg_image_atlas atlas) { return(atlas.h == 0); } + +mg_image mg_image_nil(){ return((mg_image){.h = 0}); } +bool mg_image_is_nil(mg_image atlas) { return(atlas.h == 0); } + + +typedef struct mg_image_atlas_data +{ + mg_texture texture; + vec2 pos; + u32 lineHeight; + +} mg_image_atlas_data; + +typedef struct mg_image_data +{ + mg_image_atlas atlas; + mg_texture texture; + mp_rect rect; + +} mg_image_data; + + +mg_image_atlas_data* mg_image_atlas_data_from_handle(mg_canvas_data* canvas, mg_image_atlas handle) +{ + mg_image_atlas_data* data = 0; + mg_resource_slot* slot = mg_resource_slot_from_handle(&canvas->imageAtlasPool, handle.h); + if(slot) + { + data = slot->atlas; + } + return(data); +} + + +mg_image_data* mg_image_data_from_handle(mg_canvas_data* canvas, mg_image handle) +{ + mg_image_data* data = 0; + mg_resource_slot* slot = mg_resource_slot_from_handle(&canvas->imagePool, handle.h); + if(slot) + { + data = slot->image; + } + return(data); +} + + +mg_image_atlas mg_image_atlas_create(u32 width, u32 height) +{ + mg_image_atlas handle = mg_image_atlas_nil(); + + mg_canvas_data* canvas = __mgCurrentCanvas; + if(canvas) + { + mg_resource_slot* slot = mg_resource_slot_alloc(&canvas->imageAtlasPool); + if(slot) + { + mg_image_atlas_data* atlas = malloc_type(mg_image_atlas_data); + if(atlas) + { + memset(atlas, 0, sizeof(mg_image_atlas_data)); + atlas->texture = mg_texture_create(width, height); + + slot->atlas = atlas; + handle.h = mg_resource_handle_from_slot(&canvas->imageAtlasPool, slot); + } + else + { + mg_resource_slot_recycle(&canvas->imageAtlasPool, slot); + } + } + } + return(handle); +} + +void mg_image_atlas_destroy(mg_image_atlas handle) +{ + mg_canvas_data* canvas = __mgCurrentCanvas; + if(canvas) + { + mg_image_atlas_data* atlas = mg_image_atlas_data_from_handle(canvas, handle); + if(atlas) + { + mg_texture_destroy(atlas->texture); + free(atlas); + mg_resource_handle_recycle(&canvas->imageAtlasPool, handle.h); + } + } +} + +mp_rect mg_image_atlas_allocate(mg_image_atlas_data* atlas, u32 width, u32 height) +{ + mp_rect rect = {0, 0, 0, 0}; + vec2 atlasSize = mg_texture_size(atlas->texture); + + if(atlas->pos.x + width >= atlasSize.x) + { + atlas->pos.x = 0; + atlas->pos.y += (atlas->lineHeight + 1); + atlas->lineHeight = 0; + } + if( atlas->pos.x + width < atlasSize.x + && atlas->pos.y + height < atlasSize.y) + { + rect = (mp_rect){atlas->pos.x, atlas->pos.y, width, height}; + + atlas->pos.x += (width + 1); + atlas->lineHeight = maximum(atlas->lineHeight, height); + } + return(rect); +} + +mg_image mg_image_upload_from_rgba8(mg_image_atlas atlasHandle, u32 width, u32 height, u8* pixels) +{ + mg_image res = mg_image_nil(); + + mg_canvas_data* canvas = __mgCurrentCanvas; + if(canvas) + { + mg_image_atlas_data* atlas = mg_image_atlas_data_from_handle(canvas, atlasHandle); + if(atlas) + { + mg_resource_slot* slot = mg_resource_slot_alloc(&canvas->imagePool); + if(slot) + { + mg_image_data* image = malloc_type(mg_image_data); + if(image) + { + memset(image, 0, sizeof(mg_image_data)); + mp_rect rect = mg_image_atlas_allocate(atlas, width, height); + if(rect.w == width && rect.h == height) + { + image->rect = rect; + image->texture = atlas->texture; + image->atlas = atlasHandle; + + mg_texture_upload_region_rgba8(atlas->texture, rect, pixels); + + slot->image = image; + res.h = mg_resource_handle_from_slot(&canvas->imagePool, slot); + } + else + { + free(image); + mg_resource_slot_recycle(&canvas->imagePool, slot); + } + } + else + { + mg_resource_slot_recycle(&canvas->imagePool, slot); + } + } + } + } + return(res); +} + +void mg_image_recycle(mg_image handle) +{ + mg_canvas_data* canvas = __mgCurrentCanvas; + if(canvas) + { + mg_image_data* image = mg_image_data_from_handle(canvas, handle); + if(image) + { + //TODO recycle rect + free(image); + mg_resource_handle_recycle(&canvas->imagePool, handle.h); + } + } +} + +void mg_image_draw(mg_image handle, mp_rect rect) +{ + mg_canvas_data* canvas = __mgCurrentCanvas; + if(canvas) + { + mg_image_data* image = mg_image_data_from_handle(canvas, handle); + if(image) + { + mg_texture_draw_region(image->texture, image->rect, rect); + } + } +} + +// helpers +mg_image mg_image_upload_from_data(mg_image_atlas atlas, str8 data, bool flip) +{ + mg_image image = mg_image_nil(); + + int width, height, channels; + stbi_set_flip_vertically_on_load(flip ? 1 : 0); + u8* pixels = stbi_load_from_memory((u8*)data.ptr, data.len, &width, &height, &channels, 4); + if(pixels) + { + image = mg_image_upload_from_rgba8(atlas, width, height, pixels); + free(pixels); + } + return(image); +} + +mg_image mg_image_upload_from_file(mg_image_atlas atlas, str8 path, bool flip) +{ + mg_image image = mg_image_nil(); + int width, height, channels; + + const char* cpath = str8_to_cstring(mem_scratch(), path); + + stbi_set_flip_vertically_on_load(flip ? 1 : 0); + u8* pixels = stbi_load(cpath, &width, &height, &channels, 4); + if(pixels) + { + image = mg_image_upload_from_rgba8(atlas, width, height, pixels); + free(pixels); + } + return(image); +} + + + #undef LOG_SUBSYSTEM diff --git a/src/graphics.h b/src/graphics.h index 681ad73..6800853 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -106,7 +106,7 @@ MP_API void mg_surface_set_hidden(mg_surface surface, bool hidden); //------------------------------------------------------------------------------------------ typedef struct mg_canvas { u64 h; } mg_canvas; typedef struct mg_font { u64 h; } mg_font; -typedef struct mg_image { u64 h; } mg_image; +typedef struct mg_texture { u64 h; } mg_texture; typedef struct mg_mat2x3 { @@ -169,6 +169,73 @@ MP_API mg_canvas mg_canvas_set_current(mg_canvas canvas); MP_API void mg_flush(); +//------------------------------------------------------------------------------------------ +//NOTE(martin): fonts +//------------------------------------------------------------------------------------------ +MP_API mg_font mg_font_nil(); +MP_API mg_font mg_font_create_from_memory(u32 size, byte* buffer, u32 rangeCount, unicode_range* ranges); +MP_API void mg_font_destroy(mg_font font); + +//NOTE(martin): the following int valued functions return -1 if font is invalid or codepoint is not present in font// +//TODO(martin): add enum error codes + +MP_API mg_font_extents mg_font_get_extents(mg_font font); +MP_API mg_font_extents mg_font_get_scaled_extents(mg_font font, f32 emSize); +MP_API f32 mg_font_get_scale_for_em_pixels(mg_font font, f32 emSize); + +//NOTE(martin): if you need to process more than one codepoint, first convert your codepoints to glyph indices, then use the +// glyph index versions of the functions, which can take an array of glyph indices. + +MP_API str32 mg_font_get_glyph_indices(mg_font font, str32 codePoints, str32 backing); +MP_API str32 mg_font_push_glyph_indices(mg_font font, mem_arena* arena, str32 codePoints); +MP_API u32 mg_font_get_glyph_index(mg_font font, utf32 codePoint); + +MP_API int mg_font_get_codepoint_extents(mg_font font, utf32 codePoint, mg_text_extents* outExtents); + +MP_API int mg_font_get_glyph_extents(mg_font font, str32 glyphIndices, mg_text_extents* outExtents); + +MP_API mp_rect mg_text_bounding_box_utf32(mg_font font, f32 fontSize, str32 text); +MP_API mp_rect mg_text_bounding_box(mg_font font, f32 fontSize, str8 text); + +//------------------------------------------------------------------------------------------ +//NOTE(martin): textures +//------------------------------------------------------------------------------------------ +MP_API mg_texture mg_texture_nil(); +MP_API bool mg_texture_is_nil(mg_texture a); + +MP_API mg_texture mg_texture_create(u32 width, u32 height); +MP_API mg_texture mg_texture_create_from_rgba8(u32 width, u32 height, u8* pixels); +MP_API mg_texture mg_texture_create_from_data(str8 data, bool flip); +MP_API mg_texture mg_texture_create_from_file(str8 path, bool flip); + +MP_API void mg_texture_destroy(mg_texture texture); + +MP_API void mg_texture_upload_region_rgba8(mg_texture texture, mp_rect region, u8* pixels); +MP_API vec2 mg_texture_size(mg_texture texture); + +MP_API void mg_texture_draw_region(mg_texture texture, mp_rect srcRegion, mp_rect dstRegion); +MP_API void mg_texture_draw_region_rounded(mg_texture texture, mp_rect srcRect, mp_rect dstRegion, f32 roundness); +MP_API void mg_texture_draw(mg_texture texture, mp_rect rect); +MP_API void mg_texture_draw_rounded(mg_texture texture, mp_rect rect, f32 roundness); + +//------------------------------------------------------------------------------------------ +//NOTE(martin): image +//------------------------------------------------------------------------------------------ + +typedef struct mg_image_atlas { u64 h; } mg_image_atlas; +typedef struct mg_image { u64 h; } mg_image; + +MP_API mg_image_atlas mg_image_atlas_create(u32 width, u32 height); +MP_API void mg_image_atlas_destroy(mg_image_atlas atlas); + +MP_API mg_image mg_image_upload_from_rgba8(mg_image_atlas atlas, u32 width, u32 height, u8* pixels); +MP_API void mg_image_recycle(mg_image image); +MP_API void mg_image_draw(mg_image image, mp_rect rect); + +// helpers +MP_API mg_image mg_image_upload_from_data(mg_image_atlas atlas, str8 data, bool flip); +MP_API mg_image mg_image_upload_from_file(mg_image_atlas atlas, str8 file, bool flip); + //------------------------------------------------------------------------------------------ //NOTE(martin): transform, viewport and clipping //------------------------------------------------------------------------------------------ @@ -193,8 +260,8 @@ MP_API void mg_set_cap(mg_cap_type cap); MP_API void mg_set_font(mg_font font); MP_API void mg_set_font_size(f32 size); MP_API void mg_set_text_flip(bool flip); -MP_API void mg_set_image(mg_image image); -MP_API void mg_set_image_source_region(mp_rect region); +MP_API void mg_set_texture(mg_texture texture); +MP_API void mg_set_texture_source_region(mp_rect region); MP_API mg_color mg_get_color(); MP_API f32 mg_get_width(); @@ -240,53 +307,4 @@ MP_API void mg_circle_fill(f32 x, f32 y, f32 r); MP_API void mg_circle_stroke(f32 x, f32 y, f32 r); MP_API void mg_arc(f32 x, f32 y, f32 r, f32 arcAngle, f32 startAngle); -//------------------------------------------------------------------------------------------ -//NOTE(martin): fonts -//------------------------------------------------------------------------------------------ -MP_API mg_font mg_font_nil(); -MP_API mg_font mg_font_create_from_memory(u32 size, byte* buffer, u32 rangeCount, unicode_range* ranges); -MP_API void mg_font_destroy(mg_font font); - -//NOTE(martin): the following int valued functions return -1 if font is invalid or codepoint is not present in font// -//TODO(martin): add enum error codes - -MP_API mg_font_extents mg_font_get_extents(mg_font font); -MP_API mg_font_extents mg_font_get_scaled_extents(mg_font font, f32 emSize); -MP_API f32 mg_font_get_scale_for_em_pixels(mg_font font, f32 emSize); - -//NOTE(martin): if you need to process more than one codepoint, first convert your codepoints to glyph indices, then use the -// glyph index versions of the functions, which can take an array of glyph indices. - -MP_API str32 mg_font_get_glyph_indices(mg_font font, str32 codePoints, str32 backing); -MP_API str32 mg_font_push_glyph_indices(mg_font font, mem_arena* arena, str32 codePoints); -MP_API u32 mg_font_get_glyph_index(mg_font font, utf32 codePoint); - -MP_API int mg_font_get_codepoint_extents(mg_font font, utf32 codePoint, mg_text_extents* outExtents); - -MP_API int mg_font_get_glyph_extents(mg_font font, str32 glyphIndices, mg_text_extents* outExtents); - -MP_API mp_rect mg_text_bounding_box_utf32(mg_font font, f32 fontSize, str32 text); -MP_API mp_rect mg_text_bounding_box(mg_font font, f32 fontSize, str8 text); - -//------------------------------------------------------------------------------------------ -//NOTE(martin): images -//------------------------------------------------------------------------------------------ -MP_API mg_image mg_image_nil(); -MP_API bool mg_image_is_nil(mg_image a); - -MP_API mg_image mg_image_create(u32 width, u32 height); -MP_API mg_image mg_image_create_from_rgba8(u32 width, u32 height, u8* pixels); -MP_API mg_image mg_image_create_from_data(str8 data, bool flip); -MP_API mg_image mg_image_create_from_file(str8 path, bool flip); - -MP_API void mg_image_destroy(mg_image image); - -MP_API void mg_image_upload_region_rgba8(mg_image image, mp_rect region, u8* pixels); -MP_API vec2 mg_image_size(mg_image image); - -MP_API void mg_image_draw_region(mg_image image, mp_rect srcRegion, mp_rect dstRegion); -MP_API void mg_image_draw_region_rounded(mg_image image, mp_rect srcRect, mp_rect dstRegion, f32 roundness); -MP_API void mg_image_draw(mg_image image, mp_rect rect); -MP_API void mg_image_draw_rounded(mg_image image, mp_rect rect, f32 roundness); - #endif //__GRAPHICS_H_ diff --git a/src/graphics_internal.h b/src/graphics_internal.h index 395e280..11d9323 100644 --- a/src/graphics_internal.h +++ b/src/graphics_internal.h @@ -52,13 +52,13 @@ mg_surface_data* mg_surface_data_from_handle(mg_surface handle); //--------------------------------------------------------------- // canvas backend interface //--------------------------------------------------------------- -typedef struct mg_image_data +typedef struct mg_texture_data { list_elt listElt; u32 generation; vec2 size; -} mg_image_data; +} mg_texture_data; typedef struct mg_vertex_layout { @@ -95,16 +95,16 @@ typedef void (*mg_canvas_backend_begin_proc)(mg_canvas_backend* backend); typedef void (*mg_canvas_backend_end_proc)(mg_canvas_backend* backend); typedef void (*mg_canvas_backend_clear_proc)(mg_canvas_backend* backend, mg_color clearColor); typedef void (*mg_canvas_backend_draw_batch_proc)(mg_canvas_backend* backend, - mg_image_data* imageData, + mg_texture_data* textureData, u32 vertexCount, u32 shapeCount, u32 indexCount); -typedef mg_image_data* (*mg_canvas_backend_image_create_proc)(mg_canvas_backend* backend, vec2 size); -typedef void (*mg_canvas_backend_image_destroy_proc)(mg_canvas_backend* backend, mg_image_data* image); -typedef void (*mg_canvas_backend_image_upload_region_proc)(mg_canvas_backend* backend, - mg_image_data* image, +typedef mg_texture_data* (*mg_canvas_backend_texture_create_proc)(mg_canvas_backend* backend, vec2 size); +typedef void (*mg_canvas_backend_texture_destroy_proc)(mg_canvas_backend* backend, mg_texture_data* texture); +typedef void (*mg_canvas_backend_texture_upload_region_proc)(mg_canvas_backend* backend, + mg_texture_data* texture, mp_rect region, u8* pixels); @@ -118,9 +118,9 @@ typedef struct mg_canvas_backend mg_canvas_backend_clear_proc clear; mg_canvas_backend_draw_batch_proc drawBatch; - mg_canvas_backend_image_create_proc imageCreate; - mg_canvas_backend_image_destroy_proc imageDestroy; - mg_canvas_backend_image_upload_region_proc imageUploadRegion; + mg_canvas_backend_texture_create_proc textureCreate; + mg_canvas_backend_texture_destroy_proc textureDestroy; + mg_canvas_backend_texture_upload_region_proc textureUploadRegion; } mg_canvas_backend; #ifdef __cplusplus diff --git a/src/mtl_canvas.m b/src/mtl_canvas.m index 261b272..4daacba 100644 --- a/src/mtl_canvas.m +++ b/src/mtl_canvas.m @@ -51,11 +51,11 @@ typedef struct mg_mtl_canvas_backend } mg_mtl_canvas_backend; -typedef struct mg_mtl_image_data +typedef struct mg_mtl_texture_data { - mg_image_data interface; + mg_texture_data interface; id texture; -} mg_mtl_image_data; +} mg_mtl_texture_data; mg_mtl_surface* mg_mtl_canvas_get_surface(mg_mtl_canvas_backend* canvas) @@ -139,7 +139,7 @@ void mg_mtl_canvas_clear(mg_canvas_backend* interface, mg_color clearColor) backend->clearColor = clearColor; } -void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image, u32 shapeCount, u32 vertexCount, u32 indexCount) +void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_texture_data* texture, u32 shapeCount, u32 vertexCount, u32 indexCount) { mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface; mg_mtl_surface* surface = mg_mtl_canvas_get_surface(backend); @@ -226,10 +226,10 @@ void mg_mtl_canvas_draw_batch(mg_canvas_backend* interface, mg_image_data* image [encoder setComputePipelineState:backend->computePipeline]; [encoder setTexture: backend->outTexture atIndex: 0]; int useTexture = 0; - if(image) + if(texture) { - mg_mtl_image_data* mtlImage = (mg_mtl_image_data*)image; - [encoder setTexture: mtlImage->texture atIndex: 1]; + mg_mtl_texture_data* mtlTexture = (mg_mtl_texture_data*)texture; + [encoder setTexture: mtlTexture->texture atIndex: 1]; useTexture = 1; } @@ -333,9 +333,9 @@ void mg_mtl_canvas_destroy(mg_canvas_backend* interface) } } -mg_image_data* mg_mtl_canvas_image_create(mg_canvas_backend* interface, vec2 size) +mg_texture_data* mg_mtl_canvas_texture_create(mg_canvas_backend* interface, vec2 size) { - mg_mtl_image_data* image = 0; + mg_mtl_texture_data* texture = 0; mg_mtl_canvas_backend* backend = (mg_mtl_canvas_backend*)interface; mg_mtl_surface* surface = mg_mtl_canvas_get_surface(backend); @@ -343,8 +343,8 @@ mg_image_data* mg_mtl_canvas_image_create(mg_canvas_backend* interface, vec2 siz { @autoreleasepool{ - image = malloc_type(mg_mtl_image_data); - if(image) + texture = malloc_type(mg_mtl_texture_data); + if(texture) { MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init]; texDesc.textureType = MTLTextureType2D; @@ -354,38 +354,38 @@ mg_image_data* mg_mtl_canvas_image_create(mg_canvas_backend* interface, vec2 siz texDesc.width = size.x; texDesc.height = size.y; - image->texture = [surface->device newTextureWithDescriptor:texDesc]; - if(image->texture != nil) + texture->texture = [surface->device newTextureWithDescriptor:texDesc]; + if(texture->texture != nil) { - [image->texture retain]; - image->interface.size = size; + [texture->texture retain]; + texture->interface.size = size; } else { - free(image); - image = 0; + free(texture); + texture = 0; } } } } - return((mg_image_data*)image); + return((mg_texture_data*)texture); } -void mg_mtl_canvas_image_destroy(mg_canvas_backend* backendInterface, mg_image_data* imageInterface) +void mg_mtl_canvas_texture_destroy(mg_canvas_backend* backendInterface, mg_texture_data* textureInterface) { - mg_mtl_image_data* image = (mg_mtl_image_data*)imageInterface; + mg_mtl_texture_data* texture = (mg_mtl_texture_data*)textureInterface; @autoreleasepool { - [image->texture release]; - free(image); + [texture->texture release]; + free(texture); } } -void mg_mtl_canvas_image_upload_region(mg_canvas_backend* backendInterface, mg_image_data* imageInterface, mp_rect region, u8* pixels) +void mg_mtl_canvas_texture_upload_region(mg_canvas_backend* backendInterface, mg_texture_data* textureInterface, mp_rect region, u8* pixels) {@autoreleasepool{ - mg_mtl_image_data* image = (mg_mtl_image_data*)imageInterface; + mg_mtl_texture_data* texture = (mg_mtl_texture_data*)textureInterface; MTLRegion mtlRegion = MTLRegionMake2D(region.x, region.y, region.w, region.h); - [image->texture replaceRegion:mtlRegion + [texture->texture replaceRegion:mtlRegion mipmapLevel:0 withBytes:(void*)pixels bytesPerRow: 4 * region.w]; @@ -410,9 +410,9 @@ mg_canvas_backend* mg_mtl_canvas_create(mg_surface surface) backend->interface.clear = mg_mtl_canvas_clear; backend->interface.drawBatch = mg_mtl_canvas_draw_batch; - backend->interface.imageCreate = mg_mtl_canvas_image_create; - backend->interface.imageDestroy = mg_mtl_canvas_image_destroy; - backend->interface.imageUploadRegion = mg_mtl_canvas_image_upload_region; + backend->interface.textureCreate = mg_mtl_canvas_texture_create; + backend->interface.textureDestroy = mg_mtl_canvas_texture_destroy; + backend->interface.textureUploadRegion = mg_mtl_canvas_texture_upload_region; mp_rect frame = mg_surface_get_frame(surface); backend->viewPort = (mp_rect){0, 0, frame.w, frame.h};