word wrap

This commit is contained in:
airstruck
2015-11-26 08:53:42 -05:00
parent bbba7e1b3d
commit 2c81c0c293
18 changed files with 409 additions and 89 deletions

View File

@@ -4,16 +4,18 @@ 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
local window = sdl.createWindow('', 0, 0, 800, 600,
sdl.WINDOW_SHOWN)
sdl.WINDOW_SHOWN + sdl.WINDOW_RESIZABLE)
if window == nil then
io.stderr:write(ffi.string(sdl.getError()))
@@ -58,13 +60,17 @@ Backend.run = function ()
return
elseif event.type == sdl.WINDOWEVENT
and event.window.event == sdl.WINDOWEVENT_RESIZED then
callback.resize(event.window.data1, event.window.data2)
local window = event.window
callback.resize(window.data1, window.data2)
elseif event.type == sdl.MOUSEBUTTONDOWN then
callback.mousepressed(event.button.x, event.button.y, event.button.button)
local button = event.button
callback.mousepressed(button.x, button.y, button.button)
elseif event.type == sdl.MOUSEBUTTONUP then
callback.mousereleased(event.button.x, event.button.y, event.button.button)
local button = event.button
callback.mousereleased(button.x, button.y, button.button)
elseif event.type == sdl.MOUSEMOTION then
callback.mousemoved(event.motion.x, event.motion.y)
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'])
@@ -94,6 +100,10 @@ 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
@@ -101,7 +111,28 @@ end
Backend.SpriteBatch = require((...) .. '.spritebatch')
Backend.draw = function (drawable, x, y, sx, sy)
return drawable:draw(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)
@@ -118,7 +149,7 @@ local currentFont = Font()
Backend.print = function (text, x, y)
if not text or text == '' then return end
local font = currentFont.sdlFont
local color = sdl.Color(currentFont.color)
local color = sdl.Color(currentFont.color or { 0, 0, 0, 255 })
local write = Font.SDL2_ttf.TTF_RenderUTF8_Blended
local surface = write(font, text, color)
@@ -130,7 +161,9 @@ end
Backend.printf = Backend.print
Backend.getClipboardText = sdl.getClipboardText
Backend.getClipboardText = function ()
return ffi.string(sdl.getClipboardText())
end
Backend.setClipboardText = sdl.setClipboardText

View File

@@ -197,13 +197,10 @@ Font.SDL2_ttf = SDL2_ttf
local fontCache = {}
function Font:constructor (path, size, color)
function Font:constructor (path, size)
if not size then
size = 12
end
if not color then
color = { 0, 0, 0, 255 }
end
if not path then
path = REL:gsub('%.', '/') .. 'resource/DejaVuSans.ttf'
end
@@ -222,7 +219,6 @@ function Font:constructor (path, size, color)
end
self.sdlFont = fontCache[key]
self.color = color
end
function Font:setAlignment (align)

View File

@@ -14,10 +14,12 @@ end })
function Image:constructor (renderer, path)
self.sdlRenderer = renderer
self.sdlSurface = SDL2_image.IMG_Load(path)
ffi.gc(self.sdlSurface, sdl.freeSurface)
self.sdlTexture = sdl.createTextureFromSurface(renderer, self.sdlSurface)
ffi.gc(self.sdlTexture, sdl.destroyTexture)
self.sdlSurface = ffi.gc(
SDL2_image.IMG_Load(path),
sdl.freeSurface)
self.sdlTexture = ffi.gc(
sdl.createTextureFromSurface(renderer, self.sdlSurface),
sdl.destroyTexture)
self.width = self.sdlSurface.w
self.height = self.sdlSurface.h
end
@@ -30,17 +32,4 @@ function Image:getHeight ()
return self.height
end
function Image:draw (x, y, sx, sy)
local w = self.width * (sx or 1)
local h = self.height * (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(self.sdlRenderer, -1, -1)
-- Draw the image.
sdl.renderCopy(self.sdlRenderer, self.sdlTexture, nil, sdl.Rect(x, y, w, h))
end
return Image

View File

@@ -1,7 +1,7 @@
local ROOT = (...):gsub('[^.]*$', '')
local REL = (...):gsub('[^.]*$', '')
local ffi = require 'ffi'
local sdl = require(ROOT .. 'sdl2.init')
local sdl = require(REL .. 'sdl2.init')
sdl.AudioCVT = ffi.typeof 'SDL_AudioCVT'
-- sdl.AudioDeviceEvent = ffi.typeof 'SDL_AudioDeviceEvent'

View File

@@ -0,0 +1,106 @@
local ROOT = (...):gsub('[^.]*.[^.]*.[^.]*$', '')
local REL = (...):gsub('[^.]*$', '')
local ffi = require 'ffi'
local sdl = require(REL .. 'sdl')
local Font = require(REL .. 'font')
local ttf = Font.SDL2_ttf
local Multiline = require(ROOT .. 'multiline')
local Text = setmetatable({}, { __call = function (self, ...)
local object = setmetatable({}, { __index = self })
return object, self.constructor(object, ...)
end })
local function renderSingle (self, font, text, color)
local alphaMod = color and color[4]
color = sdl.Color(color or 0)
local surface = ffi.gc(
ttf.TTF_RenderUTF8_Blended(font.sdlFont, text, color),
sdl.freeSurface)
self.sdlSurface = surface
self.sdlTexture = ffi.gc(
sdl.createTextureFromSurface(self.sdlRenderer, surface),
sdl.destroyTexture)
if alphaMod then
sdl.setTextureAlphaMod(self.sdlTexture, alphaMod)
end
self.width, self.height = surface.w, surface.h
end
local function renderMulti (self, font, text, color, align, limit)
local alphaMod = color and color[4]
local lines = Multiline.wrap(font, text, limit)
local lineHeight = font:getLineHeight()
local height = #lines * lineHeight
color = sdl.Color(color or 0)
local r, g, b, a
if sdl.BYTEORDER == sdl.BIG_ENDIAN then
r, g, b, a = 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF
else
r, g, b, a = 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
end
local surface = ffi.gc(
sdl.createRGBSurface(0, limit, height, 32, r, g, b, a),
sdl.freeSurface)
self.sdlSurface = surface
for index, line in ipairs(lines) do
local text = table.concat(line)
local lineSurface = ffi.gc(
ttf.TTF_RenderUTF8_Blended(font.sdlFont, text, color),
sdl.freeSurface)
if lineSurface ~= nil then
local w, h = lineSurface.w, lineSurface.h
local top = (index - 1) * lineHeight
if align == 'left' then
sdl.blitSurface(lineSurface, nil, surface,
sdl.Rect(0, top, w, h))
elseif align == 'right' then
sdl.blitSurface(lineSurface, nil, surface,
sdl.Rect(limit - line.width, top, w, h))
elseif align == 'center' then
sdl.blitSurface(lineSurface, nil, surface,
sdl.Rect((limit - line.width) / 2, top, w, h))
end
end
end
self.sdlTexture = ffi.gc(
sdl.createTextureFromSurface(self.sdlRenderer, surface),
sdl.destroyTexture)
if alphaMod then
sdl.setTextureAlphaMod(self.sdlTexture, alphaMod)
end
self.width, self.height = surface.w, surface.h
end
function Text:constructor (renderer, font, text, color, align, limit)
self.width, self.height = 0, 0
if not text or text == '' then return end
self.sdlRenderer = renderer
if limit then
renderMulti(self, font, text, color, align, limit)
else
renderSingle(self, font, text, color)
end
end
function Text:getWidth ()
return self.width
end
function Text:getHeight ()
return self.height
end
return Text

View File

@@ -11,13 +11,21 @@ Backend.Cursor = love.mouse.newCursor
Backend.Font = require(ROOT .. 'backend.love.font')
Backend.Text = require(ROOT .. 'backend.love.text')
Backend.Image = love.graphics.newImage
Backend.Quad = love.graphics.newQuad
Backend.SpriteBatch = love.graphics.newSpriteBatch
Backend.draw = love.graphics.draw
-- love.graphics.draw( drawable, x, y, r, sx, sy, ox, oy, kx, ky )
Backend.draw = function (drawable, ...)
if drawable.typeOf and drawable:typeOf 'Drawable' then
return love.graphics.draw(drawable, ...)
end
return drawable:draw(...)
end
Backend.drawRectangle = love.graphics.rectangle

View File

@@ -0,0 +1,72 @@
local ROOT = (...):gsub('[^.]*.[^.]*.[^.]*$', '')
local REL = (...):gsub('[^.]*$', '')
local Multiline = require(ROOT .. 'multiline')
local Text = setmetatable({}, { __call = function (self, ...)
local object = setmetatable({}, { __index = self })
return object, self.constructor(object, ...)
end })
local function renderSingle (self, x, y, font, text, color)
love.graphics.push('all')
love.graphics.setColor(color or { 0, 0, 0 })
love.graphics.setFont(font.loveFont)
love.graphics.print(text, x, y)
love.graphics.pop()
self.height = font:getLineHeight()
self.width = font:getAdvance(text)
end
local function renderMulti (self, x, y, font, text, color, align, limit)
local lines = Multiline.wrap(font, text, limit)
local lineHeight = font:getLineHeight()
local height = #lines * lineHeight
love.graphics.push('all')
love.graphics.setColor(color or { 0, 0, 0 })
love.graphics.setFont(font.loveFont)
for index, line in ipairs(lines) do
local text = table.concat(line)
local top = (index - 1) * lineHeight
local w = line.width
if align == 'left' then
love.graphics.print(text, x, top + y)
elseif align == 'right' then
love.graphics.print(text, limit - w + x, top + y)
elseif align == 'center' then
love.graphics.print(text, (limit - w) / 2 + x, top + y)
end
end
love.graphics.pop()
self.height = height
self.width = limit
end
function Text:constructor (font, text, color, align, limit)
if limit then
function self:draw (x, y)
return renderMulti(self, x, y, font, text, color, align, limit)
end
else
function self:draw (x, y)
return renderSingle(self, x, y, font, text, color)
end
end
self:draw(-1000000, -1000000)
end
function Text:getWidth ()
return self.width
end
function Text:getHeight ()
return self.height
end
return Text