REM  Vector balls 2


     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

     
*FLOAT64


     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  Select a 640x512 display mode and switch off the flashing cursor
     REM

     
MODE 8
     OFF


     
REM
     REM  Install and initialise GFXLIB and required external modules
     REM

     
INSTALL @lib$+"GFXLIB2"
     PROCInitGFXLIB( dispVars{}, 0 )

     INSTALL @lib$ + "GFXLIB_modules\PlotSwapRGB.BBC" : PROCInitModule
     INSTALL @lib$ + "GFXLIB_modules\PlotBlend.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

     
PROCLoadBMP(  @dir$ + "sphere003_64x64x8.BMP", ballBm%, FALSE )


     REM
     REM  Make our blue ball green!
     REM
     REM  This is achieved by swapping the green and blue colour channel values of every
     REM  pixel in the original bitmap (swap code 0 means swap red and green, 1 means
     REM  swap red and blue, 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, 2
     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  Copy frequently accessed integer values into static variables
     REM  (A%, B%, ..., Z%) for slightly more speed
     REM

     
D% = dispVars{}
     P% = GFXLIB_PlotBlend%
     S% = ballBm%


     REM
     REM  Initialise the rotation angles
     REM

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


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

         x1# = x#*cosa# - y#*sina#
         y1# = x#*sina# + y#*cosa#
         z1# = z%(I%)

         y2# = y1#*cosb# - z1#*sinb#
         z2# = y1#*sinb# + z1#*cosb#
         x2# = x1#

         z2%(I%) = z2#*cosc# - x2#*sinc#
         x2%(I%) = z2#*sinc# + x2#*cosc#
         y2%(I%) = y2#

       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 actual balls
       REM  =======================

       REM
       REM  Reminder:  P% = GFXLIB_PlotOpaque
       REM             D% = dispVars{}
       REM             S% = ballBm%
       REM

       
FOR I%=0 TO N%-1

         REM  Calc. perspective factor
         REM  Note: this could have been pre-calculated :)
         
p# = 1 / (&258+z2%(I%))

         REM  Calc. the depth-dependent opacity
         REM  Note:  this could also have been pre-calculated :)
         
O% = &FF*(1-(&11B+z2%(I%))/&236)^2

         REM  Ensure opacity doesn't exceed 255 (&FF)
         
IF O%>&FF THEN
           
O% = &FF
         ENDIF

         
REM  Calc. final viewport coordinates
         
X% = &140 + &2A8 * x2%(I%) * p#
         Y% = &100 + &2A8 * y2%(I%) * p#
         SYS P%, D%, S%, &40, &40, X%, Y%, O%
         REM  Slower version:  SYS GFXLIB_PlotBlend%, dispVars{}, ballBm%, 64, 64, X%, Y%, O%

       
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