#include "app.h"
//cliprenf.cをコピーして改造して作りました。
//・rendf_mesh_wired()		rendf_mesh()の引数形式で、ポリゴンは描かずにワイヤーフレームを描く。(背面も描く)
//・rendf_mesh_framed()		rendf_mesh()に加えて、輪郭のワイヤーフレームを描く。(隣接した線や背面は描かない)
//・rendf_mesh_wframed()	rendf_mesh()に加えて、輪郭のワイヤーフレームを描く。(隣接した線も描く。背面は描かない)
//ワイヤーフレームの部分は深度バッファが効いていないので、複数のオブジェクトや凹面を含むオブジェクトを描くと、正しく描けない事に注意して下さい。
/*****************************************************************************
 *	RENDF
 *****************************************************************************/
/* クリッピング用頂点 */
typedef struct _CLIPVERTEX {
	float x, y, z;		/* + 0,12: 頂点座標 */
	float s, t;		/* +12, 8: テクスチャ座標 */
} CLIPVERTEX;			/* =20 */
/* _def_vbuff[]上に確保する、描画用一時ワークの構造体 */
#define XFORMED_VECTORS_MAX	(sizeof _def_vbuff / sizeof(vec3f))	/* 128×88÷12=938: WIREの最大頂点数。MESHの最大頂点数は、MESH.nvがunsigned charなので、メモリ制限に拘らず255です。 */
typedef struct _RENDF_WORK_VBUFF {
	vec3f xformed_vectors[XFORMED_VECTORS_MAX];			/* 12*938=11256: 変換済み頂点座標バッファ */
} RENDF_WORK_VBUFF;							/* 合計  =11256: _def_vbuff[128*88=11264]のサイズを超えないよう注意!! */
#define _rendf_work_vbuff	((RENDF_WORK_VBUFF*)_def_vbuff)
#define _xformed_vectors	(_rendf_work_vbuff->xformed_vectors)
/* FRAM4領域内に確保する、描画用一時ワークの構造体 */
#define N_VERTICES_MAX		8					/* 1ポリゴン当たりの最大頂点数。 */
typedef struct _RENDF_WORK_FRAM4 {
	CLIPVERTEX clip_vertices[2][N_VERTICES_MAX];			/* 20*2*8= 320: クリッピング用頂点バッファ */
	RENDVERTEX rend_vertices[N_VERTICES_MAX];			/* 10*8  =  80: 描画用頂点バッファ */
} RENDF_WORK_FRAM4;							/* 合計  = 400: FRAM4領域のサイズ(FRAM4_SIZE=512)を超えないよう注意!! */
#define _rendf_work_fram4	((RENDF_WORK_FRAM4*)FRAM4_START)
#define _clip_vertices		(_rendf_work_fram4->clip_vertices)
#define _rend_vertices		(_rendf_work_fram4->rend_vertices)
//#define NOASM	/* アルゴリズム確認用のC言語版実装を使う場合は、NOASMを定義して下さい。 */
static const void* xform_vectors(const mat3f* m, const vec3f* v_in/*[nv]*/, vec3f* v_out/*[nv]*/, int nv);
static int pick_vertices(CLIPVERTEX* cv, const vec3f* v, const TCOORD* c, const FACE* f);
static void inhomogenize(CLIPVERTEX* cv, int nv);
static int cull_back(const CLIPVERTEX* cv, int nv);
static void init_vertices(RENDF* r, RENDVERTEX* rv, const CLIPVERTEX* cv, int nv);
static int clip_z(RENDF* r, CLIPVERTEX* cv0, CLIPVERTEX* cv1, int nsrc);
static int clip_xy(RENDF* r, CLIPVERTEX* cv0, CLIPVERTEX* cv1, int nsrc);
static int clip_z_sub(RENDF* r, CLIPVERTEX* cv0, CLIPVERTEX* cv1, int nsrc);
static int clip_xy_sub(RENDF* r, CLIPVERTEX* cv0, CLIPVERTEX* cv1, int nsrc);
//{{2008/08/09:浮動小数点演算誤差によるクリッピングバグ検出用。安定動作を確認できたら消す予定です。
static void detect_error(const RENDVERTEX* rv, int nv, int w, int h);
//}}2008/08/09:浮動小数点演算誤差によるクリッピングバグ検出用。安定動作を確認できたら消す予定です。
/* スキャンライン描画関数の選択 */
static DSLPROC select_draw_scanline(RENDF* r, DSLPARAM* param);	/*{{2009/04/11:追加}}*/
/*****************************************************************************
 *	
 *****************************************************************************/
void rendf_mesh_wired(RENDF* r, const MESH* mesh) {
//{{追加:rendf_mesh_wired()
	WSEG TBL_wseg[64/*調整可*/];
	unsigned char TBL_fore[64/*調整可*/];
	int n_wseg = 0;
//}}追加:rendf_mesh_wired()
	int n_vectors;
	int n_tcoords;
	int n_faces;
	int n_vertices;
	const vec3f* vectors;
	const TCOORD* tcoords;
	const FACE *face;
	DSLPARAM param;
	DSLPROC draw_scanline = select_draw_scanline(r, &param);
	n_vectors = mesh->nv;
	n_tcoords = mesh->nc;
	n_faces = mesh->nf;
	vectors = (const vec3f*)(mesh + 1);
	tcoords = xform_vectors(&r->matrix, vectors, _xformed_vectors, n_vectors);
	face = (const FACE*)(tcoords + n_tcoords);
	do {
		n_vertices = pick_vertices(_clip_vertices[0], _xformed_vectors, tcoords, face);
		if(n_vertices < 3) goto L_SKIP;
		n_vertices = clip_z(r, _clip_vertices[0], _clip_vertices[1], n_vertices);
		if(n_vertices < 3) goto L_SKIP;
//{{追加:rendf_mesh_wired()
		{
			FACEVERTEX* TBL_fv = (FACEVERTEX*)(face + 1);
			int i;
			for(i = 0; i < face->nfv; i++) {
				FACEVERTEX* fv0 = &TBL_fv[i];
				FACEVERTEX* fv1 = &TBL_fv[(i + 1) % face->nfv];
				int iv0 = fv0->iv;
				int iv1 = fv1->iv;
				int j;
				for(j = 0; j < n_wseg; j++) {
					if((TBL_wseg[j].iv0 == iv1) &&
					   (TBL_wseg[j].iv1 == iv0)) { break; }
				}
				if(j < n_wseg) {
					/** no job **/
				} else {
					if(j >= ARRAY_SIZE(TBL_wseg)) { DIE(); }
					TBL_wseg[j].iv0 = iv0;
					TBL_wseg[j].iv1 = iv1;
					TBL_fore[j] = 0;
					n_wseg++;
				}
			}
		}
//}}追加:rendf_mesh_wired()
		inhomogenize(_clip_vertices[0], n_vertices); /* 非同次座標化 */
		if(cull_back(_clip_vertices[0], n_vertices)) goto L_SKIP; /* バックフェースカリング */
		n_vertices = clip_xy(r, _clip_vertices[0], _clip_vertices[1], n_vertices);
		if(n_vertices < 3) goto L_SKIP;
//{{追加:rendf_mesh_wired()
		{
			FACEVERTEX* TBL_fv = (FACEVERTEX*)(face + 1);
			int i;
			for(i = 0; i < face->nfv; i++) {
				FACEVERTEX* fv0 = &TBL_fv[i];
				FACEVERTEX* fv1 = &TBL_fv[(i + 1) % face->nfv];
				int iv0 = fv0->iv;
				int iv1 = fv1->iv;
				int j;
				for(j = 0; j < n_wseg; j++) {
					if((TBL_wseg[j].iv0 == iv1) &&
					   (TBL_wseg[j].iv1 == iv0)) { break; }
				}
				if(j < n_wseg) {
					TBL_fore[j] = 1;
				} else {
					if(j >= ARRAY_SIZE(TBL_wseg)) { DIE(); }
					TBL_wseg[j].iv0 = iv0;
					TBL_wseg[j].iv1 = iv1;
					TBL_fore[j] = 1;
					n_wseg++;
				}
			}
		}
		goto L_SKIP;
//}}追加:rendf_mesh_wired()
		init_vertices(r, _rend_vertices, _clip_vertices[0], n_vertices);
		//{{2008/08/09:浮動小数点演算誤差によるクリッピングバグ検出用。安定動作を確認できたら消す予定です。
		detect_error(_rend_vertices, n_vertices, param.surface_w, param.surface_h);
		//}}2008/08/09:浮動小数点演算誤差によるクリッピングバグ検出用。安定動作を確認できたら消す予定です。
		param.fore_color = face->c      & 15;
		param.back_color = face->c >> 4 & 15;
		draw_primitive(_rend_vertices, n_vertices, &param, draw_scanline);
L_SKIP:
		face = (FACE*)((FACEVERTEX*)(face + 1) + face->nfv);
	} while(--n_faces);
//{{追加:rendf_mesh_wired()
	{
		int i;
		for(i = 0; i < 2; i++) {
			int j;
			for(j = 0; j < n_wseg; j++) {
				int iv0 = TBL_wseg[j].iv0;
				int iv1 = TBL_wseg[j].iv1;
				const vec3f* v0 = &vectors[iv0];
				const vec3f* v1 = &vectors[iv1];
				if(TBL_fore[j] == i) {
					rendf_line(r, v0, v1, i ? 3/*変更可*/ : 2/*変更可*/);
				}
			}
		}
	}
//}}追加:rendf_mesh_wired()
}
/*---------------------------------------------------------------------------*/
void rendf_mesh_framed(RENDF* r, const MESH* mesh) {
//{{追加:rendf_mesh_framed()
	WSEG TBL_wseg[64/*調整可*/];
	int n_wseg = 0;
//}}追加:rendf_mesh_framed()
	int n_vectors;
	int n_tcoords;
	int n_faces;
	int n_vertices;
	const vec3f* vectors;
	const TCOORD* tcoords;
	const FACE *face;
	DSLPARAM param;
	DSLPROC draw_scanline = select_draw_scanline(r, &param);
	n_vectors = mesh->nv;
	n_tcoords = mesh->nc;
	n_faces = mesh->nf;
	vectors = (const vec3f*)(mesh + 1);
	tcoords = xform_vectors(&r->matrix, vectors, _xformed_vectors, n_vectors);
	face = (const FACE*)(tcoords + n_tcoords);
	do {
		n_vertices = pick_vertices(_clip_vertices[0], _xformed_vectors, tcoords, face);
		if(n_vertices < 3) goto L_SKIP;
		n_vertices = clip_z(r, _clip_vertices[0], _clip_vertices[1], n_vertices);
		if(n_vertices < 3) goto L_SKIP;
		inhomogenize(_clip_vertices[0], n_vertices); /* 非同次座標化 */
		if(cull_back(_clip_vertices[0], n_vertices)) goto L_SKIP; /* バックフェースカリング */
		n_vertices = clip_xy(r, _clip_vertices[0], _clip_vertices[1], n_vertices);
		if(n_vertices < 3) goto L_SKIP;
//{{追加:rendf_mesh_framed()
		{
			FACEVERTEX* TBL_fv = (FACEVERTEX*)(face + 1);
			int i;
			for(i = 0; i < face->nfv; i++) {
				FACEVERTEX* fv0 = &TBL_fv[i];
				FACEVERTEX* fv1 = &TBL_fv[(i + 1) % face->nfv];
				int iv0 = fv0->iv;
				int iv1 = fv1->iv;
				int j;
				for(j = 0; j < n_wseg; j++) {
					if((TBL_wseg[j].iv0 == iv1) &&
					   (TBL_wseg[j].iv1 == iv0)) { break; }
				}
				if(j < n_wseg) {
					n_wseg--;
					memmove(&TBL_wseg[j], &TBL_wseg[j + 1], sizeof(WSEG) * (n_wseg - j));
				} else {
					if(j >= ARRAY_SIZE(TBL_wseg)) { DIE(); }
					TBL_wseg[j].iv0 = iv0;
					TBL_wseg[j].iv1 = iv1;
					n_wseg++;
				}
			}
		}
//}}追加:rendf_mesh_framed()
		init_vertices(r, _rend_vertices, _clip_vertices[0], n_vertices);
		//{{2008/08/09:浮動小数点演算誤差によるクリッピングバグ検出用。安定動作を確認できたら消す予定です。
		detect_error(_rend_vertices, n_vertices, param.surface_w, param.surface_h);
		//}}2008/08/09:浮動小数点演算誤差によるクリッピングバグ検出用。安定動作を確認できたら消す予定です。
		param.fore_color = face->c      & 15;
		param.back_color = face->c >> 4 & 15;
		draw_primitive(_rend_vertices, n_vertices, &param, draw_scanline);
L_SKIP:
		face = (FACE*)((FACEVERTEX*)(face + 1) + face->nfv);
	} while(--n_faces);
//{{追加:rendf_mesh_framed()
	{
		int i;
		for(i = 0; i < n_wseg; i++) {
			int iv0 = TBL_wseg[i].iv0;
			int iv1 = TBL_wseg[i].iv1;
			const vec3f* v0 = &vectors[iv0];
			const vec3f* v1 = &vectors[iv1];
			rendf_line(r, v0, v1, 3);
		}
	}
//}}追加:rendf_mesh_framed()
}
/*---------------------------------------------------------------------------*/
void rendf_mesh_wframed(RENDF* r, const MESH* mesh) {
//{{追加:rendf_mesh_wframed()
	WSEG TBL_wseg[64/*調整可*/];
	int n_wseg = 0;
//}}追加:rendf_mesh_wframed()
	int n_vectors;
	int n_tcoords;
	int n_faces;
	int n_vertices;
	const vec3f* vectors;
	const TCOORD* tcoords;
	const FACE *face;
	DSLPARAM param;
	DSLPROC draw_scanline = select_draw_scanline(r, &param);
	n_vectors = mesh->nv;
	n_tcoords = mesh->nc;
	n_faces = mesh->nf;
	vectors = (const vec3f*)(mesh + 1);
	tcoords = xform_vectors(&r->matrix, vectors, _xformed_vectors, n_vectors);
	face = (const FACE*)(tcoords + n_tcoords);
	do {
		n_vertices = pick_vertices(_clip_vertices[0], _xformed_vectors, tcoords, face);
		if(n_vertices < 3) goto L_SKIP;
		n_vertices = clip_z(r, _clip_vertices[0], _clip_vertices[1], n_vertices);
		if(n_vertices < 3) goto L_SKIP;
		inhomogenize(_clip_vertices[0], n_vertices); /* 非同次座標化 */
		if(cull_back(_clip_vertices[0], n_vertices)) goto L_SKIP; /* バックフェースカリング */
		n_vertices = clip_xy(r, _clip_vertices[0], _clip_vertices[1], n_vertices);
		if(n_vertices < 3) goto L_SKIP;
//{{追加:rendf_mesh_wframed()
		{
			FACEVERTEX* TBL_fv = (FACEVERTEX*)(face + 1);
			int i;
			for(i = 0; i < face->nfv; i++) {
				FACEVERTEX* fv0 = &TBL_fv[i];
				FACEVERTEX* fv1 = &TBL_fv[(i + 1) % face->nfv];
				int iv0 = fv0->iv;
				int iv1 = fv1->iv;
				int j;
				for(j = 0; j < n_wseg; j++) {
					if((TBL_wseg[j].iv0 == iv1) &&
					   (TBL_wseg[j].iv1 == iv0)) { break; }
				}
				if(j < n_wseg) {
					/** no job **/
				} else {
					if(j >= ARRAY_SIZE(TBL_wseg)) { DIE(); }
					TBL_wseg[j].iv0 = iv0;
					TBL_wseg[j].iv1 = iv1;
					n_wseg++;
				}
			}
		}
//}}追加:rendf_mesh_wframed()
		init_vertices(r, _rend_vertices, _clip_vertices[0], n_vertices);
		//{{2008/08/09:浮動小数点演算誤差によるクリッピングバグ検出用。安定動作を確認できたら消す予定です。
		detect_error(_rend_vertices, n_vertices, param.surface_w, param.surface_h);
		//}}2008/08/09:浮動小数点演算誤差によるクリッピングバグ検出用。安定動作を確認できたら消す予定です。
		param.fore_color = face->c      & 15;
		param.back_color = face->c >> 4 & 15;
		draw_primitive(_rend_vertices, n_vertices, &param, draw_scanline);
L_SKIP:
		face = (FACE*)((FACEVERTEX*)(face + 1) + face->nfv);
	} while(--n_faces);
//{{追加:rendf_mesh_wframed()
	{
		int i;
		for(i = 0; i < n_wseg; i++) {
			int iv0 = TBL_wseg[i].iv0;
			int iv1 = TBL_wseg[i].iv1;
			const vec3f* v0 = &vectors[iv0];
			const vec3f* v1 = &vectors[iv1];
			rendf_line(r, v0, v1, 3);
		}
	}
//}}追加:rendf_mesh_wframed()
}
/*---------------------------------------------------------------------------*/
static const void* xform_vectors(const mat3f* m, const vec3f* v_in/*[nv]*/, vec3f* v_out/*[nv]*/, int nv) {
	do {
		*v_out = *v_in++;
		vec3f_xform(m, v_out++);
	} while(--nv);
	return v_in;
}
/*---------------------------------------------------------------------------*/
static int pick_vertices(CLIPVERTEX* cv, const vec3f* v, const TCOORD* c, const FACE* f) {
	int i;
	int iv;
	int ic;
	int nfv;
	FACEVERTEX* fv;
	const vec3f* pv;
	const TCOORD* pc;
	nfv = f->nfv;
	if(nfv > N_VERTICES_MAX) {
		nfv = N_VERTICES_MAX;
	}
	fv = (FACEVERTEX*)(f + 1);
	i = nfv;
	do {
		iv = fv->iv;
		ic = fv->ic;
		pv = &v[iv];
		pc = &c[ic];
		cv->x = pv->x;
		cv->y = pv->y;
		cv->z = pv->z;
		cv->s = pc->s + 0.5f; /* テクセルの中心をポイント */
		cv->t = pc->t + 0.5f; /* テクセルの中心をポイント */
		fv++;
		cv++;
	} while(--i);
	return nfv;
}
/*---------------------------------------------------------------------------*/
static void inhomogenize(CLIPVERTEX* cv, int nv) { /* 非同次座標化 */
	do {
		cv->x /= cv->z;
		cv->y /= cv->z;
		cv++;
	} while(--nv);
}
/*---------------------------------------------------------------------------*/
static int cull_back(const CLIPVERTEX* cv, int nv) { /* バックフェースカリング */
	float xN0 = cv[0].x - cv[nv - 1].x;
	float yN0 = cv[0].y - cv[nv - 1].y;
	float x01 = cv[1].x - cv[     0].x;
	float y01 = cv[1].y - cv[     0].y;
	float s = (xN0 * y01) - (x01 * yN0);
	return s <= 0.0f;
}
/*---------------------------------------------------------------------------*/
static void init_vertices(RENDF* r, RENDVERTEX* rv, const CLIPVERTEX* cv, int nv) {
	do {
		rv->x = cv->x;
		rv->y = cv->y;
		rv->z = (((cv->z - r->front) * r->back) / ((r->back - r->front) * cv->z)) * 0xffff; /* 8.8bit */
		rv->s = cv->s * 0x100; /* 8.8bit */
		rv->t = cv->t * 0x100; /* 8.8bit */
		cv++;
		rv++;
	} while(--nv);
}
/*---------------------------------------------------------------------------*/
static int clip_z(RENDF* r, CLIPVERTEX* cv0, CLIPVERTEX* cv1, int nsrc) {
	CLIPVERTEX* v = cv0;
	int i = nsrc;
	do {
		if(v->z < r->front) goto L_CLIP;
		if(v->z > r->back ) goto L_CLIP;
		v++;
	} while(--i);
	return nsrc;
L_CLIP:
	return clip_z_sub(r, cv0, cv1, nsrc);
}
/*---------------------------------------------------------------------------*/
static int clip_xy(RENDF* r, CLIPVERTEX* cv0, CLIPVERTEX* cv1, int nsrc) {
	CLIPVERTEX* v = cv0;
	int i = nsrc;
	do {
		if(v->x < r->left  ) goto L_CLIP;
		if(v->x > r->right ) goto L_CLIP;
		if(v->y < r->top   ) goto L_CLIP;
		if(v->y > r->bottom) goto L_CLIP;
		v++;
	} while(--i);
	return nsrc;
L_CLIP:
	return clip_xy_sub(r, cv0, cv1, nsrc);
}
/*---------------------------------------------------------------------------*/
static int clip_z_sub(RENDF* r, CLIPVERTEX* cv0, CLIPVERTEX* cv1, int nsrc) {
#define CLIP(SRC, DST, OP, LIM)					\
	src = SRC;						\
	dst = DST;						\
	ndst = 0;						\
	for(i = 0, v0 = src; i < nsrc; i++, v0++) {		\
		v1 = (i < nsrc - 1) ? (v0 + 1) : src;		\
		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;					\
		n001 = n0 / n01;				\
		dst->x = v0->x + ((v1->x - v0->x) * n001);	\
		dst->y = v0->y + ((v1->y - v0->y) * n001);	\
		dst->s = v0->s + ((v1->s - v0->s) * n001);	\
		dst->t = v0->t + ((v1->t - v0->t) * n001);	\
		dst++;						\
		ndst++;						\
		if(ndst == N_VERTICES_MAX) break;		\
	}							\
	if(ndst < 3) return 0;
	CLIPVERTEX* src;
	CLIPVERTEX* dst;
	CLIPVERTEX* v0;
	CLIPVERTEX* v1;
	int i;
	int ndst;
	float n0;
	float n1;
	float n01;
	float n001;
	CLIP(cv0, cv1, >=, r->front); nsrc = ndst;
	CLIP(cv1, cv0, <=, r->back ); return ndst;
#undef CLIP
}
/*---------------------------------------------------------------------------*/
static int clip_xy_sub(RENDF* r, CLIPVERTEX* cv0, CLIPVERTEX* cv1, int nsrc) {
#define CLIP(SRC, DST, X, Y, OP, LIM)				\
	src = SRC;						\
	dst = DST;						\
	ndst = 0;						\
	for(i = 0, v0 = src; i < nsrc; i++, v0++) {		\
		v1 = (i < nsrc - 1) ? (v0 + 1) : src;		\
		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;					\
		n001 = n0 / n01;				\
		dst->Y = v0->Y + ((v1->Y - v0->Y) * n001);	\
		n0 *= v0->z;					\
		n1 *= v1->z;					\
		n01  = n0 + n1;					\
		n001 = n0 / n01;				\
		dst->z = v0->z + ((v1->z - v0->z) * n001);	\
		dst->s = v0->s + ((v1->s - v0->s) * n001);	\
		dst->t = v0->t + ((v1->t - v0->t) * n001);	\
		dst++;						\
		ndst++;						\
		if(ndst == N_VERTICES_MAX) break;		\
	}							\
	if(ndst < 3) return 0;
	CLIPVERTEX* src;
	CLIPVERTEX* dst;
	CLIPVERTEX* v0;
	CLIPVERTEX* v1;
	int i;
	int ndst;
	float n0;
	float n1;
	float n01;
	float n001;
	CLIP(cv0, cv1, x, y, >=, r->left  ); nsrc = ndst;
	CLIP(cv1, cv0, x, y, <=, r->right ); nsrc = ndst;
	CLIP(cv0, cv1, y, x, >=, r->top   ); nsrc = ndst;
	CLIP(cv1, cv0, y, x, <=, r->bottom); return ndst;
#undef CLIP
}
/*---------------------------------------------------------------------------*/
static void detect_error(const RENDVERTEX* rv, int nv, int w, int h) {
	do {
		if(((unsigned)rv->x > (unsigned)w) ||
		   ((unsigned)rv->y > (unsigned)h)) {
			DIE();
		}
	} while(--nv);
}
/*---------------------------------------------------------------------------*/
static DSLPROC select_draw_scanline(RENDF* r, DSLPARAM* param) {
	static const DSLPROC proc_table[/*i*/] = {
		draw_scanline_woz_color,	/* 0 */
		draw_scanline_woz_1bit,		/* 1 */
		draw_scanline_woz_2bit,		/* 2 */
		draw_scanline_woz_1bitmask,	/* 3 */
		draw_scanline_woz_2bitmask,	/* 4 */
		draw_scanline_wz_color,		/* 5 */
		draw_scanline_wz_1bit,		/* 6 */
		draw_scanline_wz_2bit,		/* 7 */
		draw_scanline_wz_1bitmask,	/* 8 */
		draw_scanline_wz_2bitmask,	/* 9 */
	};
	int i = 0;
	TEXTURE* texture = r->texture;
	SURFACE* surface = r->surface;
	param->surface_w = surface->w;
	param->surface_h = surface->h;
	param->surface_vbuff = surface->vbuff;
	if(surface->zbuff) {
		i += 5;
		param->surface_zbuff = surface->zbuff;
	}
	if(texture) {
		i += texture->header.bpp; /* 1 or 2 */
		param->texture_w = texture->header.w;
		param->texture_h = texture->header.h;
		param->texture_buf = texture->buf;
		if(texture->header.mask) {
			i += 2;
			param->texture_mask = texture->mask;
		}
	}
	return proc_table[i];
}
