Dark Bit Factory & Gravity
PROGRAMMING => General coding questions => Topic started by: Xalthorn on October 29, 2008
-
This must have been done countless times, but I'm blowed if I can find out how.
Basically, I'm looking to optimise the following calculation.
A = R / SQR(XX*XX + YY*YY)
If anyone can point me in the direction of a layman's article or simply explain how this is done, that would be perfect :)
-
Can you take any assumptions on XX and/or YY ?
Is the input/output integer or floating-point?
What precision is necessary?
What's expensive here is the division and the square root.
If you're working in floating point, each number is stored in exponential form.
Taking the square root is now very easy, just divide the exponent by 2.
Reciprocal is just as cheap, just negate the exponent.
Notice that you have to renormalize the mantissa when changing the exponent.
edit: wasn't quite right because f= m*2^e and not m^e, so modifying the exponent is a little bit more work.
-
Can you take any assumptions on XX and/or YY ?
Is the input/output integer or floating-point?
What precision is necessary?
What's expensive here is the division and the suqare root.
If you're working in floating point, each number is stored as:
sign * mantissa * 2^exponent
Taking the square root in this exponential form is very easy, just divide the exponent by 2:
sign * mantissa * 2^(exponent/2)
Reciprocal is just as cheap:
sign * mantissa * 2^(-exponent)
So you just have to extract the exponent (integer) from your floating-point value "x" (as definied in ieee (http://en.wikipedia.org/wiki/Ieee_float)), shift and negate it, put it back into your float and the result is a pretty good approximation of 1/sqrt(x).
Notice that you have to renormalize the mantissa when changing the exponent.
I'm using floating points.
After I posted this, I found the InvSqrt() function that's hugely talked about and that appears to be following the same logic that you're talking about.
However, can I make it work? nope :(
I'm currently doing this is Freebasic, and I think I'm tying myself in knots.
FUNCTION InvSqrt(byval X AS DOUBLE)
' I think X needs to be a positive number
X=ABS(X)
DIM AS DOUBLE xhalf
DIM AS INTEGER i
xhalf=0.5*X
i=X
' assuming the following number is hex, I converted it to decimal in a calculator...
' i=0x5f3759df-(i SHR 1)
i=1597463007-(i SHR 1)
x=i
x=x*(1.5-xhalf*x*x)
return x
END FUNCTION
-
i=X
This does a cast (skip fractional digits of the double).
What you want instead is loading the whole "bit-set" of the double into an integer (but since integers can hold 32bits only you should use "single" as input!), so you can extract the exponent/mantissa parts.
To get it right you have to get a pointer (of type integer) to your single and read (an integer) from the pointer-address.
Do the same (single-pointer to the integer) to store the modified value back into the single.
-
i=X
This does a cast (skip fractional digits of the double).
What you want instead is loading the whole "bit-set" of the double into an integer (but since integers can hold 32bits only you should use "single" as input!), so you can extract the exponent/mantissa parts.
To get it right you have to get a pointer (of type integer) to your single and read (an integer) from the pointer-address.
Do the same (single-pointer to the integer) to store the modified value back into the single.
Hmm,
I'm missing something. I changed the function to:
FUNCTION InvSqrt(byval X AS SINGLE)
X=ABS(X)
DIM AS INTEGER PTR P
DIM AS SINGLE PTR S
DIM AS SINGLE xhalf
DIM AS INTEGER i
xhalf=0.5*X
P=@X
i=*P
' i=0x5f3759df-(i SHR 1)
i=1597463007-(i SHR 1)
S=@i
X=*S
x=x*(1.5-xhalf*x*x)
return x
END FUNCTION
And calling the function as:
SUM=BR1*InvSqrt(XX*XX+YY*YY)
rather than the working version of
SUM=BR1/SQR(XX*XX+YY*YY)
The variables are defined as:
DIM AS INTEGER XX,YY
DIM AS SINGLE BR1, SUM
-
What's the return-type "InvSqrt" ?
-
What's the return-type "InvSqrt" ?
I'm asssuming it returns the variable as whatever type the variable is defined as.
-
I don't know what your compiler does, but mine (fbc 0.20.0) doesn't even compile:
test.bas(1) error 136: Default types or suffixes are only valid in -lang deprecated
So I specified the return type as single and everything worked fine.
-
I don't know what your compiler does, but mine (fbc 0.20.0) doesn't even compile:
test.bas(1) error 136: Default types or suffixes are only valid in -lang deprecated
So I specified the return type as single and everything worked fine.
weird, mine compiles and runs but it's just not returning values anywhere near to the sqrt version.
I'll have to dig deeper into the variable storage and start pulling things out of memory more precisely I guess.
-
mine compiles and runs but it's just not returning values anywhere near to the sqrt version
FUNCTION InvSqrt(byval X AS SINGLE) AS SINGLE
X=ABS(X)
DIM AS INTEGER PTR P
DIM AS SINGLE PTR S
DIM AS SINGLE xhalf
DIM AS INTEGER i
xhalf=0.5*X
P=@X
i=*P
' i=0x5f3759df-(i SHR 1)
i=1597463007-(i SHR 1)
S=@i
X=*S
x=x*(1.5-xhalf*x*x)
return x
END FUNCTION
x InvSqrt(x) 1.0/sqr(x)
0.0 1.981775e+019 1.#INF
0.5 1.41386 1.41421
1.0 0.99830 1.0
1.5 0.81536 0.81649
2.0 0.70693 0.70710
2.5 0.63137 0.63245
3.0 0.57684 0.57735
3.5 0.53442 0.53452
4.0 0.49915 0.5
4.5 0.47135 0.47140
5.0 0.44714 0.44721
5.5 0.42605 0.42640
6.0 0.40768 0.40824
6.5 0.39160 0.39223
7.0 0.37744 0.37796
7.5 0.36484 0.36514
8.0 0.35346 0.35355
8.5 0.34276 0.34299
9.0 0.33295 0.33333
9.5 0.32395 0.32444
10.0 0.31568 0.31622
???
-
Ooh, in that case I'm being dumb :)
how would I adapt this code...
SUM=BR1/SQR(XX*XX+YY*YY)
To work with InvSqrt? I figured that as 1/SQR is being returned rather than SQR, I would have to flip the calculation. So I did this (which is clearly not working)
SUM=BR1*InvSqrt(XX*XX+YY*YY)
-
Your code should work fine. Maybe the result is just not precise enough.
Depending on the range of your input-values you can either tweak the reference value (0x5f3759df) or perform additional approximation steps (see this (http://www.mceniry.net/papers/Fast%20Inverse%20Square%20Root.pdf) and this (http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf)).
Since XX and YY are integers you might want to consider using tables, too.
-
just to satisfy my curiosity... what is the problem you need to solve all this for?
-
just to satisfy my curiosity... what is the problem you need to solve all this for?
In Shocky's birthday card, I had some meta balls (I think that's what they're called) where they move around and merge into each other. The calculation is done three times per pixel and as a result it slows the thing down. I was just looking for a way to optimise things.
I know the optimisation that hellfire is talking about should work, I just can't get it to work.
I think I need to tear that routine out as a stand alone program and post the source, that would make it a lot easier for people to see where I'm missing the obvious :D
-
The code Hellfire posted above works fine for me. FB version 18.3
-
Yup, my dumbness knows no bounds.
My *theory* was okay, and my function was *almost* the same as hellfires, with the teeny little difference that the function was declared as:
FUNCTION InvSqrt(byval X AS SINGLE)
When I changed it to
FUNCTION InvSqrt(byval X AS SINGLE) AS SINGLE
I got a Type mismatch compilation error, so I removed it and kept hammering away at the problem. Major big nooby mistake ;)
It just occurred that I should check my initial function declaration, which oddly enough reads
FUNCTION InvSqrt(byval X AS SINGLE)
I then realised that of course, I had to change them both to show the return type.
Ho hum
It works now, still fairly slow, but better than before.
Thanks for the help and sorry for being so dense
hehe
-
I've seen this great code snippet before in C. It's great to see it working in FB, plus with an explanation I can understand.
Thanks guys.
:)
-
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
-
I would question whether you need sqrt at all. If you remove the sqrt and just use the squares and change the scale factor I suspect the fx will look almost identical. You're getting quite a cheap divide though (the mul by 1/sqrt).
Jim
-
I would question whether you need sqrt at all. If you remove the sqrt and just use the squares and change the scale factor I suspect the fx will look almost identical. You're getting quite a cheap divide though (the mul by 1/sqrt).
Jim
That's a thought.
I changed the calculations to
SUM=BR1/(XX*XX+YY*YY)
And increased the radius values to 16000, 20000, and 24000 respectively and it kinda works, but not as pretty. I guess I would just need to find nicer radius values. It seems to be a much more direct or linear scale than before.
It's damn fast though...
-
That's right, one algorithm is linear, the other is a quadratic curve. Small parts of quadratic curves look linear-ish, which is why you can sometimes get away with it.
Have you tried some small table look-ups?
Jim
-
Use three (relatively big) integer-tables to store BRx/sqrt(x*x+y*y) and you're done with 3 adds.
The position of each "ball" on the screen (red) is translated into an offset inside the table (blue).
Use another table (palette) to look up the final color.
With vsync disabled you get comfortable 1000 frames per second ;D
-
Using this kind of thing for a metabobs routine is heavy though... I know that the same result can be got much more cheaply (but maybe not as elegantly) by using a simple additive gradient bob routine (see attachment).
These lights are actually metaballs..
Megafast code with loads of bugs..
OPTION STATIC
OPTION EXPLICIT
#INCLUDE "TINYPTC_EXT.BI"
#INCLUDE "WINDOWS.BI"
CONST XRES = 640
CONST YRES = 480
DIM SHARED AS DOUBLE RAD2DEG
DIM SHARED AS INTEGER HALFX = (XRES/2)
DIM SHARED AS INTEGER HALFY = (YRES/2)
DIM SHARED AS INTEGER BLOB (600 * 600)
'
'
DIM SHARED AS UINTEGER PAL (10000)
RAD2DEG = ((4*ATN(1)) / 180 )
DIM SHARED AS UINTEGER BUFFER ( XRES * YRES )
DIM SHARED AS UINTEGER BUFFER2( XRES * YRES )
DECLARE SUB DRAW_BG()
DECLARE SUB PRECALC()
DECLARE SUB COPYOVER()
DECLARE SUB TWISTER()
declare sub dblob(BYVAL MVOX AS INTEGER , BYVAL MVOY AS INTEGER)
DECLARE SUB CIRC(BYVAL CX AS INTEGER , BYVAL CY AS INTEGER , BYVAL R AS INTEGER, BYVAL CR AS INTEGER)
'-------------------------------------------------------------------------------
PRECALC()
PTC_ALLOWCLOSE(0)
PTC_SETDIALOG(0,"",0,0)
IF (PTC_OPEN("<( - METABALLS - )>",XRES,YRES)=0) THEN
END-1
END IF
'-------------------------------------------------------------------------------
DIM SHARED AS DOUBLE GD1,GD2,GD3,O,DV
WHILE(GETASYNCKEYSTATE(VK_ESCAPE)<>-32767)
O=TIMER
GD1=GD1+(DV*.7)
GD2=GD2+(DV*.6)
GD3=GD3-(DV*.4)
DBLOB(90*SIN(GD1)+20,(70*COS(GD2))-40 )
DBLOB(20*SIN(GD2+90)+20,(20*SIN(GD3))+40 )
DBLOB(90*COS(GD2/3)+20,(70*COS(GD2/2)) )
DBLOB(190*SIN(GD2+150)+20,(20*SIN(GD1))-40 )
DBLOB(90*COS(GD1/4)+20,(70*COS(GD3/4)) )
DBLOB(50*SIN(GD2-50)+20,(20*SIN(GD1*2))-40 )
DBLOB(90*COS(GD1/5)+20,(70*COS(GD3+90))+40 )
DBLOB(50*COS(GD2/23)+20,(70*COS(GD2/2))-40 )
DBLOB(19*SIN(GD1+50)+20,(50*SIN(GD1+180)/6) )
DBLOB(10*COS(GD2/14)+20,(60*COS(GD3/4)) )
DBLOB(250*SIN(GD2-50)+20,(80*SIN(GD1/2))+30 )
DBLOB(190*COS(GD1/5)+20,(70*COS(GD2+90))-40 )
COPYOVER()
PTC_UPDATE@BUFFER(0)
ERASE BUFFER2
DV=(TIMER-O)*2
WEND
'-------------------------------------------------------------------------------
SUB COPYOVER()
DIM L AS INTEGER
DIM AS UINTEGER PTR PP1,PP2
PP1=@BUFFER (0)
PP2=@BUFFER2(0)
FOR L=0 TO (XRES*YRES)-1
*PP1 = PAL(*PP2)
PP1+=1
PP2+=1
NEXT
END SUB
SUB PRECALC()
DIM AS DOUBLE RR,GG,BB
DIM AS INTEGER L
dim as integer aval = 25
RR=0.0:GG=0.0:BB=0.0
FOR L=0 TO 7999
IF L>1000 THEN
RR=RR+.05
GG=GG+.05
BB=BB+.05
ELSE
BB=BB+.1
END IF
IF L>2000 THEN
RR=RR+.015
GG=GG+.015
BB=BB+.015
END IF
IF L>3000 THEN
RR=RR+.015
GG=GG+.015
BB=BB+.015
END IF
IF RR>255 THEN RR=255
IF GG>255 THEN GG=255
IF BB>255 THEN BB=255
PAL(L)=RGBA(INT(RR),INT(GG),INT(BB),aval)
NEXT
dim as integer radius,x1,y1,x2,clv,Z,A
DIM AS DOUBLE ANGLE,BANGLE
radius=299
clv=0
for z=1 to 299
bangle=360
clv=clv+1
if z>75 then clv=clv+1
if z>125 then clv=clv+1
if z>215 then clv=clv+1
if z>295 then clv=clv+1
CIRC(300,300,RADIUS,CLV)
radius=radius-1
next
END SUB
SUB DRAW_BG()
DIM PP AS UINTEGER PTR
DIM AS INTEGER Y,SLICE,TC,www
www=30
' ERASE EDGES;
TC=8000
FOR Y=0 to YRES-1
SLICE=WWW
PP = @BUFFER2((Y*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
SLICE=WWW
PP = @BUFFER2(((Y+1)*XRES)-WWW)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
NEXT
'
' BORDERS;
'
TC=30
FOR Y=0 TO 29
SLICE=HALFX-www
PP = @BUFFER2((Y*XRES)+www)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
NEXT
FOR Y=YRES-30 TO YRES-1
SLICE=HALFX-www
PP = @BUFFER2((Y*XRES)+HALFX)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
NEXT
TC=1030
FOR Y=0 TO 30
SLICE=HALFX-www
PP = @BUFFER2((Y*XRES)+HALFX)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
NEXT
FOR Y=YRES-30 TO YRES-1
SLICE=HALFX-www
PP = @BUFFER2((Y*XRES)+www)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
NEXT
'
' MAIN BODY (CENTRE)
'
TC=20
FOR Y=30 TO HALFY
SLICE=HALFX-www
PP = @BUFFER2((Y*XRES)+www)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
NEXT
FOR Y=HALFY+1 TO YRES-30
SLICE=HALFX-www
PP = @BUFFER2((Y*XRES)+HALFX)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
NEXT
TC=1020
FOR Y=30 TO HALFY
SLICE=HALFX-www
PP = @BUFFER2((Y*XRES)+HALFX)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
NEXT
FOR Y=HALFY+1 TO YRES-30
SLICE=HALFX-www
PP = @BUFFER2((Y*XRES)+www)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
NEXT
'
'
'
TC=5100
SLICE=XRES-100
PP = @BUFFER2((30*XRES)+50)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
SLICE=XRES-100
PP = @BUFFER2(((YRES-30)*XRES)+50)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
TC=5000
SLICE=XRES-100
PP = @BUFFER2((29*XRES)+50)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
SLICE=XRES-100
PP = @BUFFER2(((YRES-29)*XRES)+50)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
SLICE=XRES-100
PP = @BUFFER2((31*XRES)+50)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
SLICE=XRES-100
PP = @BUFFER2(((YRES-31)*XRES)+50)
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END SUB
sub dblob(BYVAL MVOX AS INTEGER , BYVAL MVOY AS INTEGER)
DIM AS INTEGER X,Y
'clipping
dim as integer STRTX,ENDX,SLICE,CLIPL,CLIPR
' ENDX=MVOX+600
STRTX=0
SLICE=600
IF MVOX<0 THEN
STRTX= - MVOX
SLICE=600-STRTX
END IF
IF (MVOX+600) >= XRES-1 THEN
SLICE = (XRES-MVOX)-1
END IF
IF MVOX<0 THEN MVOX=0
IF MVOX>XRES-1 THEN MVOX=XRES-1
dim pp1 as uinteger ptr
dim pp2 as uinteger ptr
for y=0 to 600
pp1=@buffer2(MVOX+((MVOY+Y)*XRES))
pp2=@blob (STRTX+(Y *600))
IF (MVOY+Y<(YRES-1)) AND (MVOY+Y>0) THEN
for x=0 to SLICE
*PP1= *PP1 + *PP2
pp1+=1
pp2+=1
next
END IF
next
end sub
SUB CIRC(BYVAL CX AS INTEGER , BYVAL CY AS INTEGER , BYVAL R AS INTEGER, BYVAL CR AS INTEGER)
DIM as integer r2,cc,loopy,ww,l,clipl , clipr,slice,tc
dim pp as integer ptr
r2=r*r
cc=-r
TC = CR
for loopy = cc to r
ww = Sqr(r2-loopy*loopy)
if loopy+cy>=0 and loopy+cy<600 then
clipl = cx-ww
clipr = (cx+ww)-1
if clipl<0 then clipl=0
if clipr>600-1 then clipr = 600-1
pp=@BLOB((600*(loopy+CY))+clipl)
slice = clipr-clipl
if slice>0 then
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
end if
end if
next
END SUB
-
just to satisfy my curiosity... what is the problem you need to solve all this for?
In Shocky's birthday card, I had some meta balls (I think that's what they're called) where they move around and merge into each other. The calculation is done three times per pixel and as a result it slows the thing down. I was just looking for a way to optimise things.
I know the optimisation that hellfire is talking about should work, I just can't get it to work.
I think I need to tear that routine out as a stand alone program and post the source, that would make it a lot easier for people to see where I'm missing the obvious :D
Are those blobs in 2d or 3d?
If it's in 2d, you prolly don't need a per pixel SQR at all.