summaryrefslogtreecommitdiff
path: root/dalos-framebuffer.lua
diff options
context:
space:
mode:
Diffstat (limited to 'dalos-framebuffer.lua')
-rw-r--r--dalos-framebuffer.lua396
1 files changed, 396 insertions, 0 deletions
diff --git a/dalos-framebuffer.lua b/dalos-framebuffer.lua
new file mode 100644
index 0000000..27e183c
--- /dev/null
+++ b/dalos-framebuffer.lua
@@ -0,0 +1,396 @@
+load "iupe-dbuffer.lua"
+
+dalosp.framebuffer = {
+ get_settings = function (self)
+ local extra = self.extra
+ return {
+ width = extra.width,
+ height = extra.height,
+ bpp = extra.bpp,
+ zoom = extra.zoom,
+ ppdir = extra.ppdir,
+ flipx = extra.flipx,
+ flipy = extra.flipy,
+ }
+ end,
+
+ input_change = function (self, ind)
+ local h = self:get_linked_input(ind)
+ if ind == 2 then
+ if h then
+ local cfg, s = h:readfile()
+ s, cfg = pcall(loadstring, "local cfg = " .. cfg .. "\nreturn cfg\n")
+ if s then
+ self:apply_config(cfg)
+ self.extra.fb:prepare()
+ self.extra.fb:draw()
+ end
+ end
+ return
+ end
+
+ if h then h.getnextbyte = dalosp.framebuffer.getnextbyte end
+ self:apply_config{}
+ self.extra.fb:prepare()
+ self.extra.fb:draw()
+ end,
+
+ activate = function (self)
+ self.extra.dlg:show()
+ end,
+
+ configure = function (self)
+ local extra = self.extra
+ invert_lookup = {
+ [1] = 0,
+ [2] = 1,
+ [4] = 2,
+ [8] = 3,
+ [24] = 4,
+ [32] = 5,
+ }
+ lookup = {
+ [0] = 1,
+ [1] = 2,
+ [2] = 4,
+ [3] = 8,
+ [4] = 24,
+ [5] = 32,
+ }
+ local owidth, oheight, obpp, oppdir, oflipx, oflipy = extra.width, extra.height, extra.bpp, extra.ppdir, not not extra.flipx, not not extra.flipy
+ local cb = function (dlg, pi)
+ if pi < 0 then return end
+ local width, height, bpp, dir
+ width = iup.GetParamParam(dlg, 1).value + 0
+ height = iup.GetParamParam(dlg, 2).value + 0
+ bpp = iup.GetParamParam(dlg, 3).value + 0
+ dir = iup.GetParamParam(dlg, 4).value + 0
+ flipx = (iup.GetParamParam(dlg, 5).value + 0) ~= 0
+ flipy = (iup.GetParamParam(dlg, 6).value + 0) ~= 0
+ self:apply_config{ width = width, height = height, bpp = lookup[bpp], dir = dir, flipx = flipx, flipy = flipy }
+ self.extra.fb:prepare()
+ self.extra.fb:draw()
+ end
+ local s, nname = iup.GetParam(self.name .. " configuration", cb, [[
+New name: %s
+Width: %i
+Height: %i
+Bpp: %l|1 bpp|2 bpp|4 bpp|8 bpp|24 bpp|32 bpp|
+Packed Pixels: %l|Little Endian|Big Endian|
+Flip X axis: %b
+Flip Y axis: %b
+]], self.name, owidth, oheight, invert_lookup[obpp], oppdir, oflipx and 1 or 0, oflipy and 1 or 0)
+ if not s then
+ self:apply_config{ width = owidth, height = oheight, bpp = obpp, ppdir = oppdir, flipx = oflipx, flipy = oflipy }
+ self.extra.fb:prepare()
+ self.extra.fb:draw()
+ else
+ self.name = nname
+ end
+ end,
+
+ apply_config = function (self, cfg)
+ local extra = self.extra
+ local fb = extra.fb
+ local h = self:get_linked_input(1)
+ if cfg.width then extra.width = cfg.width end
+ if cfg.height then extra.height = cfg.height end
+ if cfg.bpp then extra.bpp = cfg.bpp end
+ if cfg.ppdir then extra.ppdir = cfg.ppdir end
+ if cfg.flipx then extra.flipx = cfg.flipx end
+ if cfg.flipy then extra.flipy = cfg.flipy end
+ if cfg.zoom then extra.zoom = cfg.zoom end
+ local zoom = 2 ^ extra.zoom
+ local posx = fb.posx
+ local posy = fb.posy
+ local dx = fb.dx + 0
+ local dy = fb.dy + 0
+ local fw = math.floor(extra.width * zoom)
+ local fh = math.floor(extra.height * zoom)
+ if dx >= (fb.xmax - fb.xmin) then posx = math.floor((fw - dx) / 2) end
+ if dy >= (fb.ymax - fb.ymin) then posy = math.floor((fh - dy) / 2) end
+ fb.xmax = fw
+ fb.ymax = fh
+ cfg = {
+ h = h,
+ width = extra.width,
+ height = extra.height,
+ bpp = extra.bpp,
+ ppdir = extra.ppdir,
+ flipx = extra.flipx,
+ flipy = extra.flipy,
+ zoom = zoom,
+ x = -posx,
+ y = -posy,
+ fw = fw,
+ fh = fh,
+ }
+ fb.cfg = cfg
+ local cvwidth, cvheight = fb.width or 0, fb.height or 0
+ cvwidth, cvheight = cvwidth + 0, cvheight + 0
+ end,
+
+ getnextbyte = function (h)
+ return h:tell() ~= h:getsize() and h:readU8() or 0
+ end,
+
+ getbit = function (cfg)
+ local rc
+ local h = cfg.h
+ local stateful = cfg.stateful
+ if cfg.bpp >= 8 then return end
+ stateful = cfg.stateful
+ if not stateful or bit.band(stateful, 0x7f) == 0 then
+ stateful = h:getnextbyte() * 2 + 1
+ else
+ stateful = stateful * 2
+ end
+ cfg.stateful = stateful
+ return bit.band(bit.rshift(stateful, 8), 1)
+ end,
+
+ getnextpixel = function (cfg)
+ local rc
+ local r, g, b
+ local h = cfg.h
+ local getbit = function() return dalosp.framebuffer.getbit(cfg) end
+ if cfg.bpp == 1 then
+ rc = getbit() * 255
+ r, g, b = rc, rc, rc
+ elseif cfg.bpp == 2 then
+ rc = getbit() * 2
+ rc = (rc + getbit()) * 255 / 3
+ r, g, b = rc, rc, rc
+ elseif cfg.bpp == 4 then
+ rc = getbit() * 8
+ rc = rc + getbit() * 4
+ rc = rc + getbit() * 2
+ rc = (rc + getbit()) * 255 / 15
+ r, g, b = rc, rc, rc
+ elseif cfg.bpp == 8 then
+ rc = h:getnextbyte()
+ r, g, b = rc, rc, rc
+ elseif cfg.bpp == 24 then
+ r = h:getnextbyte()
+ g = h:getnextbyte()
+ b = h:getnextbyte()
+ elseif cfg.bpp == 32 then
+ r = h:getnextbyte()
+ g = h:getnextbyte()
+ b = h:getnextbyte()
+ h:getnextbyte()
+ end
+ return r, g, b
+ end,
+
+ prepare = function (self)
+ local cfg = self.cfg
+ local h = cfg.h
+ local width = cfg.width
+ local height = cfg.height
+ local bpp = cfg.bpp
+ local ppdir = cfg.ppdir
+ local flipx = cfg.flipx
+ local flipy = not cfg.flipy
+ local cim = im.ImageCreate(width, height, im.RGB, im.BYTE)
+ self.cim = cim
+ cim:Clear()
+ if not h then return iup.DEFAULT end
+ local getnextpixel = self.getnextpixel
+
+ h:seek(0)
+ cfg.stateful = 0
+ local r, g, b = cim[0], cim[1], cim[2]
+
+ for y = 0, height - 1 do
+ for x = 0, width - 1 do
+ local px, py = flipx and width - x - 1 or x, flipy and height - y - 1 or y
+ r[py][px], g[py][px], b[py][px] = getnextpixel(cfg)
+ end
+ end
+
+ return iup.DEFAULT
+ end,
+
+ draw = function (self)
+ local cvdb = self.cvdb
+ if not cvdb then return iup.DEFAULT end
+ cvdb:Clear()
+ local cim = self.cim
+ local cfg = self.cfg
+ cim:cdCanvasPutImageRect(cvdb, cfg.x, cvdb:InvertYAxis(cfg.y + cfg.fh), cfg.fw, cfg.fh, 0, 0, 0, 0)
+ cvdb:Flush()
+ end,
+
+ resize_cb = function (self, width, height)
+ self.dx = width
+ self.dy = height
+ self.posx = self.posx
+ self.posy = self.posy
+ iupep.dbuffer.resize_cb(self, width, height)
+ self.obj:apply_config{}
+ self:draw()
+ end,
+
+ fimg2canvas = function (self, ix, iy)
+ local cfg = self.cfg
+ local cx, cy
+ return ix + cfg.x, iy + cfg.y
+ end,
+
+ canvas2fimg = function (self, cx, cy)
+ local cfg = self.cfg
+ return cx - cfg.x, cy - cfg.y
+ end,
+
+ img2canvas = function (self, ix, iy)
+ local cfg = self.cfg
+ return math.floor(ix * cfg.zoom + cfg.x), math.floor(iy * cfg.zoom + cfg.y)
+ end,
+
+ canvas2img = function (self, cx, cy)
+ local cfg = self.cfg
+ return math.floor((cx - cfg.x) / cfg.zoom), math.floor((cy - cfg.y) / cfg.zoom)
+ end,
+
+ scroll_cb = function (self, op, posx, posy)
+ self:resize_cb(self.width, self.height)
+ end,
+
+ wheel_cb = function (self, delta, x, y, status)
+ local ox, oy = self:canvas2img(x, y)
+ local opx, opy = self.cfg.x, self.cfg.y
+ self.obj:apply_config { zoom = self.obj.extra.zoom + (delta / 10) }
+ local nx, ny = self:img2canvas(ox, oy)
+ local dx, dy = ox - nx, oy - ny
+ self.posx, self.posy = -opx - dx, -opy - dy
+ self:resize_cb(self.width, self.height)
+ end,
+
+ motion_cb = function (self, x, y)
+ local ox, oy = self:canvas2img(x, y)
+ local nx, ny = self:img2canvas(ox, oy)
+ end,
+
+ create = function (d, tab, settings)
+ tab.ninputs = 2
+ tab.noutputs = 0
+ tab.otype = dalos.objtype.LUA_VIEWER
+ tab.activate = dalosp.framebuffer.activate
+ tab.configure = dalosp.framebuffer.configure
+ tab.input_change = dalosp.framebuffer.input_change
+ tab.default_name = "Framebuffer"
+ tab.ntype = "Framebuffer"
+ tab.get_settings = dalosp.framebuffer.get_settings
+ local extra = {
+ width = settings.width or 256,
+ height = settings.height or 256,
+ bpp = settings.bpp or 32,
+ ppdir = settings.dir or 0,
+ flipx = settings.flipx,
+ flipy = settings.flipy,
+ zoom = settings.zoom or 0,
+ }
+
+ local obj = dalos.object(d, tab, extra)
+
+ obj.apply_config = dalosp.framebuffer.apply_config
+
+ local fb = iup.canvas {
+ expand = "Yes",
+ font = "Courier, 8",
+ action = iupep.dbuffer.action,
+ map_cb = iupep.dbuffer.map_cb,
+ unmap_cb = iupep.dbuffer.unmap_cb,
+ resize_cb = dalosp.framebuffer.resize_cb,
+ motion_cb = dalosp.framebuffer.motion_cb,
+ draw = dalosp.framebuffer.draw,
+ scroll_cb = dalosp.framebuffer.scroll_cb,
+ wheel_cb = dalosp.framebuffer.wheel_cb,
+ prepare = dalosp.framebuffer.prepare,
+ img2canvas = dalosp.framebuffer.img2canvas,
+ canvas2img = dalosp.framebuffer.canvas2img,
+ fimg2canvas = dalosp.framebuffer.img2canvas,
+ canvas2fimg = dalosp.framebuffer.canvas2img,
+ getnextpixel = dalosp.framebuffer.getnextpixel,
+ rastersize = extra.width .. "x" .. extra.height,
+ scrollbar = "Yes",
+ dx = 1,
+ dy = 1,
+ linex = 1,
+ liney = 1,
+ xmax = 0,
+ ymax = 0,
+ xautohide = "No",
+ yautohide = "No",
+ obj = obj,
+ }
+ local dlg = iup.dialog {
+ iup.vbox {
+ fb,
+ iup.hbox {
+ iup.fill{},
+ iup.button {
+ action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = -4 } fb:resize_cb(fb.width, fb.height) end,
+ title = "1:16",
+ },
+ iup.fill{},
+ iup.button {
+ action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = -3 } fb:resize_cb(fb.width, fb.height) end,
+ title = "1:8",
+ },
+ iup.fill{},
+ iup.button {
+ action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = -2 } fb:resize_cb(fb.width, fb.height) end,
+ title = "1:4",
+ },
+ iup.fill{},
+ iup.button {
+ action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = -1 } fb:resize_cb(fb.width, fb.height) end,
+ title = "1:2",
+ },
+ iup.fill{},
+ iup.button {
+ action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = 0 } fb:resize_cb(fb.width, fb.height) end,
+ title = "1:1",
+ },
+ iup.fill{},
+ iup.button {
+ action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = 1 } fb:resize_cb(fb.width, fb.height) end,
+ title = "2:1",
+ },
+ iup.fill{},
+ iup.button {
+ action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = 2 } fb:resize_cb(fb.width, fb.height) end,
+ title = "4:1",
+ },
+ iup.fill{},
+ iup.button {
+ action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = 3 } fb:resize_cb(fb.width, fb.height) end,
+ title = "8:1",
+ },
+ iup.fill{},
+ iup.button {
+ action = function () fb.posx, fb.posy = 0, 0 obj:apply_config { zoom = 4 } fb:resize_cb(fb.width, fb.height) end,
+ title = "16:1",
+ },
+ iup.fill{},
+ },
+ },
+ size = "320x200",
+ title = obj.name,
+ shrink = "Yes",
+ }
+ extra.dlg = dlg
+ extra.fb = fb
+
+ obj:apply_config{}
+ fb:prepare()
+ fb:draw()
+
+ return obj
+ end,
+}
+
+dalos.framebuffer = dalosp.framebuffer.create
+dalos:register_obj("Framebuffer", dalos.framebuffer, "Basic Viewers")