Code: Select all
/' -- peaceful stars - 2025 March 24 - by dafhi
inspired by a video background
my compiler option
-gen gcc -arch native -Wc -Ofast,-mfpmath=sse,-funroll-loops
updates:
simplified imvars
aadot rather than metaball2d
background stars more visible over time via iris diameter
'/
'#include "aadot z.bas"
/' - variably sharp anti-aliased dot - 2024 Dec 29 - by dafhi
' usage
screenres 800,600, 32
aa_dot.render_target 0
aa_dot.draw x,y,rgb,rad,edge
'/
'#include "imvars.bas"
' -- imvars.bas - 2025 March 23 - by dafhi
function min( a as double, b as double ) as double
return iif( a < b, a, b)
end function
function max( a as double, b as double ) as double
return iif( a > b, a, b)
end function
function clamp( in As double, hi As double = 1, lo As double = 0) As double
return min( max(in, lo), hi ) '' 2023 June 12
End Function
sub _gfx_release( byref im as any ptr )
if imageinfo(im) = 0 then imagedestroy im
im = 0
end sub
type imvars
as long w,h, bypp, pitch,rate
as any ptr pixels, im
as string driver_name
as long wm, hm, pitchBy ' custom
as single r
end type
sub fill_imvars( byref i as imvars, im as any ptr = 0)
if im = 0 then
_gfx_release i.im
ScreenInfo i.w, i.h, , i.bypp, i.pitch, i.rate, i.driver_name
i.pixels = screenptr
else
_gfx_release i.im
ImageInfo im, i.w, i.h, i.bypp, i.pitch, i.pixels
i.im = im
end if
i.r = sqr(i.w^2 + i.h^2) / 2
i.wm = i.w - 1
i.hm = i.h - 1
i.pitchBy = i.pitch \ i.bypp
end sub
function triwave( i as single ) as single
return abs( i - int(i) - .5 ) - .25 ' by Stonemonkey
end function
function _cchsv(h as single, s as single, v as single) as ubyte ' 2024 July 24
var wave_hgt = s * v
return 255.499 * (wave_hgt * (clamp(triwave(h)*6+.5)-1) + v)
end function
function hsv( h as single=0, s as single=1, v as single=1, a as ubyte = 255 ) as ulong ' 2024 May 21
return rgba( _
_cchsv( h + 0/3, s,v ), _
_cchsv( h + 2/3, s,v ), _
_cchsv( h + 1/3, s,v ), a )
end function
' ------------ imvars.bas
' ----- support
'
function sqr_safe( d as double ) as double
return sgn(d) * sqr( abs(d))
end function
type t_draw_area field = 2 ' 2 byte elems
dim as short x0, y0
dim as short x1, y1
declare operator cast as string
end type
operator t_draw_area.cast as string
return str(x0)+" "+str(y0)+" "+str(x1)+" "+str(y1)
end operator
#Macro Alpha256(ret,back, fore, a256) '2017 Mar 26
ret=((_
(fore And &Hff00ff) * a256 + _
(back And &Hff00ff) * (256-a256) + &H800080) And &Hff00ff00 Or (_
(fore And &H00ff00) * a256 + _
(back And &H00ff00) * (256-a256) + &H008000) And &H00ff0000) Shr 8
#EndMacro
'
' ------------ support
namespace aa_dot
dim as imvars _im
'' 1 of 2 main subs. other is draw()
''
sub render_target( im as any ptr = 0 )
fill_imvars _im, im
end sub
dim as long scan_x0, scan_x1, final_a
dim as single xm5, ym5, xp5, rp5_sq, invert, alpha_sa, edge_iRSq
dim as single dySq, dx, dy, rSq
dim as t_draw_area rc
sub _cliprect( byref rc as t_draw_area, x0 as single, y0 as single, x1 as single, y1 as single )
rc.x0 = max( 0, int( x0+.0 )) '' +.5 used previously
rc.y0 = max( 0, int( y0+.0 ))
rc.x1 = min( _im.wm, int( x1+.0 ))
rc.y1 = min( _im.hm, int( y1+.0 ))
end sub
sub _precalcs( x as single, y as single, c as ulong, r as single, edge as single )
_cliprect rc, x - r, y - r, x + r, y + r
alpha_sa = min(1, edge*r) * 256.499 * (c shr 24) / 255
rSq = r^2
edge_irSq = edge * alpha_sa / rSq
xm5 = x - .5 : xp5 = x + .5 : ym5 = y - .5 : rp5_sq = (r + .5)^2
end sub
sub _dy_and_scanline_ends( y as single, iy as long, rad as single )
dy = iy-ym5
dx = sqr_safe( rp5_sq - dy^2 )
scan_x0 = max( int(xp5 - dx), rc.x0 ) ' scan segment hugs circle
scan_x1 = min( int(xm5 + dx), rc.x1 )
dySq = dy * dy
end sub
sub _draw( x as single = 0, y as single = 0, c as ulong = -1, rad as single = 5, edge as single = 1 )
for iy as long = rc.y0 to rc.y1
_dy_and_scanline_ends y, iy, rad
var pixel = cast( ulong ptr, _im.pixels + iy * _im.pitch ) '' pitch = bytes per scanline
for ix as long = scan_x0 to scan_x1
dx = ix - xm5
invert = rSq - (dx*dx + dySq)
final_a = min( alpha_sa, edge_irSq * max(0,invert) )
alpha256( pixel[ix], pixel[ix], c, final_a )
next
next
end sub
sub draw( x as single = 0, y as single = 0, c as ulong = -1, rad as single = 5, edge as single = 1 )
_precalcs x, y, c, rad, edge
_draw x,y,c,rad,edge
end sub
end namespace ' ---- aadot
'#include "defocus_dot.bas"
namespace defocus_dot /' -- 2024 Dec 27 - by dafhi '/
dim as single iris_diam = .09 '' i recommend values close to 1.0 .. (can set elsewhere)
dim as single focus_z = 1.5
dim as single _m, _a
function new_alpha( rad as single, z as single ) as single
var r_expan = rad + iris_diam * abs(z - focus_z)
_m = r_expan / rad
_a = rad^2 / r_expan^2
return _a
End function
function rad_mul( alpha_thresh as single = 1 / 5 ) as single
'' alpha below threshold -> reduced radius (faster draw)
return iif( _a < alpha_thresh, _m * _a / alpha_thresh, _m )
end function
end namespace
'
' --------- defocus_dot
#include "fbgfx.bi" '' for alpha
using FB
type v3
as single x, y, z
End Type
type t_star
as v3 pos
as single rad, sharpness = 1.75 + rnd * 1.5
as ulong color
end type
namespace demo
const w = 1024, wh = w/2
const h = 768, hh = h/2
var seconds = 100
var report_next = 1.5
const u_stars = 11999
dim as t_star star(u_stars)
dim as single general_scale_2d
sub _initialize_star_common( t as t_star )
t.pos.x = general_scale_2d*(rnd-.5) * 2.5
t.pos.y = general_scale_2d*(rnd-.5) * 2.5
t.color = hsv( rnd, rnd^1, 1 )
t.rad = general_scale_2d * .08 * (.3 + rnd)
end sub
const rand_depth = 16
sub _dots_z_reset( dt as double )
for i as long = 0 to u_stars
if star(i).pos.z <= .03 then
star(i).pos.z += (defocus_dot.focus_z) * (rand_depth+rnd)
_initialize_star_common star(i)
else
star(i).pos.z -= dt * 0.07
endif
next
end sub
dim as double t0, t, tp, dt, dt2 '' fps average helper dt2
dim as double info_t1
dim e as EVENT
sub init
screenres w,h,32,, fb.gfx_alpha_primitives
aa_dot.render_target 0
defocus_dot.focus_z = 1
general_scale_2d = (wh+hh)*.07
for i as long = 0 to u_stars
star(i).pos.z = (0 + rnd * rand_depth)
_initialize_star_common star(i)
next
_dots_z_reset 0
t0 = Timer : info_t1 = t0 + 1.5
end sub
sub _draw_star( t as t_star )
var z_m = t.pos.z
if z_m > .04 then
var a = defocus_dot.new_alpha( t.rad, z_m )
var r = t.rad * defocus_dot.rad_mul / z_m
var z_s = general_scale_2d / z_m
var x = t.pos.x * z_s + wh
var y = t.pos.y * z_s + hh
aa_dot.draw x,y, ((255.5*a)shl 24) or (t.color and &HFFFFFF),r, t.sharpness
endif
end sub
sub DrawStars
for i as long = 0 to u_stars
_draw_star star(i): next
end sub
end namespace ' --------- demo
function round(in as double, places as ubyte = 2) as string
dim as integer mul = 10 ^ places
return str(csng( int(in * mul + .5) / mul) )
End Function
randomize
using demo
init
do
tp = t
t = timer - t0
dt = t - tp
var fade_in = csng(1.9)*t
defocus_dot.iris_diam = (fade_in + 10) / (fade_in + 1) '' approaches 1.0 as t increases.
screenlock
cls
DrawStars
screenunlock
if t > report_next then
var m = str(report_next)
windowtitle "FPS: " + round( 2 / (dt + dt2) ) + " TIme left: " + round( seconds - t )
dt2 = dt
report_next += 1
endif
if inkey <> "" then end
_dots_z_reset dt
sleep 1
loop while t < seconds
sleep