/*
 *	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));
	p->render	= render;
	p->left		= left;
	p->top		= top;
	p->right	= right;
	p->bottom	= bottom;
}
/****************************************************************************
 *	
 ****************************************************************************/
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
