FILLED VECTORS (PART 2)


In the previous issue, we've seen how double buffer works, how to rotate 3D points on all 3 axis and how to do a zoom. In this article, we'll see the z-sorting and how to draw using the blitter.

Z-SORTING

This routine is used to give a drawing priority to the faces; our object could be rotated in any way, and it will always be displayed correctly.

Removing hidden surfaces is based upon very specific algos, not very easy to implement and rarely executed with the needed speed. Removing hidden faces is divided into two parts. First one, removes the hidden faces. They are so called because they cannot be seen from observer; to find them you have just to compute the degree formed from the normal to the sourface and by the vector of the view. If this degree is between 90 and -90, the face will be visible; if the result is greater than 90 or minor than -90, the face is hidden.

To compute the normal to the surface, you have just to compute Once deleted invisible faces, you'll have to draw visible ones in a correct way. For this task two algos exist: the z-buffering and the painter algo. Both of them cannot be implemented inside a demo in a standard way, following you'll see how to implement them.

Z-buffering algo is so composed:

-  From a face's coords, you have to compute Z value for every X,Y and memorize it inside a     
   buffer 
-  Find the Z value closer to the observer, check this value with the one contained inside the
   Z buffer (with the same X and Y) and if it is closer to the observer, it will replace the current 
   value.
- Now for any X,Y coordinate we have a Z value (the one nearest to the observer) and the pixel color, you just have to      draw it.

Painter algo is based upon a series of checks :

1 - Extensions on X axe of two faces overlap ?
     If no-> end of checks, drawing priority does not matters.
     If yes-> check 2.
2 - Extensions on Y axe of two faces overlap ?
     If no-> end of controls.
     If yes-> check 3.
3&4 - Extend a polygon widely and you'll have a surface : the other polygon
is completely on the other part ?
If yes -> end of checks.
If no-> check 5.
5 - Now we know faces are in the wrong position : we'll have to swap them.

These algos are very computing-demanding, and our beloved Amigas haven't a PowerPC 604/200Mhz, so I do not suggets to anyone to use one of the above algos, and to give a look to the one I do introduce.

The following is not an algo of mine but just a modification I made to make it as fast as possibkle.

We can divide the algo into two parts. The first one takes all points making a face, sums all Z values and divide the result for the number of points (Z factor).

The second part sorts faces so that much far to the observer are rendered first. So, if an objects obscures another one, we will not have any problem : we'll see our object before all the rest.

Imagine not to use this algo : objects would be rendered always with the same priority... in a wood of trees, the foremost tree must be appear before the rest (so it has to be drawn as last). With a fixed order, everything would work until we do not begin to rotate inside this wood : then priority has to be changed. This is a typical example of when to use a Z sort algo.

Warning : you do not need it always.

There are situations when you can get rid of the Z sort, saving a lot of CPU time : in these cases drawing priorities is irrilevant. We have said that you can avoid sorting with some objects : first of all they have to be CLOSED and then they have to be SIMPLE. For example, a sphere : hidden faces will never be drawn (that's important !) and drawing priority does not mind at all. Objects have to be closed : if a side would be opened, you should have to draw also hidden faces, so you should use Z sort again.

**************************** parte 1 *********************************
CalcPoints:
; Z factor
	move.l	Dlines,a0		; how to join faces
	move.l	dplane,a1		; number of punts per face and color
	lea	Intz(pc),a2		; Z val of all points
	lea	BufferFace(pc),a3	; empty buffer
	move.w	dface,d6			; number of faces
	moveq	#0,d0
	moveq	#0,d1
LpLps:	move.w	(a1),d0			; number of punts creating a face
	add.w	#4,a1
	move.w	d0,d1			; d1 = d0
	subq.w	#1,d0			; d0 = -1 per dbf
	moveq	#0,d3
SomaLp:	move.w	(a0),d2			; point number
	add.w	#4,a0
	add.w	d2,d2			; * 2 (it is a word)
	add.w	(a2,d2.w),d3		; Z coord
	dbf	d0,SomaLp
	ext.l	d3
	divs.w	d1,d3			; points / Z total
	move.w	d3,(a3)+		; factor value
	dbf	d6,LpLps


**************************** parte 2 *********************************
; compute Z value of faces (not points)
	lea	BufferFace(pc),a0	; Z factor of all faces
	lea	FacceSeq(pc),a1		; empty buffer
	movea.l	a0,a2
	move.w	dface,d4		; number of faces
	move.w	d4,d5			; number of faces
	move.w	d5,d6			; number of faces
	subq.w	#1,d6			; number of faces -1 for dbf
	move.w	d6,d7			; number of faces -1 for dbf
	add.w	d5,d5			; number of faces *2
	addq.w	#2,d5			; +2 because -(a1) before dec
					; then we insert val in a1
	add.w	d5,a1			; last val
	move.w	#$9999,d5		; $9999 = -26215 smallest Z value
Calcs:	move.w	d7,d6			; number of faces -1 per dbf
	moveq	#2,d2			; first face to insert (1)(2=WORD)
	moveq	#0,d3			, starting face (0)
	move.w	(a0)+,d0		; Z value
Calc:	move.w	(a0)+,d1		; Z2 value
	cmp.w	d0,d1			; if Z2 

OBJECT REDRAWING

Abs addresses between $100 and $200 MUST NEVER be used ! ! They are used by me in this old routine because when I have written it (1990) I had an A500 and with A500, A2000, A3000, these addresses were always empty. Now with AGA machines these addresses are in use, so I do not assure the demo will work correctly on these machines.

A lot of time, 6 years, is passed since I have written this code, I'll try to explain it as well as I can.

Display:
	clr.w	$120.w
	clr.w	$122.w
	clr.w	$124.w
	move.l	#0,a1
	move.w	ScrClrNow,a1
	move.w	#0,(a1)+		; erase $150
	move.w	#$7fff,(a1)+		; max. value in $152
	move.w	#0,(a1)+		; delete $154
	move.w	#$7fff,(a1)+		; max. value in $156
	move.l	Dlines,a6


** this is the main routine : it is executed once per every face.

	lea	$dff000,a6
	move.l	Bm2_PL1,d1
	move.w	dpunti,d6		; number of points
	lea	UltimateFace(pc),a1	; empty buffer where to place the value
                                        ; corresponding to the faces that will be drawn
                                        ; after all the others.
	lea	IntY1(pc),a2		; Y
	lea	IntX1(pc),a3		; X
	lea	FacceSeq(pc),a0		; faces' sequence
	moveq	#0,d5
	move.w	dface,d5
Face:
	move.l	dplane,a5
	move.l	Dlines,a4
	move.w	(a0)+,d0
	lsr.w	#1,d0
	subq.w	#1,d0
	moveq	#0,d3
	moveq	#0,d4
	cmp.w	#-1,d0
	beq	EAddr
Addr:	add.w	(a5),d3
	add.w	#4,a5
	addq	#1,d4
	dbf	d0,Addr
EAddr:	add.w	d3,d3
	add.w	d3,d3
	add.w	d4,d4
	move.w	d4,$130.w
	bsr	Againdopo
	dbf	d5,Face
	tst.w	$120.w
	bne	HoHo
	rts

** this routine is executed only if there are faces that have to be drawn after all the others.
** This routine is executed as last.

HoHo:	move.w	#1,$122.w
	move.w	$124.w,d5
	subq	#1,d5
	lea	UltimateFace(pc),a1
Face2:	move.l	dplane,a5
	move.l	Dlines,a4
	move.w	(a1)+,d0
	lsr.w	#1,d0
	subq.w	#1,d0
	moveq	#0,d3
	moveq	#0,d4
	cmp.w	#-1,d0
	beq	EAddr2
Addr2:	add.w	(a5),d3
	add.w	#4,a5
	addq	#1,d4
	dbf	d0,Addr2
EAddr2:	add.w	d3,d3
	add.w	d3,d3
	add.w	d4,d4
	move.w	d4,$130.w
	bsr	Againdopo
	dbf	d5,Face2
	rts

againdopo:	; compute starting point for data in Lines2
	movem.l	a0-a3/d5,-(sp)
	clr.w	Out
	lea	BufferLine(pc),a1
	add.w	d3,a4
	move.w	d3,$104.w
	move.w	2(a5),$106.w
	move.w	(a5),d6
	move.w	d6,$10e.w
	subq.w	#1,d6

; Places in BufferLine X,Y coords of all points making a face
; so we have it in sequence

DlpLop:	movem.w	(a4)+,d2/d3
	add.w	d2,d2
	add.w	d3,d3
	move.w	(a3,d2.w),(a1)+	; x1
	move.w	(a2,d2.w),(a1)+	; y1
	move.w	(a3,d3.w),(a1)+	; x2
	move.w	(a2,d3.w),(a1)+	; y2
	dbf	d6,DlpLop

; check whether inside Priority there is  0 or 1
; if 1 this face is drawn last.

	move.l	DPriority,a1
	move.w	$130.w,d2
	move.w	(a1,d2.w),d2
	cmp.w	#1,d2		; draw all
	beq	Dloop2
	tst.w	$122.w		; if it has to draw the face
	bne	Saltoo		; 
	cmp.w	#2,d2		; last faces before the others.
	beq	Ultima
; compute whether it is a line
Saltoo:	cmp.w	#1,$10e.w	; draw just 1 line
	beq	OnlyLine

; compute if it is an hidden face (YEAAA!!!)
	lea	BufferLine(pc),a1
	movem.w	(a1),d0-d3	; d0=x0 d1=y0 d2=x1 d3=y1 d4=x2 d5=y2
	movem.w	12(a1),d4-d5
	sub.w	d0,d2		;
	sub.w	d0,d4		;
	sub.w	d1,d3		;cross product of two sides
	sub.w	d1,d5		;
	muls.w	d2,d5		;
	muls.w	d3,d4		;
	tst.w	$132.w
	bne.s	blts
	sub.l	d4,d5
	bgt.s	dloop2
	lea	$dff000,a6
	bra	NoFace		; hidden face !
blts:	sub.l	d4,d5
	blt.s	dloop2
	lea	$dff000,a6
	bra	NoFace		; hidden face!

** face is visible, draw it now !

Dloop2:	; now we have all face's point in BufferLine
	bsr	CalcScr		; compute X e Y inside the screen for clipping
	bsr.l	CalcPoits	; compute Xmax,Ymax,Xmin,Ymin
	bsr.l	TCalcAll	; compute Xmax,Ymax,Xmin,Ymin di tutto
	bsr.L	CalcArea	; compute size,mod.,....
	bsr.l	Lineeee		; draw lines
	bsr.l	Fillare		; fill between lines
	bsr.l	Copyarea	; compute draw
	lea	-$58(a6),a6	; a6 = $dff000
	bsr.l	Clerorno	; erase buffer I used to draw
NoFace:	move.w	#$400,$96(a6)
	movem.l	(sp)+,a0-a3/d5
	rts
Ultima:
	movem.l	(sp)+,a0-a3/d5
	move.w	-2(a0),(a1)+
	move.w	#1,$120.w
	add.w	#1,$124.w
	rts

*** compute screen clipping ( max size = 320*256 )
CalcScr:
	move.w	$10e,d6
	add.w	d6,d6
	subq.w	#1,d6
	lea	BufferLine(pc),a0
	lea	BufferLine2(pc),a1
Clip:	movem.w	(a0)+,d0-d1
	cmp.w	#0,d0
	bge.s	Ok0
	move.w	#0,(a1)+
	move.w	#1,Out
	bra.s	Di1
Ok0:	cmp.w	#320,d0
	ble.s	Ok2
	move.w	#320,(a1)+
	bra.s	Di1
Ok2:	move.w	d0,(a1)+
Di1:	cmp.w	#0,d1
	bge.s	Ok3
	move.w	#0,(a1)+
	bra.s	Di2
Ok3:	cmp.w	#256,d1
	ble.s	Ok4
	move.w	#256,(a1)+
	bra.s	Di2
Ok4:	move.w	d1,(a1)+
Di2:	dbf	d6,Clip
	rts


*** compute Xmax, Xmin, Ymax, Ymin of all the object

TCalcAll:
	lea	$140.w,a2
	move.w	ScrClrNow,a3
	moveq	#0,d3
	move.w	(a2)+,d3
	cmp.w	(a3)+,d3
	blt	TCalcPoits2
	move.w	d3,-2(a3)
TCalcPoits2:
	move.w	(a2)+,d3
	cmp.w	(a3)+,d3
	bgt	TCalcPoits3
	move.w	d3,-2(a3)
TCalcPoits3:
	move.w	(a2)+,d3
	cmp.w	(a3)+,d3
	blt	TCalcPoits4
	move.w	d3,-2(a3)
TCalcPoits4:
	move.w	(a2)+,d3
	cmp.w	(a3)+,d3
	bgt	TCalcPoits5
	move.w	d3,-2(a3)
TCalcPoits5:
	rts


*** compute  SIZE and modules for blitter 
CalcArea:
; calcola size
	lea	Dax(pc),a3
	movem.w	$140.w,d0-d3
	sub.w	d3,d2		; x
	sub.w	d1,d0		; y
	lsr.w	#4,d2
	addq	#2,d2		; world size
	move.w	d2,$100.w
	lsr.w	#2,d0
	addq	#1,d0		; hight screen
	lsl.l	#8,d0		; muls	#$100,d0
	add.w	d2,d0		; size $dff058
	move.w	d0,18(a3)
; compute screen
	move.l	Fill,a1
	move.l	Bm2_pl1,a2
; compute memory area to copy (desending method)
	move.w	$140.w,d1
	move.w	d1,d3
	muls	#$2c,d3
	muls	#$78,d1
	move.w	$144.w,d2
	lsr.w	#3,d2
	add.w	d2,d1
	add.w	d2,d3
	add.w	d3,a1
	add.l	d1,a2
	move.l	a1,(a3)
	move.l	a2,4(a3)
	move.l	a2,8(a3)
; calcola moduli (metodo discendente)
	moveq	#0,d1
	move.w	$100.w,d1	; num. world to copy
	add.w	d1,d1		; in bytes
	moveq	#44,d2		; 40 byte in 320 pixel
	sub.w	d1,d2		; a module 
	move.w	#$78,d3		; $78 byte
	sub.w	d1,d3		; d module
	move.w	d2,12(a3)
	move.w	d3,14(a3)
	move.w	d3,16(a3)
	rts



*** copy area created and place it in corresponding planes.

Copyarea:	; funzione d=a+c
	lea	$dff000,a6
	move.w	#$8400,$96(a6)
	lea	Jump(pc),a1
	lea	Dax(pc),a3
	move.w	$106.w,d1
	add.w	d1,d1
	move.w	d1,d2
	add.w	d2,d2
	add.w	d2,d1
	add.w	d1,a1
	moveq	#0,d0
	move.w	18(a3),d0	; size $dff058
	moveq	#$28,d1
	moveq	#0,d2
	move.l	4(a3),d2	; $dff048 - $dff054
	moveq	#0,d3
	move.l	(a3),d3		; $dff050
	move.l	#AddGriglia+[$2c*256]-2,d4
	lea	$40(a6),a2
	lea	$54(a6),a4
	lea	$48(a6),a5
	move.l	#$0b0a0002,d5
	move.l	#$0bfa0002,d6
	move.l	#$0fca0002,d7
Altola:	btst	#6,2(a6)
	bne	Altola
	move.w	12(a3),$64(a6)
	move.w	12(a3),$62(a6)
	move.w	14(a3),$66(a6)
	move.w	16(a3),$60(a6)
	lea	$50(a6),a3
	lea	$58(a6),a6
	jmp	(a1)

Please note this order :

       ______ plane 4
      | _____ plane 3
      || ____ plane 2
      ||| ___ plane 1
      ||||
0 -> %0000    non usato
1 -> %0001    plane 1   pieno, 2-3-4 vuoti
2 -> %0010    plane 2   pieno, 1-3-4 vuoti
3 -> %0011    plane 1-2 pieni,   3-4 vuoti
4 -> %0100    plane 3   pieno, 1-2-4 vuoti
. -> %....

You have to copy or erase interested area. For the copy, you just have to add the screen with the face you are drawing. For the erase, you have to do a mul with the NEG face on the destination screen.

Depending on the selected colour, just ONE SINGLE routine is executed.

Jump:	jmp	zeros
	jmp	unos
	jmp	dues
	jmp	tres
	jmp	quattros
	jmp	cinques
	jmp	seis
	jmp	settes
	jmp	ottos
	jmp	noves
	jmp	diecis
	jmp	undicis
	jmp	dodicis
	jmp	tredicis
zeros:
	bsr	disegnare		; disegna plane 0
	add.w	d1,d2
	bsr	cancellare		; cancella plane 1
	add.w	d1,d2
	bsr	cancellare		; cancella plane 2
	rts
unos:
	bsr	cancellare		; disegna plane 0
	add.w	d1,d2
	bsr	disegnare		; disegna plane 1
	add.w	d1,d2
	bsr	cancellare		; cancella plane 2
	rts
dues:
	bsr	cancellare		; cancella plane 0
	add.w	d1,d2
	bsr	cancellare		; cancella plane 1
	add.w	d1,d2
	bsr	disegnare		; disegna plane 2
	rts
tres:
	bsr	disegnare
	add.w	d1,d2
	bsr	disegnare
	add.w	d1,d2
	bsr	cancellare
	rts
quattros:
	bsr	disegnare
	add.w	d1,d2
	bsr	cancellare
	add.w	d1,d2
	bsr	disegnare
	rts
cinques:
	bsr	cancellare
	add.w	d1,d2
	bsr	disegnare
	add.w	d1,d2
 	bsr	disegnare
	rts
seis:
	bsr	disegnare
	add.w	d1,d2
	bsr	disegnare
	add.w	d1,d2
	bsr	disegnare
	rts
settes:
	bsr	griglia
	add.w	d1,d2
	bsr	cancellare
	add.w	d1,d2
	bsr	cancellare
	rts
ottos:
	bsr	cancellare
	add.w	d1,d2
	bsr	griglia
	add.w	d1,d2
	bsr	cancellare
	rts
noves:
	bsr	cancellare
	add.w	d1,d2
	bsr	cancellare
	add.w	d1,d2
	bsr	griglia
	rts
diecis:
	bsr	griglia
	add.w	d1,d2
	bsr	griglia
	add.w	d1,d2
	bsr	cancellare
	rts
undicis:
	bsr	griglia
	add.w	d1,d2
	bsr	cancellare
	add.w	d1,d2
	bsr	griglia
	rts
dodicis:
	bsr	cancellare
	add.w	d1,d2
	bsr	griglia
	add.w	d1,d2
	bsr	griglia
	rts
tredicis:
	bsr	griglia
	add.w	d1,d2
	bsr	griglia
	add.w	d1,d2
	bsr	griglia
	rts

cancellare:                              ; funzione D=A(neg)*C per cancellare
	btst	#6,-$56(a6)
	bne	cancellare
	move.l	d5,(a2)
	move.l	d3,(a3)
	move.l	d2,(a4)
	move.l	d2,(a5)
	move.w	d0,(a6)
	rts

disegnare:
	btst	#6,-$56(a6)
	bne	disegnare
	move.l	d6,(a2)
	move.l	d3,(a3)
	move.l	d2,(a4)
	move.l	d2,(a5)
	move.w	d0,(a6)
	rts

Griglia:
	btst	#6,-$56(a6)
	bne	griglia
	move.l	d7,(a2)                  ; funzione D=A(neg)*C+A*B
	move.l	d4,-$c(a6)
	move.l	d3,(a3)
	move.l	d2,(a4)
	move.l	d2,(a5)
	move.w	d0,(a6)
	rts

** This routine erases the buffer

Clerorno:	; zone to delete to erase the lines.
	btst	#6,$2(a6)
	bne	Clerorno
	lea	Dax(pc),a3
	move.l	#$01000002,$40(a6)
	move.w	12(a3),$66(a6)
	move.l	(a3),$54(a6)
	move.w	18(a3),$58(a6)
	rts

Fillare:
	lea	Dax(pc),a3
	tst.w	out
	beq	doppld
	move.w	12(a3),d0
	addq.w	#2,d0
	move.w	18(a3),d1
	subq.w	#1,d1
	bra.s	FillWait
doppld:
	move.w	12(a3),d0
	move.w	18(a3),d1
FillWait:                         ; zona da fillare per riempire linee
	btst	#6,$2(a6)
	bne	FillWait
	move.l	#$09f00012,$40(a6)
	move.w	d0,$64(a6)
	move.w	d0,$66(a6)
	move.l	(a3),$50(a6)
	move.l	(a3),$54(a6)
	move.w	d1,$58(a6)
	rts

** This routine just draws ONE SINGLE LINE with the blitter
** without using any buffer.

Onlyline:
	bsr	CalcScr		; compute  screen's X and Y
	lea	BufferLine(pc),a1
	lea	jump2(pc),a2
	move.l	BM2_PL1,a0
	move.l	BM2_PL1,a3
	lea	$dff000,a6
	move.w	$106.w,d1
	add.w	d1,d1
	move.w	d1,d2
	add.w	d2,d2
	add.w	d2,d1
	add.w	d1,a2
	jmp	(a2)

Jump2:	jmp	linep0
	jmp	linep1
	jmp	linep2
	jmp	linep3
	jmp	linep4
	jmp	linep5
	jmp	linep6

Linep0:	move.l	#$ffff8000,d7	; metodo TEXTURE = tutto pieno
	bsr	Line00
	move.l	#$00008000,d7	; metodo TEXTURE = vuoto = cancella linea
	add.w	#$28,a3
	bsr	Line00
	add.w	#$28,a3
	bsr	Line00
	bra	CalcMax
Linep1:	move.l	#$00008000,d7
	bsr	Line00
	move.l	#$ffff8000,d7
	add.w	#$28,a3
	bsr	Line00
	move.l	#$00008000,d7
	add.w	#$28,a3
	bsr	Line00
	bra	CalcMax
Linep2:	move.l	#$00008000,d7
	bsr	Line00
	add.w	#$28,a3
	bsr	Line00
	move.l	#$ffff8000,d7
	add.w	#$28,a3
	bsr	Line00
	bra	CalcMax
Linep3:	move.l	#$ffff8000,d7
	bsr	Line00
	add.w	#$28,a3
	bsr	Line00
	add.w	#$28,a3
	move.l	#$00008000,d7
	bsr	Line00
	bra	CalcMax
Linep4:	move.l	#$ffff8000,d7
	bsr	Line00
	move.l	#$00008000,d7
	add.w	#$28,a3
	bsr	Line00
	move.l	#$ffff8000,d7
	add.w	#$28,a3
	bsr	Line00
	bra	CalcMax
Linep5:	move.l	#$00008000,d7
	bsr	Line00
	move.l	#$ffff8000,d7
	add.w	#$28,a3
	bsr	Line00
	add.w	#$28,a3
	bsr	Line00
	bra	CalcMax
Linep6:	move.l	#$ffff8000,d7
	bsr	Line00
	add.w	#$28,a3
	bsr	Line00
	add.w	#$28,a3
	bsr	Line00
	bra	CalcMax


** This routine draws lines using blitter

Line00:
	movem.w	(a1),d0-d3	; coordinate x0,y0,x1,y1


****** Insert clipping routine here.


Line:
	cmp.w	d1,d3
	bne	encode
	rts
encode:
	move.l	a3,a0
	move.w	#$78,d4
	sub.w	d0,d2
	bpl.s	Oct1278
	neg.w	d2
	sub.w	d1,d3
	bpl.s	Oct34
	neg.w	d3
	cmp.w	d2,d3
	bpl.s	Oct6
	moveq.l	#28+1,d5
	bra.s	Lline
Oct6:	exg	d2,d3
	moveq.l	#12+1,d5
	bra.s	Lline
Oct34:	cmp.w	d2,d3
	bpl.s	Oct3
	moveq.l	#20+1,d5
	bra.s	Lline
Oct3:	exg	d2,d3
	moveq.l	#8+1,d5
	bra.s	Lline
Oct1278:sub.w	d1,d3
	bpl.s	Oct12
	neg.w	d3
	cmp.w	d2,d3
	bpl.s	Oct7
	moveq.l	#24+1,d5
	bra.s	Lline
Oct7:	exg	d2,d3
	moveq.l	#4+1,d5
	bra.s	Lline
Oct12:	cmp.w	d2,d3
	bpl.s	Oct2
	moveq.l	#16+1,d5
	bra.s	Lline
Oct2:	exg	d2,d3
	moveq.l	#0+1,d5
Lline:	mulu.w	d4,d1
	ror.l	#4,d0
	add.w	d0,d0
	add.l	d1,a0
	add.w	d0,a0
	swap	d0
	or.w	#$bca,d0
	add.w	d3,d3
	add.w	d3,d3
	add.w	d2,d2
	move.w	d2,d1
	lsl.w	#5,d1
	add.w	#$42,d1
	swap	d5
	move.w	d0,d5
	swap	d5
	move.w	d3,d0
	sub.w	d2,d0
	bpl	waitb1
	bset	#6,d5
waitb1:	move.w	d0,d6
	sub.w	d2,d6
Drawl2:	btst	#6,2(a6)
	bne.s	Drawl2
	move.w	d3,$62(a6)
	move.l	d0,$50(a6)
	move.l	d5,$40(a6)
	move.w	d4,$60(a6)
	move.w	d4,$66(a6)
	move.w	d6,$64(a6)
	move.l	#-1,$44(a6)
	move.l	d7,$72(a6)
	move.l	a0,$48(a6)
	move.l	a0,$54(a6)
	move.w	d1,$58(a6)
	rts


CalcMax:	; calcola
	lea	BufferLine2(pc),a1
	lea	$140.w,a2
	moveq	#0,d0
	moveq	#0,d1
	moveq	#0,d2
	moveq	#0,d3
	movem.w	(a1),d0-d3
	cmp.w	d0,d2
	ble.s	Less
	move.w	d0,6(a2)
	move.w	d2,4(a2)
	bra.s	Great
Less:	move.w	d0,4(a2)
	move.w	d2,6(a2)
Great:	cmp.w	d1,d3
	ble.s	Less2
	move.w	d1,2(a2)
	move.w	d3,(a2)
	bra.s	Great2
Less2:	move.w	d1,(a2)
	move.w	d3,2(a2)
Great2:	bsr	TCalcAll
	bra	NoFace


CalcPoits:	; Calcola Xmax,Xmin,Ymax,Ymin
	lea	BufferLine2+2(pc),a2
	move.w	$10e.w,d6
	add.w	d6,d6
	subq.w	#1,d6
	move.w	d6,d7
	moveq	#0,d1
	move.w	(a2),d2
	moveq	#0,d3
CalcPoits4:
	move.w	(a2),d1
	cmp.w	d1,d3
	bgt.s	CalcPoits2
	move.w	d1,d3
	addq	#4,a2
	dbf	d6,CalcPoits4
	bra.s	CalcPoitsend
CalcPoits2:
	cmp.w	d1,d2
	blt.s	CalcPoits3
	move.w	d1,d2
CalcPoits3:
	addq	#4,a2
	dbf	d6,CalcPoits4
CalcPoitsend:
	move.w	d3,$140.w
	move.w	d2,$142.w
	lea	BufferLine2(pc),a2
	moveq	#0,d0
	moveq	#0,d1
	move.w	(a2),d2
	moveq	#0,d3
	move.w	d7,d6
CalcPoit5:
	move.w	(a2),d1
	cmp.w	d1,d3
	bgt.s	CalcPoit6
	move.w	d1,d3
	addq	#4,a2
	dbf	d6,CalcPoit5
	move.w	d3,$144.w
	move.w	d2,$146.w
	rts
CalcPoit6:
	cmp.w	d1,d2
	blt.s	CalcPoit7
	move.w	d1,d2
CalcPoit7:
	addq	#4,a2
	dbf	d6,CalcPoit5
	move.w	d3,$144.w
	move.w	d2,$146.w
	rts

Lineeee:
	lea	BufferLine(pc),a5	; sequanza delle linee da disegnare
	move.w	$10e.w,d6
	subq.w	#1,d6
Linene:	movem.w	(a5)+,d0-d3
	bsr.s	SWline
	dbf	d6,Linene
	rts

** Qui deve essere inserita la routine di CLIPPING


SWLine:
	move.l	Fill,a0
	lea	$dff000,a6
	cmp.w	d1,d3
	bne.s	Sencode			; linea orizzontale
	rts
Sencode:bmi.s	SLine0A
	exg.l	d0,d2
	exg.l	d1,d3
SLine0A:addq.w	#1,d3
	clr.w	d4
	sub.w	d1,d3
	bge.s	SLine16
	neg.w	d3
	bra.s	SLine1A
SLine16:or.w	#1,d4
SLine1A:sub.w	d0,d2
	bge.s	SLine22
	neg.w	d2
	bra.s	SLine26
SLine22:or.w	#2,d4
SLine26:cmp.w	d3,d2
	bge.s	SLine2E
	exg.l	d2,d3
	bra.s	SLine32
SLine2E:or.w	#4,d4
SLine32:clr.w	d5
	ror.w	#4,d0
	or.w	#$B00,d0
	move.b	d0,d5
	move.b	#$5A,d0
	add.w	d5,d5
	mulu.w	#$2c,d1
	and.w	#$FFFF,d1
	add.w	d5,d1
	add.l	a0,d1
	move.b	oct(pc,d4.w),d4
	add.l	d3,d3
SLine5C:btst	#6,2(a6)
	bne.s	SLine5C
	move.w	d3,$62(a6)
	sub.w	d2,d3
	bge.s	SLine70
	or.b	#$40,d4
SLine70:
	move.l	d3,$50(a6)
	sub.w	d2,d3
	move.l	#$ffff8000,$72(a6)
	moveq	#-1,d5
	move.l	d5,$44(a6)
	moveq	#44,d5
	move.w	d5,$60(a6)
	move.w	d5,$66(a6)
	move.w	d3,$64(a6)
	move.w	d4,$42(a6)
	move.w	d0,$40(a6)
	move.l	d1,$48(a6)
	move.l	d1,$54(a6)
	lsl.w	#6,d2
	add.w	#$42,d2
	move.w	d2,$58(a6)
	rts

; octant codes
oct:	dc.b	$0f,$0b,$07,$03,$1f,$17,$1b,$13

By checking the source, you should have notice that CLIPPING routine is not present. This routine will be described in the next issue, so please BE CAREFULL not to draw objects that exists the screen !

Now we'll examine remaining source code parts.

	jmp	START
	org	$130000
	load	$130000

START:
	................

These commands are used to make code NOT RELOCABLE, so the routine will always be loaded starting from $130000.


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


	lea	$150000,a0
Clear:	clr.l	(a0)+
	cmp.l	#$180000,a0
	bne	clear
	lea	$100.w,a0
dsf:	clr.b	(a0)+
	cmp.l	#$200,a0
	bne	dsf

This loop erases memory from $150000 and $180000 and from $100 and $200

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

	lea	SphLines(pc),a0
	lea	Plane9(pc),a1
addiaz:	add.w	#96,(a0)+
	cmp.l	a0,a1
	bne	addiaz

This routine just adds the two spheres together.

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


	lea	AddGriglia,a0
	move.w	#$80,d1		; 1/2 height
gri1:	moveq	#10,d0		; num. screen in long
gri2:	move.l	#$55555555,(a0)+
	move.l	#$aaaaaaaa,$28(a0)	; $28=modulo-$4[1 long]
	dbra	d0,gri2
	add.l	#$2c,a0			; modulo
	dbra	d1,gri1

** Creates a grid for creating the dither effect.
********************************************************************************
Inter:
	btst	#5,$dff01f
	beq.w	Int
	move.w	#$20,$dff09c
	add.w	#4,ZANGLE
	add.w	#2,YANGLE
	add.w	#4,XANGLE
	move.w	#1,IntOk
Int:	rte
IntOk:	dc.w	0


** Routine in INTERRUPT $6c. That's because our object will always  run at the same speed. 

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

HOW TO DRAW OBJECTS

Dpunti:	dc.w	0		;number of points
Dface:	dc.w	0		; number of faces
DX:	dc.l	0		; coords X
DY:	dc.l	0		; coords Y
DZ:	dc.l	0		; coords Z
Dlines:	dc.l	0		; how to join lines
Dplane:	dc.l	0		; how to color object
Dpriority:	dc.l	0	; how to draw object

Blkpoints=200		;	num points
BlkLine=26		;	num lines per face
Blkface=200		;	num faces

; cube with lines
NPOINTS=76		; num points
Nface=12		; num faces
Wx:
 dc.w	-120,120,120,-120,-120,120,120,-120
 dc.w	-100,100,100,35,35,-35,-35,-100
 dc.w	120,120,120,120,120,120,120,120,120,120,120,120
 dc.w	100,-20,-100,-100,-20,100,45,5,-45,-45,5,45
 dc.w	-120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120
 dc.w	-120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120
 dc.w	0,-80,100,-100,80
 dc.w	0,-80,100,-100,80
Wy:
 dc.w	120,120,-120,-120,120,120,-120,-120
 dc.w	100,100,40,40,-100,-100,40,40
 dc.w	100,100,60,60,20,20,-20,-20,-60,-60,-100,-100
 dc.w	100,100,40,-40,-100,-100,45,45,10,-10,-45,-45
 dc.w	60,60,40,40,-40,-40,-20,-20,0,0,-20,-20,-60,-60
 dc.w	60,60,40,40,10,10,-60,-60,-40,-40,-10,-10
 dc.w	120,120,120,120,120
 dc.w	-120,-120,-120,-120,-120
Wz:
 dc.w	120,120,120,120,-120,-120,-120,-120
 dc.w	120,120,120,120,120,120,120,120
 dc.w	100,-100,-100,40,40,-40,-40,40,40,-100,-100,100
 dc.w	-120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120,-120
 dc.w	-100,-20,-20,-80,-80,-40,-40,-50,-50,-10,-10,-20,-20,-100
 dc.w	10,100,100,30,30,100,100,10,10,80,80,10
 dc.w	100,-100,20,20,-100
 dc.w	100,-100,20,20,-100
Lines:
 dc.w	0,1,1,2,2,3,3,0
 dc.w	5,4,4,7,7,6,6,5
 dc.w	1,5,5,6,6,2,2,1
 dc.w	4,0,0,3,3,7,7,4
 dc.w	4,5,5,1,1,0,0,4
 dc.w	3,2,2,6,6,7,7,3
 dc.w	8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,8
 dc.w	16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,16
 dc.w	28,29,29,30,30,31,31,32,32,33,33,28,34,35,35,36,36,37,37,38,38,39,39,34
 dc.w	40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48,49,49,50,50,51,51,52,52,53,53,40
 dc.w	54,55,55,56,56,57,57,58,58,59,59,60,60,61,61,62,62,63,63,64,64,65,65,54
 dc.w	66,67,67,68,68,69,69,70,70,66
 dc.w	75,74,74,73,73,72,72,71,71,75
Plane:
 dc.w	4,0,4,0,4,1,4,1,4,2,4,2,8,3,12,4,12,6,26,5,5,5,5,1
Priotity:	; 0 if you compute it; 1 if always draw it; 2 if it is the last
 dc.w	0,0,0,0,0,0,2,2,2,2,2,2

To draw the object you need :

- place X in Wx
- place Y in Wy
- place Z in Wz
- select draw mode

Let's do an example .

YOU CANNOT DRAW FACES RANDOMLY IF THE ERASE HIDDEN FACES ROUTINE IS PRESENT ! ! ! !

If we want to draw a cube, the first face will be in this way :


    0----1
    |    |
    |    |
    |    |
    3----2

Now we need to give a priority to the face :


    0--------1
    |   ->   |
    |        |
 /\ |        |||
 || |        |||
 || |        |\/
    |        |
    |        |
    3--------2
       <-

As you may see, the face goes from point 0 to 1, from 1 to 2, from 2 to 3 and from 3 to 0. It is IMPORTANT to start always from 0.

Next face must have opposite priority ! !

                  4
                 /|
                / |
               /  |
    0--------1/   |
    |   ->   |    |
    |        |    |
 /\ |        |    5
 || |      |||   /
 || |      |||  /
    |      \/| /
    |        |/
    3--------2
       <-

                  4
                 /|
             -> / |||
               /  |||
    0--------1/   |\/
    |        |    |
    |        |    |
    |      /\|    5
    |      |||   /
    |      |||  /
    |        | /<-
    |        |/
    3--------2

Now, with coords in 3D and central symmetry :



                                                 Y
    (-100,-100,100)         (100,-100,100)        /\
                  0---------1                      |
                  |         |                      |
                  |         |                      |
                  |    |    |                      |   / Z
                  |   - -   |                      |  /
                  |    |    |                      | /
                  |         |                      |/
                  |         |                      ----------> X
                  3---------2
     (-100,100,100)         (100,100,100)

Foreground face has Z=100, while background one has Z=-100

So we have, for the first three faces :

Wx:  dc.w   -100,100,100,-100,100,100
Wy:  dc.w   -100,-100,100,100,-100,-100
Wz:  dc.w   100,100,100,100,-100,-100
Lines:
 dc.w	0,1,1,2,2,3,3,0
 dc.w	5,2,2,1,1,4,4,5
Plane:
 dc.w	4,0,4,1

Plane defines:

4,0 = face made by 4 lines with colour 0

4,1 = face made by 4 lines with colour 1

example :13,89 = face made by 13 lines with colour no. 89

Colors :
; 0= first plane
; 1= second  plane
; 2= third  plane
; 3= first + second plane
; 4= first + third  plane
; 5= second + third  plane
; 6= first + second + third plane
; use of grid for stencil vector !!!!
; 7= first plane
; 8= second plane
; 9= third  plane
; 10= first + second plane
; 11= first + third plane
; 12= second + third  plane
; 13= first + second + third plane

P.S.: Data for the program can be d/l from the archive of the last month. P.S.2: If I have missed something, send me an e-mail.


Main Page


    Written By: Alfredo Ornaghi      e-mail: ted@intercom.it
                ITALY                   tel: