I have funtion screen_to_pixel, use case of this funtion - Handle Coordinate Mapping: Convert mouse/touch screen coordinates into local pixel coordinates x, y of the GUI node. This must account for the node’s screen position, scale, and pivot point (assuming Center pivot), window size to ensure the click aligns perfectly with the underlying pixel data.
My Issue - But as gui node is adjust to fit and when window is resize to different size than the project display size than mouse touch coordinate misalign with pixel coordinated. So i need solution for this.
-- Configuration: Use the same name as your GUI node
local CANVAS_NODE_NAME = "canvas"
local TEXTURE_NAME = "canvas_tx"
local function is_transparent(r, g, b, a)
return a == 0
end
local function is_black_outline(r, g, b, a)
return a > 0 and r < 20 and g < 20 and b < 20
end
local function is_white_fillable(r, g, b, a)
return a > 0 and r > 240 and g > 240 and b > 240
end
-- Helper to get pixel color from stream
local function get_pixel(stream, x, y, width)
local i = (y * width + x) * 4 + 1
return stream[i], stream[i+1], stream[i+2], stream[i+3]
end
-- Flood Fill Algorithm (Queue-based)
local function flood_fill(self, sx, sy, fr, fg, fb)
local w, h = self.width, self.height
local stream = self.stream
local function idx(x, y)
return (y * w + x) * 4 + 1
end
local sr, sg, sb, sa = get_pixel(stream, sx, sy, w)
-- Only allow fill if starting pixel is white
if not is_white_fillable(sr, sg, sb, sa) then
return
end
local queue_x = {}
local queue_y = {}
local qh, qt = 1, 1
queue_x[1] = sx
queue_y[1] = sy
while qh <= qt do
local x = queue_x[qh]
local y = queue_y[qh]
qh = qh + 1
if x >= 0 and x < w and y >= 0 and y < h then
local i = idx(x, y)
local r = stream[i]
local g = stream[i + 1]
local b = stream[i + 2]
local a = stream[i + 3]
-- Only fill white pixels
if is_white_fillable(r, g, b, a) then
-- Paint
stream[i] = fr
stream[i + 1] = fg
stream[i + 2] = fb
stream[i + 3] = 255
qt = qt + 1; queue_x[qt] = x + 1; queue_y[qt] = y
qt = qt + 1; queue_x[qt] = x - 1; queue_y[qt] = y
qt = qt + 1; queue_x[qt] = x; queue_y[qt] = y + 1
qt = qt + 1; queue_x[qt] = x; queue_y[qt] = y - 1
end
end
end
end
function init(self)
msg.post(".", "acquire_input_focus")
self.canvas_node = gui.get_node(CANVAS_NODE_NAME)
-- Load Image Resource
local image_src = "/game/level_selector/images/outline.png"
local data = sys.load_resource(image_src)
local img = image.load(data)
self.width = img.width
self.height = img.height
-- Setup editable buffer (RGBA)
self.buffer = buffer.create(self.width * self.height, {
{ name = hash("rgba"), type = buffer.VALUE_TYPE_UINT8, count = 4 }
})
self.stream = buffer.get_stream(self.buffer, hash("rgba"))
-- Copy initial image into our stream
local src_bytes = img.buffer
for i = 1, #src_bytes do
self.stream[i] = string.byte(src_bytes, i)
end
gui.new_texture("canvas_tx", self.width, self.height, "rgba", img.buffer)
gui.set_texture(self.canvas_node, TEXTURE_NAME)
end
local function screen_to_pixel(self, action)
local node = self.canvas_node
local pos = gui.get_position(node)
local size = gui.get_size(node)
local scale = gui.get_scale(node)
local w = size.x * scale.x
local h = size.y * scale.y
local left = pos.x - w * 0.5
local bottom = pos.y - h * 0.5
local nx = (action.x - left) / w
local ny = (action.y - bottom) / h
if nx < 0 or nx > 1 or ny < 0 or ny > 1 then
return nil
end
local px = math.floor(nx * self.width)
local py = math.floor((1.0 - ny) * self.height)
return px, py
end
function on_input(self, action_id, action)
if action_id == hash("touch") and action.pressed then
local px, py = screen_to_pixel(self, action)
if not px then return end
flood_fill(self, px, py, 255, 0, 0)
gui.set_texture_data(
TEXTURE_NAME,
self.width,
self.height,
"rgba",
buffer.get_bytes(self.buffer, true)
)
end
end
Here in image you can see missalignment pointer was outside of red fill portion.
