377 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Factor
		
	
	
		
		
			
		
	
	
			377 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Factor
		
	
	
| 
								 | 
							
								! Copyright (C) 2006 Chris Double.
							 | 
						||
| 
								 | 
							
								! See http://factorcode.org/license.txt for BSD license.
							 | 
						||
| 
								 | 
							
								!
							 | 
						||
| 
								 | 
							
								USING: cpu.8080 cpu.8080.emulator openal math alien.c-types
							 | 
						||
| 
								 | 
							
								sequences kernel shuffle arrays io.files combinators ui.gestures
							 | 
						||
| 
								 | 
							
								ui.gadgets ui.render opengl.gl system match
							 | 
						||
| 
								 | 
							
								ui byte-arrays combinators.lib qualified ;
							 | 
						||
| 
								 | 
							
								QUALIFIED: threads
							 | 
						||
| 
								 | 
							
								IN: space-invaders
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								TUPLE: space-invaders port1 port2i port2o port3o port4lo port4hi port5o bitmap sounds looping? ;
							 | 
						||
| 
								 | 
							
								: game-width 224  ; inline
							 | 
						||
| 
								 | 
							
								: game-height 256 ; inline
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: make-opengl-bitmap ( -- array )
							 | 
						||
| 
								 | 
							
								  game-height game-width 3 * * <byte-array> ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: bitmap-index ( point -- index )
							 | 
						||
| 
								 | 
							
								  #! Point is a {x y}.
							 | 
						||
| 
								 | 
							
								  first2 game-width 3 * * swap 3 * + ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: set-bitmap-pixel ( color point array -- )
							 | 
						||
| 
								 | 
							
								  #! 'color' is a {r g b}. Point is {x y}.
							 | 
						||
| 
								 | 
							
								  [ bitmap-index ] dip ! color index array
							 | 
						||
| 
								 | 
							
								  [ [ first ] 2dip set-uchar-nth ] 3keep
							 | 
						||
| 
								 | 
							
								  [ [ second ] 2dip [ 1 + ] dip set-uchar-nth ] 3keep
							 | 
						||
| 
								 | 
							
								  [ third ] 2dip [ 2 + ] dip set-uchar-nth ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: get-bitmap-pixel ( point array -- color )
							 | 
						||
| 
								 | 
							
								  #! Point is a {x y}. color is a {r g b} 
							 | 
						||
| 
								 | 
							
								  [ bitmap-index ] dip
							 | 
						||
| 
								 | 
							
								  [ uint-nth ] 2keep
							 | 
						||
| 
								 | 
							
								  [ [ 1 + ] dip uchar-nth ] 2keep
							 | 
						||
| 
								 | 
							
								  [ 2 + ] dip uchar-nth 3array ;
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								: SOUND-SHOT         ( -- number ) 0 ;
							 | 
						||
| 
								 | 
							
								: SOUND-UFO          ( -- number ) 1 ;
							 | 
						||
| 
								 | 
							
								: SOUND-BASE-HIT     ( -- number ) 2 ;
							 | 
						||
| 
								 | 
							
								: SOUND-INVADER-HIT  ( -- number ) 3 ;
							 | 
						||
| 
								 | 
							
								: SOUND-WALK1        ( -- number ) 4 ;
							 | 
						||
| 
								 | 
							
								: SOUND-WALK2        ( -- number ) 5 ;
							 | 
						||
| 
								 | 
							
								: SOUND-WALK3        ( -- number ) 6 ;
							 | 
						||
| 
								 | 
							
								: SOUND-WALK4        ( -- number ) 7 ;
							 | 
						||
| 
								 | 
							
								: SOUND-UFO-HIT      ( -- number ) 8 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: init-sound ( index cpu filename  -- )
							 | 
						||
| 
								 | 
							
								  swapd >r space-invaders-sounds nth AL_BUFFER r> 
							 | 
						||
| 
								 | 
							
								  create-buffer-from-wav set-source-param ; 
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: init-sounds ( cpu -- )
							 | 
						||
| 
								 | 
							
								  init-openal
							 | 
						||
| 
								 | 
							
								  [ 9 gen-sources swap set-space-invaders-sounds ] keep
							 | 
						||
| 
								 | 
							
								  [ SOUND-SHOT        "resource:extra/space-invaders/resources/Shot.wav" init-sound ] keep 
							 | 
						||
| 
								 | 
							
								  [ SOUND-UFO         "resource:extra/space-invaders/resources/Ufo.wav" init-sound ] keep 
							 | 
						||
| 
								 | 
							
								  [ space-invaders-sounds SOUND-UFO swap nth AL_LOOPING AL_TRUE set-source-param ] keep
							 | 
						||
| 
								 | 
							
								  [ SOUND-BASE-HIT    "resource:extra/space-invaders/resources/BaseHit.wav" init-sound ] keep 
							 | 
						||
| 
								 | 
							
								  [ SOUND-INVADER-HIT "resource:extra/space-invaders/resources/InvHit.wav" init-sound ] keep 
							 | 
						||
| 
								 | 
							
								  [ SOUND-WALK1       "resource:extra/space-invaders/resources/Walk1.wav" init-sound ] keep 
							 | 
						||
| 
								 | 
							
								  [ SOUND-WALK2       "resource:extra/space-invaders/resources/Walk2.wav" init-sound ] keep 
							 | 
						||
| 
								 | 
							
								  [ SOUND-WALK3       "resource:extra/space-invaders/resources/Walk3.wav" init-sound ] keep 
							 | 
						||
| 
								 | 
							
								  [ SOUND-WALK4       "resource:extra/space-invaders/resources/Walk4.wav" init-sound ] keep 
							 | 
						||
| 
								 | 
							
								  [ SOUND-UFO-HIT    "resource:extra/space-invaders/resources/UfoHit.wav" init-sound ] keep
							 | 
						||
| 
								 | 
							
								  f swap set-space-invaders-looping? ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: <space-invaders> ( -- cpu )
							 | 
						||
| 
								 | 
							
								  <cpu> space-invaders construct-delegate
							 | 
						||
| 
								 | 
							
								  make-opengl-bitmap over set-space-invaders-bitmap
							 | 
						||
| 
								 | 
							
								  [ init-sounds ] keep
							 | 
						||
| 
								 | 
							
								  [ reset ] keep ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: play-invaders-sound ( cpu sound -- )
							 | 
						||
| 
								 | 
							
								  swap space-invaders-sounds nth source-play ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: stop-invaders-sound ( cpu sound -- )
							 | 
						||
| 
								 | 
							
								  swap space-invaders-sounds nth source-stop ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: read-port1 ( cpu -- byte )
							 | 
						||
| 
								 | 
							
								  #! Port 1 maps the keys for space invaders
							 | 
						||
| 
								 | 
							
								  #! Bit 0 = coin slot
							 | 
						||
| 
								 | 
							
								  #! Bit 1 = two players button
							 | 
						||
| 
								 | 
							
								  #! Bit 2 = one player button
							 | 
						||
| 
								 | 
							
								  #! Bit 4 = player one fire
							 | 
						||
| 
								 | 
							
								  #! Bit 5 = player one left
							 | 
						||
| 
								 | 
							
								  #! Bit 6 = player one right
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port1 dup HEX: FE bitand ] keep 
							 | 
						||
| 
								 | 
							
								 set-space-invaders-port1 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: read-port2 ( cpu -- byte )
							 | 
						||
| 
								 | 
							
								  #! Port 2 maps player 2 controls and dip switches
							 | 
						||
| 
								 | 
							
								  #! Bit 0,1 = number of ships
							 | 
						||
| 
								 | 
							
								  #! Bit 2   = mode (1=easy, 0=hard)
							 | 
						||
| 
								 | 
							
								  #! Bit 4   = player two fire
							 | 
						||
| 
								 | 
							
								  #! Bit 5   = player two left
							 | 
						||
| 
								 | 
							
								  #! Bit 6   = player two right
							 | 
						||
| 
								 | 
							
								  #! Bit 7   = show or hide coin info
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port2i HEX: 8F bitand ] keep 
							 | 
						||
| 
								 | 
							
								  space-invaders-port1 HEX: 70 bitand bitor ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: read-port3 ( cpu -- byte )
							 | 
						||
| 
								 | 
							
								  #! Used to compute a special formula
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port4hi 8 shift ] keep 
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port4lo bitor ] keep 
							 | 
						||
| 
								 | 
							
								  space-invaders-port2o shift -8 shift HEX: FF bitand ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: space-invaders read-port ( port cpu -- byte )
							 | 
						||
| 
								 | 
							
								  #! Read a byte from the hardware port. 'port' should
							 | 
						||
| 
								 | 
							
								  #! be an 8-bit value.
							 | 
						||
| 
								 | 
							
								  swap {
							 | 
						||
| 
								 | 
							
								    { 1 [ read-port1 ] }
							 | 
						||
| 
								 | 
							
								    { 2 [ read-port2 ] }
							 | 
						||
| 
								 | 
							
								    { 3 [ read-port3 ] }
							 | 
						||
| 
								 | 
							
								    [ 2drop 0 ]
							 | 
						||
| 
								 | 
							
								  } case ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: write-port2 ( value cpu -- )
							 | 
						||
| 
								 | 
							
								  #! Setting this value affects the value read from port 3
							 | 
						||
| 
								 | 
							
								  set-space-invaders-port2o ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: bit-newly-set? ( old-value new-value bit -- bool )
							 | 
						||
| 
								 | 
							
								  tuck bit? >r bit? not r> and ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: port3-newly-set? ( new-value cpu bit -- bool )
							 | 
						||
| 
								 | 
							
								  >r space-invaders-port3o swap r> bit-newly-set? ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: port5-newly-set? ( new-value cpu bit -- bool )
							 | 
						||
| 
								 | 
							
								  >r space-invaders-port5o swap r> bit-newly-set? ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: write-port3 ( value cpu -- )
							 | 
						||
| 
								 | 
							
								  #! Connected to the sound hardware
							 | 
						||
| 
								 | 
							
								  #! Bit 0 = spaceship sound (looped)
							 | 
						||
| 
								 | 
							
								  #! Bit 1 = Shot 
							 | 
						||
| 
								 | 
							
								  #! Bit 2 = Your ship hit
							 | 
						||
| 
								 | 
							
								  #! Bit 3 = Invader hit
							 | 
						||
| 
								 | 
							
								  #! Bit 4 = Extended play sound
							 | 
						||
| 
								 | 
							
								  over 0 bit? over space-invaders-looping? not and [ 
							 | 
						||
| 
								 | 
							
								    dup SOUND-UFO play-invaders-sound 
							 | 
						||
| 
								 | 
							
								    t over set-space-invaders-looping?
							 | 
						||
| 
								 | 
							
								  ] when 
							 | 
						||
| 
								 | 
							
								  over 0 bit? not over space-invaders-looping? and [ 
							 | 
						||
| 
								 | 
							
								    dup SOUND-UFO stop-invaders-sound 
							 | 
						||
| 
								 | 
							
								    f over set-space-invaders-looping?
							 | 
						||
| 
								 | 
							
								  ] when 
							 | 
						||
| 
								 | 
							
								  2dup 0 port3-newly-set? [ dup SOUND-UFO  play-invaders-sound ] when
							 | 
						||
| 
								 | 
							
								  2dup 1 port3-newly-set? [ dup SOUND-SHOT play-invaders-sound ] when
							 | 
						||
| 
								 | 
							
								  2dup 2 port3-newly-set? [ dup SOUND-BASE-HIT play-invaders-sound ] when
							 | 
						||
| 
								 | 
							
								  2dup 3 port3-newly-set? [ dup SOUND-INVADER-HIT play-invaders-sound ] when
							 | 
						||
| 
								 | 
							
								  set-space-invaders-port3o ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: write-port4 ( value cpu -- )
							 | 
						||
| 
								 | 
							
								  #! Affects the value returned by reading port 3
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port4hi ] keep 
							 | 
						||
| 
								 | 
							
								  [ set-space-invaders-port4lo ] keep 
							 | 
						||
| 
								 | 
							
								  set-space-invaders-port4hi ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: write-port5 ( value cpu -- )
							 | 
						||
| 
								 | 
							
								  #! Plays sounds
							 | 
						||
| 
								 | 
							
								  #! Bit 0 = invaders sound 1
							 | 
						||
| 
								 | 
							
								  #! Bit 1 = invaders sound 2
							 | 
						||
| 
								 | 
							
								  #! Bit 2 = invaders sound 3
							 | 
						||
| 
								 | 
							
								  #! Bit 3 = invaders sound 4
							 | 
						||
| 
								 | 
							
								  #! Bit 4 = spaceship hit 
							 | 
						||
| 
								 | 
							
								  #! Bit 5 = amplifier enabled/disabled
							 | 
						||
| 
								 | 
							
								  2dup 0 port5-newly-set? [ dup SOUND-WALK1 play-invaders-sound ] when
							 | 
						||
| 
								 | 
							
								  2dup 1 port5-newly-set? [ dup SOUND-WALK2 play-invaders-sound ] when
							 | 
						||
| 
								 | 
							
								  2dup 2 port5-newly-set? [ dup SOUND-WALK3 play-invaders-sound ] when
							 | 
						||
| 
								 | 
							
								  2dup 3 port5-newly-set? [ dup SOUND-WALK4 play-invaders-sound ] when
							 | 
						||
| 
								 | 
							
								  2dup 4 port5-newly-set? [ dup SOUND-UFO-HIT play-invaders-sound ] when
							 | 
						||
| 
								 | 
							
								  set-space-invaders-port5o ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: space-invaders write-port ( value port cpu -- )
							 | 
						||
| 
								 | 
							
								  #! Write a byte to the hardware port, where 'port' is
							 | 
						||
| 
								 | 
							
								  #! an 8-bit value.  
							 | 
						||
| 
								 | 
							
								  swap {
							 | 
						||
| 
								 | 
							
								    { 2 [ write-port2 ] }
							 | 
						||
| 
								 | 
							
								    { 3 [ write-port3 ] }
							 | 
						||
| 
								 | 
							
								    { 4 [ write-port4 ] }
							 | 
						||
| 
								 | 
							
								    { 5 [ write-port5 ] }
							 | 
						||
| 
								 | 
							
								    [ 3drop ]
							 | 
						||
| 
								 | 
							
								  } case ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: space-invaders reset ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ delegate reset ] keep
							 | 
						||
| 
								 | 
							
								  [ 0 swap set-space-invaders-port1 ] keep
							 | 
						||
| 
								 | 
							
								  [ 0 swap set-space-invaders-port2i ] keep
							 | 
						||
| 
								 | 
							
								  [ 0 swap set-space-invaders-port2o ] keep
							 | 
						||
| 
								 | 
							
								  [ 0 swap set-space-invaders-port3o ] keep
							 | 
						||
| 
								 | 
							
								  [ 0 swap set-space-invaders-port4lo ] keep
							 | 
						||
| 
								 | 
							
								  [ 0 swap set-space-invaders-port4hi ] keep
							 | 
						||
| 
								 | 
							
								  0 swap set-space-invaders-port5o ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: gui-step ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ read-instruction ] keep ! n cpu
							 | 
						||
| 
								 | 
							
								  over get-cycles over inc-cycles
							 | 
						||
| 
								 | 
							
								  [ swap instructions case ] keep  
							 | 
						||
| 
								 | 
							
								  [ cpu-pc HEX: FFFF bitand ] keep 
							 | 
						||
| 
								 | 
							
								  set-cpu-pc ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: gui-frame/2 ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ gui-step ] keep
							 | 
						||
| 
								 | 
							
								  [ cpu-cycles ] keep
							 | 
						||
| 
								 | 
							
								  over 16667 < [ ! cycles cpu
							 | 
						||
| 
								 | 
							
								    nip gui-frame/2
							 | 
						||
| 
								 | 
							
								  ] [
							 | 
						||
| 
								 | 
							
								    [ >r 16667 - r> set-cpu-cycles ] keep
							 | 
						||
| 
								 | 
							
								    dup cpu-last-interrupt HEX: 10 = [
							 | 
						||
| 
								 | 
							
								      HEX: 08 over set-cpu-last-interrupt HEX: 08 swap interrupt
							 | 
						||
| 
								 | 
							
								    ] [
							 | 
						||
| 
								 | 
							
								      HEX: 10 over set-cpu-last-interrupt HEX: 10 swap interrupt
							 | 
						||
| 
								 | 
							
								    ] if     
							 | 
						||
| 
								 | 
							
								  ] if ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: gui-frame ( cpu -- )
							 | 
						||
| 
								 | 
							
								  dup gui-frame/2 gui-frame/2 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: coin-down ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port1 1 bitor ] keep set-space-invaders-port1 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: coin-up ( cpu --  )
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port1 255 1 - bitand ] keep set-space-invaders-port1 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: player1-down ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port1 4 bitor ] keep set-space-invaders-port1 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: player1-up ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port1 255 4 - bitand ] keep set-space-invaders-port1 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: player2-down ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port1 2 bitor ] keep set-space-invaders-port1 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: player2-up ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port1 255 2 - bitand ] keep set-space-invaders-port1 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: fire-down ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port1 HEX: 10 bitor ] keep set-space-invaders-port1 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: fire-up ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port1 255 HEX: 10 - bitand ] keep set-space-invaders-port1 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: left-down ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port1 HEX: 20 bitor ] keep set-space-invaders-port1 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: left-up ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port1 255 HEX: 20 - bitand ] keep set-space-invaders-port1 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: right-down ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port1 HEX: 40 bitor ] keep set-space-invaders-port1 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: right-up ( cpu -- )
							 | 
						||
| 
								 | 
							
								  [ space-invaders-port1 255 HEX: 40 - bitand ] keep set-space-invaders-port1 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								TUPLE: invaders-gadget cpu quit? ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								invaders-gadget H{
							 | 
						||
| 
								 | 
							
								    { T{ key-down f f "ESC" }    [ t swap set-invaders-gadget-quit? ] }
							 | 
						||
| 
								 | 
							
								    { T{ key-down f f "BACKSPACE" } [ invaders-gadget-cpu coin-down ] }
							 | 
						||
| 
								 | 
							
								    { T{ key-up   f f "BACKSPACE" } [ invaders-gadget-cpu coin-up ] }
							 | 
						||
| 
								 | 
							
								    { T{ key-down f f "1" }         [ invaders-gadget-cpu player1-down ] }
							 | 
						||
| 
								 | 
							
								    { T{ key-up   f f "1" }         [ invaders-gadget-cpu player1-up ] }
							 | 
						||
| 
								 | 
							
								    { T{ key-down f f "2" }         [ invaders-gadget-cpu player2-down ] }
							 | 
						||
| 
								 | 
							
								    { T{ key-up   f f "2" }         [ invaders-gadget-cpu player2-up ] }
							 | 
						||
| 
								 | 
							
								    { T{ key-down f f "UP" }        [ invaders-gadget-cpu fire-down ] }
							 | 
						||
| 
								 | 
							
								    { T{ key-up   f f "UP" }        [ invaders-gadget-cpu fire-up ] }
							 | 
						||
| 
								 | 
							
								    { T{ key-down f f "LEFT" }      [ invaders-gadget-cpu left-down ] }
							 | 
						||
| 
								 | 
							
								    { T{ key-up   f f "LEFT" }      [ invaders-gadget-cpu left-up ] }
							 | 
						||
| 
								 | 
							
								    { T{ key-down f f "RIGHT" }     [ invaders-gadget-cpu right-down ] }
							 | 
						||
| 
								 | 
							
								    { T{ key-up   f f "RIGHT" }     [ invaders-gadget-cpu right-up ] }
							 | 
						||
| 
								 | 
							
								  } set-gestures 
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: <invaders-gadget> ( cpu -- gadget ) 
							 | 
						||
| 
								 | 
							
								  invaders-gadget construct-gadget
							 | 
						||
| 
								 | 
							
								  [ set-invaders-gadget-cpu ] keep
							 | 
						||
| 
								 | 
							
								  f over set-invaders-gadget-quit? ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: invaders-gadget pref-dim* drop { 224 256 0 } ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: invaders-gadget draw-gadget* ( gadget -- )
							 | 
						||
| 
								 | 
							
								  0 0 glRasterPos2i
							 | 
						||
| 
								 | 
							
								  1.0 -1.0 glPixelZoom
							 | 
						||
| 
								 | 
							
								  >r 224 256 GL_RGB GL_UNSIGNED_BYTE r>
							 | 
						||
| 
								 | 
							
								  invaders-gadget-cpu space-invaders-bitmap glDrawPixels ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: black { 0 0 0 } ;
							 | 
						||
| 
								 | 
							
								: white { 255 255 255 } ;
							 | 
						||
| 
								 | 
							
								: green { 0 255 0 } ;
							 | 
						||
| 
								 | 
							
								: red   { 255 0 0 } ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: addr>xy ( addr -- point )
							 | 
						||
| 
								 | 
							
								  #! Convert video RAM address to base X Y value. point is a {x y}.
							 | 
						||
| 
								 | 
							
								  HEX: 2400 - ! n
							 | 
						||
| 
								 | 
							
								  dup HEX: 1f bitand 8 * 255 swap - ! n y
							 | 
						||
| 
								 | 
							
								  swap -5 shift swap 2array ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: plot-bitmap-pixel ( bitmap point color -- )
							 | 
						||
| 
								 | 
							
								  #! point is a {x y}. color is a {r g b}.
							 | 
						||
| 
								 | 
							
								  spin set-bitmap-pixel ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: within ( n a b -- bool )
							 | 
						||
| 
								 | 
							
								  #! n >= a and n <= b
							 | 
						||
| 
								 | 
							
								  rot tuck swap <= >r swap >= r> and ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: get-point-color ( point -- color )
							 | 
						||
| 
								 | 
							
								  #! Return the color to use for the given x/y position.
							 | 
						||
| 
								 | 
							
								  first2
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    { [ dup 184 238 within pick 0 223 within and ] [ 2drop green ] }
							 | 
						||
| 
								 | 
							
								    { [ dup 240 247 within pick 16 133 within and ] [ 2drop green ] }
							 | 
						||
| 
								 | 
							
								    { [ dup 247 215 - 247 184 - within pick 0 223 within and ] [ 2drop red ] }
							 | 
						||
| 
								 | 
							
								    [ 2drop white ]
							 | 
						||
| 
								 | 
							
								  } cond ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: plot-bitmap-bits ( bitmap point byte bit -- )
							 | 
						||
| 
								 | 
							
								  #! point is a {x y}.
							 | 
						||
| 
								 | 
							
								  [ first2 ] 2dip
							 | 
						||
| 
								 | 
							
								  dup swapd -1 * shift 1 bitand 0 =
							 | 
						||
| 
								 | 
							
								  [ - 2array ] dip
							 | 
						||
| 
								 | 
							
								  [ black ] [ dup get-point-color ] if
							 | 
						||
| 
								 | 
							
								  plot-bitmap-pixel ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: do-bitmap-update ( bitmap value addr -- )
							 | 
						||
| 
								 | 
							
								  addr>xy swap 
							 | 
						||
| 
								 | 
							
								  [ 0 plot-bitmap-bits ] 3keep
							 | 
						||
| 
								 | 
							
								  [ 1 plot-bitmap-bits ] 3keep
							 | 
						||
| 
								 | 
							
								  [ 2 plot-bitmap-bits ] 3keep
							 | 
						||
| 
								 | 
							
								  [ 3 plot-bitmap-bits ] 3keep
							 | 
						||
| 
								 | 
							
								  [ 4 plot-bitmap-bits ] 3keep
							 | 
						||
| 
								 | 
							
								  [ 5 plot-bitmap-bits ] 3keep
							 | 
						||
| 
								 | 
							
								  [ 6 plot-bitmap-bits ] 3keep
							 | 
						||
| 
								 | 
							
								  7 plot-bitmap-bits ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: space-invaders update-video ( value addr cpu -- )  
							 | 
						||
| 
								 | 
							
								  over HEX: 2400 >= [
							 | 
						||
| 
								 | 
							
								    space-invaders-bitmap -rot do-bitmap-update
							 | 
						||
| 
								 | 
							
								  ] [
							 | 
						||
| 
								 | 
							
								    3drop
							 | 
						||
| 
								 | 
							
								  ] if ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: sync-frame ( millis -- millis )
							 | 
						||
| 
								 | 
							
								  #! Sleep until the time for the next frame arrives.
							 | 
						||
| 
								 | 
							
								  1000 60 / >fixnum + millis - dup 0 >
							 | 
						||
| 
								 | 
							
								  [ threads:sleep ] [ drop threads:yield ] if millis ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: invaders-process ( millis gadget -- )
							 | 
						||
| 
								 | 
							
								  #! Run a space invaders gadget inside a 
							 | 
						||
| 
								 | 
							
								  #! concurrent process. Messages can be sent to
							 | 
						||
| 
								 | 
							
								  #! signal key presses, etc.
							 | 
						||
| 
								 | 
							
								  dup invaders-gadget-quit? [
							 | 
						||
| 
								 | 
							
								    2drop
							 | 
						||
| 
								 | 
							
								  ] [
							 | 
						||
| 
								 | 
							
								    [ sync-frame ] dip
							 | 
						||
| 
								 | 
							
								    [ invaders-gadget-cpu gui-frame ] keep
							 | 
						||
| 
								 | 
							
								    [ relayout-1 ] keep
							 | 
						||
| 
								 | 
							
								    invaders-process 
							 | 
						||
| 
								 | 
							
								  ] if ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: invaders-gadget graft* ( gadget -- )
							 | 
						||
| 
								 | 
							
								  dup invaders-gadget-cpu init-sounds
							 | 
						||
| 
								 | 
							
								  f over set-invaders-gadget-quit?
							 | 
						||
| 
								 | 
							
								  [ millis swap invaders-process ] curry
							 | 
						||
| 
								 | 
							
								  "Space invaders" threads:spawn drop ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: invaders-gadget ungraft* ( gadget -- )
							 | 
						||
| 
								 | 
							
								 t swap set-invaders-gadget-quit? ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: (run) ( title cpu rom-info -- )
							 | 
						||
| 
								 | 
							
								  over load-rom* <invaders-gadget> swap open-window ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: run ( -- )  
							 | 
						||
| 
								 | 
							
								  "Space Invaders" <space-invaders> {
							 | 
						||
| 
								 | 
							
								    { HEX: 0000 "invaders/invaders.h" }
							 | 
						||
| 
								 | 
							
								    { HEX: 0800 "invaders/invaders.g" }
							 | 
						||
| 
								 | 
							
								    { HEX: 1000 "invaders/invaders.f" }
							 | 
						||
| 
								 | 
							
								    { HEX: 1800 "invaders/invaders.e" }
							 | 
						||
| 
								 | 
							
								  } [ (run) ] with-ui ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								MAIN: run
							 |