REM  Vector balls 3


     REM
     REM  Demonstrates use of:
     REM
     REM      GFXLIB_Clr                     (dispVars, colour)
     REM      GFXLIB_DrawBmFont1             (dispVars, bmFontAddr, stringAddr, x, y)
     REM      GFXLIB_SetDispVars             (dispVars, bmpBuffAddr, bmpBuffW, bmpBuffH, viewportX, viewportY, viewportW, viewportH, paintFlag)
     REM      GFXLIB_PlotScale               (dispVars, bmAddr, bmW, bmH, x, y)
     REM      GFXLIB_PlotScaleBlend          (dispVars, bmAddr, bmW, bmH, x, y, opacity)
     REM      GFXLIB_PlotSwapRGB             (dispVars, bmAddr, bmW, bmH, x, y, swapCode)
     REM


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


     REM
     REM  Install additional required external GFXLIB modules
     REM

     
INSTALL @lib$ + "GFXLIB_modules\PlotSwapRGB"            : PROCInitModule
     INSTALL @lib$ + "GFXLIB_modules\PlotScale"              : PROCInitModule
     INSTALL @lib$ + "GFXLIB_modules\PlotShapeHalfIntensity" : PROCInitModule
     INSTALL @lib$ + "GFXLIB_modules\PlotScaleBlend"         : PROCInitModule
     INSTALL @lib$ + "GFXLIB_modules\DrawBmFont1"            : PROCInitModule


     GetTickCount% = FNSYS_NameToAddress( "GetTickCount" )


     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  Set up a table of bitmap base addresses
     REM

     
DIM bmAddrTbl%(3)


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

     
PROCLoadBMP(  @dir$ + "blueball_128x128x24.BMP", bmAddrTbl%(0), FALSE )
     PROCLoadBMP(  @dir$ + "blueball_128x128x24.BMP", bmAddrTbl%(1), FALSE )
     PROCLoadBMP(  @dir$ + "blueball_128x128x24.BMP", bmAddrTbl%(2), FALSE )
     PROCLoadBMP(  @dir$ + "blueball_128x128x24.BMP", bmAddrTbl%(3), FALSE )


     REM
     REM  Change the colour of the bitmaps by swapping their RGB colour channels
     REM

     
SYS GFXLIB_SetDispVars2%, dispVars{}, bmAddrTbl%(0), 128, 128
     SYS GFXLIB_PlotSwapRGB%, dispVars{}, bmAddrTbl%(0), 128, 128, 0, 0, 0

     SYS GFXLIB_SetDispVars2%, dispVars{}, bmAddrTbl%(1), 128, 128
     SYS GFXLIB_PlotSwapRGB%, dispVars{}, bmAddrTbl%(1), 128, 128, 0, 0, 1

     SYS GFXLIB_SetDispVars2%, dispVars{}, bmAddrTbl%(2), 128, 128
     SYS GFXLIB_PlotSwapRGB%, dispVars{}, bmAddrTbl%(2), 128, 128, 0, 0, 2

     SYS GFXLIB_SetDispVars2%, dispVars{}, bmAddrTbl%(3), 128, 128
     SYS GFXLIB_PlotSwapRGB%, dispVars{}, bmAddrTbl%(3), 128, 128, 0, 0, 3

     SYS GFXLIB_SetDispVars2%, dispVars{}, dibs%, 640, 512


     PROCLoadData( @dir$ + "Arial_16pt_32bpp_white.DAT", fontData%, 0 )


     N% = 50 : REM  Number of balls


     
DIM bmAddr%( N%-1 ), bmAddr2%( N%-1 )
     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
     REM  Ensure that the minimum separation distance between any two positions isn't less than minDist%
     REM

     
minDist% = 100

     FOR I% = 0 TO N%-1
       REPEAT
         
valid% = TRUE
         
x% = -400 + RND(2*400 - 1)
         y% = -400 + RND(2*400 - 1)
         z% = -400 + RND(2*400 - 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%
       bmAddr%( I% ) = bmAddrTbl%( RND(4)-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_PlotScale%
     Q% = GFXLIB_PlotShapeHalfIntensity%
     R% = GFXLIB_PlotScaleBlend%


     REM
     REM  Initialise frame counter
     REM

     
frames% = 0
     dispFrames% = 0


     REM
     REM  Disable the automatic window update
     REM

     
*REFRESH OFF

     SYS GetTickCount% TO time0%

     REPEAT


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

       
SYS GFXLIB_Clr%, D%, &101540


       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

       
bmAddr2%() = bmAddr%()

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


       REM
       REM  Draw the actual balls
       REM

       
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%)+&1F4))/&3E8
         SYS P%, D%, bmAddr2%(I%), 128, 128, Z%, Z%, X%, Y%
       NEXT

       SYS
GFXLIB_DrawBmFont1%, D%, fontData%, "Frame rate: "+STR$dispFrames%+" fps", 8, 480


       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

       SYS
GetTickCount% TO time1%
       IF time1%-time0% >= 1000 THEN
         
dispFrames% = frames%
         frames% = 0
         SYS GetTickCount% TO time0%
       ENDIF

       PROC
display

       frames% += 1

     UNTIL FALSE