REM  Vector balls 5

     REM. Disable the Escape key

     REM. Select 64-bit floating point mode (double-precision maths)

     REM. Set up a simple error handler

REM. Make 2 MB of RAM available for this program
M% = 2
     HIMEM = LOMEM + M%*&100000

     REM. Prevent the program window from being resized by the user
SYS "GetWindowLong", @hwnd%, -16 TO S%
     SYS "SetWindowLong", @hwnd%, -16, S% AND NOT &50000
     SYS "SetWindowPos", @hwnd%, 0, 0, 0, 0, 0, 32+7

     REM. Setup a 640x512 display mode, and turn OFF the flashing cursor

REM. Install and initialise GFXLIB and required external modules
INSTALL @lib$ + "GFXLIB2.BBC"                      : PROCInitGFXLIB

     INSTALL @lib$ + "GFXLIB_modules\PlotAND3.BBC"      : PROCInitModule
     INSTALL @lib$ + "GFXLIB_modules\DrawBmFont4.BBC"   : PROCInitModule
     INSTALL @lib$ + "GFXLIB_modules\PlotScaleTint.BBC" : PROCInitModule
     INSTALL @lib$ + "GFXLIB_modules\MMXSubtract64.BBC" : PROCInitModule

     REM. Get addresses of frequently called Windows API routines
GetTickCount% = FNSYS_NameToAddress( "GetTickCount" )
     InvalidateRect% = FNSYS_NameToAddress( "InvalidateRect" )

     REM. Declare a string array to contain the lines of text
RESTORE : numStrings%=-1 : REPEAT : READ S$ : numStrings%+=1 : UNTIL S$="*"
     DIM string$( numStrings%-1 )
     REM. Fill the string array (read the text from DATA statements into the array)
RESTORE : FOR I%=0 TO numStrings%-1 : READ string$(I%) : NEXT I%

     REM. Install and initialise SORTLIB (which will be used to depth-sort the
     REM. 'vector balls' according to their Z coordinate)
     sort% = FN_sortinit(1, 0)

     REM. Load graphics
PROCLoadBMP(  @dir$ + "blueball_128x128x24.BMP", bmAddr%, FALSE )

     REM. Load the bitmap font data
PROCLoadData( @dir$ + "bm14.DAT", font%, 0 )

     REM. Set up a 640*512-pixel 'bitmap buffer' to which the rotating pattern of
     REM. ball sprites will be written
DIM bmBuff% 4*640*512+4 : bmBuff%=(bmBuff%+3) AND -4

     REM. Number of ball sprites to display
N% = 25

     REM. Arrays holding the ball's position in 3D space, colour, and the strength of which
     REM. the colour is blended with the 'natural' colour of the ball sprite
DIM x%(N%-1), y%(N%-1), z%(N%-1), colour%(N%-1), strength%(N%-1)

     REM. Arrays holding the ball's depth-sorted position in 3D space *after* it's been rotated
DIM x2%(N%-1), y2%(N%-1), z2%(N%-1), colour2%(N%-1), strength2%(N%-1)

     REM. 'Randomize' BASIC's random number generator (using the current value of TIME as the seed)
R% = RND( -TIME )

     REM. Specify the minimum distance that any one ball can be from any other
minDist% = 100

     REM. Choose random positions such that no ball is within minDist% units of another ball
FOR I%=0 TO N%-1
valid% = TRUE
x% = -300 + RND(2*300 - 1)
         y% = -300 + RND(2*300 - 1)
         z% = -300 + RND(2*300 - 1)
         IF I%=0 THEN
x%(0) = x%
           y%(0) = y%
           z%(0) = z%
J%=0 TO I%
             d% = SQR( (x%-x%(J%))^2 + (y%-y%(J%))^2 + (z%-z%(J%))^2 )
             IF d% < minDist% THEN
valid% = FALSE
J% = I%
       x%(I%) = x%
       y%(I%) = y%
       z%(I%) = z%
       colour%(I%) = &10000*RND(&FF) + &100*RND(&FF) + RND(&FF)
       strength%(I%) = 128 + RND(127)
     NEXT I%

     REM. Set up random initial rotation angles (in radians)
a# = 2.0 * PI * RND(1)
     b# = 2.0 * PI * RND(1)
     c# = 2.0 * PI * RND(1)

     REM. Copy frequently accessed variables into BASIC's static variables for faster access
A% = GFXLIB_DrawBmFont4%
     D% = dispVars{}
     P% = GFXLIB_PlotScaleTint%

     scrollerYPxlO% = -40
     scrollerDataO% = 13



REM. Display the bitmap buffer
SYS GFXLIB_BPlot%, dispVars{}, bmBuff%, 640, 512, 0, 0

       REM. Redirect GFXLIB's output to the 640x512-pixel bitmap buffer pointed to by bmBuff%
SYS GFXLIB_QuickSetDispVars%, dispVars{}, bmBuff%

       REM. Darken all the pixels in the bitmap buffer
       REM. (i.e., Subtract 4 from the Red, Green and Blue values of each pixel)
SYS GFXLIB_MMXSubtract64%, dispVars{}, bmBuff%, 4*(640*512 DIV 64), 4

       REM. Rotate the 3D positions of the balls
cosa# = COSa#
       cosb# = COSb#
       cosc# = COSc#
       sina# = SINa#
       sinb# = SINb#
       sinc# = SINc#
       FOR I%=0 TO N%-1
         x# = x%(I%)
         y# = y%(I%)
         z# = z%(I%)
         x1# = x#*cosa# - y#*sina#
         y1# = x#*sina# + y#*cosa#
         z1# = z#
         y2# = y1#*cosb# - z1#*sinb#
         z2# = y1#*sinb# + z1#*cosb#
         x2# = x1#
         z3# = z2#*cosc# - x2#*sinc#
         x3# = z2#*sinc# + x2#*cosc#
         y3# = y2#
         x2%(I%) = x3#
         y2%(I%) = y3#
         z2%(I%) = z3#
       NEXT I%

       REM. Sort the rotated X, Y, Z coordinate arrays according to the Z coordinate
colour2%() = colour%()
       strength2%() = strength%()
       C%=N% : CALL sort%, z2%(0), x2%(0), y2%(0), colour2%(0), strength2%(0)

       REM. Draw the actual ball bitmaps
       REM. Reminder: P%=GFXLIB_PlotScaleColourBlend, D%=dispVars{}
FOR I%=0 TO N%-1
         d# = 1/(&3E8+z2%(I%))
         X% = &140 + &2A8 * x2%(I%) * d#
         Y% = &100 + &2A8 * y2%(I%) * d#
         Z% = &80*(&3E8-(z2%(I%)+&2F4))/&3E8
         SYS P%, D%, bmAddr%, 128, 128, Z%, Z%, X%-Z%/2, Y%-Z%/2, colour2%(I%), strength2%(I%)

REM. Reset the bmBuffAddr member of the dispVars struct to dibSectionAddr%
SYS GFXLIB_QuickSetDispVars%, dispVars{}, dibs%

       REM. Draw the scrolling lines of text
       REM. Reminder: A%=GFXLIB_DrawBmFont4, D%=dispVars{}
FOR Y%=13 TO 0 STEP -1
         V% = 40*Y% + scrollerYPxlO%
         C% = &10000*INT(255*(1-(V%+40)/552)) + &100*INT(128+127*(V%+40)/552) + INT(255*(V%+40)/552)
         REM. SYS GFXLIB_DrawBmFont4, dispVars{}, bmFontAddr, string, x, y, colour
SYS A%, D%, font%, string$(scrollerDataO% - Y%), 0, V%, C%
       NEXT Y%
       scrollerYPxlO% += 1
       IF scrollerYPxlO% >= 0 THEN
scrollerYPxlO% = -40
         scrollerDataO% += 1
scrollerDataO% >= numStrings%-8 THEN
scrollerDataO% = 13

REM. Bump then check the rotation angles
a# += 0.029151 + 0.01*SINb#*COSc#
       b# += 0.026316 - 0.01*COSc#
       c# += 0.022194 + 0.01*SINa#*COSb#
       IF a# > 2*PI THEN a# -= 2*PI
b# > 2*PI THEN b# -= 2*PI
c# > 2*PI THEN c# -= 2*PI

REM. Update the program output window


REM Some random verses from the New Testament :-)

DATA "","","","","","","","","","","","","","","",
DATA "Examine yourselves to see"
DATA "whether you are in the faith;"
DATA "test yourselves."
DATA "Do you not realize that"
DATA "Christ Jesus is in you -"
DATA "unless, of course, you fail"
DATA "the test?"
DATA "And I trust that you will"
DATA "discover that we have not"
DATA "failed the test."
DATA "", "", "", ""
DATA "", "", "", ""
DATA "Now we pray to God that"
DATA "you will not do anything"
DATA "wrong. Not that people will"
DATA "see that we have stood the"
DATA "test but that you will do"
DATA "what is right even though we"
DATA "may seem to have failed."
DATA "", "", "", ""
DATA "", "", "", ""
DATA "For we cannot do anything"
DATA "against the truth, but"
DATA "only for the truth."
DATA "We are glad whenever we"
DATA "are weak but you are strong;"
DATA "and our prayer is for your"
DATA "perfection. This is why I"
DATA "write these things when I am"
DATA "absent, that when I come"
DATA "I may not have to be harsh"
DATA "in my use of authority -"
DATA "the authority the Lord gave"
DATA "me for building you up,"
DATA "not for tearing you down."
DATA "","","","","","","","","","","","","","","",
DATA "","","","","","","","","","","","","","","",
DATA "*"