login

<     >

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}