#EditableImage might suck?

1 messages · Page 1 of 1 (latest)

agile hearth
#

Does anyone know why editableImage:WritePixelsBuffer(position, size, someBuffer) will not accept a size where x*y is less than buffer.len(someBuffer) even though I would then be able to reuse the same buffer for smaller writes and not have to cache and potentially continue to dynamically allocate for and write potentially enormous amounts of data every single time? Am I missing some consideration for optimization from Roblox for this that isn't obvious? I am simply trying to figure out what the best method for handling editable images for this purpose.

What I thought would be better was to allow for a smaller size than buffer.len(someBuffer) such that the buffer could be reused after buffer.fill(someBuffer, 0, buffer.len(someBuffer)) and still only need to work with anything smaller than the buffer's size without having to do many dynamic memory calls (malloc/realloc or whatever they use under the hood, maybe it's new/delete idk.) However, the current way of doing this seems to be best for just snapshots rather than something that may change over time, such as an animated editable image.

Moreover, the CPU is in charge, not the GPU, of meddling in these particular draw calls, if I'm not mistaken. Should I utilize parallelization?

#
--!strict

-- Services

local AssetService = game:GetService("AssetService")


-- Module
local Texture = {}

@native
local function barycentric(p: Vector2, a: Vector2, b: Vector2, c: Vector2)
    local v0, v1, v2 = b - a, c - a, p - a
    local d00, d01, d11 = v0:Dot(v0), v0:Dot(v1), v1:Dot(v1)
    local d20, d21 = v2:Dot(v0), v2:Dot(v1)
    local denom = d00 * d11 - d01 * d01
    local v, w = (d11 * d20 - d01 * d21) / denom, (d00 * d21 - d01 * d20) / denom
    local u = 1 - v - w
    return u, v, w
end

@native
function Texture.triangle(texture: EditableImage, data: buffer, a: Vector2, b: Vector2, c: Vector2, color: number)
    local minX, minY = math.min(a.X, b.X, c.X), math.min(a.Y, b.Y, c.Y)
    local maxX, maxY = math.max(a.X, b.X, c.X), math.max(a.Y, b.Y, c.Y)
    local width, height = maxX - minX + 1, maxY - minY + 1
    for y = minY, maxY do
        for x = minX, maxX do
            local u, v, w = barycentric(Vector2.new(x, y), a, b, c)
            local index = ((y - minY) * width + (x - minX)) * 4
            if u >= 0 and v >= 0 and w >= 0 then
                buffer.writeu32(data, index, color)
            else
                buffer.writeu32(data, index, 0)
            end
        end
    end
    texture:WritePixelsBuffer(Vector2.new(minX, minY), Vector2.new(width, height), data)
end

return Texture

Moreover, the above is just a quick thing for rasterization of triangles.

#

I'm curious about feedback and about how to effectively utilize @native

sullen dirge
#

u can slice it into a child buffer, so no extra alloc

#

so like

#
local slice = buffer.create(bytesNeeded); 
buffer.copy(slice, 0, bigBuf, 0, bytesNeeded)
``` u can pass this to WritePixelsBuffer
agile hearth
#

that would have a higher cost if it is what i think it is, unless roblox does its weird magic behind the scenes

#

if it was reusing an object instead of creating a new one, dumping old data into a new one, and then promptly garbage collecting the new one, that is what i would be looking to do

#

but I genuinely have no idea how Roblox handles its stuff in the backend, beit caching or otherwise

sullen dirge
#

it avg benchmarks under 0.1ms and its pretty cheap

#

Parallelization will likely do more harm than good

agile hearth
#
--!strict

-- Services

local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local PlayerGui = Player.PlayerGui

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local EditableImage = require(ReplicatedStorage.EditableImage)
local FrameBuffer = require(ReplicatedStorage.FrameBuffer)
local Texture = require(ReplicatedStorage.Texture)


-- Program

local ScreenGui = PlayerGui:WaitForChild("ScreenGui")

local frameBuffer = FrameBuffer.new()
local texture = EditableImage.new()

Texture.triangle(texture, Vector2.zero, Vector2.new(0, 127), Vector2.new(127, 63), 0xFF0000FF)

local Rotation = 0
game:GetService("RunService").PreRender:Connect(function(deltaTime: number)
    -- Renew scene
    EditableImage.clear(assert(frameBuffer.Image))
    
    -- Draw texture(s)
    --Texture.triangle(texture, Vector2.zero, Vector2.new(0, 127), Vector2.new(127, 63), 0xFF0000FF)
    --frameBuffer:drawTexture(texture, Vector2.new(127, 127))
    frameBuffer:drawTransformedTexture(texture, Vector2.new(127, 127), Vector2.one, Rotation)
    
    -- Update frame buffer
    frameBuffer:flush(ScreenGui.ImageLabel)
    
    -- Renew texture(s)
    --EditableImage.clear(texture)
    Rotation += deltaTime
end)

I have a new issue, which is that drawTransformedTexture (which is literally a wrapper for the actual Roblox built-in DrawImageTransformed) does not actually draw anything, even if Rotation is set to 0.

sullen dirge
#

is the order of the parameters correct for drawTransformedTexture