//----------------------------------------------------------------------------------------------
//
//  sConsole.m : スプライト描画用コンソール v1.7
//  X-BASIC' v2.0
//
//  Created by AIG-Soft(iMac) on 2013/04/29.
//  Copyright (c) 2013年 AIG-Soft. All rights reserved.
//

#import "sConsole.h"
#import <CoreGraphics/CoreGraphics.h>
#import "malloc2.h"
#import "rgbhsv.h"
#import "FileControl2.h"
#import "ImageHelper.h"
#import "gConsole.h" // エラーコードのためだけ

@implementation sConsole

//---------------------------------------------------------------------------------------
// デバッグ用
#if COMPILE_MODE<2 // Distributionの時は外す
//画像生成結果をファイルに出力するかどうか
//#define OUTPUT_CONSOLE	1
#endif

#ifdef OUTPUT_CONSOLE
// console内容をJPEGで出力する
void outputConsole(NSString *fname,Console *console)
{
	CGImageRef imageRef=CGBitmapContextCreateImage(console.context);
	UIImage *image2 = [[UIImage alloc] initWithCGImage:imageRef];
	NSData *imgdata=UIImageJPEGRepresentation(image2,0.5);
	[imgdata writeToFile:fname atomically:YES];
	[image2 release];
}
#else
#define	outputConsole(fname,console)
#endif

//---------------------------------------------------------------------------------------
// 共通サブルーチン(内部用)
//---------------------------------------------------------------------------------------

// プレーン番号補正
SWord checkPlaneNumber(SWord pl)
{
	if (pl<0) pl=0;
	else
	if (pl>=MAX_SPRITE_PLANE) pl=MAX_SPRITE_PLANE-1;
	return (pl);
}

// パターン番号補正
SWord checkPatternNumber(SWord sp)
{
	if (sp<0) sp=0;
	else
	if (sp>=MAX_SPRITE_PATTERNS) sp=MAX_SPRITE_PATTERNS-1;
	return (sp);
}

// パレットブロック番号補正
SWord checkPaletBlock(SWord pb)
{
	if (pb<=1||pb>=MAX_SPRITE_PALET_BLOCKS) pb=1; // デフォルト；0はテキストパレット用なので設定禁止(X68と合わせる)
	return (pb);
}

// BGテキストページ番号
SWord checkBGpage(SWord pg)
{
	if (pg<0||pg>=MAX_BG_TEXTPAGE) pg=0;
	return (pg);
}

// BG画面番号
SWord checkBGscrnNo(SWord scrnNo)
{
	if (scrnNo<0) scrnNo=0;
	else
	if (scrnNo>=MAX_BG_SCREEN) scrnNo=MAX_BG_SCREEN-1;
	return (scrnNo);
}

// BGテキストページ内x座標
int checkBGx(int x)
{
	if (x<0) x=0;
	else
	if (x>=BG_TEXT_PAGE_WIDTH) x=BG_TEXT_PAGE_WIDTH-1;
	return (x);
}

int checkBGy(int y)
// BGテキストページ内y座標
{
	if (y<0) y=0;
	else
	if (y>=BG_TEXT_PAGE_HEIGHT) y=BG_TEXT_PAGE_HEIGHT-1;
	return (y);
}

//---------------------------------------------------------------------------------------
// 共通関数
//---------------------------------------------------------------------------------------

// スプライト/BG画面の表示制御
// これは.fspriteBGDispのsetter
// sp_disp()もこれを呼び出す
-(void)setFspriteBGDisp:(BOOL)fspriteBGDisp
{
	printSelfs(@"%d",fspriteBGDisp);
	
	if (fspriteBGDisp) {
		// onにするときは表示処理する
		nslog(@"ONにする");
		_fspriteBGDisp=fspriteBGDisp; // 先に表示設定して
		nslog(@"setFspriteBGDisp");
		fBGupdate1st=YES; // 表示をONするときは強制更新させる（非表示中は更新処理されないので）
		[self spriteBGDraw:YES]; // 描画
	} else {
		// offするときは表示を消すだけ
		nslog(@"OFFにする");
		[self spriteBGcLear]; // 先にクリアして
		_fspriteBGDisp=fspriteBGDisp; // 設定
	}
}

// スプライト/BG画面の表示一時停止
// これはself.fhaltのsetter
-(void)setFhalt:(BOOL)fhalt
{
	printSelfs(@"%d",fhalt);
	_fhalt=fhalt;
	
	if (!fhalt) {
		// off=表示再開するときは表示処理する
		nslog(@"sp_halt(NO)表示再開");
		// 表示停止中に更新された部分があるかもしれないので、それを表示させる
		[self spriteBGDraw:YES];
	}
}

// リターン値 : YES=ワークが確保できない , NO=正常終了
-(BOOL)setFDisableBG0SPBG1:(BOOL)fDisableBG0SPBG1_
{
	printSelfs(@"%d",fDisableBG0SPBG1_);
	
	fDisableBG0SPBG1=fDisableBG0SPBG1_;
	
	// ワークと表示順位が変わるので以下を実行
	// BG用ワーク(再)確保
	if ([self allocBG]) {
		// メモリ不足
		return (YES);
	}
	// スプライト/BG表示処理
	nslog(@"setFDisableBG0SPBG1");
	[self spriteBGDraw:NO]; // BG0>BG1は変わらないのでNO(でもallogBGで初期更新はONになる）
	return (NO);
}

//---------------------------------------------------------------------------------------
// スプライト関数
//---------------------------------------------------------------------------------------

// スプライトとBGの初期化
-(void)sp_init
{
	printSelf();
	
	_fhalt=YES; 		// 念のため即時表示をOFFにしておく
	_fspriteBGDisp=NO;	// スプライト/BG画面を消す
	fDisableBG0SPBG1=NO;	// BG0>SP>BG1を有効にする(無効にしない)
	
	// スプライトスクロールレジスタの初期化
	nslog(@"スプライトスクロールレジスタの初期化");
	// =プレーンの初期化
	int i;
	SpriteRegs *spRegs=spriteRegs;
	for (i=0;i<MAX_SPRITE_PLANE;i++) {
		// 初期座標は画面外にする(V3.00)
		// sp_disp(1)でスプライト表示ON,sp_on()されていて、
		// sp_def(0,〜)した時に(0,0)の位置に何故かパターンが表示されるので初期座標を画面外にしておくことでこれを防ぐ
		// 残念ながらなぜ表示されるか、そのバグの発生場所はわからない
		// どのプレーンが表示されているかわからない(0ではなさそう。sp_move(0)しても移動しないから)
		// これは対処療法
		spRegs->xpos=-256;
		spRegs->ypos=-256;
		spRegs->prw	=SPRITE_PRW_HIDE; // 非表示
		spRegs->ptnRegs.fflip		=SPRITE_FLIP_NONE;
		spRegs->ptnRegs.paletBlock	=DEFAULT_SPRITE_PALET_BLOCK; // デフォルトパレットブロック
		spRegs->ptnRegs.ptrn		=DEFAULT_SPRITE_PATTERN;
		spRegs++;
	}
	
	// パレットブロックの初期化
	nslog(@"パレットブロックの初期化");
	for (i=0;i<MAX_SPRITE_PALET_BLOCKS;i++) {
		nslog(@"パレットブロック%d",i);
		// そのパレットブロックがBGで実際に使われている回数 spV1.7
		cntPaletInBG[i]=0;
		for (int j=0;j<MAX_SPRITE_PALET_1BLOCK;j++) {
			if (i==0) {
				// ブロック0のみ構築
				rgba_color rgba=getStandardColorTable(j);
				x68_sprite_palet[i][j]=rgb(rgba.r,rgba.g,rgba.r,rgba.alpha);
				/*
				 0	CTBLACK=黒
				 1	CTBLUE
				 ～
				 7	CTWHITE
				 8	CTHBLACK=黒
				 9	CTHBLUE
				 ～
				 15	CTHWHITE
				 */
			} else {
				// 0以外は0をコピーする
				x68_sprite_palet[i][j]=x68_sprite_palet[0][j];
			}
		}
	}
	// パターンの初期化
	[self spClear:0 sp2:MAX_SPRITE_PATTERNS-1];
	// そのパターンがBGで使われている回数 spV1.7
	for (i=0;i<MAX_SPRITE_PATTERNS;i++) {
		cntPatternInBG[i]=0; // BGに設定されるまではすべて0
	}
	
	// BG初期化
	nslog(@"BG初期化");
	BGpages=0; // BGページなし
	for (i=0;i<MAX_BG_SCREEN;i++) {
		nslog(@"BG画面:%d",i);
		BGRegs *reg=&BGscreen[i];
		reg->xpos	 =0;
		reg->ypos	 =0;
		reg->textPage=i; 	// BG text page i → BG screen i
		reg->fdisp 	 =NO;
		reg->lpixel	 =NULL;	// BG用ワーク未確保
	}
	for (i=0;i<MAX_BG_TEXTPAGE;i++) {
		nslog(@"BGテキストページ:%d",i);
		[self bgFill:i sp:DEFAULT_BG_PATTERN paletBlock:DEFAULT_BG_PALET_BLOCK flip:SPRITE_FLIP_NONE finit:YES];
	}
	
	// 表示はoffになるので実表示処理は不要
	// ただし、画面表示上は消す
	//	[self spriteBGcLear];
	pushContext();
	CGContextClearRect(context,self.frame);
	[self draw];
	// 即時表示指定
	_fhalt=NO;
}

//---------------------------------------------------------------------------------------

// プレーン毎の優先順位設定(SPRITE_PRW_*)
// sp_on/sp_offもここで処理する
// pl1/pl2 : プレーン番号範囲
-(void)sp_priority:(SWord)prw pl1:(SWord)pl1 pl2:(SWord)pl2
{
	printSelf();
	nslog(@"prw=%d,pl1=%d,pl2=%d",prw,pl1,pl2);
	pl1=checkPlaneNumber(pl1);
	pl2=checkPlaneNumber(pl2);
	if (pl1>pl2) {
		int p=pl1;
		pl1=pl2;
		pl2=p;
	}
	int cnt=0; // 実際に更新される回数
	for (;pl1<=pl2;pl1++) {
		if (spriteRegs[pl1].prw!=prw) {
			spriteRegs[pl1].prw=prw;
			cnt++;
		}
	}
	// スプライト/BG表示処理
	nslog(@"cnt=%d",cnt);
	[self spriteBGDraw:(cnt>0)];
}

//-----------------

// スプライトパターンの初期化(メイン)
-(int)spClear:(SWord)sp1 sp2:(SWord)sp2
{
	printSelf();
	nslog(@"sp1=%d,sp2=%d",sp1,sp2);
	int cnt=0;
	for (;sp1<=sp2;sp1++) {
		// スプライトパターン定義形式
		spriteType[sp1]=SPRITE_IOS; // iOS型
		// パターンそのもののクリア
		for (int cy=0;cy<SPRITE_HEIGHT;cy++) {
			for (int cx=0;cx<SPRITE_WIDTH;cx++) {
				sprite_pattern[sp1][cy][cx]=0; // 透明
			}
		}
		// 各パターンのBG内で使われている回数を合計する spV1.7
		cnt+=cntPatternInBG[sp1];
	}
	// クリアしたパターンの、BG内での利用回数の合計を返す
	return (cnt);
}

// スプライトパターンの初期化
// sp1/sp2 : パターン番号
-(void)sp_clr:(SWord)sp1 sp2:(SWord)sp2
{
	printSelf();
	nslog(@"sp1=%d,sp2=%d",sp1,sp2);
	sp1=checkPatternNumber(sp1);
	sp2=checkPatternNumber(sp2);
	if (sp1>sp2) {
		int sp=sp1;
		sp1=sp2;
		sp2=sp;
	}
	// 実クリア
	// 今回定義したパターンがBG内で使われているかどうかも調べる spV1.7
	BOOL fUpdateBG=([self spClear:sp1 sp2:sp2]>0);
	
	// スプライト/BG表示処理
	// 表示中にクリアした場合は変わるので
	// 1つのパターンは複数のプレーンおよびBGに割りつけできるので、1つの変更が画面上複数箇所の変更につながることもある
	nslog(@"clr");
	[self spriteBGDraw:fUpdateBG];
}

//-----------------

// スプライトパターンの定義
// ptn[]の各要素はtypeによる
// sp   : パターン番号
// ptn  : パターン ; X68型の時はchar *に読み替える
// type : iOS(合成RGB値)/X68(パレットコード)型
-(void)sp_def:(SWord)sp ptn:(ULong *)ptn type:(char)type
{
	printSelf();
	nslog(@"sp=%d,type=%d",sp,type);
	
	sp=checkPatternNumber(sp);
	spriteType[sp]=type;
	//
	switch (type) {
		case SPRITE_IOS:
			for (int cy=0;cy<SPRITE_HEIGHT;cy++) {
				for (int cx=0;cx<SPRITE_WIDTH;cx++) {
					sprite_pattern[sp][cy][cx]=*ptn++;
				}
			}
			break;
		case SPRITE_X68:
			{
			char *bptn=(char *)ptn;
			for (int cy=0;cy<SPRITE_HEIGHT;cy++) {
				for (int cx=0;cx<SPRITE_WIDTH;cx++) {
					sprite_pattern[sp][cy][cx]=(ULong)*bptn++;
				}
			}
			}
			break;
	}
	// 今回定義したパターンがBG内で使われているかどうか
	BOOL fUpdateBG=(cntPatternInBG[sp]>0); // このパレットブロックがBGでも使われているならBGも更新 spV1.7
	// スプライト/BG表示処理
	// 1つのパターンは複数のプレーンおよびBGに割りつけできるので、1つの変更が画面上複数箇所の変更につながることもある
	nslog(@"fUpdateBG=%d",fUpdateBG);
	
	[self spriteBGDraw:fUpdateBG];
}

//-----------------

// スプライトパターンの読み出し
// ptn[]の各要素はパレットコードか合成RGB値
// sp : パターン番号
// リターン値 : パターンの型
-(int)sp_pat:(SWord)sp ptn:(ULong *)ptn size1:(int)size1
{
	printSelfs(@"sp=%d",sp);
	sp=checkPatternNumber(sp);
	int type=(int)spriteType[sp];
	switch (type) {
		case SPRITE_X68:
			nslog(@"X68型");
			if (size1==sizeof(char)) {
				// X68型をchar配列に格納する
				char *bptn=(char *)ptn;
				for (int cy=0;cy<SPRITE_HEIGHT;cy++) {
					for (int cx=0;cx<SPRITE_WIDTH;cx++) {
						*bptn++=(char)sprite_pattern[sp][cy][cx];
					}
				}
				break;
			}
			// size1==sizeof(int)
			// X68型int配列に格納する
		case SPRITE_IOS:
			nslog(@"iOS型/X68→int配列");
			if (size1==sizeof(char)) return(-1); // iOS型はchar配列には格納できない
			for (int cy=0;cy<SPRITE_HEIGHT;cy++) {
				for (int cx=0;cx<SPRITE_WIDTH;cx++) {
					*ptn++=sprite_pattern[sp][cy][cx];
				}
			}
			break;
	}
	return (type);
}

//-----------------

// パレットブロックのパレットコードに実色を割り当てる
// ＝パレットブロックの定義
-(ULong)sp_color:(SWord)p col:(ULong)col paletBlock:(SWord)pb
{
	printSelf();

	if (p<0||p>15) p=15; // パレットコードの範囲限定(念のため) ；p=0は基本変更禁止(透明固定)
	pb=checkPaletBlock(pb);
	nslog(@"palet code=%u/block=%d←$%08x:色",p,pb,(uint)col);
	ULong bcol=x68_sprite_palet[pb][p]; // 変更前の色を取得する
	// 前の色の取得だけも実装したかったが、指定するための引数を設定できないのでなし
	if (bcol!=col) {
		// 実更新があるとき
		x68_sprite_palet[pb][p]=col; // 変更
		
		// スプライト/BG表示処理；色が変わることがあるので
		BOOL fUpdateBG=(cntPaletInBG[pb]>0); // このパレットブロックがBGでも使われているならBGも更新 spV1.7
		nslog(@"color");
		[self spriteBGDraw:fUpdateBG];
	}
	return (bcol);
}

//-----------------

// pl以外は省略可能
// x,yを省略するときはfomit?=YESを設定する
// 他の値は-1で省略を意味する
-(void)sp_setting:(SWord)pl x:(int)x y:(int)y sp:(SWord)sp paletBlock:(SWord)pb flip:(SWord)flip prw:(SWord)prw fomitX:(BOOL)fomitX fomitY:(BOOL)fomitY
{
	printSelf();

	pl=checkPlaneNumber(pl);
	nslog(@"(%d,%d):plane=%d,sp=%d,pb=%d,flip=%d,prw=%d,fomitX/Y=%d,%d",x,y,pl,sp,pb,flip,prw,fomitX,fomitY);
	SpriteRegs *spRegs=&spriteRegs[pl];
	
	// 座標だけは-1を省略値に出来ない
	if (fomitX) x=spRegs->xpos;
	if (fomitY) y=spRegs->ypos;
	
	if (pb==-1) {
		pb=spRegs->ptnRegs.paletBlock;
	} else {
		pb=checkPaletBlock(pb);
	}
	if (sp==-1) {
		sp=spRegs->ptnRegs.ptrn;
	} else {
		sp=checkPatternNumber(sp);
	}
	if (flip==-1) {
		flip=spRegs->ptnRegs.fflip;
	}
	if (prw==-1) {
		prw=spRegs->prw;
	}
	
	if (spRegs->xpos!=x
	 || spRegs->ypos!=y
	 || spRegs->ptnRegs.paletBlock	!=pb
	 ||	spRegs->ptnRegs.ptrn	!=sp
	 || spRegs->ptnRegs.fflip	!=flip
	 || spRegs->prw 			!=prw
	) {
		spRegs->xpos=x;
		spRegs->ypos=y;
		spRegs->ptnRegs.paletBlock=pb;
		spRegs->ptnRegs.ptrn	=sp;
		spRegs->ptnRegs.fflip	=flip;
		spRegs->prw 			=prw;
		// スプライト表示処理
		[self spriteBGDraw:NO];
	}
	// 1つも変更項目がないときは再表示しない
	// これをしないとちらついてしまう
}

//-----------------

-(int)sp_stat:(SWord)pl dataType:(int)dataType
// スプライト状態取得
{
	printSelfs(@"dataType=%d",dataType);
	pl=checkPlaneNumber(pl);
	SpriteRegs *spRegs=&spriteRegs[pl];
	switch (dataType) {
		case 0: // x座標
			return (spRegs->xpos);
		case 1: // y座標
			return (spRegs->ypos);
		case 2: // パターン番号
			return (spRegs->ptnRegs.ptrn);
		case 3: // 表示設定
			return (spRegs->prw);
		case 4: // 反転設定
			return (spRegs->ptnRegs.fflip);
		case 5: // パレットブロック番号
			return (spRegs->ptnRegs.paletBlock);
	}
	// 指定ミス
	return (-1);
}

//---------------------------------------------------------------------------------------

-(int)sp_image:(NSString *)fname ofstx:(SWord)ofstx ofsty:(SWord)ofsty pwx:(int *)pwx pwy:(int *)pwy tsp:(SWord)tsp tpl:(SWord)tpl
	sx:(int)sx sy:(int)sy fomitSX:(BOOL)fomitSX fomitSY:(BOOL)fomitSY prw:(SWord)prw fblack:(BOOL)fblack
{
	printSelf();
	nslog(@"fname=%@,ofstx=%d,ofsty=%d,pwx=%d,pwy=%d,tsp=%d,tlp=%d,prw=%d",fname,ofstx,ofsty,*pwx,*pwy,tsp,tpl,prw);
	nslog(@"sx=%d,sy=%d,fomitSX=%d,fomitSY=%d,fblack=%d",sx,sy,fomitSX,fomitSY,fblack);
	// 画像ファイルをUIImageに読み込む
	NSString *path=getResourceOrSavedataPath(fname);
	if (path==nil) {
		nslog(@"ファイルが見つからない");
		return (-PIC_FILENOTFOUND);
	}
	UIImage *loadImg=[UIImage imageWithContentsOfFile:path];
	if (loadImg==nil) {
		nslog(@"ファイルが見つからない/読み込めない");
		return (-PIC_FILENOTFOUND);
	}
#ifdef DEBUG
	{
		NSData *imgdata=UIImagePNGRepresentation(loadImg);
		[imgdata writeToFile:TestFile(@"sp_image.png") atomically:YES];
	}
#endif
	// 画像サイズはUIImage.sizeによる
	// 読み出し位置補正
	int width =(int)loadImg.size.width;
	int height=(int)loadImg.size.height;
	nslog(@"画像サイズ=%d*%d",width,height);
	if (width<SPRITE_WIDTH || height<SPRITE_HEIGHT) {
		nslog(@"画像が小さすぎる");
		return (-PIC_TOO_SMALL);
	}
	if (ofstx<0) ofstx=0;
	if (ofstx>=width -SPRITE_WIDTH ) ofstx=width -SPRITE_WIDTH;
	if (ofsty<0) ofsty=0;
	if (ofsty>=height-SPRITE_HEIGHT) ofsty=height-SPRITE_HEIGHT;
	nslog(@"補正後:ofstx=%d,ofsty=%d",ofstx,ofsty);
	// 残り幅
	int leftwx=width -ofstx;
	int leftwy=height-ofsty;
	nslog(@"ofstxから先、残り幅(ドット単位):%d*%d",leftwx,leftwy);
	leftwx/=SPRITE_WIDTH;
	leftwy/=SPRITE_HEIGHT;
	nslog(@"ofstyから先、残り幅(パターン単位):%d*%d",leftwx,leftwy);
	if (*pwx>=leftwx||*pwx==0) *pwx=leftwx;
	if (*pwx<1) *pwx=1;
	if (*pwy>=leftwy||*pwy==0) *pwy=leftwy;
	if (*pwy<1) *pwy=1;
	nslog(@"補正後:pwx=%d,pwy=%d",*pwx,*pwy);
	
	// tsp補正
	if (tsp<0) tsp=0;
	if (tsp>=MAX_SPRITE_PATTERNS) tsp=MAX_SPRITE_PATTERNS-1;
	
	// UIImageをビットマップに展開する
	ULong *bitmap=(ULong *)[ImageHelper convertUIImageToBitmap:loadImg
													bitmapInfo:kCGBitmapByteOrder32Little|kCGImageAlphaPremultipliedLast	// RGBAの86形式
							];
	if (bitmap==NULL) {
		nslog(@"ワークが確保できない");
		return (-PIC_NOMEMORY);
	}
	//
	BOOL fUpdateBG=NO;
	SWord sp=tsp;
//	printf("tsp=%d〜\n",sp);
	printf("tsp=%d〜",sp);
	int x,y;
#if 0	//!!debug!!
	int xx=0;
#endif
	for (y=0;y<*pwy;y++) {
		for (x=0;x<*pwx;x++) {
			// 画像から1パターン分を読み出す
			for (int cy=0;cy<SPRITE_HEIGHT;cy++) {
				ULong *lp=bitmap+(ofstx+x*SPRITE_WIDTH)+(ofsty+(y*SPRITE_HEIGHT+cy))*width;
				for (int cx=0;cx<SPRITE_WIDTH;cx++) {
					ULong c=*lp++;
					if (c==0x000000ff && fblack) c=0; // 黒を透明に変換する時
#if 0	//!!debug!!
					printf("$%08lx,",c);
					if (++xx>=15) {
						printf("\n");
						xx=0;
					}
#endif
					sprite_pattern[sp][cy][cx]=c;
				}
			}
			// spV1.7
			if (cntPatternInBG[sp]>0) {
				// BGで使われているパターンが更新された
				fUpdateBG=YES;
			}
			//
			spriteType[sp]=SPRITE_IOS; // iOS型で登録
			if (++sp>=MAX_SPRITE_PATTERNS) break;
		}
	}
	// tsp〜sp-1までが登録されたパターン番号
	printf("%d\n",sp-1);
//	printf("\n%d\n",sp-1);
	//
	free2(bitmap);
	//
	if (tpl>=0) {
		nslog(@"プレーンへの登録:%d〜,prw=%d",tpl,prw);
		SpriteRegs *spRegs=&spriteRegs[tpl];

		if (fomitSX) sx=spRegs->xpos;
		if (fomitSY) sy=spRegs->ypos;

		x=0;
		for (;tsp<sp;tsp++) {
			if (tpl>=MAX_SPRITE_PLANE) {
				nslog(@"プレーン最大数を超えるときは中断");
				break;
			}
			spRegs->xpos=sx+x*SPRITE_WIDTH;
			spRegs->ypos=sy;
			if (++x>=*pwx) {
				x=0;
				sy+=SPRITE_HEIGHT;
			}
			spRegs->ptnRegs.paletBlock=DEFAULT_BG_PALET_BLOCK; // 設定してるけどiOS型なので無効
			spRegs->ptnRegs.ptrn	=tsp;
			spRegs->ptnRegs.fflip	=SPRITE_FLIP_NONE; // 固定
			spRegs->prw 			=prw;
			spRegs++;
		}
	} else {
		nslog(@"プレーンへの登録はしない");
	}
	// スプライト/BG表示処理
	nslog(@"sp_image end");
	[self spriteBGDraw:fUpdateBG];
	//
	return (sp); // 登録したパターン番号+1
}

//---------------------------------------------------------------------------------------
// BG関数
//---------------------------------------------------------------------------------------

-(BOOL)bgPut1:(SWord)pg x:(int)x y:(int)y sp:(SWord)sp paletBlock:(SWord)pb flip:(SWord)flip finit:(BOOL)finit
{
//	printSelf();
	SWord oldPb  =BGtextPage[pg][y][x].paletBlock;
	SWord oldPtrn=BGtextPage[pg][y][x].ptrn;
	if (BGtextPage[pg][y][x].fflip!=flip || oldPb!=pb || oldPtrn!=sp) {
//		nslog(@"実更新あり");
		// 実際に設定が変更されるとき
		BGtextPage[pg][y][x].fflip		=flip;
		BGtextPage[pg][y][x].paletBlock	=pb;
		BGtextPage[pg][y][x].ptrn		=sp;
//		nslog(@"bgPut1:sp=%d,pb=%d,flip=%d",sp,pb,flip);
		
		// 利用中カウンター spV1.7
		if (!finit) {
			// 旧を-1
			if (cntPatternInBG[oldPtrn]>0) cntPatternInBG[oldPtrn]--;
			if (cntPaletInBG[oldPb]>0)	   cntPaletInBG[oldPb]--;
		}
		// 新を+1
		cntPatternInBG[sp]++;
		cntPaletInBG[pb]++;
		// 実際に更新される
		return (YES);
	}
	// 実更新なし
	return (NO);
}

-(int)bgFill:(SWord)pg sp:(SWord)sp paletBlock:(SWord)pb flip:(SWord)flip finit:(BOOL)finit
// BGをパターンで埋める(メイン)
// finit : 初期化処理時
{
	printSelf();
	nslog(@"pg=%d,sp=%d,pb=%d,flip=%d",pg,sp,pb,flip);
	int cnt=0;
	for (int y=0;y<BG_TEXT_PAGE_HEIGHT;y++) {
		for (int x=0;x<BG_TEXT_PAGE_WIDTH;x++) {
			if ([self bgPut1:pg	x:x y:y sp:sp paletBlock:pb flip:flip finit:finit]) {
				// 実際に更新がかかったマスの数
				cnt++;
			}
		}
	}
	return (cnt);
}

-(void)bg_fill:(SWord)pg sp:(SWord)sp paletBlock:(SWord)pb flip:(SWord)flip
// テキストページをパターンで埋める
{
	printSelf();
	nslog(@"pg=%d,sp=%d,pb=%d,flip=%d",pg,sp,pb,flip);
	
	pg=checkBGpage(pg);
	sp=checkPatternNumber(sp);
	pb=checkPaletBlock(pb);
	//
	if ([self bgFill:pg sp:sp paletBlock:pb flip:flip finit:NO]>0) {
		// スプライト/BG表示処理
		nslog(@"bg_fill");
		[self spriteBGDraw:YES];
	}
}

//-----------------

-(void)bg_put:(SWord)pg x:(int)x y:(int)y sp:(SWord)sp paletBlock:(SWord)pb flip:(SWord)flip
// テキストページにパターン番号を割り付ける
{
	printSelf();
	nslog(@"pg=%d,x=%d,y=%d,sp=%d,pb=%d,flip=%d",pg,x,y,sp,pb,flip);
	
	pg=checkBGpage(pg);
	 x=checkBGx(x);
	 y=checkBGy(y);
	sp=checkPatternNumber(sp);
	nslog(@"bg_put:pg=%d,x=%d,y=%d,sp=%d",pg,x,y,sp);
	//
	if ([self bgPut1:pg x:x y:y sp:sp paletBlock:pb flip:flip finit:NO]) {
		// スプライト/BG表示処理
		nslog(@"bg_put実更新あり");
		[self spriteBGDraw:YES];
	} // 実変更がないときは処理なし
}

//-----------------

-(PatternRegs *)bg_get:(SWord)pg x:(int)x y:(int)y
{
	printSelf();

	pg=checkBGpage(pg);
	x=checkBGx(x);
	y=checkBGy(y);
	nslog(@"pg=%d,x=%d,y=%d",pg,x,y);
	nslog(@"x=%d,y=%d,ptrn=%d,pb=%d",x,y,BGtextPage[pg][y][x].ptrn,BGtextPage[pg][y][x].paletBlock);
	return (&BGtextPage[pg][y][x]);
}

//-----------------

-(BOOL)bg_set:(SWord)scrnNo page:(SWord)pg fdisp:(BOOL)fdisp
// BG画面にテキストページを割り付ける
// リターン値 : YES=ワークが確保できない , NO=正常終了
{
	printSelf();
	
	scrnNo=checkBGscrnNo(scrnNo);
	pg=checkBGpage(pg);
	if (BGscreen[scrnNo].textPage!=pg || BGscreen[scrnNo].fdisp!=fdisp) {
		// 前回と状態が変更
		BGscreen[scrnNo].textPage=pg;
		BGscreen[scrnNo].fdisp	 =fdisp;
		// BG用ワーク(再)確保
		if ([self allocBG]) {
			// メモリ不足
			return(YES);
		}
		// スプライト/BG表示処理
		nslog(@"bg_set");
		[self spriteBGDraw:YES];
	
		// BG0画面.textPage==BG1画面.textPageでかつxpos/yposも同じ時はBG0だけ処理良い
		// しかし、実際には2画面利用を設定しているのに両方を同じにすることはないはずなので、考慮しない
	} // 前回と同じ設定の時は何もしない
	return (NO);
}

//-----------------

-(void)bg_scroll:(SWord)scrnNo x:(int)x y:(int)y fomitX:(BOOL)fomitX fomitY:(BOOL)fomitY
{
	printSelf();
	nslog(@"x=%d(%d),y=%d(%d),scrn=%d",x,BGscreen[scrnNo].xpos,y,BGscreen[scrnNo].ypos,scrnNo);
	
	scrnNo=checkBGscrnNo(scrnNo);
	if (fomitX) x=BGscreen[scrnNo].xpos;
	if (fomitY) y=BGscreen[scrnNo].ypos;
	if (BGscreen[scrnNo].xpos!=x || BGscreen[scrnNo].ypos!=y) {
		nslog(@"異なる座標なので実行");
		// スプライト/BG表示処理
		BGscreen[scrnNo].xpos=x;
		BGscreen[scrnNo].ypos=y;
		nslog(@"bg_scroll");
		[self spriteBGDraw:YES];
	}
#ifdef DEBUG
	else{
		nslog(@"同一座標なのでスキップ");
	}
#endif
	// 同じ座標の時は再表示処理をかけない。
	// これをしないとちらつく。
	// scroll以外では表示がかかるので問題ない。
}

//-----------------

-(int)bg_stat:(SWord)scrnNo dataType:(int)dataType
{
	printSelfs(@"dataType=%d",dataType);
	scrnNo=checkBGscrnNo(scrnNo);
	BGRegs *bgRegs=&BGscreen[scrnNo];
	switch (dataType) {
		case 0: // x座標
			return (bgRegs->xpos);
		case 1: // y座標
			return (bgRegs->ypos);
		case 2: // テキストページ番号
			return (bgRegs->textPage);
		case 3: // 表示設定
			return (bgRegs->fdisp);
	}
	// 指定ミス
	return (-1);
}

//---------------------------------------------------------------------------------------
// 総合表示処理
//---------------------------------------------------------------------------------------
// 初期化
//---------------------------------------------------------------------------------------

// ビットマップワークのクリア
#define clearBitmap(Lpixcel)	memset(Lpixcel,0,consoleByte1Page)

//--------------------------------------------

-(void)freeSprite
// スプライトを開放する
{
	printSelf();
#if 0	// context内ビットマップを使うので開放不要
	if (lpixel!=NULL) { // 合成用
		free2(lpixel);
		lpixel=NULL;
	}
#endif
}

-(BOOL)initSprite
// スプライトを初期化する
// 先にcontextを設定しておくこと
// これは最初の1回しか呼び出してはいけない
// リターン値 : YES=ワークが確保できない , NO=正常終了
{
	printSelf();
	
	// 合成用ワーク(これは常に必要) : Consoleが作っているビットマップを使う
	lpixel=(ULong *)consolePixel; // 型変換のみ
	nslog(@"lpixel=%p",lpixel);

	// 初期化
	[self sp_init];
	//
	return (NO);
}

//--------------------------------------------

// BGを開放する
-(void)freeBG
{
	printSelf();
	if (BG01lpixel!=NULL) {
		free2(BG01lpixel);
		BG01lpixel=NULL;
	}
	// 確保は[0]だけで行われている
	if (BGscreen[0].lpixel!=NULL) {
		free2(BGscreen[0].lpixel);
		BGscreen[0].lpixel=NULL;
		BGscreen[1].lpixel=NULL; // [1]にも未確保の印は入れる
	}
	fBGupdate1st=NO;
}

// BGピクセルワーク確保
// fDisableUseBG0SPBG1 : YES=prwとしてBG0>SP>BG1を無効にする(あった場合、BG0>BG1>SPとみなす)
// bg_set()で表示BGページを変更したときは freeBG() → allocBG() してワークを再構築すること
// リターン値 : YES=ワークが確保できない , NO=正常終了
-(BOOL)allocBG
{
	printSelf();

	// 前のワークを開放
	[self freeBG];
	
	// 表示BGページ数を数える
	BGpages=0;
	int i;
	for (i=MAX_BG_SCREEN-1;i>=0;i--) { // BG番号 max → 0の順
		BGRegs *bgReg=&BGscreen[i];
		if (bgReg->fdisp) BGpages++; // 表示BGページ数
	}
	nslog(@"BGpages=%d",BGpages);

	if (BGpages!=0) {
		// BGが使われている
		fBGupdate1st=YES;
		BG01lpixel=(ULong *)malloc2(consoleByte1Page);
		if (BG01lpixel==NULL) {
			nslog(@"BG01合成ワークが確保できない");
			return(YES);
		}
		if (BGpages==MAX_BG_SCREEN) {
			if (!fDisableBG0SPBG1) { // BG0>SP>BG1が有効の時
				nslog(@"fDisableBG0SPBG1無効");
				// BG0/1両方使うときはさらに個別ワークを確保する
				// 2ページ同時確保する(開放時は[0]で行う)
				UByte *p=malloc2(consoleByte1Page*MAX_BG_SCREEN);
				if (p==NULL) {
					nslog(@"個別BGワークが確保できない");
					return(YES);
				}
				for (i=0;i<MAX_BG_SCREEN;i++) {
					BGscreen[i].lpixel=(ULong *)p;
					clearBitmap(BGscreen[i].lpixel);
					p+=consoleByte1Page;
				}
			} else { // BG0>SP>BG1が無効の時は追加ワーク不要
				nslog(@"fDisableBG0SPBG1有効");
				BGpages=1; // 個別ワークがないので
			}
		} // BGが0/1ページの時は追加ワーク不要
	} // 使われてないときはBG用ワーク不要
	return (NO);
}

//---------------------------------------------------------------------------------------
// 実描画処理
//---------------------------------------------------------------------------------------

void setDrawDirectionAndOffset(PatternRegs *reg,int *ofstX,int *ofstY,int *direcX,int *direcY)
{
	// 描画準備
	// 水平：通常、垂直：通常	c=sprite_pattern[sp][cy                ][cx               ];
	// 水平：反転、垂直：通常	c=sprite_pattern[sp][cy                ][SPRITE_WIDTH-1-cx];
	// 水平：通常、垂直：反転	c=sprite_pattern[sp][SPRITE_HEIGHT-1-cy][cx               ];
	// 水平：反転、垂直：反転	c=sprite_pattern[sp][SPRITE_HEIGHT-1-cy][SPRITE_WIDTH-1-cx];
	*ofstX	=0; // オフセット
	*ofstY	=0;
	*direcX	=+1; // 増分
	*direcY	=+1;
	if (reg->fflip&SPRITE_FLIP_HORIZONTAL) { // 水平反転
		*ofstX	=SPRITE_WIDTH-1;
		*direcX	=-1;
	}
	if (reg->fflip&SPRITE_FLIP_VERTICAL  ) { // 垂直反転
		*ofstY	=SPRITE_HEIGHT-1;
		*direcY	=-1;
	}
	nslog(@"[%d%ccy][%d%ccx]",*ofstY,(*direcY>0? '+':'-'),*ofstX,(*direcX>0? '+':'-'));
}

-(BOOL)draw1patternBG:(int)xpos gy:(int)gy reg:(PatternRegs *)reg pages:(int)pages BGlpixcel:(ULong *)BGlpixcel
// BG用1パターンの展開(BG画面別処理)
{
	printSelf();

	int    sp=reg->ptrn;	 	// 割り付けられているパターン番号
	SWord  pb=reg->paletBlock;  // 利用するパレットブロック
	char type=spriteType[sp]; 	// パターンの型を得る ; SPRITE_IOS/X68
	nslog(@"sp=%d/type=%d/pb=%d",sp,type,pb);
	
	// 描画方向設定
	int ofstX,ofstY; 	// オフセット
	int direcX,direcY;	// 増分
	setDrawDirectionAndOffset(reg,&ofstX,&ofstY,&direcX,&direcY);
	
	// 実描画処理
	int cy=0;
	if (gy<0) { // gy<0の部分は実表示しないので飛ばす
		cy=-gy;
		gy=0;
	}
	for (;cy<SPRITE_HEIGHT;cy++) {
		if (gy>=consoleHeight) return(YES); // これ以上の部分は表示領域外
		int cx=0;
		int gx=xpos;
		if (gx<0) {
			//nslog(@"gx=%d",gx);
			cx=-gx; // gx<0の部分は実表示しないので飛ばす
			gx=0;
		}
		ULong lbase=calcConsolePixelOffset(gx,gy);
		nslog(@"(%d,%d):lbase=%u",gx,gy,(uint)lbase);
		ULong *Lpixel  =lpixel   +lbase; // 合成BG用
		ULong *LpixelBG=BGlpixcel+lbase; // 個別BG用(無効なこともある）
		ULong c;
		for (;cx<SPRITE_WIDTH;cx++) {
			if (gx>=consoleWidth) break; // これ以上の部分は表示領域外なので次のcyへ
			c=sprite_pattern[sp][ofstY+direcY*cy][ofstX+direcX*cx];
			if (type==SPRITE_X68) {
				// パレットコードを実色に変換する
				c=x68_sprite_palet[pb][c];
			}
			if (c==0) { // BG透明
				if (pages==0) *Lpixel=c; // 一番下のページの時は透明でもクリアする(合成BGクリアを兼ねているから)
				// 上のページでは何もしない＝下を残す＝透過
			} else { // BG透明以外
				*Lpixel=c;
			}
			Lpixel++;
			if (BGlpixcel!=NULL) {
				*LpixelBG++=c; // 個別BGへは合成なく入れ込む(色のアルファ値はそのままで）
			}
			gx++;
		}
		gy++;
	} // for (cy)
	// 全体が描画範囲内だった印
	return (NO);
}

//---------------------------------------------------------------------------------------

// SP用1パターンの展開
-(BOOL)draw1pattern:(int)xpos gy:(int)gy reg:(PatternRegs *)reg prw:(SWord)prw
{
	printSelf();

	int    sp=reg->ptrn;	 	// 割り付けられているパターン番号
	SWord  pb=reg->paletBlock;  // 利用するパレットブロック
	char type=spriteType[sp]; 	// パターンの型を得る ; SPRITE_IOS/X68
	nslog(@"(%d,%d):sp=%d/type=%d/pb=%d",xpos,gy,sp,type,pb);

	// 描画方向設定
	int ofstX,ofstY; 	// オフセット
	int direcX,direcY;	// 増分
	setDrawDirectionAndOffset(reg,&ofstX,&ofstY,&direcX,&direcY);
	
	switch (prw) { // 優先順位補正
		case SPRITE_PRW_BG0SPBG1:	// BG0>SP>BG1
			if (!BGscreen[0].fdisp) { // BG0表示なし
				prw=SPRITE_PRW_SPBG0BG1; // SP>BG1と同じになる
				// BG1表示もないときも同じ
			} else { // BG0表示あり
				if (!BGscreen[1].fdisp) { // BG1表示なし
					prw=SPRITE_PRW_BG0BG1SP; // BG0>SPと同じになる
				} else {
					// BG0/1表示ともにあり
					if (fDisableBG0SPBG1) prw=SPRITE_PRW_BG0BG1SP;
				}
			}
			break;
	}
	nslog(@"prw=%d",prw);
	
	// 実描画処理
	int cy=0;
	if (gy<0) { // gy<0の部分は実表示しないので飛ばす
		cy=-gy;
		gy=0;
	}
	for (;cy<SPRITE_HEIGHT;cy++) {
		if (gy>=consoleHeight) {
			// これ以上の部分は表示領域外
			nslog(@"これ以上の部分は表示領域外:gy:%d>=%d:consoleHeight",gy,consoleHeight);
			return(YES);
		}
		int cx=0;
		int gx=xpos;
		if (gx<0) {
			cx=-gx; // gx<0の部分は実表示しないので飛ばす
			gx=0;
		}
		
		// どのBGワークを使うかは、スプライトのprwによる
		ULong lbase=calcConsolePixelOffset(gx,gy);
		nslog(@"(%d,%d):lbase=%u",gx,gy,(uint)lbase);
		ULong *Lpixel   =lpixel+lbase; // 合成BG用(パレットコードは展開済み)
		ULong *LpixelBG0=BGscreen[0].lpixel+lbase; // BG0:BG0 offのときは無意味
		ULong *LpixelBG1=BGscreen[1].lpixel+lbase; // BG1:BG1 offのときは無意味
//		nslog(@"cy=%d,cx初期=%d,base=%d",cy,cx,base);
		//
		ULong c;
		for (;cx<SPRITE_WIDTH;cx++) {
			if (gx>=consoleWidth) {
				// これ以上の部分はx表示領域外なので次のcyへ
				nslog(@"これ以上の部分は表示領域外:gx:%d>=%d:consoleWidth",gx,consoleWidth);
				break;
			}
			switch (prw) {
				case SPRITE_PRW_BG0SPBG1:	// BG0>SP>BG1
					// (1)BG0を描画する
					c=*LpixelBG0;
					// (2)=0ならSPを描画する
					if (c==0) { // 透明
						c=sprite_pattern[sp][ofstY+direcY*cy][ofstX+direcX*cx];
						if (type==SPRITE_X68) {
							// パレットコードを実色に変換する
						//	printf("palet:%ld→",c);
							c=x68_sprite_palet[pb][c];
						//	printf("$%08lx:color\n",c);
						}
						if (c==0) { // 透明
							// (3)SPも=0ならBG1を描画する
							c=*LpixelBG1;
						}
					}
					*Lpixel=c;
					break;
				//
				// 以下はlpixcelと合成(BGscreen.lpixcelは使わない）
				case SPRITE_PRW_BG0BG1SP:	// (BG0>BG1)>SP
					if (*Lpixel!=0) break; // BGが黒でなかったらBGそのまま
					// BGが透明の部分のみSPで描画
				case SPRITE_PRW_SPBG0BG1:	// SP>(BG0>BG1)
					c=sprite_pattern[sp][ofstY+direcY*cy][ofstX+direcX*cx];
					if (type==SPRITE_X68) {
						// パレットコードを実色に変換する
					//	printf("palet:%ld→",c);
						c=x68_sprite_palet[pb][c];
					//	printf("$%08lx:color\n",c);
					}
					if (c!=0) { // 透明以外
						*Lpixel=c;
					} // SP=透明部分はBGそのものなので描画なし
					break;
			}
			Lpixel++;
			LpixelBG0++;
			LpixelBG1++;
			gx++;
		} // for (cx)
		gy++;
	} // for (cy)
	// 全体が描画範囲内だった印
	return (NO);
}

// スプライト/BGをbitmap上に展開してから表示
// fBGupdate : BGも更新するかどうか
-(void)spriteBGDraw:(BOOL)fBGupdate
{
	printSelf();

	nslog(@"fBGupdate=%d",fBGupdate);
	nslog(@"_fhalt=%d,_fspriteBGDisp=%d",_fhalt,_fspriteBGDisp);
	if (_fhalt) {
		// 表示停止中は処理しない
		nslog(@"表示停止中");
		return;
	}
	if (!_fspriteBGDisp) {
		nslog(@"非表示時は処理しない");
		return;
	}

	//------------------------------------
	
	int i,gx,gy;
	if (fBGupdate||fBGupdate1st) {
		nslog(@"BG更新:fBGupdate=%d,fBGupdate1st=%d",fBGupdate,fBGupdate1st);
		// BG0画面>BG1画面で合成
		// BG0画面.textPage==BG1画面.textPageでかつxpos/yposも同じ時はBG0だけ処理良い
		// しかし、実際には2画面利用を設定しているのに両方を同じにすることはないはずなので、考慮しない
		clearBitmap(lpixel); // 合成側ワークをクリア
		// BGは2ページあり、それぞれが独立表示位置を持つため、合成時にクリア対象となる場所を特定しにくい。なので固定的に全体をクリアしている。
		if (BGpages!=0) {
			nslog(@"BG画面あり:BGpages=%d",BGpages);
			// 1:片方のみまたは2画面でfDisableBG0SPBG1 : lpixelにのみ展開
			// 2:両方表示 : BGlpixelにも展開
			int pages=0;
			for (i=MAX_BG_SCREEN-1;i>=0;i--) { // BG画面番号 max → 0の順
				BGRegs *bgReg=&BGscreen[i];
				if (!bgReg->fdisp) continue; // このBG画面は非表示
				nslog(@"BG画面%d描画(%d画面目)",i,pages+1);
				//
				// BGテキスト座標でループ
				int ypos=bgReg->ypos; // 表示開始座標y
				for (gy=0;gy<BG_TEXT_PAGE_HEIGHT;gy++) {
					nslog(@"ypos=%d",ypos);
					if (ypos>-SPRITE_HEIGHT) {
						if (ypos>=consoleHeight) break; // これ以上は描画不要
						int xpos=bgReg->xpos; // 表示開始座標x
						for (gx=0;gx<BG_TEXT_PAGE_WIDTH;gx++) {
							if (xpos>-SPRITE_WIDTH) {
								nslog(@"xpos>=consoleWidth:%d",xpos>=consoleWidth);
								if (xpos>=consoleWidth) {
									// これ以上は描画不要
									nslog(@"x領域外へ:%d(consoleWidth=%d)",xpos,consoleWidth);
									break;
								}
								// ここは描画対象になる(ただし全体とは限らない)
								[self draw1patternBG:xpos
												  gy:ypos
												 reg:&BGtextPage[bgReg->textPage][gy][gx]
											   pages:pages
										   BGlpixcel:BGscreen[i].lpixel
								 ];
							} // xpos<=-SPRITE_WIDTHは描画対象に入らない
							xpos+=SPRITE_WIDTH;
						} // for (gx)
					} // <=-SPRITE_HEIGHTは描画対象に入らない
					ypos+=SPRITE_HEIGHT;
				} // for (gy)
				pages++;
			} // for (i)
			// 合成情報を保存
			memcpy(BG01lpixel,lpixel,consoleByte1Page);
			fBGupdate1st=NO;
		} // if (BGpages)
		else {
			nslog(@"BG画面なし");
		}
		// BGが両方非表示のときはクリアのみである
	} else { // BGの更新がないとき
		// 前の合成情報をコピーするだけ
		nslog(@"BG更新なし");
		memcpy(lpixel,BG01lpixel,consoleByte1Page);
	}
	
	//------------------------------------
	// スプライト部分の描画
	nslog(@"スプライト更新");
	// １プレーン毎にBGとの重ね合わせが必要
	SpriteRegs *reg;
	for (int i=MAX_SPRITE_PLANE-1;i>=0;i--) { // プレーン番号 max → 0の順
		reg=&spriteRegs[i];
		if (reg->prw!=SPRITE_PRW_HIDE) {
			gy=reg->ypos;
			gx=reg->xpos;
			if (gy<=-SPRITE_HEIGHT
			 || gx<=-SPRITE_WIDTH
			 || gx>= consoleWidth
			) {
				nslog(@"SPプレーン%d:表示範囲外(%d,%d)",i,gx,gy);
				continue; // 表示範囲外
			}
			// １パターン表示
			nslog(@"SPプレーン%d描画/(gx,gy)=(%d,%d)",i,gx,gy);
			
			if (i==0) {
				nslog(@"i==0");
			}
			
			[self draw1pattern:gx gy:gy reg:&reg->ptnRegs prw:reg->prw];
		}
	} // for (i)

	//------------------------------------
#ifdef OUTPUT_CONSOLE
	outputConsole(@"/test/bitmap.jpg",self);
#endif

#if 0
	pushContext();
	
	// 描画指示
	[self draw];
#else
	// 上の２つの実体を合わせただけ
	if (self.imageRef) { // 前の描画がまだ終わってない時にここに来た時
		imageCnt++; // 回数だけ数えておく
		nslog(@"imgCnt=%d",imageCnt);
	} else {
		UIGraphicsPushContext(context); // contextをカレントにする(push)
		imageRef=CGBitmapContextCreateImage(context); // CGBitmapContextCreateImage()はコピーを作るのでこの後操作してもimageRef内容は変わらない、らしい
		self.fimage=DRAW_NOWAIT; // KVO発生
		UIGraphicsPopContext(); // contextを戻す(pop)
	}
#endif
}

-(void)spriteBGcLear
{
	printSelf();

	if (_fhalt) {
		// 表示停止中は処理しない
		nslog(@"表示停止中");
		return;
	}
	if (!_fspriteBGDisp) {
		nslog(@"非表示時は処理しない");
		return;
	}
	
	nslog(@"実クリア");
	pushContext();
	CGContextClearRect(context,self.frame);
	[self draw];
}

//---------------------------------------------------------------------------------------

-(void)dealloc
{
	printSelf();
	[self freeBG];
	[self freeSprite];
}

//---------------------------------------------------------------------------------------


@end
