REM  Vector balls 5


     REM. Disable the Escape key
     
*ESC OFF


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


     REM. Set up a simple error handler
     
ON ERROR OSCLI "REFRESH ON" : REPORT : PRINT " at line ";ERL : VDU 7 : END


     
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
     
MODE 8
     OFF


     
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)
     
INSTALL @lib$+"SORTLIB"
     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
       REPEAT
         
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%
         ELSE
           FOR
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%
             ENDIF
           NEXT
J%
         ENDIF
       UNTIL
valid%
       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


     *REFRESH OFF


     REPEAT


       
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%)
       NEXT


       
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
       ENDIF
       IF
scrollerDataO% >= numStrings%-8 THEN
         
scrollerDataO% = 13
       ENDIF


       
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
       IF
b# > 2*PI THEN b# -= 2*PI
       IF
c# > 2*PI THEN c# -= 2*PI


       
REM. Update the program output window
       
PROCdisplay


     UNTIL FALSE

     
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 "*"