/*	
 *	cliprend.c
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2002 Naoyuki Sawa
 *
 *	* Wed Feb 13 06:00:00 JST 2002 Naoyuki Sawa
 *	- 作成開始。
 *	* Fri Mar  8 07:00:00 JST 2002 Naoyuki Sawa
 *	- render_line()で終点側がクリッピングされた時に、
 *	  画面端に1ピクセル隙間が出来てしまう問題を修正。
 *	* Wed Apr 24 10:11:00 JST 2002 Naoyuki Sawa
 *	- render_polygon()を追加。
 *	* Wed Jun  5 13:51:00 JST 2002 Naoyuki Sawa
 *	- render_point()を追加。
 *	* Wed Jun 18 21:39:00 JST 2002 Naoyuki Sawa
 *	- render_fill()を追加。
 *	* Sat Jul  6 08:42:00 JST 2002 Naoyuki Sawa
 *	- surface_point()を追加。
 *	* Sat Jul  6 17:51:00 JST 2002 Naoyuki Sawa
 *	- render_fill()の関数名をrender_paint()に変更。
 *	- render_rectangle()を追加。
 *	* Thu Jul 25 04:07:00 JST 2002 Naoyuki Sawa
 *	- render_rectangle_fill()を追加。
 *	* Sun Jul 28 16:56:00 JST 2002 Naoyuki Sawa
 *	- render_paint()に戻り値(塗ったピクセル数)を追加。
 *	* Sat Sep 21 23:02:00 JST 2002 Naoyuki Sawa
 *	- render_dashes()追加。
 *	* Sat Oct 21 15:58:00 JST 2002 Naoyuki Sawa
 *	- render_dashes()に戻り値を追加。
 *	* Sat Mar  8 06:23:00 JST 2003 Naoyuki Sawa
 *	- 描画用ワーク(xformed_vectors[],clip_vertices[]など)を_def_vbuff[]上に確保。
 */
#include "clip.h"

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

TEXTURE*
texture_init(TEXTURE* texture, const void* data)
{
	TEXTUREHEADER* header;

	header = (TEXTUREHEADER*)data;

	/* ヘッダ情報を検査します。
	 * * P/ECEの仕様に「1bitデータmask付き」(bpp=1,mask=1)は存在しませんが、
	 *   本ライブラリでは、有効なテクスチャ形式としてとして利用可能なので、
	 *   エラーにはしません。
	 * * テクセル座標として指定可能なのは0〜255に制限されますが、
	 *   テクスチャ自体のサイズは256ドット以上でも構いません。
	 *   従って、ここではサイズの上限は検査していません。
	 */
	if(strncmp((char*)&header->head, "PMBP", 4) != 0) DIE();
	if(header->bpp  != 1 && header->bpp  != 2) DIE();
	if(header->mask != 0 && header->mask != 1) DIE();
	if(header->w < 8 || (header->w & 7) != 0) DIE();
	/* if(header->h < 8 || (header->h & 7) != 0) DIE(); -> 修正：縦サイズは任意でした。 */

	/* テクスチャヘッダとポインタを格納します。 */
	memset(texture, 0, sizeof(TEXTURE));
	texture->header = *header;
	texture->buf  = (unsigned char*)(header + 1);
	if(header->mask) {
		texture->mask = (unsigned char*)(header + 1) +
				header->w * header->h / (8 / header->bpp);
	}

	return texture;
}

void
surface_clear(SURFACE* surface, int color)
{
	int n;

	n = surface->w * surface->h;
	if(surface->vbuff != NULL) memset(surface->vbuff, color, n);
	if(surface->zbuff != NULL) memset(surface->zbuff, 0xFF, n);
}

int
surface_point(SURFACE* surface, int x, int y)
{
	return 0 <= x && x <= surface->w - 1 &&
	       0 <= y && y <= surface->h - 1 ?
		surface->vbuff[surface->w * y + x] : -1;
}

/*****************************************************************************
 *	RENDER
 *****************************************************************************/

#define N_VERTICES_MAX	8	/* 1ポリゴン当たりの最大頂点数 */

/* クリッピング用頂点 */
typedef struct _CLIPVERTEX {
	float x, y, z;		/* + 0,12 頂点座標       */
	unsigned short s, t;	/* +12, 4 テクスチャ座標 */
				/* =16                   */
} CLIPVERTEX;

/* 描画用頂点 */
typedef struct _RENDVERTEX {
	unsigned short x, y;	/* + 0,4 頂点座標               */
	unsigned short z;	/* + 4,2 Ｚ値(8.8bit)           */
	unsigned short s, t;	/* + 6,4 テクスチャ座標(8.8bit) */
				/* =10                          */
} RENDVERTEX;

/* DDA */
typedef struct _DDA {
	int n;			/* + 0,4 端数の増加量     */
	int d;			/* + 4,4 端数             */
	int u;			/* + 8,4 毎回の変化量     */
	int v;			/* +12,4 繰上げ時の変化量 */
				/* =16                    */
} DDA;

typedef struct _RENDER_WORK {
	VECTOR xformed_vectors[255];								/* 12*255=3060: 変換済み頂点座標バッファ（MESH.nvが符号無し8ビットなので、最大255頂点です） */
	CLIPVERTEX clip_vertices[2][N_VERTICES_MAX];						/* 16*2*8= 256: クリッピング用頂点バッファ         */
	RENDVERTEX rend_vertices[N_VERTICES_MAX];						/* 10*8  =  80: 描画用頂点バッファ                 */
	unsigned char fore_color;								/*           1: 前景色                             */
	unsigned char back_color;								/*           1: 背景色                             */
	void (*draw_scanline)(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1);	/*           4: スキャンライン描画関数へのポインタ */
} RENDER_WORK;											/* 合計 = 3402: _def_vbuff[128*88=11264]のサイズを超えないこと！（まだ3倍以上余裕あります） */
#define render_work	((RENDER_WORK*)_def_vbuff)	/* 描画用一時ワークは、_def_vbuff[]上に確保します。 */
							/* これらのワークはローカル関数間の連絡のみに利用され、グローバル関数間で保持する必要はないので、 */
							/* 基本的にユーザーアプリケーションから意識する必要はありません。 */
							/* ただし、直接_def_vbuff[]に描画しようとすると、描画中にワークが破壊され、正しく動作しません。 */
							/* 描画ターゲットに_def_vbuff[]を指定しないよう、ご注意ください。 */

static int  clip_z(RENDER* render, int nsrc);
static int clip_xy(RENDER* render, int nsrc);
/* Ｚコンペアあり */
static void select_draw_scanline_wz(RENDER* render);
static void draw_primitive_wz(RENDER* render, int n_vertices);
static void draw_scanline_wz_color(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1);
static void draw_scanline_wz_1bit(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1);
static void draw_scanline_wz_1bitmask(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1);
static void draw_scanline_wz_2bit(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1);
static void draw_scanline_wz_2bitmask(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1);
/* Ｚコンペアなし */
static void select_draw_scanline_woz(RENDER* render);
static void draw_primitive_woz(RENDER* render, int n_vertices);
static void draw_scanline_woz_color(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1);
static void draw_scanline_woz_1bit(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1);
static void draw_scanline_woz_1bitmask(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1);
static void draw_scanline_woz_2bit(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1);
static void draw_scanline_woz_2bitmask(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1);

void
render_init(RENDER* render, SURFACE* surface, int x, int y, int width, int height, float front, float back, float fovy)
{
	/* サーフェイスを設定します。 */
	render->surface = surface;

	/* ビューポート矩形を設定します。 */
	if(width == 0) width = surface->w;
	if(height == 0) height = surface->h;
	render->left = x;
	render->top = y;
	render->right = x + width;
	render->bottom = y + height;
	if(render->left < 0 ) render->left = 0;
	if(render->top < 0 ) render->top = 0;
	if(render->right > surface->w) render->right = surface->w;
	if(render->bottom > surface->h) render->bottom = surface->h;

	/* クリッピング距離を設定します。 */
	render->front = front;
	render->back = back;

	/* コンテキストスタックを初期化します。 */
	render->context = render->context_stack;

	/* 変換行列を初期化します。 */
	matrix_viewportz(&render->context->matrix, &MATRIX_I, x, y, width, height);
	matrix_perspect (&render->context->matrix, &render->context->matrix, fovy, (float)width / height, front);

	/* テクスチャを初期化します。 */
	render->context->texture = NULL;
}

void
render_save(RENDER* render)
{
	/* スタックトップを複製します。 */
	if(++render->context == render->context_stack + RENDER_CONTEXT_STACK_SIZE) DIE();
	memcpy(render->context, render->context - 1, sizeof(RENDERCONTEXT));
}

void
render_restore(RENDER* render)
{
	/* スタックトップを捨てます。 */
	if(render->context-- == render->context_stack) DIE();
}

void
render_point(RENDER* render, int x, int y, int color)
{
	SURFACE* surface;
	unsigned char* vptr;
	int ofs;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* ビューポート矩形外なら、描きません。 */
	if(x < render->left || render->right  <= x ||
	   y < render->top  || render->bottom <= y) return;

	/* ピクセルアドレスを求めます。 */
	ofs = surface->w * y + x;
	vptr = surface->vbuff + ofs;

	/* ピクセルを描きます。 */
	*vptr = color;
}

/* 全く高速化していません。遅いです。
 * ゲームでは、高速塗りつぶしが要求される場面は少ないと思うので、
 * 現状のままでも特に問題はないと思います。
 */
int
render_paint(RENDER* render, int x0, int y0, int color)
{
/* 塗りつぶし点スタックサイズ：
 * 実験したところ、かなり複雑な塗りつぶしでも24程度で充分でしたが、
 * 念のため、余裕を見込んで、大きめに取っておくことにします。
 * あまり大きすぎると、P/ECEではスタックがあふれるので、ご注意ください。
 */
#define RENDER_PAINT_STACK_SIZE	64

	SURFACE* surface;
	short stack[RENDER_PAINT_STACK_SIZE][2]; /* メモリ節約のためshortで */
	int i_stack, ofs, x, y, x1, x2;
	unsigned char c;
	int cnt = 0; /* ここに塗ったピクセル数をカウントします */

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 塗りつぶし開始点がビューポート外なら、何もしません。 */
	if(x0 < render->left || render->right  - 1 < x0) return 0;
	if(y0 < render->top  || render->bottom - 1 < y0) return 0;

	/* 塗りつぶされる色を取得します。 */
	ofs = surface->w * y0 + x0;
	c = surface->vbuff[ofs];

	/* 塗りつぶし開始点が既に塗りつぶす色なら、何もしません。 */
	/* if(c == color) return 0; */
	/* ->よく考えたら、このチェックは不要でした。
	 *   もしも塗りつぶし開始点が既に塗りつぶす色なら、
	 *   1. スタックに最初の(x0,y0)を積む。
	 *   2. while()ループの中で(x0,y0)を取り出す。
	 *   3. 既に塗られているので、continueで飛ばされる。
	 *   4. スタックは空なので、終了する。
	 *   となり、何もせずに終了します。
	 */

	/* 塗りつぶし開始点をスタックに積みます。 */
	stack[0][0] = x0;
	stack[0][1] = y0;
	i_stack = 1;

	/* 塗りつぶし点がなくなるまで... */
	while(i_stack != 0) {
		/* 塗りつぶし点を取り出します。 */
		i_stack--;
		x0 = stack[i_stack][0];
		y0 = stack[i_stack][1];

		/* 既に塗られていたら、飛ばします。 */
		ofs = surface->w * y0 + x0;
		if(surface->vbuff[ofs] == color) continue;

		/* 塗られる色の左端を探します。 */
		x1 = x0;
		for(;;) {
			x1--;
			if(x1 < render->left) break; /* ビューポート外 */
			ofs = surface->w * y0 + x1;
			if(surface->vbuff[ofs] != c) break; /* 別色 */
		}
		x1++; /* 一つ行き過ぎているので戻す */

		/* 塗られる色の右端を探します。 */
		x2 = x0;
		for(;;) {
			x2++;
			if(x2 > render->right - 1) break; /* ビューポート外 */
			ofs = surface->w * y0 + x2;
			if(surface->vbuff[ofs] != c) break; /* 別色 */
		}
		x2--; /* 一つ行き過ぎているので戻す */

		/* 左右の間を塗りつぶします。 */
		for(x = x1; x <= x2; x++) {
			ofs = surface->w * y0 + x;
			surface->vbuff[ofs] = color;
			cnt++; /* 塗ったピクセル数をカウント */
			/* ここでpceLCDTrans()を呼ぶと、塗りつぶしの様子を1ピクセル単位で観察できます。 */
			/* pceLCDTrans() */
		}
		/* ここでpceLCDTrans()を呼ぶと、塗りつぶしの様子を1ライン単位で観察できます。 */
		/* pceLCDTrans() */

		/* 上のラインの調査。 */
		if(y0 != render->top) {
			y = y0 - 1;
			x = x1;
			for(;;) {
				/* 塗られる色の始まりを探します。 */
				for(;;) {
					if(x > x2) break;
					ofs = surface->w * y + x;
					if(surface->vbuff[ofs] == c) break;
					x++;
				}
				if(x > x2) break; /* もうない */

				/* 塗られる色の終わりを探します。 */
				for(;;) {
					if(x > x2) break;
					ofs = surface->w * y + x;
					if(surface->vbuff[ofs] != c) break;
					x++;
				}

				/* 塗られる色の終わりの位置をスタックに積みます。 */
				if(i_stack < RENDER_PAINT_STACK_SIZE) {
					stack[i_stack][0] = x - 1; /* 一つ行き過ぎているので戻す */
					stack[i_stack][1] = y;
					i_stack++;
				}
			}
		}

		/* 下のラインの調査。 */
		if(y0 != render->bottom - 1) {
			y = y0 + 1;
			x = x1;
			for(;;) {
				/* 塗られる色の始まりを探します。 */
				for(;;) {
					if(x > x2) break;
					ofs = surface->w * y + x;
					if(surface->vbuff[ofs] == c) break;
					x++;
				}
				if(x > x2) break; /* もうない */

				/* 塗られる色の終わりを探します。 */
				for(;;) {
					if(x > x2) break;
					ofs = surface->w * y + x;
					if(surface->vbuff[ofs] != c) break;
					x++;
				}

				/* 塗られる色の終わりの位置をスタックに積みます。 */
				if(i_stack < RENDER_PAINT_STACK_SIZE) {
					stack[i_stack][0] = x - 1; /* 一つ行き過ぎているので戻す */
					stack[i_stack][1] = y;
					i_stack++;
				}
			}
		}
	}

	return cnt;

#undef RENDER_PAINT_STACK_SIZE
}

void
render_line(RENDER* render, int x0, int y0, int x1, int y1, int color)
{
	/* 一方向クリッピング用マクロ。 */
#define CLIP(X, Y, A, B, OP, LIM) \
	if(!((X##A) OP (LIM))) { \
		if(!((X##B) OP (LIM))) { \
			return; \
		} else { \
			(Y##A) = (Y##A) + \
			((Y##B) - (Y##A)) * ((LIM) - (X##A)) / ((X##B) - (X##A)); \
			(X##A) = (LIM); \
			clipped |= (A); /* (x1,y1)側をクリップしたらclipped=1 */ \
		} \
	}

	SURFACE* surface;
	unsigned char* vptr;
	int nx, ny;
	int ux, uy;
	int d, n;
	int tmp, ofs;
	/* 終点側のクリッピングフラグ。
	 * 初期値は0で、(x1,y1)側がクリップされると1になります。
	 * (x0,y0)側がクリップされたかどうかには影響されません。
	 * 線は常に、(x0,y0)から(x1,y1)に向かって描かれます。
	 * 連続線を想定しているので、通常、終点は描きませんが、
	 * (x1,y1)側がクリップされた場合のみ、終点も描きます。
	 */
	int clipped = 0;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 各頂点を、左右上下でクリップします。 */
	CLIP(x, y, 0, 1, >=, render->left);
	CLIP(x, y, 0, 1, <=, render->right - 1);
	CLIP(x, y, 1, 0, >=, render->left);
	CLIP(x, y, 1, 0, <=, render->right - 1);
	CLIP(y, x, 0, 1, >=, render->top);
	CLIP(y, x, 0, 1, <=, render->bottom - 1);
	CLIP(y, x, 1, 0, >=, render->top);
	CLIP(y, x, 1, 0, <=, render->bottom - 1);

	/* 始点アドレスを求めます。 */
	ofs = surface->w * y0 + x0;
	vptr = surface->vbuff + ofs;

	/* X軸のDDAパラメタを計算します。 */
	if(x1 >= x0) {
		nx = x1 - x0;
		ux =  1;
	} else {
		nx = x0 - x1;
		ux = -1;
	}

	/* Y軸のDDAパラメタを計算します。 */
	if(y1 >= y0) {
		ny = y1 - y0;
		uy =  surface->w;
	} else {
		ny = y0 - y1;
		uy = -surface->w;
	}

	/* 長い方を主軸(X)、もう一方を副軸(Y)とします。 */
	if(nx < ny) {
		tmp = x0; x0 = y0; y0 = tmp;
		tmp = x1; x1 = y1; y1 = tmp;
		tmp = nx; nx = ny; ny = tmp;
		tmp = ux; ux = uy; uy = tmp;
	}
	if(nx == 0) return; /* 点なら描きません。 */

	/* DDAループ。 */
	d = -nx;
	n = nx + clipped; /* 終点側がクリップされたら、終点も描く。 */
	do {
		*vptr = color;
		vptr += ux;
		d += ny * 2;
		if(d >= 0) {
			vptr += uy;
			d -= nx * 2;
		}
	} while(--n); /* 終点は描かないので、プリデクリメントです。   */
		      /* 終点側がクリップされたら、終点も描きますが、 */
		      /* その場合は、ループ前に予め+1されているので、 */
		      /* いずれにせよここではプリデクリメントです。   */

#undef CLIP
}

/* render_line()をベースに、破線パターンの取り出しだけ追加しました。
 * render_line()を変更・修正したときは、render_dashes()も追従してください。
 */
int
render_dashes(RENDER* render, int x0, int y0, int x1, int y1, unsigned i_pat, const unsigned char* pat, unsigned n_pat)
{
	/* 一方向クリッピング用マクロ。 */
#define CLIP(X, Y, A, B, OP, LIM) \
	if(!((X##A) OP (LIM))) { \
		if(!((X##B) OP (LIM))) { \
			return i_pat; \
		} else { \
			(Y##A) = (Y##A) + \
			((Y##B) - (Y##A)) * ((LIM) - (X##A)) / ((X##B) - (X##A)); \
			(X##A) = (LIM); \
			clipped |= (A); /* (x1,y1)側をクリップしたらclipped=1 */ \
		} \
	}

	SURFACE* surface;
	unsigned char *vptr, color;
	int nx, ny;
	int ux, uy;
	int d, n;
	int tmp, ofs;
	/* 終点側のクリッピングフラグ。
	 * 初期値は0で、(x1,y1)側がクリップされると1になります。
	 * (x0,y0)側がクリップされたかどうかには影響されません。
	 * 線は常に、(x0,y0)から(x1,y1)に向かって描かれます。
	 * 連続線を想定しているので、通常、終点は描きませんが、
	 * (x1,y1)側がクリップされた場合のみ、終点も描きます。
	 */
	int clipped = 0;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 各頂点を、左右上下でクリップします。 */
	CLIP(x, y, 0, 1, >=, render->left);
	CLIP(x, y, 0, 1, <=, render->right - 1);
	CLIP(x, y, 1, 0, >=, render->left);
	CLIP(x, y, 1, 0, <=, render->right - 1);
	CLIP(y, x, 0, 1, >=, render->top);
	CLIP(y, x, 0, 1, <=, render->bottom - 1);
	CLIP(y, x, 1, 0, >=, render->top);
	CLIP(y, x, 1, 0, <=, render->bottom - 1);

	/* 始点アドレスを求めます。 */
	ofs = surface->w * y0 + x0;
	vptr = surface->vbuff + ofs;

	/* X軸のDDAパラメタを計算します。 */
	if(x1 >= x0) {
		nx = x1 - x0;
		ux =  1;
	} else {
		nx = x0 - x1;
		ux = -1;
	}

	/* Y軸のDDAパラメタを計算します。 */
	if(y1 >= y0) {
		ny = y1 - y0;
		uy =  surface->w;
	} else {
		ny = y0 - y1;
		uy = -surface->w;
	}

	/* 長い方を主軸(X)、もう一方を副軸(Y)とします。 */
	if(nx < ny) {
		tmp = x0; x0 = y0; y0 = tmp;
		tmp = x1; x1 = y1; y1 = tmp;
		tmp = nx; nx = ny; ny = tmp;
		tmp = ux; ux = uy; uy = tmp;
	}
	if(nx == 0) return i_pat; /* 点なら描きません。 */

	/* 最初のパターンインデクスを確実に有効範囲内にします。 */
	i_pat %= n_pat;

	/* DDAループ。 */
	d = -nx;
	n = nx + clipped; /* 終点側がクリップされたら、終点も描く。 */
	do {
		color = pat[i_pat++];
		if(i_pat == n_pat) i_pat = 0;
		if(color < 4) *vptr = color;
		vptr += ux;
		d += ny * 2;
		if(d >= 0) {
			vptr += uy;
			d -= nx * 2;
		}
	} while(--n); /* 終点は描かないので、プリデクリメントです。   */
		      /* 終点側がクリップされたら、終点も描きますが、 */
		      /* その場合は、ループ前に予め+1されているので、 */
		      /* いずれにせよここではプリデクリメントです。   */

	return i_pat;

#undef CLIP
}

void
render_rectangle(RENDER* render, int x, int y, int w, int h, int color)
{
	int x0, y0, x1, y1;

	/* サイズが0x0なら何もしません。 */
	if(w == 0 || h == 0) return;

	/* 正規化します。(左上〜右下の形) */
	if(w < 0) { x += w; w = -w; }
	if(h < 0) { y += h; h = -h; }

	/* 点の場合のみ、render_line()では描けないので、別処理です。 */
	if(w == 1 && h == 1) {
		render_point(render, x, y, color);
		return;
	}

	/* 矩形を描きます。
	 * * 現在の実装は簡単のためにrender_line()を使っていますが、
	 *   水平線・垂直線しか描かないので、もっと高速化可能です。
	 */
	x0 = x;
	y0 = y;
	x1 = x + w - 1;
	y1 = y + h - 1;
	render_line(render, x0, y0, x1, y0, color); /* 左上〜右上 */
	render_line(render, x1, y0, x1, y1, color); /* 右上〜右下 */
	render_line(render, x1, y1, x0, y1, color); /* 右下〜左下 */
	render_line(render, x0, y1, x0, y0, color); /* 左下〜左上 */
}

void
render_rectangle_fill(RENDER* render, int x, int y, int w, int h, int color)
{
	SURFACE* surface;
	unsigned char* p;
	int i, n;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 正規化します。(左上〜右下の形) */
	if(w < 0) { x += w; w = -w; }
	if(h < 0) { y += h; h = -h; }

	/* クリッピングします。 */
	if(x < render->left) {
		n = render->left - x; /* 左にはみ出たピクセル数 */
		x = render->left;
		w -= n;
	}
	if(x + w > render->right) {
		w = render->right - x;
	}
	if(w <= 0) return; /* 画面外 */
	if(y < render->top) {
		n = render->top - y; /* 上にはみ出たピクセル数 */
		y = render->top;
		h -= n;
	}
	if(y + h > render->bottom) {
		h = render->bottom - y;
	}
	if(h <= 0) return; /* 画面外 */

	/* 塗りつぶします。 */
	for(i = 0, p = &surface->vbuff[surface->w * y + x]; i < h; i++, p += surface->w) {
		memset(p, color, w);
	}
}

/* * ポリゴン描画は全て整数で処理できますが、現在の実装ではそうなっていません。
 *   メッシュ描画のコードを流用したため、クリッピングに浮動小数を使っています。
 *   この部分を独自の整数処理に書き直せば、大幅に高速化できるはずです。(※TODO)
 * * と思いましたが、クリッピングの改良だけでは、3%程度しか速くならないようです。
 *   ポリゴン描画ではＺコンペアが不要なので、これを省略すると25%程度速くなります。
 *   高速化のために、Ｚコンペア無しのスキャンライン描画を追加するのが良さそうです。
 * * ->やってみました。
 */
void
render_polygon(RENDER* render, const VERTEX* vertices, int n_vertices, int color)
{
	int i;
	const VERTEX* vertex;
	CLIPVERTEX *clip_vertex;
	RENDVERTEX *rend_vertex;

	/* スキャンライン描画コードを選択します。 */
	select_draw_scanline_woz(render);

	/* 前景色・背景色を格納します。 */
	render_work->fore_color = color >> 4 & 15;
	render_work->back_color = color      & 15;

	/* クリッピング用頂点リストを組み立てます。 */
	if(n_vertices > N_VERTICES_MAX) n_vertices = N_VERTICES_MAX;
	for(i = 0, vertex = vertices, clip_vertex = render_work->clip_vertices[0];
	    i < n_vertices;
	    i++, vertex++, clip_vertex++) {
		clip_vertex->x = vertex->x;
		clip_vertex->y = vertex->y;
		clip_vertex->z = render->front; /* 平面クリッピングのためのダミー。0以外なら何でもOKです。 */
		clip_vertex->s = (unsigned short)(vertex->s * 0x100 + 0x80); /* +0x80で、テクセルの中心をポイント */
		clip_vertex->t = (unsigned short)(vertex->t * 0x100 + 0x80); /* +0x80で、テクセルの中心をポイント */
	}
	if(n_vertices < 3) return;

	/* 平面クリッピングを行います。 */
	n_vertices = clip_xy(render, n_vertices);
	if(n_vertices < 3) return;

	/* 描画用頂点リストを組み立てます。 */
	for(i = 0, clip_vertex = render_work->clip_vertices[0], rend_vertex = render_work->rend_vertices;
	    i < n_vertices;
	    i++, clip_vertex++, rend_vertex++) {
		rend_vertex->x = (unsigned short)clip_vertex->x;
		rend_vertex->y = (unsigned short)clip_vertex->y;
		/* draw_primitive_woz()はrend_vertex->zを使わないので、不定値のままで大丈夫です。 */
		rend_vertex->s = clip_vertex->s; /* クリッピング前に既に8.8bit固定小数に変換済み。 */
		rend_vertex->t = clip_vertex->t; /* クリッピング前に既に8.8bit固定小数に変換済み。 */
	}

	/* プリミティブを描きます。 */
	draw_primitive_woz(render, n_vertices);
}

void
render_mesh(RENDER* render, const MESH* mesh)
{
	int i, j, n_vectors, n_tcoords, n_faces, n_face_vertices, n_vertices;
	float s, xN0, yN0, x01, y01;
	VECTOR *vectors, *vector, *vector_src, *vector_dst;
	TCOORD *tcoords, *tcoord;
	FACE *face;
	FACEVERTEX *face_vertices, *face_vertex;
	CLIPVERTEX *clip_vertex;
	RENDVERTEX *rend_vertex;

	/* スキャンライン描画コードを選択します。 */
	select_draw_scanline_wz(render);

	/* リストの先頭アドレスを計算します。 */
	n_vectors = mesh->nv;
	n_tcoords = mesh->nc;
	n_faces = mesh->nf;
	vectors = (VECTOR*)(mesh + 1);
	tcoords = (TCOORD*)(vectors + n_vectors);
	face = (FACE*)(tcoords + n_tcoords);

	/* 全頂点座標を変換します。 */
	for(i = 0, vector_src = vectors, vector_dst = render_work->xformed_vectors;
	    i < n_vectors;
	    i++, vector_src++, vector_dst++) {
		vector_xform(vector_dst, &render->context->matrix, vector_src);
	}

	/* 各フェイスを描きます。 */
	for(i = 0;
	    i < n_faces;
	    i++, face = (FACE*)(face_vertices + n_face_vertices)) {
		n_face_vertices = face->nfv;
		render_work->fore_color = face->c >> 4 & 15;
		render_work->back_color = face->c      & 15;
		face_vertices = (FACEVERTEX*)(face + 1);

		/* クリッピング用頂点リストを組み立てます。
		 * * テクスチャ無しの場合分けを行っていませんが、動作に問題ないはずです。
		 *   テクスチャ無しならmesh->nc=0なので、tcoordsは最初のフェイスを指しています。
		 *   各フェイス頂点のface_vertex->ic=0なので、テクスチャ座標として最初のフェイスのm,nを取得します。
		 *   mesh->nf=0の場合のみ最初のフェイスが存在しませんが、その場合はこのループ自体が回りません。
		 *   取得したテクスチャ座標は描画時に無視されるので、テクスチャ座標値は関係ありません。
		 *   上記の通り、テクスチャ座標取得時に不正なメモリ領域にアクセスしないことが保証されます。
		 *   従って、テクスチャ無しの場合分けを行わなくても、動作に問題はないと思います。
		 */
		n_vertices = 0;
		for(j = 0, face_vertex = face_vertices, clip_vertex = render_work->clip_vertices[0];
		    j < n_face_vertices;
		    j++, face_vertex++, clip_vertex++) {
			vector = &render_work->xformed_vectors[face_vertex->iv];
			tcoord = &tcoords[face_vertex->ic];
			clip_vertex->x = vector->x;
			clip_vertex->y = vector->y;
			clip_vertex->z = vector->z;
			clip_vertex->s = (unsigned short)(tcoord->s * 0x100 + 0x80); /* +0x80で、テクセルの中心をポイント */
			clip_vertex->t = (unsigned short)(tcoord->t * 0x100 + 0x80); /* +0x80で、テクセルの中心をポイント */
			if(++n_vertices == N_VERTICES_MAX) break;
		}
		if(n_vertices < 3) continue;

		/* Ｚクリッピングを行います。 */
		n_vertices = clip_z(render, n_vertices);
		if(n_vertices < 3) continue;

		/* 透視変換のための x=x/z,y=y/z を行います。 */
		for(j = 0, clip_vertex = render_work->clip_vertices[0];
		    j < n_vertices;
		    j++, clip_vertex++) {
			clip_vertex->x /= clip_vertex->z;
			clip_vertex->y /= clip_vertex->z;
		}

		/* 表裏判定を行います。
		 * 右回り(=表)記述なので、左回り(=裏)なら描きません。
		 */
		xN0 = render_work->clip_vertices[0][0].x - render_work->clip_vertices[0][n_vertices - 1].x;
		yN0 = render_work->clip_vertices[0][0].y - render_work->clip_vertices[0][n_vertices - 1].y;
		x01 = render_work->clip_vertices[0][1].x - render_work->clip_vertices[0][             0].x;
		y01 = render_work->clip_vertices[0][1].y - render_work->clip_vertices[0][             0].y;
		s = xN0 * y01 - x01 * yN0;
		if(s <= 0) continue;

		/* 平面クリッピングを行います。 */
		n_vertices = clip_xy(render, n_vertices);
		if(n_vertices < 3) continue;

		/* 描画用頂点リストを組み立てます。 */
		for(j = 0, clip_vertex = render_work->clip_vertices[0], rend_vertex = render_work->rend_vertices;
		    j < n_vertices;
		    j++, clip_vertex++, rend_vertex++) {
			rend_vertex->x = (unsigned short)clip_vertex->x;
			rend_vertex->y = (unsigned short)clip_vertex->y;
			rend_vertex->z = (unsigned short)((clip_vertex->z - render->front) * render->back   /
							  (render->back   - render->front) / clip_vertex->z * 0xFFFF);
			rend_vertex->s = clip_vertex->s; /* クリッピング前に既に8.8bit固定小数に変換済み。 */
			rend_vertex->t = clip_vertex->t; /* クリッピング前に既に8.8bit固定小数に変換済み。 */
		}

		/* プリミティブを描きます。 */
		draw_primitive_wz(render, n_vertices);
	}
}

/* Ｚクリッピングを行います。
 * [in]
 *	render				レンダラーへのポインタ。
 *	nsrc				クリッピングする頂点の数。
 *	render_work->clip_vertices[0]	クリッピングする頂点リスト。(グローバル変数)
 * [out]
 *	戻り値				クリッピング後の頂点の数。
 *	render_work->clip_vertices[0]	クリッピング後の頂点リスト。(グローバル変数)
 * [note]
 *	* 作業領域として、render_work->clip_vertices[1]も使います。
 */
static int
clip_z(RENDER* render, int nsrc)
{
#define CLIP(SRC, DST, OP, LIM) \
	src = SRC; \
	dst = DST; \
	ndst = 0; \
	lim = LIM; \
	for(i = 0; i < nsrc; i++) { \
		v0 = src +  i; \
		v1 = src + (i + 1) % nsrc; \
		if(v0->z OP lim) { \
			*dst = *v0; \
			dst++; \
			ndst++; \
			if(ndst == N_VERTICES_MAX) break; \
			if(v1->z OP lim) { \
				continue; \
			} else { \
				/* go clip */ \
			} \
		} else { \
			if(v1->z OP lim) { \
				/* go clip */ \
			} else { \
				continue; \
			} \
		} \
		/* do clip */ \
		dst->z = lim; \
		n0 = lim - v0->z; \
		n1 = v1->z - lim; \
		n01 = n0 + n1; \
		dst->x = v0->x + (v1->x - v0->x) * n0 / n01; \
		dst->y = v0->y + (v1->y - v0->y) * n0 / n01; \
		dst->s = v0->s + (v1->s - v0->s) * n0 / n01; \
		dst->t = v0->t + (v1->t - v0->t) * n0 / n01; \
		dst++; \
		ndst++; \
		if(ndst == N_VERTICES_MAX) break; \
	} \
	if(ndst < 3) return 0; \

	CLIPVERTEX *src, *dst;
	CLIPVERTEX *v0, *v1;
	float lim, n0, n1, n01;
	int i, ndst;

	CLIP(render_work->clip_vertices[0], render_work->clip_vertices[1], >=, render->front); nsrc = ndst;
	CLIP(render_work->clip_vertices[1], render_work->clip_vertices[0], <=, render->back );
	return ndst;

#undef CLIP
}

/* 平面クリッピングを行います。
 * [in]
 *	render				レンダラーへのポインタ。
 *	nsrc				クリッピングする頂点の数。
 *	render_work->clip_vertices[0]	クリッピングする頂点リスト。(グローバル変数)
 * [out]
 *	戻り値				クリッピング後の頂点の数。
 *	render_work->clip_vertices[0]	クリッピング後の頂点リスト。(グローバル変数)
 * [note]
 *	* 作業領域として、render_work->clip_vertices[1]も使います。
 */
static int
clip_xy(RENDER* render, int nsrc)
{
#define CLIP(SRC, DST, X, Y, OP, LIM) \
	src = SRC; \
	dst = DST; \
	ndst = 0; \
	lim = LIM; \
	for(i = 0; i < nsrc; i++) { \
		v0 = src +  i; \
		v1 = src + (i + 1) % nsrc; \
		if(v0->X OP lim) { \
			*dst = *v0; \
			dst++; \
			ndst++; \
			if(ndst == N_VERTICES_MAX) break; \
			if(v1->X OP lim) { \
				continue; \
			} else { \
				/* go clip */ \
			} \
		} else { \
			if(v1->X OP lim) { \
				/* go clip */ \
			} else { \
				continue; \
			} \
		} \
		/* do clip */ \
		dst->X = lim; \
		n0 = lim - v0->X; \
		n1 = v1->X - lim; \
		n01 = n0 + n1; \
		dst->Y = v0->Y + (v1->Y - v0->Y) * n0 / n01; \
		n0 *= v0->z; \
		n1 *= v1->z; \
		n01 = n0 + n1; \
		dst->z = v0->z + (v1->z - v0->z) * n0 / n01; \
		dst->s = v0->s + (v1->s - v0->s) * n0 / n01; \
		dst->t = v0->t + (v1->t - v0->t) * n0 / n01; \
		dst++; \
		ndst++; \
		if(ndst == N_VERTICES_MAX) break; \
	} \
	if(ndst < 3) return 0; \

	CLIPVERTEX *src, *dst;
	CLIPVERTEX *v0, *v1;
	float lim, n0, n1, n01;
	int i, ndst;

	CLIP(render_work->clip_vertices[0], render_work->clip_vertices[1], x, y, >=, render->left  ); nsrc = ndst;
	CLIP(render_work->clip_vertices[1], render_work->clip_vertices[0], x, y, <=, render->right ); nsrc = ndst;
	CLIP(render_work->clip_vertices[0], render_work->clip_vertices[1], y, x, >=, render->top   ); nsrc = ndst;
	CLIP(render_work->clip_vertices[1], render_work->clip_vertices[0], y, x, <=, render->bottom);
	return ndst;

#undef CLIP
}

/****************************************************************************
 *	Ｚコンペアあり
 ****************************************************************************/

/* スキャンライン描画関数を選択します。
 * [in]
 *	render				レンダラーへのポインタ。
 * [out]
 *	render_work->draw_scanline	スキャンライン描画関数へのポインタ。(グローバル変数)
 */
static void
select_draw_scanline_wz(RENDER* render)
{
	TEXTURE* texture;

	texture = render->context->texture;
	if(texture == NULL) {
		render_work->draw_scanline = draw_scanline_wz_color;
	} else {
		if(!texture->header.mask) {
			switch(texture->header.bpp) {
			case 1:
				render_work->draw_scanline = draw_scanline_wz_1bit;
				break;
			default/*2*/:
				render_work->draw_scanline = draw_scanline_wz_2bit;
				break;
			}
		} else {
			switch(texture->header.bpp) {
			case 1:
				render_work->draw_scanline = draw_scanline_wz_1bitmask;
				break;
			default/*2*/:
				render_work->draw_scanline = draw_scanline_wz_2bitmask;
				break;
			}
		}
	}
}

/* プリミティブを描きます。
 * [in]
 *	render				レンダラーへのポインタ。
 *	n_vertices			頂点の数。
 *	render_work->rend_vertices	頂点リスト。(グローバル変数)
 */
static void
draw_primitive_wz(RENDER* render, int n_vertices)
{
	/* DDAセットアップ用マクロ。 */
#define SETUP(i) \
	side->cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		side->i.n = (v1->i - v0->i) % side->ny; \
		side->i.d = -side->ny; \
		side->i.u =  (v1->i - v0->i) / side->ny; \
		side->i.v =  1; \
	} else { \
		side->i.n = (v0->i - v1->i) % side->ny; \
		side->i.d = -side->ny; \
		side->i.u = -(v0->i - v1->i) / side->ny; \
		side->i.v = -1; \
	}

	/* DDAステップ実行用マクロ。 */
#define STEP(i) \
	side->cur.i += side->i.u; \
	side->i.d += side->i.n * 2; \
	if(side->i.d >= 0) { \
		side->cur.i += side->i.v; \
		side->i.d -= side->ny * 2; \
	}

	struct {
		int iv;		/* 現在の辺の終点インデクス            */
		int ny;		/* 現在の辺の高さの変位                */
		int n;		/* 現在の辺の残りライン数              */
		RENDVERTEX cur;	/* 現在値                              */
		DDA x, z;	/* 頂点座標DDA(yは左右共通で1づつ進む) */
		DDA s, t;	/* テクスチャ座標DDA                   */
	} sides[2], *side;

	int i, itop, y, top, bottom;
	RENDVERTEX *v, *v0, *v1;

	/* 上下端の位置と、上端の頂点を求めます。 */
	itop = 0;
	top = bottom = render_work->rend_vertices[0].y;
	for(i = 1; i < n_vertices; i++) {
		v = &render_work->rend_vertices[i];
		if(v->y < top) {
			itop = i;
			top = v->y;
		}
		if(v->y > bottom) {
			bottom = v->y;
		}
	}
	if(top == bottom) return; /* 水平ポリゴンは描きません。 */

	/* 左右の辺を初期化します。 */
	for(i = 0; i < 2; i++) {
		side = &sides[i];
		side->iv = itop;
		side->n = 0; /* 初回に本当の初期化を行うように */
	}

	/* 下端を除く、各スキャンラインについて... */
	for(y = top; y < bottom; y++) {
		/* 左右の辺について... */
		for(i = 0; i < 2; i++) {
			side = &sides[i];
			/* 次の辺に達したら... */
			if(side->n == 0) {
				do {
					/* 次の辺の両端の頂点を求めます。 */
					v0 = &render_work->rend_vertices[side->iv];
					if(i == 0) {
						side->iv--;
						if(side->iv == -1) {
							side->iv = n_vertices - 1;
						}
					} else {
						side->iv++;
						if(side->iv == n_vertices) {
							side->iv = 0;
						}
					}
					v1 = &render_work->rend_vertices[side->iv];
					/* この辺の高さの変位を求めます。 */
					side->ny = v1->y - v0->y;
					/* V字ポリゴンを検出したら、残りの描画はキャンセルします。 */
					if(side->ny < 0) return;
				} while(side->ny == 0); /* 水平な辺は無視します。 */
				/* DDAセットアップ。 */
				SETUP(x);
				SETUP(z);
				SETUP(s);
				SETUP(t);
				/* 次の辺までのカウンタを初期化。 */
				side->n = side->ny;
			}
		}
		/* 左右の辺の間に、水平線を描きます。 */
		sides[0].cur.y = sides[1].cur.y = y;
		render_work->draw_scanline(render, &sides[0].cur, &sides[1].cur);
		/* 左右の辺について... */
		for(i = 0; i < 2; i++) {
			side = &sides[i];
			/* 次の辺までのライン数を減らします。 */
			side->n--;
			/* DDAステップ実行。 */
			STEP(x)
			STEP(z)
			STEP(s)
			STEP(t)
		}
	}
	/* 下端のスキャンラインは描きません。 */

#undef SETUP
#undef STEP
}

static void
draw_scanline_wz_color(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1)
{
	/* DDAセットアップ用マクロ。 */
#define SETUP(i) \
	cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		i.n = (v1->i - v0->i) % nx; \
		i.d = -nx; \
		i.u =  (v1->i - v0->i) / nx; \
		i.v =  1; \
	} else { \
		i.n = (v0->i - v1->i) % nx; \
		i.d = -nx; \
		i.u = -(v0->i - v1->i) / nx; \
		i.v = -1; \
	}

	/* DDAステップ実行用マクロ。 */
#define STEP(i) \
	cur.i += i.u; \
	i.d += i.n * 2; \
	if(i.d >= 0) { \
		cur.i += i.v; \
		i.d -= nx * 2; \
	}

	SURFACE* surface;	/* サーフェイス               */
	unsigned char* vptr;	/* カラーバッファポインタ     */
	unsigned char* zptr;	/* Ｚバッファポインタ         */
	int nx;			/* 現在のスキャンラインの長さ */
	int n;			/* 現在の辺の残りピクセル数   */
	RENDVERTEX cur;		/* 現在値                     */
	DDA z;			/* Ｚ値DDA                    */
	const RENDVERTEX* tmp;
	int ofs;
	unsigned char zval;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 確実に 左:v0 -> v1:右 とします。 */
	if(v0->x > v1->x) {
		tmp = v0;
		      v0 = v1;
		           v1 = tmp;
	}

	/* 始点アドレスを求めます。 */
	ofs = surface->w * v0->y + v0->x;
	vptr = surface->vbuff + ofs;
	zptr = surface->zbuff + ofs;

	/* 主軸のDDAセットアップ。 */
	nx = v1->x - v0->x;
	if(nx == 0) return; /* 点なら描きません。 */

	/* 副軸のDDAセットアップ。 */
	SETUP(z);

	/* DDAループ。 */
	n = nx;
	do {
		/* Ｚ比較。 */
		zval = (unsigned char)(cur.z >> 8);
		if(zval <= *zptr) {
			/* テクスチャ無しなら、フェイスの背景色で描きます。 */
			*vptr = render_work->back_color;
			*zptr = zval;
		}
		/* バッファポインタを進めます。 */
		vptr++;
		zptr++;
		/* DDAステップ実行。 */
		STEP(z);
	} while(--n); /* 右端ピクセルは描かないので、プリデクリメントです。 */

#undef SETUP
#undef STEP
}

static void
draw_scanline_wz_1bit(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1)
{
	/* DDAセットアップ用マクロ。 */
#define SETUP(i) \
	cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		i.n = (v1->i - v0->i) % nx; \
		i.d = -nx; \
		i.u =  (v1->i - v0->i) / nx; \
		i.v =  1; \
	} else { \
		i.n = (v0->i - v1->i) % nx; \
		i.d = -nx; \
		i.u = -(v0->i - v1->i) / nx; \
		i.v = -1; \
	}

	/* DDAステップ実行用マクロ。 */
#define STEP(i) \
	cur.i += i.u; \
	i.d += i.n * 2; \
	if(i.d >= 0) { \
		cur.i += i.v; \
		i.d -= nx * 2; \
	}

	SURFACE* surface;	/* サーフェイス               */
	TEXTURE* texture;	/* テクスチャ                 */
	unsigned char* vptr;	/* カラーバッファポインタ     */
	unsigned char* zptr;	/* Ｚバッファポインタ         */
	int nx;			/* 現在のスキャンラインの長さ */
	int n;			/* 現在の辺の残りピクセル数   */
	RENDVERTEX cur;		/* 現在値                     */
	DDA z;			/* Ｚ値DDA                    */
	DDA s, t;		/* テクスチャ座標DDA          */
	const RENDVERTEX* tmp;
	int ofs;
	unsigned char zval;
	unsigned char sval, tval;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 確実に 左:v0 -> v1:右 とします。 */
	if(v0->x > v1->x) {
		tmp = v0;
		      v0 = v1;
		           v1 = tmp;
	}

	/* 始点アドレスを求めます。 */
	ofs = surface->w * v0->y + v0->x;
	vptr = surface->vbuff + ofs;
	zptr = surface->zbuff + ofs;

	/* 主軸のDDAセットアップ。 */
	nx = v1->x - v0->x;
	if(nx == 0) return; /* 点なら描きません。 */

	/* 副軸のDDAセットアップ。 */
	SETUP(z);
	SETUP(s);
	SETUP(t);

	/* テクスチャを取り出しておきます。 */
	texture = render->context->texture;

	/* DDAループ。 */
	n = nx;
	do {
		/* Ｚ比較。 */
		zval = (unsigned char)(cur.z >> 8);
		if(zval <= *zptr) {
			/* P/ECEは除算が遅いので、除算の要・不要を判定してから除算を行ったほうがまだマシです。
			 * テクスチャ座標がWrapしない場合のスキャンライン描画コードを展開すれば、さらに高速化できますが、
			 * コードサイズ増加との兼ね合いで、このあたりで妥協しました。
			 * 速度比較の参考数値: 常に除算(100%)->判定して除算(150%高速化)->コード展開(110%高速化)
			 */
			sval = (unsigned char)(cur.s >> 8); if(sval >= texture->header.w) sval %= texture->header.w;
			tval = (unsigned char)(cur.t >> 8); if(tval >= texture->header.h) tval %= texture->header.h;
			ofs = texture->header.w * tval + sval;
			/* 1bitテクスチャなら、テクセル値によって 1:フェイスの前景色/0:フェイスの背景色 で描きます。 */
			*vptr = texture->buf[ofs / 8] >> (7 - (ofs & 7)) & 1 ? render_work->fore_color : render_work->back_color;
			*zptr = zval;
		}
		/* バッファポインタを進めます。 */
		vptr++;
		zptr++;
		/* DDAステップ実行。 */
		STEP(z);
		STEP(s);
		STEP(t);
	} while(--n); /* 右端ピクセルは描かないので、プリデクリメントです。 */

#undef SETUP
#undef STEP
}

static void
draw_scanline_wz_1bitmask(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1)
{
	/* DDAセットアップ用マクロ。 */
#define SETUP(i) \
	cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		i.n = (v1->i - v0->i) % nx; \
		i.d = -nx; \
		i.u =  (v1->i - v0->i) / nx; \
		i.v =  1; \
	} else { \
		i.n = (v0->i - v1->i) % nx; \
		i.d = -nx; \
		i.u = -(v0->i - v1->i) / nx; \
		i.v = -1; \
	}

	/* DDAステップ実行用マクロ。 */
#define STEP(i) \
	cur.i += i.u; \
	i.d += i.n * 2; \
	if(i.d >= 0) { \
		cur.i += i.v; \
		i.d -= nx * 2; \
	}

	SURFACE* surface;	/* サーフェイス               */
	TEXTURE* texture;	/* テクスチャ                 */
	unsigned char* vptr;	/* カラーバッファポインタ     */
	unsigned char* zptr;	/* Ｚバッファポインタ         */
	int nx;			/* 現在のスキャンラインの長さ */
	int n;			/* 現在の辺の残りピクセル数   */
	RENDVERTEX cur;		/* 現在値                     */
	DDA z;			/* Ｚ値DDA                    */
	DDA s, t;		/* テクスチャ座標DDA          */
	const RENDVERTEX* tmp;
	int ofs;
	unsigned char zval;
	unsigned char sval, tval;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 確実に 左:v0 -> v1:右 とします。 */
	if(v0->x > v1->x) {
		tmp = v0;
		      v0 = v1;
		           v1 = tmp;
	}

	/* 始点アドレスを求めます。 */
	ofs = surface->w * v0->y + v0->x;
	vptr = surface->vbuff + ofs;
	zptr = surface->zbuff + ofs;

	/* 主軸のDDAセットアップ。 */
	nx = v1->x - v0->x;
	if(nx == 0) return; /* 点なら描きません。 */

	/* 副軸のDDAセットアップ。 */
	SETUP(z);
	SETUP(s);
	SETUP(t);

	/* テクスチャを取り出しておきます。 */
	texture = render->context->texture;

	/* DDAループ。 */
	n = nx;
	do {
		/* Ｚ比較。 */
		zval = (unsigned char)(cur.z >> 8);
		if(zval <= *zptr) {
			/* P/ECEは除算が遅いので、除算の要・不要を判定してから除算を行ったほうがまだマシです。
			 * テクスチャ座標がWrapしない場合のスキャンライン描画コードを展開すれば、さらに高速化できますが、
			 * コードサイズ増加との兼ね合いで、このあたりで妥協しました。
			 * 速度比較の参考数値: 常に除算(100%)->判定して除算(150%高速化)->コード展開(110%高速化)
			 */
			sval = (unsigned char)(cur.s >> 8); if(sval >= texture->header.w) sval %= texture->header.w;
			tval = (unsigned char)(cur.t >> 8); if(tval >= texture->header.h) tval %= texture->header.h;
			ofs = texture->header.w * tval + sval;
			if(texture->mask[ofs / 8] >> (7 - (ofs & 7)) & 1) {
				/* 1bitテクスチャなら、テクセル値によって 1:フェイスの前景色/0:フェイスの背景色 で描きます。 */
				*vptr = texture->buf[ofs / 8] >> (7 - (ofs & 7)) & 1 ? render_work->fore_color : render_work->back_color;
				*zptr = zval;
			}
		}
		/* バッファポインタを進めます。 */
		vptr++;
		zptr++;
		/* DDAステップ実行。 */
		STEP(z);
		STEP(s);
		STEP(t);
	} while(--n); /* 右端ピクセルは描かないので、プリデクリメントです。 */

#undef SETUP
#undef STEP
}

static void
draw_scanline_wz_2bit(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1)
{
	/* DDAセットアップ用マクロ。 */
#define SETUP(i) \
	cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		i.n = (v1->i - v0->i) % nx; \
		i.d = -nx; \
		i.u =  (v1->i - v0->i) / nx; \
		i.v =  1; \
	} else { \
		i.n = (v0->i - v1->i) % nx; \
		i.d = -nx; \
		i.u = -(v0->i - v1->i) / nx; \
		i.v = -1; \
	}

	/* DDAステップ実行用マクロ。 */
#define STEP(i) \
	cur.i += i.u; \
	i.d += i.n * 2; \
	if(i.d >= 0) { \
		cur.i += i.v; \
		i.d -= nx * 2; \
	}

	SURFACE* surface;	/* サーフェイス               */
	TEXTURE* texture;	/* テクスチャ                 */
	unsigned char* vptr;	/* カラーバッファポインタ     */
	unsigned char* zptr;	/* Ｚバッファポインタ         */
	int nx;			/* 現在のスキャンラインの長さ */
	int n;			/* 現在の辺の残りピクセル数   */
	RENDVERTEX cur;		/* 現在値                     */
	DDA z;			/* Ｚ値DDA                    */
	DDA s, t;		/* テクスチャ座標DDA          */
	const RENDVERTEX* tmp;
	int ofs;
	unsigned char zval;
	unsigned char sval, tval;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 確実に 左:v0 -> v1:右 とします。 */
	if(v0->x > v1->x) {
		tmp = v0;
		      v0 = v1;
		           v1 = tmp;
	}

	/* 始点アドレスを求めます。 */
	ofs = surface->w * v0->y + v0->x;
	vptr = surface->vbuff + ofs;
	zptr = surface->zbuff + ofs;

	/* 主軸のDDAセットアップ。 */
	nx = v1->x - v0->x;
	if(nx == 0) return; /* 点なら描きません。 */

	/* 副軸のDDAセットアップ。 */
	SETUP(z);
	SETUP(s);
	SETUP(t);

	/* テクスチャを取り出しておきます。 */
	texture = render->context->texture;

	/* DDAループ。 */
	n = nx;
	do {
		/* Ｚ比較。 */
		zval = (unsigned char)(cur.z >> 8);
		if(zval <= *zptr) {
			/* P/ECEは除算が遅いので、除算の要・不要を判定してから除算を行ったほうがまだマシです。
			 * テクスチャ座標がWrapしない場合のスキャンライン描画コードを展開すれば、さらに高速化できますが、
			 * コードサイズ増加との兼ね合いで、このあたりで妥協しました。
			 * 速度比較の参考数値: 常に除算(100%)->判定して除算(150%高速化)->コード展開(110%高速化)
			 */
			sval = (unsigned char)(cur.s >> 8); if(sval >= texture->header.w) sval %= texture->header.w;
			tval = (unsigned char)(cur.t >> 8); if(tval >= texture->header.h) tval %= texture->header.h;
			ofs = texture->header.w * tval + sval;
			/* 2bitテクスチャなら、テクセル値をそのまま描きます。 */
			*vptr = texture->buf[ofs / 4] >> (3 - (ofs & 3)) * 2 & 3;
			*zptr = zval;
		}
		/* バッファポインタを進めます。 */
		vptr++;
		zptr++;
		/* DDAステップ実行。 */
		STEP(z);
		STEP(s);
		STEP(t);
	} while(--n); /* 右端ピクセルは描かないので、プリデクリメントです。 */

#undef SETUP
#undef STEP
}

static void
draw_scanline_wz_2bitmask(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1)
{
	/* DDAセットアップ用マクロ。 */
#define SETUP(i) \
	cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		i.n = (v1->i - v0->i) % nx; \
		i.d = -nx; \
		i.u =  (v1->i - v0->i) / nx; \
		i.v =  1; \
	} else { \
		i.n = (v0->i - v1->i) % nx; \
		i.d = -nx; \
		i.u = -(v0->i - v1->i) / nx; \
		i.v = -1; \
	}

	/* DDAステップ実行用マクロ。 */
#define STEP(i) \
	cur.i += i.u; \
	i.d += i.n * 2; \
	if(i.d >= 0) { \
		cur.i += i.v; \
		i.d -= nx * 2; \
	}

	SURFACE* surface;	/* サーフェイス               */
	TEXTURE* texture;	/* テクスチャ                 */
	unsigned char* vptr;	/* カラーバッファポインタ     */
	unsigned char* zptr;	/* Ｚバッファポインタ         */
	int nx;			/* 現在のスキャンラインの長さ */
	int n;			/* 現在の辺の残りピクセル数   */
	RENDVERTEX cur;		/* 現在値                     */
	DDA z;			/* Ｚ値DDA                    */
	DDA s, t;		/* テクスチャ座標DDA          */
	const RENDVERTEX* tmp;
	int ofs;
	unsigned char zval;
	unsigned char sval, tval;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 確実に 左:v0 -> v1:右 とします。 */
	if(v0->x > v1->x) {
		tmp = v0;
		      v0 = v1;
		           v1 = tmp;
	}

	/* 始点アドレスを求めます。 */
	ofs = surface->w * v0->y + v0->x;
	vptr = surface->vbuff + ofs;
	zptr = surface->zbuff + ofs;

	/* 主軸のDDAセットアップ。 */
	nx = v1->x - v0->x;
	if(nx == 0) return; /* 点なら描きません。 */

	/* 副軸のDDAセットアップ。 */
	SETUP(z);
	SETUP(s);
	SETUP(t);

	/* テクスチャを取り出しておきます。 */
	texture = render->context->texture;

	/* DDAループ。 */
	n = nx;
	do {
		/* Ｚ比較。 */
		zval = (unsigned char)(cur.z >> 8);
		if(zval <= *zptr) {
			/* P/ECEは除算が遅いので、除算の要・不要を判定してから除算を行ったほうがまだマシです。
			 * テクスチャ座標がWrapしない場合のスキャンライン描画コードを展開すれば、さらに高速化できますが、
			 * コードサイズ増加との兼ね合いで、このあたりで妥協しました。
			 * 速度比較の参考数値: 常に除算(100%)->判定して除算(150%高速化)->コード展開(110%高速化)
			 */
			sval = (unsigned char)(cur.s >> 8); if(sval >= texture->header.w) sval %= texture->header.w;
			tval = (unsigned char)(cur.t >> 8); if(tval >= texture->header.h) tval %= texture->header.h;
			ofs = texture->header.w * tval + sval;
			if(texture->mask[ofs / 8] >> (7 - (ofs & 7)) & 1) {
				/* 2bitテクスチャなら、テクセル値をそのまま描きます。 */
				*vptr = texture->buf[ofs / 4] >> (3 - (ofs & 3)) * 2 & 3;
				*zptr = zval;
			}
		}
		/* バッファポインタを進めます。 */
		vptr++;
		zptr++;
		/* DDAステップ実行。 */
		STEP(z);
		STEP(s);
		STEP(t);
	} while(--n); /* 右端ピクセルは描かないので、プリデクリメントです。 */

#undef SETUP
#undef STEP
}

/****************************************************************************
 *	Ｚコンペアなし
 ****************************************************************************/

/* スキャンライン描画関数を選択します。
 * [in]
 *	render				レンダラーへのポインタ。
 * [out]
 *	render_work->draw_scanline	スキャンライン描画関数へのポインタ。(グローバル変数)
 */
static void
select_draw_scanline_woz(RENDER* render)
{
	TEXTURE* texture;

	texture = render->context->texture;
	if(texture == NULL) {
		render_work->draw_scanline = draw_scanline_woz_color;
	} else {
		if(!texture->header.mask) {
			switch(texture->header.bpp) {
			case 1:
				render_work->draw_scanline = draw_scanline_woz_1bit;
				break;
			default/*2*/:
				render_work->draw_scanline = draw_scanline_woz_2bit;
				break;
			}
		} else {
			switch(texture->header.bpp) {
			case 1:
				render_work->draw_scanline = draw_scanline_woz_1bitmask;
				break;
			default/*2*/:
				render_work->draw_scanline = draw_scanline_woz_2bitmask;
				break;
			}
		}
	}
}

/* プリミティブを描きます。
 * [in]
 *	render				レンダラーへのポインタ。
 *	n_vertices			頂点の数。
 *	render_work->rend_vertices	頂点リスト。(グローバル変数)
 */
static void
draw_primitive_woz(RENDER* render, int n_vertices)
{
	/* DDAセットアップ用マクロ。 */
#define SETUP(i) \
	side->cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		side->i.n = (v1->i - v0->i) % side->ny; \
		side->i.d = -side->ny; \
		side->i.u =  (v1->i - v0->i) / side->ny; \
		side->i.v =  1; \
	} else { \
		side->i.n = (v0->i - v1->i) % side->ny; \
		side->i.d = -side->ny; \
		side->i.u = -(v0->i - v1->i) / side->ny; \
		side->i.v = -1; \
	}

	/* DDAステップ実行用マクロ。 */
#define STEP(i) \
	side->cur.i += side->i.u; \
	side->i.d += side->i.n * 2; \
	if(side->i.d >= 0) { \
		side->cur.i += side->i.v; \
		side->i.d -= side->ny * 2; \
	}

	struct {
		int iv;		/* 現在の辺の終点インデクス            */
		int ny;		/* 現在の辺の高さの変位                */
		int n;		/* 現在の辺の残りライン数              */
		RENDVERTEX cur;	/* 現在値                              */
		DDA x;		/* 頂点座標DDA(yは左右共通で1づつ進む) */
		DDA s, t;	/* テクスチャ座標DDA                   */
	} sides[2], *side;

	int i, itop, y, top, bottom;
	RENDVERTEX *v, *v0, *v1;

	/* 上下端の位置と、上端の頂点を求めます。 */
	itop = 0;
	top = bottom = render_work->rend_vertices[0].y;
	for(i = 1; i < n_vertices; i++) {
		v = &render_work->rend_vertices[i];
		if(v->y < top) {
			itop = i;
			top = v->y;
		}
		if(v->y > bottom) {
			bottom = v->y;
		}
	}
	if(top == bottom) return; /* 水平ポリゴンは描きません。 */

	/* 左右の辺を初期化します。 */
	for(i = 0; i < 2; i++) {
		side = &sides[i];
		side->iv = itop;
		side->n = 0; /* 初回に本当の初期化を行うように */
	}

	/* 下端を除く、各スキャンラインについて... */
	for(y = top; y < bottom; y++) {
		/* 左右の辺について... */
		for(i = 0; i < 2; i++) {
			side = &sides[i];
			/* 次の辺に達したら... */
			if(side->n == 0) {
				do {
					/* 次の辺の両端の頂点を求めます。 */
					v0 = &render_work->rend_vertices[side->iv];
					if(i == 0) {
						side->iv--;
						if(side->iv == -1) {
							side->iv = n_vertices - 1;
						}
					} else {
						side->iv++;
						if(side->iv == n_vertices) {
							side->iv = 0;
						}
					}
					v1 = &render_work->rend_vertices[side->iv];
					/* この辺の高さの変位を求めます。 */
					side->ny = v1->y - v0->y;
					/* V字ポリゴンを検出したら、残りの描画はキャンセルします。 */
					if(side->ny < 0) return;
				} while(side->ny == 0); /* 水平な辺は無視します。 */
				/* DDAセットアップ。 */
				SETUP(x);
				SETUP(s);
				SETUP(t);
				/* 次の辺までのカウンタを初期化。 */
				side->n = side->ny;
			}
		}
		/* 左右の辺の間に、水平線を描きます。 */
		sides[0].cur.y = sides[1].cur.y = y;
		render_work->draw_scanline(render, &sides[0].cur, &sides[1].cur);
		/* 左右の辺について... */
		for(i = 0; i < 2; i++) {
			side = &sides[i];
			/* 次の辺までのライン数を減らします。 */
			side->n--;
			/* DDAステップ実行。 */
			STEP(x)
			STEP(s)
			STEP(t)
		}
	}
	/* 下端のスキャンラインは描きません。 */

#undef SETUP
#undef STEP
}

static void
draw_scanline_woz_color(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1)
{
	/* DDAセットアップ用マクロ。 */
#define SETUP(i) \
	cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		i.n = (v1->i - v0->i) % nx; \
		i.d = -nx; \
		i.u =  (v1->i - v0->i) / nx; \
		i.v =  1; \
	} else { \
		i.n = (v0->i - v1->i) % nx; \
		i.d = -nx; \
		i.u = -(v0->i - v1->i) / nx; \
		i.v = -1; \
	}

	/* DDAステップ実行用マクロ。 */
#define STEP(i) \
	cur.i += i.u; \
	i.d += i.n * 2; \
	if(i.d >= 0) { \
		cur.i += i.v; \
		i.d -= nx * 2; \
	}

	SURFACE* surface;	/* サーフェイス               */
	unsigned char* vptr;	/* カラーバッファポインタ     */
	int nx;			/* 現在のスキャンラインの長さ */
	int n;			/* 現在の辺の残りピクセル数   */
	const RENDVERTEX* tmp;
	int ofs;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 確実に 左:v0 -> v1:右 とします。 */
	if(v0->x > v1->x) {
		tmp = v0;
		      v0 = v1;
		           v1 = tmp;
	}

	/* 始点アドレスを求めます。 */
	ofs = surface->w * v0->y + v0->x;
	vptr = surface->vbuff + ofs;

	/* 主軸のDDAセットアップ。 */
	nx = v1->x - v0->x;
	if(nx == 0) return; /* 点なら描きません。 */

	/* DDAループ。 */
	n = nx;
	do {
		/* テクスチャ無しなら、フェイスの背景色で描きます。 */
		*vptr = render_work->back_color;
		/* バッファポインタを進めます。 */
		vptr++;
	} while(--n); /* 右端ピクセルは描かないので、プリデクリメントです。 */

#undef SETUP
#undef STEP
}

static void
draw_scanline_woz_1bit(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1)
{
	/* DDAセットアップ用マクロ。 */
#define SETUP(i) \
	cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		i.n = (v1->i - v0->i) % nx; \
		i.d = -nx; \
		i.u =  (v1->i - v0->i) / nx; \
		i.v =  1; \
	} else { \
		i.n = (v0->i - v1->i) % nx; \
		i.d = -nx; \
		i.u = -(v0->i - v1->i) / nx; \
		i.v = -1; \
	}

	/* DDAステップ実行用マクロ。 */
#define STEP(i) \
	cur.i += i.u; \
	i.d += i.n * 2; \
	if(i.d >= 0) { \
		cur.i += i.v; \
		i.d -= nx * 2; \
	}

	SURFACE* surface;	/* サーフェイス               */
	TEXTURE* texture;	/* テクスチャ                 */
	unsigned char* vptr;	/* カラーバッファポインタ     */
	int nx;			/* 現在のスキャンラインの長さ */
	int n;			/* 現在の辺の残りピクセル数   */
	RENDVERTEX cur;		/* 現在値                     */
	DDA s, t;		/* テクスチャ座標DDA          */
	const RENDVERTEX* tmp;
	int ofs;
	unsigned char sval, tval;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 確実に 左:v0 -> v1:右 とします。 */
	if(v0->x > v1->x) {
		tmp = v0;
		      v0 = v1;
		           v1 = tmp;
	}

	/* 始点アドレスを求めます。 */
	ofs = surface->w * v0->y + v0->x;
	vptr = surface->vbuff + ofs;

	/* 主軸のDDAセットアップ。 */
	nx = v1->x - v0->x;
	if(nx == 0) return; /* 点なら描きません。 */

	/* 副軸のDDAセットアップ。 */
	SETUP(s);
	SETUP(t);

	/* テクスチャを取り出しておきます。 */
	texture = render->context->texture;

	/* DDAループ。 */
	n = nx;
	do {
		/* P/ECEは除算が遅いので、除算の要・不要を判定してから除算を行ったほうがまだマシです。
		 * テクスチャ座標がWrapしない場合のスキャンライン描画コードを展開すれば、さらに高速化できますが、
		 * コードサイズ増加との兼ね合いで、このあたりで妥協しました。
		 * 速度比較の参考数値: 常に除算(100%)->判定して除算(150%高速化)->コード展開(110%高速化)
		 */
		sval = (unsigned char)(cur.s >> 8); if(sval >= texture->header.w) sval %= texture->header.w;
		tval = (unsigned char)(cur.t >> 8); if(tval >= texture->header.h) tval %= texture->header.h;
		ofs = texture->header.w * tval + sval;
		/* 1bitテクスチャなら、テクセル値によって 1:フェイスの前景色/0:フェイスの背景色 で描きます。 */
		*vptr = texture->buf[ofs / 8] >> (7 - (ofs & 7)) & 1 ? render_work->fore_color : render_work->back_color;
		/* バッファポインタを進めます。 */
		vptr++;
		/* DDAステップ実行。 */
		STEP(s);
		STEP(t);
	} while(--n); /* 右端ピクセルは描かないので、プリデクリメントです。 */

#undef SETUP
#undef STEP
}

static void
draw_scanline_woz_1bitmask(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1)
{
	/* DDAセットアップ用マクロ。 */
#define SETUP(i) \
	cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		i.n = (v1->i - v0->i) % nx; \
		i.d = -nx; \
		i.u =  (v1->i - v0->i) / nx; \
		i.v =  1; \
	} else { \
		i.n = (v0->i - v1->i) % nx; \
		i.d = -nx; \
		i.u = -(v0->i - v1->i) / nx; \
		i.v = -1; \
	}

	/* DDAステップ実行用マクロ。 */
#define STEP(i) \
	cur.i += i.u; \
	i.d += i.n * 2; \
	if(i.d >= 0) { \
		cur.i += i.v; \
		i.d -= nx * 2; \
	}

	SURFACE* surface;	/* サーフェイス               */
	TEXTURE* texture;	/* テクスチャ                 */
	unsigned char* vptr;	/* カラーバッファポインタ     */
	int nx;			/* 現在のスキャンラインの長さ */
	int n;			/* 現在の辺の残りピクセル数   */
	RENDVERTEX cur;		/* 現在値                     */
	DDA s, t;		/* テクスチャ座標DDA          */
	const RENDVERTEX* tmp;
	int ofs;
	unsigned char sval, tval;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 確実に 左:v0 -> v1:右 とします。 */
	if(v0->x > v1->x) {
		tmp = v0;
		      v0 = v1;
		           v1 = tmp;
	}

	/* 始点アドレスを求めます。 */
	ofs = surface->w * v0->y + v0->x;
	vptr = surface->vbuff + ofs;

	/* 主軸のDDAセットアップ。 */
	nx = v1->x - v0->x;
	if(nx == 0) return; /* 点なら描きません。 */

	/* 副軸のDDAセットアップ。 */
	SETUP(s);
	SETUP(t);

	/* テクスチャを取り出しておきます。 */
	texture = render->context->texture;

	/* DDAループ。 */
	n = nx;
	do {
		/* P/ECEは除算が遅いので、除算の要・不要を判定してから除算を行ったほうがまだマシです。
		 * テクスチャ座標がWrapしない場合のスキャンライン描画コードを展開すれば、さらに高速化できますが、
		 * コードサイズ増加との兼ね合いで、このあたりで妥協しました。
		 * 速度比較の参考数値: 常に除算(100%)->判定して除算(150%高速化)->コード展開(110%高速化)
		 */
		sval = (unsigned char)(cur.s >> 8); if(sval >= texture->header.w) sval %= texture->header.w;
		tval = (unsigned char)(cur.t >> 8); if(tval >= texture->header.h) tval %= texture->header.h;
		ofs = texture->header.w * tval + sval;
		if(texture->mask[ofs / 8] >> (7 - (ofs & 7)) & 1) {
			/* 1bitテクスチャなら、テクセル値によって 1:フェイスの前景色/0:フェイスの背景色 で描きます。 */
			*vptr = texture->buf[ofs / 8] >> (7 - (ofs & 7)) & 1 ? render_work->fore_color : render_work->back_color;
		}
		/* バッファポインタを進めます。 */
		vptr++;
		/* DDAステップ実行。 */
		STEP(s);
		STEP(t);
	} while(--n); /* 右端ピクセルは描かないので、プリデクリメントです。 */

#undef SETUP
#undef STEP
}

static void
draw_scanline_woz_2bit(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1)
{
	/* DDAセットアップ用マクロ。 */
#define SETUP(i) \
	cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		i.n = (v1->i - v0->i) % nx; \
		i.d = -nx; \
		i.u =  (v1->i - v0->i) / nx; \
		i.v =  1; \
	} else { \
		i.n = (v0->i - v1->i) % nx; \
		i.d = -nx; \
		i.u = -(v0->i - v1->i) / nx; \
		i.v = -1; \
	}

	/* DDAステップ実行用マクロ。 */
#define STEP(i) \
	cur.i += i.u; \
	i.d += i.n * 2; \
	if(i.d >= 0) { \
		cur.i += i.v; \
		i.d -= nx * 2; \
	}

	SURFACE* surface;	/* サーフェイス               */
	TEXTURE* texture;	/* テクスチャ                 */
	unsigned char* vptr;	/* カラーバッファポインタ     */
	int nx;			/* 現在のスキャンラインの長さ */
	int n;			/* 現在の辺の残りピクセル数   */
	RENDVERTEX cur;		/* 現在値                     */
	DDA s, t;		/* テクスチャ座標DDA          */
	const RENDVERTEX* tmp;
	int ofs;
	unsigned char sval, tval;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 確実に 左:v0 -> v1:右 とします。 */
	if(v0->x > v1->x) {
		tmp = v0;
		      v0 = v1;
		           v1 = tmp;
	}

	/* 始点アドレスを求めます。 */
	ofs = surface->w * v0->y + v0->x;
	vptr = surface->vbuff + ofs;

	/* 主軸のDDAセットアップ。 */
	nx = v1->x - v0->x;
	if(nx == 0) return; /* 点なら描きません。 */

	/* 副軸のDDAセットアップ。 */
	SETUP(s);
	SETUP(t);

	/* テクスチャを取り出しておきます。 */
	texture = render->context->texture;

	/* DDAループ。 */
	n = nx;
	do {
		/* P/ECEは除算が遅いので、除算の要・不要を判定してから除算を行ったほうがまだマシです。
		 * テクスチャ座標がWrapしない場合のスキャンライン描画コードを展開すれば、さらに高速化できますが、
		 * コードサイズ増加との兼ね合いで、このあたりで妥協しました。
		 * 速度比較の参考数値: 常に除算(100%)->判定して除算(150%高速化)->コード展開(110%高速化)
		 */
		sval = (unsigned char)(cur.s >> 8); if(sval >= texture->header.w) sval %= texture->header.w;
		tval = (unsigned char)(cur.t >> 8); if(tval >= texture->header.h) tval %= texture->header.h;
		ofs = texture->header.w * tval + sval;
		/* 2bitテクスチャなら、テクセル値をそのまま描きます。 */
		*vptr = texture->buf[ofs / 4] >> (3 - (ofs & 3)) * 2 & 3;
		/* バッファポインタを進めます。 */
		vptr++;
		/* DDAステップ実行。 */
		STEP(s);
		STEP(t);
	} while(--n); /* 右端ピクセルは描かないので、プリデクリメントです。 */

#undef SETUP
#undef STEP
}

static void
draw_scanline_woz_2bitmask(RENDER* render, const RENDVERTEX* v0, const RENDVERTEX* v1)
{
	/* DDAセットアップ用マクロ。 */
#define SETUP(i) \
	cur.i = v0->i; \
	if(v0->i <= v1->i) { \
		i.n = (v1->i - v0->i) % nx; \
		i.d = -nx; \
		i.u =  (v1->i - v0->i) / nx; \
		i.v =  1; \
	} else { \
		i.n = (v0->i - v1->i) % nx; \
		i.d = -nx; \
		i.u = -(v0->i - v1->i) / nx; \
		i.v = -1; \
	}

	/* DDAステップ実行用マクロ。 */
#define STEP(i) \
	cur.i += i.u; \
	i.d += i.n * 2; \
	if(i.d >= 0) { \
		cur.i += i.v; \
		i.d -= nx * 2; \
	}

	SURFACE* surface;	/* サーフェイス               */
	TEXTURE* texture;	/* テクスチャ                 */
	unsigned char* vptr;	/* カラーバッファポインタ     */
	int nx;			/* 現在のスキャンラインの長さ */
	int n;			/* 現在の辺の残りピクセル数   */
	RENDVERTEX cur;		/* 現在値                     */
	DDA s, t;		/* テクスチャ座標DDA          */
	const RENDVERTEX* tmp;
	int ofs;
	unsigned char sval, tval;

	/* サーフェイスを取り出しておきます。 */
	surface = render->surface;

	/* 確実に 左:v0 -> v1:右 とします。 */
	if(v0->x > v1->x) {
		tmp = v0;
		      v0 = v1;
		           v1 = tmp;
	}

	/* 始点アドレスを求めます。 */
	ofs = surface->w * v0->y + v0->x;
	vptr = surface->vbuff + ofs;

	/* 主軸のDDAセットアップ。 */
	nx = v1->x - v0->x;
	if(nx == 0) return; /* 点なら描きません。 */

	/* 副軸のDDAセットアップ。 */
	SETUP(s);
	SETUP(t);

	/* テクスチャを取り出しておきます。 */
	texture = render->context->texture;

	/* DDAループ。 */
	n = nx;
	do {
		/* P/ECEは除算が遅いので、除算の要・不要を判定してから除算を行ったほうがまだマシです。
		 * テクスチャ座標がWrapしない場合のスキャンライン描画コードを展開すれば、さらに高速化できますが、
		 * コードサイズ増加との兼ね合いで、このあたりで妥協しました。
		 * 速度比較の参考数値: 常に除算(100%)->判定して除算(150%高速化)->コード展開(110%高速化)
		 */
		sval = (unsigned char)(cur.s >> 8); if(sval >= texture->header.w) sval %= texture->header.w;
		tval = (unsigned char)(cur.t >> 8); if(tval >= texture->header.h) tval %= texture->header.h;
		ofs = texture->header.w * tval + sval;
		if(texture->mask[ofs / 8] >> (7 - (ofs & 7)) & 1) {
			/* 2bitテクスチャなら、テクセル値をそのまま描きます。 */
			*vptr = texture->buf[ofs / 4] >> (3 - (ofs & 3)) * 2 & 3;
		}
		/* バッファポインタを進めます。 */
		vptr++;
		/* DDAステップ実行。 */
		STEP(s);
		STEP(t);
	} while(--n); /* 右端ピクセルは描かないので、プリデクリメントです。 */

#undef SETUP
#undef STEP
}

