2021-04-18 12:25:03 (UTC-03:00)
Marcel Rodrigues <marcelgmr@gmail.com>
add ByteMap, inheriting same drawing methods as BitMap
diff --git a/surf.lua b/surf.lua index ee84df3..e1c5562 100644 --- a/surf.lua +++ b/surf.lua @@ -17,63 +17,25 @@ local function round(x) return i end -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 +local Surf = {} -function BitMap:inside(x, y) +function Surf: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) - 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) - if not self:inside(x, y) then return 0 end - 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) - if not self:inside(x, y) then return end - 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) - -- TODO: optimize this using ffi.fill() for large enough w? +function Surf: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) +function Surf:vline(x, y, h, v) for i = y, y+h-1 do self:pset(x, i, v) end end -function BitMap:disk(cx, cy, r, v) +function Surf:disk(cx, cy, r, v) if r == 0 then self:pset(cx, cy, v) return @@ -94,7 +56,7 @@ function BitMap:disk(cx, cy, r, v) end end -function BitMap:line(x0, y0, x1, y1, v, r) +function Surf:line(x0, y0, x1, y1, v, r) r = r or 0 x0, y0 = round(x0), round(y0) x1, y1 = round(x1), round(y1) @@ -141,7 +103,7 @@ function BitMap:line(x0, y0, x1, y1, v, r) end end -function BitMap:polyline(points, v, r) +function Surf:polyline(points, v, r) local x0, y0, x1, y1 x0, y0 = unpack(points[1]) for i = 2, #points do @@ -151,7 +113,7 @@ function BitMap:polyline(points, v, r) end end -function BitMap:polygon(points, v) +function Surf:polygon(points, v) local scans = {} for i = 0, self.h-1 do scans[i] = {} @@ -191,6 +153,37 @@ function BitMap:polygon(points, v) end end +local BitMap = {} + +function BitMap:fill(v) + ffi.fill(self.p, self.t * self.h, v) +end + +function BitMap:_index_shift_mask(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) + if not self:inside(x, y) then return 0 end + 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) + if not self:inside(x, y) then return end + 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:save_pbm(fname) local pbm = io.open(fname, "wb") pbm:write("P4\n", self.w, " ", self.h, "\n") @@ -202,4 +195,46 @@ function BitMap:save_pbm(fname) pbm:close() end -return {new_bitmap=new_bitmap} +setmetatable(BitMap, {__index=Surf}) + +local function new_bitmap(w, h) + local self = setmetatable({w=w, h=h}, {__index=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 + +local ByteMap = {} + +function ByteMap:fill(v) + ffi.fill(self.p, self.w * self.h, v) +end + +function ByteMap:pget(x, y) + if not self:inside(x, y) then return 0 end + return self.p[y*self.w+x] +end + +function ByteMap:pset(x, y, v) + if not self:inside(x, y) then return end + self.p[y*self.w+x] = v +end + +function ByteMap:save_ppm(fname, colors) + local ppm = io.open(fname, "wb") + ppm:write("P6\n", self.w, " ", self.h, "\n", 255, "\n") + for i = 0, self.w*self.h-1 do + ppm:write(string.char(unpack(colors[self.p[i]+1]))) + end + ppm:close() +end + +setmetatable(ByteMap, {__index=Surf}) + +local function new_bytemap(w, h) + local self = setmetatable({w=w, h=h}, {__index=ByteMap}) + self.p = ffi.new("unsigned char[?]", self.w * self.h) + return self +end + +return {new_bitmap=new_bitmap, new_bytemap=new_bytemap}