Code: Select all
/' -- unique metaballs - 2024 Jan 3 - by dafhi
no alpha blending here .. just adds, where r,g,b can be negative.
- some specs -
MX Linux - HP Spectre 1165g7
215-ish fps
combined gcc options from UEZ / DeltaRho comment
-arch native -Wc -Ofast,-mfpmath=sse,-funroll-loops
update
tweaked visibility / performance
'/
'#include "workspace.bas"
' ----- workspace.bas - 2023 Feb 27 - by dafhi
'
' #include "boilerplate.bas"
' -- boilerplate.bas - 2023 Feb 24 - by dafhi
'' replaces int()
#define flo(x) (((x)*2.0-0.5)shr 1) '' http://www.freebasic.net/forum/viewtopic.php?p=118633
#define ceil(x) (-((-(x)*2.0-0.5)shr 1))
#undef int
#define int as Integer
#define sng as single
#define dbl as double
#define decl declare
#define oper operator
#define prop property
#define min( a, b) iif( (a)<(b), (a), (b) )
#define max( a, b) iif( (a)>(b), (a), (b) )
function bclamp( i sng ) as ubyte '' Feb 23
return min( max( i, 0), 255 )
End Function
function int2float( i as ulong) as single
return i / ((culngint(1) shl 32) + 128)
end function
const tau = 8 * atn(1)
'
' ------------------- boilerplate
' - workspace.bas continued ..
namespace gfx_workspace '' 2023 Feb 27 - by dafhi
function c( _c as ubyte) int
return _c
end function
type pixel
sng x,y,z
decl oper cast as ulong
decl sub in_rgb( as ulong, sng = 1)
decl sub subm_rgb( as ulong, sng = 1) '' Feb 19
decl sub add( as pixel, sng = 1) '' Feb 19
end type
sub pixel.add( in as pixel, alpha sng) '' Feb 19
x += alpha * in.x
y += alpha * in.y
z += alpha * in.z
end sub
sub pixel.subm_rgb( col as ulong, alpha sng) '' Feb 19 (old name add_rgb)
x += alpha * ( c( col shr 16 )-127.5 )
y += alpha * ( c( col shr 8 )-127.5 )
z += alpha * ( c( col shr 0 )-127.5 )
end sub
sub pixel.in_rgb( col as ulong, alpha sng)
x = alpha * c( col shr 16 )
y = alpha * c( col shr 8 )
z = alpha * c( col shr 0 )
end sub
oper pixel.cast as ulong
return rgb( bclamp(x), bclamp(y), bclamp(z) )
end oper
dim as pixel buf(any, any)
dim int wm
dim int hm
sub setup( w as short, h as short )
const dimension_thresh = 11000
if w > dimension_thresh orelse h > dimension_thresh then exit sub
if w < 1 orelse h < 1 then exit sub
wm = w - 1
hm = h - 1
redim buf(wm, hm)
end sub
sub fill( col as ulong = rgb(128,128,128), stren sng = 0.5)
dim as pixel iwa: iwa.in_rgb col, stren
for p as pixel ptr = @buf(0,0) to @buf(wm,hm)
*p = iwa
next
end sub
end namespace ' ------ workspace
namespace metaball2D ' 2024 Jan 3 - by dafhi
type int_rect
as long x0, x1 = -1
as long y0, y1 = -1
declare operator cast as string
end type
operator int_rect.cast as string
return "rect (" + str(x0) + "," + str(y0) + _
") - " + str(x1) + "," + str(y1) + ")"
end operator
dim as int_rect _clipped '' namespace globals
dim sng _slope_by_rad', _clipSQ '' April 11
dim sng _metaball_alpha_scalar '' March 21
dim sng dx, dy, dx0', dSQ, dSQ_alpha_clip
sub _cliprect_calc( x sng, y sng, rad_multed sng ) '' Feb 24
_clipped.x0 = max( flo( x - rad_multed ), 0 )
_clipped.x1 = min( flo( x + rad_multed ), gfx_workspace.wm )
_clipped.y0 = max( flo( y - rad_multed ), 0 )
_clipped.y1 = min( flo( y + rad_multed ), gfx_workspace.hm )
end sub
dim as gfx_workspace.pixel pel '' March 24
sub _scan( col as ulong, plot_y int )
static sng alpha, dSQ, dySQ
dySQ = dy * dy
dx = dx0
for plot_x int = _clipped.x0 to _clipped.x1
dSQ = dx*dx+dySQ
var alpha = _metaball_alpha_scalar / (dSQ^3 + .00011) '' small = sharp
gfx_workspace.buf(plot_x, plot_y).add pel, alpha '' Feb 19
dx += _slope_by_rad
next
dy += _slope_by_rad
end sub
sub draw( x sng, y sng, col as ulong = -1, rad sng = 10)
var draw_dist_from_center = .6 '' smaller: rect more visible
_metaball_alpha_scalar = -min( rad, .0002 ) '' precalc where true = -1
_cliprect_calc x, y, rad * draw_dist_from_center * .91
_slope_by_rad = 1 / max(rad, .001)
' dSQ_alpha_clip = .28
dx0 = (_clipped.x0 - x) * _slope_by_rad
dy = (_clipped.y0 - y) * _slope_by_rad
pel = type(0,0,0)
pel.subm_rgb col
for plot_y int = _clipped.y0 to _clipped.y1
_scan col, plot_y
next
end sub
end namespace ' ---- metaball2D
namespace myhash '' 2023 Feb 19
type base_literal as ulong '' size: ubyte to ulongint (ubyte during development)
const lenx8 = len(base_literal) * 8
const lenByv = lenx8 \ 2 + 1'' integer divide
const as ulongint mulC = &b1000000001000000000100000000100000001000000100000100001000100101
const as ulongint xorA = &b0101010101010101010101010101010101010101010101010101010101010101
dim as base_literal a, b, c
const _rotbits_count = log(lenx8) / log(2) '' inspired by PCG
const as ubyte _rota_mask = 2 ^ (_rotbits_count-2) - 1
sub reset(aa as base_literal = 0, bb as base_literal = 0)
a = aa
b = bb
c = 0
End Sub
function prng( seed_a as base_literal = 0 ) as single
c xor= seed_a xor xora + a
b xor= c + c shl (c and _rota_mask)
a xor= b shr 1
a *= mulC
a xor= a shr lenbyv
return int2float(a)
end function
end namespace
'
' --------- workspace.bas
sub show
dim int w, h, bpp, bypp, pitch, rate
dim as string driver_name
ScreenInfo w,h, bpp, bypp, pitch, rate, driver_name
var pixels = screenptr
for y int = 0 to h - 1
dim as ulong ptr p = pixels + y * pitch
for x int = 0 to w - 1
p[x] = gfx_workspace.buf(x,y)
next
next
end sub
const w = 800
const h = 600
dim shared sng diagonal
#undef rnd
#define rnd myhash.prng
type dotvars
sng rot_cenx = rnd * w
sng rot_ceny = rnd * h
sng rad = (.2 * (.1 + rnd * rnd)) * diagonal
as ulong col = rgb(rnd*255.499, rnd*255.499, rnd*255.499)
sng rad_offset = diagonal * 0.07 * (.4 + rnd)
sng angle = rnd * tau
sng iangle
end type
dim shared as dotvars dot(any)
sub ini
gfx_workspace.setup w,h
screenres w, h, 32
diagonal = sqr(w*w+h*h)
var seed = 39
myhash.reset seed
redim dot(139)
for i int = 0 to ubound(dot)
var direction = 2 * flo(rnd + .5) - 1
dot(i).iangle = 0.7 * (.03 + rnd*rnd) * direction
next
end sub
sub animate( seconds as ubyte = 80 )
dim dbl seconds_remain = seconds
dim dbl dt(1)
dim dbl report_next = seconds_remain - 1
var tp = timer
while seconds_remain > 0
var strength = 1
gfx_workspace.fill rgb(128,128,128), strength
for i int = 0 to ubound(dot)
with dot(i)
metaball2d.draw _
.rot_cenx + .rad_offset * cos(.angle),_
.rot_ceny + .rad_offset * sin(.angle), _
.col, .rad
.angle += .iangle * dt(0)
end with
next
show
screenlock
screenunlock
sleep 1
if inkey<>"" then exit sub
var t = timer: dt(1) = dt(0): dt(0) = t - tp
seconds_remain -= dt(0): tp = t
if seconds_remain < report_next then
windowtitle "FPS: " + str( 2 / ( dt(0)+dt(1) ) )
report_next -= 1
endif
wend
end sub
ini
animate
sleep