;*********************************
;* Jungle Jag - JagCode 500 Game *
;*********************************
;
; by Cedric Bourse, (a.k.a Orion_) [2007]
;
; http://onorisoft.info/
;
; This Source Code is licensed under the term of the following Creative Commons License:
; http://creativecommons.org/licenses/by-nc/3.0/
;
; You are free:
;  * to Share : to copy, distribute and transmit the work
;  * to Remix : to adapt the work
;
; Under the following conditions:
;  * Attribution. You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
;  * Noncommercial. You may not use this work for commercial purposes.
;  * For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page.
;  * Any of the above conditions can be waived if you get permission from the copyright holder.
;  * Nothing in this license impairs or restricts the author's moral rights.
;

;******************************************************************
;* Sprite Lib / Objects Processor Handler - by Orion_ [2006-2007] *
;******************************************************************
;
; 68k Version 0.8 !!
; special 8/16 bits mode version !
; bugfree (?)
; new mirror mode !
; rgb 24/16 clut converter ! / Fader

MAXSPRITE	.equ	128

;---------------------------------------------
;
;       76543210765432107654321076543210 76543210765432107654321076543210
;Bits : DDDDDDDDDDDDDDDDDDDDDLLLLLLLLLLL LLLLLLLLHHHHHHHHHHYYYYYYYYYYYTTT
;
;Type = 0
;Y = *2 !
;H = hauteur
;L = next obj = (a0+(2*8))>>3
;D = data address >> 3 (64bits aligned)
;
;       76543210765432107654321076543210 76543210765432107654321076543210
;Bits : 000000000FFFFFFRTRRIIIIIIIWWWWWW WWWWAAAAAAAAAAPPPDDDXXXXXXXXXXXX
;
;X = ..
;D = 3 / 8bits | 4 / 16bits | 5 / 32bits
;P = 1
;A = largeur>>2
;W = A
;I = 0
;first R = mirror mode
;second R = 0
;T = transparent mode
;third R = 0
;F = 0
;
;---------------------------------------------

	.text

;*******************************************
;* CLUT Init | convert a 24bits RGB Palette to a 16bits Jaguar RGB Palette
;*<-----------

MakeClut24_16:		; a0 = 24bits RGB palette source, a1 = 16bits RGB palette destination, d0 = nof colors
	subq.w	#1,d0	; dbra
.copypal:
	moveq	#0,d1
	moveq	#0,d2
	moveq	#0,d3

	move.b	(a0)+,d1	; R
	move.b	(a0)+,d2	; G
	move.b	(a0)+,d3	; B

	lsl.w	#8,d1
	lsr.w	#2,d2
	lsl.w	#3,d3
	andi.w	#%1111100000000000,d1
	andi.w	#%11111000000,d3
	or.w	d1,d2
	or.w	d3,d2
	move.w	d2,(a1)+

	dbra	d0,.copypal
	rts


;*******************
;* Fade In CLUT |
;*<--------------

FadeInCLUT:		; a0 = CLUT To fade to, d0 = nof colors, Return: fade_end.w = 0 if fade complete, else not complete
	clr.w	fade_end
	lea	CLUT,a1
	subq.w	#1,d0	; dbra
.fadepal:
	move.w	(a0)+,d5
	move.w	(a1),d1
	move.w	d1,d2
	move.w	d1,d3
	move.w	d1,d4
	move.w	d5,d6
	move.w	d5,d7

	andi.w	#%1111100000000000,d1
	andi.w	#%0000011111000000,d2
	andi.w	#%0000000000111111,d3
	andi.w	#%1111100000000000,d5
	andi.w	#%0000011111000000,d6
	andi.w	#%0000000000111111,d7

	cmp.w	d1,d5
	beq.s	.nr
	addi.w	#%0000100000000000,d4
	addq.w	#1,fade_end
.nr:	cmp.w	d2,d6
	beq.s	.nb
	addi.w	#%0000000001000000,d4
	addq.w	#1,fade_end
.nb:	cmp.w	d3,d7
	beq.s	.ng
	addq.w	#%0000000000000001,d4
	addq.w	#1,fade_end
.ng:
	move.w	d4,(a1)+
	dbra	d0,.fadepal
	rts


;********************
;* Fade Out CLUT |
;*<---------------

FadeOutCLUT:		; d0 = nof colors, Return: d0 = -1 if fade not complete, 0 if fade complete
	clr.w	fade_end
	lea	CLUT,a0
	subq.w	#1,d0	; dbra
.fadepal:
	move.w	(a0),d1
	move.w	d1,d2
	move.w	d1,d3
	move.w	d1,d4

	andi.w	#%1111100000000000,d1
	andi.w	#%0000011111000000,d2
	andi.w	#%0000000000111111,d3

	tst.w	d1
	beq.s	.nr
	subi.w	#%0000100000000000,d4
	addq.w	#1,fade_end
.nr:	tst.w	d2
	beq.s	.nb
	subi.w	#%0000000001000000,d4
	addq.w	#1,fade_end
.nb:	tst.w	d3
	beq.s	.ng
	subq.w	#%0000000000000001,d4
	addq.w	#1,fade_end
.ng:
	move.w	d4,(a0)+
	dbra	d0,.fadepal
	rts


;*******************************************
;* Load and Init OP List |
;*<-----------------------

InitSpriteList:
	lea.l	OPList,a0
	lea.l	SpriteList,a1
	lea.l	StopObject,a2
	clr.l	OPspritenumber

	move.l	a2,d0			; Stop Object Address
	lsr.l	#3,d0			; >> 3 (64bits aligned)
	move.l	d0,d1
	lsr.l	#8,d0			; first part of the phrase
	lsl.w	#8,d1			; second part
	swap	d1
	clr.w	d1
	move.l	d1,d2			; save the phrase for the second branch object
	ori.w	#%1000000000000011,d1	; Condition: VCnt<VC | Type = Branch Object
	ori.w	#%0100000000000011,d2	; Condition: VCnt>VC | Type = Branch Object
	move.w	a_vde,d3		; VCnt = a_vde
	lsl.w	#3,d3
	or.w	d3,d1
	move.w	a_vdb,d3		; VCnt = a_vdb
	lsl.w	#3,d3
	or.w	d3,d2

	move.l	d0,(a0)+		; Put the Branch Object 1 !
	move.l	d1,(a0)+
	move.l	d0,(a0)+		; Put the Branch Object 2 !
	move.l	d2,(a0)+
	rts

;*******************************************



;*******************************************
;* End OP List |
;*<-------------

EndSpriteList:
	move.l	#0,(a0)+		; Stop Object
	move.l	#4,(a0)
	move.l	#0,(a1)+
	move.l	#4,(a1)
	rts

;*******************************************



;*******************************************
;* Set Sprite List to the OP: |
;* Must be called just before |
;* the VBL Int Start.         |
;*<----------------------------

SetSpriteList:
	move.l	#OPList,d0
	swap	d0
	move.l	d0,OLP
	rts

;*******************************************


;*******************************************
;* Set Empty List to the OP |
;* to stop it !             |
;*<--------------------------

UnSetSpriteList:
	move.l	#StopObject,d0
	swap	d0
	move.l	d0,OLP
	rts

;*******************************************


;*******************************************
;* Set the "Saturation Add" |
;* mode for sprite.         |		Work only when calling AddSprite after
;*<--------------------------

SetSprite_SaturationAdd:
	or.w	#$4000,AS_SMC+2
	or.w	#$4000,AS_SMC8+2
	rts

;*******************************************



;*******************************************
;* UnSet the "Saturation Add" |
;* mode for sprite.           |		Work only when calling AddSprite after
;*<----------------------------

UnSetSprite_SaturationAdd:
	and.w	#$BFFF,AS_SMC+2
	and.w	#$BFFF,AS_SMC8+2
	rts

;*******************************************



;*******************************************
;* Add 8bits Sprite to the OP List    |	d0:X, d1:Y, d2:X Size, d3:Y Size, d4:Data (64bits aligned)
;* and SaveList for the Update.    ---/	d1, d4, d5, d6 data register modified !
;*<-------------------------------/	a0 = Current OPList, a1 = Current SpriteList (Call InitSpriteList at first !!!)

AddSprite8:
	add.w	XRELATIF,d0	; Repositionne le sprite par rapport au decalage ecran
	add.w	YRELATIF,d1

	moveq	#0,d5
	moveq	#0,d6

	move.w	d1,d6
	lsl.w	#1+3,d6		; (Y * 2) << 3

	andi.w	#%0011111111111000,d6	; Y

	move.w	d3,d5
	moveq	#14,d1
	lsl.l	d1,d5		; Y Size << 14
	or.l	d5,d6

	moveq	#11,d5		; (data address >> 3) << 11
	lsr.l	#3,d4
	lsl.l	d5,d4

	move.l	a0,d5		; next obj = (a0 + (2 * 8)) >> 3
	addq.l	#8,d5
	addq.l	#8,d5
	lsr.l	#3,d5
	lsl.l	#8,d5
	swap	d5
	or.w	d5,d4		; first part of the phrase
	clr.w	d5
	or.l	d5,d6		; second part of the phrase

	move.l	d4,(a0)+	; Phrase 1 in OP List
	move.l	d6,(a0)+
	move.l	d4,(a1)+	; Phrase 1 in Sprite List
	move.l	d6,(a1)+

	moveq	#0,d6
	moveq	#0,d4

	andi.w	#%0000111111111111,d0	; X
	move.w	d0,d6
	ori.w	#$8000|$3000,d6	; 8bits mode

	move.w	d2,d5		; A = X Size >> 3	<- 8 bits ! (phrase/pixsize = 8/1 = 8)
	lsr.w	#3,d5
	move.w	d5,d4
	swap	d6
	add.w	d5,d5		; << 2
	add.w	d5,d5
	or.w	d5,d6
	lsl.w	#8,d5		; W = A
	add.w	d5,d5		; << 2
	add.w	d5,d5
	or.w	d5,d6
	swap	d6

	lsr.w	#4,d4
AS_SMC8:
	ori.w	#$8000,d4	; transparent + RMW (if saturation add is set !) | $4000

	move.l	d4,(a0)+	; Phrase 2 in OP List
	move.l	d6,(a0)+
	move.l	d4,(a1)+	; Phrase 2 in Sprite List
	move.l	d6,(a1)+

	addq.l	#1,OPspritenumber
	rts


;*******************************************
;* Add 16bits Sprite to the OP List   |	d0:X, d1:Y, d2:X Size, d3:Y Size, d4:Data (64bits aligned)
;* and SaveList for the Update.    ---/	d1, d4, d5, d6 data register modified !
;*<-------------------------------/	a0 = Current OPList, a1 = Current SpriteList (Call InitSpriteList at first !!!)

AddSprite:
	add.w	XRELATIF,d0	; Repositionne le sprite par rapport au decalage ecran
	add.w	YRELATIF,d1

	moveq	#0,d5
	moveq	#0,d6

	move.w	d1,d6
	lsl.w	#1+3,d6		; (Y * 2) << 3

	andi.w	#%0011111111111000,d6	; Y

	move.w	d3,d5
	moveq	#14,d1
	lsl.l	d1,d5		; Y Size << 14
	or.l	d5,d6

	moveq	#11,d5		; (data address >> 3) << 11
	lsr.l	#3,d4
	lsl.l	d5,d4

	move.l	a0,d5		; next obj = (a0 + (2 * 8)) >> 3
	addq.l	#8,d5
	addq.l	#8,d5
	lsr.l	#3,d5
	lsl.l	#8,d5
	swap	d5
	or.w	d5,d4		; first part of the phrase
	clr.w	d5
	or.l	d5,d6		; second part of the phrase

	move.l	d4,(a0)+	; Phrase 1 in OP List
	move.l	d6,(a0)+
	move.l	d4,(a1)+	; Phrase 1 in Sprite List
	move.l	d6,(a1)+

	moveq	#0,d6
	moveq	#0,d4

	andi.w	#%0000111111111111,d0	; X
	move.w	d0,d6
	ori.w	#$8000|$4000,d6	; 16bits mode

	move.w	d2,d5		; A = X Size >> 2	<- 16 bits ! (phrase/pixsize = 8/2 = 4)
	lsr.w	#2,d5
	move.w	d5,d4
	swap	d6
	add.w	d5,d5		; << 2
	add.w	d5,d5
	or.w	d5,d6
	lsl.w	#8,d5		; W = A
	add.w	d5,d5		; << 2
	add.w	d5,d5
	or.w	d5,d6
	swap	d6

	lsr.w	#4,d4
AS_SMC:	ori.w	#$8000,d4	; transparent + RMW (if saturation add is set !) | $4000

	move.l	d4,(a0)+	; Phrase 2 in OP List
	move.l	d6,(a0)+
	move.l	d4,(a1)+	; Phrase 2 in Sprite List
	move.l	d6,(a1)+

	addq.l	#1,OPspritenumber
	rts


;*******************************************
;* Add Sprite List to the OP List  |	a0 = Current OPList, a1 = Current SpriteList (Call InitSpriteList at first !!!)
;*<---------------------------------	a2 = Your User Friendly Sprite List Data (Format: X.w, Y.w, SpriteWithHeader.l ... -1.l

AddSpriteList:
	move.w	(a2)+,d0	; X
	move.w	(a2)+,d1	; Y
	move.l	(a2)+,a3	; Get TGA2CRY Sprite Data Address
	move.w	(a3)+,d2	; Get XSize from Header
	move.w	(a3)+,d3	; Get YSier
	addq.l	#4,a3		; Skip Video Mode
	move.l	a3,d4		; Get Gfx Sprite Data Address
	bsr	AddSprite
	cmp.l	#-1,(a2)	; end of list ?
	bne.s	AddSpriteList	; no then continus
	rts


;*******************************************

SetSpriteXY:					; d0:Sprite Number, d1:X, d2:Y
	lea	SpriteList,a0
	lsl.w	#4,d0
	adda.w	d0,a0				; Point to the correct sprite to modify

	add.w	XRELATIF,d1			; Repositionne le sprite par rapport au decalage ecran
	add.w	YRELATIF,d2
	andi.w	#%0000111111111111,d1
	andi.w	#%1111000000000000,14(a0)	; Clear the current X
	or.w	d1,14(a0)			; Put the new X

	lsl.w	#1+3,d2				; (Y * 2) << 3
	andi.w	#%0011111111111000,d2
	andi.w	#%1100000000000111,6(a0)	; Clear the current Y
	or.w	d2,6(a0)			; Put the new Y

	rts

;*******************************************

SetSpriteX:					; d0:Sprite Number, d1:X
	lea	SpriteList,a0
	lsl.w	#4,d0
	adda.w	d0,a0				; Point to the correct sprite to modify

	add.w	XRELATIF,d1			; Repositionne le sprite par rapport au decalage ecran

	andi.w	#%0000111111111111,d1
	andi.w	#%1111000000000000,14(a0)	; Clear the current X
	or.w	d1,14(a0)			; Put the new X

	rts

;*******************************************

SetSpriteY:					; d0:Sprite Number, d1:Y
	lea	SpriteList,a0
	lsl.w	#4,d0
	adda.w	d0,a0				; Point to the correct sprite to modify

	add.w	YRELATIF,d1			; Repositionne le sprite par rapport au decalage ecran

	lsl.w	#1+3,d1				; (Y * 2) << 3
	andi.w	#%0011111111111000,d1
	andi.w	#%1100000000000111,6(a0)	; Clear the current Y
	or.w	d1,6(a0)			; Put the new Y

	rts

;*******************************************

SetSpriteData:				; d0:Sprite Number, d1:Data (64bits aligned)
	lea.l	SpriteList,a0
	lsl.w	#4,d0
	adda.w	d0,a0			; Point to the correct sprite to modify

	moveq	#11,d0
	lsr.l	#3,d1
	lsl.l	d0,d1

	andi.l	#%11111111111,(a0)	; Clear the current data
	or.l	d1,(a0)			; Put the new data

	rts

;*******************************************

SetMirrorSprite:			; d0:Sprite Number
	lea.l	SpriteList,a0
	lsl.w	#4,d0
	adda.w	d0,a0			; Point to the correct sprite to modify
	bset.b	#5,10(a0)
	rts

;*******************************************

UnSetMirrorSprite:			; d0:Sprite Number
	lea.l	SpriteList,a0
	lsl.w	#4,d0
	adda.w	d0,a0			; Point to the correct sprite to modify
	bclr.b	#5,10(a0)
	rts

;*******************************************
; 68k Version

UpdateSpriteList:
	movem.l	d0/a0-a1,-(a7)

	lea	OPList+16,a0
	lea	SpriteList,a1
	move.l	OPspritenumber,d0
;	subq	#1,d0
.rrstor:
	move.l	(a1)+,(a0)+
	move.l	(a1)+,(a0)+
	move.l	(a1)+,(a0)+
	move.l	(a1)+,(a0)+
	dbra	d0,.rrstor

	movem.l	(a7)+,d0/a0-a1
	rts

;*******************************************

;--------
; Datas
;--------

	.data

	.qphrase

	dc.b	13,10
	dc.b	"**************************************",13,10
	dc.b	"* - 68k Jaguar Sprite Manager v0.8 - *",13,10
	dc.b	"*  <->  by Orion_  [2006-2007]  <->  *",13,10
	dc.b	"**************************************",13,10

	.long
OPspritenumber:		dc.l	0

	.qphrase
StopObject:	dc.l	0,4			; StopObject for the 2 first Branch Object

XRELATIF:	dc.w	20			; Relative Sprite Position (on TV Screen)
YRELATIF:	dc.w	36
fade_end:	dc.w	0

;***************************

;---------
;-- Bss --
;---------

	.bss

	.qphrase
OPList:		ds.l	MAXSPRITE*4+2+2+2	; The OP List

	.qphrase
SpriteList:	ds.l	MAXSPRITE*4		; Sprite List Save

	.text
