/*
 *	clipcqrd.c
 *
 *	コールバックキューを用いた優先度付き描画
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2016 Naoyuki Sawa
 *
 *	* Sat Jan 30 21:30:05 JST 2016 Naoyuki Sawa
 *	- 1st リリース。
 *	- 特に良く使う描画関数の、優先度付きバージョンを定義しました。
 *	  他にも優先度付き描画を行いたい描画関数が有れば、このモジュールに追加して下さい。
 *	- 当モジュールには特に良く使う描画関数だけを定義したので、当モジュールの関数は既存の描画関数とほぼ1:1に対応しています。
 *	  しかし、コールバックキューによる描画は、必ずしもそのように使う必要は有りません。
 *	  例えば、特定の優先度でコールバックを行い、その時点のフレームバッファに対して、アプリケーション定義のフィルタを掛けるような使い方も出来ます。
 *	  具体例としては、優先度マイナスを背景,優先度プラスを前景として、優先度0でコールバックを掛けて、背景だけにラスタスクロールを掛けたり出来ます。
 *	  上記のような、アプリケーション特有の処理を行う場合は、当モジュール内に機能を追加するよりも、個々のアプリケーションのソース内で定義する方が良いでしょう
 *	* Sun Jan 31 21:43:46 JST 2016 Naoyuki Sawa
 *	- CbkQue_render_set_draw_area()を追加しました。
 */
#include "clip.h"
/****************************************************************************
 *	
 ****************************************************************************/
struct ST_CbkQue_surface_clear {
	SURFACE*		surface;		//+ 0, 4
	uint16_t		color;			//+ 4, 2
    //	uint16_t		padding;		//+ 6, 2
};							//= 8
static void fn_CbkQue_surface_clear(ST_CbkQue* pCbkQue, int pri, void* param) {
	struct ST_CbkQue_surface_clear* p = param;
	surface_clear(p->surface, p->color);
}
/*--------------------------------------------------------------------------*/
//□surface_clear()の優先度付きバージョン
void CbkQue_surface_clear(ST_CbkQue* pCbkQue, int pri, SURFACE* surface, int color) {
	struct ST_CbkQue_surface_clear* p = CbkQue_AddMem(pCbkQue, pri, fn_CbkQue_surface_clear, sizeof(struct ST_CbkQue_surface_clear));
	p->surface		= surface;
	p->color		= color;
}
/****************************************************************************
 *	
 ****************************************************************************/
struct ST_CbkQue_render_set_draw_area {
	RENDER*			render;			//+ 0, 4
	 int16_t		left;			//+ 4, 2
	 int16_t		top;			//+ 6, 2
	 int16_t		right;			//+ 8, 2
	 int16_t		bottom;			//+10, 2
};							//=12
static void fn_CbkQue_render_set_draw_area(ST_CbkQue* pCbkQue, int pri, void* param) {
	struct ST_CbkQue_render_set_draw_area* p = param;
	RENDER* render		= p->render;
	render->left		= p->left;
	render->top		= p->top;
	render->right		= p->right;
	render->bottom		= p->bottom;
}
/*--------------------------------------------------------------------------*/
//□RENDER.left,top,right,bottomを設定する優先度付きバージョン
void CbkQue_render_set_draw_area(ST_CbkQue* pCbkQue, int pri, RENDER* render, int left, int top, int right, int bottom) {
	struct ST_CbkQue_render_set_draw_area* p = CbkQue_AddMem(pCbkQue, pri, fn_CbkQue_render_set_draw_area, sizeof(struct ST_CbkQue_render_set_draw_area));
//{{クリッピング領域にサーフェイス範囲外を設定すると各種描画関数がメモリを破壊する恐れが有るので、安全のためにクリッピング領域が範囲内である事を確認しておく。
	SURFACE* surface	= render->surface;
	if((left < 0) || (right  > surface->w) || (left >  right) ||		//クリッピング領域の左右がサーフェイスの範囲内であり、左右が逆転していない事。
	   (top  < 0) || (bottom > surface->h) || (top  > bottom)) { DIE(); }	//クリッピング領域の上下がサーフェイスの範囲内であり、上下が逆転していない事。
//}}クリッピング領域にサーフェイス範囲外を設定すると各種描画関数がメモリを破壊する恐れが有るので、安全のためにクリッピング領域が範囲内である事を確認しておく。
	p->render		= render;
	p->left			= left;
	p->top			= top;
	p->right		= right;
	p->bottom		= bottom;
}
/****************************************************************************
 *	
 ****************************************************************************/
struct ST_CbkQue_render_set_draw_area_full {
	RENDER*			render;			//+ 0, 4
};							//= 4
static void fn_CbkQue_render_set_draw_area_full(ST_CbkQue* pCbkQue, int pri, void* param) {
	struct ST_CbkQue_render_set_draw_area_full* p = param;
	RENDER* render		= p->render;
	SURFACE* surface	= render->surface;
	render->left		= 0;
	render->top		= 0;
	render->right		= surface->w;
	render->bottom		= surface->h;
}
/*--------------------------------------------------------------------------*/
//□RENDER.left,top,right,bottomをサーフェイス全体に設定する優先度付きバージョン
void CbkQue_render_set_draw_area_full(ST_CbkQue* pCbkQue, int pri, RENDER* render) {
	struct ST_CbkQue_render_set_draw_area_full* p = CbkQue_AddMem(pCbkQue, pri, fn_CbkQue_render_set_draw_area_full, sizeof(struct ST_CbkQue_render_set_draw_area_full));
	p->render		= render;
}
/****************************************************************************
 *	
 ****************************************************************************/
struct ST_CbkQue_render_point {
	RENDER*			render;			//+ 0, 4
	 int16_t		x;			//+ 4, 2
	 int16_t		y;			//+ 6, 2
	uint16_t		color;			//+ 8, 2
    //	uint16_t		padding;		//+10, 2
};							//=12
static void fn_CbkQue_render_point(ST_CbkQue* pCbkQue, int pri, void* param) {
	struct ST_CbkQue_render_point* p = param;
	render_point(p->render, p->x, p->y, p->color);
}
/*--------------------------------------------------------------------------*/
//□render_point()の優先度付きバージョン
void CbkQue_render_point(ST_CbkQue* pCbkQue, int pri, RENDER* render, int x, int y, int color) {
	struct ST_CbkQue_render_point* p = CbkQue_AddMem(pCbkQue, pri, fn_CbkQue_render_point, sizeof(struct ST_CbkQue_render_point));
	p->render		= render;
	p->x			= x;
	p->y			= y;
	p->color		= color;
}
/****************************************************************************
 *	
 ****************************************************************************/
struct ST_CbkQue_render_line {
	RENDER*			render;			//+ 0, 4
	 int16_t		x0;			//+ 4, 2
	 int16_t		y0;			//+ 6, 2
	 int16_t		x1;			//+ 8, 2
	 int16_t		y1;			//+10, 2
	uint16_t		color;			//+12, 2
    //	uint16_t		padding;		//+14, 2
};							//=16
static void fn_CbkQue_render_line(ST_CbkQue* pCbkQue, int pri, void* param) {
	struct ST_CbkQue_render_line* p = param;
	render_line(p->render, p->x0, p->y0, p->x1, p->y1, p->color);
}
/*--------------------------------------------------------------------------*/
//□render_line()の優先度付きバージョン
void CbkQue_render_line(ST_CbkQue* pCbkQue, int pri, RENDER* render, int x0, int y0, int x1, int y1, int color) {
	struct ST_CbkQue_render_line* p = CbkQue_AddMem(pCbkQue, pri, fn_CbkQue_render_line, sizeof(struct ST_CbkQue_render_line));
	p->render		= render;
	p->x0			= x0;
	p->y0			= y0;
	p->x1			= x1;
	p->y1			= y1;
	p->color		= color;
}
/****************************************************************************
 *	
 ****************************************************************************/
struct ST_CbkQue_render_rectangle {
	RENDER*			render;			//+ 0, 4
	 int16_t		x;			//+ 4, 2
	 int16_t		y;			//+ 6, 2
	 int16_t		w;			//+ 8, 2
	 int16_t		h;			//+10, 2
	uint16_t		color;			//+12, 2
	uint8_t			fill;			//+14, 1
    //	uint8_t			padding;		//+15, 1
};							//=16
static void fn_CbkQue_render_rectangle(ST_CbkQue* pCbkQue, int pri, void* param) {
	struct ST_CbkQue_render_rectangle* p = param;
	(*(p->fill ? render_rectangle_fill : render_rectangle))(p->render, p->x, p->y, p->w, p->h, p->color);
}
static void CbkQue_render_rectangle_subr(ST_CbkQue* pCbkQue, int pri, RENDER* render, int x, int y, int w, int h, int color, int fill) {
	struct ST_CbkQue_render_rectangle* p = CbkQue_AddMem(pCbkQue, pri, fn_CbkQue_render_rectangle, sizeof(struct ST_CbkQue_render_rectangle));
	p->render		= render;
	p->x			= x;
	p->y			= y;
	p->w			= w;
	p->h			= h;
	p->color		= color;
	p->fill			= fill;
}
/*--------------------------------------------------------------------------*/
//□render_rectangle()の優先度付きバージョン
void CbkQue_render_rectangle(ST_CbkQue* pCbkQue, int pri, RENDER* render, int x, int y, int w, int h, int color) {
	CbkQue_render_rectangle_subr(pCbkQue, pri, render, x, y, w, h, color, 0/*fill*/);
}
//□render_rectangle_fill()の優先度付きバージョン
void CbkQue_render_rectangle_fill(ST_CbkQue* pCbkQue, int pri, RENDER* render, int x, int y, int w, int h, int color) {
	CbkQue_render_rectangle_subr(pCbkQue, pri, render, x, y, w, h, color, 1/*fill*/);
}
/****************************************************************************
 *	
 ****************************************************************************/
struct ST_CbkQue_render_printf {
	RENDER*			render;			//+ 0, 4
	 int16_t		x;			//+ 4, 2
	 int16_t		y;			//+ 6, 2
	uint16_t		type;			//+ 8, 2
	uint16_t		color;			//+10, 2
	uint8_t			framed;			//+12, 1
	char			str[0];			//+13, ?
};							//=13+ ?
static void fn_CbkQue_render_printf(ST_CbkQue* pCbkQue, int pri, void* param) {
	struct ST_CbkQue_render_printf* p = param;
	(*(p->framed ? render_string_framed : render_string))(p->render, p->x, p->y, p->str, p->type, p->color);
}
static void CbkQue_render_printf_subr(ST_CbkQue* pCbkQue, int pri, RENDER* render, int x, int y, int type, int color, const char* fmt, va_list ap, int framed) {
	struct ST_CbkQue_render_printf* p;
	va_list ap2;
	va_copy(ap2, ap);
	p = CbkQue_AddMem(pCbkQue, pri, fn_CbkQue_render_printf, sizeof(struct ST_CbkQue_render_printf) + vscprintf(fmt, ap2) + 1/*nul*/);
	va_end(ap2);
	p->render		= render;
	p->x			= x;
	p->y			= y;
	p->type			= type;
	p->color		= color;
	p->framed		= framed;
	vsprintf(p->str, fmt, ap);
}
/*--------------------------------------------------------------------------*/
//□render_printf()の優先度付きバージョン
void CbkQue_render_printf(ST_CbkQue* pCbkQue, int pri, RENDER* render, int x, int y, int type, int color, const char* fmt, ...) {
	va_list ap;
	va_start(ap, fmt);
	CbkQue_render_printf_subr(pCbkQue, pri, render, x, y, type, color, fmt, ap, 0/*framed*/);
	va_end(ap);
}
//□render_printf_framed()の優先度付きバージョン
void CbkQue_render_printf_framed(ST_CbkQue* pCbkQue, int pri, RENDER* render, int x, int y, int type, int color, const char* fmt, ...) {
	va_list ap;
	va_start(ap, fmt);
	CbkQue_render_printf_subr(pCbkQue, pri, render, x, y, type, color, fmt, ap, 1/*framed*/);
	va_end(ap);
}
/****************************************************************************
 *	
 ****************************************************************************/
struct ST_CbkQue_sprite_draw {
	 int16_t		x;			//+ 0, 2
	 int16_t		y;			//+ 2, 2
	uint16_t		sprno;			//+ 4, 2
	uint16_t		param;			//+ 6, 2
};							//= 8
static void fn_CbkQue_sprite_draw(ST_CbkQue* pCbkQue, int pri, void* param) {
	struct ST_CbkQue_sprite_draw* p = param;
	sprite_draw(p->x, p->y, p->sprno, p->param);
}
/*--------------------------------------------------------------------------*/
//□sprite_draw()の優先度付きバージョン
void CbkQue_sprite_draw(ST_CbkQue* pCbkQue, int pri, int x, int y, int sprno, int param) {
	struct ST_CbkQue_sprite_draw* p = CbkQue_AddMem(pCbkQue, pri, fn_CbkQue_sprite_draw, sizeof(struct ST_CbkQue_sprite_draw));
	p->x			= x;
	p->y			= y;
	p->sprno		= sprno;
	p->param		= param;
}
/****************************************************************************
 *	
 ****************************************************************************/
//当モジュール内ではsprite_draw2()の優先度付きバージョンを定義しない事にしました。理由は、以下の通りです。
//sprite_draw2()を呼び出すと、clipspr2.o,及び,一連の3D関連モジュールがリンクされてしまいます。特に、3D関連モジュールの容量が大きいです。
//それらが無駄にリンクされて、アプリケーションの容量が増える事を避けるために、当モジュール内ではsprite_draw2()の優先度付きバージョンを定義しない事にしました。
//その代わりに、sprite_draw2()の優先度付きバージョンを使用するアプリケーションでは、アプリケーションのソースコードに、以下のコードをコピーして使用して下さい。
#if 0
struct ST_CbkQue_sprite_draw2 {
	 int16_t		x;			//+ 0, 2
	 int16_t		y;			//+ 2, 2
	uint16_t		sprno;			//+ 4, 2
	uint16_t		param;			//+ 6, 2
	fixed			scale_x;		//+ 8, 4
	fixed			scale_y;		//+12, 4
	fixed			rot;			//+16, 4
};							//=20
static void fn_CbkQue_sprite_draw2(ST_CbkQue* pCbkQue, int pri, void* param) {
	struct ST_CbkQue_sprite_draw2* p = param;
	sprite_draw2(p->x, p->y, p->sprno, p->param, p->scale_x, p->scale_y, p->rot);
}
/*--------------------------------------------------------------------------*/
//□sprite_draw2()の優先度付きバージョン
void CbkQue_sprite_draw2(ST_CbkQue* pCbkQue, int pri, int x, int y, int sprno, int param, fixed scale_x, fixed scale_y, fixed rot) {
	struct ST_CbkQue_sprite_draw2* p = CbkQue_AddMem(pCbkQue, pri, fn_CbkQue_sprite_draw2, sizeof(struct ST_CbkQue_sprite_draw2));
	p->x			= x;
	p->y			= y;
	p->sprno		= sprno;
	p->param		= param;
	p->scale_x		= scale_x;
	p->scale_y		= scale_y;
	p->rot			= rot;
}
#endif
