DrawImageTrans	;this routine should be called as a library routine!
		;See intuition.library/DrawImage() for more info.

** SOME COMMENTS **************************************************************
*
* This function only works with OS 3.x because of the AllocBitmap() function.
* However this can be worked around by making your own AllocBitmap() function.
* DFunc.library provides this function in OS 2.x and above as well (util/libs).
*
* How it works:
*
*	- First we create our own special private structure to contain
*	  important data. The reason is that this will be easier and more safer
*	  to program with.
*	- Then we initialize it with datas from the function call and from the
*	  image structure itself
*	- We allocate space for a rastport (we want this code to be re-entrant)
*	- Then we InitRastport on our own rastport
*	- Then we allocate a bitmap with same dimensions as the image
*	- We initialize our bitmap into that rastport
*	- Then we DrawImage() the image into our own rastport. This is because
*	  we need to get the plane datas and we will have an image to blit
*	  thrue the mask we're gonna create with the bitmap.
*	  NOTE: first we MUST clean next_image entry in the image structure or
*	  else the routine will draw a whole list with images if that's so.
*	  Also: we clear the x and y position since we need this image to be
*	  at a zero offset in our bitmap. After the DrawImage() we restore the
*	  values.
*	- Now we calculate how many bytes there are in one bitplane in image
*	- Then we allocate a mask buffer equal the calculated size
*	- We OR all bitplanes in our bitmap into our maskplane
*	- Then we invert the image in our bitmap
*	- And finally we set the destination position and blit it back to
*	  the final bitmap
*	- We take a clean up
*	- At last we check the Next_image field and if non-empty, repeat the
*	  process.
*	- Phew! :-)
*
* NOTES: Some differences from the DrawImage()
*
* If the image has less bitplanes than the bitmap it's suppose to be drawn in
* the last bitplane will not be considered (eg. not cleared) so pixels set in
* that last bitplane will be there on top of image.
*
* This routine is slower than the DrawImage() (not to suprising I guess :).
* It's uses the DrawImage() itself pluss a couple of blitter functions and
* OR algorithm and finally memory functions and precalculation.
* However, you could optimize this routine and sent a copy back to me. That
* would be nice considering my pre-work eh? :-) (kennecni@IDGonline.no).
*
* Returns NULL if any errors!
*
* SMART STUFF:
*
* The imagedata doesn't have to be in CHIP_MEM with this function. It will
* check the memory attributes of the imagedata block and if it's in FAST_MEM
* it will create a temporary chip_mem buffer and copy the image data into it.
* Then it will replace the imagedata pointer temporarly and restore it after
* use.
*
* This routine uses the original DrawImage() to make the PlanePickOnOff etc.
* to be compatible. This saves us for lot of problems calculatingthe image
* data itself.
*
* Another feature of this function is that it's not required to have as many
* bitplanes in the destination bitmap as the image itself. The DrawImage()
* would not work to well if the image had more bitplanes than the destBM.
* This function automatically truncates the bitmap thanks to the Blt** funcs.
* (don't take this statement to serious since I am not 100% ;-)
*
*
* This routine can be way optimized. If you do so please send a copy back to
* me.
*
*******************************************************************************

* To make the function work more flawlessly, we make a buffer for own data:

    STRUCTURE  PrivateDIT,0		;DIT ?!? :)

	long	dit_rastport		;destination rastport
	long	dit_myrastport		;our "fake" rastport
	long	dit_bitmap		;our bitmap
	long	dit_mask		;our maskplane
	long	dit_image		;image structure
	long	dit_imagedata		;ptr. to image data (body)
	long	dit_orgimage		;original imagedata if in fastram
	long	dit_imagesize		;total size of image in bytes
	word	dit_dx			;delta x
	word	dit_dy			;delta y
	word	dit_x			;image structure x
	word	dit_y			;image structure y
	word	dit_width
	word	dit_height
	word	dit_depth		;depth of image (we use word here)
	byte	dit_flag		;set if image is in fastram
	byte	dit_padme

	label	dit_sizeof

	movem.l	d2-d7/a2-a6,-(sp)	;preserve regs. Scratch: a0/a1/d0/d1

.start	move.l	d0,d2			;backup some values
	move.l	d1,d3
	move.l	a0,a2
	move.l	a1,a3

* Allocate our structure:

	LibBase	exec

	move.l	#dit_sizeof,d0
	move.l	#$10001,d1
	Call	AllocMem		;alloc structure
	tst.l	d0
	beq.w	.exit			;exit if error

* Init data:

	move.l	d0,a5			;our structure
	move.l	a2,dit_rastport(a5)	;function data:
	move.l	a3,dit_image(a5)
	move.w	d2,dit_dx(a5)
	move.w	d3,dit_dy(a5)
	move.l	0(a3),dit_x(a5)		;copy x and y
	move.l	4(a3),dit_width(a5)	;copy width and height
	move.w	8(a3),dit_depth(a5)
	move.l	10(a3),dit_imagedata(a5)
	move.l	10(a3),dit_orgimage(a5)

* Calculate number of bytes in image (one bitplane):

	move.w	dit_width(a5),d7
	ext.l	d7
	add.w	#15,d7			;word aligned
	divu	#8,d7			;get bytes (from word aligned pixels)
	ext.l	d7			;remove decimals
	move.w	dit_height(a5),d1	;number of rows (height)
	ext.l	d1			;remove trash in upper word
	mulu	d1,d7			;multiply the byte width and rows
	ext.l	d7			;number of bytes in one bitplane

* Check if imagedata is in chipmem or in fastmem:

	move.l	10(a3),a1
	Call	TypeOfMem
	cmp.l	#$703,d0	;$703 = CHIP_MEM
	beq.b	.inChip		;it's already in chip so don't bother

	move.l	d7,d0
	move.w	dit_depth(a5),d1
	ext.l	d1
	mulu	d1,d0
	move.l	d0,dit_imagesize(a5)
	move.l	d0,d2
	move.l	#$10002,d1
	Call	AllocMem		;alloc chip buffer for imagedata
	move.l	d0,dit_imagedata(a5)	;store in structure
	beq.w	.error2			;well, no chip buffer.. 8~(

	move.l	d0,a1
	move.l	dit_orgimage(a5),a0
	subq.l	#1,d2
.copyI	move.b	(a0)+,(a1)+		;copy imagedata to our chip buffer
	dbra	d2,.copyI

	st	dit_flag(a5)		;set flag telling we use own I-buffer

* Create a rastport structure

.inChip	move.l	#rp_sizeof,d0
	moveq.l	#$1,d1			;InitRastport() will clear the buffer
	Call	AllocMem		;allocate rastport structure
	move.l	d0,dit_myrastport(a5)
	beq.w	.error2

* Allocate bitmap for rastport:

	LibBase	graphics

	move.l	d0,a1
	Call	InitRastport		;make our rastport valid

	move.w	dit_width(a5),d0
	move.w	dit_height(a5),d1
	move.w	dit_depth(a5),d2
	move.l	#BMF_DISPLAYABLE,d3
	sub.l	a0,a0
	Call	AllocBitmap		;get a bitmap for our rastport
	move.l	d0,dit_bitmap(a5)
	beq.w	.error3

	move.l	dit_myrastport(a5),a0	;our rastport
	move.l	d0,rp_bitmap(a0)	;copy bitmap into rastport

* draw image into our rastport:

	LibBase	intuition

	move.l	dit_myrastport(a5),a0
	move.l	dit_image(a5),a1
	move.l	dit_imagedata(a5),10(a1)	;use our buffer in case no_chip
	move.l	16(a1),d3
	clr.l	(a1)		;no dx or dy
	clr.l	16(a1)		;and no next_image!
	moveq	#0,d0
	moveq	#0,d1
	Call	DrawImage		;DrawImage()
	move.l	dit_image(a5),a1
	move.l	dit_orgimage(a5),10(a1)	;restore original image buffer
	move.l	dit_x(a5),(a1)		;restore dx and dy
	move.l	d3,16(a1)		;restore next_image

	LibBase	exec

	tst.b	dit_flag(a5)
	beq.b	.noChip

	move.l	dit_imagesize(a5),d0
	move.l	dit_imagedata(a5),a1
	Call	FreeMem
	sf	dit_flag(a5)

.noChip	move.l	d7,d0
	move.l	#$10002,d1
	Call	AllocMem		;allocate mask space in chipram
	tst.l	d0
	beq.w	.cleanup

	move.l	d0,a4

* Now OR all planes together:

	move.l	dit_orgimage(a5),a3	;image data (body)
	move.w	dit_depth(a5),d6	;number of bitplanes in image
	ext.l	d6			;number of bitplanes
	bra.b	.goon2
.init	move.l	d7,d2			;number of bytes to count
	lea	(a4),a0			;mskplane start pointer
	bra.b	.goon1
.ORit	move.b	(a3)+,d0
	or.b	d0,(a0)+
.goon1	dbra	d2,.ORit
.goon2	dbra	d6,.init

* Blit image back from bitmap to rastport with our mask:

	LibBase	graphics

* Invert source bitmap:

	move.l	dit_bitmap(a5),a0
	lea	(a0),a1
	sub.l	a2,a2
	moveq	#0,d0
	moveq	#0,d1
	moveq	#0,d2
	moveq	#0,d3
	move.w	dit_width(a5),d4
	move.w	dit_height(a5),d5
	move.b	#$30,d6		;invert source before copy back to itself
;here we invert the source first.. see below.
	move.l	d7,-(sp)
	moveq.l	#-1,d7
	Call	BltBitmap

	Call	WaitBlit

	move.l	dit_bitmap(a5),a0
	moveq	#0,d0
	moveq	#0,d1
	move.l	dit_rastport(a5),a1
	move.w	dit_x(a5),d2		;the image structure x pos.
	move.w	dit_y(a5),d3
	add.w	dit_dx(a5),d2		;add function delta x
	add.w	dit_dy(a5),d3		;the same with the y pos.
	move.l	#$20,d6			;Blitmode: ANBC
;If someone knows a combination to blit thrue the mask without inverting the
;source I would be pleased to hear from you! If so the function call above can
;be eliminated!
	lea	(a4),a2			;our maskplane
	Call	BltMaskBitMapRastPort

	Call	WaitBlit

	LibBase	exec

	lea	(a4),a1
	move.l	(sp)+,d0
	Call	FreeMem			;free maskplane

	LibBase	graphics
	move.l	dit_bitmap(a5),a0
	Call	FreeBitmap		;free bitmap

	LibBase	exec
	move.l	dit_myrastport(a5),a1
	move.l	#rp_sizeof,d0
	Call	FreeMem			;free rastport

	move.l	dit_rastport(a5),a3	;get function call datas
	move.l	dit_image(a5),a4
	move.w	dit_dx(a5),d2
	move.w	dit_dy(a5),d3

	lea	(a5),a1
	move.l	#dit_sizeof,d0
	Call	FreeMem			;free our struct (data becomes invalid)

	tst.l	16(a4)			;a next_image ?
	beq.b	.ok			;nope, exit
	lea	(a3),a0
	move.l	16(a4),a1
	move.w	d2,d0
	move.w	d3,d1
	bra.w	.start			;instant replay! :-)

.ok	moveq.l	#-1,d0			;no errors!

.exit	movem.l	(sp)+,d2-d7/a2-a6
	rts

.error2	LibBase	exec			*** failure at alloc rastport
	move.l	a5,a1
	move.l	#dit_sizeof,d0
	Call	FreeMem			;free our structure
	moveq.l	#0,d0
	movem.l	(sp)+,d2-d7/a2-a6
	rts

.error3	LibBase	exec			*** failure at allocbitmap
	move.l	dit_myrastport(a5),a1
	move.l	#rp_sizeof,d0
	Call	FreeMem			;free rastport

	move.l	a5,a1
	move.l	#dit_sizeof,d0
	Call	FreeMem			;free our structure
	moveq.l	#0,d0
	movem.l	(sp)+,d2-d7/a2-a6
	rts

.cleanup
	LibBase	graphics
	move.l	dit_bitmap(a5),a0
	Call	FreeBitmap		;free bitmap

	LibBase	exec
	move.l	dit_myrastport(a5),a1
	move.l	#rp_sizeof,d0
	Call	FreeMem			;free rastport

	tst.b	dit_flag(a5)
	beq.b	.noC
	move.l	dit_imagesize(a5),d0
	move.l	dit_imagedata(a5),a1
	Call	FreeMem			;free our chip buffer

.noC	move.l	a5,a1
	move.l	#dit_sizeof,d0
	Call	FreeMem			;free our structure
	moveq.l	#0,d0
	movem.l	(sp)+,d2-d7/a2-a6
	rts
