summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Wilgus <me.theuser@yahoo.com>2018-09-23 18:25:31 +0200
committerWilliam Wilgus <me.theuser@yahoo.com>2018-10-09 01:02:25 +0200
commitc0682e094414d0748456d0b01000727039ff701c (patch)
tree2cc08bfdfe967bbe18fade1ed835d54a3f91cd23
parente4b843335bc34810c11ed405d473e6f7c94a153f (diff)
downloadrockbox-c0682e094414d0748456d0b01000727039ff701c.tar.gz
rockbox-c0682e094414d0748456d0b01000727039ff701c.zip
Clean up rocklib_img
optimize both size and speed fix invert for color screens Change-Id: I7edecae32dcb3daf5b3ed984a0e5b3d463269e60
-rw-r--r--apps/plugins/lua/include_lua/blit.lua2
-rw-r--r--apps/plugins/lua/include_lua/color.lua31
-rw-r--r--apps/plugins/lua/include_lua/draw.lua229
-rw-r--r--apps/plugins/lua/include_lua/image.lua117
-rw-r--r--apps/plugins/lua/include_lua/lcd.lua24
-rw-r--r--apps/plugins/lua/include_lua/print.lua80
-rw-r--r--apps/plugins/lua/rocklib_img.c632
7 files changed, 513 insertions, 602 deletions
diff --git a/apps/plugins/lua/include_lua/blit.lua b/apps/plugins/lua/include_lua/blit.lua
index 6c5ea377e4..3505ae4943 100644
--- a/apps/plugins/lua/include_lua/blit.lua
+++ b/apps/plugins/lua/include_lua/blit.lua
@@ -36,7 +36,7 @@ if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end
36 36
37local _blit ={} do 37local _blit ={} do
38 38
39 _blit.CUSTOM = 0xFF --user defined blit function func(dst_val, x, y, src_val, x, y) 39 _blit.CUSTOM = nil --user defined blit function func(dst_val, x, y, src_val, x, y)
40 _blit.BCOPY = 0x0 --copy (use :copy() instead it is slightly faster 40 _blit.BCOPY = 0x0 --copy (use :copy() instead it is slightly faster
41 _blit.BOR = 0x1 --OR source and dest pixels 41 _blit.BOR = 0x1 --OR source and dest pixels
42 _blit.BXOR = 0x2 --XOR source and dest pixels 42 _blit.BXOR = 0x2 --XOR source and dest pixels
diff --git a/apps/plugins/lua/include_lua/color.lua b/apps/plugins/lua/include_lua/color.lua
index ed2e4f865e..fd321edd9d 100644
--- a/apps/plugins/lua/include_lua/color.lua
+++ b/apps/plugins/lua/include_lua/color.lua
@@ -49,17 +49,9 @@ local _clr = {} do
49 maxstate = (bit.lshift(1, 24) - 1) 49 maxstate = (bit.lshift(1, 24) - 1)
50 end 50 end
51 51
52 local function init(v)
53 return v or 0
54 end
55
56 -- clamps value to >= min and <= max rolls over to opposite 52 -- clamps value to >= min and <= max rolls over to opposite
57 local function clamp_roll(val, min, max) 53 local function clamp_roll(val, min, max)
58 if min > max then 54 -- Warning doesn't check if min < max
59 local swap = min
60 min, max = max, swap
61 end
62
63 if val < min then 55 if val < min then
64 val = max 56 val = max
65 elseif val > max then 57 elseif val > max then
@@ -72,12 +64,12 @@ local _clr = {} do
72 -- sets color -- monochrome / greyscale use 'set' -- color targets 'r,b,g' 64 -- sets color -- monochrome / greyscale use 'set' -- color targets 'r,b,g'
73 -- on monochrome/ greyscale targets: 65 -- on monochrome/ greyscale targets:
74 -- '-1' sets the highest 'color' state & 0 is the minimum 'color' state 66 -- '-1' sets the highest 'color' state & 0 is the minimum 'color' state
75 local function clrset(set, r, g, b) 67 _clr.set = function(set, r, g, b)
76 local color = set or 0 68 local color = set or 0
77 69
78 if IS_COLOR_TARGET then 70 if IS_COLOR_TARGET then
79 if (r ~= _NIL or g ~= _NIL or b ~= _NIL) then 71 if (r or g or b) then
80 r, g, b = init(r), init(g), init(b) 72 r, g, b = (r or 0), (g or 0), (b or 0)
81 color = rb.lcd_rgbpack(r, g, b) 73 color = rb.lcd_rgbpack(r, g, b)
82 end 74 end
83 end 75 end
@@ -86,21 +78,21 @@ local _clr = {} do
86 end -- clrset 78 end -- clrset
87 79
88 -- de/increments current color by 'inc' -- optionally color targets by 'r,g,b' 80 -- de/increments current color by 'inc' -- optionally color targets by 'r,g,b'
89 local function clrinc(current, inc, r, g, b) 81 _clr.inc = function(current, inc, r, g, b)
90 local color = 0 82 local color = 0
91 current = current or color 83 current = current or color
92 inc = inc or 1 84 inc = inc or 1
93 85
94 if IS_COLOR_TARGET then 86 if IS_COLOR_TARGET then
95 local ru, gu, bu = rb.lcd_rgbunpack(current); 87 local ru, gu, bu = rb.lcd_rgbunpack(current);
96 if (r ~= _NIL or g ~= _NIL or b ~= _NIL) then 88 if (r or g or b) then
97 r, g, b = init(r), init(g), init(b) 89 r, g, b = (r or 0), (g or 0), (b or 0)
98 ru = ru + r; gu = gu + g; bu = bu + b 90 ru = ru + r; gu = gu + g; bu = bu + b
99 color = rb.lcd_rgbpack(ru, gu, bu)
100 else 91 else
101 ru = ru + inc; gu = gu + inc; bu = bu + inc 92 ru = ru + inc; gu = gu + inc; bu = bu + inc
102 color = rb.lcd_rgbpack(ru, gu, bu)
103 end 93 end
94
95 color = rb.lcd_rgbpack(ru, gu, bu)
104 else 96 else
105 color = current + inc 97 color = current + inc
106 end 98 end
@@ -108,9 +100,6 @@ local _clr = {} do
108 return clamp_roll(color, 0, maxstate) 100 return clamp_roll(color, 0, maxstate)
109 end -- clrinc 101 end -- clrinc
110 102
111 -- expose functions to the outside through _clr table
112 _clr.set = clrset
113 _clr.inc = clrinc
114end -- color functions 103end -- color functions
115 104
116return _clr 105return _clr
diff --git a/apps/plugins/lua/include_lua/draw.lua b/apps/plugins/lua/include_lua/draw.lua
index 4409ab7838..7b239339ff 100644
--- a/apps/plugins/lua/include_lua/draw.lua
+++ b/apps/plugins/lua/include_lua/draw.lua
@@ -52,35 +52,39 @@ if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end
52 52
53local _draw = {} do 53local _draw = {} do
54 54
55 local rocklib_image = getmetatable(rb.lcd_framebuffer())
56 setmetatable(_draw, rocklib_image)
57
55 -- Internal Constants 58 -- Internal Constants
56 local _LCD = rb.lcd_framebuffer() 59 local _LCD = rb.lcd_framebuffer()
57 local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT 60 local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT
58 local BSAND = 8 -- blits color to dst if src <> 0 61 local BSAND = 8 -- blits color to dst if src <> 0
59 local _NIL = nil -- nil placeholder 62 local _NIL = nil -- nil placeholder
60 63
61 local function set_viewport(vp) 64 local _abs = math.abs
62 if not vp then rb.set_viewport() return end 65 local _clear = rocklib_image.clear
63 if rb.LCD_DEPTH == 2 then -- invert 2-bit screens 66 local _copy = rocklib_image.copy
64 --vp.drawmode = bit.bxor(vp.drawmode, 4) 67 local _ellipse = rocklib_image.ellipse
65 vp.fg_pattern = 3 - vp.fg_pattern 68 local _get = rocklib_image.get
66 vp.bg_pattern = 3 - vp.bg_pattern 69 local _line = rocklib_image.line
67 end 70 local _marshal = rocklib_image.marshal
68 rb.set_viewport(vp) 71 local _min = math.min
69 end 72 local _newimg = rb.new_image
73 local _points = rocklib_image.points
70 74
71 -- line 75 -- line
72 local function line(img, x1, y1, x2, y2, color, bClip) 76 _draw.line = function(img, x1, y1, x2, y2, color, bClip)
73 img:line(x1, y1, x2, y2, color, bClip) 77 _line(img, x1, y1, x2, y2, color, bClip)
74 end 78 end
75 79
76 -- horizontal line; x, y define start point; length in horizontal direction 80 -- horizontal line; x, y define start point; length in horizontal direction
77 local function hline(img, x, y , length, color, bClip) 81 local function hline(img, x, y , length, color, bClip)
78 img:line(x, y, x + length, _NIL, color, bClip) 82 _line(img, x, y, x + length, _NIL, color, bClip)
79 end 83 end
80 84
81 -- vertical line; x, y define start point; length in vertical direction 85 -- vertical line; x, y define start point; length in vertical direction
82 local function vline(img, x, y , length, color, bClip) 86 local function vline(img, x, y , length, color, bClip)
83 img:line(x, y, _NIL, y + length, color, bClip) 87 _line(img, x, y, _NIL, y + length, color, bClip)
84 end 88 end
85 89
86 -- draws a non-filled figure based on points in t-points 90 -- draws a non-filled figure based on points in t-points
@@ -100,7 +104,7 @@ local _draw = {} do
100 104
101 local pt2 = t_points[i + 1] or pt_first_last-- first and last point 105 local pt2 = t_points[i + 1] or pt_first_last-- first and last point
102 106
103 img:line(pt1[1] + x, pt1[2] + y, pt2[1]+x, pt2[2]+y, color, bClip) 107 _line(img, pt1[1] + x, pt1[2] + y, pt2[1] + x, pt2[2] + y, color, bClip)
104 end 108 end
105 109
106 end 110 end
@@ -109,90 +113,80 @@ local _draw = {} do
109 local function rect(img, x, y, width, height, color, bClip) 113 local function rect(img, x, y, width, height, color, bClip)
110 if width == 0 or height == 0 then return end 114 if width == 0 or height == 0 then return end
111 115
112 local ppt = {{0, 0}, {width, 0}, {width, height}, {0, height}} 116 polyline(img, x, y, {{0, 0}, {width, 0}, {width, height}, {0, height}}, color, true, bClip)
113 polyline(img, x, y, ppt, color, true, bClip) 117
114 --[[
115 vline(img, x, y, height, color, bClip);
116 vline(img, x + width, y, height, color, bClip);
117 hline(img, x, y, width, color, bClip);
118 hline(img, x, y + height, width, color, bClip);]]
119 end 118 end
120 119
121 -- filled rect, fillcolor is color if left empty 120 -- filled rect, fillcolor is color if left empty
122 local function rect_filled(img, x, y, width, height, color, fillcolor, bClip) 121 _draw.rect_filled = function(img, x, y, width, height, color, fillcolor, bClip)
123 if width == 0 or height == 0 then return end 122 if width == 0 or height == 0 then return end
124 123
125 if not fillcolor then 124 if not fillcolor then
126 img:clear(color, x, y, x + width, y + height, bClip) 125 _clear(img, color, x, y, x + width, y + height, bClip)
127 else 126 else
128 img:clear(fillcolor, x, y, x + width, y + height, bClip) 127 _clear(img, fillcolor, x, y, x + width, y + height, bClip)
129 rect(img, x, y, width, height, color, bClip) 128 rect(img, x, y, width, height, color, bClip)
130 end 129 end
131 end 130 end
132 131
133 -- circle cx,cy define center point 132 -- circle cx,cy define center point
134 local function circle(img, cx, cy, radius, color, bClip) 133 _draw.circle = function(img, cx, cy, radius, color, bClip)
135 local r = radius 134 local r = radius
136 img:ellipse(cx - r, cy - r, cx + r, cy + r, color, _NIL, bClip) 135 _ellipse(img, cx - r, cy - r, cx + r, cy + r, color, _NIL, bClip)
137 end 136 end
138 137
139 -- filled circle cx,cy define center, fillcolor is color if left empty 138 -- filled circle cx,cy define center, fillcolor is color if left empty
140 local function circle_filled(img, cx, cy, radius, color, fillcolor, bClip) 139 _draw.circle_filled = function(img, cx, cy, radius, color, fillcolor, bClip)
141 fillcolor = fillcolor or color 140 fillcolor = fillcolor or color
142 local r = radius 141 local r = radius
143 img:ellipse(cx - r, cy - r, cx + r, cy + r, color, fillcolor, bClip) 142 _ellipse(img, cx - r, cy - r, cx + r, cy + r, color, fillcolor, bClip)
144 end 143 end
145 144
146 -- ellipse that fits into defined rect 145 -- ellipse that fits into defined rect
147 local function ellipse_rect(img, x1, y1, x2, y2, color, bClip) 146 _draw.ellipse_rect = function(img, x1, y1, x2, y2, color, bClip)
148 img:ellipse(x1, y1, x2, y2, color, _NIL, bClip) 147 _ellipse(img, x1, y1, x2, y2, color, _NIL, bClip)
149 end 148 end
150 149
151 --ellipse that fits into defined rect, fillcolor is color if left empty 150 --ellipse that fits into defined rect, fillcolor is color if left empty
152 local function ellipse_rect_filled(img, x1, y1, x2, y2, color, fillcolor, bClip) 151 _draw.ellipse_rect_filled = function(img, x1, y1, x2, y2, color, fillcolor, bClip)
153 if not fillcolor then fillcolor = color end 152 if not fillcolor then fillcolor = color end
154 153
155 img:ellipse(x1, y1, x2, y2, color, fillcolor, bClip) 154 _ellipse(img, x1, y1, x2, y2, color, fillcolor, bClip)
156 end 155 end
157 156
158 -- ellipse cx, cy define center point; a, b the major/minor axis 157 -- ellipse cx, cy define center point; a, b the major/minor axis
159 local function ellipse(img, cx, cy, a, b, color, bClip) 158 _draw.ellipse = function(img, cx, cy, a, b, color, bClip)
160 img:ellipse(cx - a, cy - b, cx + a, cy + b, color, _NIL, bClip) 159 _ellipse(img, cx - a, cy - b, cx + a, cy + b, color, _NIL, bClip)
161 end 160 end
162 161
163 -- filled ellipse cx, cy define center point; a, b the major/minor axis 162 -- filled ellipse cx, cy define center point; a, b the major/minor axis
164 -- fillcolor is color if left empty 163 -- fillcolor is color if left empty
165 local function ellipse_filled(img, cx, cy, a, b, color, fillcolor, bClip) 164 _draw.ellipse_filled = function(img, cx, cy, a, b, color, fillcolor, bClip)
166 if not fillcolor then fillcolor = color end 165 if not fillcolor then fillcolor = color end
167 166
168 img:ellipse(cx - a, cy - b, cx + a, cy + b, color, fillcolor, bClip) 167 _ellipse(img, cx - a, cy - b, cx + a, cy + b, color, fillcolor, bClip)
169 end 168 end
170 169
171 -- rounded rectangle 170 -- rounded rectangle
172 local function rounded_rect(img, x, y, w, h, radius, color, bClip) 171 local function rounded_rect(img, x, y, w, h, radius, color, bClip)
173 local c_img 172 local c_img
174
175 local function blit(dx, dy, sx, sy, ox, oy)
176 img:copy(c_img, dx, dy, sx, sy, ox, oy, bClip, BSAND, color)
177 end
178
179 if w == 0 or h == 0 then return end 173 if w == 0 or h == 0 then return end
180 174
181 -- limit the radius of the circle otherwise it will overtake the rect 175 -- limit the radius of the circle otherwise it will overtake the rect
182 radius = math.min(w / 2, radius) 176 radius = _min(w / 2, radius)
183 radius = math.min(h / 2, radius) 177 radius = _min(h / 2, radius)
184 178
185 local r = radius 179 local r = radius
186 180
187 c_img = rb.new_image(r * 2 + 1, r * 2 + 1) 181 c_img = _newimg(r * 2 + 1, r * 2 + 1)
188 c_img:clear(0) 182 _clear(c_img, 0)
189 circle(c_img, r + 1, r + 1, r, 0xFFFFFF) 183 _ellipse(c_img, 1, 1, 1 + r + r, 1 + r + r, 0x1, _NIL, bClip)
190 184
191 -- copy 4 pieces of circle to their respective corners 185 -- copy 4 pieces of circle to their respective corners
192 blit(x, y, _NIL, _NIL, r + 1, r + 1) --TL 186 _copy(img, c_img, x, y, _NIL, _NIL, r + 1, r + 1, bClip, BSAND, color) --TL
193 blit(x + w - r - 2, y, r, _NIL, r + 1, r + 1) --TR 187 _copy(img, c_img, x + w - r - 2, y, r, _NIL, r + 1, r + 1, bClip, BSAND, color) --TR
194 blit(x , y + h - r - 2, _NIL, r, r + 1, _NIL) --BL 188 _copy(img, c_img, x , y + h - r - 2, _NIL, r, r + 1, _NIL, bClip, BSAND, color) --BL
195 blit(x + w - r - 2, y + h - r - 2, r, r, r + 1, r + 1)--BR 189 _copy(img, c_img, x + w - r - 2, y + h - r - 2, r, r, r + 1, r + 1, bClip, BSAND, color)--BR
196 c_img = _NIL 190 c_img = _NIL
197 191
198 vline(img, x, y + r, h - r * 2, color, bClip); 192 vline(img, x, y + r, h - r * 2, color, bClip);
@@ -202,38 +196,34 @@ local _draw = {} do
202 end 196 end
203 197
204 -- rounded rectangle fillcolor is color if left empty 198 -- rounded rectangle fillcolor is color if left empty
205 local function rounded_rect_filled(img, x, y, w, h, radius, color, fillcolor, bClip) 199 _draw.rounded_rect_filled = function(img, x, y, w, h, radius, color, fillcolor, bClip)
206 local c_img 200 local c_img
207 201
208 local function blit(dx, dy, sx, sy, ox, oy)
209 img:copy(c_img, dx, dy, sx, sy, ox, oy, bClip, BSAND, fillcolor)
210 end
211
212 if w == 0 or h == 0 then return end 202 if w == 0 or h == 0 then return end
213 203
214 if not fillcolor then fillcolor = color end 204 if not fillcolor then fillcolor = color end
215 205
216 -- limit the radius of the circle otherwise it will overtake the rect 206 -- limit the radius of the circle otherwise it will overtake the rect
217 radius = math.min(w / 2, radius) 207 radius = _min(w / 2, radius)
218 radius = math.min(h / 2, radius) 208 radius = _min(h / 2, radius)
219 209
220 local r = radius 210 local r = radius
221 211
222 c_img = rb.new_image(r * 2 + 1, r * 2 + 1) 212 c_img = _newimg(r * 2 + 1, r * 2 + 1)
223 c_img:clear(0) 213 _clear(c_img, 0)
224 circle_filled(c_img, r + 1, r + 1, r, fillcolor) 214 _ellipse(c_img, 1, 1, 1 + r + r, 1 + r + r, 0x1, 0x1, bClip)
225 215
226 -- copy 4 pieces of circle to their respective corners 216 -- copy 4 pieces of circle to their respective corners
227 blit(x, y, _NIL, _NIL, r + 1, r + 1) --TL 217 _copy(img, c_img, x, y, _NIL, _NIL, r + 1, r + 1, bClip, BSAND, fillcolor) --TL
228 blit(x + w - r - 2, y, r, _NIL, r + 1, r + 1) --TR 218 _copy(img, c_img, x + w - r - 2, y, r, _NIL, r + 1, r + 1, bClip, BSAND, fillcolor) --TR
229 blit(x, y + h - r - 2, _NIL, r, r + 1, _NIL) --BL 219 _copy(img, c_img, x, y + h - r - 2, _NIL, r, r + 1, _NIL, bClip, BSAND, fillcolor) --BL
230 blit(x + w - r - 2, y + h - r - 2, r, r, r + 1, r + 1) --BR 220 _copy(img, c_img, x + w - r - 2, y + h - r - 2, r, r, r + 1, r + 1, bClip, BSAND, fillcolor) --BR
231 c_img = _NIL 221 c_img = _NIL
232 222
233 -- finish filling areas circles didn't cover 223 -- finish filling areas circles didn't cover
234 img:clear(fillcolor, x + r, y, x + w - r, y + h - 1, bClip) 224 _clear(img, fillcolor, x + r, y, x + w - r, y + h - 1, bClip)
235 img:clear(fillcolor, x, y + r, x + r, y + h - r, bClip) 225 _clear(img, fillcolor, x, y + r, x + r, y + h - r, bClip)
236 img:clear(fillcolor, x + w - r, y + r, x + w - 1, y + h - r - 1, bClip) 226 _clear(img, fillcolor, x + w - r, y + r, x + w - 1, y + h - r - 1, bClip)
237 227
238 if fillcolor ~= color then 228 if fillcolor ~= color then
239 rounded_rect(img, x, y, w, h, r, color, bClip) 229 rounded_rect(img, x, y, w, h, r, color, bClip)
@@ -241,23 +231,23 @@ local _draw = {} do
241 end 231 end
242 232
243 -- draws an image at xy coord in dest image 233 -- draws an image at xy coord in dest image
244 local function image(dst, src, x, y, bClip) 234 _draw.image = function(dst, src, x, y, bClip)
245 if not src then --make sure an image was passed, otherwise bail 235 if not src then --make sure an image was passed, otherwise bail
246 rb.splash(rb.HZ, "No Image!") 236 rb.splash(rb.HZ, "No Image!")
247 return _NIL 237 return _NIL
248 end 238 end
249 239
250 dst:copy(src, x, y, 1, 1, _NIL, _NIL, bClip) 240 _copy(dst, src, x, y, 1, 1, _NIL, _NIL, bClip)
251 end 241 end
252 242
253 -- floods an area of targetclr with fillclr x, y specifies the start seed 243 -- floods an area of targetclr with fillclr x, y specifies the start seed
254 function flood_fill(img, x, y, targetclr, fillclr) 244 _draw.flood_fill = function(img, x, y, targetclr, fillclr)
255 -- scanline 4-way flood algorithm 245 -- scanline 4-way flood algorithm
256 -- ^ 246 -- ^
257 -- <--------x---> 247 -- <--------x--->
258 -- v 248 -- v
259 -- check that target color doesn't = fill and the first point is target color 249 -- check that target color doesn't = fill and the first point is target color
260 if targetclr == fillclr or targetclr ~= img:get(x,y, true) then return end 250 if targetclr == fillclr or targetclr ~= _get(img, x, y, true) then return end
261 local max_w = img:width() 251 local max_w = img:width()
262 local max_h = img:height() 252 local max_h = img:height()
263 253
@@ -271,21 +261,20 @@ local _draw = {} do
271 -- y coordinates are in even indices 261 -- y coordinates are in even indices
272 262
273 local qtail = 0 263 local qtail = 0
274 local iter_n; -- North iteration
275 local iter_s; -- South iteration
276 264
277 local function check_ns(val, x, y) 265 local function check_ns(val, x, y)
278 if targetclr == val then 266 if targetclr == val then
279 if targetclr == iter_n() then 267 y = y - 1
268 if targetclr == _get(img, x, y, true) then -- north
280 qtail = qtail + 2 269 qtail = qtail + 2
281 qpt[qtail - 1] = x 270 qpt[qtail - 1] = x
282 qpt[qtail] = (y - 1) 271 qpt[qtail] = y
283 end 272 end
284 273 y = y + 2
285 if targetclr == iter_s() then 274 if targetclr == _get(img, x, y, true) then -- south
286 qtail = qtail + 2 275 qtail = qtail + 2
287 qpt[qtail - 1] = x 276 qpt[qtail - 1] = x
288 qpt[qtail] = (y + 1) 277 qpt[qtail] = y
289 end 278 end
290 return fillclr 279 return fillclr
291 end 280 end
@@ -293,17 +282,12 @@ local _draw = {} do
293 end 282 end
294 283
295 local function seed_pt(x, y) 284 local function seed_pt(x, y)
296 -- will never hit max_w * max_h^2 but make sure not to end early 285 -- should never hit max but make sure not to end early
297 for qhead = 2, max_w * max_h * max_w * max_h, 2 do 286 for qhead = 2, 0x40000000, 2 do
298
299 if targetclr == img:get(x, y, true) then
300 iter_n = img:points(x, y - 1, 1, y - 1)
301 iter_s = img:points(x, y + 1, 1, y + 1)
302 img:marshal(x, y, 1, y, _NIL, _NIL, true, check_ns)
303 287
304 iter_n = img:points(x + 1, y - 1, max_w, y - 1) 288 if targetclr == _get(img, x, y, true) then
305 iter_s = img:points(x + 1, y + 1, max_w, y + 1) 289 _marshal(img, x, y, 1, y, _NIL, _NIL, true, check_ns) -- west
306 img:marshal(x + 1, y, max_w, y, _NIL, _NIL, true, check_ns) 290 _marshal(img, x + 1, y, max_w, y, _NIL, _NIL, true, check_ns) -- east
307 end 291 end
308 292
309 x = qpt[qhead - 1] 293 x = qpt[qhead - 1]
@@ -320,7 +304,7 @@ local _draw = {} do
320 end -- flood_fill 304 end -- flood_fill
321 305
322 -- draws a closed figure based on points in t_points 306 -- draws a closed figure based on points in t_points
323 local function polygon(img, x, y, t_points, color, fillcolor, bClip) 307 _draw.polygon = function(img, x, y, t_points, color, fillcolor, bClip)
324 if #t_points < 2 then error("not enough points", 3) end 308 if #t_points < 2 then error("not enough points", 3) end
325 309
326 if fillcolor then 310 if fillcolor then
@@ -335,35 +319,41 @@ local _draw = {} do
335 if pt[2] < y_min then y_min = pt[2] end 319 if pt[2] < y_min then y_min = pt[2] end
336 if pt[2] > y_max then y_max = pt[2] end 320 if pt[2] > y_max then y_max = pt[2] end
337 end 321 end
338 w = math.abs(x_max) + math.abs(x_min) 322 w = _abs(x_max) + _abs(x_min)
339 h = math.abs(y_max) + math.abs(y_min) 323 h = _abs(y_max) + _abs(y_min)
340 x_min = x_min - 2 -- leave a border to use flood_fill 324 x_min = x_min - 2 -- leave a border to use flood_fill
341 y_min = y_min - 2 325 y_min = y_min - 2
342 326
343 local fill_img = rb.new_image(w + 3, h + 3) 327 local fill_img = _newimg(w + 3, h + 3)
344 fill_img:clear(0xFFFFFF) 328 _clear(fill_img, 0x1)
345 329
346 for i = 1, #t_points, 1 do 330 for i = 1, #t_points, 1 do
347 local pt1 = t_points[i] 331 local pt1 = t_points[i]
348 local pt2 = t_points[i + 1] or t_points[1]-- first and last point 332 local pt2 = t_points[i + 1] or t_points[1]-- first and last point
349 fill_img:line(pt1[1] - x_min, pt1[2] - y_min, 333 _line(fill_img, pt1[1] - x_min, pt1[2] - y_min,
350 pt2[1]- x_min, pt2[2] - y_min, 0) 334 pt2[1]- x_min, pt2[2] - y_min, 0)
351 335
352 end 336 end
353 flood_fill(fill_img, fill_img:width(), fill_img:height() , 1, 0) 337 _draw.flood_fill(fill_img, fill_img:width(), fill_img:height() , 0x1, 0x0)
354 img:copy(fill_img, x - 1, y - 1, _NIL, _NIL, _NIL, _NIL, bClip, BSAND, fillcolor) 338 _copy(img, fill_img, x - 1, y - 1, _NIL, _NIL, _NIL, _NIL, bClip, BSAND, fillcolor)
355 end 339 end
356 340
357 polyline(img, x, y, t_points, color, true, bClip) 341 polyline(img, x, y, t_points, color, true, bClip)
358 end 342 end
359 343
360 -- draw text onto image if width/height are supplied text is centered 344 -- draw text onto image if width/height are supplied text is centered
361 local function text(img, x, y, width, height, font, color, text) 345 _draw.text = function(img, x, y, width, height, font, color, text)
362 font = font or rb.FONT_UI 346 font = font or rb.FONT_UI
363 347
364 local opts = {x = 0, y = 0, width = LCD_W - 1, height = LCD_H - 1, 348 local opts = {x = 0, y = 0, width = LCD_W - 1, height = LCD_H - 1,
365 font = font, drawmode = 3, fg_pattern = 0xFFFFFF, bg_pattern = 0} 349 font = font, drawmode = 3, fg_pattern = 0x1, bg_pattern = 0}
366 set_viewport(opts) 350
351 if rb.LCD_DEPTH == 2 then -- invert 2-bit screens
352 --vp.drawmode = bit.bxor(vp.drawmode, 4)
353 vp.fg_pattern = 3 - vp.fg_pattern
354 vp.bg_pattern = 3 - vp.bg_pattern
355 end
356 rb.set_viewport(opts)
367 357
368 local res, w, h = rb.font_getstringsize(text, font) 358 local res, w, h = rb.font_getstringsize(text, font)
369 359
@@ -380,8 +370,8 @@ local _draw = {} do
380 end 370 end
381 371
382 -- make a copy of the current screen for later 372 -- make a copy of the current screen for later
383 local screen_img = rb.new_image(LCD_W, LCD_H) 373 local screen_img = _newimg(LCD_W, LCD_H)
384 screen_img:copy(_LCD) 374 _copy(screen_img, _LCD)
385 375
386 -- check if the screen buffer is supplied image if so set img to the copy 376 -- check if the screen buffer is supplied image if so set img to the copy
387 if img == _LCD then 377 if img == _LCD then
@@ -391,10 +381,6 @@ local _draw = {} do
391 -- we will be printing the text to the screen then blitting into img 381 -- we will be printing the text to the screen then blitting into img
392 rb.lcd_clear_display() 382 rb.lcd_clear_display()
393 383
394 local function blit(dx, dy)
395 img:copy(_LCD, dx, dy, _NIL, _NIL, _NIL, _NIL, false, BSAND, color)
396 end
397
398 if w > LCD_W then -- text is too long for the screen do it in chunks 384 if w > LCD_W then -- text is too long for the screen do it in chunks
399 local l = 1 385 local l = 1
400 local resp, wp, hp 386 local resp, wp, hp
@@ -417,7 +403,7 @@ local _draw = {} do
417 end 403 end
418 404
419 -- using the mask we made blit color into img 405 -- using the mask we made blit color into img
420 blit(x + width, y + height) 406 _copy(img, _LCD, x + width, y + height, _NIL, _NIL, _NIL, _NIL, false, BSAND, color)
421 x = x + wp 407 x = x + wp
422 rb.lcd_clear_display() 408 rb.lcd_clear_display()
423 lenr = text:len() 409 lenr = text:len()
@@ -426,43 +412,20 @@ local _draw = {} do
426 rb.lcd_putsxy(0, 0, text) 412 rb.lcd_putsxy(0, 0, text)
427 413
428 -- using the mask we made blit color into img 414 -- using the mask we made blit color into img
429 blit(x + width, y + height) 415 _copy(img, _LCD, x + width, y + height, _NIL, _NIL, _NIL, _NIL, false, BSAND, color)
430 end 416 end
431 417
432 _LCD:copy(screen_img) -- restore screen 418 _copy(_LCD, screen_img) -- restore screen
433 set_viewport() -- set viewport default 419 rb.set_viewport() -- set viewport default
434 return res, w, h 420 return res, w, h
435 end 421 end
436 422
437 -- expose functions to the outside through _draw table 423 -- expose internal functions to the outside through _draw table
438 _draw.image = image
439 _draw.text = text
440 _draw.line = line
441 _draw.hline = hline 424 _draw.hline = hline
442 _draw.vline = vline 425 _draw.vline = vline
443 _draw.polygon = polygon
444 _draw.polyline = polyline 426 _draw.polyline = polyline
445 _draw.rect = rect 427 _draw.rect = rect
446 _draw.circle = circle
447 _draw.ellipse = ellipse
448 _draw.flood_fill = flood_fill
449 _draw.ellipse_rect = ellipse_rect
450 _draw.rounded_rect = rounded_rect 428 _draw.rounded_rect = rounded_rect
451 -- filled functions use color as fillcolor if fillcolor is left empty...
452 _draw.rect_filled = rect_filled
453 _draw.circle_filled = circle_filled
454 _draw.ellipse_filled = ellipse_filled
455 _draw.ellipse_rect_filled = ellipse_rect_filled
456 _draw.rounded_rect_filled = rounded_rect_filled
457
458 -- adds the above _draw functions into the metatable for RLI_IMAGE
459 local ex = getmetatable(rb.lcd_framebuffer())
460 for k, v in pairs(_draw) do
461 if ex[k] == _NIL then
462 ex[k] = v
463 end
464 end
465
466end -- _draw functions 429end -- _draw functions
467 430
468return _draw 431return _draw
diff --git a/apps/plugins/lua/include_lua/image.lua b/apps/plugins/lua/include_lua/image.lua
index c8d7aad9dd..2b2a1ce19f 100644
--- a/apps/plugins/lua/include_lua/image.lua
+++ b/apps/plugins/lua/include_lua/image.lua
@@ -65,35 +65,43 @@ if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end
65 65
66local _img = {} do 66local _img = {} do
67 67
68 local rocklib_image = getmetatable(rb.lcd_framebuffer())
69 setmetatable(_img, rocklib_image)
70
68 -- internal constants 71 -- internal constants
69 local _NIL = nil -- _NIL placeholder 72 local _NIL = nil -- _NIL placeholder
70 local _math = require("math_ex") -- math functions needed 73 local _math = require("math_ex") -- math functions needed
71 local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT 74 local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT
72 75
76 local _copy = rocklib_image.copy
77 local _get = rocklib_image.get
78 local _marshal = rocklib_image.marshal
79 local _points = rocklib_image.points
80
73 -- returns new image -of- img sized to fit w/h tiling to fit if needed 81 -- returns new image -of- img sized to fit w/h tiling to fit if needed
74 local function tile(img, w, h) 82 _img.tile = function(img, w, h)
75 local hs , ws = img:height(), img:width() 83 local hs , ws = img:height(), img:width()
76 local t_img = rb.new_image(w, h) 84 local t_img = rb.new_image(w, h)
77 85
78 for x = 1, w, ws do t_img:copy(img, x, 1, 1, 1) end 86 for x = 1, w, ws do _copy(t_img, img, x, 1, 1, 1) end
79 for y = hs, h, hs do t_img:copy(t_img, 1, y, 1, 1, w, hs) end 87 for y = hs, h, hs do _copy(t_img, t_img, 1, y, 1, 1, w, hs) end
80 return t_img 88 return t_img
81 end 89 end
82 90
83 -- resizes src to size of dst 91 -- resizes src to size of dst
84 local function resize(dst, src) 92 _img.resize = function(dst, src)
85 -- simple nearest neighbor resize derived from rockbox - pluginlib_bmp.c 93 -- simple nearest neighbor resize derived from rockbox - pluginlib_bmp.c
86 -- pretty rough results highly recommend building one more suited.. 94 -- pretty rough results highly recommend building one more suited..
87 local dw, dh = dst:width(), dst:height() 95 local dw, dh = dst:width(), dst:height()
88 96
89 local xstep = (bit.lshift(src:width(),8) / (dw)) + 1 97 local xstep = (bit.lshift(src:width(), 8) / (dw)) + 1
90 local ystep = (bit.lshift(src:height(),8) / (dh)) 98 local ystep = (bit.lshift(src:height(), 8) / (dh))
91 99
92 local xpos, ypos = 0, 0 100 local xpos, ypos = 0, 0
93 local src_x, src_y 101 local src_x, src_y
94 102
95 -- walk the dest get src pixel 103 -- walk the dest get src pixel
96 function rsz_trans(val, x, y) 104 local function rsz_trans(val, x, y)
97 if x == 1 then 105 if x == 1 then
98 src_y = bit.rshift(ypos,8) + 1 106 src_y = bit.rshift(ypos,8) + 1
99 xpos = xstep - bit.rshift(xstep,4) + 1 107 xpos = xstep - bit.rshift(xstep,4) + 1
@@ -101,14 +109,14 @@ local _img = {} do
101 end 109 end
102 src_x = bit.rshift(xpos,8) + 1 110 src_x = bit.rshift(xpos,8) + 1
103 xpos = xpos + xstep 111 xpos = xpos + xstep
104 return (src:get(src_x, src_y, true) or 0) 112 return (_get(src, src_x, src_y, true) or 0)
105 end 113 end
106 --/* (dst*, [x1, y1, x2, y2, dx, dy, clip, function]) */ 114 --/* (dst*, [x1, y1, x2, y2, dx, dy, clip, function]) */
107 dst:marshal(1, 1, dw, dh, _NIL, _NIL, false, rsz_trans) 115 _marshal(dst, 1, 1, dw, dh, _NIL, _NIL, false, rsz_trans)
108 end 116 end
109 117
110 -- returns new image -of- img rotated in whole degrees 0 - 360 118 -- returns new image -of- img rotated in whole degrees 0 - 360
111 local function rotate(img, degrees) 119 _img.rotate = function(img, degrees)
112 -- we do this backwards as if dest was the unrotated object 120 -- we do this backwards as if dest was the unrotated object
113 degrees = 360 - degrees 121 degrees = 360 - degrees
114 local c, s = _math.d_cos(degrees), _math.d_sin(degrees) 122 local c, s = _math.d_cos(degrees), _math.d_sin(degrees)
@@ -133,7 +141,7 @@ local _img = {} do
133 |_____| |_______| |_______| ]] 141 |_____| |_______| |_______| ]]
134 142
135 -- walk the dest get translated src pixel, oversamples src to fill gaps 143 -- walk the dest get translated src pixel, oversamples src to fill gaps
136 function rot_trans(val, x, y) 144 local function rot_trans(val, x, y)
137 -- move center x/y to the origin 145 -- move center x/y to the origin
138 local xtran = x - d_xctr; 146 local xtran = x - d_xctr;
139 local ytran = y - d_yctr; 147 local ytran = y - d_yctr;
@@ -142,68 +150,56 @@ local _img = {} do
142 local yrot = ((xtran * s) + (ytran * c)) / 10000 + s_yctr 150 local yrot = ((xtran * s) + (ytran * c)) / 10000 + s_yctr
143 local xrot = ((xtran * c) - (ytran * s)) / 10000 + s_xctr 151 local xrot = ((xtran * c) - (ytran * s)) / 10000 + s_xctr
144 -- upper left of src image back to origin, copy src pixel 152 -- upper left of src image back to origin, copy src pixel
145 return img:get(xrot, yrot, true) or 0 153 return _get(img, xrot, yrot, true) or 0
146 end 154 end
147 r_img:marshal(1, 1, dw, dh, _NIL, _NIL, false, rot_trans) 155 _marshal(r_img, 1, 1, dw, dh, _NIL, _NIL, false, rot_trans)
148 return r_img 156 return r_img
149 end 157 end
150 158
151 -- saves img to file: name 159 -- saves img to file: name
152 local function save(img, name) 160 _img.save = function(img, name)
153 -- bmp saving derived from rockbox - screendump.c 161 -- bmp saving derived from rockbox - screendump.c
154 -- bitdepth is limited by the device 162 -- bitdepth is limited by the device
155 -- eg. device displays greyscale, rgb images are saved greyscale 163 -- eg. device displays greyscale, rgb images are saved greyscale
156 local file 164 local file
157 165 local bbuffer = {} -- concat buffer for s_bytes
158 local fbuffer = {} -- concat buffer for file writes, reused 166 local fbuffer = {} -- concat buffer for file writes, reused
159 167
160 local function dump_fbuffer(thresh)
161 if #fbuffer >= thresh then
162 file:write(table.concat(fbuffer))
163 for i=1, #fbuffer do fbuffer[i] = _NIL end -- reuse table
164 end
165 end
166
167 local function s_bytesLE(bits, value) 168 local function s_bytesLE(bits, value)
168 -- bits must be multiples of 8 (sizeof byte) 169 -- bits must be multiples of 8 (sizeof byte)
169 local byte 170 local byte
170 local result = "" 171 local nbytes = bit.rshift(bits, 3)
171 for b = 1, bit.rshift(bits, 3) do 172 for b = 1, nbytes do
172 if value > 0 then 173 if value > 0 then
173 byte = value % 256 174 byte = value % 256
174 value = (value - byte) / 256 175 value = (value - byte) / 256
175 result = result .. string.char(byte)
176 else 176 else
177 result = result .. string.char(0) 177 byte = 0
178 end 178 end
179 bbuffer[b] = string.char(byte)
179 end 180 end
180 return result 181 return table.concat(bbuffer, _NIL, 1, nbytes)
181 end 182 end
182 183
183 local function s_bytesBE(bits, value) 184 local function s_bytesBE(bits, value)
184 -- bits must be multiples of 8 (sizeof byte) 185 -- bits must be multiples of 8 (sizeof byte)
185 local byte 186 local byte
186 local result = "" 187 local nbytes = bit.rshift(bits, 3)
187 for b = 1, bit.rshift(bits, 3) do 188 for b = nbytes, 1, -1 do
188 if value > 0 then 189 if value > 0 then
189 byte = value % 256 190 byte = value % 256
190 value = (value - byte) / 256 191 value = (value - byte) / 256
191 result = string.char(byte) .. result
192 else 192 else
193 result = string.char(0) .. result 193 byte = 0
194 end 194 end
195 bbuffer[b] = string.char(byte)
195 end 196 end
196 return result 197 return table.concat(bbuffer, _NIL, 1, nbytes)
197 end
198
199 local function c_cmp(color, shift)
200 -- [RR][GG][BB]
201 return bit.band(bit.rshift(color, shift), 0xFF)
202 end 198 end
203 199
204 local cmp = {["r"] = function(c) return c_cmp(c, 16) end, 200 local cmp = {["r"] = function(c) return bit.band(bit.rshift(c, 16), 0xFF) end,
205 ["g"] = function(c) return c_cmp(c, 08) end, 201 ["g"] = function(c) return bit.band(bit.rshift(c, 08), 0xFF) end,
206 ["b"] = function(c) return c_cmp(c, 00) end} 202 ["b"] = function(c) return bit.band(c, 0xFF) end}
207 203
208 local function bmp_color(color) 204 local function bmp_color(color)
209 return s_bytesLE(8, cmp.b(color)).. 205 return s_bytesLE(8, cmp.b(color))..
@@ -314,7 +310,8 @@ local _img = {} do
314 end 310 end
315 end 311 end
316 312
317 dump_fbuffer(0) -- write the header to the file now 313 file:write(table.concat(fbuffer))-- write the header to the file now
314 for i=1, #fbuffer do fbuffer[i] = _NIL end -- reuse table
318 315
319 local imgdata = fbuffer 316 local imgdata = fbuffer
320 -- pad rows to a multiple of 4 bytes 317 -- pad rows to a multiple of 4 bytes
@@ -327,18 +324,23 @@ local _img = {} do
327 end 324 end
328 325
329 -- Bitmap lines start at bottom unless biHeight is negative 326 -- Bitmap lines start at bottom unless biHeight is negative
330 for point in img:points(1, h, w + bytesleft, 1) do 327 for point in _points(img, 1, h, w + bytesleft, 1) do
331 imgdata[#imgdata + 1] = fs_bytes_E(bpp, point or 0) 328 imgdata[#imgdata + 1] = fs_bytes_E(bpp, point or 0)
332 dump_fbuffer(31) -- buffered write, increase # for performance
333 end
334 329
335 dump_fbuffer(0) --write leftovers to file 330 if #fbuffer >= 31 then -- buffered write, increase # for performance
331 file:write(table.concat(fbuffer))
332 for i=1, #fbuffer do fbuffer[i] = _NIL end -- reuse table
333 end
334
335 end
336 file:write(table.concat(fbuffer)) --write leftovers to file
337 fbuffer = _NIL
336 338
337 file:close() 339 file:close()
338 end -- save(img, name) 340 end -- save(img, name)
339 341
340 --searches an image for target color 342 --searches an image for target color
341 local function search(img, x1, y1, x2, y2, targetclr, variation, stepx, stepy) 343 _img.search = function(img, x1, y1, x2, y2, targetclr, variation, stepx, stepy)
342 344
343 if variation > 128 then variation = 128 end 345 if variation > 128 then variation = 128 end
344 if variation < -128 then variation = -128 end 346 if variation < -128 then variation = -128 end
@@ -352,7 +354,7 @@ local _img = {} do
352 targetl = swap 354 targetl = swap
353 end 355 end
354 356
355 for point, x, y in img:points(x1, y1, x2, y2, stepx, stepy) do 357 for point, x, y in _points(img, x1, y1, x2, y2, stepx, stepy) do
356 if point >= targetl and point <= targeth then 358 if point >= targetl and point <= targeth then
357 return point, x, y 359 return point, x, y
358 end 360 end
@@ -362,12 +364,12 @@ local _img = {} do
362 364
363 --[[ we won't be extending these into RLI_IMAGE]] 365 --[[ we won't be extending these into RLI_IMAGE]]
364 -- creates a new rbimage size w x h 366 -- creates a new rbimage size w x h
365 local function new(w, h) 367 _img.new = function(w, h)
366 return rb.new_image(w, h) 368 return rb.new_image(w, h)
367 end 369 end
368 370
369 -- returns new image -of- file: name (_NIL if error) 371 -- returns new image -of- file: name (_NIL if error)
370 local function load(name) 372 _img.load = function(name)
371 return rb.read_bmp_file("/" .. name) 373 return rb.read_bmp_file("/" .. name)
372 end 374 end
373 375
@@ -381,23 +383,6 @@ local _img = {} do
381 _img.RLI_INFO_DEPTH = 0x6 383 _img.RLI_INFO_DEPTH = 0x6
382 _img.RLI_INFO_FORMAT = 0x7 384 _img.RLI_INFO_FORMAT = 0x7
383 _img.RLI_INFO_ADDRESS = 0x8 385 _img.RLI_INFO_ADDRESS = 0x8
384
385 -- expose functions to the outside through _img table
386 _img.save = save
387 _img.search = search
388 _img.rotate = rotate
389 _img.resize = resize
390 _img.tile = tile
391
392 -- adds the above _img functions into the metatable for RLI_IMAGE
393 local ex = getmetatable(rb.lcd_framebuffer())
394 for k, v in pairs(_img) do
395 if ex[k] == _NIL then ex[k] = v end
396 end
397 -- not exposed through RLI_IMAGE
398 _img.new = new
399 _img.load = load
400
401end -- _img functions 386end -- _img functions
402 387
403return _img 388return _img
diff --git a/apps/plugins/lua/include_lua/lcd.lua b/apps/plugins/lua/include_lua/lcd.lua
index e0a3c5895a..f4bb0db695 100644
--- a/apps/plugins/lua/include_lua/lcd.lua
+++ b/apps/plugins/lua/include_lua/lcd.lua
@@ -51,7 +51,6 @@ local _lcd = {} do
51 51
52 --internal constants 52 --internal constants
53 local _NIL = nil -- _NIL placeholder 53 local _NIL = nil -- _NIL placeholder
54 local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT
55 54
56 -- clamps value to >= min and <= max 55 -- clamps value to >= min and <= max
57 local function clamp(val, min, max) 56 local function clamp(val, min, max)
@@ -65,21 +64,21 @@ local _lcd = {} do
65 end 64 end
66 65
67 -- return a copy of lcd screen 66 -- return a copy of lcd screen
68 local function duplicate(t, screen_img) 67 _lcd.duplicate = function(t, screen_img)
69 screen_img = screen_img or rb.new_image() 68 screen_img = screen_img or rb.new_image()
70 screen_img:copy(rb.lcd_framebuffer()) 69 screen_img:copy(rb.lcd_framebuffer())
71 return screen_img 70 return screen_img
72 end 71 end
73 72
74 -- updates screen in specified rectangle 73 -- updates screen in specified rectangle
75 local function update_rect(t, x, y, w, h) 74 _lcd.update_rect = function(t, x, y, w, h)
76 rb.lcd_update_rect(x - 1, y - 1, 75 rb.lcd_update_rect(x - 1, y - 1,
77 clamp(x + w, 1, LCD_W) - 1, 76 clamp(x + w, 1, rb.LCD_WIDTH) - 1,
78 clamp(y + h, 1, LCD_H) - 1) 77 clamp(y + h, 1, rb.LCD_HEIGHT) - 1)
79 end 78 end
80 79
81 -- clears lcd, optional.. ([color, x1, y1, x2, y2, clip]) 80 -- clears lcd, optional.. ([color, x1, y1, x2, y2, clip])
82 local function clear(t, clr, ...) 81 _lcd.clear = function(t, clr, ...)
83 rb.lcd_scroll_stop() --rb really doesn't like bg change while scroll 82 rb.lcd_scroll_stop() --rb really doesn't like bg change while scroll
84 if clr == _NIL and ... == _NIL then 83 if clr == _NIL and ... == _NIL then
85 rb.lcd_clear_display() 84 rb.lcd_clear_display()
@@ -89,7 +88,7 @@ local _lcd = {} do
89 end 88 end
90 89
91 -- loads an image to the screen 90 -- loads an image to the screen
92 local function image(t, src, x, y) 91 _lcd.image = function(t, src, x, y)
93 if not src then --make sure an image was passed, otherwise bail 92 if not src then --make sure an image was passed, otherwise bail
94 rb.splash(rb.HZ, "No Image!") 93 rb.splash(rb.HZ, "No Image!")
95 return _NIL 94 return _NIL
@@ -98,19 +97,19 @@ local _lcd = {} do
98 end 97 end
99 98
100 -- Formattable version of splash 99 -- Formattable version of splash
101 local function splashf(t, timeout, ...) 100 _lcd.splashf = function(t, timeout, ...)
102 rb.splash(timeout, string.format(...)) 101 rb.splash(timeout, string.format(...))
103 end 102 end
104 103
105 -- Gets size of text 104 -- Gets size of text
106 local function text_extent(t, msg, font) 105 _lcd.text_extent = function(t, msg, font)
107 font = font or rb.FONT_UI 106 font = font or rb.FONT_UI
108 107
109 return rb.font_getstringsize(msg, font) 108 return rb.font_getstringsize(msg, font)
110 end 109 end
111 110
112 -- Sets viewport size 111 -- Sets viewport size
113 local function set_viewport(t, vp) 112 _lcd.set_viewport = function(t, vp)
114 if not vp then rb.set_viewport() return end 113 if not vp then rb.set_viewport() return end
115 if rb.LCD_DEPTH == 2 then -- invert 2-bit screens 114 if rb.LCD_DEPTH == 2 then -- invert 2-bit screens
116 --vp.drawmode = bit.bxor(vp.drawmode, 4) 115 --vp.drawmode = bit.bxor(vp.drawmode, 4)
@@ -133,14 +132,17 @@ local _lcd = {} do
133 end 132 end
134 133
135 --expose functions to the outside through _lcd table 134 --expose functions to the outside through _lcd table
135--[[
136 _lcd.text_extent = text_extent 136 _lcd.text_extent = text_extent
137 _lcd.set_viewport = set_viewport 137 _lcd.set_viewport = set_viewport
138 _lcd.duplicate = duplicate 138 _lcd.duplicate = duplicate
139 _lcd.update = rb.lcd_update 139 _lcd.update = _update
140 _lcd.update_rect = update_rect 140 _lcd.update_rect = update_rect
141 _lcd.clear = clear 141 _lcd.clear = clear
142 _lcd.splashf = splashf 142 _lcd.splashf = splashf
143 _lcd.image = image 143 _lcd.image = image
144]]
145 _lcd.update = rb.lcd_update
144 _lcd.DEPTH = rb.LCD_DEPTH 146 _lcd.DEPTH = rb.LCD_DEPTH
145 _lcd.W = rb.LCD_WIDTH 147 _lcd.W = rb.LCD_WIDTH
146 _lcd.H = rb.LCD_HEIGHT 148 _lcd.H = rb.LCD_HEIGHT
diff --git a/apps/plugins/lua/include_lua/print.lua b/apps/plugins/lua/include_lua/print.lua
index 9b21dafb9d..3a11e7c3dc 100644
--- a/apps/plugins/lua/include_lua/print.lua
+++ b/apps/plugins/lua/include_lua/print.lua
@@ -49,13 +49,12 @@ local _print = {} do
49 49
50 local _NIL = nil -- _NIL placeholder 50 local _NIL = nil -- _NIL placeholder
51 local _LCD = rb.lcd_framebuffer() 51 local _LCD = rb.lcd_framebuffer()
52 local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT
53 local WHITE = _clr.set(-1, 255, 255, 255) 52 local WHITE = _clr.set(-1, 255, 255, 255)
54 local BLACK = _clr.set(0, 0, 0, 0) 53 local BLACK = _clr.set(0, 0, 0, 0)
55 local DRMODE_SOLID = 3 54 local DRMODE_SOLID = 3
56 local col_buf, s_lines = {}, {} 55 local col_buf, s_lines = {}, {}
57 local _p_opts = _NIL 56 local _p_opts = _NIL
58 57 local tabstring = string.rep(" ", 2)
59-- print internal helper functions 58-- print internal helper functions
60-------------------------------------------------------------------------------- 59--------------------------------------------------------------------------------
61 -- clamps value to >= min and <= max 60 -- clamps value to >= min and <= max
@@ -69,46 +68,20 @@ local _print = {} do
69 return max 68 return max
70 end 69 end
71 70
72 -- updates screen in specified rectangle
73 local function update_rect(x, y, w, h)
74 rb.lcd_update_rect(x - 1, y - 1,
75 clamp(x + w, 1, LCD_W) - 1,
76 clamp(y + h, 1, LCD_H) - 1)
77 end
78
79 -- Gets size of text 71 -- Gets size of text
80 local function text_extent(msg, font) 72 local function text_extent(msg, font)
81 font = font or rb.FONT_UI
82 -- res, w, h 73 -- res, w, h
83 return rb.font_getstringsize(msg, font) 74 return rb.font_getstringsize(msg, font or rb.FONT_UI)
84 end
85
86 -- Sets viewport size
87 local function set_viewport(vp)
88 if not vp then rb.set_viewport() return end
89
90 if rb.LCD_DEPTH == 2 then -- invert 2-bit screens
91 --vp.drawmode = bit.bxor(vp.drawmode, 4)
92 vp.fg_pattern = 3 - vp.fg_pattern
93 vp.bg_pattern = 3 - vp.bg_pattern
94 end
95 rb.set_viewport(vp)
96 end
97
98 -- shallow copy of table
99 function table_clone(t)
100 local copy = {}
101 for k, v in pairs(t) do
102 copy[k] = v
103 end
104 return copy
105 end 75 end
106 76
107 -- Updates a single line on the screen 77 -- Updates a single line on the screen
108 local function update_line(enabled, opts, line, h) 78 local function update_line(enabled, opts, line, h)
109 if enabled ~= true then return end 79 if enabled ~= true then return end
110 local o = opts or _p_opts 80 local o = opts or _p_opts
111 update_rect(o.x, o.y + line * h + 1, o.width, h) 81 -- updates screen in specified rectangle
82 rb.lcd_update_rect(o.x - 1, o.y + line * h,
83 clamp(o.x + o.width, 1, rb.LCD_WIDTH) - 1,
84 clamp(o.y + line * h + 1 + h, 1, rb.LCD_HEIGHT) - 1)
112 end 85 end
113 86
114 -- Clears a single line on the screen 87 -- Clears a single line on the screen
@@ -129,22 +102,23 @@ local _print = {} do
129 local function col_buf_insert(msg, line, _p_opts) 102 local function col_buf_insert(msg, line, _p_opts)
130 --if _p_opts.line <= 1 then col_buf = {} end 103 --if _p_opts.line <= 1 then col_buf = {} end
131 if not col_buf[line] then 104 if not col_buf[line] then
132 table.insert(col_buf, line, msg) end 105 table.insert(col_buf, line, msg)
106 end
133 end 107 end
134 108
135 --replaces / strips escape characters 109 --replaces / strips tab characters
136 local function check_escapes(o, msg) 110 local function check_escapes(o, msg)
111--[[ --for replacing a variety of escapes
137 local tabsz = 2 112 local tabsz = 2
138 local tabstr = string.rep(" ", tabsz) 113 local tabstr = string.rep(" ", tabsz)
139
140 local function repl(esc) 114 local function repl(esc)
141 local ret = "" 115 local ret = ""
142 if esc:sub(1,1) == "\t" then ret = string.rep(tabstr, esc:len()) end 116 if esc:sub(1,1) == "\t" then ret = string.rep(tabstr, esc:len()) end
143 return ret 117 return ret
144 end 118 end
145
146 msg = msg:gsub("(%c+)", repl) 119 msg = msg:gsub("(%c+)", repl)
147 120]]
121 msg = msg:gsub("\t", tabstring)
148 local res, w, h = text_extent(msg, o.font) 122 local res, w, h = text_extent(msg, o.font)
149 return w, h, msg 123 return w, h, msg
150 end 124 end
@@ -154,8 +128,8 @@ local _print = {} do
154 local function set_defaults() 128 local function set_defaults()
155 _p_opts = { x = 1, 129 _p_opts = { x = 1,
156 y = 1, 130 y = 1,
157 width = LCD_W - 1, 131 width = rb.LCD_WIDTH - 1,
158 height = LCD_H - 1, 132 height = rb.LCD_HEIGHT - 1,
159 font = rb.FONT_UI, 133 font = rb.FONT_UI,
160 drawmode = DRMODE_SOLID, 134 drawmode = DRMODE_SOLID,
161 fg_pattern = WHITE, 135 fg_pattern = WHITE,
@@ -178,7 +152,15 @@ local _print = {} do
178 -- if bByRef is _NIL or false then a copy is returned 152 -- if bByRef is _NIL or false then a copy is returned
179 local function get_settings(bByRef) 153 local function get_settings(bByRef)
180 _p_opts = _p_opts or set_defaults() 154 _p_opts = _p_opts or set_defaults()
181 if not bByRef then return table_clone(_p_opts) end 155 if not bByRef then
156 -- shallow copy of table
157 local copy = {}
158 for k, v in pairs(_p_opts) do
159 copy[k] = v
160 end
161 return copy
162 end
163
182 return _p_opts 164 return _p_opts
183 end 165 end
184 166
@@ -216,7 +198,16 @@ local _print = {} do
216 -- alternative selection method 198 -- alternative selection method
217 --msg = "> " .. msg 199 --msg = "> " .. msg
218 end 200 end
219 set_viewport(o) 201
202 if not o then rb.set_viewport() return end
203
204 if rb.LCD_DEPTH == 2 then -- invert 2-bit screens
205 o.fg_pattern = 3 - o.fg_pattern
206 o.bg_pattern = 3 - o.bg_pattern
207 end
208
209 rb.set_viewport(o)
210
220 o = _NIL 211 o = _NIL
221 end 212 end
222 213
@@ -251,8 +242,8 @@ local _print = {} do
251 -- sets print area 242 -- sets print area
252 local function set_area(x, y, w, h) 243 local function set_area(x, y, w, h)
253 local o = get_settings(true) 244 local o = get_settings(true)
254 o.x, o.y = clamp(x, 1, LCD_W), clamp(y, 1, LCD_H) 245 o.x, o.y = clamp(x, 1, rb.LCD_WIDTH), clamp(y, 1, rb.LCD_HEIGHT)
255 o.width, o.height = clamp(w, 1, LCD_W - o.x), clamp(h, 1, LCD_H - o.y) 246 o.width, o.height = clamp(w, 1, rb.LCD_WIDTH - o.x), clamp(h, 1, rb.LCD_HEIGHT - o.y)
256 o.max_line = max_lines(_p_opts) 247 o.max_line = max_lines(_p_opts)
257 248
258 clear() 249 clear()
@@ -312,6 +303,7 @@ local _print = {} do
312 local o = get_settings(true) 303 local o = get_settings(true)
313 local w, h, msg 304 local w, h, msg
314 local line = o.line - 1 -- rb is 0-based lua is 1-based 305 local line = o.line - 1 -- rb is 0-based lua is 1-based
306
315 if not (...) or (...) == "\n" then -- handles blank line / single '\n' 307 if not (...) or (...) == "\n" then -- handles blank line / single '\n'
316 local res, w, h = text_extent(" ", o.font) 308 local res, w, h = text_extent(" ", o.font)
317 309
diff --git a/apps/plugins/lua/rocklib_img.c b/apps/plugins/lua/rocklib_img.c
index 083679cdbb..35c2699b5d 100644
--- a/apps/plugins/lua/rocklib_img.c
+++ b/apps/plugins/lua/rocklib_img.c
@@ -57,10 +57,6 @@
57#define ABS(a)(((a) < 0) ? - (a) :(a)) 57#define ABS(a)(((a) < 0) ? - (a) :(a))
58#endif 58#endif
59 59
60#ifndef LCD_BLACK
61#define LCD_BLACK 0x0
62#endif
63
64struct rocklua_image 60struct rocklua_image
65{ 61{
66 int width; 62 int width;
@@ -68,18 +64,18 @@ struct rocklua_image
68 int stride; 64 int stride;
69 size_t elems; 65 size_t elems;
70 fb_data *data; 66 fb_data *data;
71 fb_data dummy[1]; 67 fb_data dummy[1][1];
72}; 68};
73 69
74/* holds iterator data for rlimages */ 70/* holds iterator data for rlimages */
75struct rli_iter_d 71struct rli_iter_d
76{ 72{
77 struct rocklua_image *img;
78 fb_data *elem;
79 int x , y; 73 int x , y;
80 int x1, y1; 74 int x1, y1;
81 int x2, y2; 75 int x2, y2;
82 int dx, dy; 76 int dx, dy;
77 fb_data *elem;
78 struct rocklua_image *img;
83}; 79};
84 80
85/* __tostring information enums */ 81/* __tostring information enums */
@@ -92,8 +88,8 @@ enum rli_info {RLI_INFO_ALL = 0, RLI_INFO_TYPE, RLI_INFO_WIDTH,
92static inline fb_data invert_color(fb_data rgb) 88static inline fb_data invert_color(fb_data rgb)
93{ 89{
94 uint8_t r = 0xFFU - FB_UNPACK_RED(rgb); 90 uint8_t r = 0xFFU - FB_UNPACK_RED(rgb);
95 uint8_t g = 0xFFU - FB_UNPACK_RED(rgb); 91 uint8_t g = 0xFFU - FB_UNPACK_GREEN(rgb);
96 uint8_t b = 0xFFU - FB_UNPACK_RED(rgb); 92 uint8_t b = 0xFFU - FB_UNPACK_BLUE(rgb);
97 93
98 return FB_RGBPACK(r, g, b); 94 return FB_RGBPACK(r, g, b);
99} 95}
@@ -244,17 +240,45 @@ static inline void swap_int(bool swap, int *v1, int *v2)
244static void bounds_check_xy(lua_State *L, struct rocklua_image *img, 240static void bounds_check_xy(lua_State *L, struct rocklua_image *img,
245 int nargx, int x, int nargy, int y) 241 int nargx, int x, int nargy, int y)
246{ 242{
247 luaL_argcheck(L, x <= img->width && x > 0, nargx, ERR_IDX_RANGE); 243 int narg;
248 luaL_argcheck(L, y <= img->height && y > 0, nargy, ERR_IDX_RANGE); 244
245 if(x > img->width || x < 1)
246 narg = nargx;
247 else if(y <= img->height && y > 0)
248 return; /* note -- return if no error */
249 else
250 narg = nargy;
251
252 luaL_argerror(L, narg, ERR_IDX_RANGE);
249} /* bounds_check_xy */ 253} /* bounds_check_xy */
250 254
251static struct rocklua_image* rli_checktype(lua_State *L, int arg) 255static struct rocklua_image* rli_checktype(lua_State *L, int arg)
252{ 256{
253 void *ud = luaL_checkudata(L, arg, ROCKLUA_IMAGE); 257#if 0
258 return (struct rocklua_image*) luaL_checkudata(L, arg, ROCKLUA_IMAGE);
259#else /* cache result */
260 static struct rocklua_image* last = NULL;
261 void *ud = lua_touserdata(L, arg);
254 262
255 luaL_argcheck(L, ud != NULL, arg, "'" ROCKLUA_IMAGE "' expected"); 263 if(ud != NULL)
264 {
265 if(ud == last)
266 return last;
267 else if (lua_getmetatable(L, arg))
268 { /* does it have a metatable? */
269 luaL_getmetatable(L, ROCKLUA_IMAGE); /* get correct metatable */
270 if (lua_rawequal(L, -1, -2))
271 { /* does it have the correct mt? */
272 lua_pop(L, 2); /* remove both metatables */
273 last = (struct rocklua_image*) ud;
274 return last;
275 }
276 }
277 }
256 278
257 return (struct rocklua_image*) ud; 279 luaL_typerror(L, arg, ROCKLUA_IMAGE); /* else error */
280 return NULL; /* to avoid warnings */
281#endif
258} /* rli_checktype */ 282} /* rli_checktype */
259 283
260static struct rocklua_image * alloc_rlimage(lua_State *L, bool alloc_data, 284static struct rocklua_image * alloc_rlimage(lua_State *L, bool alloc_data,
@@ -286,7 +310,7 @@ static struct rocklua_image * alloc_rlimage(lua_State *L, bool alloc_data,
286 /* apparent w/h is stored but behind the scenes native w/h is used */ 310 /* apparent w/h is stored but behind the scenes native w/h is used */
287 img->width = width; 311 img->width = width;
288 img->height = height; 312 img->height = height;
289 img->stride = w_native; 313 img->stride = STRIDE_MAIN(w_native, h_native);
290 img->elems = n_elems; 314 img->elems = n_elems;
291 315
292 return img; 316 return img;
@@ -305,14 +329,14 @@ static inline fb_data* rli_alloc(lua_State *L, int width, int height)
305 /* rliimage is pushed on the stack it is up to you to pop it */ 329 /* rliimage is pushed on the stack it is up to you to pop it */
306 struct rocklua_image *a = alloc_rlimage(L, true, width, height); 330 struct rocklua_image *a = alloc_rlimage(L, true, width, height);
307 331
308 a->data = &a->dummy[0]; /* ref to beginning of alloc'd img data */ 332 a->data = &a->dummy[0][0]; /* ref to beginning of alloc'd img data */
309 333
310 return a->data; 334 return a->data;
311} /* rli_alloc */ 335} /* rli_alloc */
312 336
313static inline fb_data data_setget(fb_data *elem, int x, int y, fb_data *val) 337static inline fb_data data_set(fb_data *elem, int x, int y, fb_data *val)
314{ 338{
315 fb_data old_val = FB_SCALARPACK(0); 339 fb_data old_val;
316 fb_data new_val; 340 fb_data new_val;
317 341
318 if(elem) 342 if(elem)
@@ -328,23 +352,18 @@ static inline fb_data data_setget(fb_data *elem, int x, int y, fb_data *val)
328 else 352 else
329 pixel_to_fb(x, y, &old_val, &new_val); 353 pixel_to_fb(x, y, &old_val, &new_val);
330 } 354 }
355 else
356 old_val = FB_SCALARPACK(0);
331 357
332 return old_val; 358 return old_val;
333} /* data_setget */
334
335static inline fb_data data_set(fb_data *elem, int x, int y, fb_data *new_val)
336{
337 /* get and set share the same underlying function */
338 return data_setget(elem, x, y, new_val);
339} /* data_set */ 359} /* data_set */
340 360
341static inline fb_data data_get(fb_data *elem, int x, int y) 361static inline fb_data data_get(fb_data *elem, int x, int y)
342{ 362{
343 /* get and set share the same underlying function */ 363 return data_set(elem, x, y, NULL);
344 return data_setget(elem, x, y, NULL);
345} /* data_get */ 364} /* data_get */
346 365
347static fb_data* rli_get_element(struct rocklua_image* img, int x, int y) 366static inline fb_data* rli_get_element(struct rocklua_image* img, int x, int y)
348{ 367{
349 int stride = img->stride; 368 int stride = img->stride;
350 size_t elements = img->elems; 369 size_t elements = img->elems;
@@ -352,60 +371,61 @@ static fb_data* rli_get_element(struct rocklua_image* img, int x, int y)
352 371
353 pixel_to_native(x, y, &x, &y); 372 pixel_to_native(x, y, &x, &y);
354 373
374#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
375 /* column major address */
376 size_t data_address = (stride * (x - 1)) + (y - 1);
377
378 /* y needs bound between 0 and stride otherwise overflow to prev/next x */
379 if(y <= 0 || y > stride || data_address >= elements)
380 return NULL; /* data overflow */
381#else
355 /* row major address */ 382 /* row major address */
356 size_t data_address = (stride * (y - 1)) + (x - 1); 383 size_t data_address = (stride * (y - 1)) + (x - 1);
357 384
358 /* x needs bound between 0 and stride otherwise overflow to prev/next y */ 385 /* x needs bound between 0 and stride otherwise overflow to prev/next y */
359 if(x <= 0 || x > stride || data_address >= elements) 386 if(x <= 0 || x > stride || data_address >= elements)
360 return NULL; /* data overflow */ 387 return NULL; /* data overflow */
388#endif
361 389
362 return &data[data_address]; /* return element address */ 390 return &data[data_address]; /* return element address */
363} /* rli_get_element */ 391} /* rli_get_element */
364 392
365/* Lua to C Interface for pixel set and get functions */ 393/* Lua to C Interface for pixel set and get functions */
366static int rli_setget(lua_State *L, bool is_get) 394static int rli_setget(lua_State *L, bool is_get, int narg_clip)
367{ 395{
368 /*(set) (dst*, [x1, y1, clr, clip]) */ 396 /*(set) (dst*, [x1, y1, clr, clip]) */
369 /*(get) (dst*, [x1, y1, clip]) */ 397 /*(get) (dst*, [x1, y1, clip]) */
370 struct rocklua_image *a = rli_checktype(L, 1); 398 struct rocklua_image *a = rli_checktype(L, 1);
371 int x = luaL_checkint(L, 2); 399 int x = lua_tointeger(L, 2);
372 int y = luaL_checkint(L, 3); 400 int y = lua_tointeger(L, 3);
373
374 fb_data clr = FB_SCALARPACK(0); /* Arg 4 is color if set element */
375 fb_data *p_clr = &clr;
376 401
377 int clip_narg; 402 fb_data clr; /* Arg 4 is color if set element */
378
379 if(is_get) /* get element */
380 {
381 p_clr = NULL;
382 clip_narg = 4;
383 }
384 else /* set element */
385 {
386 clr = FB_SCALARPACK((unsigned) luaL_checknumber(L, 4));
387 clip_narg = 5;
388 }
389 403
390 fb_data *element = rli_get_element(a, x, y); 404 fb_data *element = rli_get_element(a, x, y);
391 405
392 if(!element) 406 if(!element)
393 { 407 {
394 if(!luaL_optboolean(L, clip_narg, false)) /* Error if !clip */ 408 if(!lua_toboolean(L, narg_clip)) /* Error if !clip */
395 bounds_check_xy(L, a, 2, x, 3, y); 409 bounds_check_xy(L, a, 2, x, 3, y);
396 410
397 lua_pushnil(L); 411 lua_pushnil(L);
398 return 1; 412 return 1;
399 } 413 }
400 414
401 lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(data_setget(element, x, y, p_clr))); 415 if(is_get) /* get element */
416 lua_pushinteger(L, FB_UNPACK_SCALAR_LCD(data_get(element, x, y)));
417 else /* set element */
418 {
419 clr = FB_SCALARPACK((unsigned) lua_tointeger(L, 4));
420 lua_pushinteger(L, FB_UNPACK_SCALAR_LCD(data_set(element, x, y, &clr)));
421 }
402 422
403 /* returns old value */ 423 /* returns old value */
404 return 1; 424 return 1;
405} /* rli_setget */ 425} /* rli_setget */
406 426
407#ifdef RLI_EXTENDED 427#ifdef RLI_EXTENDED
408static bool init_rli_iter(struct rli_iter_d *d, 428static bool rli_iter_init(struct rli_iter_d *d,
409 struct rocklua_image *img, 429 struct rocklua_image *img,
410 int x1, int y1, 430 int x1, int y1,
411 int x2, int y2, 431 int x2, int y2,
@@ -417,11 +437,11 @@ static bool init_rli_iter(struct rli_iter_d *d,
417 swap_int((swy), &y1, &y2); 437 swap_int((swy), &y1, &y2);
418 438
419 /* stepping in the correct x direction ? */ 439 /* stepping in the correct x direction ? */
420 if((dx > 0 && x1 > x2) || (dx < 0 && x1 < x2)) 440 if((dx ^ (x2 - x1)) < 0)
421 dx = -dx; 441 dx = -dx;
422 442
423 /* stepping in the correct y direction ? */ 443 /* stepping in the correct y direction ? */
424 if((dy > 0 && y1 > y2) || (dy < 0 && y1 < y2)) 444 if((dy ^ (y2 - y1)) < 0)
425 dy = -dy; 445 dy = -dy;
426 446
427 d->img = img; 447 d->img = img;
@@ -436,7 +456,33 @@ static bool init_rli_iter(struct rli_iter_d *d,
436 d->elem = rli_get_element(img, d->x, d->y); 456 d->elem = rli_get_element(img, d->x, d->y);
437 457
438 return(dx != 0 || dy != 0); 458 return(dx != 0 || dy != 0);
439} /* init_rli_iter */ 459} /* rli_iter_init */
460
461static struct rli_iter_d * rli_iter_create(lua_State *L)
462{
463 struct rocklua_image *a = rli_checktype(L, 1);
464 int x1 = luaL_optint(L, 2, 1);
465 int y1 = luaL_optint(L, 3, 1);
466 int x2 = luaL_optint(L, 4, a->width);
467 int y2 = luaL_optint(L, 5, a->height);
468 int dx = luaL_optint(L, 6, 1);
469 int dy = luaL_optint(L, 7, 1);
470 bool clip = lua_toboolean(L, 8);
471
472 if(!clip)
473 {
474 bounds_check_xy(L, a, 2, x1, 3, y1);
475 bounds_check_xy(L, a, 4, x2, 5, y2);
476 }
477
478 struct rli_iter_d *ds;
479 /* create new iter + pushed onto stack */
480 ds = (struct rli_iter_d *) lua_newuserdata(L, sizeof(struct rli_iter_d));
481
482 rli_iter_init(ds, a, x1, y1, x2, y2, dx, dy, false, false);
483
484 return ds;
485}
440 486
441/* steps to the next point(x, y) by delta x/y, stores pointer to element 487/* steps to the next point(x, y) by delta x/y, stores pointer to element
442 returns true if x & y haven't reached x2 & y2 488 returns true if x & y haven't reached x2 & y2
@@ -464,11 +510,10 @@ static bool next_rli_iter(struct rli_iter_d *d)
464 return true; 510 return true;
465} /* next_rli_iter */ 511} /* next_rli_iter */
466 512
467static int d_line(struct rocklua_image *img, 513static void d_line(struct rocklua_image *img,
468 int x1, int y1, 514 int x1, int y1,
469 int x2, int y2, 515 int x2, int y2,
470 fb_data *clr, 516 fb_data *clr)
471 bool clip)
472{ 517{
473 /* NOTE! clr passed as pointer */ 518 /* NOTE! clr passed as pointer */
474 /* Bresenham midpoint line algorithm */ 519 /* Bresenham midpoint line algorithm */
@@ -477,8 +522,8 @@ static int d_line(struct rocklua_image *img,
477 int r_a = x2 - x1; /* range of x direction called 'a' for now */ 522 int r_a = x2 - x1; /* range of x direction called 'a' for now */
478 int r_b = y2 - y1; /* range of y direction called 'b' for now */ 523 int r_b = y2 - y1; /* range of y direction called 'b' for now */
479 524
480 int s_a = 1; /* step of a direction */ 525 int s_a = (r_a > 0) - (r_a < 0); /* step of a direction -1, 0, 1 */
481 int s_b = 1; /* step of b direction */ 526 int s_b = (r_b > 0) - (r_b < 0); /* step of b direction -1, 0, 1 */
482 527
483 int d_err; 528 int d_err;
484 int numpixels; 529 int numpixels;
@@ -486,42 +531,28 @@ static int d_line(struct rocklua_image *img,
486 int *a1 = &x1; /* pointer to the x var 'a' */ 531 int *a1 = &x1; /* pointer to the x var 'a' */
487 int *b1 = &y1; /* pointer to the y var 'b' */ 532 int *b1 = &y1; /* pointer to the y var 'b' */
488 533
489 if(r_a < 0) /* instead of negative range we will switch step instead */ 534 r_a = ABS(r_a);/* instead of negative range we switch step */
490 { 535 r_b = ABS(r_b);/* instead of negative range we switch step */
491 r_a = -r_a;
492 s_a = -s_a;
493 }
494
495 if(r_b < 0) /* instead of negative range we will switch step instead */
496 {
497 r_b = -r_b;
498 s_b = -s_b;
499 }
500
501 x2 += s_a; /* add 1 extra point to make the whole line */
502 y2 += s_b; /* add 1 extra point */
503 536
504 if(r_b > r_a) /*if rangeY('b') > rangeX('a') swap their identities */ 537 if(r_b > r_a) /*if rangeY('b') > rangeX('a') swap their identities */
505 { 538 {
506 a1 = &y1; 539 a1 = &y1; /* pointer to the y var 'a' */
507 b1 = &x1; 540 b1 = &x1; /* pointer to the x var 'b' */
508 swap_int((true), &r_a, &r_b); 541 swap_int((true), &r_a, &r_b);
509 swap_int((true), &s_a, &s_b); 542 swap_int((true), &s_a, &s_b);
510 } 543 }
511 544
512 d_err = ((r_b << 1) - r_a) >> 1; /* preload err of 1 step (px centered) */ 545 d_err = ((r_b << 1) - r_a) >> 1; /* preload err of 1 step (px centered) */
513 546
547 /* add 1 extra point to make the whole line */
514 numpixels = r_a + 1; 548 numpixels = r_a + 1;
515 549
516 r_a -= r_b; /* pre-subtract 'a' - 'b' */ 550 r_a -= r_b; /* pre-subtract 'a' - 'b' */
517 551
518 for(;numpixels > 0; numpixels--) 552 for(; numpixels > 0; numpixels--)
519 { 553 {
520 element = rli_get_element(img, x1, y1); 554 element = rli_get_element(img, x1, y1);
521 if(element || clip) 555 data_set(element, x1, y1, clr);
522 data_set(element, x1, y1, clr);
523 else
524 return numpixels + 1; /* Error */
525 556
526 if(d_err >= 0) /* 0 is our target midpoint(exact point on the line) */ 557 if(d_err >= 0) /* 0 is our target midpoint(exact point on the line) */
527 { 558 {
@@ -534,73 +565,60 @@ static int d_line(struct rocklua_image *img,
534 *a1 += s_a; /* whichever axis is in 'a' stepped(-1 or +1) */ 565 *a1 += s_a; /* whichever axis is in 'a' stepped(-1 or +1) */
535 } 566 }
536 567
537 return 0;
538} /* d_line */ 568} /* d_line */
539 569
540/* ellipse worker function */ 570/* ellipse worker function */
541static int d_ellipse_elements(struct rocklua_image * img, 571static void d_ellipse_elements(struct rocklua_image * img,
542 int x1, int y1, 572 int x1, int y1,
543 int x2, int y2, 573 int x2, int y2,
544 int sx, int sy, 574 fb_data *clr,
545 fb_data *clr, 575 fb_data *fillclr)
546 fb_data *fillclr,
547 bool clip)
548{ 576{
549 int ret = 0; 577 fb_data *element;
550 fb_data *element1, *element2, *element3, *element4;
551 578
552 if(fillclr && x1 - sx != x2 + sx) 579 if(fillclr)
553 { 580 {
554 ret |= d_line(img, x1, y1, x2, y1, fillclr, clip); /* I. II.*/ 581 d_line(img, x1, y1, x2, y1, fillclr); /* I. II.*/
555 ret |= d_line(img, x1, y2, x2, y2, fillclr, clip); /* III.IV.*/ 582 d_line(img, x1, y2, x2, y2, fillclr); /* III.IV.*/
556 } 583 }
557 584
558 x1 -= sx; /* shift x & y */ 585 element = rli_get_element(img, x2, y1);
559 y1 -= sy; 586 data_set(element, x2, y1, clr); /* I. Quadrant +x +y */
560 x2 += sx;
561 y2 += sy;
562 587
563 element1 = rli_get_element(img, x2, y1); 588 element = rli_get_element(img, x1, y1);
564 element2 = rli_get_element(img, x1, y1); 589 data_set(element, x1, y1, clr); /* II. Quadrant -x +y */
565 element3 = rli_get_element(img, x1, y2);
566 element4 = rli_get_element(img, x2, y2);
567 590
568 if(clip || (element1 && element2 && element3 && element4)) 591 element = rli_get_element(img, x1, y2);
569 { 592 data_set(element, x1, y2, clr); /* III. Quadrant -x -y */
570 data_set(element1, x2, y1, clr); /* I. Quadrant +x +y */ 593
571 data_set(element2, x1, y1, clr); /* II. Quadrant -x +y */ 594 element = rli_get_element(img, x2, y2);
572 data_set(element3, x1, y2, clr); /* III. Quadrant -x -y */ 595 data_set(element, x2, y2, clr); /* IV. Quadrant +x -y */
573 data_set(element4, x2, y2, clr); /* IV. Quadrant +x -y */
574 }
575 else
576 ret = 2; /* ERROR */
577 596
578 return ret;
579} /* d_ellipse_elements */ 597} /* d_ellipse_elements */
580 598
581static int d_ellipse(struct rocklua_image *img, 599static void d_ellipse(struct rocklua_image *img,
582 int x1, int y1, 600 int x1, int y1,
583 int x2, int y2, 601 int x2, int y2,
584 fb_data *clr, 602 fb_data *clr,
585 fb_data *fillclr, 603 fb_data *fillclr)
586 bool clip)
587{ 604{
588 /* NOTE! clr and fillclr passed as pointers */ 605 /* NOTE! clr and fillclr passed as pointers */
589 /* Rasterizing algorithm derivative of work by Alois Zingl */ 606 /* Rasterizing algorithm derivative of work by Alois Zingl */
590#if LCD_WIDTH > 1024 || LCD_HEIGHT > 1024 607#if (LCD_WIDTH > 1024 || LCD_HEIGHT > 1024) && defined(INT64_MAX)
591 /* Prevents overflow on large screens */ 608 /* Prevents overflow on large screens */
592 double dx, dy, err, e2; 609 int64_t dx, dy, err, e1;
593#else 610#else
594 long dx, dy, err, e2; 611 int32_t dx, dy, err, e1;
595#endif 612#endif
613 /* if called with swapped points .. exchange them */
614 swap_int((x1 > x2), &x1, &x2);
615 swap_int((y1 > y2), &y1, &y2);
596 616
597 int ret = 0; 617 int a = x2 - x1; /* diameter */
598 618 int b = y2 - y1; /* diameter */
599 int a = ABS(x2 - x1); /* diameter */
600 int b = ABS(y2 - y1); /* diameter */
601 619
602 if(a == 0 || b == 0 || !clr) 620 if(a == 0 || b == 0)
603 return ret; /* not an error but nothing to display */ 621 return; /* not an error but nothing to display */
604 622
605 int b1 = (b & 1); 623 int b1 = (b & 1);
606 b = b - (1 - b1); 624 b = b - (1 - b1);
@@ -613,21 +631,16 @@ static int d_ellipse(struct rocklua_image *img,
613 631
614 err = dx + dy + b1 * a2; /* error of 1.step */ 632 err = dx + dy + b1 * a2; /* error of 1.step */
615 633
616 /* if called with swapped points .. exchange them */
617 swap_int((x1 > x2), &x1, &x2);
618 swap_int((y1 > y2), &y1, &y2);
619
620 y1 += (b + 1) >> 1; 634 y1 += (b + 1) >> 1;
621 y2 = y1 - b1; 635 y2 = y1 - b1;
622 636
623 do 637 do
624 { 638 {
625 ret = d_ellipse_elements(img, x1, y1, x2, y2, 0, 0, clr, fillclr, clip); 639 d_ellipse_elements(img, x1, y1, x2, y2, clr, fillclr);
626 640
627 e2 = err; 641 e1 = err;
628 642
629 /* using division because you can't use bit shift on doubles.. */ 643 if(e1 <= (dy >> 1)) /* target midpoint - y step */
630 if(e2 <= (dy / 2)) /* target midpoint - y step */
631 { 644 {
632 y1++; 645 y1++;
633 y2--; 646 y2--;
@@ -635,7 +648,7 @@ static int d_ellipse(struct rocklua_image *img,
635 err += dy; 648 err += dy;
636 } 649 }
637 650
638 if(e2 >= (dx / 2) || err > (dy / 2)) /* target midpoint - x step */ 651 if(e1 >= (dx >> 1) || err > (dy >> 1)) /* target midpoint - x step */
639 { 652 {
640 x1++; 653 x1++;
641 x2--; 654 x2--;
@@ -643,21 +656,23 @@ static int d_ellipse(struct rocklua_image *img,
643 err += dx; 656 err += dx;
644 } 657 }
645 658
646 } while(ret == 0 && x1 <= x2); 659 } while(x1 <= x2);
660
661 if (fillclr && x1 - x2 <= 2)
662 fillclr = clr;
647 663
648 while (ret == 0 && y1 - y2 < b) /* early stop of flat ellipse a=1 finish tip */ 664 while (y1 - y2 < b) /* early stop of flat ellipse a=1 finish tip */
649 { 665 {
650 ret = d_ellipse_elements(img, x1, y1, x2, y2, 1, 0, clr, fillclr, clip); 666 d_ellipse_elements(img, x1, y1, x2, y2, clr, fillclr);
651 667
652 y1++; 668 y1++;
653 y2--; 669 y2--;
654 } 670 }
655 671
656 return ret;
657} /* d_ellipse */ 672} /* d_ellipse */
658 673
659/* Lua to C Interface for line and ellipse */ 674/* Lua to C Interface for line and ellipse */
660static int rli_line_ellipse(lua_State *L, bool is_ellipse) 675static int rli_line_ellipse(lua_State *L, bool is_ellipse, int narg_clip)
661{ 676{
662 struct rocklua_image *a = rli_checktype(L, 1); 677 struct rocklua_image *a = rli_checktype(L, 1);
663 678
@@ -666,20 +681,12 @@ static int rli_line_ellipse(lua_State *L, bool is_ellipse)
666 int x2 = luaL_optint(L, 4, x1); 681 int x2 = luaL_optint(L, 4, x1);
667 int y2 = luaL_optint(L, 5, y1); 682 int y2 = luaL_optint(L, 5, y1);
668 683
669 fb_data clr = FB_SCALARPACK((unsigned) luaL_checknumber(L, 6)); 684 fb_data clr = FB_SCALARPACK((unsigned) lua_tointeger(L, 6));
670 685
671 fb_data fillclr; /* fill color is index 7 if is_ellipse */ 686 fb_data fillclr; /* fill color is index 7 if is_ellipse */
672 fb_data *p_fillclr = NULL; 687 fb_data *p_fillclr = NULL;
673 688
674 bool clip; 689 bool clip = lua_toboolean(L, narg_clip);
675 int clip_narg;
676
677 if(is_ellipse)
678 clip_narg = 8;
679 else
680 clip_narg = 7;
681
682 clip = luaL_optboolean(L, clip_narg, false);
683 690
684 if(!clip) 691 if(!clip)
685 { 692 {
@@ -689,31 +696,27 @@ static int rli_line_ellipse(lua_State *L, bool is_ellipse)
689 696
690 if(is_ellipse) 697 if(is_ellipse)
691 { 698 {
692 if(!lua_isnoneornil(L, 7)) 699 if(lua_type(L, 7) == LUA_TNUMBER)
693 { 700 {
694 fillclr = FB_SCALARPACK((unsigned) luaL_checkint(L, 7)); 701 fillclr = FB_SCALARPACK((unsigned) lua_tointeger(L, 7));
695 p_fillclr = &fillclr; 702 p_fillclr = &fillclr;
696 } 703 }
697 704
698 luaL_argcheck(L, d_ellipse(a, x1, y1, x2, y2, &clr, p_fillclr, clip) == 0, 705 d_ellipse(a, x1, y1, x2, y2, &clr, p_fillclr);
699 1, ERR_DATA_OVF);
700 } 706 }
701 else 707 else
702 luaL_argcheck(L, d_line(a, x1, y1, x2, y2, &clr, clip) == 0, 708 d_line(a, x1, y1, x2, y2, &clr);
703 1, ERR_DATA_OVF);
704 709
705 return 0; 710 return 0;
706} /* rli_line_ellipse */ 711} /* rli_line_ellipse */
707 712
708/* Pushes lua function from Stack at position narg to top of stack 713static inline int rli_pushpixel(lua_State *L, fb_data color, int x, int y)
709 and puts a reference in the global registry for later use */
710static inline int register_luafunc(lua_State *L, int narg_funct)
711{ 714{
712 lua_pushvalue(L, narg_funct); /* lua function */ 715 lua_pushinteger(L, FB_UNPACK_SCALAR_LCD(color));
713 int lf_ref = luaL_ref(L, LUA_REGISTRYINDEX); 716 lua_pushinteger(L, x);
714 lua_settop(L, 0); /* clear C stack for use by lua function */ 717 lua_pushinteger(L, y);
715 return lf_ref; 718 return 3;
716} /* register_luafunc */ 719}
717 720
718/* User defined pixel manipulations through rli_copy, rli_marshal */ 721/* User defined pixel manipulations through rli_copy, rli_marshal */
719static int custom_transform(lua_State *L, 722static int custom_transform(lua_State *L,
@@ -723,42 +726,40 @@ static int custom_transform(lua_State *L,
723 fb_data *color) 726 fb_data *color)
724{ 727{
725 (void) color; 728 (void) color;
726 729 (void) op;
727 fb_data dst; 730 fb_data dst;
728 fb_data src; 731 fb_data src;
729 732
730 unsigned int params = 3; 733 int params;
731 int ret = 0; 734 int ret = 0;
732 735
733 lua_rawgeti(L, LUA_REGISTRYINDEX, op); 736 if (!lua_isfunction(L, -1))
737 return ret; /* error */
738
739 lua_pushvalue(L, -1); /* make a copy of the lua function */
734 740
735 dst = data_get(ds->elem, ds->x, ds->y); 741 dst = data_get(ds->elem, ds->x, ds->y);
736 lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(dst)); 742 params = rli_pushpixel(L, dst, ds->x, ds->y);
737 lua_pushnumber(L, ds->x);
738 lua_pushnumber(L, ds->y);
739 743
740 if(ss) /* Allows src to be omitted */ 744 if(ss) /* Allows src to be omitted */
741 { 745 {
742 params += 3;
743 src = data_get(ss->elem, ss->x, ss->y); 746 src = data_get(ss->elem, ss->x, ss->y);
744 lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(src)); 747 params += rli_pushpixel(L, src, ss->x, ss->y);
745 lua_pushnumber(L, ss->x);
746 lua_pushnumber(L, ss->y);
747 } 748 }
748 749
749 lua_call(L, params, 2); /* call custom function w/ n-params & 2 ret */ 750 lua_call(L, params, 2); /* call custom function w/ n-params & 2 ret */
750 751
751 if(!lua_isnoneornil(L, -2)) 752 if(lua_type(L, -2) == LUA_TNUMBER)
752 { 753 {
753 ret = 1; 754 ret |= 1;
754 dst = FB_SCALARPACK((unsigned) luaL_checknumber(L, -2)); 755 dst = FB_SCALARPACK((unsigned) lua_tointeger(L, -2));
755 data_set(ds->elem, ds->x, ds->y, &dst); 756 data_set(ds->elem, ds->x, ds->y, &dst);
756 } 757 }
757 758
758 if(!lua_isnoneornil(L, -1) && ss) 759 if(ss && (lua_type(L, -1) == LUA_TNUMBER))
759 { 760 {
760 ret |= 2; 761 ret |= 2;
761 src = FB_SCALARPACK((unsigned) luaL_checknumber(L, -1)); 762 src = FB_SCALARPACK((unsigned) lua_tointeger(L, -1));
762 data_set(ss->elem, ss->x, ss->y, &src); 763 data_set(ss->elem, ss->x, ss->y, &src);
763 } 764 }
764 765
@@ -834,10 +835,21 @@ static int blit_transform(lua_State *L,
834 case 27: { if(dst == src) { dst = clr; } break; } 835 case 27: { if(dst == src) { dst = clr; } break; }
835 case 28: { if(dst > src) { dst = clr; } break; } 836 case 28: { if(dst > src) { dst = clr; } break; }
836 case 29: { if(dst < src) { dst = clr; } break; } 837 case 29: { if(dst < src) { dst = clr; } break; }
838#if 0
839 /* src unneeded */
840 case 30: { dst = clr; break; }/* copyC */
841 case 31: { dst = clr | dst; break; }/* DorC */
842 case 32: { dst = clr ^ dst; break; }/* DxorC */
843 case 33: { dst = ~(clr | dst); break; }/* nDorC */
844 case 34: { dst = (~clr) | dst; break; }/* DornC */
845 case 35: { dst = clr & dst; break; }/* DandC */
846 case 36: { dst = clr & (~dst); break; }/* nDandC */
847 case 37: { dst = ~clr; break; }/* notC */
848#endif
837 849
838 }/*switch op*/ 850 }/*switch op*/
839 fb_data data = FB_SCALARPACK(dst); 851 fb_data val = FB_SCALARPACK(dst);
840 data_set(ds->elem, ds->x, ds->y, &data); 852 data_set(ds->elem, ds->x, ds->y, &val);
841 return 1; 853 return 1;
842} /* blit_transform */ 854} /* blit_transform */
843 855
@@ -857,6 +869,22 @@ static int invert_transform(lua_State *L,
857 869
858 return 1; 870 return 1;
859} /* invert_transform */ 871} /* invert_transform */
872
873static int clear_transform(lua_State *L,
874 struct rli_iter_d *ds,
875 struct rli_iter_d *ss,
876 int op,
877 fb_data *color)
878{
879 (void) L;
880 (void) op;
881 (void) ss;
882
883 data_set(ds->elem, ds->x, ds->y, color);
884
885 return 1;
886} /* clear_transform */
887
860#endif /* RLI_EXTENDED */ 888#endif /* RLI_EXTENDED */
861 889
862/* RLI to LUA Interface functions *********************************************/ 890/* RLI to LUA Interface functions *********************************************/
@@ -865,8 +893,7 @@ RLI_LUA rli_new(lua_State *L)
865 int width = luaL_optint(L, 1, LCD_WIDTH); 893 int width = luaL_optint(L, 1, LCD_WIDTH);
866 int height = luaL_optint(L, 2, LCD_HEIGHT); 894 int height = luaL_optint(L, 2, LCD_HEIGHT);
867 895
868 luaL_argcheck(L, width > 0, 1, ERR_IDX_RANGE); 896 luaL_argcheck(L, width > 0 && height > 0, (width <= 0) ? 1 : 2, ERR_IDX_RANGE);
869 luaL_argcheck(L, height > 0, 2, ERR_IDX_RANGE);
870 897
871 rli_alloc(L, width, height); 898 rli_alloc(L, width, height);
872 899
@@ -876,43 +903,41 @@ RLI_LUA rli_new(lua_State *L)
876RLI_LUA rli_set(lua_State *L) 903RLI_LUA rli_set(lua_State *L)
877{ 904{
878 /*(set) (dst*, [x1, y1, clr, clip]) */ 905 /*(set) (dst*, [x1, y1, clr, clip]) */
879 /* get and set share the same underlying function */ 906 return rli_setget(L, false, 5);
880 return rli_setget(L, false);
881} 907}
882 908
883RLI_LUA rli_get(lua_State *L) 909RLI_LUA rli_get(lua_State *L)
884{ 910{
885 /*(get) (dst*, [x1, y1, clip]) */ 911 /*(get) (dst*, [x1, y1, clip]) */
886 /* get and set share the same underlying function */ 912 return rli_setget(L, true, 4);
887 return rli_setget(L, true);
888} 913}
889 914
890RLI_LUA rli_height(lua_State *L) 915RLI_LUA rli_equal(lua_State *L)
891{ 916{
892 struct rocklua_image *a = rli_checktype(L, 1); 917 struct rocklua_image *a = rli_checktype(L, 1);
893 lua_pushnumber(L, a->height); 918 struct rocklua_image *b = rli_checktype(L, 2);
919 lua_pushboolean(L, a->data == b->data);
894 return 1; 920 return 1;
895} 921}
896 922
897RLI_LUA rli_width(lua_State *L) 923RLI_LUA rli_height(lua_State *L)
898{ 924{
899 struct rocklua_image *a = rli_checktype(L, 1); 925 struct rocklua_image *a = rli_checktype(L, 1);
900 lua_pushnumber(L, a->width); 926 lua_pushinteger(L, a->height);
901 return 1; 927 return 1;
902} 928}
903 929
904RLI_LUA rli_equal(lua_State *L) 930RLI_LUA rli_width(lua_State *L)
905{ 931{
906 struct rocklua_image *a = rli_checktype(L, 1); 932 struct rocklua_image *a = rli_checktype(L, 1);
907 struct rocklua_image *b = rli_checktype(L, 2); 933 lua_pushinteger(L, a->width);
908 lua_pushboolean(L, a->data == b->data);
909 return 1; 934 return 1;
910} 935}
911 936
912RLI_LUA rli_size(lua_State *L) 937RLI_LUA rli_size(lua_State *L)
913{ 938{
914 struct rocklua_image *a = rli_checktype(L, 1); 939 struct rocklua_image *a = rli_checktype(L, 1);
915 lua_pushnumber(L, a->elems); 940 lua_pushinteger(L, a->elems);
916 return 1; 941 return 1;
917} 942}
918 943
@@ -921,17 +946,17 @@ RLI_LUA rli_raw(lua_State *L)
921 /*val = (img*, index, [new_val]) */ 946 /*val = (img*, index, [new_val]) */
922 struct rocklua_image *a = rli_checktype(L, 1); 947 struct rocklua_image *a = rli_checktype(L, 1);
923 948
924 size_t i = (unsigned) luaL_checkint(L, 2); 949 size_t i = (unsigned) lua_tointeger(L, 2);
925 950
926 fb_data val; 951 fb_data val;
927 952
928 luaL_argcheck(L, i > 0 && i <= (a->elems), 2, ERR_IDX_RANGE); 953 luaL_argcheck(L, i > 0 && i <= (a->elems), 2, ERR_IDX_RANGE);
929 954
930 lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(a->data[i-1])); 955 lua_pushinteger(L, FB_UNPACK_SCALAR_LCD(a->data[i-1]));
931 956
932 if(!lua_isnoneornil(L, 3)) 957 if(lua_type(L, 3) == LUA_TNUMBER)
933 { 958 {
934 val = FB_SCALARPACK((unsigned) luaL_checknumber(L, 3)); 959 val = FB_SCALARPACK((unsigned) lua_tointeger(L, 3));
935 a->data[i-1] = val; 960 a->data[i-1] = val;
936 } 961 }
937 962
@@ -943,7 +968,7 @@ RLI_LUA rli_tostring(lua_State *L)
943 /* (img, [infoitem]) */ 968 /* (img, [infoitem]) */
944 struct rocklua_image *a = rli_checktype(L, 1); 969 struct rocklua_image *a = rli_checktype(L, 1);
945 970
946 int item = (unsigned) luaL_optint(L, 2, 0); 971 int item = lua_tointeger(L, 2);
947 size_t bytes = a->elems * sizeof(fb_data); 972 size_t bytes = a->elems * sizeof(fb_data);
948 973
949 switch(item) 974 switch(item)
@@ -956,16 +981,19 @@ RLI_LUA rli_tostring(lua_State *L)
956 a->width, a->height, a->elems, bytes, LCD_DEPTH, LCD_PIXELFORMAT); 981 a->width, a->height, a->elems, bytes, LCD_DEPTH, LCD_PIXELFORMAT);
957 break; 982 break;
958 } 983 }
959 case RLI_INFO_TYPE: { lua_pushfstring(L, ROCKLUA_IMAGE ); break; } 984 case RLI_INFO_TYPE: { lua_pushfstring(L, ROCKLUA_IMAGE); break; }
960 case RLI_INFO_WIDTH: { lua_pushfstring(L, "%d", a->width ); break; } 985 case RLI_INFO_WIDTH: { lua_pushinteger(L, a->width); break; }
961 case RLI_INFO_HEIGHT: { lua_pushfstring(L, "%d", a->height ); break; } 986 case RLI_INFO_HEIGHT: { lua_pushinteger(L, a->height); break; }
962 case RLI_INFO_ELEMS: { lua_pushfstring(L, "%d", a->elems ); break; } 987 case RLI_INFO_ELEMS: { lua_pushinteger(L, a->elems); break; }
963 case RLI_INFO_BYTES: { lua_pushfstring(L, "%d", bytes ); break; } 988 case RLI_INFO_BYTES: { lua_pushinteger(L, bytes); break; }
964 case RLI_INFO_DEPTH: { lua_pushfstring(L, "%d", LCD_DEPTH ); break; } 989 case RLI_INFO_DEPTH: { lua_pushinteger(L, LCD_DEPTH ); break; }
965 case RLI_INFO_FORMAT: { lua_pushfstring(L, "%d", LCD_PIXELFORMAT); break; } 990 case RLI_INFO_FORMAT: { lua_pushinteger(L, LCD_PIXELFORMAT); break; }
966 case RLI_INFO_ADDRESS: { lua_pushfstring(L, "%p", a->data); break; } 991 case RLI_INFO_ADDRESS: { lua_pushfstring(L, "%p", a->data); break; }
967 } 992 }
968 993
994 /* lua_pushstring(L, lua_tostring(L, -1)); */
995 lua_tostring(L, -1); /* converts item at index to string */
996
969 return 1; 997 return 1;
970} 998}
971 999
@@ -974,52 +1002,38 @@ RLI_LUA rli_ellipse(lua_State *L)
974{ 1002{
975 /* (dst*, x1, y1, x2, y2, [clr, fillclr, clip]) */ 1003 /* (dst*, x1, y1, x2, y2, [clr, fillclr, clip]) */
976 /* line and ellipse share the same init function */ 1004 /* line and ellipse share the same init function */
977 return rli_line_ellipse(L, true); 1005 return rli_line_ellipse(L, true, 8);
978} 1006}
979 1007
980RLI_LUA rli_line(lua_State *L) 1008RLI_LUA rli_line(lua_State *L)
981{ 1009{
982 /* (dst*, x1, y1, [x2, y2, clr, clip]) */ 1010 /* (dst*, x1, y1, [x2, y2, clr, clip]) */
983 /* line and ellipse share the same init function */ 1011 /* line and ellipse share the same init function */
984 return rli_line_ellipse(L, false); 1012 return rli_line_ellipse(L, false, 7);
985} 1013}
986 1014
987RLI_LUA rli_iterator(lua_State *L) { 1015RLI_LUA rli_iterator(lua_State *L) {
988 /* see rli_iterator_factory */ 1016 /* see rli_iterator_factory */
1017 int params = 0;
989 struct rli_iter_d *ds; 1018 struct rli_iter_d *ds;
990 ds = (struct rli_iter_d *) lua_touserdata(L, lua_upvalueindex(1)); 1019 ds = (struct rli_iter_d *) lua_touserdata(L, lua_upvalueindex(1));
991 1020
992 if(ds->dx != 0 || ds->dy != 0) 1021 if(ds->dx != 0 || ds->dy != 0)
993 { 1022 {
994 lua_pushnumber(L, FB_UNPACK_SCALAR_LCD(data_get(ds->elem, ds->x, ds->y))); 1023 params = rli_pushpixel(L, data_get(ds->elem, ds->x, ds->y), ds->x, ds->y);
995
996 lua_pushinteger(L, ds->x);
997 lua_pushinteger(L, ds->y);
998 1024
999 next_rli_iter(ds); /* load next element */ 1025 next_rli_iter(ds); /* load next element */
1000
1001 return 3;
1002 } 1026 }
1003 return 0; /* nothing left to do */ 1027 return params; /* nothing left to do */
1004} 1028}
1005 1029
1006RLI_LUA rli_iterator_factory(lua_State *L) { 1030RLI_LUA rli_iterator_factory(lua_State *L)
1007 /* (src*, [x1, y1, x2, y2, dx, dy]) */ 1031{
1008 struct rocklua_image *a = rli_checktype(L, 1); /*image we wish to iterate*/ 1032 /* (points) (img*, [x1, y1, x2, y2, dx, dy, clip]) */
1009 1033 /* (indices 1-8 are used by rli_iter_create) */
1010 struct rli_iter_d *ds;
1011
1012 int x1 = luaL_optint(L, 2, 1);
1013 int y1 = luaL_optint(L, 3, 1);
1014 int x2 = luaL_optint(L, 4, a->width - x1 + 1);
1015 int y2 = luaL_optint(L, 5, a->height - y1 + 1);
1016 int dx = luaL_optint(L, 6, 1);
1017 int dy = luaL_optint(L, 7, 1);
1018 1034
1019 /* create new iter + pushed onto stack */ 1035 /* create new iter + pushed onto stack */
1020 ds = (struct rli_iter_d *) lua_newuserdata(L, sizeof(struct rli_iter_d)); 1036 rli_iter_create(L);
1021
1022 init_rli_iter(ds, a, x1, y1, x2, y2, dx, dy, false, false);
1023 1037
1024 /* returns the iter function with embedded iter data(up values) */ 1038 /* returns the iter function with embedded iter data(up values) */
1025 lua_pushcclosure(L, &rli_iterator, 1); 1039 lua_pushcclosure(L, &rli_iterator, 1);
@@ -1027,66 +1041,54 @@ RLI_LUA rli_iterator_factory(lua_State *L) {
1027 return 1; 1041 return 1;
1028} 1042}
1029 1043
1030RLI_LUA rli_marshal(lua_State *L) /* also invert */ 1044RLI_LUA rli_marshal(lua_State *L) /* also invert, clear */
1031{ 1045{
1032 /* (img*, [x1, y1, x2, y2, dx, dy, clip, function]) */ 1046 /* (marshal/invert/clear) (img*, [x1, y1, x2, y2, dx, dy, clip, function]) */
1033 struct rocklua_image *a = rli_checktype(L, 1); 1047 /* (indices 1-8 are used by rli_iter_create) */
1034 1048 fb_data clr;
1035 struct rli_iter_d ds;
1036
1037 int x1 = luaL_optint(L, 2, 1);
1038 int y1 = luaL_optint(L, 3, 1);
1039 int x2 = luaL_optint(L, 4, a->width);
1040 int y2 = luaL_optint(L, 5, a->height);
1041 int dx = luaL_optint(L, 6, 1);
1042 int dy = luaL_optint(L, 7, 1);
1043 bool clip = luaL_optboolean(L, 8, false);
1044
1045 int lf_ref = LUA_NOREF; /* de-ref'd without consequence */
1046 1049
1047 int (*rli_trans)(lua_State *, struct rli_iter_d *, struct rli_iter_d *, int, fb_data *); 1050 int (*rli_trans)(lua_State *, struct rli_iter_d *, struct rli_iter_d *, int, fb_data *);
1048 rli_trans = invert_transform; /* default transformation */ 1051 int ltype = lua_type (L, 9);
1049 1052
1050 if(!clip) 1053 /* create new iter + pushed onto stack */
1054 struct rli_iter_d *ds = rli_iter_create(L);
1055
1056 if (ltype == LUA_TNUMBER)
1051 { 1057 {
1052 bounds_check_xy(L, a, 2, x1, 3, y1); 1058 clr = FB_SCALARPACK((unsigned) lua_tointeger(L, 9));
1053 bounds_check_xy(L, a, 4, x2, 5, y2); 1059 rli_trans = clear_transform;
1054 } 1060 }
1055 1061 else if(ltype == LUA_TFUNCTION) /* custom function */
1056 init_rli_iter(&ds, a, x1, y1, x2, y2, dx, dy, false, false);
1057
1058 if(lua_isfunction(L, 9)) /* custom function */
1059 { 1062 {
1060 rli_trans = custom_transform; 1063 rli_trans = custom_transform;
1061 lf_ref = register_luafunc(L, 9); 1064 lua_pushvalue(L, 9); /* ensure lua function on top of stack */
1062 } 1065 }
1066 else
1067 rli_trans = invert_transform; /* default transformation */
1063 1068
1064 do 1069 do
1065 { 1070 {
1066 luaL_argcheck(L, clip || (ds.elem != NULL), 1, ERR_DATA_OVF); 1071 if(!(*rli_trans)(L, ds, NULL, 0, &clr))
1067
1068 if(!(*rli_trans)(L, &ds, NULL, lf_ref, NULL))
1069 break; /* Custom op can quit early */ 1072 break; /* Custom op can quit early */
1070 1073
1071 } while(next_rli_iter(&ds)); 1074 } while(next_rli_iter(ds));
1072 1075
1073 luaL_unref(L, LUA_REGISTRYINDEX, lf_ref); /* de-reference custom function */
1074 return 0; 1076 return 0;
1075} 1077}
1076 1078
1077RLI_LUA rli_copy(lua_State *L) 1079RLI_LUA rli_copy(lua_State *L)
1078{ 1080{
1079 /* (dst*, src*, [d_x, d_y, s_x, s_y, x_off, y_off, clip, [op, funct/clr]]) */ 1081 /* (dst*, src*, [d_x, d_y, s_x, s_y, x_off, y_off, clip, [op, funct/clr]]) */
1080 struct rocklua_image *d = rli_checktype(L, 1); /*dst*/ 1082 struct rocklua_image *dst = rli_checktype(L, 1); /* dst */
1081 struct rocklua_image *s = rli_checktype(L, 2); /*src*/ 1083 struct rocklua_image *src = rli_checktype(L, 2); /* src */
1082 1084
1083 struct rli_iter_d ds; /*dst*/ 1085 struct rli_iter_d ds; /* dst */
1084 struct rli_iter_d ss; /*src*/ 1086 struct rli_iter_d ss; /* src */
1085 1087
1086 /* copy whole image if possible */ 1088 /* copy whole image if possible */
1087 if(s->elems == d->elems && s->width == d->width && lua_gettop(L) < 3) 1089 if(src->elems == dst->elems && src->width == dst->width && lua_gettop(L) < 3)
1088 { 1090 {
1089 rb->memcpy(d->data, s->data, d->elems * sizeof(fb_data)); 1091 rb->memcpy(dst->data, src->data, dst->elems * sizeof(fb_data));
1090 return 0; 1092 return 0;
1091 } 1093 }
1092 1094
@@ -1095,38 +1097,41 @@ RLI_LUA rli_copy(lua_State *L)
1095 int s_x = luaL_optint(L, 5, 1); 1097 int s_x = luaL_optint(L, 5, 1);
1096 int s_y = luaL_optint(L, 6, 1); 1098 int s_y = luaL_optint(L, 6, 1);
1097 1099
1098 int w = MIN(d->width - d_x, s->width - s_x); 1100 int w = MIN(dst->width - d_x, src->width - s_x);
1099 int h = MIN(d->height - d_y, s->height - s_y); 1101 int h = MIN(dst->height - d_y, src->height - s_y);
1100 1102
1101 int x_off = luaL_optint(L, 7, w); 1103 int x_off = luaL_optint(L, 7, w);
1102 int y_off = luaL_optint(L, 8, h); 1104 int y_off = luaL_optint(L, 8, h);
1103 1105
1104 bool clip = luaL_optboolean(L, 9, false); 1106 bool clip = lua_toboolean(L, 9);
1105 int op = luaL_optint(L, 10, 0); 1107 int op; /* 10 is operation for blit */
1106 fb_data clr = FB_SCALARPACK(0); /* 11 is custom function | color */ 1108 fb_data clr; /* 11 is custom function | color */
1107 1109
1108 bool d_swx = (x_off < 0); /* dest swap */ 1110 bool d_swx = (x_off < 0); /* dest swap */
1109 bool d_swy = (y_off < 0); 1111 bool d_swy = (y_off < 0);
1110 bool s_swx = false; /* src swap */ 1112 bool s_swx = false; /* src swap */
1111 bool s_swy = false; 1113 bool s_swy = false;
1112 1114
1113 int (*rli_trans)(lua_State *, struct rli_iter_d *, struct rli_iter_d *, int, fb_data *); 1115 int (*rli_trans)(lua_State *, struct rli_iter_d *, struct rli_iter_d *, int, fb_data *);
1114 rli_trans = blit_transform; /* default transformation */
1115
1116 int lf_ref = LUA_NOREF; /* de-ref'd without consequence */
1117 1116
1118 if(!clip) /* Out of bounds is not allowed */ 1117 if(!clip) /* Out of bounds is not allowed */
1119 { 1118 {
1120 bounds_check_xy(L, d, 3, d_x, 4, d_y); 1119 bounds_check_xy(L, dst, 3, d_x, 4, d_y);
1121 bounds_check_xy(L, s, 5, s_x, 6, s_y); 1120 bounds_check_xy(L, src, 5, s_x, 6, s_y);
1121 w = MIN(w, ABS(x_off));
1122 h = MIN(h, ABS(y_off));
1123 bounds_check_xy(L, dst, 7, d_x + w, 8, d_y + h);
1124 bounds_check_xy(L, src, 7, s_x + w, 8, s_y + h);
1125 }
1126 else
1127 {
1128 if (w < 0 || h < 0) /* not an error but nothing to display */
1129 return 0;
1130 w = MIN(w, ABS(x_off));
1131 h = MIN(h, ABS(y_off));
1122 } 1132 }
1123 else if (w < 0 || h < 0) /* not an error but nothing to display */
1124 return 0;
1125
1126 w = MIN(w, ABS(x_off));
1127 h = MIN(h, ABS(y_off));
1128 1133
1129 /* if(s->data == d->data) need to care about fill direction */ 1134 /* if src->data == dst->data need to care about fill direction */
1130 if(d_x > s_x) 1135 if(d_x > s_x)
1131 { 1136 {
1132 d_swx = !d_swx; 1137 d_swx = !d_swx;
@@ -1139,67 +1144,46 @@ RLI_LUA rli_copy(lua_State *L)
1139 s_swy = !s_swy; 1144 s_swy = !s_swy;
1140 } 1145 }
1141 1146
1142 init_rli_iter(&ds, d, d_x, d_y, d_x + w, d_y + h, 1, 1, d_swx, d_swy); 1147 rli_iter_init(&ds, dst, d_x, d_y, d_x + w, d_y + h, 1, 1, d_swx, d_swy);
1143 1148
1144 init_rli_iter(&ss, s, s_x, s_y, s_x + w, s_y + h, 1, 1, s_swx, s_swy); 1149 rli_iter_init(&ss, src, s_x, s_y, s_x + w, s_y + h, 1, 1, s_swx, s_swy);
1145 1150
1146 if (op == 0xFF && lua_isfunction(L, 11)) /* custom function specified.. */ 1151 if (lua_type(L, 11) == LUA_TFUNCTION) /* custom function supplied.. */
1147 { 1152 {
1148 rli_trans = custom_transform; 1153 rli_trans = custom_transform;
1149 lf_ref = register_luafunc(L, 11); 1154 lua_settop(L, 11); /* ensure lua function on top of stack */
1150 op = lf_ref; 1155 clr = 0;
1156 op = 0;
1151 } 1157 }
1152 else 1158 else
1153 clr = FB_SCALARPACK((unsigned) luaL_optnumber(L, 11, LCD_BLACK)); 1159 {
1160 rli_trans = blit_transform; /* default transformation */
1161 clr = FB_SCALARPACK((unsigned) lua_tointeger(L, 11));
1162 op = lua_tointeger(L, 10);
1163 }
1154 1164
1155 do 1165 do
1156 { 1166 {
1157 if(!clip)
1158 {
1159 luaL_argcheck(L, ss.elem != NULL, 2, ERR_DATA_OVF);
1160 luaL_argcheck(L, ds.elem != NULL, 1, ERR_DATA_OVF);
1161 }
1162
1163 if(!(*rli_trans)(L, &ds, &ss, op, &clr)) 1167 if(!(*rli_trans)(L, &ds, &ss, op, &clr))
1164 break; /* Custom op can quit early */ 1168 break; /* Custom op can quit early */
1165 1169
1166 } while(next_rli_iter(&ds) && next_rli_iter(&ss)); 1170 } while(next_rli_iter(&ds) && next_rli_iter(&ss));
1167 1171
1168 luaL_unref(L, LUA_REGISTRYINDEX, lf_ref); /* de-reference custom function */
1169 return 0; 1172 return 0;
1170} 1173}
1171 1174
1172RLI_LUA rli_clear(lua_State *L) 1175RLI_LUA rli_clear(lua_State *L)
1173{ 1176{
1174 /* (dst*, [color, x1, y1, x2, y2, clip]) */ 1177 /* (clear) (dst*, [color, x1, y1, x2, y2, clip, dx, dy]) */
1175 struct rocklua_image *a = rli_checktype(L, 1); 1178 lua_settop(L, 9);
1176
1177 struct rli_iter_d ds;
1178 1179
1179 fb_data clr = FB_SCALARPACK((unsigned) luaL_optnumber(L, 2, LCD_BLACK)); 1180 lua_pushvalue(L, 7); /* clip -- index 8 */
1180 int x1 = luaL_optint(L, 3, 1); 1181 lua_remove(L, 7);
1181 int y1 = luaL_optint(L, 4, 1);
1182 int x2 = luaL_optint(L, 5, a->width);
1183 int y2 = luaL_optint(L, 6, a->height);
1184 bool clip = luaL_optboolean(L, 7, false);
1185 1182
1186 if(!clip) 1183 lua_pushinteger(L, lua_tointeger(L, 2)); /*color -- index 9*/
1187 { 1184 lua_remove(L, 2);
1188 bounds_check_xy(L, a, 3, x1, 4, y1);
1189 bounds_check_xy(L, a, 5, x2, 6, y2);
1190 }
1191 1185
1192 init_rli_iter(&ds, a, x1, y1, x2, y2, 1, 1, false, false); 1186 return rli_marshal(L); /* (img*, [x1, y1, x2, y2, dx, dy, clip, function]) */
1193
1194 do
1195 {
1196 luaL_argcheck(L, clip || (ds.elem != NULL), 1, ERR_DATA_OVF);
1197
1198 data_set(ds.elem, ds.x, ds.y, &clr);
1199
1200 } while(next_rli_iter(&ds));
1201
1202 return 0;
1203} 1187}
1204#endif /* RLI_EXTENDED */ 1188#endif /* RLI_EXTENDED */
1205 1189
@@ -1236,15 +1220,11 @@ LUALIB_API int rli_init(lua_State *L)
1236 1220
1237 luaL_newmetatable(L, ROCKLUA_IMAGE); 1221 luaL_newmetatable(L, ROCKLUA_IMAGE);
1238 1222
1239 lua_pushstring(L, "__index"); 1223 lua_pushvalue(L, -1); /* pushes the metatable */
1240 lua_pushvalue(L, -2); /* pushes the metatable */ 1224 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1241 lua_settable(L, -3); /* metatable.__index = metatable */
1242 1225
1243 luaL_register(L, NULL, rli_lib); 1226 luaL_register(L, NULL, rli_lib);
1244 1227
1245#ifdef RLI_EXTENDED
1246 luaL_register(L, ROCKLUA_IMAGE, rli_lib);
1247#endif
1248 return 1; 1228 return 1;
1249} 1229}
1250 1230
@@ -1256,7 +1236,7 @@ LUALIB_API int rli_init(lua_State *L)
1256 * ----------------------------- 1236 * -----------------------------
1257 */ 1237 */
1258 1238
1259#define RB_WRAP(M) static int rock_##M(lua_State UNUSED_ATTR *L) 1239#define RB_WRAP(func) static int rock_##func(lua_State UNUSED_ATTR *L)
1260#ifdef HAVE_LCD_BITMAP 1240#ifdef HAVE_LCD_BITMAP
1261RB_WRAP(lcd_framebuffer) 1241RB_WRAP(lcd_framebuffer)
1262{ 1242{