zeta0134 / LuaGB

A gameboy emulator written in pure Lua. Work in progress.
BSD 3-Clause "New" or "Revised" License
412 stars 35 forks source link

Two requests: copy mGBA's API, and use cdata instead of tables #10

Open N64N64 opened 7 years ago

N64N64 commented 7 years ago

Hi. Thank you for making this. This is amazing.

I am currently making a hack of pokered in Lua, and am using an edit of mGBA with it. I really want to integrate this project into my code as another emulator backend but there are a few things stopping me right now:

The reason why I need C data structures is because I use pointer arithmetic to lookup values in ROM from banks and symbol tables and stuff like that.

I understand the want for it to be in PUC Lua but I think for development's (and speed's) sake it would be better to use ffi datastructures?

zeta0134 commented 7 years ago

Greetings N64N64,

Concerning the API: I could not possibly agree more, and fleshing the API out is one of the longer term goals of the project. One of my core goals with this project is for it to be easy to interface with, and any improvements I can make on that front are welcome. This is very much an alpha release right now, and everything's in flux and subject to change, so I haven't been as focused on nailing down the external interface.

Concerning FFI: While I don't mind using a little bit of this in the Love2D shell, and in any other frontends for specific platforms, I'm very firm in my belief that the core gameboy module should run in pure Lua. That's a core goal of this project, as I do intend to port it to platforms where FFI isn't available, and I won't compromise on it. You're welcome to fork it and add FFI support to the internal structures (might want to wait a bit for the code structure to settle down, as it's still in flux) but I won't incorporate those changes back into the pure LuaGB repository, even as an optional feature.

N64N64 commented 7 years ago

What if you made it transparent through metatables? For example:

ffi = {}

local function boundscheck(i, siz)
    if i < 0 or i >= siz then
        error('segmentation fault')
    else
        return true
    end
end

local function fake_cdata(self, siz, offset)
    local t = {__self = self, __siz = siz, __offset = offset}
    setmetatable(t, {
        __index = function(_, k)
            boundscheck(offset + k, siz)
            return self[offset + k] or error('garbage data')
        end,
        __newindex = function(_, k, v)
            boundscheck(offset + k, siz)
            self[offset + k] = v
        end,
        __add = function(a, b)
            local i
            if a == t then
                i = b
            else
                i = a
            end
            return fake_cdata(self, siz, offset + i)
        end,
        __sub = function(a, i)
            assert(a == t)
            return fake_cdata(self, siz, offset - i)
        end,
    })
    return t
end

function ffi.new(ctype, siz)
    assert(ctype == 'uint8_t[?]') -- probably all youd ever use in a gameboy emulator
    return fake_cdata({}, siz, 0)
end

function ffi.sizeof(cdata)
    return cdata.__siz
end

function ffi.copy(dst, src, len)
    for i=0,len-1 do
        dst[i] = src[i]
    end
end

function ffi.fill(dst, len, c)
    c = c or 0

    for i=0,len-1 do
        dst[i] = c
    end
end

That way, it can still be in PUC Lua, and you'd get a nice performance boost on platforms that support the FFI. And, the added bonus of being able to use pointer arithmetic!