[alt.sources] FC Clipper

jcs@crash.cts.com (John Schultz) (04/13/90)

                 


                    SOURCE CODE FOR THE FC CLIPPER
                               4/10/90


  The Fast Clipper (FC) 2D line clipper algorithm uses line encoding
as opposed to end point encoding as with the Cohen-Sutherland (CS)
method, or parametric methods of Liang-Barsky and Cyrus-Beck.  The
Sobkow-Pospisil-Yang paper shows benchmarks where the FC clipper
is over twice as fast as the CS algorithm. The parametric methods are
much slower.  The paper has a source code listing in C, which has a few
errors.  These errors were in the #define statements for clipping to
screen edges.  A divide and a subtract were left out:

  as published:
    #define ClipPTop (*Px) = (*Px) + ((*Qx) - (*Px)) * (YTop - (*Py))

  should read:
    #define ClipPTop (*Px) = (*Px) + ((*Qx) - (*Px)) * (YTop - (*Py)) /
                                     ((*Qy) - (*Py))

  Once these errors were corrected, the algorithm worked properly.
At the time I was experimenting with clipping, I was using a Modula-2
compiler, so my HLL source is in modula-2.  The latest version is in
68000 assembly, linked to C test code.  

  The original paper on the FC algorithm was published in
Computers & Graphics Vol. 11, No. 4, pp. 459-467, 1987
Printed in Great Britain.  The publisher was Pergamon Journals Ltd.

Authors of the paper (Creators of the FC algorithm):

  Mark S. Sobkow, Paul Pospisil, and Yee-Hong Yang (to whom
correspondence should be addressed), 
Department of Computational Science, University of Saskatchewan, Saskatoon,
Saskatchewan, Canada S7N 0W0.


  I never tested my code against any other algorithms, so I'm curious to
see if it is twice as fast as SC. Please let me know of any further
optimizations.


  Also, quite a few requests were for the C source, so someone might
want to convert the Modula-2 source to C and re-post.



  John


Here is the source code. Each file is separated by a 2 rows of 
asteriks.

***********************************************************************
FILE: Clip.a
***********************************************************************

; Clip.a,  Fast Clipper (FC).

; A modified implementation of the Sobkow-Pospisil-Yang clipping algorithm.
; References: Computers & Graphics, Vol. 11. No. 4, pp. 459-467, 1987.

; This algorithm uses line encoding as opposed to end point encoding.

; Created 19-Nov-89
; by John C. Schultz


; Successfully assembled with Lattice 5.04 asm, CAPE 2.5, and Devpac 2.14.


	section Clip,CODE

	xdef	_minX
	xdef	_maxX
	xdef	_minY
	xdef	_maxY
	xdef	_clipline

; User definable clipping window.

_minX	dc.w	0		; Popular defaults
_maxX	dc.w	319
_minY	dc.w	0
_maxY	dc.w	199

; code size can be reduced (with a loss of speed) by using
; bra's and bsr's instead of complete inline expanded macros.

; ClipEdge: \2 = result, d0,d1 are scratched
CLIPEDGE	MACRO		; comments as per clip minX edge:
	move.w	\1,d0		;   copy p.y
	sub.w	\2,d0		;   d0 = p.y - s.y
	move.w	\3,d1		;   copy _minX(pc)
	sub.w	\4,d1		;   d1 = _minX(pc) - s.x
	muls	d0,d1		;   d1 = (p.y - s.y)*(_minX(pc) - s.x)
	move.w	\5,d0		;   copy p.x
	sub.w	\4,d0		;   d0 = p.x - s.x
	divs	d0,d1		;   d1 = deltay
	add.w	d1,\2		;   \2 = deltay + s.y
		ENDM

clippmaxY	macro
	CLIPEDGE d4,d2,_maxY(pc),d3,d5
	move.w	_maxY(pc),d3
		endm

clippminY	macro
	CLIPEDGE d4,d2,_minY(pc),d3,d5
	move.w	_minY(pc),d3
		endm

clippmaxX	macro
	CLIPEDGE d5,d3,_maxX(pc),d2,d4
	move.w	_maxX(pc),d2
		endm

clippminX	macro
	CLIPEDGE d5,d3,_minX(pc),d2,d4
	move.w	_minX(pc),d2
		endm

clipqmaxY	macro
	CLIPEDGE d2,d4,_maxY(pc),d5,d3
	move.w	_maxY(pc),d5
		endm

clipqminY	macro
	CLIPEDGE d2,d4,_minY(pc),d5,d3
	move.w	_minY(pc),d5
		endm

clipqmaxX	macro
	CLIPEDGE d3,d5,_maxX(pc),d4,d2
	move.w	_maxX(pc),d4
		endm

clipqminX	macro
	CLIPEDGE d3,d5,_minX(pc),d4,d2
	move.w	_minX(pc),d4
		endm

accept	macro
	movem.w	d2/d3/d4/d5,(a0)
	moveq.l	#1,d0
	movem.l	(sp)+,d2-d5
	rts
	endm

reject	macro
	moveq.l	#0,d0
	movem.l	(sp)+,d2-d5
	rts
	endm


; Fast Clipper (FC) line clipping algorithm.
; a0 = line pointer, format: px,py,qx,qy.
; d0 = return value, 1 = visible, 0 = invisible
_clipline
	movem.l	d2-d5,-(sp)

	movem.w	(a0),d2/d3/d4/d5 ; px,py,qx,qy

; px = d2
; py = d3
; qx = d4
; qy = d5

	moveq.l	#0,d1		; clear line code

; There might be a way to do the following using ROXL, with no
; branches (10 cycles a pop)...

; check qx,qy.

checkqmaxY
	cmp.w	_maxY(pc),d5	; y maxY ok?
	ble.b	checkqminY	; yes.
	addq.w	#8,d1		; else set code bit
	bra.b	checkqmaxX
checkqminY
	cmp.w	_minY(pc),d5	; y minY ok?
	bge.b	checkqmaxX	; yes.
	addq.w	#4,d1		; else set code bit
checkqmaxX
	cmp.w	_maxX(pc),d4	; x maxX ok?
	ble.b	checkqminX	; yes
	addq.w	#2,d1		; else set code bit
checkqminX
	cmp.w	_minX(pc),d4	; x minX ok?
	bge.b	checkpmaxY	; yes
	addq.w	#1,d1		; else set code bit

; check px,py.

checkpmaxY
	cmp.w	_maxY(pc),d3	; y maxY ok?
	ble.b	checkpminY	; yes.
	add.w	#128,d1		; else set code bit
	bra.b	checkpmaxX
checkpminY
	cmp.w	_minY(pc),d3	; y minY ok?
	bge.b	checkpmaxX	; yes.
	add.w	#64,d1		; else set code bit
checkpmaxX
	cmp.w	_maxX(pc),d2	; x maxX ok?
	ble.b	checkpminX	; yes
	add.w	#32,d1		; else set code bit
checkpminX
	cmp.w	_minX(pc),d2	; x minX ok?
	bge.b	checkcode	; yes
	add.w	#16,d1		; else set code bit

checkcode
	add.w	d1,d1		; entries are 4 bytes
	add.w	d1,d1
	lea	casetable(pc),a1
	movea.l	0(a1,d1.w),a1
	jmp	(a1)		; perform specific clipping action.

; Specific line case functions.

; From the Center

case00	accept
case01	clipqminX
	accept
case02	clipqmaxX
	accept
case04	clipqminY
	accept
case05	clipqminX
	cmp.w	_minY(pc),d5	; qy < minY?
	bge.b	1$
	clipqminY
1$	accept
case06	clipqmaxX
	cmp.w	_minY(pc),d5	; qy < minY?
	bge.b	1$
	clipqminY
1$	accept
case08	clipqmaxY
	accept
case09	clipqminX
	cmp.w	_maxY(pc),d5	; qy > maxY?
	ble.b	1$
	clipqmaxY
1$	accept
case0A	clipqmaxX
	cmp.w	_maxY(pc),d5	; qy > maxY?
	ble.b	1$
	clipqmaxY
1$	accept

; From the minX

case10	clippminX
	accept
case11	reject
case12	clippminX
	clipqmaxX
	accept
case14	clippminX
	cmp.w	_minY(pc),d3	; py < minY?
	bge.b	1$
	reject
1$	clipqminY
	accept
case15	reject
case16	clippminX
	cmp.w	_minY(pc),d3	; py < minY?
	bge.b	1$
	reject
1$	clipqminY
	cmp.w	_maxX(pc),d4	; qx > maxX?
	ble.b	2$
	clipqmaxX
2$	accept
case18	clippminX
	cmp.w	_maxY(pc),d3	; py > maxY?
	ble.b	1$
	reject
1$	clipqmaxY
	accept
case19	reject
case1A	clippminX
	cmp.w	_maxY(pc),d3	; py > maxY?
	ble.b	1$
	reject
1$	clipqmaxY
	cmp.w	_maxX(pc),d4	; qx > maxX?
	ble.b	2$
	clipqmaxX
2$	accept

; From maxX

case20	clippmaxX
	accept
case21	clippmaxX
	clipqminX
	accept
case22	reject
case24	clippmaxX
	cmp.w	_minY(pc),d3	; py < minY?
	bge.b	1$
	reject
1$	clipqminY
	accept
case25	clippmaxX
	cmp.w	_minY(pc),d3	; py < minY?
	bge.b	1$
	reject
1$	clipqminY
	cmp.w	_minX(pc),d4	; qx < minX?
	bge.b	2$
	clipqminX
2$	accept
case26	reject
case28	clippmaxX
	cmp.w	_maxY(pc),d3	; py > maxY?
	ble.b	1$
	reject
1$	clipqmaxY
	accept
case29	clippmaxX
	cmp.w	_maxY(pc),d3	; py > maxY?
	ble.b	1$
	reject
1$	clipqmaxY
	cmp.w	_minX(pc),d4	; qx < minX?
	bge.b	2$
	clipqminX
2$	accept
case2A	reject

; From minY

case40	clippminY
	accept
case41	clippminY
	cmp.w	_minX(pc),d2	; px < minX?
	bge.b	1$
	reject
1$	clipqminX
	cmp.w	_minY(pc),d5	; qy < minY?
	bge.b	2$
	clipqminY
2$	accept
case42	clippminY
	cmp.w	_maxX(pc),d2	; px > maxX?
	ble.b	1$
	reject
1$	clipqmaxX
	accept
case44	; reject
case45	; reject
case46	reject
case48	clippminY
	clipqmaxY
	accept
case49	clippminY
	cmp.w	_minX(pc),d2	; px < minX?
	bge.b	1$
	reject
1$	clipqminX
	cmp.w	_maxY(pc),d5	; qy > maxY?
	ble.b	2$
	clipqmaxY
2$	accept
case4A	clippminY
	cmp.w	_maxX(pc),d2	; px > maxX?
	ble.b	1$
	reject
1$	clipqmaxX
	cmp.w	_maxY(pc),d5	; qy > maxY?
	ble.b	2$
	clipqmaxY
2$	accept

; From Lower minX

case50	clippminX
	cmp.w	_minY(pc),d3	; py < minY?
	bge.b	1$
	clippminY
1$	accept
case51	reject
case52	clipqmaxX
	cmp.w	_minY(pc),d5	; qy < minY?
	bge.b	1$
	reject
1$	clippminY
	cmp.w	_minX(pc),d2	; px < minX?
	bge.b	2$
	clippminX
2$	accept
case54  ; reject
case55	; reject
case56	reject
case58	clipqmaxY
	cmp.w	_minX(pc),d4	; qx < minX?
	bge.b	1$
	reject
1$	clippminY
	cmp.w	_minX(pc),d2	; px < minX?
	bge.b	2$
	clippminX
2$	accept
case59	reject
case5A	clippminX
	cmp.w	_maxY(pc),d3	; py > maxY?
	ble.b	1$
	reject
1$	clipqmaxX
	cmp.w	_minY(pc),d5	; qy < minY?
	bge.b	2$
	reject
2$	cmp.w	_minY(pc),d3	; py < minY?
	bge.b	3$
	clippminY
3$	cmp.w	_maxY(pc),d5	; qy > maxY?
	ble.b	4$
	clipqmaxY
4$	accept

; From Lower maxX

case60	clippmaxX
	cmp.w	_minY(pc),d3	; py < minY?
	bge.b	1$
	clippminY
1$	accept
case61	clipqminX
	cmp.w	_minY(pc),d5	; qy < minY?
	bge.b	1$
	reject
1$	clippminY
	cmp.w	_maxX(pc),d2	; px > maxX?
	ble.b	2$
	clippmaxX
2$	accept
case62	; reject
case64	; reject
case65	; reject
case66	reject
case68	clipqmaxY
	cmp.w	_maxX(pc),d4	; qx > maxX?
	ble.b	1$
	reject
1$	clippmaxX
	cmp.w	_minY(pc),d3	; py < minY?
	bge.b	2$
	clippminY
2$	accept
case69	clipqminX
	cmp.w	_minY(pc),d5	; qy < minY?
	bge.b	1$
	reject
1$	clippmaxX
	cmp.w	_maxY(pc),d3	; py > maxY?
	ble.b	2$
	reject
2$	cmp.w	_maxY(pc),d5	; qy > maxY?
	ble.b	3$
	clipqmaxY
3$	cmp.w	_minY(pc),d3	; py < minY?
	bge.b	4$
	clippminY
4$	accept
case6A	reject

; From maxY

case80	clippmaxY
	accept
case81	clippmaxY
	cmp.w	_minX(pc),d2	; px < minX?
	bge.b	1$
	reject
1$	clipqminX
	accept
case82	clippmaxY
	cmp.w	_maxX(pc),d2	; px > maxX?
	ble.b	1$
	reject
1$	clipqmaxX
	accept
case84	clippmaxY
	clipqminY
	accept
case85	clippmaxY
	cmp.w	_minX(pc),d2	; px < minX?
	bge.b	1$
	reject
1$	clipqminX
	cmp.w	_minY(pc),d5	; qy < minY?
	bge.b	2$
	clipqminY
2$	accept
case86	clippmaxY
	cmp.w	_maxX(pc),d2	; px > maxX?
	ble.b	1$
	reject
1$	clipqmaxX
	cmp.w	_minY(pc),d5	; qy < minY?
	bge.b	2$
	clipqminY
2$	accept
case88	; reject
case89	; reject
case8A	reject

; From Upper minX

case90	clippminX
	cmp.w	_maxY(pc),d3	; py > maxY?
	ble.b	1$
	clippmaxY
1$	accept
case91	reject
case92	clipqmaxX
	cmp.w	_maxY(pc),d5	; qy > maxY?
	ble.b	1$
	reject
1$	clippmaxY
	cmp.w	_minX(pc),d2	; px < minX?
	bge.b	2$
	clippminX
2$	accept
case94	clipqminY
	cmp.w	_minX(pc),d4	; qx < minX?
	bge.b	1$
	reject
1$	clippminX
	cmp.w 	_maxY(pc),d3	; py > maxY?
	ble.b	2$
	clippmaxY
2$	accept
case95	reject
case96	clippminX
	cmp.w	_minY(pc),d3	; py < minY?
	bge.b	1$
	reject
1$	clipqmaxX
	cmp.w	_maxY(pc),d5	; qy > maxY?
	ble.b	2$
	reject
2$	cmp.w	_maxY(pc),d3	; py > maxY?
	ble.b	3$
	clippmaxY
3$	cmp.w	_minY(pc),d5	; qy < minY
	bge.b	4$
	clipqminY
4$	accept
case98	; reject
case99	; reject
case9A	reject

; From Upper maxX

caseA0	clippmaxX
	cmp.w	_maxY(pc),d3	; py > maxY?
	ble.b	1$
	clippmaxY
1$	accept
caseA1	clipqminX
	cmp.w	_maxY(pc),d5	; qy > maxY?
	ble.b	1$
	reject
1$	clippmaxY
	cmp.w	_maxX(pc),d2	; px > maxX?
	ble.b	2$
	clippmaxX
2$	accept
caseA2	reject
caseA4	clipqminY
	cmp.w	_maxX(pc),d4	; qx > maxX?
	ble.b	1$
	reject
1$	clippmaxX
	cmp.w	_maxY(pc),d3	; py > maxY?
	ble.b	2$
	clippmaxY
2$	accept
caseA5	clipqminX
	cmp.w	_maxY(pc),d5	; qy > maxY?
	ble.b	1$
	reject
1$	clippmaxX
	cmp.w	_minY(pc),d3	; py < minY?
	bge.b	2$
	reject
2$	cmp.w	_minY(pc),d5	; qy < minY?
	bge.b	3$
	clipqminY
3$	cmp.w	_maxY(pc),d3	; py > maxY?
	ble.b	4$
	clippmaxY
4$	accept
caseA6	; reject
caseA8	; reject
caseA9	; reject
caseAA	reject

dummycase reject
	
casetable
	dc.l	case00
	dc.l	case01
	dc.l	case02

	dc.l	dummycase ; 03

	dc.l	case04
	dc.l	case05
	dc.l	case06

	dc.l	dummycase ; 07

	dc.l	case08
	dc.l	case09
	dc.l	case0A

	dc.l	dummycase ; 0B 
	dc.l	dummycase ; 0C
	dc.l	dummycase ; 0D
	dc.l	dummycase ; 0E 
	dc.l	dummycase ; 0F

	dc.l	case10
	dc.l	case11
	dc.l	case12

	dc.l	dummycase ; 13

	dc.l	case14
	dc.l	case15
	dc.l	case16

	dc.l	dummycase ; 17

	dc.l	case18
	dc.l	case19
	dc.l	case1A

	dc.l	dummycase ; 1B 
	dc.l	dummycase ; 1C
	dc.l	dummycase ; 1D
	dc.l	dummycase ; 1E 
	dc.l	dummycase ; 1F

	dc.l	case20
	dc.l	case21
	dc.l	case22

	dc.l	dummycase ; 23

	dc.l	case24
	dc.l	case25
	dc.l	case26

	dc.l	dummycase ; 27

	dc.l	case28
	dc.l	case29
	dc.l	case2A

	dc.l	dummycase ; 2B 
	dc.l	dummycase ; 2C
	dc.l	dummycase ; 2D
	dc.l	dummycase ; 2E 
	dc.l	dummycase ; 2F
	dc.l	dummycase ; 30 
	dc.l	dummycase ; 31
	dc.l	dummycase ; 32
	dc.l	dummycase ; 33 
	dc.l	dummycase ; 34
	dc.l	dummycase ; 35 
	dc.l	dummycase ; 36
	dc.l	dummycase ; 37
	dc.l	dummycase ; 38 
	dc.l	dummycase ; 39
	dc.l	dummycase ; 3A
	dc.l	dummycase ; 3B 
	dc.l	dummycase ; 3C
	dc.l	dummycase ; 3D
	dc.l	dummycase ; 3E 
	dc.l	dummycase ; 3F

	dc.l	case40
	dc.l	case41
	dc.l	case42

	dc.l	dummycase ; 43

	dc.l	case44
	dc.l	case45
	dc.l	case46

	dc.l	dummycase ; 47

	dc.l	case48
	dc.l	case49
	dc.l	case4A

	dc.l	dummycase ; 4B 
	dc.l	dummycase ; 4C
	dc.l	dummycase ; 4D
	dc.l	dummycase ; 4E 
	dc.l	dummycase ; 4F

	dc.l	case50
	dc.l	case51
	dc.l	case52

	dc.l	dummycase ; 53

	dc.l	case54
	dc.l	case55
	dc.l	case56

	dc.l	dummycase ; 57

	dc.l	case58
	dc.l	case59
	dc.l	case5A

	dc.l	dummycase ; 5B 
	dc.l	dummycase ; 5C
	dc.l	dummycase ; 5D
	dc.l	dummycase ; 5E 
	dc.l	dummycase ; 5F

	dc.l	case60
	dc.l	case61
	dc.l	case62

	dc.l	dummycase ; 63

	dc.l	case64
	dc.l	case65
	dc.l	case66

	dc.l	dummycase ; 67

	dc.l	case68
	dc.l	case69
	dc.l	case6A

	dc.l	dummycase ; 6B 
	dc.l	dummycase ; 6C
	dc.l	dummycase ; 6D
	dc.l	dummycase ; 6E 
	dc.l	dummycase ; 6F

	dc.l	dummycase ; 70 
	dc.l	dummycase ; 71
	dc.l	dummycase ; 72
	dc.l	dummycase ; 73 
	dc.l	dummycase ; 74
	dc.l	dummycase ; 75 
	dc.l	dummycase ; 76
	dc.l	dummycase ; 77
	dc.l	dummycase ; 78 
	dc.l	dummycase ; 79
	dc.l	dummycase ; 7A
	dc.l	dummycase ; 7B 
	dc.l	dummycase ; 7C
	dc.l	dummycase ; 7D
	dc.l	dummycase ; 7E 
	dc.l	dummycase ; 7F

	dc.l	case80
	dc.l	case81
	dc.l	case82

	dc.l	dummycase ; 83

	dc.l	case84
	dc.l	case85
	dc.l	case86

	dc.l	dummycase ; 87

	dc.l	case88
	dc.l	case89
	dc.l	case8A

	dc.l	dummycase ; 8B 
	dc.l	dummycase ; 8C
	dc.l	dummycase ; 8D
	dc.l	dummycase ; 8E 
	dc.l	dummycase ; 8F

	dc.l	case90
	dc.l	case91
	dc.l	case92

	dc.l	dummycase ; 93

	dc.l	case94
	dc.l	case95
	dc.l	case96

	dc.l	dummycase ; 97

	dc.l	case98
	dc.l	case99
	dc.l	case9A

	dc.l	dummycase ; 9B 
	dc.l	dummycase ; 9C
	dc.l	dummycase ; 9D
	dc.l	dummycase ; 9E 
	dc.l	dummycase ; 9F

	dc.l	caseA0
	dc.l	caseA1
	dc.l	caseA2

	dc.l	dummycase ; A3

	dc.l	caseA4
	dc.l	caseA5
	dc.l	caseA6

	dc.l	dummycase ; A7

	dc.l	caseA8
	dc.l	caseA9
	dc.l	caseAA
	
	END

***********************************************************************
FILE: Cliptest.c
***********************************************************************

/* Cliptest.c, by John Schultz, a modification of: */

/* This is a line drawing demo for the Commodore/Amiga  */
/* Written by	John Riley, Lattice, Inc.		*/
/* 							*/

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <intuition/intuition.h>
#include <graphics/text.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <hardware/custom.h>

/***************** This is all you need for the FC clipper **************/

typedef struct {short px,py,qx,qy;} line;

extern short __asm clipline(register __a0 line * l);

extern unsigned short far minX,far minY,far maxX,far maxY;

/************************************************************************/

line l;

extern struct Custom far custom;
                                            
USHORT wakeup;	/* Wake me up for event */
USHORT class;	/* Intu event class */
USHORT code;	/* Intu event code */

struct Window *w;
struct RastPort *rp,*cdrp;
struct ViewPort *vp;
struct IntuiMessage *message;
int event(void);
long rand(void);
void srand(int);

/************************ Window Defines ********************************/

struct NewWindow nw = {
		0,0,			/* Starting corner */
		80,40,			/* Width, height */
		2,1,			/* detail, block pens */
	CLOSEWINDOW | NEWSIZE,		/* IDCMP flags */
	WINDOWDEPTH | WINDOWDRAG | WINDOWCLOSE | GIMMEZEROZERO | WINDOWSIZING,
					/* Window flags */
		NULL,			/* Pointer to first gadget */
		NULL,			/* Pointer to checkmark */
		"FC Clipper Test",	/* title */
		NULL,			/* screen pointer */
		NULL,			/* bitmap pointer */
		0,0,640,400,		/* window not sized */
		WBENCHSCREEN		/* type of screen */
		};

int co,xlim,ylim;

short centerx,centery;

main(int argc,char * argv[])
{
  unsigned short linesize,halflinesize;

  if (argc > 1) {
    linesize = atoi(argv[1]);
    if (linesize > 32767) {
      printf("Maximum line size exceeded, using 32767 (max).\n");
      linesize = 32767;
    }
  } else {
    printf("USAGE: cliptest <linesize>\n");
    printf("  using default linesize of 500.\n");
    linesize = 500;
  } 
  halflinesize = linesize >> 1;


/************************ Set-Up routines **********************************/
	GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0);
	if(GfxBase == NULL) return;
	IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
	if(IntuitionBase == NULL) 
		{
		CloseLibrary((struct Library *)GfxBase);
		return;
		}
	w = OpenWindow(&nw);
	rp = w->RPort;			/* Get the raster port pointer */
	vp = &w->WScreen->ViewPort;	/* Get the view port pointer */
	SetAPen(rp,3);			/* Set foreground pen to white */
	SetDrMd(rp,JAM1);		/* Draw with foreground pen */

	minX = 0;
	minY = 0;
	maxX = w->Width-1;
	maxY = w->Height-1;

	centerx = w->Width >> 1;
	centery = w->Height >> 1;

	co = 1;
	do {

 /**************************  FC clipper test code *************************/

                srand(custom.vhposr); /* video beam position */
		SetAPen(rp,co);
                co = (co+1) & 3;

                l.px = (rand() & linesize) - halflinesize + centerx;
                l.py = (rand() & linesize) - halflinesize + centery;
                l.qx = (rand() & linesize) - halflinesize + centerx;
                l.qy = (rand() & linesize) - halflinesize + centery;

                if (clipline(&l)) {
                  if ((l.px < minX) || (l.px > maxX)
                   || (l.py < minY) || (l.py > maxY)  
                   || (l.qx < minX) || (l.qx > maxX)
                   || (l.qy < minY) || (l.qy > maxY)) {
                    printf("FC Clip Error.\n");
                  } else {  
                    Move(rp,l.px,l.py);
		    Draw(rp,l.qx,l.qy);
                  }
                }

 /************************** End FC clipper test code ***********************/

		if(w->UserPort->mp_SigBit)
		{
			message = (struct IntuiMessage *)GetMsg(w->UserPort);
			if(message != NULL)
			{
				class = message->Class;
				code = message->Code;
				ReplyMsg((struct Message *)message);
			}
		}
	} while(event());
	CloseWindow(w);
	CloseLibrary((struct Library *)GfxBase);
	CloseLibrary((struct Library *)IntuitionBase);
}

int event()
{
	switch(class)
	{
		case CLOSEWINDOW:
			return(0);
		case NEWSIZE:
		    	maxX = w->Width-1;
			maxY = w->Height-1;
		 	centerx = w->Width >> 1;
			centery = w->Height >> 1;
			return(1);

	}
	return(1);
}

***********************************************************************
FILE: Makefile
***********************************************************************

cliptest: cliptest.o clip.o
  blink from lib:c.o cliptest.o clip.o to cliptest lib lib:lc.lib \
             lib:amiga.lib sd sc

cliptest.o: cliptest.c
  lc -O cliptest.c

clip.o:	clip.a
  comp:cape/cape -a clip.a -oclip.o

***********************************************************************
FILE: Clip2d.def
***********************************************************************

DEFINITION MODULE clip2d;

VAR
  XLeft,XRight,YTop,YBottom : INTEGER;

PROCEDURE clip2d(VAR px,py,qx,qy : INTEGER): BOOLEAN;

END clip2d.

***********************************************************************
FILE: Clip2d.mod
***********************************************************************

IMPLEMENTATION MODULE clip2d;

VAR
  code : CARDINAL;

PROCEDURE clip2d(VAR px,py,qx,qy : INTEGER): BOOLEAN;

(* These can be done in C with inline macros instead of functions *)

PROCEDURE ClipPBottom;
BEGIN
  px := (qx - px)*(YBottom - py) DIV (qy - py) + px;
  py := YBottom;
END ClipPBottom;

PROCEDURE ClipPTop;
BEGIN
  px := (qx - px)*(YTop - py) DIV (qy - py) + px;
  py := YTop;
END ClipPTop;

PROCEDURE ClipPRight;
BEGIN
  py := (qy - py)*(XRight - px) DIV (qx - px) + py;
  px := XRight;
END ClipPRight;

PROCEDURE ClipPLeft;
BEGIN
  py := (qy - py)*(XLeft - px) DIV (qx - px) + py;
  px := XLeft;
END ClipPLeft;

PROCEDURE ClipQBottom;
BEGIN
  qx := (px - qx)*(YBottom - qy) DIV (py - qy) + qx;
  qy := YBottom;
END ClipQBottom;

PROCEDURE ClipQTop;
BEGIN
  qx := (px - qx)*(YTop - qy) DIV (py - qy) + qx;
  qy := YTop;
END ClipQTop;

PROCEDURE ClipQRight;
BEGIN
  qy := (py - qy)*(XRight - qx) DIV (px - qx) + qy;
  qx := XRight;
END ClipQRight;

PROCEDURE ClipQLeft;
BEGIN
  qy := (py - qy)*(XLeft - qx) DIV (px - qx) + qy;
  qx := XLeft;
END ClipQLeft;

BEGIN
  code := 0;
  
  IF qy > YBottom THEN
    INC(code,8);
  ELSIF qy < YTop THEN
    INC(code,4);
  END;

  IF qx > XRight THEN
    INC(code,2);
  ELSIF qx < XLeft THEN
    INC(code,1);
  END;

  IF py > YBottom THEN
    INC(code,128);
  ELSIF py < YTop THEN
    INC(code,64);
  END;

  IF px > XRight THEN
    INC(code,32);
  ELSIF px < XLeft THEN
    INC(code,16);
  END;
  
  CASE code OF

   (**************  From Center ***************)

    00H : RETURN TRUE;
  | 01H : ClipQLeft; 
          RETURN TRUE;
  | 02H : ClipQRight; 
          RETURN TRUE;
  | 04H : ClipQTop;
          RETURN TRUE;
  | 05H : ClipQLeft;
          IF qy < YTop THEN
            ClipQTop;
          END;
          RETURN TRUE;
  | 06H : ClipQRight;
          IF qy < YTop THEN
            ClipQTop;
          END;
          RETURN TRUE;
  | 08H : ClipQBottom;
          RETURN TRUE;
  | 09H : ClipQLeft;
          IF qy > YBottom THEN
            ClipQBottom;
          END;
          RETURN TRUE;
  | 0AH : ClipQRight;
          IF qy > YBottom THEN
            ClipQBottom;
          END;
          RETURN TRUE;

  (**************  From Left ***************)

  | 10H : ClipPLeft;
          RETURN TRUE;
  | 11H : RETURN FALSE;
  | 12H : ClipPLeft;
          ClipQRight;
          RETURN TRUE;
  | 14H : ClipPLeft;
          IF py < YTop THEN
            RETURN FALSE;
          ELSE
            ClipQTop;
            RETURN TRUE;
          END;
  | 15H : RETURN FALSE;
  | 16H : ClipPLeft;
          IF py < YTop THEN
            RETURN FALSE;
          ELSE
            ClipQTop;
            IF qx > XRight THEN
              ClipQRight;
            END;
            RETURN TRUE;
          END;
  | 18H : ClipPLeft;
          IF py > YBottom THEN
            RETURN FALSE;
          ELSE
            ClipQBottom;
            RETURN TRUE;
          END;
  | 19H : RETURN FALSE;
  | 1AH : ClipPLeft;
          IF py > YBottom THEN
            RETURN FALSE;
          ELSE
            ClipQBottom;
            IF qx > XRight THEN
              ClipQRight;
            END;
            RETURN TRUE;
          END;

  (**************  From Right ***************)

  | 20H : ClipPRight;
          RETURN TRUE;
  | 21H : ClipPRight;
          ClipQLeft;
          RETURN TRUE;
  | 22H : RETURN FALSE;
  | 24H : ClipPRight;
          IF py < YTop THEN
            RETURN FALSE;
          ELSE
            ClipQTop;
            RETURN TRUE;
          END;
  | 25H : ClipPRight;
          IF py < YTop THEN
            RETURN FALSE;
          ELSE
            ClipQTop;
            IF qx < XLeft THEN
              ClipQLeft;
            END;
            RETURN TRUE;
          END;
  | 26H : RETURN FALSE;
  | 28H : ClipPRight;
          IF py > YBottom THEN
            RETURN FALSE;
          ELSE
            ClipQBottom;
            RETURN TRUE;
          END;
  | 29H : ClipPRight;
          IF py > YBottom THEN
            RETURN FALSE;
          ELSE
            ClipQBottom;
            IF qx < XLeft THEN
              ClipQLeft;
            END;
            RETURN TRUE;
          END;
  | 2AH : RETURN FALSE;
   
  (**************  From Top ***************)

  | 40H : ClipPTop;
          RETURN TRUE;
  | 41H : ClipPTop;
          IF px < XLeft THEN
            RETURN FALSE;
          ELSE
            ClipQLeft;
            IF qy < YTop THEN
              ClipQTop;
            END;
            RETURN TRUE;
          END;
  | 42H : ClipPTop;
          IF px > XRight THEN
            RETURN FALSE;
          ELSE
            ClipQRight;
            RETURN TRUE;
          END;
  | 44H : RETURN FALSE;
  | 45H : RETURN FALSE;
  | 46H : RETURN FALSE;
  | 48H : ClipPTop;
          ClipQBottom;
          RETURN TRUE;
  | 49H : ClipPTop;
          IF px < XLeft THEN
            RETURN FALSE;
          ELSE
            ClipQLeft;
            IF qy > YBottom THEN
              ClipQBottom;
            END;
            RETURN TRUE;
          END;
  | 4AH : ClipPTop;
          IF px > XRight THEN
            RETURN FALSE;
          ELSE
            ClipQRight;
            IF qy > YBottom THEN
              ClipQBottom;
            END;
            RETURN TRUE;
          END;

  (**************  From Bottom ***************)

  | 50H : ClipPLeft;
          IF py < YTop THEN
            ClipPTop;
          END;
          RETURN TRUE;
  | 51H : RETURN FALSE;
  | 52H : ClipQRight;
          IF qy < YTop THEN
            RETURN FALSE;
          ELSE
            ClipPTop;
            IF px < XLeft THEN
              ClipPLeft;
            END;
            RETURN TRUE;
          END;
  | 54H : RETURN FALSE;
  | 55H : RETURN FALSE;
  | 56H : RETURN FALSE;
  | 58H : ClipQBottom;
          IF qx < XLeft THEN
            RETURN FALSE;
          ELSE
            ClipPTop;
            IF px < XLeft THEN
              ClipPLeft;
            END;
            RETURN TRUE;
          END;
  | 59H : RETURN FALSE;
  | 5AH : ClipPLeft;
          IF py > YBottom THEN
            RETURN FALSE;
          ELSE
            ClipQRight;
            IF qy < YTop THEN
              RETURN FALSE;
            ELSE
              IF py < YTop THEN
                ClipPTop;
              END;
              IF qy > YBottom THEN
                ClipQBottom;
              END;
              RETURN TRUE;
            END;
          END;

  (**************  From Lower Right ***************)

  | 60H : ClipPRight;
          IF py < YTop THEN
            ClipPTop;
          END;
          RETURN TRUE;
  | 61H : ClipQLeft;
          IF qy < YTop THEN
            RETURN FALSE;
          ELSE
            ClipPTop;
            IF px > XRight THEN
              ClipPRight;
            END;
            RETURN TRUE;
          END;
  | 62H : RETURN FALSE;
  | 64H : RETURN FALSE;
  | 65H : RETURN FALSE;
  | 66H : RETURN FALSE;
  | 68H : ClipQBottom;
          IF qx > XRight THEN
            RETURN FALSE;
          ELSE
            ClipPRight;
            IF py < YTop THEN
              ClipPTop;
            END;
            RETURN TRUE;
          END;
  | 69H : ClipQLeft;
          IF qy < YTop THEN
            RETURN FALSE;
          ELSE
            ClipPRight;
            IF py > YBottom THEN
              RETURN FALSE;
            ELSE
              IF qy > YBottom THEN
                ClipQBottom;
              END;
              IF py < YTop THEN
                ClipPTop;
              END;
              RETURN TRUE;
            END;
          END;
  | 6AH : RETURN FALSE;

  (**************  From Bottom ***************)
   
  | 80H : ClipPBottom;
          RETURN TRUE;
  | 81H : ClipPBottom;
          IF px < XLeft THEN
            RETURN FALSE;
          ELSE
            ClipQLeft;
            RETURN TRUE;
          END;
  | 82H : ClipPBottom;
          IF px > XRight THEN
            RETURN FALSE;
          ELSE
            ClipQRight;
            RETURN TRUE;
          END;
  | 84H : ClipPBottom;
          ClipQTop;
          RETURN TRUE;
  | 85H : ClipPBottom;
          IF px < XLeft THEN
            RETURN FALSE;
          ELSE
            ClipQLeft;
            IF qy < YTop THEN
              ClipQTop;
            END;
            RETURN TRUE;
          END;
  | 86H : ClipPBottom;
          IF px > XRight THEN
            RETURN FALSE;
          ELSE
            ClipQRight;
            IF qy < YTop THEN
              ClipQTop;
            END;
            RETURN TRUE;
          END;
  | 88H : RETURN FALSE;
  | 89H : RETURN FALSE;
  | 8AH : RETURN FALSE;

  (**************  From Bottom ***************)

  | 90H : ClipPLeft;
          IF py > YBottom THEN
            ClipPBottom;
          END;
          RETURN TRUE;
  | 91H : RETURN FALSE;
  | 92H : ClipQRight;
          IF qy > YBottom THEN
            RETURN FALSE;
          ELSE
            ClipPBottom;
            IF px < XLeft THEN
              ClipPLeft;
            END;
            RETURN TRUE;
          END;
  | 94H : ClipQTop;
          IF qx < XLeft THEN
            RETURN FALSE;
          ELSE
            ClipPLeft;
            IF py > YBottom THEN
              ClipPBottom;
            END;
            RETURN TRUE;
          END;
  | 95H : RETURN FALSE;
  | 96H : ClipPLeft;
          IF py < YTop THEN
            RETURN FALSE;
          ELSE
            ClipQRight;
            IF qy > YBottom THEN
              RETURN FALSE;
            ELSE
              IF py > YBottom THEN
                ClipPBottom;
              END;
              IF qy < YTop THEN
                ClipQTop;
              END;
              RETURN TRUE;
            END;
          END;
  | 98H : RETURN FALSE;
  | 99H : RETURN FALSE;
  | 9AH : RETURN FALSE;

  (**************  From Bottom ***************)

  | 0A0H : ClipPRight;
           IF py > YBottom THEN
             ClipPBottom;
           END;
           RETURN TRUE;
  | 0A1H : ClipQLeft;
           IF qy > YBottom THEN
             RETURN FALSE;
           ELSE
             ClipPBottom;
             IF px > XRight THEN 
               ClipPRight;
             END;
             RETURN TRUE;
           END;
  | 0A2H : RETURN FALSE;
  | 0A4H : ClipQTop;
           IF qx > XRight THEN
             RETURN FALSE;
           ELSE
             ClipPRight;
             IF py > YBottom THEN
               ClipPBottom;
             END;
             RETURN TRUE;
           END;
  | 0A5H : ClipQLeft;
           IF qy > YBottom THEN
             RETURN FALSE;
           ELSE
             ClipPRight;
             IF py < YTop THEN
               RETURN FALSE;
             ELSE
               IF qy < YTop THEN
                 ClipQTop;
               END;
               IF py > YBottom THEN
                 ClipPBottom;
               END;
               RETURN TRUE;
             END;
           END;
  | 0A6H : RETURN FALSE;
  | 0A8H : RETURN FALSE;
  | 0A9H : RETURN FALSE;
  | 0AAH : RETURN FALSE;

  (************** Error Trap ***************)

  ELSE  (* Undefined Code *)

    RETURN FALSE;

  END; (* CASE code *)

END clip2d;

BEGIN
  XLeft   := 0;
  XRight  := 319;
  YTop    := 0;
  YBottom := 199;
END clip2d.

***********************************************************************
No more files.
***********************************************************************