=========================================================================

JV Enterprises is proud to release to Freeware a modified version 
of the Towers II graphic engine.

 Written by: Vince Valenti
(c)1993-1996 JV Enterprises
Ver. 1.1


You may use this engine in any application/game that you are making, 
free of charge, as long as you give credit to Vince and JV Enterprises
in the code and manual, and you only include the Object file in your 
program.  The credits in the code can be included in the
Title screen, Information box, or where credit is given to the 
programmer(s) for the application/game that is using this engine.

You may make any change to the source, but you may not distribute any 
modified source code as part of this archive, and you may not charge 
for the source or object code, modified or unmodified.
PD houses may charge the nominal fee for the disc and shipping.

Okay Now that's out of the way... ENJOY...

-------------------------------------------------------------------------

This Archive comes with four files.

Falc_eng.obj		This is the file you will include in you GFA,
			C, or Assembly program.
Falc_eng.is		This is the tokenized version of the source
			for GFA Assembly
Falc_eng.asm		This is an ASCII version of the source for
			GFA assembly.
Falc_eng.txt		This file.  :)


The Falcon Engine is a 2D and 3D graphic engine with a modified bubble 
sort routine, and a Y axis Rotate and X,Z,Y Translate routine.

All the routines are designed to be called from GFA Basic.  However, you
can call them from assembly or C.  All calls are passed via the stack.
In assembly you must reverse the order in which you place data into the
stack.  ie...

	~C:code_falc_eng%(L:a&,L:a%,W:b&)
	
would be passed to assembly as:
	
	move.w	word_b,-(sp)
	move.l  long_a,-(sp)
	move.w	word_a,d0
	ext.l	d0
	move.l	d0,-(sp)
	jsr	code_falc_eng
	add.w	#10,sp
	
-------------------------------------------------------------------------

This code was never meant to be released as an engine, so there might be
some examples that look strange, sorry.  :)

You can call all the routines via the ~C: command in GFA basic.  Please 
make sure that if you see (L:a&) that you include the 'L:' and that
you pass a WORD Value 'xxxx&' through.  Several routines do not handle
values larger than a word an can produce unpredicable results if the value
is larger. Routines that can handle longwords will look like this: 
(L:a%)

With the ~C: command you may not pass ~C:asm%+28(...), so all the
examples will include this:	stuff%=asm%+28
				~C:stuff%(...)
				
Remember that you only need to define stuff%, for this example, at the
beginning of you code, and you don't have to define it every time you
call stuff%.  	


=========================================================================
-------------------------------------------------------------------------

Here is the list of routines provided with the Falcon Engine.


;  --- General purpose routines    ---
             aseven               ;+28 Jump to find out stack value
             mouse_hand           ;+32 Jump for mouse handler

;  --- 2D TC block routines        ---
             rput                 ;+36 jump to replace put
             rputp                ;+40 Jump to replace put part
             tput                 ;+44 jump to trans put
             typut                ;+48 jump to trans 2X put w/ y-clip
             blkget               ;+52 jump to block get
             backput              ;+56 Jump for background put

;  --- TC full screen routines     ---
             clear                ;+60 jump to clear screen
             fade                 ;+64 jump to fade (log to phy) routine
             fade2                ;+68 Jump for fade effects (log to log)

;  --- 3D scale and T-map routines ---
             scaleput             ;+72 jump to trans scale put
             wallput              ;+76 jump to wall only texture map 
             mapput               ;+80 jump to texture map

;  --- 3D rotate and sort routines ---
             sound_trans          ;+84 Jump to sound translate
             y_rot_trans          ;+88 jump to rotate and translate
             zsort                ;+92 jump to z-sort w/offset calc

;  --- Misc config variables       ---
brite:        WORD                ;+96 FADE variable 0=off (def. 0)
y_value1:     WORD                ;100 max y		   (def. 200)
y_value2:     WORD                ;102 max y-1		   (def. 199)



To use the Falcon engine in GFA basic, you can include with the basic 
code like so:

	INLINE code_start%,10118

Then Press HELP with the cursor on that line.  You will get a menu at 
the top of the screen.  Click on load and find FALC_ENG.OBJ, then 
click on OK.  The file will now be included with every SAVE of your 
GFA Basic code.  Make sure you don't SAVE,A as an ASCII save will not 
save INLINEs.


There will be several example variables that will be used...
	
	ret%		Return Variable from call
	addr_block%	Starting location of 2D block graphic w/header
			WORD{addr_block%}       =   X 
			WORD{addr_block%+2}     =   Y
			WORD{addr_block%+4}...  =   graphic data
			You can use BLKGET to get a 2D graphic in this
			format into memory
	addr_screen%	Starting address of either the logical or
			physical screen.
	addr_log%	Starting address of the logical screen
	addr_phy%	Starting address of the physical screen
	degrees&	Angle that player is facing must be 0-359 ONLY!
	addr_mem%	Any buffer, including block, screen or 
			variable.
		

Variables and Arrays for 3D transformation and sorting functions
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	addr_vect%	starting address of the vector table array
			[ie.  DIM vectors&(2,M) ]
			              0=x 1=y 2=z  
			M is the max number of vectors you will have
			copied at any given time.
	
	num_of_vect&	Is the current number of vectors you want to 
			rotate in this game loop
	
	addr_lookup%	starting address of the lookup table array
			[ie.  DIM lookup&(3,M2) ]
			    R/W 0=Graphic Value (<256 4vect , =>256 2vect)
			      R 1=Vect offset in bytes (set by Zsort)
			    R/W 2=Misc value  (extra)
			      R 3=Ave Z value (set by Zsort)
			M2 is the max number of Objects you will have
			copied at any given time.
	
	addr_groff%	starting address of the graphic block array.
			[ie.   DIM graph_offset%(M2) ]
			M2 is the max number of Objects, same as 
			lookup&().
			
	num_of_obj&	Is the current number of Objects you want to
	 		manipulate in this game loop

- - - - - - - - - - - - - - -


When making a logical or physical screen please make sure to pad it
for clipping errors. (sorry) Leave about 2000 bytes above and below
the actual start of the screen address (log or phy)

	DIM log%(33000)
	addr_log%=V:log%(0)+2048	

This sets up a 132000 byte buffer with appx 2000 byte pads on both 
sides.



-------------------------------------------------------
General Purpose Routines
-------------------------------------------------------

A-Seven routine
- - - - - - - -
	code_aseven%=code_start%+28
	ret%=C:code_aseven%()
	
This routine returns the stack pointer in the ret% variable.


Mouse Handler routine
- - - - - - - - - - -
	code_mouse_hand%=code_start%+32
	ret%=C:code_mouse_hand%()

This routine returns the starting address for the data and interrupt
routine if you ever wish to use this in place of the standard routine.
This routine will disable any mouse accelerator, and can slow the 
mouse down even more if you wish.

	WORD{ret%}	=	Mouse Button State (1=rht 2=lft 3=bth) 
	WORD{ret%+2}	=	X value
	WORD{ret%+4}	=	Y value
	WORD{ret%+6}	=	Slowdown value (0=norn  1=1/2  2=1/4)
	ret%+8		=	start of the interrupt handler routine

This routine will replace the GEM mouse handler.  You can install it 
with:
	ret%=C:code_mouse_hand%()
	addr_mouse%=XBIOS(34)
	ADD addr_mouse%,16
	old_mouse%=LPEEK(addr_mouse%)
	SLPOKE (addr_mouse%),ret%+8

Before you exit your program you must restore the mouse with:
	
	SLPOKE (addr_mouse%),old_mouse%
	
To read the mouse just use: a&=WORD{ret%+2}  this will give you the X 
screen coords. for the mouse.  This handler does NOT do any clipping, 
and will count from -30000 to +30000, you will have to make sure the 
mouse does not go passed 320 or get smaller than 0, by poking directly
to it like: IF WORD{ret%+2}<0 THEN WORD{ret%+2}=0


-------------------------------------------------------
2D True Color Block routines
-------------------------------------------------------

Replace Put routine
- - - - - - - - - -
	code_rput%=code_start%+36
	~C:code_rput%(L:x&,L:y&,L:addr_block%,L:addr_screen%)
	
This routine places a 2D graphic on the screen at X,Y.  This routine 
does NOT do any clipping and can write anywhere in memory!


Replace Put Part routine
- - - - - - - - - - - - -
	code_rputp%=code_start%+40
	~C:code_rputp%(L:x&,L:y&,L:addr_block%,L:addr_screen%,W:part&)

This routine places a 2D graphic on the screen at X,Y.  It will draw
the graphic from X to X+part&.  This routine would be good for a bar
graphic where the bar drops slowly as your health drops or something. 
:)  Other than part&, this routine has NO clipping.


Transparent Put routine
- - - - - - - - - - - -
	code_tput%=code_start%+44
	~C:code_tput%(L:x&,L:y&,L:addr_block%,L:addr_screen%)
	
This routine places a 2D graphic on the screen at X,Y.  Any block 
pixel equaling '0' will not be drawn and hence transparent. This 
routine has NO clipping.


Transparent 2X Put routine w/Y clipping	[effected by: y_value(1&2)]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
	code_typut%=code_start%+48
	~C:code_typut%(L:x&,L:y&,L:addr_block%,L:addr_screen%)

This routine places a 2D graphic on the screen at X,Y.  works like
Transparent Put, plus it doubles the width of the graphic on the 
screen.  Also, any value greater than Y_VALUE(1&2) is not drawn. It
also clips at X>319.


Block Get routine
- - - - - - - - -
	code_blkget%=code_start%+52
	~C:code_blkget%(L:x&,L:y&,W:xl&,W:yl&,L:addr_block%,L:addr_screen%)

This routine captures a 2D graphic from X,Y to X+xl,Y+yl, and puts it
into the header starting at ADDR_BLOCK%.  xl& will be rounded down to 
the next even number.  (eg. 3 to 2,  7 to 6)


Background Put routine
- - - - - - - - - - - -
	code_backput%=code_start%+56
	~C:code_backput%(W:degrees&,W:y&,L:addr_block%,L:addr_screen%)
	
This wraps at 2D graphic that is 320x???, and puts it onto the screen 
at 0,Y.  The graphic MUST be 320 X.  It will roll the graphic based on
what degrees& is. This routine does NOT clip.


-------------------------------------------------------
True Color Full Screen Routines
-------------------------------------------------------


Clear Memory/Screen Routine
- - - - - - - - - - - - - -
	code_clear%=code_start%+60
	~C:code_clear%(L:addr_mem%,L:num_of_byte%)
	
Puts zero for x number of bytes.  Rounds down num_of_byte% to the 
nearest unit of 64.  Make sure you have ENOUGH MEMORY in your buffer, 
or you may overwrite memory!


Fade from Logical to Physical	  [effected by: y_value(1&2)]
- - - - - - - - - - - - - - -
	code_fade%=code_start%+64
	~C:code_fade%(L:addr_log%,L:addr_phy%,W:mode&)
	
This routine fade graphic data from the logical to the physical 
address.  From black to graphic, mode& is positive (0 to 4).  From 
graphic to black, mode& is negative (0 to -4). Any Y greater than
Y_VALUE will not be touched.


Effects Fade on Screen		[effected by: y_value(1&2)]
- - - - - - - - - - - -
	code_fade2%=code_start%+68
	~C:code_fade2%(L:addr_screen%,W:fade&,W:mode&)
	
This routine washes any graphic currently on the screen to several 
colors.  fade& increases the wash.  mode& sets the color.
		mode&=0		wash to black  (fade& 0-4)
		mode&=1		wash to white  (fade& 4-0)
		mode&=2		wash to red    "         "
		mode&=3		wash to green  "         "
		mode&=4		wash to blue   "         "

Any screen location lower than the Y value set in Y_VALUE(1&2) will 
not be touched.


-------------------------------------------------------
3D True Color Scale and Texture Map routines
-------------------------------------------------------


Transparent Scaled Put routine	 [effected by: y_value(1&2),brite]
- - - - - - - - - - - - - - - -
	code_scaleput%=code_start%+72
	~C:code_scaleput%(L:bcx&,L:by&,L:ty&,L:addr_block%,L:addr_screen%)
	
This routine scales a 2D graphic a puts it on the screen at BCX,BY
(bottom-center-X, bottom-Y).  Unlike the other 2D routines, this 
routine does not start at the top-left corner of the screen, but 
on the bottom-center.  This makes it easy in 3D environments to find 
the floor of the graphic when drawn.
				
				tcx,ty (1)
				|
				|
				bcx,by (2)

It handles ALL clipping from 0-320 X and 0-y_value Y.  If BRITE is set 
to something other than 0, fading to black will occur when the graphic 
gets smaller.

TY, the top-Y position, is used as a scale value, so the routine 
knows when to shrink or enlarge the graphic. This will only handle 
graphics that are 16, 32, or 64 pixels wide.


Textured Wall Map routine      [effected by: y_value(1&2),brite]
- - - - - - - - - - - - -
	code_wallput%=code_start%+76
	~C:wallput%(L:x1&,L:x3&,L:y2&,L:y4&,L:y1&,L:y3&,L:addr_block%,
		L:addr_screen%,W:door&)
		
This routine takes a 2D graphic and shapes it into the coords. given.
This routine is for walls only, that is x1 & x2 are the same and x3 
& x4 are the same.  3   1                      1
		  /|     |\                   /|
		1/ |	 | \3               3/ |
	    	 | |	 | |Normal           | | Backfaced
		2\ |	 | /4               4| |
		  \|4   2|/                   \|2

The routines then fills this area with the texture at ADDR_BLOCK%.
It handles all clipping from 0-320 X and 0-y_value Y. If BRITE is 
anything other than 0, the graphic fades to black as it gets smaller.
DOOR& is used to simulate an open door. if DOOR&=0 the full graphic is 
drawn.  As DOOR& grows to 64 it becomes less, and less visible leaving 
a space open, like a sliding door.

This routine will only handle 2D graphics that are 64x64. If in the 2D 
graphic header you replace the XL (WORD{addr_block%}=0) from 64 to 0, 
this routine will make that graphic transparent, and any pixel on the 
graphic that is black(0) will not be drawn leaving a hole.  This is 
great if you want to simulate a window or gate in your texture.

If at any time x3 < x1 that is called backfacing, and this routine 
will not draw it.


Texture Map routine		[effected by: y_value(1&2)]
- - - - - - - - - -
	code_mapput%=code_start%+80
	~C:code_mapput%(W:x1&,W:y1&,W:x2&,W:y2&,W:x3&,W:y3&,W:x4&,
		W:y4&,L:addr_block%,L:addr_screen%)
		
This is the slowest of the 3D routines, but it can texture any CONVEX 
4 vector polygon.       1    4             /\1
			\\  //            /  \
			 \\3/ Concave    2\  /3 Convex
			  \/               \/
			  2                4

It handles all Clipping from 0-320 X and 0-y_value Y.  It only works 
with 64x64 2D graphics.


-------------------------------------------------------
3D Rotate and Sort routines
-------------------------------------------------------

I was not going to include this, but sorting and rotating in GFA or C 
can be slow.  So I inlcuded the sort, transform and rotate commands.

NOTE:  These routines were designed for Objects with the vectors 256 
units away or closer.  May produce strange results when ave Z < 0 and 
the vectors are >256 units apart. (These terms will be explained 
later)


Sound Rotate
- - - - - - -
	code_sound_trans%=code_start%+88
	ret%=C:code_sound_trans%(W:x&,W:z&,W:degrees&,W:xs&,W:zs&)
	
This routine modifies xs&,zs& and returns it rotated and translated in 
ret%.  The hiword in ret% is X and the loword in ret% is Z.  Great for 
creating 3D or stereo sound.


Y Rotate and XYZ translate routine
- - - - - - - - - - - - - - - - - -
	code_y_rot_trans%=code_start%+92
	~C:code_y_rot_trans%(L:x&,L:z&,W:num_of_vect&,W:degrees&,
		L:addr_vect%,W:y_off&,W:y&)
		
WOW!  Lots of stuff here!  This routine, Y-axis rotates, and 
translates each vector in an array that starts at addr_vect&, and then
converts it to U & V screen coord. Don't worry about the names U and 
V, they just mean a 2D X & Y.  The names of the variables change so 
you don't confuse X in the 3D coord. system with X in the 2D coord. 
system.  This is the only place I will use U&V, all the previous 
routines use the 2D X and Y.

x&,y&, and z& is your absolute position in the 3D world.  addr_vect% 
is the starting address of an array set up in GFA. The array must be
a word value array with any number of max vectors 
	
	DIM vectors&(2,M)    ! M=max vectors

The array conatains absolute positions (X,Y,Z) of each vector up to 
num_of_vect&.  The routine then converts all the vectors and changes 
them to (U,V,RZ).  The RZ (relative Z) is preserved so that we can 
Z-sort later.  The values U and V can then be taken directly to the 
3D drawing routines as X and Y.  

NOTE: You will need either 2 or 4 sets of U,V (ie. vectors) depending 
on what 3D routine you use.  The Wall Map and Texture Map require 
4 vectors, while the Scale Put only requires 2 vectors.

Y_OFF& is used to offset the horizon on the screen, Usually the 
horizon is at y=0, but thats at the top of the screen, increase this 
number to drop the horizon.  (I used 39)

Y& in Towers II was set to 80. If is was set to 0, you would be 
hitting the ceiling and 300 or so and you would be crawling on the 
ground.

Make sure the that array vectors&() is not your master vector table.
Copy only the vectors you know can be displayed on the screen from the
master vector table.  If you use vectors&() as the master vector 
table, it will start to corrupt after several calculations.  That is 
becuase rounding errors add up and corrupts the data.  Also, don't 
copy the whole table.  It takes an exponential amount of time to 
rotate and sort.  If you have a real big 3D world you can't see all 
of it!  Don't copy the vectors you know you can't see.  


2/4 Vector Z-average and Z-sort routine
- - - - - - - - - - - - - - - - - - - -
	code_zsort%=code_start%+92
	~C:code_zsort%(L:addr_lookup%,L:addr_vect%,L:addr_groff%,
		W:num_of_obj&)
		
This one is just a difficult to explain as the Rotate routine.
You should always run this routine AFTER you run the Rotate routine 
above.

The routine works with the vectors&() array in the previous example, 
and first calculates an offset and an ave. z-value, and puts it into the 
lookup&() array.  Then it Z-sorts by the ave. z-value and reorganizes 
according to the Z-value, lookup&() and graph_offset%() arrays.

	DIM graph_offset%(M2),lookup&(3,M2)  !M2 = max number of objects
	DIM vectors&(2,M)     ! M = max number of vectors (same as 
			      ! previous example)
	addr_vect%=V:vectors&(0,0)
	addr_lookup%=V:lookup&(0,0)
	addr_groff%=V:graph_offset%(0)
	
Before you run either this routine or the previous one, you need to 
copy the vectors and data into these arrays.  Depending if you have a 
2-Vector Object or a 4-Vector Object, you add the information in.  
ADDR_LOOKUP% is the starting address of lookup&() array.  the 
lookup&() array is arranged like so:

		R/W=Read/Write	R=Read Only
	
	    R/W 0=Graphic Value (<256 4vect , =>256 2vect)
	      R 1=Vect offset in bytes (set by Zsort)
	    R/W 2=Misc value  (extra)
	      R 3=Ave Z value (set by Zsort)
 
You only have to enter data in (0,x) and (2,x).  You can add anything 
you like in (2,x), but in (0,x) you need to keep to the following 
guidelines.  (0,x) is the Graphic Value, if your object is a Wall or 
Texture then you need 4 vectors and the Graphic Value (0,x) must be 0-255.
If the object is a Scale graphic then the Graphic Value (0,x) must be
256 or greater.  NOTE: Do this before you run Zsort or the Rotate 
routines!

   2 Vector Object example	        4 Vector Object example
   - - - - - - - - - - - -	        - - - - - - - - - - - -
   vector&(0,count&)=x1			vector&(0,count&)=x1
   vector&(1,count&)=y1			vector&(1,count&)=y1
   vector&(2,count&)=z1			vector&(2,count&)=z1
   
   vector&(0,count&+1)=x2		vector&(0,count&+1)=x2
   vector&(1,count&+1)=y2		vector&(1,count&+1)=y2
   vector&(2,count&+1)=z2		vector&(2,count&+1)=z2
   
   lookup&(0,obj_cnt&)=300		vector&(0,count&+2)=x3
   lookup&(2,obj_cnt&)=RANDOM(100)	vector&(1,count&+2)=y3
   graph_offset%(obj_cnt&)=addr_block%	vector&(2,count&+2)=z3
   ADD count&,2
   INC obj_cnt& 			vector&(0,count&+3)=x4
   					vector&(1,count&+3)=y4
   					vector&(2,count&+3)=z4
	
	      				lookup&(0,obj_cnt&)=5
	      				lookup&(2,obj_cnt&)=RANDOM(100)
	      				graph_offset%(obj_cnt&)=addr_block%
					ADD count&,4
					INC obj_cnt&
					
Needless to say, that copying vectors and objects this way will not
produce the fastest code, but this is just an example.  You could 
easily BMOVE the data or use {addr_vect%} instead.  But you get the 
idea.  I ended up creating an assembly routine just to do all of this,
but Towers II was set up kinda strange.  :)

When Making List make sure the order is correct, a 2 vector list 
should look like this:
				1
				|
				|
				2
				
While a 4 vector list should be ordered like this:

			1 +----+ 3
			  |    |
			2 +----+ 4
			
The RANDOM command was used to demonstrate that it does not matter what
the number is, and the object number '5' could have been anything 
under 256.  Also, graph_offset%(), as seen in the example, is the 
starting address of the texture map that you want hooked to this 
object.

Once you have this set up, run the Rotate routine to rotate the world, 
then run this routine.  After you have done so, you will notice that 
lookup&(1,x) is filled with a number.  That number is the start of the 
vector list for this object.  It is represented in bytes.  To find the 
first value, just add it to addr_vect%.  
	
	x1=WORD{addr_vect%+lookup&(1,x)}
		or
	x1=vectors&(0,lookup&(1,x) DIV 6)
	
Also, lookup&(3,x) will also be filled.  That is the average Z Value 
for that object.  The larger the number the further away from you the 
object is.  As you run down the list of objects you will notice that 
the Z-value gets smaller and smaller.  If the average Z value is 
smaller than -49, then DONT draw it since it's behind you.



-------------------------------------------------------
Misc. Config Variables
-------------------------------------------------------

brite:        WORD               
- - - - - - - - - -
	addr_brite%=code_start%+96
	WORD{addr_brite%}=x
	
This sets the global variable BRITE for any routine effected by this 
variable.  This variable sets the fade routine On or OFF.

	x=0		OFF    (Default)
	x=-1 to -4	Start fading closer
	x= 1 to  4	Start fading further


y_value1:     WORD                Default = 200
y_value2:     WORD                Default = 199
- - - - - - - - - -
	addr_y_value%=code_start%+100
	WORD{addr_y_value%}=x
	WORD{addr_y_value%+2}=x-1
	
This sets the global variable Y_VALUE1 and Y_VALUE2 for any routine 
effected by this variable.  This changes the clipping value of Y.  
Y_VALUE2 MUST be one less than Y_VALUE1 or unpredictable results may 
occur.
	
Lets say you are making a game in 320x200 TC.  And you want the last 
40 scan lines for information.  You can set Y_value1 to 160 and 
Y_value2 to 159.  From this point all routines effected by these 
variables will clip at 160-199 and only draw from 0-159.