diff options
author | William Wilgus <me.theuser@yahoo.com> | 2018-09-23 18:25:31 +0200 |
---|---|---|
committer | William Wilgus <me.theuser@yahoo.com> | 2018-10-09 01:02:25 +0200 |
commit | c0682e094414d0748456d0b01000727039ff701c (patch) | |
tree | 2cc08bfdfe967bbe18fade1ed835d54a3f91cd23 | |
parent | e4b843335bc34810c11ed405d473e6f7c94a153f (diff) | |
download | rockbox-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.lua | 2 | ||||
-rw-r--r-- | apps/plugins/lua/include_lua/color.lua | 31 | ||||
-rw-r--r-- | apps/plugins/lua/include_lua/draw.lua | 229 | ||||
-rw-r--r-- | apps/plugins/lua/include_lua/image.lua | 117 | ||||
-rw-r--r-- | apps/plugins/lua/include_lua/lcd.lua | 24 | ||||
-rw-r--r-- | apps/plugins/lua/include_lua/print.lua | 80 | ||||
-rw-r--r-- | apps/plugins/lua/rocklib_img.c | 632 |
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 | ||
37 | local _blit ={} do | 37 | local _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 | ||
114 | end -- color functions | 103 | end -- color functions |
115 | 104 | ||
116 | return _clr | 105 | return _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 | ||
53 | local _draw = {} do | 53 | local _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 | |||
466 | end -- _draw functions | 429 | end -- _draw functions |
467 | 430 | ||
468 | return _draw | 431 | return _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 | ||
66 | local _img = {} do | 66 | local _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 | |||
401 | end -- _img functions | 386 | end -- _img functions |
402 | 387 | ||
403 | return _img | 388 | return _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 | |||
64 | struct rocklua_image | 60 | struct 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 */ |
75 | struct rli_iter_d | 71 | struct 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, | |||
92 | static inline fb_data invert_color(fb_data rgb) | 88 | static 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) | |||
244 | static void bounds_check_xy(lua_State *L, struct rocklua_image *img, | 240 | static 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 | ||
251 | static struct rocklua_image* rli_checktype(lua_State *L, int arg) | 255 | static 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 | ||
260 | static struct rocklua_image * alloc_rlimage(lua_State *L, bool alloc_data, | 284 | static 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 | ||
313 | static inline fb_data data_setget(fb_data *elem, int x, int y, fb_data *val) | 337 | static 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 | |||
335 | static 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 | ||
341 | static inline fb_data data_get(fb_data *elem, int x, int y) | 361 | static 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 | ||
347 | static fb_data* rli_get_element(struct rocklua_image* img, int x, int y) | 366 | static 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 */ |
366 | static int rli_setget(lua_State *L, bool is_get) | 394 | static 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 |
408 | static bool init_rli_iter(struct rli_iter_d *d, | 428 | static 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 | |||
461 | static 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 | ||
467 | static int d_line(struct rocklua_image *img, | 513 | static 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 */ |
541 | static int d_ellipse_elements(struct rocklua_image * img, | 571 | static 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 | ||
581 | static int d_ellipse(struct rocklua_image *img, | 599 | static 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 */ |
660 | static int rli_line_ellipse(lua_State *L, bool is_ellipse) | 675 | static 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 | 713 | static 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 */ | ||
710 | static 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 */ |
719 | static int custom_transform(lua_State *L, | 722 | static 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 | |||
873 | static 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) | |||
876 | RLI_LUA rli_set(lua_State *L) | 903 | RLI_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 | ||
883 | RLI_LUA rli_get(lua_State *L) | 909 | RLI_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 | ||
890 | RLI_LUA rli_height(lua_State *L) | 915 | RLI_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 | ||
897 | RLI_LUA rli_width(lua_State *L) | 923 | RLI_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 | ||
904 | RLI_LUA rli_equal(lua_State *L) | 930 | RLI_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 | ||
912 | RLI_LUA rli_size(lua_State *L) | 937 | RLI_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 | ||
980 | RLI_LUA rli_line(lua_State *L) | 1008 | RLI_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 | ||
987 | RLI_LUA rli_iterator(lua_State *L) { | 1015 | RLI_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 | ||
1006 | RLI_LUA rli_iterator_factory(lua_State *L) { | 1030 | RLI_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 | ||
1030 | RLI_LUA rli_marshal(lua_State *L) /* also invert */ | 1044 | RLI_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 | ||
1077 | RLI_LUA rli_copy(lua_State *L) | 1079 | RLI_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 | ||
1172 | RLI_LUA rli_clear(lua_State *L) | 1175 | RLI_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 |
1261 | RB_WRAP(lcd_framebuffer) | 1241 | RB_WRAP(lcd_framebuffer) |
1262 | { | 1242 | { |