/*	
 *	clipspr.c
 *
 *	簡易スプライトドライバを定義します。
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2007 Naoyuki Sawa
 *
 *	* Sat Apr 24 06:00:00 JST 2004 Naoyuki Sawa
 *	- 作成開始。
 *	* Mon Aug  2 06:00:00 JST 2004 Naoyuki Sawa
 *	- clipspr2.cを追加するために、sprite_driverをローカル→グローバルに変更。
 *	  SPRITE_DRIVERの定義をローカル→グローバル(clipspr.h)へ移動しました。
 *	* Thu Oct 25 11:37:22 JST 2007 Naoyuki Sawa
 *	- sprite_draw()をASM化しました。
 */
#include "clip.h"

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

SPRITE_DRIVER sprite_driver;

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

void
sprite_init(RENDER* render,
	const SPRITE* sprites/*[sprite_count]*/, int sprite_count,
	TEXTURE* textures/*[texture_count]*/, int texture_count)
{
	SPRITE_DRIVER* driver = &sprite_driver;

	memset(driver, 0, sizeof sprite_driver);
	driver->render = render;
	driver->sprites = sprites;
	driver->sprite_count = sprite_count;
	driver->textures = textures;
	driver->texture_count = texture_count;
}

/*{{2007/10/25:ASM化に伴い削除。これまで安定動作していたので、参考に残しておきます。*/
//void
//sprite_draw(int x, int y, int sprno, int param)
//{
//	SPRITE_DRIVER* driver = &sprite_driver;
//	RENDER* render = driver->render;
//	//
//	const SPRITE* sprite;
//	TEXTURE* texture_save;
//
//	/* 高速化のため、render_save()を使わずにテクスチャだけ退避します。 */
//	texture_save = render->context->texture;
//
//	/* スプライトを取得します。 */
//	if(sprno < 0 || driver->sprite_count - 1 < sprno) DIE();
//	sprite = &driver->sprites[sprno];
//
//	/* テクスチャを設定します。 */
//	if(sprite->texno > driver->texture_count - 1) DIE();
//	render->context->texture = &driver->textures[sprite->texno];
//
//	/* スプライトを描きます。 */
//	param ^= sprite->param;
//	if(!(param & DRW_REVX)) {
//		x -= sprite->cx;
//	} else {
//		x += sprite->cx - sprite->w + 1;
//	}
//	if(!(param & DRW_REVY)) {
//		y -= sprite->cy;
//	} else {
//		y += sprite->cy - sprite->h + 1;
//	}
//	render_object(render, x, y, sprite->x, sprite->y, sprite->w, sprite->h, param);
//
//	/* 高速化のため、render_restore()を使わずにテクスチャだけ復元します。 */
//	render->context->texture = texture_save;
//}
/*}}2007/10/25:ASM化に伴い削除。これまで安定動作していたので、参考に残しておきます。*/

/* * Thu Oct 25 11:37:22 JST 2007 Naoyuki Sawa
 * - sprite_draw()をASM化しました。
 * - レジスタの使い回しを工夫して、高速化と、コードサイズを削減しました。
 *   ASM版はレジスタの使い回しがかなり複雑ですが、処理の内容はC版と同じです。
 *   処理の内容を思い出すときには、C版を参照してください。
 * - 高速化の効果は、約10〜15%です。(この関数内だけの実行時間で比較)
 *   実際にはrender_object()の実行時間も含むので、高速化の効果はもっと小さくなります。
 *   2bitマスク付き8×8ピクセルスプライトの描画で、約2〜3%程度です。
 * - コードサイズ削減の効果は、約100バイトの削減です。
 */
void sprite_draw(int x, int y, int sprno, int param);
asm("
	.code
	.align	1
	.global	sprite_draw
sprite_draw:
	pushn	%r1
	;// %r12 := x
	;// %r13 := y
	;// %r14 := sprno
	;// %r15 := param
	xld.w	%r9, sprite_driver		; %r9  := driver = &sprite_driver
	ld.w	%r4, %r15			; %r4  := param
	ld.w	%r5, [%r9]+			; %r5  := render = driver->render
	ld.w	%r6, [%r9]+			; %r6  := sprites = driver->sprites
	ld.w	%r7, [%r9]+			; %r7  := sprite_count = driver->sprite_count
	ld.w	%r10, [%r9]+			; %r10 := textures = driver->textures
	ld.w	%r11, [%r9]			; %r11 := texture_count = driver->texture_count
	xld.w	%r0, [%r5+20]			; %r0  := context = render->context
	xadd	%r0, %r0, 48			; %r0  := &context->texture
	ld.w	%r1, [%r0]			; %r1  := texture_save = context->texture
	;// %r0  := &context->texture
	;// %r1  := texture_save
	;// %r4  := param
	;// %r5  := render
	;// %r6  := sprites
	;// %r7  := sprite_count
	;// %r10 := textures
	;// %r11 := texture_count
	;// %r12 := x
	;// %r13 := y
	;// %r14 := sprno
	cmp	%r14, %r7			; if((unsigned)sprno >= (unsigned)sprite_count) DIE()
	xjruge	sprite_draw_DIE
	xsla	%r14, 3				; %r14 := sprno * 8 // 8 = sizeof(SPRITE)
	add	%r14, %r6			; %r14 := sprite = sprites + sprno * 8
	;// %r0  := &context->texture
	;// %r1  := texture_save
	;// %r4  := param
	;// %r5  := render
	;// %r10 := textures
	;// %r11 := texture_count
	;// %r12 := x
	;// %r13 := y
	;// %r14 := sprite
	ld.ub	%r6, [%r14]+			; %r6  := texno = sprite->texno
	cmp	%r6, %r11			; if((unsigned)texno >= (unsigned)texture_count) DIE()
	xjruge	sprite_draw_DIE
	xld.w	%r9, 28				; %r9  := 28 // 28 = sizeof(TEXTURE)
	mlt.h	%r6, %r9			; %alr := texno * 28
	ld.w	%r9, %alr			; %r9  := texno * 28
	add	%r9, %r10			; %r9  := texture = textures + texno * 28
	ld.w	[%r0], %r9			; context->texture = texture
	;// %r0  := &context->texture
	;// %r1  := texture_save
	;// %r4  := param
	;// %r5  := render
	;// %r12 := x
	;// %r13 := y
	;// %r14 := sprite + 1
	xsub	%sp, %sp, 16
	ld.ub	%r15, [%r14]+			; %r15       := sprite->x
	ld.ub	%r9, [%r14]+			; %r9        := sprite->y
	xld.w	[%sp+0], %r9			; [%sp+0]    := sprite->y
	ld.ub	%r6, [%r14]+			; %r6        := sprite->w
	xld.w	[%sp+4], %r6			; [%sp+4]    := sprite->w
	ld.ub	%r7, [%r14]+			; %r7        := sprite->h
;//	xld.w	[%sp+8], %r7			; [%sp+8]    := sprite->h ----+
	ld.b	%r10, [%r14]+			; %r10       := sprite->cx    |
	ld.b	%r11, [%r14]+			; %r11       := sprite->cy    |
	ld.ub	%r14, [%r14]			; %r14       := sprite->param |
	xld.w	[%sp+8], %r7			; <---------------------------+		*anti-interlock*
	xor	%r4, %r14			; %r4        := param ^= sprite->param
	xld.w	[%sp+12], %r4			; [%sp+12]   := param
	xrr	%r4, 8				; %r4(31:30) := DRW_REVX,DRW_REVY
	;// %r0        := &context->texture
	;// %r1        := texture_save
	;// %r4(31:30) := DRW_REVX,DRW_REVY
	;// %r5        := render
	;// %r6        := sprite->w
	;// %r7        := sprite->h
	;// %r10       := sprite->cx
	;// %r11       := sprite->cy
	;// %r12       := x
	;// %r13       := y
	;// %r15       := sprite->x
	;// [%sp+0]    := sprite->y
	;// [%sp+4]    := sprite->w
	;// [%sp+8]    := sprite->h
	;// [%sp+12]   := param
	add	%r4, %r4			; if(param & DRW_REVX)
	jruge.d	4
	 ld.w	%r14, %r13			; %r14 := y				*delay*
	 sub	%r10, %r6			;   %r10 :=   sprite->cx - sprite->w
	 not	%r10, %r10			;   %r10 := -(sprite->cx - sprite->w + 1)
	sub	%r12, %r10			; %r12 := (x -= sprite->cx) or (x += sprite->cx - sprite->w + 1)
	;// %r0        := &context->texture
	;// %r1        := texture_save
	;// %r4(31:30) := DRW_REVX,DRW_REVY
	;// %r5        := render
	;// %r7        := sprite->h
	;// %r11       := sprite->cy
	;// %r12       := x
	;// %r14       := y
	;// %r15       := sprite->x
	;// [%sp+0]    := sprite->y
	;// [%sp+4]    := sprite->w
	;// [%sp+8]    := sprite->h
	;// [%sp+12]   := param
	add	%r4, %r4			; if(param & DRW_REVY)
	jruge.d	4
	 ld.w	%r13, %r12			; %r13 := x				*delay*
	 sub	%r11, %r7			;   %r11 :=   sprite->cy - sprite->h
	 not	%r11, %r11			;   %r11 := -(sprite->cy - sprite->h + 1)
	sub	%r14, %r11			; %r14 := (y -= sprite->cy) or (y += sprite->cy - sprite->h + 1)
	;// %r0      := &context->texture
	;// %r1      := texture_save
	;// %r5      := render
	;// %r13     := x
	;// %r14     := y
	;// %r15     := sprite->x
	;// [%sp+0]  := sprite->y
	;// [%sp+4]  := sprite->w
	;// [%sp+8]  := sprite->h
	;// [%sp+12] := param
	xcall.d	render_object
	ld.w	%r12, %r5			; %r12 := render			*delay*
	xadd	%sp, %sp, 16
	;// %r0 := &context->texture
	;// %r1 := texture_save
	ld.w	[%r0], %r1			; context->texture = texture_save
	popn	%r1
	ret
");
static void sprite_draw_DIE() __attribute__((noreturn,unused));
static void sprite_draw_DIE() { DIE(); }
