********************************************

*  BallTrick.asm by Richard Horne
*  Requires xspecs.library version 0 in df0:libs
*  Freely distributable in the public domain

********************************************

   INCLUDE     "exec/types.i"
   INCLUDE     "exec/memory.i"
   INCLUDE     "intuition/intuition.i"

   XREF  _AbsExecBase
   XREF  _LVOAllocMem
   XREF  _LVOFreeMem
   XREF  _LVOOpenLibrary
   XREF  _LVOCloseLibrary
   XREF  _LVOGetMsg
   XREF  _LVOReplyMsg
   XREF  _LVOWaitTOF

_LVOXSpecsAllocateView        EQU   -30
_LVOXSpecsDeallocateView      EQU   -36
_LVOXSpecsOn                  EQU   -42
_LVOXSpecsOff                 EQU   -48
_LVOXSpecsSetAPen             EQU   -54
_LVOXSpecsSetRGB4             EQU   -60
_LVOXSpecsLoadRGB4            EQU   -66
_LVOXSpecsText                EQU   -72
_LVOXSpecsWritePixel          EQU   -78
_LVOXSpecsDraw                EQU   -84
_LVOXSpecsChangeSprite        EQU   -90
_LVOXSpecsMoveSprite          EQU   -96
_LVOXSpecsLeftXY              EQU   -102
_LVOXSpecsRightXY             EQU   -108
_LVOXSpecsLeftRastPort        EQU   -114
_LVOXSpecsRightRastPort       EQU   -120
_LVOXSpecsLeftViewPort        EQU   -126
_LVOXSpecsRightViewPort       EQU   -132
_LVOXSpecsSetDrMd             EQU   -138
_LVOXSpecsPolyDraw            EQU   -144
_LVOXSpecsMove                EQU   -150
_LVOXSpecsGetSprite           EQU   -156
_LVOXSpecsFreeSprite          EQU   -162
_LVOXSpecsTime                EQU   -168

***************************************

Start:

*  open Graphics library

   move.l  _AbsExecBase,a6
   move.l   #GraphicsName,a1
   clr.l    d0
   jsr      _LVOOpenLibrary(a6)
   tst.l    d0
   beq      Abort
   move.l   d0,GfxBase

*  open XSpecs library

   move.l  _AbsExecBase,a6
   move.l   #XSpecsName,a1
   clr.l    d0                         ;Version 0
   jsr      _LVOOpenLibrary(a6)
   beq      Abort
   move.l   d0,XSpecsBase

*  Allocate Sprite Chip Memory.
*  In order to use sprites later, we must set up sprite image data in
*  chip memory.  We are going to use three sprites, each 16 pixels wide
*  by 12 lines high (14 lines including top and bottom headers).

   move.l  _AbsExecBase,a6             ;Allocate chip memory
   move.l   #168,d0                    ;3 sprites, each 14 lines (56 bytes)
   move.l   #MEMF_CHIP!MEMF_CLEAR,d1
   jsr      _LVOAllocMem(a6)
   move.l   d0,Sprite2CM               ;CM address of Sprite2 image
   add.l    #56,d0
   move.l   d0,Sprite4CM               ;CM address of Sprite4 image
   add.l    #56,d0
   move.l   d0,Sprite6CM               ;CM address of Sprite6 image

   move.l   #SpriteData,a0             ;Sprite shape into chip memory
   move.l   Sprite2CM,a1
   move.l   #13,d1
CS1:
   move.l   (a0)+,(a1)+
   dbra     d1,CS1

   move.l   #SpriteData,a0             ;Sprite shape into chip memory
   move.l   Sprite4CM,a1
   move.l   #13,d1
CS2:
   move.l   (a0)+,(a1)+
   dbra     d1,CS2

   move.l   #SpriteData,a0             ;Sprite shape into chip memory
   move.l   Sprite6CM,a1
   move.l   #13,d1
CS3:
   move.l   (a0)+,(a1)+
   dbra     d1,CS3


********************** XSpecs Code *********************

*  Allocate XSpecs View.  This function allocates memory and initializes
*  data structures required for XSpecs left and right bitmaps, rastports,
*  and viewports.

   move.l   XSpecsBase,a6
   move.l   #V_HIRES!V_SPRITES,d0         ;ViewModes
   jsr      _LVOXSpecsAllocateView(a6)
   cmpi.l   #0,d0                         ;Successful?
   bne      Abort

*  Turn On XSpecs.  This function starts the vertical blank interrupt
*  which switches the XSpecs lenses.

   move.l   XSpecsBase,a6
   move.l   #RAWKEY,d0                    ;Our IDCMP messages
   jsr      _LVOXSpecsOn(a6)
   move.l   d0,UserPort                   ;Our message port for IDCMP
   cmpi.l   #1,d0                         ;Successful?
   beq      Close

*  Set XSpecs View Colors

   move.l   XSpecsBase,a6
   move.l   #Colors,a0
   move.l   #32,d0
   jsr      _LVOXSpecsLoadRGB4(a6)

   move.l   XSpecsBase,a6
   move.l   #1,d0
   jsr      _LVOXSpecsSetAPen(a6)

*  Draw XSpecs Cube #200 units each side, centered around 0,0,0

   move.l   XSpecsBase,a6
   move.l   #Points,a0                 ;Array of (x,y,z) points to connect
   move.l   #16,d0                     ;Number of points
   jsr      _LVOXSpecsPolyDraw(a6)
   cmpi.l   #1,d0                      ;Successful?
   beq      Close

*  Write XSpecsText at position x,y,z

   move.l   #-78,d0                    ;x
   move.l   #120,d1                    ;y
   move.l   #-160,d2                   ;z
   move.l   #24,d3                     ;count
   move.l   #TestText,a0               ;Address of text string
   move.l   XSpecsBase,a6
   jsr      _LVOXSpecsText(a6)
   cmpi.l   #1,d0                      ;Successful?
   beq      Close

*  Get XSpecs Sprites

   move.l   XSpecsBase,a6
   move.l   #2,d0                      ;SpriteNumber 2
   move.l   #Sprite,a0                 ;Simple Sprite Structure
   move.l   Sprite2CM,a1               ;Sprite Image Address
   jsr      _LVOXSpecsGetSprite(a6)
   cmpi.l   #-1,d0                     ;Successful?
   beq      Close

   move.l   Sprite2CM,a0               ;Sprite Image Address
   move.l   #2,d0                      ;Sprite Number
   move.l   XSpecsBase,a6
   jsr      _LVOXSpecsChangeSprite(a6)
   cmpi.l   #1,d0                      ;Successful?
   beq      Close

   move.l   XSpecsBase,a6
   move.l   #4,d0                      ;SpriteNumber 4
   move.l   #Sprite,a0                 ;Simple Sprite Structure
   move.l   Sprite4CM,a1               ;Sprite Image Address
   jsr      _LVOXSpecsGetSprite(a6)
   cmpi.l   #-1,d0                     ;Successful?
   beq      Close

   move.l   Sprite4CM,a0               ;Sprite Image Address
   move.l   #4,d0                      ;Sprite Number
   move.l   XSpecsBase,a6
   jsr      _LVOXSpecsChangeSprite(a6)
   cmpi.l   #1,d0                      ;Successful?
   beq      Close

   move.l   XSpecsBase,a6
   move.l   #6,d0                      ;SpriteNumber 6
   move.l   #Sprite,a0                 ;Simple Sprite Structure
   move.l   Sprite6CM,a1               ;Sprite Image Address
   jsr      _LVOXSpecsGetSprite(a6)
   cmpi.l   #-1,d0                     ;Successful?
   beq      Close

   move.l   Sprite6CM,a0               ;Sprite Image Address
   move.l   #6,d0                      ;Sprite Number
   move.l   XSpecsBase,a6
   jsr      _LVOXSpecsChangeSprite(a6)
   cmpi.l   #1,d0                      ;Successful?
   beq      Close

*  Begin BallTrick.  Now that everything is set up, we can begin
*  the program loop to move the sprites.

BallLoop:

   move.l   XSpecsBase,a6              ;Get current time
   jsr      _LVOXSpecsTime(a6)
   add.l    #2,d0
   move.l   d0,CycleTime               ;Time for start of next cycle

*  Update Ball Position and Velocity.  Each ball (sprite) has a position
*  (X,Y,Z) and a velocity (Vx,Vy,Vz).  This function calcultes a new position
*  for each ball based on its current velocity.  If a ball strikes a
*  wall of the box, the velocity perpindicular to that wall is reversed
*  causing the ball to bounce away from the wall.

   move.l   XVxSprite2,d0
   move.l   YVySprite2,d1
   move.l   ZVzSprite2,d2
   jsr      GetNewPosition
   move.l   d0,XVxSprite2
   move.l   d1,YVySprite2
   move.l   d2,ZVzSprite2

   move.l   XVxSprite4,d0
   move.l   YVySprite4,d1
   move.l   ZVzSprite4,d2
   jsr      GetNewPosition
   move.l   d0,XVxSprite4
   move.l   d1,YVySprite4
   move.l   d2,ZVzSprite4

   move.l   XVxSprite6,d0
   move.l   YVySprite6,d1
   move.l   ZVzSprite6,d2
   jsr      GetNewPosition
   move.l   d0,XVxSprite6
   move.l   d1,YVySprite6
   move.l   d2,ZVzSprite6

*  Move XSpecs Sprites to New Positions.  We have calculated the new ball
*  (sprite) positions in the XSpecs (x,y,z) three dimensional coordinate
*  system.  Now we need to move the balls (sprites) to corresponding
*  positions in the XSpecs left and right viewports.  Switching of the
*  XSpecs lenses will give the illusion of movement in three dimensions.

   move.w   XVxSprite2,d0              ;x position, 16 bits
   move.w   YVySprite2,d1              ;y position, 16 bits
   move.w   ZVzSprite2,d2              ;z position, 16 bits
   move.l   #-8,d3                     ;x pixel offset
   move.l   #-6,d4                     ;y pixel offset
   move.l   #2,d5                      ;SpriteNumber
   move.l   XSpecsBase,a6
   jsr      _LVOXSpecsMoveSprite(a6)
   cmpi.l   #1,d0                      ;Successful?
   beq      Close

   move.w   XVxSprite4,d0              ;x position, 16 bits
   move.w   YVySprite4,d1              ;y position, 16 bits
   move.w   ZVzSprite4,d2              ;z position, 16 bits
   move.l   #-8,d3                     ;x pixel offset
   move.l   #-6,d4                     ;y pixel offset
   move.l   #4,d5                      ;SpriteNumber
   move.l   XSpecsBase,a6
   jsr      _LVOXSpecsMoveSprite(a6)
   cmpi.l   #1,d0                      ;Successful?
   beq      Close

   move.w   XVxSprite6,d0              ;x position, 16 bits
   move.w   YVySprite6,d1              ;y position, 16 bits
   move.w   ZVzSprite6,d2              ;z position, 16 bits
   move.l   #-8,d3                     ;x pixel offset
   move.l   #-6,d4                     ;y pixel offset
   move.l   #6,d5                      ;SpriteNumber
   move.l   XSpecsBase,a6
   jsr      _LVOXSpecsMoveSprite(a6)
   cmpi.l   #1,d0                      ;Successful?
   beq      Close

*  Check Time

TimeLoop:
   move.l   GfxBase,a6
   jsr      _LVOWaitTOF(a6)

*  Compare Time against Cycle Time

   move.l   XSpecsBase,a6
   jsr      _LVOXSpecsTime(a6)
   move.l   CycleTime,d1
   cmp.l    d1,d0                      ;If Time < = CycleTime, then wait.
   blt      TimeLoop

*  Get IDCMP messages
   move.l  UserPort,a0
   move.l  _AbsExecBase,a6
   jsr      _LVOGetMsg(a6)
   tst.l    d0
   beq      BallLoop
   move.l   d0,IDCMPMessage

*  Reply to message
   move.l   _AbsExecBase,a6
   move.l   IDCMPMessage,a1
   jsr      _LVOReplyMsg(a6)

*  Find Message Class
   move.l  IDCMPMessage,a0
   move.l   im_Class(a0),MessageClass

*  Find Messsage Code
   move.l  IDCMPMessage,a0
   move.w   im_Code(a0),MessageCode

*  is message rawkey?

   cmpi.l   #RAWKEY,MessageClass
   bne      BallLoop


***************** Close *******************

Close:

   move.l  XSpecsBase,a6
   move.l   #2,d0
   jsr      _LVOXSpecsFreeSprite(a6)

   move.l  XSpecsBase,a6
   move.l   #4,d0
   jsr      _LVOXSpecsFreeSprite(a6)

   move.l  XSpecsBase,a6
   move.l   #6,d0
   jsr      _LVOXSpecsFreeSprite(a6)

   move.l   XSpecsBase,a6
   jsr      _LVOXSpecsOff(a6)

   move.l   XSpecsBase,a6
   jsr      _LVOXSpecsDeallocateView(a6)

*  Free Sprite Memory

   move.l   _AbsExecBase,a6
   move.l   Sprite2CM,a1
   move.l   #168,d0
   jsr      _LVOFreeMem(a6)

*  Close Libraries

   move.l  _AbsExecBase,a6
   move.l   XSpecsBase,a1
   jsr      _LVOCloseLibrary(a6)

   move.l  _AbsExecBase,a6
   move.l   GfxBase,a1
   jsr      _LVOCloseLibrary(a6)

Abort:
   rts

******************* Subroutines ***********************

GetNewPosition:
   move.l   d0,d3          ;X,Vx in d3
   swap     d0             ;Vx,X in d0
   add.w    d3,d0          ;Vx,X+Vx in d0
   cmpi.w   #100,d0
   bge      ReverseVx
   cmpi.w   #-100,d0
   ble      ReverseVx
   swap     d0
   bra      YCal
ReverseVx:
   move.l   d3,d0
   neg.w    d0

YCal:
   move.l   d1,d3          ;Y,Vy in d3
   swap     d1             ;Vy,Y in d1
   add.w    d3,d1          ;Vy,Y+Vy in d1
   cmpi.w   #100,d1
   bge      ReverseVy
   cmpi.w   #-100,d1
   ble      ReverseVy
   swap     d1
   bra      ZCal
ReverseVy:
   move.l   d3,d1
   neg.w    d1

ZCal:
   move.l   d2,d3          ;Z, Vz in d3
   swap     d2             ;Vz, Z in d2
   add.w    d3,d2          ;Vz, Z+Vz in d2
   cmpi.w   #100,d2
   bge      ReverseVz
   cmpi.w   #-100,d2
   ble      ReverseVz
   swap     d2
   bra      EndGetNewPosition
ReverseVz:
   move.l   d3,d2
   neg.w    d2

EndGetNewPosition:
   rts

****************** Data ********************

   SECTION  data,DATA

GraphicsName:
   dc.b     'graphics.library',0
   cnop     0,2

XSpecsName:
   dc.b     'xspecs.library',0
   cnop     0,2

GfxBase:
   ds.l     1

XSpecsBase:
   ds.l     1

TestText:
   dc.b     'xspecs.library version 0',0
   cnop     0,2

UserPort:                        ;Address of XSpecs IDCMP Message Port
   ds.l     1

IDCMPMessage:
   ds.l     1

MessageClass:
   ds.l     1

MessageCode:
   ds.w     1

Points:
   dc.w     -100,100,-100
   dc.w     -100,-100,-100
   dc.w     100,-100,-100
   dc.w     100,-100,100
   dc.w     -100,-100,100
   dc.w     -100,-100,-100
   dc.w     100,-100,-100
   dc.w     100,100,-100
   dc.w     -100,100,-100
   dc.w     -100,100,100
   dc.w     -100,-100,100
   dc.w     100,-100,100
   dc.w     100,100,100
   dc.w     -100,100,100
   dc.w     100,100,100
   dc.w     100,100,-100

****************** Sprite **********************

Sprite:                 ;Simple Sprite Structure
   dc.l     0
   dc.w     12          ;Height
   dc.w     0
   dc.w     0
   dc.w     0

Sprite2CM:                 ;Chip Memory address of sprite image
   ds.l     1

Sprite4CM:                 ;Chip Memory address of sprite image
   ds.l     1

Sprite6CM:                 ;Chip Memory address of sprite image
   ds.l     1

SpriteData:
  dc.l  $00000000
  dc.l  $00000000,$00000000,$00000000,$00000000
  dc.l  $01800780,$0CC003C0,$0CE013E0,$00E01FE0
  dc.l  $11E01FE0,$0FC00FC0,$07800780,$00000000
  dc.l  $00000000

XVxSprite2:                ;Initial ball (sprite) position and velocity
   dc.w     20,8           ;16 bits position, 16 bits velocity
YVySprite2:
   dc.w     10,7
ZVzSprite2:
   dc.w     -40,6

XVxSprite4:
   dc.w     10,9
YVySprite4:
   dc.w     12,4
ZVzSprite4:
   dc.w     -20,-7

XVxSprite6:
   dc.w     8,3
YVySprite6:
   dc.w     9,-8
ZVzSprite6:
   dc.w     10,-9

CycleTime:
   ds.l     1

Colors:
   dc.w     $0000,$026F,$0000,$0000       ;0-3
   dc.w     $0000,$0000,$0000,$0000       ;4-7
   dc.w     $0000,$0000,$0000,$0000       ;8-11
   dc.w     $0000,$0000,$0000,$0000       ;12-15
   dc.w     $0000,$0000,$0000,$0000       ;16-19
   dc.w     $0000,$0FCA,$0E86,$0D22       ;20-23
   dc.w     $0000,$0AC8,$08A6,$0282       ;24-27
   dc.w     $0000,$0ACF,$068E,$022D       ;28-31


   END

