Skip to content

Commit

Permalink
keira: fix Lua image transforms
Browse files Browse the repository at this point in the history
  • Loading branch information
and3rson committed Apr 3, 2024
1 parent 226ce97 commit ac36455
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 85 deletions.
14 changes: 7 additions & 7 deletions firmware/keira/sdcard/test_draw_image.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
print("Printing stuff to console, yay!")

local face = resources.load_image("face.bmp", display.color565(0, 0, 0))
local face = resources.load_image("face.bmp", display.color565(0, 0, 0), 32, 32) -- Image size is 64x64, pivot is at 32, 32

print('Face size: ' .. face.width .. 'x' .. face.height)

Expand All @@ -9,8 +9,8 @@ for i = 10, 1, -1 do
display.set_cursor(64, 64)
display.print("Start in " .. i .. "...")

local x = math.random(240 - 64)
local y = math.random(280 - 64)
local x = math.random(32, display.width - 32)
local y = math.random(32, display.height - 32)
display.draw_image(face, x, y)

display.queue_draw()
Expand All @@ -23,8 +23,8 @@ for i = 10, 1, -1 do
display.set_cursor(64, 64)
display.print("Start in " .. i .. "...")

local x = math.random(240)
local y = math.random(280 - 64)
local x = math.random(32, display.width - 32)
local y = math.random(32, display.height - 32)
local rot = math.random(360)

local scaleX = math.min({ math.random(), 0.1 })
Expand Down Expand Up @@ -52,8 +52,8 @@ while not key.a.just_pressed do
local color = math.random(0xFFFF)
display.draw_line(x1, y1, x2, y2, color)

local x = math.random(240 - 64)
local y = math.random(280 - 64)
local x = math.random(32, display.width - 32)
local y = math.random(32, display.height - 32)
display.draw_image(face, x, y)

display.queue_draw()
Expand Down
48 changes: 2 additions & 46 deletions firmware/keira/src/apps/lua/lualilka_display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,60 +267,16 @@ int lualilka_display_drawImageTransformed(lua_State* L) {
return luaL_error(L, "Invalid image pointer");
}

lilka::Image* image = reinterpret_cast<lilka::Image*>(lua_touserdata(L, -1));
lilka::Image* image = static_cast<lilka::Image*>(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<lilka::Transform**>(luaL_checkudata(L, 4, IMAGE_TRANSFORM));
lilka::Transform* transform = static_cast<lilka::Transform*>(luaL_checkudata(L, 4, IMAGE_TRANSFORM));

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;
}

Expand Down
49 changes: 21 additions & 28 deletions firmware/keira/src/apps/lua/lualilka_imageTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,55 @@
#include "lilka/display.h"

static int lualilka_create_object_imageTransform(lua_State* L) {
*reinterpret_cast<lilka::Transform**>(lua_newuserdata(L, sizeof(lilka::Transform*))) = new lilka::Transform();
lilka::Transform* userdata = static_cast<lilka::Transform*>(lua_newuserdata(L, sizeof(lilka::Transform)));
new (userdata) lilka::Transform();
luaL_setmetatable(L, IMAGE_TRANSFORM);
return 1;
}

static int lualilka_delete_object_imageTransform(lua_State* L) {
lilka::Transform** transformPtr = reinterpret_cast<lilka::Transform**>(luaL_checkudata(L, 1, IMAGE_TRANSFORM));
if (*transformPtr) {
delete *transformPtr;
*transformPtr = nullptr;
} else {
lilka::serial_err("double free of transform %p, should never happen", transformPtr);
}
const lilka::Transform* transformPtr = static_cast<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM));
transformPtr->~Transform();
return 0;
}

static int lualilka_imageTransform_rotate(lua_State* L) {
lilka::Transform* transformPtr = reinterpret_cast<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM));
lilka::Transform* rotatedTransform = new lilka::Transform(transformPtr->rotate(luaL_checknumber(L, 2)));
*reinterpret_cast<lilka::Transform**>(lua_newuserdata(L, sizeof(lilka::Transform))) = rotatedTransform;
lilka::Transform* transformPtr = static_cast<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM));
lilka::Transform* rotatedTransform = static_cast<lilka::Transform*>(lua_newuserdata(L, sizeof(lilka::Transform)));
new (rotatedTransform) lilka::Transform(transformPtr->rotate(luaL_checknumber(L, 2)));
luaL_setmetatable(L, IMAGE_TRANSFORM);
return 1;
}

static int lualilka_imageTransform_scale(lua_State* L) {
lilka::Transform* transformPtr = reinterpret_cast<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM));
lilka::Transform* scaledTransform =
new lilka::Transform(transformPtr->scale(luaL_checknumber(L, 2), luaL_checknumber(L, 3)));
*reinterpret_cast<lilka::Transform**>(lua_newuserdata(L, sizeof(lilka::Transform))) = scaledTransform;
lilka::Transform* transformPtr = static_cast<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM));
lilka::Transform* scaledTransform = static_cast<lilka::Transform*>(lua_newuserdata(L, sizeof(lilka::Transform)));
new (scaledTransform) lilka::Transform(transformPtr->scale(luaL_checknumber(L, 2), luaL_checknumber(L, 3)));
luaL_setmetatable(L, IMAGE_TRANSFORM);
return 1;
}

static int lualilka_imageTransform_multiply(lua_State* L) {
lilka::Transform* transformPtr = reinterpret_cast<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM));
lilka::Transform* multipliedTransfform = new lilka::Transform(
transformPtr->multiply(*reinterpret_cast<lilka::Transform*>(luaL_checkudata(L, 2, IMAGE_TRANSFORM)))
);
*reinterpret_cast<lilka::Transform**>(lua_newuserdata(L, sizeof(lilka::Transform))) = multipliedTransfform;
lilka::Transform* transformPtr = static_cast<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM));
lilka::Transform* multipliedTransfform =
static_cast<lilka::Transform*>(lua_newuserdata(L, sizeof(lilka::Transform)));
new (multipliedTransfform
) lilka::Transform(transformPtr->multiply(*static_cast<lilka::Transform*>(luaL_checkudata(L, 2, IMAGE_TRANSFORM))));
luaL_setmetatable(L, IMAGE_TRANSFORM);
return 1;
}

static int lualilka_imageTransform_inverse(lua_State* L) {
lilka::Transform* transformPtr = reinterpret_cast<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM));
lilka::Transform* inversedTransform = new lilka::Transform(transformPtr->inverse());
*reinterpret_cast<lilka::Transform**>(lua_newuserdata(L, sizeof(lilka::Transform))) = inversedTransform;
lilka::Transform* transformPtr = static_cast<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM));
lilka::Transform* inversedTransform = static_cast<lilka::Transform*>(lua_newuserdata(L, sizeof(lilka::Transform)));
new (inversedTransform) lilka::Transform(transformPtr->inverse());
luaL_setmetatable(L, IMAGE_TRANSFORM);
return 1;
}

static int lualilka_imageTransform_vtransform(lua_State* L) {
lilka::int_vector_t result =
(*reinterpret_cast<lilka::Transform**>(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))
(static_cast<lilka::Transform*>(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);
Expand All @@ -67,9 +62,7 @@ static int lualilka_imageTransform_get_matrix(lua_State* L) {
for (int i = 0; i < 2; ++i) {
lua_newtable(L);
for (int j = 0; j < 2; ++j) {
lua_pushinteger(
L, (*reinterpret_cast<lilka::Transform**>(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->matrix[i][j]
);
lua_pushinteger(L, (static_cast<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->matrix[i][j]);
lua_rawseti(L, -2, j + 1);
}
lua_rawseti(L, -2, i + 1);
Expand All @@ -91,7 +84,7 @@ static int lualilka_imageTransform_set_matrix(lua_State* L) {
return luaL_error(L, "Element at (%d, %d) is not a number", i, j);
}

(*reinterpret_cast<lilka::Transform**>(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->matrix[i][j] =
(static_cast<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->matrix[i][j] =
lua_tonumber(L, -1);
lua_pop(L, 1);
}
Expand Down
13 changes: 11 additions & 2 deletions firmware/keira/src/apps/lua/lualilka_resources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,23 @@ int lualilka_resources_loadImage(lua_State* L) {
transparencyColor = lua_tointeger(L, 2);
}
}
int32_t pivotX = 0;
int32_t pivotY = 0;
if (lua_gettop(L) > 3) {
// Pivot X/Y
pivotX = luaL_checkinteger(L, 3);
pivotY = luaL_checkinteger(L, 4);
}

lilka::Image* image = lilka::resources.loadImage(fullPath, transparencyColor);
lilka::Image* image = lilka::resources.loadImage(fullPath, transparencyColor, pivotX, pivotY);

if (!image) {
return luaL_error(L, "Не вдалося завантажити зображення %s", fullPath.c_str());
}

lilka::serial_log("lua: loaded image %s, width: %d, height: %d", path, image->width, image->height);
lilka::serial_log(
"lua: loaded image %s, size: %d x %d, pivot: %d,%d", path, image->width, image->height, pivotX, pivotY
);

// Append image to images table in registry
lua_getfield(L, LUA_REGISTRYINDEX, "images");
Expand Down
13 changes: 13 additions & 0 deletions sdk/addons/lualilka/library/display.lua
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,19 @@ function display.fill_arc(x, y, r1, r2, start_angle, end_angle, color) end
--- display.draw_image(image, 50, 80) -- малює зображення в точці (50, 80)
function display.draw_image(image, x, y) end

---Малює зображення на екрані з перетворенням.
---@param image table ідентифікатор зображення
---@param x integer координата x лівого верхнього кута зображення
---@param y integer координата y лівого верхнього кута зображення
---@param transform userdata перетворення (TODO: додати опис модуля imageTransform)
---@usage
--- local image = resource.load_image("face.bmp", display.color565(0, 0, 0))
--- local transform = imageTransform()
-- transform = transform:scale(1.5, 0.5)
--- transform = transform:rotate(45)
--- display.draw_image(image, 50, 80, transform) -- малює зображення в точці (50, 80) з перетвореннями
function display.draw_image_transformed(image, x, y, transform) end

---Примусово оновлює вміст екрану.
---
---.. warning:: Ми не радимо використовувати цю функцію. Вона викликається автоматично після кожного виконання ``lilka.draw()``. Вам слід писати весь код малювання всередині своєї функції ``lilka.draw()``, а цю функцію використовувати лише для тестування простих програм.
Expand Down
4 changes: 3 additions & 1 deletion sdk/addons/lualilka/library/resources.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ resources = {}
---
---@param filename string шлях до файлу зображення .BMP (відносно місця знаходження скрипта, що виконується)
---@param transparent_color? integer колір, який буде використаний для прозорості (5-6-5). Якщо цей параметр не вказаний, зображення буде виводитись без прозорості
---@param pivotX? integer X-координата центру зображення (за замовчуванням це середина зображення)
---@param pivotY? integer Y-координата центру зображення (за замовчуванням це середина зображення)
---@return table
---@usage
--- local face = resources.load_image("face.bmp", display.color565(0, 0, 0))
--- print(face.width, face.height) -- Виведе розміри зображення
--- display.draw_image(face, 50, 80) -- Виведе зображення на екран у позицію (50, 80)
function resources.load_image(filename, transparent_color) end
function resources.load_image(filename, transparent_color, pivotX, pivotY) end

---Повертає зображення на певну кількість градусів за годинниковою стрілкою навколо його центру.
---
Expand Down
3 changes: 2 additions & 1 deletion sdk/lib/lilka/src/lilka/menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,8 @@ void Menu::draw(Arduino_GFX* canvas) {
canvas->println(items[i].postfix);
}

int16_t widthAvailable = canvas->width() - 32 - postfixWidth - 8 - 8; // 8 pixels for scrollbar, 8 more for padding
int16_t widthAvailable =
canvas->width() - 32 - postfixWidth - 8 - 8; // 8 pixels for scrollbar, 8 more for padding
if (widthAvailable < 0) {
// No space for title
continue;
Expand Down

0 comments on commit ac36455

Please sign in to comment.