Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yboichuk/lua/draw image transformed #47

Merged
merged 6 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
88 changes: 80 additions & 8 deletions firmware/keira/src/apps/lua/lualilka_display.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#include "lualilka_display.h"
#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<App*>(lua_touserdata(L, -1));
lua_pop(L, 1);
Expand Down Expand Up @@ -242,17 +243,87 @@ 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;
};

int lualilka_display_drawImageTransformed(lua_State* L) {
// 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");

// 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<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));

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

int lualilka_display_queueDraw(lua_State* L) {
// Get App from registry
lua_getfield(L, LUA_REGISTRYINDEX, "app");
Expand Down Expand Up @@ -284,6 +355,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},
};
Expand Down
123 changes: 123 additions & 0 deletions firmware/keira/src/apps/lua/lualilka_imageTransform.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include "lualilka_imageTransform.h"
#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();
luaL_setmetatable(L, IMAGE_TRANSFORM);
return 1;
}

static int lualilka_delete_object_imageTransform(lua_State* L) {
delete *reinterpret_cast<lilka::Transform**>(lua_touserdata(L, 1));
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 = transformPtr->rotate(luaL_checknumber(L, 2));
*reinterpret_cast<lilka::Transform*>(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<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM));
lilka::Transform scaledTransform = transformPtr->scale(luaL_checknumber(L, 2), luaL_checknumber(L, 3));
*reinterpret_cast<lilka::Transform*>(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<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM));
lilka::Transform multipliedTransfform =
transformPtr->multiply(*reinterpret_cast<lilka::Transform*>(luaL_checkudata(L, 2, IMAGE_TRANSFORM)));
*reinterpret_cast<lilka::Transform*>(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<lilka::Transform*>(luaL_checkudata(L, 1, IMAGE_TRANSFORM));
lilka::Transform inversedTransform = transformPtr->inverse();
*reinterpret_cast<lilka::Transform*>(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<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);
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<lilka::Transform**>(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");

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<lilka::Transform**>(luaL_checkudata(L, 1, IMAGE_TRANSFORM)))->matrix[i][j] =
lua_tonumber(L, -1);
lua_pop(L, 1);
}

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);
return 0;
}
8 changes: 8 additions & 0 deletions firmware/keira/src/apps/lua/lualilka_imageTransform.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

#include <lilka.h>
#include <lua.hpp>

#define IMAGE_TRANSFORM "imageTransform"

int lualilka_imageTransform_register(lua_State* L);
2 changes: 2 additions & 0 deletions firmware/keira/src/apps/lua/luarunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "lualilka_buzzer.h"
#include "lualilka_state.h"
#include "lualilka_wifi.h"
#include "lualilka_imageTransform.h"

jmp_buf stopjmp;

Expand Down Expand Up @@ -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();
Expand Down
Loading