mirror of
https://github.com/airstruck/luigi.git
synced 2025-11-18 12:25:06 +00:00
332 lines
9.2 KiB
Lua
332 lines
9.2 KiB
Lua
local ROOT = (...):gsub('[^.]*.[^.]*$', '')
|
|
|
|
local Hooker = require(ROOT .. 'hooker')
|
|
|
|
local ffi = require 'ffi'
|
|
local sdl = require((...) .. '.sdl')
|
|
|
|
local Image = require((...) .. '.image')
|
|
local Font = require((...) .. '.font')
|
|
local Keyboard = require((...) .. '.keyboard')
|
|
local Text = require((...) .. '.text')
|
|
|
|
local IntOut = ffi.typeof 'int[1]'
|
|
|
|
-- create window and renderer
|
|
sdl.setHint(sdl.HINT_VIDEO_ALLOW_SCREENSAVER, '1')
|
|
|
|
local window = sdl.createWindow('', 0, 0, 800, 600,
|
|
sdl.WINDOW_SHOWN + sdl.WINDOW_RESIZABLE)
|
|
|
|
if window == nil then
|
|
error(ffi.string(sdl.getError()))
|
|
end
|
|
|
|
ffi.gc(window, sdl.destroyWindow)
|
|
|
|
local renderer = sdl.createRenderer(window, -1,
|
|
sdl.RENDERER_ACCELERATED + sdl.RENDERER_PRESENTVSYNC)
|
|
|
|
if renderer == nil then
|
|
error(ffi.string(sdl.getError()))
|
|
end
|
|
|
|
ffi.gc(renderer, sdl.destroyRenderer)
|
|
|
|
local Backend = {}
|
|
|
|
Backend.sdl = sdl
|
|
|
|
local callback = {
|
|
draw = function () end,
|
|
resize = function () end,
|
|
mousepressed = function () end,
|
|
mousereleased = function () end,
|
|
mousemoved = function () end,
|
|
keypressed = function () end,
|
|
keyreleased = function () end,
|
|
textinput = function () end,
|
|
wheelmoved = function () end,
|
|
}
|
|
|
|
Backend.run = function ()
|
|
local event = sdl.Event()
|
|
|
|
while true do
|
|
sdl.pumpEvents()
|
|
|
|
while sdl.pollEvent(event) ~= 0 do
|
|
if event.type == sdl.QUIT then
|
|
return
|
|
elseif event.type == sdl.WINDOWEVENT
|
|
and event.window.event == sdl.WINDOWEVENT_RESIZED then
|
|
local window = event.window
|
|
callback.resize(window.data1, window.data2)
|
|
elseif event.type == sdl.MOUSEBUTTONDOWN then
|
|
local button = event.button
|
|
callback.mousepressed(button.x, button.y, button.button)
|
|
elseif event.type == sdl.MOUSEBUTTONUP then
|
|
local button = event.button
|
|
callback.mousereleased(button.x, button.y, button.button)
|
|
elseif event.type == sdl.MOUSEMOTION then
|
|
local motion = event.motion
|
|
callback.mousemoved(motion.x, motion.y)
|
|
elseif event.type == sdl.KEYDOWN then
|
|
local key = Keyboard.stringByKeycode[event.key.keysym.sym]
|
|
callback.keypressed(key, event.key['repeat'])
|
|
elseif event.type == sdl.KEYUP then
|
|
local key = Keyboard.stringByKeycode[event.key.keysym.sym]
|
|
callback.keyreleased(key, event.key['repeat'])
|
|
elseif event.type == sdl.TEXTINPUT then
|
|
callback.textinput(ffi.string(event.text.text))
|
|
elseif event.type == sdl.MOUSEWHEEL then
|
|
local wheel = event.wheel
|
|
callback.wheelmoved(wheel.x, wheel.y)
|
|
end
|
|
end
|
|
|
|
sdl.renderSetClipRect(renderer, nil)
|
|
sdl.setRenderDrawColor(renderer, 0, 0, 0, 255)
|
|
sdl.renderClear(renderer)
|
|
callback.draw()
|
|
sdl.renderPresent(renderer)
|
|
sdl.delay(1)
|
|
end
|
|
end
|
|
|
|
Backend.Cursor = function (image, x, y)
|
|
return sdl.createColorCursor(image.sdlSurface, x, y)
|
|
end
|
|
|
|
Backend.Font = Font
|
|
|
|
Backend.Image = function (path)
|
|
return Image(renderer, path)
|
|
end
|
|
|
|
Backend.Text = function (...)
|
|
return Text(renderer, ...)
|
|
end
|
|
|
|
Backend.Quad = function (x, y, w, h)
|
|
return { x, y, w, h }
|
|
end
|
|
|
|
Backend.SpriteBatch = require((...) .. '.spritebatch')
|
|
|
|
Backend.draw = function (drawable, x, y, sx, sy)
|
|
if drawable.draw then
|
|
return drawable:draw(x, y, sx, sy)
|
|
end
|
|
|
|
if drawable.sdlTexture == nil
|
|
or drawable.sdlRenderer == nil
|
|
or drawable.getWidth == nil
|
|
or drawable.getHeight == nil
|
|
then return
|
|
end
|
|
|
|
local w = drawable:getWidth() * (sx or 1)
|
|
local h = drawable:getHeight() * (sy or 1)
|
|
|
|
-- HACK. Somehow drawing something first prevents renderCopy from
|
|
-- incorrectly scaling up in some cases (after rendering slices).
|
|
-- For example http://stackoverflow.com/questions/28218906
|
|
sdl.renderDrawPoint(drawable.sdlRenderer, -1, -1)
|
|
|
|
-- Draw the image.
|
|
sdl.renderCopy(drawable.sdlRenderer, drawable.sdlTexture,
|
|
nil, sdl.Rect(x, y, w, h))
|
|
end
|
|
|
|
Backend.drawRectangle = function (mode, x, y, w, h)
|
|
if mode == 'fill' then
|
|
sdl.renderFillRect(renderer, sdl.Rect(x, y, w, h))
|
|
else
|
|
sdl.renderDrawRect(renderer, sdl.Rect(x, y, w, h))
|
|
end
|
|
end
|
|
|
|
local currentFont = Font()
|
|
|
|
local lastColor
|
|
|
|
-- print( text, x, y, r, sx, sy, ox, oy, kx, ky )
|
|
Backend.print = function (text, x, y)
|
|
if not text or text == '' then return end
|
|
local font = currentFont.sdlFont
|
|
local color = sdl.Color(lastColor or { 0, 0, 0, 255 })
|
|
local write = Font.SDL2_ttf.TTF_RenderUTF8_Blended
|
|
|
|
local surface = write(font, text, color)
|
|
ffi.gc(surface, sdl.freeSurface)
|
|
local texture = sdl.createTextureFromSurface(renderer, surface)
|
|
ffi.gc(texture, sdl.destroyTexture)
|
|
sdl.renderCopy(renderer, texture, nil, sdl.Rect(x, y, surface.w, surface.h))
|
|
end
|
|
|
|
Backend.printf = Backend.print
|
|
|
|
Backend.getClipboardText = function ()
|
|
return ffi.string(sdl.getClipboardText())
|
|
end
|
|
|
|
Backend.setClipboardText = sdl.setClipboardText
|
|
|
|
Backend.getMousePosition = function ()
|
|
local x, y = IntOut(), IntOut()
|
|
sdl.getMouseState(x, y)
|
|
return x[0], y[0]
|
|
end
|
|
|
|
local function SystemCursor (id)
|
|
local cursor = sdl.createSystemCursor(id)
|
|
ffi.gc(cursor, sdl.freeCursor)
|
|
return cursor
|
|
end
|
|
|
|
local systemCursors = {
|
|
arrow = SystemCursor(sdl.SYSTEM_CURSOR_ARROW),
|
|
ibeam = SystemCursor(sdl.SYSTEM_CURSOR_IBEAM),
|
|
wait = SystemCursor(sdl.SYSTEM_CURSOR_WAIT),
|
|
crosshair = SystemCursor(sdl.SYSTEM_CURSOR_CROSSHAIR),
|
|
waitarrow = SystemCursor(sdl.SYSTEM_CURSOR_WAITARROW),
|
|
sizenwse = SystemCursor(sdl.SYSTEM_CURSOR_SIZENWSE),
|
|
sizenesw = SystemCursor(sdl.SYSTEM_CURSOR_SIZENESW),
|
|
sizewe = SystemCursor(sdl.SYSTEM_CURSOR_SIZEWE),
|
|
sizens = SystemCursor(sdl.SYSTEM_CURSOR_SIZENS),
|
|
sizeall = SystemCursor(sdl.SYSTEM_CURSOR_SIZEALL),
|
|
no = SystemCursor(sdl.SYSTEM_CURSOR_NO),
|
|
hand = SystemCursor(sdl.SYSTEM_CURSOR_HAND),
|
|
}
|
|
|
|
Backend.getSystemCursor = function (name)
|
|
return systemCursors[name] or systemCursors.arrow
|
|
end
|
|
|
|
Backend.getWindowSize = function ()
|
|
local x, y = IntOut(), IntOut()
|
|
sdl.getWindowSize(window, x, y)
|
|
return x[0], y[0]
|
|
end
|
|
|
|
Backend.getTime = function ()
|
|
return sdl.getTicks() * 0.001
|
|
end
|
|
|
|
Backend.isKeyDown = function (...)
|
|
local state = sdl.getKeyboardState(nil)
|
|
|
|
for i = 1, select('#', ...) do
|
|
local name = select(i, ...)
|
|
local scan = Keyboard.scancodeByString[name]
|
|
if scan and state[scan] ~= 0 then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
Backend.isMouseDown = function ()
|
|
end
|
|
|
|
Backend.quit = function ()
|
|
sdl.quit()
|
|
os.exit()
|
|
end
|
|
|
|
Backend.setColor = function (color)
|
|
lastColor = color
|
|
sdl.setRenderDrawColor(renderer,
|
|
color[1], color[2], color[3], color[4] or 255)
|
|
end
|
|
|
|
Backend.setCursor = function (cursor)
|
|
sdl.setCursor(cursor or Backend.getSystemCursor('arrow'))
|
|
end
|
|
|
|
Backend.setFont = function (font)
|
|
currentFont = font
|
|
end
|
|
|
|
local lastScissor
|
|
|
|
Backend.setScissor = function (x, y, w, h)
|
|
lastScissor = x and sdl.Rect(x, y, w, h)
|
|
sdl.renderSetClipRect(renderer, lastScissor)
|
|
end
|
|
|
|
function Backend.hide (layout)
|
|
for _, item in ipairs(layout.hooks) do
|
|
Hooker.unhook(item)
|
|
end
|
|
layout.hooks = {}
|
|
end
|
|
|
|
local function hook (layout, key, method, hookLast)
|
|
layout.hooks[#layout.hooks + 1] = Hooker.hook(
|
|
callback, key, method, hookLast)
|
|
end
|
|
|
|
local stack = {}
|
|
|
|
Backend.pop = function ()
|
|
local history = stack[#stack]
|
|
local color = history.color or { 0, 0, 0, 255 }
|
|
|
|
sdl.setRenderDrawColor(renderer,
|
|
color[1], color[2], color[3], color[4] or 255)
|
|
sdl.renderSetClipRect(renderer, history.scissor) -- Backend.setScissor(history.scissor)
|
|
stack[#stack] = nil
|
|
end
|
|
|
|
Backend.push = function ()
|
|
stack[#stack + 1] = {
|
|
color = lastColor,
|
|
scissor = lastScissor,
|
|
}
|
|
end
|
|
|
|
local isMouseDown = function ()
|
|
return sdl.getMouseState(nil, nil) > 0
|
|
end
|
|
|
|
function Backend.show (layout)
|
|
local input = layout.input
|
|
|
|
hook(layout, 'draw', function ()
|
|
input:handleDisplay(layout)
|
|
end, true)
|
|
hook(layout, 'resize', function (width, height)
|
|
return input:handleReshape(layout, width, height)
|
|
end)
|
|
hook(layout, 'mousepressed', function (x, y, button)
|
|
return input:handlePressStart(layout, button, x, y)
|
|
end)
|
|
hook(layout, 'mousereleased', function (x, y, button)
|
|
return input:handlePressEnd(layout, button, x, y)
|
|
end)
|
|
hook(layout, 'mousemoved', function (x, y, dx, dy)
|
|
if isMouseDown() then
|
|
return input:handlePressedMove(layout, x, y)
|
|
else
|
|
return input:handleMove(layout, x, y)
|
|
end
|
|
end)
|
|
hook(layout, 'keypressed', function (key, isRepeat)
|
|
return input:handleKeyPress(layout, key, Backend.getMousePosition())
|
|
end)
|
|
hook(layout, 'keyreleased', function (key)
|
|
return input:handleKeyRelease(layout, key, Backend.getMousePosition())
|
|
end)
|
|
hook(layout, 'textinput', function (text)
|
|
return input:handleTextInput(layout, text, Backend.getMousePosition())
|
|
end)
|
|
hook(layout, 'wheelmoved', function (x, y)
|
|
return input:handleWheelMove(layout, x, y)
|
|
end)
|
|
end
|
|
|
|
return Backend
|