REM. Vector balls 1


     REM
     REM  Disable the Escape key
     REM

     
*ESC OFF


     REM
     REM  Set up a simple error handler
     REM

     
ON ERROR OSCLI "REFRESH ON" : MODE 8 : VDU 7 : REPORT : PRINT " at line ";ERL : END


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

     
*FLOAT 64


     REM
     REM  Prevent the program window from being resized by the user
     REM

     
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
     REM  Setup a 640x512 display mode, and turn OFF the flashing cursor
     REM

     
MODE 8
     OFF


     
REM
     REM  Install and initialise GFXLIB
     REM

     
INSTALL @lib$ + "GFXLIB2.BBC"
     PROCInitGFXLIB


     REM
     REM  Load the required GFXLIB external modules
     REM

     
INSTALL @lib$ + "GFXLIB_modules\PlotSwapRGB.BBC"            : PROCInitModule
     INSTALL @lib$ + "GFXLIB_modules\PlotShapeHalfIntensity.BBC" : PROCInitModule


     REM
     REM  Install and initialise SORTLIB (which will be used to depth-sort the
     REM  'vector balls' according to their Z coordinate)
     REM

     
INSTALL @lib$+"SORTLIB"
     sort% = FN_sortinit(1,0)


     REM
     REM  Load-in the ball graphic (64x64 pixels, 24bpp) and convert to 32bpp
     REM

     
ballBm% = FNLoadBMP(  @dir$ + "sphere003_64x64x24", FALSE )


     REM
     REM  Make our blue ball pink!
     REM
     REM  This is achieved by swapping the red and blue colour channel values of every
     REM  pixel in the original bitmap (swap code 1 means swap red and blue channel values,
     REM  0 means swap red and green, 2 means swap green and blue).
     REM
     REM  Note that an alternative GFXLIB function, GFXLIB_RGBSwap, could have been
     REM  used instead and which would have not necessitated the use of GFXLIB_SetDispVars2.
     REM

     
SYS GFXLIB_SetDispVars2%, dispVars{}, ballBm%, 64, 64
     SYS GFXLIB_PlotSwapRGB%, dispVars{}, ballBm%, 64, 64, 0, 0, 1
     SYS GFXLIB_SetDispVars2%, dispVars{}, dibs%, 640, 512



     N% = 50  : REM  Number of balls

     
DIM x%(N%-1), y%(N%-1), z%(N%-1)     : REM  Arrays to hold the ball's position in 3D space
     
DIM x2%(N%-1), y2%(N%-1), z2%(N%-1)  : REM  Arrays to hold the ball's position in 3D space *after* it's been rotated


     REM
     REM  Define balls' 3D coordinates
     REM

     
FOR I%=0 TO N%-1
       x%(I%)=-200+RND(400 - 1)
       y%(I%)=-200+RND(400 - 1)
       z%(I%)=-200+RND(400 - 1)
     NEXT I%


     REM
     REM  Initialise the rotation angles
     REM

     
a# = 0
     b# = 0
     c# = 0


     REM
     REM  Copy frequently accessed integer values into static variables
     REM  (A%, B%, ..., Z%) for slightly more speed
     REM

     
D% = dispVars{}
     P% = GFXLIB_Plot%
     Q% = GFXLIB_PlotShapeHalfIntensity%
     S% = ballBm%


     REM
     REM  Disable the automatic window update
     REM

     
*REFRESH OFF


     REPEAT


       
REM
       REM  Clear the viewport (fill it with blue)
       REM

       
SYS GFXLIB_Clr%, D%, &203080


       REM
       REM  Rotate the 3D positions of the balls
       REM

       
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
       REM  Sort the rotated X, Y, Z coordinate arrays according to the Z coordinate
       REM

       
C%=N% : CALL sort%, z2%(0), x2%(0), y2%(0)


       REM
       REM  Draw the shadows
       REM
       REM  These loops are intended to be fast, and therefore may appear rather cryptic.
       REM
       REM  What's with the hexadecimal values? They tend to be 'processed' a little bit
       REM  faster than decimal integers (although this assertion is open to challenge!)
       REM

       
FOR I%=0 TO N%-1
         d# = 1/(&258+z2%(I%))
         K% = &30*(1-(&12C+z2%(I%))/&258)
         X% = &140 + &2A8 * x2%(I%) * d#
         Y% = &100 + &2A8 * y2%(I%) * d#
         SYS Q%, D%, S%, &40, &40, X%-K%, Y%-K%
         REM Slower version:  SYS GFXLIB GFXLIB_PlotShapeHalfIntensity%, dispVars{}, ballBm%, 64, 64, X%-K%, Y%-K%
       
NEXT

       
REM
       REM  Note that an alternative (but slower) way of drawing the ball shadows (and which avoids
       REM  the shadow overlap darkening effect), would be to use GFXLIB_PlotShadow.
       REM


       REM
       REM  Draw the actual balls
       REM

       
FOR I%=0 TO N%-1
         d# = 1/(&258+z2%(I%))
         X% = &140 + &2A8 * x2%(I%) * d#
         Y% = &100 + &2A8 * y2%(I%) * d#
         SYS P%, D%, S%, &40, &40, X%, Y%
         REM Slower version:  SYS GFXLIB_Plot%, dispVars{}, ballBm%, 64, 64, X%, Y%
       
NEXT


       
REM
       REM  Bump then check the rotation angles
       REM

       
a# += 0.019151
       b# += 0.016316
       c# += 0.012194

       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
       REM  Update the program window
       REM

       
PROCdisplay

     UNTIL FALSE