Skip to content

Instantly share code, notes, and snippets.

@Skaruts
Last active September 16, 2021 06:04
Show Gist options
  • Save Skaruts/736521d9cb6d136cfb6c8aedbb9602a5 to your computer and use it in GitHub Desktop.
Save Skaruts/736521d9cb6d136cfb6c8aedbb9602a5 to your computer and use it in GitHub Desktop.
A terminal emulator console in love2d, which renders using spritebatches
-- import() is a custom made relative-require function
local Class = import("lib/middleclass/middleclass", ...)
local ClassProperties = import("lib/middleclass/class_properties", ...)
local BaseConsole = import("console_base", ...)
local palette = import("palette", ...)
local db = import("database", ...)
local ml = import("main_loop", ...)
local vec = import("lib/vec2", ...)
-- extends BaseConsole
local BatchConsole = Class('BatchConsole', BaseConsole):include(ClassProperties)
function BatchConsole:initialize(x, y, w, h, tileset, clear_char, clear_fg, clear_bg)
BaseConsole.initialize(self, "root", x, y, w, h, clear_char, clear_fg, clear_bg)
self._tileset = tileset
self._quads = {}
self._fg_spritebatch = nil
self._bg_spritebatch = nil
self._old_chars = {}
self._old_fgs = {}
self._old_bgs = {}
self:_init_cells()
self:_init_quads()
self:_init_spritebatch()
end
function BatchConsole:_init_cells()
for i=0, (self.w*self.h)-1 do
self._old_chars[i] = true -- just reserve memory for now
self._old_fgs[i] = true
self._old_bgs[i] = true
-- these are all from BaseConsole
self._chars[i] = self._clear_char -- text chars
self._fgs[i] = self._clear_fg -- foreground color (text)
self._bgs[i] = self._clear_bg -- background color (around the text)
end
end
-- take each character in a font set (i.e. cp437 ascii image), and create a
-- quad that encompasses it's position and size in the tileset (in pixels)
function BatchConsole:_init_quads()
local idx = 0
for j=0, self._tileset.rows-1 do
for i=0, self._tileset.cols-1 do
self._quads[idx] = love.graphics.newQuad(
i*self._tileset.cw, j*self._tileset.ch,
self._tileset.cw, self._tileset.ch, -- tileset's cell width/height
self._tileset.w, self._tileset.h -- tileset's image width/height
)
idx = idx + 1
end
end
end
function BatchConsole:_init_spritebatch()
-- self.w/h is in cells, not in pixels
self._fg_spritebatch = love.graphics.newSpriteBatch(self._tileset.image, self.w*self.h)
self._bg_spritebatch = love.graphics.newSpriteBatch(self._tileset.image, self.w*self.h)
local idx = 0
for j=0, self.h-1 do
for i=0, self.w-1 do
self._fg_spritebatch:setColor( self._fgs[idx] )
self._fg_spritebatch:add( self._quads[self._chars[idx]], i*self._tileset.cw, j*self._tileset.ch )
self._bg_spritebatch:setColor( self._bgs[idx] )
self._bg_spritebatch:add( self._quads[self._chars[self._tileset.bg_char]], i*self._tileset.cw, j*self._tileset.ch )
idx = idx + 1
end
end
end
function BatchConsole:render()
local chars, fgs, bgs = self._chars, self._fgs, self._bgs
local ochars, ofgs, obgs = self._old_chars, self._old_fgs, self._old_bgs
local CW, CH, bg_char = self._tileset.cw, self._tileset.ch, self._tileset.bg_char
-- check what has changed since last frame and apply to spritebatches
local idx = -1
local char, fg, bg, ochar, ofg, obg, qx, qy
for j=0, self.h-1 do
qy = j*CH -- quad y
for i=0, self.w-1 do
idx = idx + 1
qx = i*CW -- quad x
char, fg, bg = chars[idx], fgs[idx], bgs[idx]
if bg ~= obgs[idx] then
self._bg_spritebatch:setColor(bg)
self._bg_spritebatch:set(idx+1, self._quads[bg_char], qx, qy)
obgs[idx] = bg
end
if char ~= ochars[idx] or fg ~= ofgs[idx] then
self._fg_spritebatch:setColor(fg)
self._fg_spritebatch:set(idx+1, self._quads[char], qx, qy)
ochars[idx] = char
ofgs[idx] = fg
end
end
end
-- render spritebatches
love.graphics.setColor( palette.WHITE )
love.graphics.draw( self._bg_spritebatch, self.x*CW, self.y*CH )
love.graphics.draw( self._fg_spritebatch, self.x*CW, self.y*CH )
end
--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--
-- getters / setters (made possible with ClassProperties)
--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--=--
function BatchConsole:_get_global_x_() return self.x end
function BatchConsole:_get_global_y_() return self.y end
function BatchConsole:_get_global_pos_() return vec(self.x, self.y) end
function BatchConsole:_set_tileset_(ts)
if ts ~= self._tileset then
local old_ts = self._tileset
self._tileset = ts
if ts.cw ~= old_ts.cw or ts.ch ~= old_ts.ch then
self:_init_quads()
if self == db.main_console then
ml.set_window(self.w*ts.cw, self.h*ts.ch)
end
end
self._fg_spritebatch:setTexture(self._tileset.image)
self._bg_spritebatch:setTexture(self._tileset.image)
for j = 0, self.h-1 do
for i = 0, self.w-1 do
local idx = i+j*self.w
self._old_chars[idx] = true
self._old_fgs[idx] = true
self._old_bgs[idx] = true
end
end
end
end
function BatchConsole:_get_tileset_()
return self._tileset
end
-- TODO: account for zoom/scale
function BatchConsole:_get_global_mouse_pos_()
-- (vecf(self._mouse_pos-self.rpos)/self.scale) / self.cs
-- return vec( math.floor((self._mouse_pos.x / self.scale.x) / self._tileset.cw),
-- math.floor((self._mouse_pos.y / self.scale.y) / self._tileset.ch) )
return vec(self._mouse_pos.x / self._tileset.cw, self._mouse_pos.y / self._tileset.ch):floored()
end
-- local floor = math.floor
function BatchConsole:_get_mouse_pos_()
-- return vec( float((self._mouse_pos.x - (self.x*self.cw)) / self.scale.x) // self.cw,
-- float((self._mouse_pos.y - (self.y*self.ch)) / self.scale.y) // self.ch )
return vec( (self._mouse_pos.x - (self.x * self._tileset.cw)) / self._tileset.cw,
(self._mouse_pos.y - (self.y * self._tileset.ch)) / self._tileset.ch ):floored()
end
function BatchConsole:_set_mouse_pos_(mp)
self._mouse_pos = mp
end
return BatchConsole
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment