Difference between revisions of "Ftf libs"
From GiderosMobile
(5 intermediate revisions by the same user not shown) | |||
Line 4: | Line 4: | ||
'''All samples are ready to use. Enjoy!''' | '''All samples are ready to use. Enjoy!''' | ||
+ | |||
+ | == AUDIO == | ||
+ | === Producing Sound Without Resources '''@PaulH''' === | ||
+ | '''Creates files on the fly using the .wav format for playback''' | ||
+ | <syntaxhighlight lang="lua"> | ||
+ | -- https://forum.gideros.rocks/discussion/comment/68095/#Comment_68095 | ||
+ | function make_wave(file_name, length, wave, freq, vol) | ||
+ | -- We'll need to write some 32 bit values in binary. Helper function for that: | ||
+ | local function to4Bytes(n) return n & 0xff, (n>>8) & 0xff, (n>>16) & 0xff, (n>>24) & 0xff end | ||
+ | |||
+ | -- For a given point (sample number) in a wav file, return the 16 bit value for the specified sound wave and frequency | ||
+ | local function sound_wave(wave,p,freq,vol) | ||
+ | local sample_rate = 6000 | ||
+ | local n = 0 -- Default to silence | ||
+ | if wave == "noise" then n = math.random(-255*128*vol, 255*128*vol) | ||
+ | elseif wave == "sine" then n = math.floor(math.sin(p/sample_rate*freq*math.rad(180))*256*vol*127) | ||
+ | elseif wave == "sawtooth" then n = math.floor((freq*p/sample_rate)*256*vol*256) | ||
+ | end | ||
+ | local c2, c1 = (n>>8) & 0xff, n & 0xff | ||
+ | return string.char(c1, c2) | ||
+ | end | ||
+ | |||
+ | -- We're just dealing with a fixed format wav file: | ||
+ | local sample_rate = 6000 | ||
+ | local samples = length*sample_rate | ||
+ | local data_size = samples*2 | ||
+ | local total_file_length = 44+data_size | ||
+ | local fl1, fl2, fl3, fl4 = to4Bytes(total_file_length) | ||
+ | local ds1, ds2, ds3, ds4 = to4Bytes(data_size) | ||
+ | local f = io.open(file_name, "wb") | ||
+ | -- Write the WAV file header: | ||
+ | f:write( | ||
+ | string.char( | ||
+ | 82,73,70,70,--RIFF | ||
+ | fl1, fl2, fl3, fl4,-- File size overall | ||
+ | 87,65,86,69,-- WAVE header | ||
+ | 102,109,116,32,--fmt chunk marker w/ trailing null | ||
+ | 16,0,0,0, -- Length of format data (16 bytes before this) | ||
+ | 1,0, -- Wave type. 1 == PCM | ||
+ | 1,0, -- Channels. 1 == mono | ||
+ | 112,23,0,0,-- Sample rate (Hertz) | ||
+ | 224,46,0,0, -- Bits per sample * channels * sample rate / 8 | ||
+ | 2,0, | ||
+ | 16,0, -- Bytes per sample - this is 16 | ||
+ | 100,97,116,97, -- "data" - chunk header | ||
+ | ds1,ds2,ds3,ds4-- size of data section | ||
+ | ) | ||
+ | ) | ||
+ | -- Write the data: | ||
+ | for l = 1, samples do | ||
+ | f:write(sound_wave(wave,l,freq, vol or 1)) | ||
+ | end | ||
+ | f:close() | ||
+ | end | ||
+ | |||
+ | -- Demo some white noise: | ||
+ | --make_wave("|D|noise.wav", 1, "noise") -- 0.1 second sine wave at 256 Herz (middle C) at full volume | ||
+ | --s=Sound.new("|D|noise.wav") | ||
+ | --s:play() | ||
+ | |||
+ | -- one note with a sawtooth wave: | ||
+ | --make_wave("|D|note.wav", 2, "sawtooth", 262, 1) -- 0.1 second sine wave at 256 Herz (middle C) at full volume | ||
+ | --s=Sound.new("|D|note.wav") | ||
+ | --s:play() | ||
+ | |||
+ | -- Make wave files for the chromatic scale. | ||
+ | -- The frequencies in Hertz of the notes in octave zero: | ||
+ | notes = { 16.35, 17.32, 18.35, 19.45, 20.60, 21.83, 23.12, 24.5, 25.96, 27.50, 29.14, 30.87 } | ||
+ | -- 3 letter names for those notes: | ||
+ | names = { "C0n", "C0s", "D0n", "D0s", "E0n", "F0n", "F0s", "G0n", "G0s", "A0n", "A0s", "B0n" } | ||
+ | -- Compute the ratio of each note to the C: | ||
+ | local note_multipliers = {} | ||
+ | for i = 1, #notes do | ||
+ | note_multipliers[i] = notes[i]/notes[1] | ||
+ | end | ||
+ | |||
+ | -- Make a sound for each note in several octaves: | ||
+ | local sounds = {} | ||
+ | for octave = 3, 7 do | ||
+ | for i = 1, #names do | ||
+ | local original_note = names[i] | ||
+ | local octave_note = string.gsub(original_note, "0", octave) | ||
+ | local file_name = "|D|note_" .. octave_note .. ".wav" | ||
+ | -- Compute the frequency for the note by applying the ratio of that note over C | ||
+ | -- and then apply the octave multiplier. Each octave is double the frequency | ||
+ | -- of the one below it: | ||
+ | local fr = math.floor(notes[1] * note_multipliers[i] * math.pow(2, octave)) | ||
+ | -- We'll make each note 0.2 seconds, using a sine wave | ||
+ | --function make_wave(file_name, length, wave, freq, vol) | ||
+ | make_wave(file_name, 0.2, "sine", fr, 1) | ||
+ | sounds[octave_note] = Sound.new(file_name) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | -- Given a string of 3 letter note names, play those notes in order: | ||
+ | function play_sequence(seq) | ||
+ | for i = 1, string.len(seq), 3 do | ||
+ | local note = string.sub(seq, i, i+2) | ||
+ | if sounds[note] then | ||
+ | Timer.delayedCall(60 * (i-1), function() | ||
+ | sounds[note]:play() | ||
+ | end) | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | local fur_elise = | ||
+ | "E4nD4sE4nD4sE4nB3nD4nC4nA3n ".. | ||
+ | "C3nE3nA3nB3n ".. | ||
+ | "E3nG3sB3nC4n ".. | ||
+ | "E3nE4nD4sE4nD4sE4nB3nD4nC4nA3n ".. | ||
+ | "C3nE3nA3nB3n ".. | ||
+ | "E3nC4nB3nA3n" | ||
+ | play_sequence(fur_elise) | ||
+ | -- To play an octave higher: | ||
+ | Timer.delayedCall(9000, function() | ||
+ | play_sequence(string.gsub(string.gsub(fur_elise,"4","5"),"3","4")) | ||
+ | end) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == STRING == | ||
+ | === Score Counting TextField '''@errorpi''' === | ||
+ | <syntaxhighlight lang="lua"> | ||
+ | --[[ | ||
+ | Score Counting TextField | ||
+ | by: @errorpi | ||
+ | ]] | ||
+ | |||
+ | Score = Core.class(Sprite) | ||
+ | |||
+ | function Score:init(xscore, xincrease) | ||
+ | self.score = xscore or 0 | ||
+ | self.countTime = (xincrease or 5) * 100 | ||
+ | -- a textfield | ||
+ | self.scoreText = TextField.new(nil, tostring(self.score)) | ||
+ | self.scoreText:setLayout({wid = 80, hei = 40, flags=FontBase.TLF_CENTER}) | ||
+ | self.scoreText:setTextColor(math.random(0xffffff)) | ||
+ | self.scoreText:setScale(5) | ||
+ | self.scoreText:setPosition(64, 64) | ||
+ | self:addChild(self.scoreText) | ||
+ | -- a timer | ||
+ | self.t = Timer.new(1) -- timer init | ||
+ | self.t:addEventListener(Event.TIMER, self.updateText, self) | ||
+ | end | ||
+ | |||
+ | function Score:updateText() | ||
+ | local displayScore = tonumber(self.scoreText:getText()) | ||
+ | if displayScore < self.score then | ||
+ | self.scoreText:setText(tostring( displayScore + 1) ) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | function Score:addScore(add) | ||
+ | self.score += add | ||
+ | local displayScore = tonumber(self.scoreText:getText()) | ||
+ | -- set timer properties (bigger add score means faster steps) | ||
+ | local tRepeat = self.score - displayScore | ||
+ | local tDelay = self.countTime / tRepeat | ||
+ | self.t:stop() | ||
+ | self.t:reset() | ||
+ | self.t:setDelay(tDelay) | ||
+ | self.t:setRepeatCount(tRepeat) | ||
+ | self.t:start() | ||
+ | |||
+ | return self.score | ||
+ | end | ||
+ | |||
+ | -------------------- | ||
+ | application:setBackgroundColor(0x4d4d4d) | ||
+ | -- demo | ||
+ | local initialscore = 500 | ||
+ | local score = Score.new(initialscore, 6) -- initial score value, increase speed | ||
+ | stage:addChild(score) | ||
+ | local earnedpoints = 300 | ||
+ | |||
+ | Timer.delayedCall(3000, function() | ||
+ | score:addScore(earnedpoints) -- target score value | ||
+ | end) | ||
+ | </syntaxhighlight> | ||
== GFX == | == GFX == | ||
− | === Hex to Number / Number to Hex === | + | === Hex to Number / Number to Hex '''@hanzhao''' === |
<syntaxhighlight lang="lua"> | <syntaxhighlight lang="lua"> | ||
--[[ | --[[ | ||
Line 167: | Line 346: | ||
end) | end) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | === Xml Parser '''@Alexander Makeev''' === | ||
+ | <syntaxhighlight lang="lua"> | ||
+ | ----------------------------------------------------------------------------------------- | ||
+ | -- LUA only XmlParser from Alexander Makeev | ||
+ | ----------------------------------------------------------------------------------------- | ||
+ | XmlParser = {} | ||
+ | |||
+ | function XmlParser:ToXmlString(value) | ||
+ | value = string.gsub(value, "&", "&") -- '&' -> "&" | ||
+ | value = string.gsub(value, "<", "<") -- '<' -> "<" | ||
+ | value = string.gsub(value, ">", ">") -- '>' -> ">" | ||
+ | --value = string.gsub(value, "'", "'") -- '\'' -> "'" | ||
+ | value = string.gsub(value, "\"", """) -- '"' -> """ | ||
+ | -- replace non printable char -> "
" | ||
+ | value = string.gsub(value, "([^%w%&%;%p%\t% ])", function(c) | ||
+ | return string.format("&#x%X;", string.byte(c)) | ||
+ | --return string.format("&#x%02X;", string.byte(c)) | ||
+ | --return string.format("&#%02d;", string.byte(c)) | ||
+ | end) | ||
+ | return value | ||
+ | end | ||
+ | |||
+ | function XmlParser:FromXmlString(value) | ||
+ | value = string.gsub(value, "&#x([%x]+)%;", function(h) | ||
+ | return string.char(tonumber(h,16)) | ||
+ | end) | ||
+ | value = string.gsub(value, "&#([0-9]+)%;", function(h) | ||
+ | return string.char(tonumber(h,10)) | ||
+ | end) | ||
+ | value = string.gsub(value, """, "\"") | ||
+ | value = string.gsub(value, "'", "'") | ||
+ | value = string.gsub(value, ">", ">") | ||
+ | value = string.gsub(value, "<", "<") | ||
+ | value = string.gsub(value, "&", "&") | ||
+ | return value | ||
+ | end | ||
+ | |||
+ | function XmlParser:ParseArgs(s) | ||
+ | local arg = {} | ||
+ | string.gsub(s, "(%w+)=([\"'])(.-)%2", function(w, _, a) | ||
+ | arg[w] = self:FromXmlString(a) | ||
+ | end) | ||
+ | return arg | ||
+ | end | ||
+ | |||
+ | function XmlParser:ParseXmlText(xmlText) | ||
+ | local stack = {} | ||
+ | local top = { Name=nil, Value=nil, Attributes={}, ChildNodes={} } | ||
+ | table.insert(stack, top) | ||
+ | local ni, c, label, xarg, empty | ||
+ | local i, j = 1, 1 | ||
+ | while true do | ||
+ | ni, j, c, label, xarg, empty = string.find(xmlText, "<(%/?)([%w:]+)(.-)(%/?)>", i) | ||
+ | if not ni then break end | ||
+ | local text = string.sub(xmlText, i, ni-1) | ||
+ | if not string.find(text, "^%s*$") then | ||
+ | top.Value=(top.Value or "")..self:FromXmlString(text) | ||
+ | end | ||
+ | if empty == "/" then -- empty element tag | ||
+ | table.insert(top.ChildNodes, | ||
+ | { | ||
+ | Name=label, Value=nil, Attributes=self:ParseArgs(xarg), ChildNodes={} | ||
+ | } | ||
+ | ) | ||
+ | elseif c == "" then -- start tag | ||
+ | top = { Name=label, Value=nil, Attributes=self:ParseArgs(xarg), ChildNodes={} } | ||
+ | table.insert(stack, top) -- new level | ||
+ | --log("openTag ="..top.Name) | ||
+ | else -- end tag | ||
+ | local toclose = table.remove(stack) -- remove top | ||
+ | --log("closeTag="..toclose.Name) | ||
+ | top = stack[#stack] | ||
+ | if #stack < 1 then | ||
+ | error("XmlParser: nothing to close with "..label) | ||
+ | end | ||
+ | if toclose.Name ~= label then | ||
+ | error("XmlParser: trying to close "..toclose.Name.." with "..label) | ||
+ | end | ||
+ | table.insert(top.ChildNodes, toclose) | ||
+ | end | ||
+ | i = j + 1 | ||
+ | end | ||
+ | local text = string.sub(xmlText, i) | ||
+ | if not string.find(text, "^%s*$") then | ||
+ | stack[#stack].Value=(stack[#stack].Value or "")..self:FromXmlString(text) | ||
+ | end | ||
+ | if #stack > 1 then | ||
+ | error("XmlParser: unclosed "..stack[stack.n].Name) | ||
+ | end | ||
+ | return stack[1].ChildNodes[1] | ||
+ | end | ||
+ | |||
+ | function XmlParser:ParseXmlFile(xmlFileName) | ||
+ | local hFile, err = io.open(xmlFileName,"r") | ||
+ | if (not err) then | ||
+ | local xmlText=hFile:read("*a") -- read file content | ||
+ | io.close(hFile) | ||
+ | return self:ParseXmlText(xmlText),nil | ||
+ | else | ||
+ | return nil, err | ||
+ | end | ||
+ | end | ||
+ | |||
+ | --[[ | ||
+ | -- Usage: | ||
+ | -- parse xml | ||
+ | local xml = XmlParser:ParseXmlText(myxmlfile) | ||
+ | ]] | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == TABLE == | ||
+ | === Var Dump '''@xxx''' === | ||
+ | <syntaxhighlight lang="lua"> | ||
+ | function vardump(value, depth, key) | ||
+ | local linePrefix = "" | ||
+ | local spaces = "" | ||
+ | |||
+ | if key ~= nil then | ||
+ | linePrefix = "["..key.."] = " | ||
+ | end | ||
+ | |||
+ | if depth == nil then | ||
+ | depth = 0 | ||
+ | else | ||
+ | depth = depth + 1 | ||
+ | for i = 1, depth do | ||
+ | spaces = spaces .. " " | ||
+ | end | ||
+ | end | ||
+ | |||
+ | if type(value) == 'table' then | ||
+ | local mTable = getmetatable(value) | ||
+ | if mTable == nil then | ||
+ | print(spaces ..linePrefix.."(table) ") | ||
+ | else | ||
+ | print(spaces .."(metatable) ") | ||
+ | value = mTable | ||
+ | end | ||
+ | for tableKey, tableValue in pairs(value) do | ||
+ | vardump(tableValue, depth, tableKey) | ||
+ | end | ||
+ | elseif type(value) == 'function' or | ||
+ | type(value) == 'thread' or | ||
+ | type(value) == 'userdata' or | ||
+ | value == nil | ||
+ | then | ||
+ | print(spaces..tostring(value)) | ||
+ | else | ||
+ | print(spaces..linePrefix.."("..type(value)..") "..tostring(value)) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | --[[ | ||
+ | Usage: | ||
+ | foo="Hello world" | ||
+ | vardump(foo) | ||
+ | vardump( { print, 12, nil, io.stdin, math } ) | ||
+ | |||
+ | foo = { | ||
+ | "zero",1,2,3,{1,{1,2,3,4,{1,2,{1,"cool",2},4},6},3,vardump,5,6}, 5,{Mary=10, Paul="10"},"last value" | ||
+ | } | ||
+ | vardump(foo) | ||
+ | --]] | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | |||
Latest revision as of 04:06, 31 July 2025
Here are some longer code (classes) from the Gideros forum and some other places :-)
All samples are ready to use. Enjoy!
AUDIO
Producing Sound Without Resources @PaulH
Creates files on the fly using the .wav format for playback
-- https://forum.gideros.rocks/discussion/comment/68095/#Comment_68095
function make_wave(file_name, length, wave, freq, vol)
-- We'll need to write some 32 bit values in binary. Helper function for that:
local function to4Bytes(n) return n & 0xff, (n>>8) & 0xff, (n>>16) & 0xff, (n>>24) & 0xff end
-- For a given point (sample number) in a wav file, return the 16 bit value for the specified sound wave and frequency
local function sound_wave(wave,p,freq,vol)
local sample_rate = 6000
local n = 0 -- Default to silence
if wave == "noise" then n = math.random(-255*128*vol, 255*128*vol)
elseif wave == "sine" then n = math.floor(math.sin(p/sample_rate*freq*math.rad(180))*256*vol*127)
elseif wave == "sawtooth" then n = math.floor((freq*p/sample_rate)*256*vol*256)
end
local c2, c1 = (n>>8) & 0xff, n & 0xff
return string.char(c1, c2)
end
-- We're just dealing with a fixed format wav file:
local sample_rate = 6000
local samples = length*sample_rate
local data_size = samples*2
local total_file_length = 44+data_size
local fl1, fl2, fl3, fl4 = to4Bytes(total_file_length)
local ds1, ds2, ds3, ds4 = to4Bytes(data_size)
local f = io.open(file_name, "wb")
-- Write the WAV file header:
f:write(
string.char(
82,73,70,70,--RIFF
fl1, fl2, fl3, fl4,-- File size overall
87,65,86,69,-- WAVE header
102,109,116,32,--fmt chunk marker w/ trailing null
16,0,0,0, -- Length of format data (16 bytes before this)
1,0, -- Wave type. 1 == PCM
1,0, -- Channels. 1 == mono
112,23,0,0,-- Sample rate (Hertz)
224,46,0,0, -- Bits per sample * channels * sample rate / 8
2,0,
16,0, -- Bytes per sample - this is 16
100,97,116,97, -- "data" - chunk header
ds1,ds2,ds3,ds4-- size of data section
)
)
-- Write the data:
for l = 1, samples do
f:write(sound_wave(wave,l,freq, vol or 1))
end
f:close()
end
-- Demo some white noise:
--make_wave("|D|noise.wav", 1, "noise") -- 0.1 second sine wave at 256 Herz (middle C) at full volume
--s=Sound.new("|D|noise.wav")
--s:play()
-- one note with a sawtooth wave:
--make_wave("|D|note.wav", 2, "sawtooth", 262, 1) -- 0.1 second sine wave at 256 Herz (middle C) at full volume
--s=Sound.new("|D|note.wav")
--s:play()
-- Make wave files for the chromatic scale.
-- The frequencies in Hertz of the notes in octave zero:
notes = { 16.35, 17.32, 18.35, 19.45, 20.60, 21.83, 23.12, 24.5, 25.96, 27.50, 29.14, 30.87 }
-- 3 letter names for those notes:
names = { "C0n", "C0s", "D0n", "D0s", "E0n", "F0n", "F0s", "G0n", "G0s", "A0n", "A0s", "B0n" }
-- Compute the ratio of each note to the C:
local note_multipliers = {}
for i = 1, #notes do
note_multipliers[i] = notes[i]/notes[1]
end
-- Make a sound for each note in several octaves:
local sounds = {}
for octave = 3, 7 do
for i = 1, #names do
local original_note = names[i]
local octave_note = string.gsub(original_note, "0", octave)
local file_name = "|D|note_" .. octave_note .. ".wav"
-- Compute the frequency for the note by applying the ratio of that note over C
-- and then apply the octave multiplier. Each octave is double the frequency
-- of the one below it:
local fr = math.floor(notes[1] * note_multipliers[i] * math.pow(2, octave))
-- We'll make each note 0.2 seconds, using a sine wave
--function make_wave(file_name, length, wave, freq, vol)
make_wave(file_name, 0.2, "sine", fr, 1)
sounds[octave_note] = Sound.new(file_name)
end
end
-- Given a string of 3 letter note names, play those notes in order:
function play_sequence(seq)
for i = 1, string.len(seq), 3 do
local note = string.sub(seq, i, i+2)
if sounds[note] then
Timer.delayedCall(60 * (i-1), function()
sounds[note]:play()
end)
end
end
end
local fur_elise =
"E4nD4sE4nD4sE4nB3nD4nC4nA3n "..
"C3nE3nA3nB3n "..
"E3nG3sB3nC4n "..
"E3nE4nD4sE4nD4sE4nB3nD4nC4nA3n "..
"C3nE3nA3nB3n "..
"E3nC4nB3nA3n"
play_sequence(fur_elise)
-- To play an octave higher:
Timer.delayedCall(9000, function()
play_sequence(string.gsub(string.gsub(fur_elise,"4","5"),"3","4"))
end)
STRING
Score Counting TextField @errorpi
--[[
Score Counting TextField
by: @errorpi
]]
Score = Core.class(Sprite)
function Score:init(xscore, xincrease)
self.score = xscore or 0
self.countTime = (xincrease or 5) * 100
-- a textfield
self.scoreText = TextField.new(nil, tostring(self.score))
self.scoreText:setLayout({wid = 80, hei = 40, flags=FontBase.TLF_CENTER})
self.scoreText:setTextColor(math.random(0xffffff))
self.scoreText:setScale(5)
self.scoreText:setPosition(64, 64)
self:addChild(self.scoreText)
-- a timer
self.t = Timer.new(1) -- timer init
self.t:addEventListener(Event.TIMER, self.updateText, self)
end
function Score:updateText()
local displayScore = tonumber(self.scoreText:getText())
if displayScore < self.score then
self.scoreText:setText(tostring( displayScore + 1) )
end
end
function Score:addScore(add)
self.score += add
local displayScore = tonumber(self.scoreText:getText())
-- set timer properties (bigger add score means faster steps)
local tRepeat = self.score - displayScore
local tDelay = self.countTime / tRepeat
self.t:stop()
self.t:reset()
self.t:setDelay(tDelay)
self.t:setRepeatCount(tRepeat)
self.t:start()
return self.score
end
--------------------
application:setBackgroundColor(0x4d4d4d)
-- demo
local initialscore = 500
local score = Score.new(initialscore, 6) -- initial score value, increase speed
stage:addChild(score)
local earnedpoints = 300
Timer.delayedCall(3000, function()
score:addScore(earnedpoints) -- target score value
end)
GFX
Hex to Number / Number to Hex @hanzhao
--[[
Lua Hex v0.4
-------------------
Hex conversion lib for Lua.
How to use:
lhex.to_hex(n) -- convert a number to a hex string
lhex.to_dec(hex) -- convert a hex "string" (prefix with "0x..." or "0X...") to number
Part of LuaBit(http://luaforge.net/projects/bit/).
Under the MIT license.
copyright(c) 2006~2007 hanzhao (abrash_han@hotmail.com)
--]]
local function to_bits(n)
-- checking not float
if(n - (n//1) > 0) then error("trying to apply bitwise operation on non-integer!") end
if(n < 0) then return to_bits(~(n//1) + 1) end -- negative
-- to bits table
local tbl = {}
local cnt = 1
while (n > 0) do
local last = n%2
if(last == 1) then tbl[cnt] = 1
else tbl[cnt] = 0
end
n = (n-last)/2
cnt += 1
end
return tbl
end
local function tbl_to_number(tbl)
local n = #tbl
local rslt = 0
local power = 1
for i = 1, n do
rslt += tbl[i]*power
power *= 2
end
return rslt
end
local function to_hex(n)
if(type(n) ~= "number") then error("non-number type passed in.") end
-- checking not float
if(n - (n//1) > 0) then error("trying to apply bitwise operation on non-integer!") end
if(n < 0) then -- negative
n = to_bits(~(-n<>n) + 1)
n = tbl_to_number(n)
end
local hex_tbl = { "A", "B", "C", "D", "E", "F" }
local hex_str = ""
while(n ~= 0) do
local last = n%16
if(last < 10) then hex_str = tostring(last) .. hex_str
else hex_str = hex_tbl[last-10+1] .. hex_str
end
n = (n/16)//1 -- floor
end
if(hex_str == "") then hex_str = "0" end
return "0x"..hex_str
end
local function to_dec(hexstring)
if(type(hexstring) ~= "string") then error("non-string type passed in.") end
local head = string.sub(hexstring, 1, 2)
if(head ~= "0x" and head ~= "0X") then error("wrong hex format, should lead by 0x or 0X.") end
return tonumber(hexstring:sub(3), 16) -- base 16
end
--------------------
-- lua hex lib interface
lhex = {
to_hex=to_hex,
to_dec=to_dec,
}
--------------------
-- examples
local dec = 4341688
local hex = lhex.to_hex(dec) -- number to hex
print(hex) -- 0x423FB8
local revdec = lhex.to_dec(hex) -- hex string (prefix with "0x" or "0X") to number
print(revdec) -- 4341688
print(lhex.to_dec("0x0")) -- 0, hex string (prefix with "0x" or "0X") to number
print(lhex.to_dec("0x00ff00")) -- 65280, hex string (prefix with "0x" or "0X") to number
print(lhex.to_hex(16777215)) -- 0xFFFFFF, number to hex
local pix = Pixel.new(lhex.to_hex(56816), 1, 32, 32)
stage:addChild(pix)
print("hex is", hex)
FILES
Get Files in Folder @xxx
note: requires the Lfs plugin
Gets all the files in a folder matching a file extension and store them in a list.
local myos = application:getDeviceInfo()
local iswin32 = if myos == "win32" then true else false
--print(iswin32)
function getFilesInFolder(xpath, xlist)
local lfs = require "lfs"
for file in lfs.dir(xpath) do
if file ~= "." and file ~= ".." then
if file:match(".png$") then -- choose your file extension here
if iswin32 then
local f = xpath.."\\"..file
-- print(f)
xlist[#xlist + 1] = f:gsub("/", "\\")
else
local f = xpath.."/"..file
-- print(f)
xlist[#xlist + 1] = f:gsub("\\", "/")
end
end
end
end
lfs = nil
end
Demo code using ButtonMonster
local myos = application:getDeviceInfo()
local iswin32 = if myos == "win32" then true else false
--print(iswin32)
local folderimages = {} -- list all images in user selected folder
local images = {} -- list all images with valid extension
local btnimagefolder = ButtonMonster.new({
pixelcolorup=0xffaa00, text="import images", textcolorup=0xaa0000, textscalex=3,
isautoscale=true,
})
btnimagefolder:setPosition(16, 16)
stage:addChild(btnimagefolder)
btnimagefolder:addEventListener("clicked", function()
local path
if iswin32 then path = application:get("openDirectoryDialog", "Select Folder", "C:\\tmp\\")
else path = application:get("openDirectoryDialog", "Select Folder", "C:/tmp/")
end -- print(path)
if path then getFilesInFolder(path, folderimages) end
if folderimages and #folderimages > 0 then
for i = 1, #folderimages do
images[i] = Bitmap.new(Texture.new(folderimages[i]), true)
images[i]:setAnchorPoint(0.5, 1)
images[i]:setPosition(8, 8)
-- ...
end
end
end)
Xml Parser @Alexander Makeev
-----------------------------------------------------------------------------------------
-- LUA only XmlParser from Alexander Makeev
-----------------------------------------------------------------------------------------
XmlParser = {}
function XmlParser:ToXmlString(value)
value = string.gsub(value, "&", "&") -- '&' -> "&"
value = string.gsub(value, "<", "<") -- '<' -> "<"
value = string.gsub(value, ">", ">") -- '>' -> ">"
--value = string.gsub(value, "'", "'") -- '\'' -> "'"
value = string.gsub(value, "\"", """) -- '"' -> """
-- replace non printable char -> "
"
value = string.gsub(value, "([^%w%&%;%p%\t% ])", function(c)
return string.format("&#x%X;", string.byte(c))
--return string.format("&#x%02X;", string.byte(c))
--return string.format("&#%02d;", string.byte(c))
end)
return value
end
function XmlParser:FromXmlString(value)
value = string.gsub(value, "&#x([%x]+)%;", function(h)
return string.char(tonumber(h,16))
end)
value = string.gsub(value, "&#([0-9]+)%;", function(h)
return string.char(tonumber(h,10))
end)
value = string.gsub(value, """, "\"")
value = string.gsub(value, "'", "'")
value = string.gsub(value, ">", ">")
value = string.gsub(value, "<", "<")
value = string.gsub(value, "&", "&")
return value
end
function XmlParser:ParseArgs(s)
local arg = {}
string.gsub(s, "(%w+)=([\"'])(.-)%2", function(w, _, a)
arg[w] = self:FromXmlString(a)
end)
return arg
end
function XmlParser:ParseXmlText(xmlText)
local stack = {}
local top = { Name=nil, Value=nil, Attributes={}, ChildNodes={} }
table.insert(stack, top)
local ni, c, label, xarg, empty
local i, j = 1, 1
while true do
ni, j, c, label, xarg, empty = string.find(xmlText, "<(%/?)([%w:]+)(.-)(%/?)>", i)
if not ni then break end
local text = string.sub(xmlText, i, ni-1)
if not string.find(text, "^%s*$") then
top.Value=(top.Value or "")..self:FromXmlString(text)
end
if empty == "/" then -- empty element tag
table.insert(top.ChildNodes,
{
Name=label, Value=nil, Attributes=self:ParseArgs(xarg), ChildNodes={}
}
)
elseif c == "" then -- start tag
top = { Name=label, Value=nil, Attributes=self:ParseArgs(xarg), ChildNodes={} }
table.insert(stack, top) -- new level
--log("openTag ="..top.Name)
else -- end tag
local toclose = table.remove(stack) -- remove top
--log("closeTag="..toclose.Name)
top = stack[#stack]
if #stack < 1 then
error("XmlParser: nothing to close with "..label)
end
if toclose.Name ~= label then
error("XmlParser: trying to close "..toclose.Name.." with "..label)
end
table.insert(top.ChildNodes, toclose)
end
i = j + 1
end
local text = string.sub(xmlText, i)
if not string.find(text, "^%s*$") then
stack[#stack].Value=(stack[#stack].Value or "")..self:FromXmlString(text)
end
if #stack > 1 then
error("XmlParser: unclosed "..stack[stack.n].Name)
end
return stack[1].ChildNodes[1]
end
function XmlParser:ParseXmlFile(xmlFileName)
local hFile, err = io.open(xmlFileName,"r")
if (not err) then
local xmlText=hFile:read("*a") -- read file content
io.close(hFile)
return self:ParseXmlText(xmlText),nil
else
return nil, err
end
end
--[[
-- Usage:
-- parse xml
local xml = XmlParser:ParseXmlText(myxmlfile)
]]
TABLE
Var Dump @xxx
function vardump(value, depth, key)
local linePrefix = ""
local spaces = ""
if key ~= nil then
linePrefix = "["..key.."] = "
end
if depth == nil then
depth = 0
else
depth = depth + 1
for i = 1, depth do
spaces = spaces .. " "
end
end
if type(value) == 'table' then
local mTable = getmetatable(value)
if mTable == nil then
print(spaces ..linePrefix.."(table) ")
else
print(spaces .."(metatable) ")
value = mTable
end
for tableKey, tableValue in pairs(value) do
vardump(tableValue, depth, tableKey)
end
elseif type(value) == 'function' or
type(value) == 'thread' or
type(value) == 'userdata' or
value == nil
then
print(spaces..tostring(value))
else
print(spaces..linePrefix.."("..type(value)..") "..tostring(value))
end
end
--[[
Usage:
foo="Hello world"
vardump(foo)
vardump( { print, 12, nil, io.stdin, math } )
foo = {
"zero",1,2,3,{1,{1,2,3,4,{1,2,{1,"cool",2},4},6},3,vardump,5,6}, 5,{Mary=10, Paul="10"},"last value"
}
vardump(foo)
--]]
More to come God's willing...