Code: Select all
'#include "aniwave_2d.bas"
/' -- aniwave_2d -- 2023 April 25 - by dafhi
2d animated wave generator
important functions showcased in demo subs
randomize_layers
show_all
update:
wave_group
param-less layer constructor
'/
#define flo(x) (((x)*2.0-0.5)shr 1) '' replaces int (and faster) - http://www.freebasic.net/forum/viewtopic.php?p=118633
#undef int
#define int as integer
#define sng as single
#define dbl as double
#define min( a, b) iif( (a)<(b), (a), (b) )
#define max( a, b) iif( (a)>(b), (a), (b) )
function clamp( in sng, hi sng = 1, lo sng = 0) sng
return min( max(in, lo), hi ) '' Mar 8
End Function
const tau = 8 * atn(1)
'
' ------------ boilerplate
function tr_wave( i sng ) sng
return abs(i - flo(i) - .5) - .25 '' by Stonemonkey
End function
function sw_wave( i sng ) sng
return i - flo(i) - .5
End function
namespace aniwave_2d '' 2023 April 23 - by dafhi
dim sng dt
sub grab_delta_time( _dt sng )
dt = _dt
end sub
type _osc_endpoint
declare sub calc
sng rad = .15 + rnd * 1.33
sng ia = .5 * (.3 + rnd)
dbl a = rnd * tau
sng x
sng _result
End Type
sub _osc_endpoint.calc
_result = rad * sin(a) + x
end sub
type _anim_frame_vars
declare constructor
declare sub advance
as _osc_endpoint e0, e1
end type
constructor _anim_frame_vars
const c_b = 1.5, c_a = .3
e0.x = -c_b * ( c_a + rnd )
e1.x = c_b * ( c_a + rnd )
if rnd < .5 then swap e0, e1
end constructor
sub _anim_frame_vars.advance
e0.a += e0.ia * dt
e1.a += e1.ia * dt
end sub
type _clip_vars
sng y_offs = 1.2 * (rnd - .5) '' > 1.3 = frequent high offset
const clip_a = .05, clip_b = 2.5
sng hi = clip_a + rnd * clip_b
sng lo = -clip_a - rnd * clip_b
declare constructor
end type
constructor _clip_vars
hi += y_offs
lo += y_offs
end constructor
type _layer_base
declare sub frame_precalcs( () sng )
as _anim_frame_vars anim
as _clip_vars clip
sng amp
sng _slen
sng x_zoom
sng x, dx
end type
sub _layer_base.frame_precalcs( out() sng )
anim.e0.calc
anim.e1.calc
_slen = anim.e1._result - anim.e0._result
dx = _slen / ( ( ubound(out) + 0) * x_zoom)
end sub
const triangle = 0
const sawtooth = 1
type layer extends _layer_base
declare constructor
declare constructor(x_zoom sng = 1, tri_to_saw_ratio sng = .75 )
declare sub addto( () sng )
declare sub rand( x_zoom sng = 1, tri_to_saw_ratio sng = .75 )
declare sub _set_function_type( int )
as function(sng) sng f
end type
constructor layer
rand
end constructor
constructor layer( xzoom sng, tri_to_saw_ratio sng )
rand xzoom, tri_to_saw_ratio
end constructor
sub layer.rand( xzoom sng, tri_to_saw_ratio sng )
'' cast(myRand, this) = myRand() - gracias fxm
cast( _layer_base, this).constructor()
x_zoom = xzoom
_set_function_type rnd > tri_to_saw_ratio
end sub
sub layer._set_function_type( j int )
if j then
f = @sw_wave '' muchas gracias fxm
amp = 3 * (.15 + rnd)
else
f = @tr_wave
amp = 8 * (.15 + rnd)
endif
end sub
sub layer.addto( out() sng )
frame_precalcs out()
x = ( anim.e0._result ) / x_zoom
for j int = 0 to ubound( out )
var f = f(x) * amp + clip.y_offs
out(j) += clamp( f, clip.hi, clip.lo )
x += dx
next
anim.advance
end sub
type wave_group
declare constructor( c int = -1, xzoom sng = 0, tri sng = -1)
declare sub init( c int = -1, xzoom sng = 0, tri sng = -1 )
declare property val( sng ) sng
declare sub calc( w int = 50 )
as layer L(any)
dim sng result(any)
dim sng _tri = .5
dim sng _xzoom = .5
dim int _c = 3
end type
constructor wave_group( c int, xzoom sng, tri_to_saw_ratio sng )
init c, xzoom, tri_to_saw_ratio
end constructor
sub wave_group.init( c int, xzoom sng, tri_to_saw_ratio sng )
if c < 1 then c = _c
redim L(c-1)
if xzoom = 0 then xzoom = _xzoom
if tri_to_saw_ratio = -1 then tri_to_saw_ratio = _tri
for i int = 0 to c-1
L(i).rand xzoom, tri_to_saw_ratio
next
_tri = tri_to_saw_ratio
_xzoom = xzoom
_c = max(c, 1)
end sub
property wave_group.val( x sng ) sng
static sng sum: sum = 0 '' i think static stays 1 instance
for i int = 0 to ubound(L)
with L(i)
var x0 = .anim.e0.rad * sin(.anim.e0.a)
var x1 = .anim.e1.rad * sin(.anim.e1.a)
sum += (x1 - x0) / .x_zoom
end with
next
return sum * x
end property
sub wave_group.calc( w int )
var additive_downscale = 1 / ( ubound(L)+1 ) ^ .7
redim result(w-1)
for i int = 0 to ubound( L )
L(i).addto result()
next
for i int = 0 to ubound( result )
result(i) *= additive_downscale
next
end sub
end namespace ' -- aniwave_2d
' -- demo support
'
sub demo_rect( ary_out() sng, _
x int = 1, _
y int = 1, _
w int = 150, h int = 50, _
col as ulong = rgb(99,99,99) )
var hh = y + h / 2
for i int = x to x + w-1
var y = h * clamp( ary_out(i-x), .5, -.5 )
pset ( i, hh - y ), col
next
end sub
' -- meat and potatoes demo
'
sub show_all( wg as aniwave_2d.wave_group, rcw int, rch int )
dim sng sum( rcw - 1 )
var sum_yscale = 1 / (ubound(wg.L)+1) ^ .7
var y = 15
var x = 20
for i int = 0 to ubound( wg.L )
dim sng result( rcw - 1 )
wg.L(i).addto result() '' meat-and-potatoes
demo_rect result(), x, y, rcw, rch
for i int = 0 to ubound( sum )
sum(i) += result(i) * sum_yscale
next
y += rch + 3
next
y += rch * 1.5
demo_rect sum(), x, y, rcw, rch, rgb(255,255,255)
end sub
sub randomize_layers( wg as aniwave_2d.wave_group )
var tri_to_saw_ratio = .5
for i int = 0 to ubound( wg.L )
var x_zoom = .5 * (.2 + rnd)
wg.L(i).rand x_zoom, tri_to_saw_ratio '' meat-and-potatoes
next
end sub
' ---------------- Main
'
var wid = 800
var hgt = 600
screenres wid,hgt,32
var seconds_max = 290
var time_between_new = 3.5
var rcw = 600
var rch = 30
randomize
var cLayers = 2
var xzoom = 6
var tri_to_saw_ratio = .5
dim as aniwave_2d.wave_group _
wg = type( cLayers, xzoom, tri_to_saw_ratio )
var curr_run_time = 0f
var tp = timer
var report_next = tp + 2.5
var new_waves_trig = tp
while curr_run_time < seconds_max
screenlock
cls
var t = timer
dim sng dt = t - tp
tp = t
curr_run_time += dt
if t > new_waves_trig then
randomize_layers wg
new_waves_trig += time_between_new
endif
aniwave_2d.grab_delta_time dt
show_all wg, rcw, rch
static sng dt2, dt_sum
if t > report_next then
dt_sum = dt + dt2
var m = str(report_next)
windowtitle "FPS: " + str( 2 / dt_sum ) '' deltatime avg
report_next += 1
elseif curr_run_time < 1.75 then
locate 2,2
? "demo runs"; seconds_max; " seconds"
endif
screenunlock
dt2 = dt
var k = inkey
select case lcase(k)
case ""
case "a" to "z", " "
new_waves_trig = t
case else
end
end select
sleep 1
wend