diff options
Diffstat (limited to 'dalos-framebuffer.lua')
-rw-r--r-- | dalos-framebuffer.lua | 396 |
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") |