; Voxelspace Source
; 1994 Magna Media / Amiga Magazin
; von Gürkan Demirci
; und Christoph Stahl
;
; (ASM-ONE source)

; Linker Mausknopf = Verlassen
; Rechter Mausknopf= Hohenändern

; Benutzte Kennungen
;--------------------
; STRK	=	Struktur
; INFO	=	Informations Struktur
; CPU	=	Rechentabellen
; BUF	=	Arbeitsspeicher
; HARD	=	Hardwareroutinen
; INI	=	Initialisierungsroutinen
; RAM	=	Speicherroutinen
; SUB	=	Unterfunktionen
; BEOB	=	Beobachter
; CALC	=	Variable Größen
; MODE	=	Modus werte

; Beobachter
BEOB_Radius1	=	40
BEOB_Radius2	=	200
BEOB_Winkel	=	70		;(0-360)
; Blickkreis
MODE_Punkte	=	%01		;(%00=032, %01=064, %10=128, %11=256)
MODE_Geraden	=	%10		;(%00=128, %01=256, %10=512, %11=1024)
; Bildschirm
MODE_Spalten	=	%01		;(%00=040, %01=080, %10=160, %11=320)
MODE_Bild	=	%01		;(%00=128, %01=256, %10=512, %11=1024)
MODE_Farbe	=	%00		;(%00=016, %01=032, %10=064, %11=256)
; Perspektive
MODE_Hohe	=	%01		;(%00=  1, %01=  4, %10=  8, %11= 16)
PERS_FluchtX	=	216
PERS_FluchtY	=	256+128
PERS_Obenstart	=	128+32
PERS_Obenend	=	128+32+200
PERS_Untenstart	=	128
PERS_Untenend	=	128+200



	IF	MODE_Hohe=%00
		CALC_Hohe=1
	ENDIF
	IF	MODE_Hohe=%01
		CALC_Hohe=4
	ENDIF
	IF	MODE_Hohe=%10
		CALC_Hohe=8
	ENDIF
	IF	MODE_Hohe=%11
		CALC_Hohe=16
	ENDIF
	IF	MODE_Spalten=%00
		CALC_Spalten=40
		CALC_draw=$ff00
		CALC_roll=8
	ENDIF
	IF	MODE_Spalten=%01
		CALC_Spalten=80
		CALC_draw=$f000
		CALC_roll=4
	ENDIF
	IF	MODE_Spalten=%10
		CALC_Spalten=160
		CALC_draw=$c000
		CALC_roll=2
	ENDIF
	IF	MODE_Spalten=%11
		CALC_Spalten=320
		CALC_draw=$8000
		CALC_roll=1
	ENDIF
	IF	MODE_Punkte=%00
		CALC_Punkte=32
		CALC_Pshift=5
	ENDIF
	IF	MODE_Punkte=%01
		CALC_Punkte=64
		CALC_Pshift=6
	ENDIF
	IF	MODE_Punkte=%10
		CALC_Punkte=128
		CALC_Pshift=7
	ENDIF
	IF	MODE_Punkte=%11
		CALC_Punkte=256
		CALC_Pshift=8
	ENDIF
	IF	MODE_Geraden=%00
		CALC_Geraden=128
		CALC_Gshift=7
	ENDIF
	IF	MODE_Geraden=%01
		CALC_Geraden=256
		CALC_Gshift=8
	ENDIF
	IF	MODE_Geraden=%10
		CALC_Geraden=512
		CALC_Gshift=9
	ENDIF
	IF	MODE_Geraden=%11
		CALC_Geraden=1024
		CALC_Gshift=10
	ENDIF
	IF	MODE_Bild=%00
		CALC_Bild=128
		CALC_Shift=8
		CALC_Mask=%111111101111111
	ENDIF
	IF	MODE_Bild=%01
		CALC_Bild=256
		CALC_Shift=9
		CALC_Mask=%11111111011111111
	ENDIF
	IF	MODE_Bild=%10
		CALC_Bild=512
		CALC_Shift=10
		CALC_Mask=%1111111110111111111
	ENDIF
	IF	MODE_Bild=%11
		CALC_Bild=1024
		CALC_Shift=11
		CALC_Mask=%111111111101111111111
	ENDIF
	IF	MODE_FARBE=%00
		CALC_FARBE=16
		NAME_FARBE=0
	ENDIF
	IF	MODE_FARBE=%01
		CALC_FARBE=32
		NAME_FARBE=32
	ENDIF
	IF	MODE_FARBE=%10
		CALC_FARBE=64
		NAME_FARBE=64
	ENDIF
	IF	MODE_FARBE=%11
		CALC_FARBE=256
		NAME_FARBE=96
	ENDIF


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

Programmstart

; Programm Kopf
;---------------
; Speicher reservieren.
; Datenstrukturen initialisieren.
; Hardwarezustand speichern.
; Hardwarezustand aktivieren.
 
		jsr	RAM_reservieren
		bmi	.error1

		jsr	INI_Datenstrukturen
		bmi	.error2

		jsr	HARD_Speichern

		jsr	HARD_Aktivieren

		lea	$dff002,a6
		move.l	#Interrupt,[$6C].W
		move.w	#$c020,$DFF09a
; Schleife 1
;------------
; Bildspeicher löschen.
; Mausbewegung abfragen.
; Beobachterrichtung berechnen.
; Beobachterposition berechnen.
; Bildberechnen.
; Bild wechseln.
; Meldung an Schleife 2.  (Interrupt)

.Schleife1
		jsr	SUB_Clrscreen
		jsr	SUB_Maus
		jsr	SUB_BEOB_Hohe
		jsr	SUB_BEOB_Richtung
		jsr	SUB_BEOB_Position
		jsr	MAIN
		jsr	SUB_Chgscreen
		jsr	SUB_Schleife2meldung

		btst	#6,$bfe001
		bne.w	.Schleife1


; Programm abbruch
;------------------
; Hardwarezustand zurücksetzen.
; Speicher freigeben.

		jsr	HARD_Laden
		jsr	RAM_freigeben
.QUIT		moveq	#0,d0
		rts
.error1		moveq	#0,d0
		rts
.error2		jsr	RAM_freigeben
		bra.s	.error1

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

; Schleife 2 ( Verticalblank interrupt )
; Bei einem neuen Bildaufbau, wechselt diese Routine
; das Bild auf das schon berechnete Bild.

Interrupt
		movem.l	d0-d7/a0-a5,-(a7)
		tst.b	Bildwechseln
		beq.s	.nichtwechseln
		sf	Bildwechseln
		BSR	SUB_SetScreen
.nichtwechseln	movem.l	(a7)+,d0-d7/a0-a5
		move.w	#$0020,$DFF09C
		rte
Bildwechseln	dc.b	0
		even

****************************************************************
; Hauproutine
; Diese Routine berechnet das Voxelspace Bild.

MAIN
		move.l	STRK_CPU_Blickkreis(PC),a0
		move.l	STRK_CPU_Offnungswinkel(PC),a1
		move.l	STRK_INFO_Landschaft(PC),a2
		lea	CALC_BILD(a2),a3
		move.l	STRK_CPU_Perspektive(PC),a4
		add.l	Hohenoffset(PC),a4
		move.l	STRK_CPU_Rasterwerte(PC),a5

		move.w	BEOB_Richtung(PC),d0
		sub.w	#CALC_Geraden*BEOB_winkel/360/2,d0
		and.w	#CALC_Geraden-1,d0
		mulu	#CALC_Punkte*4,d0		;Blickgeraden Offset

		movem.w	BEOB_Position(PC),d1/d2
		moveq	#CALC_SHIFT,d7
		lsl.l	d7,d2
		or.w	d1,d2				;Beobachter position
		move.l	#CALC_MASK,d1			;Überlauf Maske

		move.w	#CALC_Spalten-1,d7		;Anzahl Spalten


		move.l	STRK_BUF_Screen(PC),d6
		add.l	Screenoffset(PC),d6
		add.l	#40*255*4-40,d6

.busy3		btst	#6,(a6)
		bne.s	.busy3
		move.l	#-1,$44-2(a6)
		move.w	#2,$42-2(a6)
		move.w	#38,$66-2(a6)
		move.w	#38,$62-2(a6)
		clr.w	$60-2(a6)

		move.w	#CALC_draw,d5
.GeradenSchleife
		movem.l	d2/a0,-(a7)
		add.l	(a1)+,d0			;Geraden Offset
		and.l	#[CALC_Geraden-1]*CALC_Punkte*4,d0
		add.l	d0,a0
		move.l	#$ff00,d3
		moveq	#1,d4				;Höhealt

		swap	d7
		move.w	#CALC_Punkte-1,d7
.busy2		btst	#6,(a6)
		bne.s	.busy2
		move.l	d6,$54-2(a6)
		move.l	d6,$4c-2(a6)
		move.w	d5,$74-2(a6)

.PunkteSchleife
		add.w	#$100,d3
		add.l	(a0)+,d2
		and.l	d1,d2
		move.b	(a2,d2.l),d3
		move.b	(a4,d3.l),d3			;Höheneu
		dbne	d7,.PunkteSchleife
		beq.s	.Spalteok
		sub.b	d4,d3				;Höhealt,Höhene
		dbcc	d7,.PunkteSchleife
		bcs.s	.Spalteok
		add.b	d3,d4
		swap	d4
		clr.w	d4
		move.b	(a3,d2.l),d4			;Farbe
		lsl.w	#3,d4
.busy		btst	#6,(a6)
		bne.s	.busy
		move.l	(a5,d4.w),$48-2(a6)		;Farbe
		move.w	4(a5,d4.w),$40-2(a6)
		clr.w	d4
		move.b	d3,d4
		lsl.w	#3,d4
		move.w	6(a5,d4.w),$58-2(a6)		;Höhe
		swap	d4
		addq.b	#1,d4				;Höhealt
		beq.s	.Spalteok
		dbf	d7,.PunkteSchleife
.Spalteok	movem.l	(a7)+,d2/a0
		ror.w	#CALC_roll,d5
		cmp.w	#CALC_draw,d5
		bne.s	.cc
		addq.l	#2,d6
.cc		swap	d7
		dbf	d7,.GeradenSchleife
		rts


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

; Unterfunktionen
;-----------------
; SUB_Clrscreen
; SUB_Chgscreen
; SUB_Schleife2meldung
; SUB_Setscreen
; SUB_Maus
; SUB_BEOB_Position
; SUB_BEOB_Richtung

; Diese Routine löscht das aktuelle Screen.
SUB_Clrscreen
		move.l	Screenoffset(PC),d0
		add.l	STRK_BUF_screen(PC),d0
.busy		btst	#6,(a6)
		bne.s	.busy
		move.l	#$1000000,$40-2(a6)
		clr.w	$66-2(a6)
		move.l	d0,$54-2(a6)
		move.w	#255*4*64+40/2,$58-2(a6)
		rts

; Diese Routine erhöht den Screenoffset um ein Bild.
; Bei einem überlauf, wird das erste Screen wieder benutzt.
; Insgesammt werden drei Screens benutzt.
SUB_Chgscreen
		move.l	Screenoffset(PC),d0
		add.l	#255*40*4,d0
		cmp.l	#255*40*4*3,d0
		blt.s	.keinuberlauf
		clr.l	d0
.keinuberlauf	move.l	d0,Screenoffset
		rts

; Diese Routine setzt die Meldung in einem Flag, damit
; die Interruptroutine feststellen kann, ob ein
; Bildwechsel statt finden soll.
SUB_Schleife2meldung
		st	Bildwechseln
		rts

; Diese Routine setzt die Screenpointer in der Copperliste.
SUB_Setscreen
		move.l	Screenoffset(PC),d0
		sub.l	#40*255*4,d0
		bpl.s	.keinuberlauf
		move.l	#40*255*4*2,d0
.keinuberlauf	add.l	STRK_BUF_screen(PC),d0
		move.l	d0,a0
		move.l	PTR_screen(PC),a1
		addq.w	#2,a1
		moveq	#3,d1
.loop		move.l	a0,d0
		move.w	d0,4(a1)
		swap	d0
		move.w	d0,(a1)
		addq.w	#8,a1
		add.w	#40,a0
		dbf	d1,.loop
		rts
Screenoffset	dc.l	0
PTR_screen	dc.l	0				;pointer of copper

; Diese Routine liest die Aktuellen Mausbewegungsdaten, um
; danach die Beobachteposition und -richtung zu berechnen
SUB_Maus
		move.w	$a-2(a6),d0
		move.w	Mausraw(PC),d1
		move.w	d0,Mausraw
		move.w	d0,d2
		move.w	d1,d3
		lsr.w	#8,d0
		and.w	#$ff,d2
		lsr.w	#8,d1
		and.w	#$ff,d3
		sub.w	d1,d0
		sub.w	d3,d2
		ext.w	d0
		ext.w	d2
		movem.w	d0/d2,Mausdata
		rts
Mausraw		dc.w	0
Mausdata	dc.w	0,0

; Diese Routine berechnet die aktuelle Perspektivenoffset, für die
; verschiedenen Höhen.
SUB_BEOB_Hohe
		btst	#10,$16-2(a6)		;linke Maustaste
		bne.s	.nicht
		lea	Hohenoffset(PC),a0
		lea	.Hohe(PC),a1
		move.w	(a1),d0
		tst.w	Mausdata
		beq.s	.nicht
		bmi.s	.nachOben
.nachUnten	subq.w	#1,d0
		bpl.s	.Hoheok
		clr.w	d0
		bra.s	.Hoheok
.nachOben	addq.w	#1,d0
		cmp.w	#CALC_Hohe-1,d0
		ble.s	.Hoheok
		move.w	#CALC_Hohe-1,d0
.Hoheok		move.w	d0,(a1)
		mulu	#256*CALC_Punkte,d0
		move.l	d0,(a0)
.nicht		rts

.Hohe		dc.w	0
Hohenoffset	dc.l	0

; Diese Routine berechnet die aktuelle Beobachterposition,
; mit hilfe der Angaben, die die SUB_Maus-routine liefert.
SUB_BEOB_Position
		move.l	STRK_CPU_winkel(PC),a0
		move.w	BEOB_Richtung(PC),d0
		lea	BEOB_Position(PC),a1
		mulu	#1024/CALC_Geraden*4,d0
		and.w	#$ffc,d0
		move.w	Mausdata(PC),d1
		movem.w	(a0,d0.w),d2/d3
		muls	d1,d2
		muls	d1,d3
		asr.l	#2,d2				;xadd:8
		asr.l	#2,d3				;yadd:8
		swap	d2
		swap	d3
		movem.w	(a1),d4/d5
		sub.w	d2,d4
		sub.w	d3,d5
		and.w	#CALC_Bild-1,d4
		and.w	#CALC_Bild-1,d5
		movem.w	d4/d5,(a1)
		rts
BEOB_Position	dc.w	0,0

; Diese Routine berechnet die aktuelle Beobachterrichtung
; mit hilfe der Angaben, die die SUB_Maus-routine liefert.
SUB_BEOB_Richtung
		move.w	Mausdata+2(PC),d0
		add.w	d0,BEOB_Richtung
		rts
BEOB_Richtung	dc.w	0

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

; RAM_reservieren (MODE) (D0)	Speicher reservieren
; RAM_freigeben			Speicher freigeben

Exec_base		equ	$04
AllocEntry		equ	-222
FreeEntry		equ	-228
MemListlen		equ	88

; Diese Routine benutzt die DOS MemList-Struktur, um den benötigten
; Speicher für die INFO, CPU und BUF-Datenstrukturen zu reservieren.
; Konnte der Speicher nicht reserviert werden, wird bei Verlassen
; der Routine, das negativ Flag gesetzt.
; Um auf den reservierten Speicher nicht über die MemList-Struktur
; zugreifen zu müssen, wird die neue MemList in die alte MemList
; kopiert.

; Speicher reservieren
;-----------------
; Landschaftsdaten
; Farbrasterdaten
; Blickkreis
; Perspektive
; Rasterwerte
; Winkelfunktionen
; Bildspeicher
; Copperspeicher

RAM_reservieren
		move.l	[Exec_base].W,a6
		lea	MemList(PC),a0
		jsr	AllocEntry(a6)
		tst.l	d0
		bmi.s	.error
		move.l	d0,MemListadrs
		move.l	d0,a1
		lea	MemList(PC),a0
		moveq	#MemListlen-1,d0
.copynxt	move.b	(a1)+,(a0)+
		dbf	d0,.copynxt
		moveq	#0,d0
.error		rts

; Speicher freigeben
;-----------------
; Landschaftsdaten
; Farbrasterdaten
; Blickkreis
; Perspektive
; Rasterwerte
; Winkelfunktionen
; Bildspeicher
; Copperspeicher

RAM_freigeben
		move.l	[Exec_base].W,a6
		move.l	MemListadrs(PC),a0
		jsr	FreeEntry(a6)
		rts
MEMF_CHIP		equ	$02
MEMF_PUBLIC		equ	$01
MEMF_CLEAR		equ	$10000
MemListadrs		dc.l	0
MemList			dc.l	0			;node_succ
			dc.l	0			;node_pred
			dc.b	10			;node_type
			dc.b	0			;node_pri
			dc.l	0			;node_name
			dc.w	9			;ML_numentries
STRK_INFO_Landschaft	dc.l	MEMF_PUBLIC		;ML_reqs
SLEN_INFO_Landschaft	dc.l	CALC_Bild*CALC_Bild*2	;ML_lenght
STRK_INFO_Farbraster	dc.l	MEMF_CHIP		;ML_reqs
SLEN_INFO_Farbraster	dc.l	CALC_FARBE*255*4*2	;ML_lenght
STRK_CPU_Blickkreis	dc.l	MEMF_PUBLIC		;ML_reqs
SLEN_CPU_Blickkreis	dc.l	CALC_Geraden*CALC_Punkte*4	;ML_lenght
STRK_CPU_Offnungswinkel	dc.l	MEMF_PUBLIC		;ML_reqs
SLEN_CPU_Offnungswinkel	dc.l	CALC_Spalten*4		;ML_lenght
STRK_CPU_Perspektive	dc.l	MEMF_PUBLIC		;ML_reqs
SLEN_CPU_Perspektive	dc.l	256*CALC_Punkte*CALC_Hohe	;ML_lenght
STRK_CPU_Rasterwerte	dc.l	MEMF_PUBLIC		;ML_reqs
SLEN_CPU_Rasterwerte	dc.l	256*8			;ML_lenght
STRK_CPU_Winkel		dc.l	MEMF_PUBLIC		;ML_reqs
SLEN_CPU_Winkel		dc.l	4096			;ML_lenght
STRK_BUF_Screen		dc.l	MEMF_CHIP!MEMF_CLEAR	;ML_reqs
SLEN_BUF_Screen		dc.l	40*255*4*3		;ML_lenght
STRK_BUF_Copper		dc.l	MEMF_CHIP		;ML_reqs
SLEN_BUF_Copper		dc.l	37*4			;ML_lenght

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

; INI_Datenstrukturen	(D0)	(MODE)

OldOpenLib	equ	-408
CloseLib	equ	-414
Open		equ	-30
Close		equ	-36
Read		equ	-42
Mode_old	equ	1005

; Diese Routine initialisiert die reservierten Datenstrukturen.
; Bei Informationsdatenstrukturen(INFO) werden die Daten von
; einer Peripherie geladen. (s.h. NAME)
; Bei Rechentabellen werden die Daten in die Struktur hinein
; berechnet.

; INI_Datenstrukturen
;---------------------
; Landschaftdaten
; Farbrasterdaten
; Blickkreis
; Perspektive
; Rasterwerte
; Winkelfunktionen
; Copper

INI_Datenstrukturen
		lea	NAME_INFO_Landschaft(PC),a0
		jsr	INI_INFO_Landschaft
		bmi.s	.error
		lea	NAME_CPU_Winkel(PC),a0
		jsr	INI_CPU_Winkel
		bmi.s	.error
		lea	NAME_INFO_RASTER+NAME_FARBE(PC),a0
		jsr	INI_INFO_Farbraster
		bmi.s	.error
		jsr	INI_BUF_Copper
		bmi.s	.error
		jsr	INI_CPU_Blickkreis
		bmi.s	.error
		jsr	INI_CPU_Offnungswinkel
		bmi.s	.error
		jsr	INI_CPU_Perspektive
		bmi.s	.error
		jsr	INI_CPU_Rasterwerte
		bmi.s	.error
		moveq	#0,d0
		rts
.error		moveq	#-1,d0
		rts

NAME_INFO_RASTER
		dc.b	"RAST16.iff",0,0
		blk.b	20
		dc.b	"RAST32.iff",0,0
		blk.b	20
		dc.b	"RAST64.iff",0,0
		blk.b	20
		dc.b	"RAST256.iff",0
		blk.b	20
NAME_INFO_Landschaft
		dc.b	"Landschaft.dta",0
		even
NAME_CPU_Winkel	dc.b	"SinCos.dta",0
		even
NAME_DOSlib	dc.b	"dos.library",0
		even

; Diese Routine Läd die Landschaftdaten (Höhen- und Farbinformationen)
; Der Name des Files muß in A0 übergeben werden.
INI_INFO_Landschaft	;(A0) (AdrsName)
		BSR	INI_OpenLib
		beq.s	INI_error1
		move.l	d0,a6
		BSR	INI_OpenFile
		beq.s	INI_error2
		move.l	d0,a5
		move.l	a5,d1
		move.l	STRK_INFO_Landschaft(PC),d2
		move.l	SLEN_INFO_Landschaft(PC),d3
		jsr	Read(a6)
		cmp.l	SLEN_INFO_Landschaft(PC),d0
		bne.s	INI_error3
		BSR	INI_CloseFile
		BSR	INI_CloseLib
		moveq	#0,d0
		rts
INI_error1	moveq	#-1,d0
		rts
INI_error2	BSR	INI_CloseLib
		bra.s	INI_error1
INI_error3	BSR	INI_CloseFile
		BSR	INI_CloseLib
		bra.s	INI_error1
INI_OpenFile	;(A0)	(adrsName)
		move.l	a0,d1
		move.l	#Mode_old,d2
		jsr	Open(a6)
		tst.l	d0
		rts
INI_CloseFile	;(A5) (adrsHandle)
		move.l	a5,d1
		jmp	Close(a6)
INI_OpenLib	movem.l	d1-d7/a0-a6,-(a7)
		move.l	[Exec_base].W,a6
		lea	NAME_DOSlib(PC),a1
		jsr	OldOpenLib(a6)
		movem.l	(a7)+,d1-d7/a0-a6
		tst.l	d0
		rts
INI_CloseLib	;(A6) (adrsLib)
		move.l	a6,a1
		move.l	[Exec_base].W,a6
		jmp	CloseLib(a6)

; Diese Routine Läd die Winkelfunktionen (Sinus- und Cosinusfunktionsdaten)
; Der Name des Files muß in A0 übergeben werden.
INI_CPU_Winkel	;(A0)	(AdrsName)
		BSR	INI_OpenLib
		beq.s	INI_error1
		move.l	d0,a6
		BSR	INI_OpenFile
		beq.s	INI_error2
		move.l	d0,a5
		move.l	a5,d1
		move.l	STRK_CPU_Winkel(PC),d2
		move.l	SLEN_CPU_Winkel(PC),d3
		jsr	Read(a6)
		cmp.l	SLEN_CPU_Winkel(PC),d0
		bne.s	INI_error3
		BSR	INI_CloseFile
		BSR	INI_CloseLib
		moveq	#0,d0
		rts

; Diese Routine läd die Werte für die Farbrasterstruktur.
INI_INFO_Farbraster ;(a0=*name)
		BSR	INI_OpenLib
		beq.w	INI_error1
		move.l	d0,a6
		BSR	INI_OpenFile
		beq.w	INI_error2
		move.l	d0,a5
		move.l	a5,d1
		move.l	STRK_BUF_Screen(PC),d2
		move.l	#256*4*40,d3
		jsr	Read(a6)
		tst.l	d0
		beq.w	INI_error3
		BSR	INI_CloseFile
		BSR	INI_CloseLib
		BSR	SUB_IFF
		bmi.w	INI_error1
		move.l	STRK_INFO_Farbraster(PC),a0
		move.l	STRK_BUF_SCREEN(PC),a1
		add.l	#256*4*40,a1
		moveq	#0,d0
.loop1		move.w	#$f0,d1
		and.w	d0,d1
		lsr.w	#3,d1
		lea	(a1,d1.w),a2
		moveq	#$f,d1
		and.w	d0,d1
		mulu	#16*40*4,d1
		add.l	d1,a2
		moveq	#14,d2
.loop3		move.l	a2,a3
		moveq	#16*4-1,d1
.loop2		move.w	(a3),(a0)+
		add.w	#40,a3
		dbf	d1,.loop2
		dbf	d2,.loop3
		move.l	a2,a3
		moveq	#15*4-1,d1
.loop4		move.w	(a3),(a0)+
		add.w	#40,a3
		dbf	d1,.loop4
		add.w	#256/CALC_FARBE,d0
		cmp.w	#256,d0
		blt.s	.loop1
		moveq	#0,d0
		rts

SUB_IFF
	move.l	STRK_BUF_SCREEN(PC),a1
	add.l	#256*4*40,a1
	move.l	STRK_BUF_SCREEN(PC),a0
	cmp.l	#"FORM",(a0)+
	bne.s	.error
	move.l	(a0)+,d1
	subq.l	#4,d1
	bmi.s	.error
	cmp.l	#"ILBM",(a0)+
	bne.s	.error
.findbody
	move.l	(a0)+,d0
	subq.l	#4,d1
	bmi.s	.error
	cmp.l	#"BODY",d0
	beq.s	.bodyfound
	move.l	(a0)+,d0
	add.l	d0,a0
	subq.l	#4,d1
	sub.l	d0,d1
	bmi.s	.error
	bra.s	.findbody
.bodyfound
	move.l	(a0)+,d1
	move.w	#256*4-1,d7
.loop2	moveq	#0,d6
.loop1	clr.w	d0
	move.b	(a0)+,d0
	bmi.s	.min
	move.w	d0,d1
.pos_loop1
	move.b	(a0)+,(a1)+
	dbf	d1,.pos_loop1
.weiter	addq.w	#1,d6
	add.w	d0,d6
	cmp.w	#40,d6
	bgt.s	.error
	bne.s	.loop1
	dbf	d7,.loop2
	moveq	#0,d0
	rts
.min	neg.b	d0
	move.w	d0,d1
	move.b	(a0)+,d2
.min_loop1
	move.b	d2,(a1)+
	dbf	d1,.min_loop1
	bra.s	.weiter
.error	moveq	#-1,d0
	rts

; Diese Routine initialisiert die Copperliste mit
; Bildgröße, Farben und Bildspeicher.
INI_BUF_Copper
		move.l	STRK_BUF_Copper(PC),a0
		move.l	#$1800000,(a0)+
		move.l	#$1000200,(a0)+
		move.l	#$8e2981,(a0)+
		move.l	#$9028c1,(a0)+
		move.l	#$920038,(a0)+
		move.l	#$9400d0,(a0)+
		lea	Farbtabelle(PC),a1
		moveq	#16-1,d0
		move.w	#$180,d1
.setcolor	move.w	d1,(a0)+
		move.w	(a1)+,(a0)+
		addq.w	#2,d1
		dbf	d0,.setcolor
		move.l	#$1020000,(a0)+
		move.l	#$1040000,(a0)+
		move.l	#$1080078,(a0)+
		move.l	#$10a0078,(a0)+
		move.l	#$200ffffe,(a0)+
		move.l	a0,PTR_screen
		moveq	#7,d0
		move.w	#$e0,d1
.setbpladrs	move.w	d1,(a0)+
		clr.w	(a0)+
		addq.w	#2,d1
		dbf	d0,.setbpladrs
		move.l	#$1004200,(a0)+
		move.l	#$fffffffe,(a0)+
		moveq	#0,d0
		rts

****************************************************************
* Funktionen, die die Datenstrukturen initialisieren, die der
* Geschwindigkeit der Programmausführung dienen (Rechentabellen).
****************************************************************

; Diese Routine berechnet die Blickkreisstruktur.
INI_CPU_Blickkreis
		move.l	STRK_CPU_Blickkreis(PC),a0
		move.l	STRK_CPU_winkel(PC),a1
		clr.w	d0
.nxtGerade	move.l	d0,-(a7)
		mulu	#1024,d0
		divu	#CALC_Geraden,d0
		add.w	d0,d0
		add.w	d0,d0
		and.w	#$ffc,d0
		movem.w	(a1,d0.w),d0/d1
		move.w	d0,d2
		move.w	d1,d3
		muls	#BEOB_Radius1,d0	;in Kreis
		muls	#BEOB_Radius1,d1
		muls	#BEOB_Radius2,d2	;out Kreis
		muls	#BEOB_Radius2,d3
		add.l	d0,d0
		add.l	d1,d1
		add.l	d2,d2
		add.l	d3,d3
		swap	d0
		swap	d1
		swap	d2
		swap	d3
		sub.w	d0,d2
		sub.w	d1,d3
		ext.l	d2
		ext.l	d3

		sub.w	a2,a2
		sub.w	a3,a3
		clr.l	d4
		clr.l	d5
		move.w	#CALC_Punkte-1,d6
.nxtPunkt	movem.l	d4/d5,-(a7)
		divs	#CALC_Punkte,d4
		divs	#CALC_Punkte,d5
		add.w	d0,d4
		add.w	d1,d5
		ext.w	d4
		ext.w	d5
		movem.w	d4/d5,-(a7)
		sub.w	a2,d4
		sub.w	a3,d5
		movem.w	(a7)+,a2/a3
		and.l	#CALC_BILD-1,d4
		and.l	#CALC_BILD-1,d5
		moveq	#CALC_SHIFT,d7
		lsl.l	d7,d5
		or.l	d4,d5
		move.l	d5,(a0)+
		movem.l	(a7)+,d4/d5
		add.l	d2,d4
		add.l	d3,d5
		dbf	d6,.nxtPunkt
		move.l	(a7)+,d0
		addq.w	#1,d0
		cmp.w	#CALC_Geraden,d0
		bne.w	.nxtGerade
		moveq	#0,d0
		rts

; Diese Routine errechnet die Datenstruktur in der
; die Anfangsaddressen für die Blickgeraden enthalten sind
; ,die den Offnungswinkel ausmachen.
INI_CPU_Offnungswinkel
		move.l	STRK_CPU_Blickkreis(PC),a0
		move.l	STRK_CPU_Offnungswinkel(PC),a1
		move.w	#CALC_Pshift,d0

		move.l	#CALC_Geraden*BEOB_Winkel,d1

		move.l	#CALC_Spalten*360/4,d2
		clr.l	d3
		clr.l	d4

		move.w	#CALC_Spalten-1,d5
.nxtGerade	move.l	d3,-(a7)
		divu	d2,d3
		and.l	#$fffc,d3

		lsl.l	d0,d3
		move.l	d3,-(a7)
		sub.l	d4,d3
		move.l	(a7)+,d4
		move.l	d3,(a1)+
		move.l	(a7)+,d3
		add.l	d1,d3
		dbf	d5,.nxtGerade

		moveq	#0,d0
		rts

; Diese Routine berechnet die Perspektivenstruktur für
; die anzahl der Höhen.
INI_CPU_Perspektive
		move.l	STRK_CPU_Perspektive(PC),a0
		moveq	#0,d0			;Oben
		moveq	#0,d1			;Unten

.nxtHohe	movem.l	d0/d1,-(a7)
		divu	#CALC_Hohe,d0
		add.w	#PERS_Obenstart,d0
		divu	#CALC_Hohe,d1
		add.w	#PERS_Untenstart,d1
		*
		move.w	d0,d2
		sub.w	#255,d2
		ext.l	d2
		asl.l	#8,d2
		divs	#PERS_FluchtX,d2	:mo

		move.w	d0,d3
		ext.l	d3
		asl.l	#8,d3
		divs	#PERS_FluchtX,d3	;mu



		moveq	#0,d4			;n
.nxtPunkt	movem.l	d2/d3/d4,-(a7)
		mulu	#BEOB_Radius2-BEOB_Radius1,d4
		add.l	#BEOB_Radius1*CALC_Punkte,d4
		divu	#CALC_Punkte,d4		;xp

		muls	d4,d2
		add.l	#255*256,d2		;ypmax
		muls	d4,d3			;ypmin
		asr.l	#8,d2
		asr.l	#8,d3

		moveq	#0,d5			;p
.nxtWert	move.w	d2,d7
		sub.w	d3,d7
		mulu	d5,d7
		divu	#255,d7
		add.w	d3,d7			;b
		sub.w	d1,d7			;b-unten
		ext.l	d7
		muls	#255,d7
		move.w	#PERS_FluchtY,d6
		sub.w	d1,d6
		divs	d6,d7			;h
		add.w	#128,d7
		bpl.s	.low


		moveq	#0,d7
.low		cmp.w	#256,d7
		blt.s	.ok
		move.w	#255,d7
.ok		move.b	d7,(a0)+
		addq.b	#1,d5
		bne.s	.nxtWert
		movem.l	(a7)+,d2/d3/d4
		addq.w	#1,d4
		cmp.w	#CALC_Punkte,d4
		bne.w	.nxtPunkt
		*
		movem.l	(a7)+,d0/d1
		add.l	#PERS_Obenend-PERS_Obenstart,d0
		add.l	#PERS_Untenend-PERS_Untenstart,d1
		addq.w	#1,.Hohe
		cmp.w	#CALC_Hohe,.Hohe
		bne.w	.nxtHohe
		moveq	#0,d0
		rts
.Hohe		dc.w	0

; Diese Routine berechnet die Rasterwertestruktur für die Farbdarstellung.
INI_CPU_Rasterwerte
		move.l	STRK_CPU_rasterwerte(PC),a0
		move.l	STRK_INFO_Farbraster(PC),a1
		add.w	#255*4*2-2,a1
		move.w	#256-1,d0
		moveq	#1,d1
.nxtadrs	add.w	#64*4,d1
		move.l	a1,(a0)+
		move.w	#$7ac,(a0)+
		move.w	d1,(a0)+
		add.w	#255*4*2,a1
		dbf	d0,.nxtadrs
		moveq	#0,d0
		rts

****************************************************************
* Funktionen, die die Hardwareregister Speichern, Aktivieren und
* Laden.
****************************************************************

; Hardwareregister zwischenspeichern.
HARD_Speichern
		lea	$DFF000,a6
		move.w	$1c(a6),d0
		or.w	#$c000,d0
		swap	d0
		move.w	$2(a6),d0
		or.w	#$8000,d0
		movem.l	[$68].W,d1-d7/a0
		movem.l	d0-d7/a0,HARD_buffer
		rts

; Hardwareregister initialisieren.
HARD_Aktivieren
		lea	$DFF000,a6
		move.w	#$7fff,$96(a6)
		move.w	#$7fff,$9a(a6)
		move.w	#$7fff,$9c(a6)
		move.l	STRK_BUF_Copper(PC),$80(a6)
		move.w	#$87c0,$96(a6)
		rts

; Hardwareregister zurücksetzen.
HARD_Laden
		movem.l	HARD_buffer(PC),d0-d7/a0
		lea	$DFF000,a6
		move.w	#$7fff,$96(a6)
		move.w	#$7fff,$9a(a6)
		move.w	#$7fff,$9c(a6)
		movem.l	d1-d7/a0,[$68].W
		move.w	d0,$96(a6)
		swap	d0
		move.w	d0,$9a(a6)
		move.l	[Exec_base].W,a6
		lea	NAME_Gfxlib(PC),a1
		jsr	OldOpenLib(a6)
		move.l	d0,a1
		move.l	$26(a1),$DFF080
		jsr	CloseLib(a6)
		lea	$DFF000,a6
		clr.w	$88(a6)
		rts
HARD_Buffer	blk.l	9,0
NAME_Gfxlib	dc.b	"graphics.library",0
		even

****************************************************************
* Daten
****************************************************************
; Diese 16 Paletten Farben. ( Rot/Grün/Blau nibble )

Farbtabelle	;RGB
	DC.B	$00,$00,$03,$10,$04,$10,$05,$20
	DC.B	$06,$30,$07,$41,$08,$52,$09,$63
	DC.B	$0A,$74,$0B,$85,$0C,$96,$0D,$A7
	DC.B	$0E,$B8,$02,$48,$01,$23,$09,$F3
E
