2021-04-09 18:33:39 (UTC-03:00)
Marcel Rodrigues <marcelgmr@gmail.com>
add BitMap
diff --git a/surf.lua b/surf.lua new file mode 100644 index 0000000..b58ff23 --- /dev/null +++ b/surf.lua @@ -0,0 +1,109 @@ +local ffi = require "ffi" +local bit = require "bit" + +ffi.cdef[[ +double hypot(double x, double y); +double copysign(double x, double y); +]] +local mathx = ffi.C + +local bnot = bit.bnot +local bor, band = bit.bor, bit.band +local lshift, rshift = bit.lshift, bit.rshift + +local BitMap = {} +BitMap.__index = BitMap + +local function new_bitmap(w, h) + local self = setmetatable({w=w, h=h}, BitMap) + self.t = math.ceil(w / 8) -- stride, i.e., bytes/row + self.p = ffi.new("unsigned char[?]", self.t * self.h) + return self +end + +function BitMap:fill(v) + ffi.fill(self.p, self.t * self.h, v) +end + +function BitMap:inside(x, y) + return x >= 0 and x < self.w and y >= 0 and y < self.h +end + +function BitMap:_index_shift_mask(x, y) + assert(self:inside(x, y)) + local index = y * self.t + math.floor(x / 8) + local shift = (7-x) % 8 + local mask = lshift(1, shift) + return index, shift, mask +end + +function BitMap:pget(x, y) + local index, shift, mask = self:_index_shift_mask(x, y) + return rshift(band(self.p[index], mask), shift) +end + +function BitMap:pset(x, y, v) + local index, shift, mask = self:_index_shift_mask(x, y) + local byte = self.p[index] + if v > 0 then + byte = bor(byte, mask) + else + byte = band(byte, bnot(mask)) + end + self.p[index] = byte +end + +function BitMap:hline(x, y, w, v) + for i = x, x+w-1 do + self:pset(i, y, v) + end +end + +function BitMap:vline(x, y, h, v) + for i = y, y+h-1 do + self:pset(x, i, v) + end +end + +function BitMap:line(x0, y0, x1, y1, v) + if x1 == x0 then + if y1 > y0 then + self:vline(x0, y0, y1 - y0) + else + self:vline(x0, y1, y0 - y1) + end + elseif y1 == y0 then + if x1 > x0 then + self:hline(x0, y0, x1 - x0) + else + self:hline(x1, y0, x0 - x1) + end + else + local dx, dy = x1-x0, y1-y0 + local sx, sy = mathx.copysign(1, dx), mathx.copysign(1, dy) + local de = math.abs(dy / dx) + local e = 0 + local x, y = x0, y0 + while x ~= x1 do + self:pset(x, y, v) + e = e + de + while e >= 0.5 do + self:pset(x, y, v) + y = y + sy + e = e - 1 + end + x = x + sx + end + end +end + +function BitMap:save_pbm(fname) + local pbm = io.open(fname, "wb") + pbm:write("P4\n", self.w, " ", self.h, "\n") + local row = self.p + 0 + for y = 0, self.h-1 do + pbm:write(ffi.string(row, self.t)) + row = row + self.t + end + pbm:close() +end