From 93d820a2f441922da6a09dab8199a8b4cf169031 Mon Sep 17 00:00:00 2001 From: Yevhen Boichuk Date: Sat, 23 Mar 2024 18:55:54 +0200 Subject: [PATCH 1/6] Prepare for imageTransform --- .../src/apps/lua/lualilka_imageTransform.cpp | 62 +++++++++++++++++++ .../src/apps/lua/lualilka_imageTransform.h | 6 ++ firmware/keira/src/apps/lua/luarunner.cpp | 2 + 3 files changed, 70 insertions(+) create mode 100644 firmware/keira/src/apps/lua/lualilka_imageTransform.cpp create mode 100644 firmware/keira/src/apps/lua/lualilka_imageTransform.h diff --git a/firmware/keira/src/apps/lua/lualilka_imageTransform.cpp b/firmware/keira/src/apps/lua/lualilka_imageTransform.cpp new file mode 100644 index 00000000..5fd47adb --- /dev/null +++ b/firmware/keira/src/apps/lua/lualilka_imageTransform.cpp @@ -0,0 +1,62 @@ +#include "lualilka_imageTransform.h" +#include "lilka/display.h" + +#define IMAGE_TRANSFORM "imageTransform" + +static int lualilka_imageTransform_rotate(lua_State* L){ + (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->rotate(luaL_checknumber(L, 2)); + return 0; +} + +static int lualilka_imageTransform_scale(lua_State* L){ + (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->scale(luaL_checknumber(L, 2), luaL_checknumber(L, 3)); + return 0; +} + +static int lualilka_imageTransform_multiply(lua_State* L){ + // (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->multiply((*reinterpret_cast(luaL_checkudata(L, 2, IMAGE_TRANSFORM)))); + (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM))).multiply(*reinterpret_cast(luaL_checkudata(L, 2, IMAGE_TRANSFORM))); + + return 0; +} + +// static int myobject_get(lua_State* L){ +// lua_pushnumber(L, (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->get()); +// return 1; +// } + +static int lualilka_create_object_imageTransform(lua_State* L){ + *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform*))) = new lilka::Transform(); + luaL_setmetatable(L, IMAGE_TRANSFORM); + return 1; +} + +static int lualilka_delete_object_imageTransform(lua_State* L){ + delete *reinterpret_cast(lua_touserdata(L, 1)); + return 0; +} + +// static const luaL_Reg lualilka_resources[] = { +// // {"load_image", lualilka_resources_loadImage}, +// // {"rotate_image", lualilka_resources_rotateImage}, +// // {"flip_image_x", lualilka_resources_flipImageX}, +// // {"flip_image_y", lualilka_resources_flipImageY}, +// // {"read_file", lualilka_resources_readFile}, +// // {"write_file", lualilka_resources_writeFile}, +// {NULL, NULL}, +// }; + +int lualilka_imageTransform_register(lua_State* L) { + lua_register(L, IMAGE_TRANSFORM, lualilka_create_object_imageTransform); + luaL_newmetatable(L, IMAGE_TRANSFORM); + lua_pushcfunction(L, lualilka_delete_object_imageTransform); lua_setfield(L, -2, "__gc"); + lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); + // lua_pushcfunction(L, myobject_set); lua_setfield(L, -2, "set"); + // lua_pushcfunction(L, myobject_get); lua_setfield(L, -2, "get"); + lua_pop(L, 1); + + // Create global "resources" table that contains all resources functions + // luaL_newlib(L, lualilka_resources); + // lua_setglobal(L, "imageTransform"); + return 0; +} diff --git a/firmware/keira/src/apps/lua/lualilka_imageTransform.h b/firmware/keira/src/apps/lua/lualilka_imageTransform.h new file mode 100644 index 00000000..a33d11dd --- /dev/null +++ b/firmware/keira/src/apps/lua/lualilka_imageTransform.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +int lualilka_imageTransform_register(lua_State* L); diff --git a/firmware/keira/src/apps/lua/luarunner.cpp b/firmware/keira/src/apps/lua/luarunner.cpp index 8c9fa441..c42e46b1 100644 --- a/firmware/keira/src/apps/lua/luarunner.cpp +++ b/firmware/keira/src/apps/lua/luarunner.cpp @@ -16,6 +16,7 @@ #include "lualilka_buzzer.h" #include "lualilka_state.h" #include "lualilka_wifi.h" +#include "lualilka_imageTransform.h" jmp_buf stopjmp; @@ -157,6 +158,7 @@ void AbstractLuaRunnerApp::luaSetup(const char* dir) { lualilka_util_register(L); lualilka_buzzer_register(L); lualilka_wifi_register(L); + lualilka_imageTransform_register(L); // lilka::serial_log("lua: init canvas"); // lilka::Canvas* canvas = new lilka::Canvas(); From 984cd047c60c6fd4b8b56adf42e94adb96f0de7d Mon Sep 17 00:00:00 2001 From: Yevhen Boichuk Date: Sun, 24 Mar 2024 14:36:00 +0200 Subject: [PATCH 2/6] lua: add interface beetween imageTransform and lua, add draw image with transformation --- firmware/keira/sdcard/test.lua | 25 ++++ .../keira/src/apps/lua/lualilka_display.cpp | 66 +++++++++++ .../src/apps/lua/lualilka_imageTransform.cpp | 111 +++++++++++++----- .../src/apps/lua/lualilka_imageTransform.h | 2 + 4 files changed, 172 insertions(+), 32 deletions(-) diff --git a/firmware/keira/sdcard/test.lua b/firmware/keira/sdcard/test.lua index 9e461880..e1c45a05 100644 --- a/firmware/keira/sdcard/test.lua +++ b/firmware/keira/sdcard/test.lua @@ -18,6 +18,31 @@ for i = 10, 1, -1 do util.sleep(0.25) end +for i = 10, 1, -1 do + display.fill_rect(0, 0, display.width, display.height, math.random(0xFFFF)) + display.set_cursor(64, 64) + display.print("Start in " .. i .. "...") + + local x = math.random(240 ) + local y = math.random(280 - 64) + local rot = math.random(360) + + local scaleX = math.random() + local scaleY = math.random() + + local transform = imageTransform() + + transform = transform:rotate(rot) + + transform = transform:scale(scaleX, scaleY) + + display.draw_image_transformed(face, x, y, transform) + + display.queue_draw() + + util.sleep(0.25) +end + local key = controller.get_state() while not key.a.just_pressed do local x1 = math.random(240) diff --git a/firmware/keira/src/apps/lua/lualilka_display.cpp b/firmware/keira/src/apps/lua/lualilka_display.cpp index 1f1a6120..d81bba1d 100644 --- a/firmware/keira/src/apps/lua/lualilka_display.cpp +++ b/firmware/keira/src/apps/lua/lualilka_display.cpp @@ -1,5 +1,6 @@ #include "lualilka_display.h" #include "app.h" +#include "lualilka_imageTransform.h" Arduino_GFX* getDrawable(lua_State* L) { lua_getfield(L, LUA_REGISTRYINDEX, "app"); @@ -253,6 +254,70 @@ int lualilka_display_drawImage(lua_State* L) { return 0; }; +int lualilka_display_drawImageTransformed(lua_State* L) { + // Args are image table, X & Y + // First argument is table that contains image width, height and pointer. We only need the pointer. + lua_getfield(L, 1, "pointer"); + + // Check if value is a valid pointer + if (!lua_islightuserdata(L, -1)) { + lua_pop(L, 1); // Pop the invalid value + return luaL_error(L, "Invalid image pointer"); + } + + lilka::Image* image = reinterpret_cast(lua_touserdata(L, -1)); + lua_pop(L, 1); // Pop the userdata pointer + + int16_t x = luaL_checknumber(L, 2); + int16_t y = luaL_checknumber(L, 3); + + int32_t imageWidth = image->width; + int32_t imageHeight = image->height; + + lilka::Transform& transform = *reinterpret_cast(luaL_checkudata(L, 4, IMAGE_TRANSFORM)); + + // Calculate the coordinates of the four corners of the destination rectangle. + lilka::int_vector_t v1 = transform.transform(lilka::int_vector_t{-image->pivotX, -image->pivotY}); + lilka::int_vector_t v2 = transform.transform(lilka::int_vector_t{imageWidth - image->pivotX, -image->pivotY}); + lilka::int_vector_t v3 = transform.transform(lilka::int_vector_t{-image->pivotX, imageHeight - image->pivotY}); + lilka::int_vector_t v4 = transform.transform(lilka::int_vector_t{imageWidth - image->pivotX, imageHeight - image->pivotY}); + + // Find the bounding box of the transformed image. + lilka::int_vector_t topLeft = lilka::int_vector_t{min(min(v1.x, v2.x), min(v3.x, v4.x)), min(min(v1.y, v2.y), min(v3.y, v4.y))}; + lilka::int_vector_t bottomRight = + lilka::int_vector_t{max(max(v1.x, v2.x), max(v3.x, v4.x)), max(max(v1.y, v2.y), max(v3.y, v4.y))}; + + // Create a new image to hold the transformed image. + lilka::Image destImage(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y, image->transparentColor, 0, 0); + + // Draw the transformed image to the new image. + lilka::Transform inverse = transform.inverse(); + for (int y = topLeft.y; y < bottomRight.y; y++) { + for (int x = topLeft.x; x < bottomRight.x; x++) { + lilka::int_vector_t v = inverse.transform(lilka::int_vector_t{x, y}); + // Apply pivot offset + v.x += image->pivotX; + v.y += image->pivotY; + if (v.x >= 0 && v.x < image->width && v.y >= 0 && v.y < image->height) { + destImage.pixels[x - topLeft.x + (y - topLeft.y) * destImage.width] = + image->pixels[v.x + v.y * image->width]; + } else { + destImage.pixels[x - topLeft.x + (y - topLeft.y) * destImage.width] = image->transparentColor; + } + } + } + + if (destImage.transparentColor >= 0) { + getDrawable(L)->draw16bitRGBBitmapWithTranColor( + x, y, destImage.pixels, destImage.transparentColor, destImage.width, destImage.height + ); + } else { + getDrawable(L)->draw16bitRGBBitmap(x, y, destImage.pixels, destImage.width, destImage.height); + } + + return 0; +} + int lualilka_display_queueDraw(lua_State* L) { // Get App from registry lua_getfield(L, LUA_REGISTRYINDEX, "app"); @@ -284,6 +349,7 @@ static const luaL_Reg lualilka_display[] = { {"draw_arc", lualilka_display_drawArc}, {"fill_arc", lualilka_display_fillArc}, {"draw_image", lualilka_display_drawImage}, + {"draw_image_transformed", lualilka_display_drawImageTransformed}, {"queue_draw", lualilka_display_queueDraw}, {NULL, NULL}, }; diff --git a/firmware/keira/src/apps/lua/lualilka_imageTransform.cpp b/firmware/keira/src/apps/lua/lualilka_imageTransform.cpp index 5fd47adb..e72ddd3a 100644 --- a/firmware/keira/src/apps/lua/lualilka_imageTransform.cpp +++ b/firmware/keira/src/apps/lua/lualilka_imageTransform.cpp @@ -1,62 +1,109 @@ #include "lualilka_imageTransform.h" #include "lilka/display.h" -#define IMAGE_TRANSFORM "imageTransform" +static int lualilka_create_object_imageTransform(lua_State* L){ + *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform*))) = new lilka::Transform(); + luaL_setmetatable(L, IMAGE_TRANSFORM); + return 1; +} -static int lualilka_imageTransform_rotate(lua_State* L){ - (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->rotate(luaL_checknumber(L, 2)); +static int lualilka_delete_object_imageTransform(lua_State* L){ + delete *reinterpret_cast(lua_touserdata(L, 1)); return 0; } +static int lualilka_imageTransform_rotate(lua_State* L){ + lilka::Transform* transformPtr = reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)); + lilka::Transform rotatedTransform = transformPtr->rotate(luaL_checknumber(L, 2)); + *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform))) = rotatedTransform; + luaL_setmetatable(L, IMAGE_TRANSFORM); + return 1; +} + static int lualilka_imageTransform_scale(lua_State* L){ - (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->scale(luaL_checknumber(L, 2), luaL_checknumber(L, 3)); - return 0; + lilka::Transform* transformPtr = reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)); + lilka::Transform scaledTransform = transformPtr->scale(luaL_checknumber(L, 2), luaL_checknumber(L, 3)); + *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform))) = scaledTransform; + luaL_setmetatable(L, IMAGE_TRANSFORM); + return 1; } static int lualilka_imageTransform_multiply(lua_State* L){ - // (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->multiply((*reinterpret_cast(luaL_checkudata(L, 2, IMAGE_TRANSFORM)))); - (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM))).multiply(*reinterpret_cast(luaL_checkudata(L, 2, IMAGE_TRANSFORM))); + lilka::Transform* transformPtr = reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)); + lilka::Transform multipliedTransfform = transformPtr->multiply(*reinterpret_cast(luaL_checkudata(L, 2, IMAGE_TRANSFORM))); + *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform))) = multipliedTransfform; + luaL_setmetatable(L, IMAGE_TRANSFORM); + return 1; +} - return 0; +static int lualilka_imageTransform_inverse(lua_State* L){ + lilka::Transform* transformPtr = reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)); + lilka::Transform inversedTransform = transformPtr->inverse(); + *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform))) = inversedTransform; + luaL_setmetatable(L, IMAGE_TRANSFORM); + return 1; } -// static int myobject_get(lua_State* L){ -// lua_pushnumber(L, (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->get()); -// return 1; -// } +static int lualilka_imageTransform_vtransform(lua_State* L){ + lilka::int_vector_t result = (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->transform(lilka::int_vector_t {.x = (int) luaL_checknumber(L, 2), .y = (int) luaL_checknumber(L, 3)}); + lua_pushinteger(L, result.x); + lua_pushinteger(L, result.y); + return 2; +} -static int lualilka_create_object_imageTransform(lua_State* L){ - *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform*))) = new lilka::Transform(); - luaL_setmetatable(L, IMAGE_TRANSFORM); +static int lualilka_imageTransform_get_matrix(lua_State* L){ + lua_newtable(L); + for (int i = 0; i < 2; ++i) { + lua_newtable(L); + for (int j = 0; j < 2; ++j) { + lua_pushinteger(L, (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->matrix[i][j]); + lua_rawseti(L, -2, j + 1); + } + lua_rawseti(L, -2, i + 1); + } return 1; } -static int lualilka_delete_object_imageTransform(lua_State* L){ - delete *reinterpret_cast(lua_touserdata(L, 1)); +static int lualilka_imageTransform_set_matrix(lua_State* L){ +if (!lua_istable(L, 1)) { + return luaL_error(L, "Expected a table as the first argument"); + + for (int i = 0; i < 2; ++i) { + lua_rawgeti(L, 1, i + 1); + for (int j = 0; j < 2; ++j) { + lua_rawgeti(L, -1, j + 1); + + if (!lua_isnumber(L, -1)) { + lua_pop(L, 2); + return luaL_error(L, "Element at (%d, %d) is not a number", i, j); + } + + (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->matrix[i][j] = lua_tonumber(L, -1); + lua_pop(L, 1); + } + + lua_pop(L, 1); + } + } return 0; } -// static const luaL_Reg lualilka_resources[] = { -// // {"load_image", lualilka_resources_loadImage}, -// // {"rotate_image", lualilka_resources_rotateImage}, -// // {"flip_image_x", lualilka_resources_flipImageX}, -// // {"flip_image_y", lualilka_resources_flipImageY}, -// // {"read_file", lualilka_resources_readFile}, -// // {"write_file", lualilka_resources_writeFile}, -// {NULL, NULL}, -// }; int lualilka_imageTransform_register(lua_State* L) { lua_register(L, IMAGE_TRANSFORM, lualilka_create_object_imageTransform); luaL_newmetatable(L, IMAGE_TRANSFORM); lua_pushcfunction(L, lualilka_delete_object_imageTransform); lua_setfield(L, -2, "__gc"); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); - // lua_pushcfunction(L, myobject_set); lua_setfield(L, -2, "set"); - // lua_pushcfunction(L, myobject_get); lua_setfield(L, -2, "get"); + + lua_pushcfunction(L, lualilka_imageTransform_set_matrix); lua_setfield(L, -2, "set"); + lua_pushcfunction(L, lualilka_imageTransform_get_matrix); lua_setfield(L, -2, "get"); + + lua_pushcfunction(L, lualilka_imageTransform_scale); lua_setfield(L, -2, "scale"); + lua_pushcfunction(L, lualilka_imageTransform_rotate); lua_setfield(L, -2, "rotate"); + lua_pushcfunction(L, lualilka_imageTransform_multiply); lua_setfield(L, -2, "multiply"); + lua_pushcfunction(L, lualilka_imageTransform_inverse); lua_setfield(L, -2, "inverse"); + lua_pushcfunction(L, lualilka_imageTransform_vtransform); lua_setfield(L, -2, "vtransform"); + lua_pop(L, 1); - - // Create global "resources" table that contains all resources functions - // luaL_newlib(L, lualilka_resources); - // lua_setglobal(L, "imageTransform"); return 0; } diff --git a/firmware/keira/src/apps/lua/lualilka_imageTransform.h b/firmware/keira/src/apps/lua/lualilka_imageTransform.h index a33d11dd..9c3a3f95 100644 --- a/firmware/keira/src/apps/lua/lualilka_imageTransform.h +++ b/firmware/keira/src/apps/lua/lualilka_imageTransform.h @@ -3,4 +3,6 @@ #include #include +#define IMAGE_TRANSFORM "imageTransform" + int lualilka_imageTransform_register(lua_State* L); From e46da3e3834d4cb9d92c4aaec4f0df9a7edb794e Mon Sep 17 00:00:00 2001 From: Yevhen Boichuk Date: Sun, 24 Mar 2024 14:37:54 +0200 Subject: [PATCH 3/6] Change name for test lua script what test draw function, fix cpp check --- .../sdcard/{test.lua => test_draw_image.lua} | 0 .../src/apps/lua/lualilka_imageTransform.cpp | 176 ++++++++++-------- 2 files changed, 95 insertions(+), 81 deletions(-) rename firmware/keira/sdcard/{test.lua => test_draw_image.lua} (100%) diff --git a/firmware/keira/sdcard/test.lua b/firmware/keira/sdcard/test_draw_image.lua similarity index 100% rename from firmware/keira/sdcard/test.lua rename to firmware/keira/sdcard/test_draw_image.lua diff --git a/firmware/keira/src/apps/lua/lualilka_imageTransform.cpp b/firmware/keira/src/apps/lua/lualilka_imageTransform.cpp index e72ddd3a..7b78e402 100644 --- a/firmware/keira/src/apps/lua/lualilka_imageTransform.cpp +++ b/firmware/keira/src/apps/lua/lualilka_imageTransform.cpp @@ -1,109 +1,123 @@ #include "lualilka_imageTransform.h" #include "lilka/display.h" -static int lualilka_create_object_imageTransform(lua_State* L){ - *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform*))) = new lilka::Transform(); - luaL_setmetatable(L, IMAGE_TRANSFORM); - return 1; +static int lualilka_create_object_imageTransform(lua_State* L) { + *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform*))) = new lilka::Transform(); + luaL_setmetatable(L, IMAGE_TRANSFORM); + return 1; } -static int lualilka_delete_object_imageTransform(lua_State* L){ - delete *reinterpret_cast(lua_touserdata(L, 1)); - return 0; +static int lualilka_delete_object_imageTransform(lua_State* L) { + delete *reinterpret_cast(lua_touserdata(L, 1)); + return 0; } -static int lualilka_imageTransform_rotate(lua_State* L){ - lilka::Transform* transformPtr = reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)); - lilka::Transform rotatedTransform = transformPtr->rotate(luaL_checknumber(L, 2)); - *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform))) = rotatedTransform; - luaL_setmetatable(L, IMAGE_TRANSFORM); - return 1; +static int lualilka_imageTransform_rotate(lua_State* L) { + lilka::Transform* transformPtr = reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)); + lilka::Transform rotatedTransform = transformPtr->rotate(luaL_checknumber(L, 2)); + *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform))) = rotatedTransform; + luaL_setmetatable(L, IMAGE_TRANSFORM); + return 1; } -static int lualilka_imageTransform_scale(lua_State* L){ - lilka::Transform* transformPtr = reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)); - lilka::Transform scaledTransform = transformPtr->scale(luaL_checknumber(L, 2), luaL_checknumber(L, 3)); - *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform))) = scaledTransform; - luaL_setmetatable(L, IMAGE_TRANSFORM); - return 1; +static int lualilka_imageTransform_scale(lua_State* L) { + lilka::Transform* transformPtr = reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)); + lilka::Transform scaledTransform = transformPtr->scale(luaL_checknumber(L, 2), luaL_checknumber(L, 3)); + *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform))) = scaledTransform; + luaL_setmetatable(L, IMAGE_TRANSFORM); + return 1; } -static int lualilka_imageTransform_multiply(lua_State* L){ - lilka::Transform* transformPtr = reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)); - lilka::Transform multipliedTransfform = transformPtr->multiply(*reinterpret_cast(luaL_checkudata(L, 2, IMAGE_TRANSFORM))); - *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform))) = multipliedTransfform; - luaL_setmetatable(L, IMAGE_TRANSFORM); - return 1; +static int lualilka_imageTransform_multiply(lua_State* L) { + lilka::Transform* transformPtr = reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)); + lilka::Transform multipliedTransfform = + transformPtr->multiply(*reinterpret_cast(luaL_checkudata(L, 2, IMAGE_TRANSFORM))); + *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform))) = multipliedTransfform; + luaL_setmetatable(L, IMAGE_TRANSFORM); + return 1; } -static int lualilka_imageTransform_inverse(lua_State* L){ - lilka::Transform* transformPtr = reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)); - lilka::Transform inversedTransform = transformPtr->inverse(); - *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform))) = inversedTransform; - luaL_setmetatable(L, IMAGE_TRANSFORM); - return 1; +static int lualilka_imageTransform_inverse(lua_State* L) { + lilka::Transform* transformPtr = reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)); + lilka::Transform inversedTransform = transformPtr->inverse(); + *reinterpret_cast(lua_newuserdata(L, sizeof(lilka::Transform))) = inversedTransform; + luaL_setmetatable(L, IMAGE_TRANSFORM); + return 1; } -static int lualilka_imageTransform_vtransform(lua_State* L){ - lilka::int_vector_t result = (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->transform(lilka::int_vector_t {.x = (int) luaL_checknumber(L, 2), .y = (int) luaL_checknumber(L, 3)}); - lua_pushinteger(L, result.x); - lua_pushinteger(L, result.y); - return 2; +static int lualilka_imageTransform_vtransform(lua_State* L) { + lilka::int_vector_t result = + (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM))) + ->transform(lilka::int_vector_t{.x = (int)luaL_checknumber(L, 2), .y = (int)luaL_checknumber(L, 3)}); + lua_pushinteger(L, result.x); + lua_pushinteger(L, result.y); + return 2; } -static int lualilka_imageTransform_get_matrix(lua_State* L){ - lua_newtable(L); - for (int i = 0; i < 2; ++i) { - lua_newtable(L); - for (int j = 0; j < 2; ++j) { - lua_pushinteger(L, (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->matrix[i][j]); - lua_rawseti(L, -2, j + 1); - } - lua_rawseti(L, -2, i + 1); - } - return 1; +static int lualilka_imageTransform_get_matrix(lua_State* L) { + lua_newtable(L); + for (int i = 0; i < 2; ++i) { + lua_newtable(L); + for (int j = 0; j < 2; ++j) { + lua_pushinteger( + L, (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->matrix[i][j] + ); + lua_rawseti(L, -2, j + 1); + } + lua_rawseti(L, -2, i + 1); + } + return 1; } -static int lualilka_imageTransform_set_matrix(lua_State* L){ -if (!lua_istable(L, 1)) { - return luaL_error(L, "Expected a table as the first argument"); +static int lualilka_imageTransform_set_matrix(lua_State* L) { + if (!lua_istable(L, 1)) { + return luaL_error(L, "Expected a table as the first argument"); - for (int i = 0; i < 2; ++i) { - lua_rawgeti(L, 1, i + 1); - for (int j = 0; j < 2; ++j) { - lua_rawgeti(L, -1, j + 1); + for (int i = 0; i < 2; ++i) { + lua_rawgeti(L, 1, i + 1); + for (int j = 0; j < 2; ++j) { + lua_rawgeti(L, -1, j + 1); - if (!lua_isnumber(L, -1)) { - lua_pop(L, 2); - return luaL_error(L, "Element at (%d, %d) is not a number", i, j); - } + if (!lua_isnumber(L, -1)) { + lua_pop(L, 2); + return luaL_error(L, "Element at (%d, %d) is not a number", i, j); + } - (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->matrix[i][j] = lua_tonumber(L, -1); - lua_pop(L, 1); - } + (*reinterpret_cast(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->matrix[i][j] = + lua_tonumber(L, -1); + lua_pop(L, 1); + } - lua_pop(L, 1); - } - } - return 0; + lua_pop(L, 1); + } + } + return 0; } - int lualilka_imageTransform_register(lua_State* L) { - lua_register(L, IMAGE_TRANSFORM, lualilka_create_object_imageTransform); - luaL_newmetatable(L, IMAGE_TRANSFORM); - lua_pushcfunction(L, lualilka_delete_object_imageTransform); lua_setfield(L, -2, "__gc"); - lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); - - lua_pushcfunction(L, lualilka_imageTransform_set_matrix); lua_setfield(L, -2, "set"); - lua_pushcfunction(L, lualilka_imageTransform_get_matrix); lua_setfield(L, -2, "get"); - - lua_pushcfunction(L, lualilka_imageTransform_scale); lua_setfield(L, -2, "scale"); - lua_pushcfunction(L, lualilka_imageTransform_rotate); lua_setfield(L, -2, "rotate"); - lua_pushcfunction(L, lualilka_imageTransform_multiply); lua_setfield(L, -2, "multiply"); - lua_pushcfunction(L, lualilka_imageTransform_inverse); lua_setfield(L, -2, "inverse"); - lua_pushcfunction(L, lualilka_imageTransform_vtransform); lua_setfield(L, -2, "vtransform"); - - lua_pop(L, 1); + lua_register(L, IMAGE_TRANSFORM, lualilka_create_object_imageTransform); + luaL_newmetatable(L, IMAGE_TRANSFORM); + lua_pushcfunction(L, lualilka_delete_object_imageTransform); + lua_setfield(L, -2, "__gc"); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, lualilka_imageTransform_set_matrix); + lua_setfield(L, -2, "set"); + lua_pushcfunction(L, lualilka_imageTransform_get_matrix); + lua_setfield(L, -2, "get"); + + lua_pushcfunction(L, lualilka_imageTransform_scale); + lua_setfield(L, -2, "scale"); + lua_pushcfunction(L, lualilka_imageTransform_rotate); + lua_setfield(L, -2, "rotate"); + lua_pushcfunction(L, lualilka_imageTransform_multiply); + lua_setfield(L, -2, "multiply"); + lua_pushcfunction(L, lualilka_imageTransform_inverse); + lua_setfield(L, -2, "inverse"); + lua_pushcfunction(L, lualilka_imageTransform_vtransform); + lua_setfield(L, -2, "vtransform"); + + lua_pop(L, 1); return 0; } From 301ffded433a297f91530e7a96cfdcd2186e9d23 Mon Sep 17 00:00:00 2001 From: Yevhen Boichuk Date: Sun, 24 Mar 2024 14:44:33 +0200 Subject: [PATCH 4/6] fixes: --- firmware/keira/src/apps/lua/lualilka_display.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/firmware/keira/src/apps/lua/lualilka_display.cpp b/firmware/keira/src/apps/lua/lualilka_display.cpp index d81bba1d..60a76b4a 100644 --- a/firmware/keira/src/apps/lua/lualilka_display.cpp +++ b/firmware/keira/src/apps/lua/lualilka_display.cpp @@ -268,8 +268,8 @@ int lualilka_display_drawImageTransformed(lua_State* L) { lilka::Image* image = reinterpret_cast(lua_touserdata(L, -1)); lua_pop(L, 1); // Pop the userdata pointer - int16_t x = luaL_checknumber(L, 2); - int16_t y = luaL_checknumber(L, 3); + int16_t d_x = luaL_checknumber(L, 2); + int16_t d_y = luaL_checknumber(L, 3); int32_t imageWidth = image->width; int32_t imageHeight = image->height; @@ -280,12 +280,14 @@ int lualilka_display_drawImageTransformed(lua_State* L) { lilka::int_vector_t v1 = transform.transform(lilka::int_vector_t{-image->pivotX, -image->pivotY}); lilka::int_vector_t v2 = transform.transform(lilka::int_vector_t{imageWidth - image->pivotX, -image->pivotY}); lilka::int_vector_t v3 = transform.transform(lilka::int_vector_t{-image->pivotX, imageHeight - image->pivotY}); - lilka::int_vector_t v4 = transform.transform(lilka::int_vector_t{imageWidth - image->pivotX, imageHeight - image->pivotY}); + lilka::int_vector_t v4 = + transform.transform(lilka::int_vector_t{imageWidth - image->pivotX, imageHeight - image->pivotY}); // Find the bounding box of the transformed image. - lilka::int_vector_t topLeft = lilka::int_vector_t{min(min(v1.x, v2.x), min(v3.x, v4.x)), min(min(v1.y, v2.y), min(v3.y, v4.y))}; + lilka::int_vector_t topLeft = + lilka::int_vector_t{min(min(v1.x, v2.x), min(v3.x, v4.x)), min(min(v1.y, v2.y), min(v3.y, v4.y))}; lilka::int_vector_t bottomRight = - lilka::int_vector_t{max(max(v1.x, v2.x), max(v3.x, v4.x)), max(max(v1.y, v2.y), max(v3.y, v4.y))}; + lilka::int_vector_t{max(max(v1.x, v2.x), max(v3.x, v4.x)), max(max(v1.y, v2.y), max(v3.y, v4.y))}; // Create a new image to hold the transformed image. lilka::Image destImage(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y, image->transparentColor, 0, 0); @@ -309,10 +311,10 @@ int lualilka_display_drawImageTransformed(lua_State* L) { if (destImage.transparentColor >= 0) { getDrawable(L)->draw16bitRGBBitmapWithTranColor( - x, y, destImage.pixels, destImage.transparentColor, destImage.width, destImage.height + d_x, d_y, destImage.pixels, destImage.transparentColor, destImage.width, destImage.height ); } else { - getDrawable(L)->draw16bitRGBBitmap(x, y, destImage.pixels, destImage.width, destImage.height); + getDrawable(L)->draw16bitRGBBitmap(d_x, d_y, destImage.pixels, destImage.width, destImage.height); } return 0; From 62e73e6e0119bf3039031092c114eb2227ee1444 Mon Sep 17 00:00:00 2001 From: Yevhen Boichuk Date: Sun, 24 Mar 2024 18:56:05 +0200 Subject: [PATCH 5/6] fix one comment on code --- firmware/keira/src/apps/lua/lualilka_display.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/keira/src/apps/lua/lualilka_display.cpp b/firmware/keira/src/apps/lua/lualilka_display.cpp index 60a76b4a..863691a0 100644 --- a/firmware/keira/src/apps/lua/lualilka_display.cpp +++ b/firmware/keira/src/apps/lua/lualilka_display.cpp @@ -255,7 +255,7 @@ int lualilka_display_drawImage(lua_State* L) { }; int lualilka_display_drawImageTransformed(lua_State* L) { - // Args are image table, X & Y + // Args are image table, X & Y, imageTransform object // First argument is table that contains image width, height and pointer. We only need the pointer. lua_getfield(L, 1, "pointer"); From 8114a4de9f16da7e6776db681f7dc9568a32d571 Mon Sep 17 00:00:00 2001 From: Yevhen Boichuk Date: Mon, 25 Mar 2024 18:59:06 +0200 Subject: [PATCH 6/6] Fix code to useless code --- .../keira/src/apps/lua/lualilka_display.cpp | 108 +++++++++--------- 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/firmware/keira/src/apps/lua/lualilka_display.cpp b/firmware/keira/src/apps/lua/lualilka_display.cpp index 863691a0..8b1289eb 100644 --- a/firmware/keira/src/apps/lua/lualilka_display.cpp +++ b/firmware/keira/src/apps/lua/lualilka_display.cpp @@ -2,7 +2,7 @@ #include "app.h" #include "lualilka_imageTransform.h" -Arduino_GFX* getDrawable(lua_State* L) { +lilka::Canvas* getDrawable(lua_State* L) { lua_getfield(L, LUA_REGISTRYINDEX, "app"); const App* app = static_cast(lua_touserdata(L, -1)); lua_pop(L, 1); @@ -243,13 +243,15 @@ int lualilka_display_drawImage(lua_State* L) { int16_t x = luaL_checknumber(L, 2); int16_t y = luaL_checknumber(L, 3); - if (image->transparentColor >= 0) { - getDrawable(L)->draw16bitRGBBitmapWithTranColor( - x, y, image->pixels, image->transparentColor, image->width, image->height - ); - } else { - getDrawable(L)->draw16bitRGBBitmap(x, y, image->pixels, image->width, image->height); - } + getDrawable(L)->drawImage(image, x, y); + + // if (image->transparentColor >= 0) { + // getDrawable(L)->draw16bitRGBBitmapWithTranColor( + // x, y, image->pixels, image->transparentColor, image->width, image->height + // ); + // } else { + // getDrawable(L)->draw16bitRGBBitmap(x, y, image->pixels, image->width, image->height); + // } return 0; }; @@ -268,54 +270,56 @@ int lualilka_display_drawImageTransformed(lua_State* L) { lilka::Image* image = reinterpret_cast(lua_touserdata(L, -1)); lua_pop(L, 1); // Pop the userdata pointer - int16_t d_x = luaL_checknumber(L, 2); - int16_t d_y = luaL_checknumber(L, 3); + int16_t x = luaL_checknumber(L, 2); + int16_t y = luaL_checknumber(L, 3); - int32_t imageWidth = image->width; - int32_t imageHeight = image->height; + // int32_t imageWidth = image->width; + // int32_t imageHeight = image->height; lilka::Transform& transform = *reinterpret_cast(luaL_checkudata(L, 4, IMAGE_TRANSFORM)); - // Calculate the coordinates of the four corners of the destination rectangle. - lilka::int_vector_t v1 = transform.transform(lilka::int_vector_t{-image->pivotX, -image->pivotY}); - lilka::int_vector_t v2 = transform.transform(lilka::int_vector_t{imageWidth - image->pivotX, -image->pivotY}); - lilka::int_vector_t v3 = transform.transform(lilka::int_vector_t{-image->pivotX, imageHeight - image->pivotY}); - lilka::int_vector_t v4 = - transform.transform(lilka::int_vector_t{imageWidth - image->pivotX, imageHeight - image->pivotY}); - - // Find the bounding box of the transformed image. - lilka::int_vector_t topLeft = - lilka::int_vector_t{min(min(v1.x, v2.x), min(v3.x, v4.x)), min(min(v1.y, v2.y), min(v3.y, v4.y))}; - lilka::int_vector_t bottomRight = - lilka::int_vector_t{max(max(v1.x, v2.x), max(v3.x, v4.x)), max(max(v1.y, v2.y), max(v3.y, v4.y))}; - - // Create a new image to hold the transformed image. - lilka::Image destImage(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y, image->transparentColor, 0, 0); - - // Draw the transformed image to the new image. - lilka::Transform inverse = transform.inverse(); - for (int y = topLeft.y; y < bottomRight.y; y++) { - for (int x = topLeft.x; x < bottomRight.x; x++) { - lilka::int_vector_t v = inverse.transform(lilka::int_vector_t{x, y}); - // Apply pivot offset - v.x += image->pivotX; - v.y += image->pivotY; - if (v.x >= 0 && v.x < image->width && v.y >= 0 && v.y < image->height) { - destImage.pixels[x - topLeft.x + (y - topLeft.y) * destImage.width] = - image->pixels[v.x + v.y * image->width]; - } else { - destImage.pixels[x - topLeft.x + (y - topLeft.y) * destImage.width] = image->transparentColor; - } - } - } - - if (destImage.transparentColor >= 0) { - getDrawable(L)->draw16bitRGBBitmapWithTranColor( - d_x, d_y, destImage.pixels, destImage.transparentColor, destImage.width, destImage.height - ); - } else { - getDrawable(L)->draw16bitRGBBitmap(d_x, d_y, destImage.pixels, destImage.width, destImage.height); - } + getDrawable(L)->drawImageTransformed(image, x, y, transform); + + // // Calculate the coordinates of the four corners of the destination rectangle. + // lilka::int_vector_t v1 = transform.transform(lilka::int_vector_t{-image->pivotX, -image->pivotY}); + // lilka::int_vector_t v2 = transform.transform(lilka::int_vector_t{imageWidth - image->pivotX, -image->pivotY}); + // lilka::int_vector_t v3 = transform.transform(lilka::int_vector_t{-image->pivotX, imageHeight - image->pivotY}); + // lilka::int_vector_t v4 = + // transform.transform(lilka::int_vector_t{imageWidth - image->pivotX, imageHeight - image->pivotY}); + + // // Find the bounding box of the transformed image. + // lilka::int_vector_t topLeft = + // lilka::int_vector_t{min(min(v1.x, v2.x), min(v3.x, v4.x)), min(min(v1.y, v2.y), min(v3.y, v4.y))}; + // lilka::int_vector_t bottomRight = + // lilka::int_vector_t{max(max(v1.x, v2.x), max(v3.x, v4.x)), max(max(v1.y, v2.y), max(v3.y, v4.y))}; + + // // Create a new image to hold the transformed image. + // lilka::Image destImage(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y, image->transparentColor, 0, 0); + + // // Draw the transformed image to the new image. + // lilka::Transform inverse = transform.inverse(); + // for (int y = topLeft.y; y < bottomRight.y; y++) { + // for (int x = topLeft.x; x < bottomRight.x; x++) { + // lilka::int_vector_t v = inverse.transform(lilka::int_vector_t{x, y}); + // // Apply pivot offset + // v.x += image->pivotX; + // v.y += image->pivotY; + // if (v.x >= 0 && v.x < image->width && v.y >= 0 && v.y < image->height) { + // destImage.pixels[x - topLeft.x + (y - topLeft.y) * destImage.width] = + // image->pixels[v.x + v.y * image->width]; + // } else { + // destImage.pixels[x - topLeft.x + (y - topLeft.y) * destImage.width] = image->transparentColor; + // } + // } + // } + + // if (destImage.transparentColor >= 0) { + // getDrawable(L)->draw16bitRGBBitmapWithTranColor( + // d_x, d_y, destImage.pixels, destImage.transparentColor, destImage.width, destImage.height + // ); + // } else { + // getDrawable(L)->draw16bitRGBBitmap(d_x, d_y, destImage.pixels, destImage.width, destImage.height); + // } return 0; }