No, you didn't misread, what i'm about to give you is a series of scripts normally used in mathematics.
They don't desserve any porpose other than having fun with the engine, so enjoy !
1. the Mandelbrot set--[[
A useless-thus-indispensable Mandelbrot set renderer
How it works :
the Mandelbrod set consists of a 2d grid of complex numbers,
which are an extension of real numbers and are written in, the form :
a+b*i, where a and b are two real numbers, and i is the square root of -1,
also called the imaginary nuimber.
For each point of the grid, let(s call it c, we gererate a new complex, number called z by applying the following formula :
initial z value : 0
new z = (z to the power of <whatever you want>) + c
then we compare the new value to (2 to the power of <the same exponent as before>
then, we continue in one of the wollowing cases :
if z is lower than the powered 2, then we do the above steps again, unless we reached the maximum number if iterations
if, however, we are equal or higher than the powered 2,
then we stop iterating since the next calculated numbers wil keep growing forever, namely, we escaped the 2-range stability area
Anyway, once we have finished calculatins the final value for a given number, we color it according to it's behaviour :
-if we escaped, then we color the corresponding point using the number of cleared iterations to index the color from a palette
taking the mod from table size
-else, we color it pitch black
this process goes on and on until all visible points are rendered.
For more information, feel free to check on the Wiki or any math article
How to use :
1. create a map of the size of your choice
2. copy/paste this whole code in the map script.
3. setup the config table with your own parameters
4. Run the map !
--]]
local map = ...
local game = map:get_game()
-- the configuration table
local config={
-- Size of the rendering area in game pixels.
-- Must be lower than the map size to render properly
grid={
width=401,
height=401
},
-- the maximum number of iterations for each point.
maxIterations=1000,
-- the calculation power. Defaulr : 2
powerExponent=2,
-- the starting complex numbers boundaries
numberBoundaries={
x={
min=-2,
max=2,
},
y={
min=-2,
max=2,
},
},
step={},
}
local start_time
-- returns the module of any complex number, aka the length of the vector represented by this number
local function get_module(c)
return c.real*c.real+c.imag*c.imag
end
--calculates z^N with z=real+i*imag and N>0
local function complex_power(c, exponent)
local squaredModule=get_module(c)
local newModule=math.pow(squaredModule,exponent/2)
local argument=math.atan2(c.imag,c.real)
return {
real=math.cos(exponent*argument)*newModule,
imag=math.sin(exponent*argument)*newModule,
}
end
local currentNumber={
real=config.numberBoundaries.x.min,
imag=config.numberBoundaries.y.max,
}
local currentPoint={
x=0,
y=0,
}
-- a 1*1 surface used as a pixel, to compensate the lack of proper API pixel manipulatinf functions
local pixel=sol.surface.create(1,1)
local fractalRender=sol.surface.create(config.grid.width,config.grid.height)
-- the actual color palette. Feel free to modify it with your own colors (any size will work)
local color_palette={
{255,255,0},
{255,223,31},
{255,191,63},
{255,159,95},
{255,127,127},
{255,95,159},
{255,63,191},
{255,31,223},
{223,0,255},
{255,31,255},
{191,63,255},
{159,95,255},
{127,127,255},
{95,159,255},
{63,191,255},
{31,223,255},
{0,255,255},
{31,255,223},
{63,255,191},
{95,255,159},
{127,255,127},
{159,255,95},
{191,255,63},
{223,255,31},
}
-- the rendering call
local function draw_point(x,y,i)
local color
if i==config.maxIterations then
color={0,0,0}
else
local index=(i%#color_palette)+1
color=color_palette[index]
end
pixel:fill_color(color)
pixel:draw(fractalRender,x,y)
end
-- the core functions. Called once per map update.
-- i don't use for loops to get each point, but increase indices at the end of this function instead.
-- to save the engine from lagging/crashing
local function calculateNextPoint()
local z={
real=0,
imag=0,
}
local real=currentNumber.real
local imag=currentNumber.imag
local i=0
local e=config.powerExponent
--The core calculation loop. see the explaination at the beginning of the script
while (i<config.maxIterations and get_module(z)<=math.pow(2,e)) do
local temp=complex_power(z,e)
z.real=temp.real+real
z.imag=temp.imag+imag
i=i+1
end
--render point
draw_point(currentPoint.x,currentPoint.y,i)
--Prepare for next loop
currentPoint.x=currentPoint.x+1
currentNumber.real = real + config.step.x
--End of horizontal line
if real > config.numberBoundaries.x.max then
currentNumber.real = config.numberBoundaries.x.min
currentNumber.imag = imag-config.step.y
currentPoint.x=0
currentPoint.y=currentPoint.y+1
end
if imag<config.numberBoundaries.y.min then
--All points have been processed. We can stop the function from starting again
--Debug lines for render time benchmarking? uncomment the next two lines to activate
--print("done !")
--print("time elapsed :"..os.clock()-start_time .."s")
return false
end
return true
end
function map:on_started()
map:get_hero():set_visible(false)
end
function map:on_finished()
map:get_hero():set_visible(true)
end
-- starting the whole process
function map:on_opening_transition_finished()
config.step.x=(config.numberBoundaries.x.max-config.numberBoundaries.x.min)/(config.grid.width-1)
config.step.y=(config.numberBoundaries.y.max-config.numberBoundaries.y.min)/(config.grid.height-1)
--print("step X="..config.step.x..",step Y="..config.step.y)
--getting the current time for later usage, if you want to benchmark the rendering duration, just uncomment the next line
--start_time=os.clock()
sol.timer.start(1, calculateNextPoint)
end
function map:on_draw(dst)
local camera=map:get_camera()
local x,y=camera:get_position()
local w,h=sol.video.get_quest_size()
fractalRender:draw_region(x,y,w,h,dst)
end
Here is a screenshot of a render using the default exponent (2) :
2. the Sierpinsky Triangle--[[
The Sierpinsky triangle.
On of the well known fractals, often used as a demonstration for calculators programming
When rendered, it shows a Triforce-like shape, with each triangle being a raduction of the base figure.
like this
/\
/--\
/\ /\
/__\/__\
/\ /\
/__\ /__\
/\ /\ /\ /\
/__\/__\/__\/__\
For more information, feel free to check on the Wiki or any math article
How to use :
1. create a map of the size of your choice
2. copy/paste this whole code in the map script.
3. setup the config variables with your own parameters
4. Run the map !
--]]
local map = ...
-- Must be lower or equel to map size to render properly
local grid={
width=200,
height=200
}
local maxIterations=10000
-- the outer triangle summits
local summits={
{0,0},
{grid.width,0},
{grid.width/2,grid.height},
}
local point
-- initial position
local x=grid.width/2
local y=grid.height/2
local iter
local fractalRender= sol.surface.create(grid.width,grid.height)
local pixel=sol.surface.create(1,1)
pixel:fill_color({0,0,0})
local game = map:get_game()
-- Event called at initialization time, as soon as this map becomes is loaded.
function map:on_started()
map:get_hero():set_visible(false)
iter=0
--print("initial point : X="..x..", Y="..y)
end
function map:on_finished()
map:get_hero():set_visible(true)
end
function map:on_update()
if iter <maxIterations then
--these three lines are all the calculation. Yes, this fractal is very easy to setup.
--Note, they directly come from internet, so feel free to change to your own.
point=summits[math.random(3)]
x=(x+point[1])/2
y=(y+point[2])/2
--[[
-- my calculator's example script from the instruction book. Kept here for historical reasons, feel free to remove.
random=math.random(999)
--local random
--print("random number : "..random)
if random<=333 then
x=x/2
y=y/2
elseif random >333 and random <=666 then
x=(x+(base_size/2))/2
y=(y+base_size)/2
else
x=(x+base_size)/2
y=y/2
end
--]]
--print("new point on cycle "..count..": X="..x..", Y="..y)
pixel:draw(fractalRender, x,grid.height-y)
iter=iter+1
end
end
function map:on_draw(dst)
fractalRender:draw(dst)
end
Screenshot of the render :

That's all for now! More to come later.... maybe !
Feel free to test, but be warned : it can, and will, take some time to get a full render, depending of your computer power and the parameters you chose.
if you have suggestions for improvements, feel free to.
Enjoy !
Edit (2017/09/21) : Added screenshots of the renders.