I figured it would be a cunning plan to put a little test program together that uses this approach. So here goes.
The zip file contains a compiled executable and the source.
' ------------------------------------------------------------------------------
' Blobs - By Xalthorn
'
' An experiment with meta balls (I think that's what they are called).
' Basically, we loop through the screen, work out how far each pixel is from
' each of the balls (well, the centre of them) and colour the pixel according
' to the sum of these distances.
'
' ------------------------------------------------------------------------------
' ------------------------------------------------------------------------------
' Include any libraries and external code files that we want to use
' ------------------------------------------------------------------------------
#Include Once "tinyptc_ext.bi"
#include once "windows.bi"
' Get ourselves set up for good coding practice
OPTION STATIC
OPTION EXPLICIT
' ------------------------------------------------------------------------------
' Set up any variables that will never change (they will stay constant)
' ------------------------------------------------------------------------------
' Our main display resolution
CONST XRES=640
CONST YRES=480
CONST PI AS DOUBLE = 3.1415926535897932
CONST PIR AS DOUBLE = PI/180
' ------------------------------------------------------------------------------
' We need to set up a bunch of variables that can be used anywhere in the code
' ------------------------------------------------------------------------------
DIM SHARED AS UINTEGER DRAWBUFFER (XRES*YRES)
DIM SHARED AS UINTEGER GLOBALROT
DIM SHARED AS DOUBLE SINES(720), COSINES(720)
DIM SHARED AS DOUBLE OLDTIMER
' ------------------------------------------------------------------------------
' Now to declare which subroutines we are going to write
' ------------------------------------------------------------------------------
DECLARE FUNCTION InvSqrt(byval X AS SINGLE) AS SINGLE
DECLARE SUB BLOBS()
DECLARE SUB INIT() :' Set up our variables and arrays
INIT()
' ------------------------------------------------------------------------------
' Now we're ready to get going, let's try and open a screen. If it fails, there
' is no point in continuing
' ------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
'1st param. = Enable messagebox (dialog)
'2nd param. = Messagebox text
'3rd param. = Start in fullscreen or windowed mode if 1st param. is zero
'4th param. = Window normal border (0) or borderless (1)
ptc_allowclose(1) 'enable tinyptc_ext to close on Escape Key press
ptc_setdialog(1,"Fullscreen Mode?",1,1)
'-------------------------------------------------------------------------------
IF ( PTC_OPEN ( "Blobby", XRES, YRES ) = 0 ) THEN
END -1
END IF
' ------------------------------------------------------------------------------
' We have our variables and arrays set up, we have an open screen display, so
' we can get going.
' ------------------------------------------------------------------------------
DO
OLDTIMER=TIMER
GLOBALROT=(GLOBALROT+1) MOD 360
BLOBS()
PTC_UPDATE@DRAWBUFFER(0)
DO
LOOP UNTIL TIMER>OLDTIMER+0.01
' Keep looping forever (or until the main escape handler catches us)
LOOP UNTIL 1=2
' We're all done now, we pressed escape, time to finish things up
END
PTC_CLOSE()
SUB BLOBS()
DIM AS INTEGER X,Y,L,XX,YY,COL,YOFF,FULLPURPLE
DIM AS SINGLE BX1,BX2,BX3,BY1,BY2,BY3,BR1,BR2,BR3
DIM AS SINGLE SUM
DIM AS UINTEGER PTR DP
' Once we get past a certain threshold, we'll stay purple
' so let's prepare a colour value for that
FULLPURPLE=RGB(255,0,255)
' Now we'll set the position and radius of the three
' blobs according to the global rotation variable
BX1=SINES(GLOBALROT+60)*60+320
BX2=SINES(GLOBALROT+120)*90+320
BX3=SINES(GLOBALROT+180)*120+320
BY1=COSINES(GLOBALROT+60)*(SINES(GLOBALROT)*120)+280
BY2=COSINES(GLOBALROT+120)*(SINES(GLOBALROT)*180)+280
BY3=COSINES(GLOBALROT+180)*(SINES(GLOBALROT)*200)+280
BR1=200
BR2=250
BR3=300
' loop through the whole screen, jumping by two. This
' speeds the thing up without any real visible loss of
' detail. To be perfect, you'd step one pixel at a time
' and only draw the single pixel in the drawing bit
FOR Y=0 TO YRES-1 step 2
YOFF=Y*XRES
FOR X=0 TO XRES-1 step 2
DP=@DRAWBUFFER(X+YOFF)
XX=X-BX1
YY=Y-BY1
' This is the original raw calculation which we replaced with the
' InvSqrt function. As the InvSqrt returns 1/SQR, we multiply the
' result by the radius rather than dividing it.
' SUM=BR1/SQR(XX*XX+YY*YY)
SUM=BR1*InvSqrt(XX*XX+YY*YY)
XX=X-BX2
YY=Y-BY2
' SUM+=BR2/SQR(XX*XX+YY*YY)
SUM+=BR2*InvSqrt(XX*XX+YY*YY)
XX=X-BX3
YY=Y-BY3
' SUM+=BR3/SQR(XX*XX+YY*YY)
SUM+=BR3*InvSqrt(XX*XX+YY*YY)
COL=SUM*40
IF COL>255 THEN
COL-=255
IF COL>255 THEN COL=255
COL=RGB(COL,0,255)
END IF
IF COL<=0 THEN COL=FULLPURPLE
' In this version, we're plotting four pixels as
' we're jumping through X and Y by two each time
' Place the colour in the pixel
*DP=COL
' Move right one and plot the next
' pixel
DP+=1
*DP=COL
' Move down one line and left one pixel
' and plot the next pixel
DP+=XRES-1
*DP=COL
' Now move right one and plot again
DP+=1
*DP=COL
NEXT X
NEXT Y
END SUB
' This is the clever function that does a speedy 1/SQR calculation
' Copyright of this function is hard to track down, there are websites
' that are trying to find the source of who came up with the idea and
' the magic number.
'
' Suffice it to say that I didn't work this out, I just (with some
' help from Hellfire) converted it to Freebasic.
'
' It does some freaky stuff and you will get compiler warnings about
' suspicious pointer assignment. Don't worry, it really *IS* doing
' some suspicious pointer stuff
FUNCTION InvSqrt(byval X AS SINGLE) AS SINGLE
' We want X to be positive
X=ABS(X)
' It's important that we're working with integers and singles
' because of the clever stuff it does with parts of a computer
' stored variable. You can surf the 'net for an explanation of
' what it does as I'm certainly not going to try and explain it
DIM AS INTEGER PTR P
DIM AS SINGLE PTR S
DIM AS SINGLE xhalf
DIM AS INTEGER i
xhalf=0.5*X
' We want a pointer to the SINGLE variable X
P=@X
' Now we store the appropriate parts of that SINGLE variable
' into the INTEGER variable i
i=*P
' This is the wonderful magic number bit
i=1597463007-(i SHR 1)
' We want a pointer to the INTEGER i
S=@i
' So we can store the appropriate parts of that INTEGER variable
' into the SINGLE variable X
X=*S
' Another quick calculation
x=x*(1.5-xhalf*x*x)
' and throw the result back
return x
END FUNCTION
' ------------------------------------------------------------------------------
' INIT
'
' This is where we will initialise all of our variables and arrays. It is
' kept at the end of the code to keep the front tidy
' ------------------------------------------------------------------------------
SUB INIT()
DIM AS INTEGER A
FOR A=0 TO 719
SINES(A)=SIN(A*PIR)
COSINES(A)=COS(A*PIR)
NEXT A
END SUB