rockbox/apps/plugins/lua/include_lua/math_ex.lua
William Wilgus af35d19916 Rocklua -- Extend / Fix rliImage
Some devices(1-bit / 2-bit displays) have packed bit formats that
 need to be unpacked in order to work on them at a pixel level.

This caused a few issues on 1 & 2-bit devices:
 Greatly Oversized data arrays for bitmaps
 Improper handling of native image data
 Framebuffer data was near unusable without jumping through hoops

Conversion between native addressing and per pixel addressing
 incurs extra overhead but it is much faster to do it
 on the 'C' side rather than in lua.

Not to mention the advantage of a unified interface for the end programer

-------------------------------------------------------------------
Adds a sane way to access each pixel of image data
Adds:
--------------------------------------------------------------------
img:clear([color],[x1],[y1],[x2],[y2])
 (set whole image or a portion to a particular value)
--------------------------------------------------------------------
img:invert([x1],[y1],[x2],[y2])
 (inverts whole image or a portion)
--------------------------------------------------------------------
img:marshal([x1],[y1],[x2],[y2],[funct])
 (calls funct for each point defined by rect of x1,y1 x2,y2
  returns value and allows setting value of each point return
  nil to terminate early)
--------------------------------------------------------------------
img:points([x1],[y1],[x2],[y2],[dx],[dy])
 (returns iterator function that steps delta-x and delta-y pixels each call
  returns value of pixel each call but doesn't allow setting to a new value
  compare to lua pairs method)
--------------------------------------------------------------------
img:copy(src,[x1],[y1],[x2],[y2],[w],[h],[clip][operation][clr/funct])
 (copies all or part of an image -- straight copy or special ops
  optionally calls funct for each point defined by rect of
  x1, y1, w, h and  x2, y2, w, h for dest and src images
  returns value of dst and src and allows setting value of
  each point return nil to terminate early)
--------------------------------------------------------------------
img:line(x1, y1, x2, y2, color)
--------------------------------------------------------------------
img:ellipse(x1, y1, x2, y2, color, [fillcolor]
--------------------------------------------------------------------
Fixed handling of 2-bit vertical integrated screens

Added direct element access for saving / restoring native image etc.

Added more data to tostring() handler and a way to access individual items

Added equals method to see if two variables reference the same image address
(doesn't check if two separate images contain the same 'picture')

Optimized get and set routines

Fixed out of bound x coord access shifting to next line

Added lua include files to expose new functionality

Finished image saving routine

Static allocation of set_viewport struct faster + saves ram over dynamic

Cleaned up code

Fixed pixel get/set for 1/2 bit devices

Fixed handling for 24-bit devices (32?)

-------------------------------------------------------------------------
Example lua script to follow on forums
-------------------------------------------------------------------------

Change-Id: I8a9ff0ff72aacf4b1662767ccb2b312fc355239c
2018-07-23 05:13:32 +02:00

159 lines
4.5 KiB
Lua

--[[ Lua Missing Math functions
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2017 William Wilgus
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
]]
--[[ Exposed Functions
_math.clamp
_math.clamp_roll
_math.d_sin
_math.d_cos
_math.d_tan
_math.i_sqrt
]]
local _math = {} do
-- internal constants
local _NIL = nil -- _NIL placeholder
-- clamps value to >= min and <= max
local function clamp(iVal, iMin, iMax)
if iMin > iMax then
local swap = iMin
iMin, iMax = iMax, swap
end
if iVal < iMin then
return iMin
elseif iVal < iMax then
return iVal
end
return iMax
end
-- clamps value to >= min and <= max rolls over to opposite
local function clamp_roll(iVal, iMin, iMax)
if iMin > iMax then
local swap = iMin
iMin, iMax = iMax, swap
end
if iVal < iMin then
iVal = iMax
elseif iVal > iMax then
iVal = iMin
end
return iVal
end
local function i_sqrt(n)
-- Newtons square root approximation
if n < 2 then return n end
local g = n / 2
local l = 1
for c = 1, 25 do -- if l,g haven't converged after 25 iterations quit
l = (n / g + g)/ 2
g = (n / l + l)/ 2
if g == l then return g end
end
-- check for period-two cycle between g and l
if g - l == 1 then
return l
elseif l - g == 1 then
return g
end
return _NIL
end
local function d_sin(iDeg, bExtraPrecision)
--[[ values are returned multiplied by 10000
II | I 180-90 | 90-0
---(--)--- -------(--)-------
III | IV 180-270 | 270-360
sine is only positive in quadrants I , II => 0 - 180 degrees
sine 180-360 degrees is a reflection of sine 0-180
Bhaskara I's sine approximation formula isn't overly accurate
but it is close enough for rough image work.
]]
local sign, x
-- no negative angles -10 degrees = 350 degrees
if iDeg < 0 then
x = 360 + (iDeg % 360)
else --keep rotation in 0-360 range
x = iDeg % 360
end
-- reflect II & I onto III & IV
if x > 180 then
sign = -1
x = x % 180
else
sign = 1
end
local x1 = x * (180 - x)
if bExtraPrecision then -- ~halves the largest errors
if x <= 22 or x >= 158 then
return sign * 39818 * x1 / (40497 - x1)
elseif (x >= 40 and x <= 56) or (x > 124 and x < 140) then
return sign * 40002 * x1 / (40450 - x1)
elseif (x > 31 and x < 71) or (x > 109 and x < 150) then
return sign * 40009 * x1 / (40470 - x1)
end
end
--multiplied by 10000 so no decimal in results (RB LUA is integer only)
return sign * 40000 * x1 / (40497 - x1)
end
local function d_cos(iDeg, bExtraPrecision)
--cos is just sine shifed by 90 degrees CCW
return d_sin(90 - iDeg, bExtraPrecision)
end
local function d_tan(iDeg, bExtraPrecision)
--tan = sin0 / cos0
return (d_sin(iDeg, bExtraPrecision) * 10000 / d_sin(90 - iDeg, bExtraPrecision))
end
--expose functions to the outside through _math table
_math.clamp = clamp
_math.clamp_roll = clamp_roll
_math.i_sqrt = i_sqrt
_math.d_sin = d_sin
_math.d_cos = d_cos
_math.d_tan = d_tan
end -- missing math functions
return _math