texture.c 9.57 KB

#include "graphic.h"

int lod_tab[MM_MAX_LEVEL+2] =
        { 0, 51, 102, 153, 204, 256 };

/*------------------------------*/
set_texture_image( im)
struct Image *im;
{
struct Image *ti = &tex_image[0];
	*ti = *im;
}
/*------------------------------*/
do_tc_step()
{
struct TC_step *ts;
struct Tex_coord *tc;
	ts = &tc_step[0];
	tc = &tex_coord[0];

/* perspective on first coord of span */
if (ts->first) {
	ts->first = FALSE;
	tc_div_count = 0;	/* force last interval coord */
	do_tc_persp( ts->pnt.s, ts->pnt.t, ts->pnt.w, &tc_cur.s, &tc_cur.t);
	}
/* perspective on coord of span at TC_DIV_STEP interval */
if (--tc_div_count < 0 ) {
	tc_pre = tc_cur;		/* copy persp coord */
	tc_div_count = TC_DIV_STEP-1;	/* enable interpolation */
/*    step to span coordinate at plus TC_DIV_STEP */	
	ts->pnt.s += ts->del.s << TC_DIV_SHFT;
	ts->pnt.t += ts->del.t << TC_DIV_SHFT;
	ts->pnt.w += ts->del.w << TC_DIV_SHFT;
	do_tc_persp( ts->pnt.s, ts->pnt.t, ts->pnt.w, &tc_cur.s, &tc_cur.t);
/*    compute delta for linear interpolation in TC_DIV_STEP interval */
	tc_del.s = (tc_cur.s - tc_pre.s) >> TC_DIV_SHFT;
	tc_del.t = (tc_cur.t - tc_pre.t) >> TC_DIV_SHFT;
	}

/* write s, t, l to texture filter */
	tc->s = int_ewa( tc_pre.s);
	tc->t = int_ewa( tc_pre.t);
	tc->l = int_ewa( ts->pnt.l);
/* interpolate to next coord */
	tc_pre.s += tc_del.s; 
	tc_pre.t += tc_del.t; 
	ts->pnt.l += ts->del.l;
}
/*------------------------------*/
do_tc_persp( s, t, w, sp, tp)
int s, t, w, *sp, *tp;
{
/* extract integer portion */
	s = int_ewa( s);
	t = int_ewa( t);
	w = int_ewa( w);
/* perspective correction s/w, t/w */
	if (en_tc_persp) {
	/* clamp w before divide so no overflow */
		clamp( 0, w, (TC_PERSP_ONE-1));
		s = (int)((float)TC_PERSP_ONE*(float)s/(float)w);
		t = (int)((float)TC_PERSP_ONE*(float)t/(float)w);
		}
/* convert to fixed point for interpolation */
	*sp = fix_ewa( s);
	*tp = fix_ewa( t);
}
/*------------------------------*/
do_tex_filter()
{
struct Image *im;
struct Tex_coord *tc;
struct Tex_color *tp;
struct Tex_color level_color, *tq  = &level_color; /* lod color */
int level_type, level_frac, level; /* mipmap */
int l, f;			/* lod temps */

/* assign pointers */
	im = &tex_image[0];
	tc = &tex_coord[0];
	tp = &tex_color[0];
/* default to mipmap level 0 */
	level = 0;
/* if not tram tile, use tile to hold image info */
if (!en_tramtile) {
	mipmap[level].w = im->xsize;
	mipmap[level].s = im->xsize;
	mipmap[level].t = im->ysize;
	mipmap[level].addr = 0;
	}
/* extract level of detail */
if (en_tc_lod) {
int i;
	if (!en_mipmap) max_mipmap = MM_MAX_LEVEL;
	level_type = MM_LEVEL_LO;
	level_frac = 0;
	l = tc->l >> TI_FRAC_SHFT;
	if (l & (-1 << (max_mipmap+1))) level_type = MM_LEVEL_HI;
	else {
		for (i=max_mipmap; i>=0; i--) {
			if (l & (1 << i)) break;
			}
		if (i >= 0) {
			level = i;
			level_frac = (tc->l >> level) & TI_FRAC_MASK;
			level_type = MM_LEVEL_IN;
			}
		}
	}
/* sample texture */
if (en_tc_lod) { 
	unpack_colora( im->avg_color, tq->r, tq->g, tq->b, tq->a);
	if (level_type == MM_LEVEL_HI) *tp = *tq;
	else if (level_type == MM_LEVEL_IN) {
		if (en_mipmap) {
			do_tile_sample( level, tc->s, tc->t, tp);
		    if (level < max_mipmap)
			do_tile_sample( level+1, tc->s, tc->t, tq);
			f = (int)((float)level_frac * (256.0/TI_FRAC_ONE));
		} else {	/* no mipmap */
			do_tile_sample( 0, tc->s, tc->t, tp);
			f = lod_tab[level];
			f += (int)((float)(lod_tab[level+1] - f)
				* level_frac * (1.0/TI_FRAC_ONE));
			}
		tp->r = blend_color( tp->r, tq->r, f);
		tp->g = blend_color( tp->g, tq->g, f);
		tp->b = blend_color( tp->b, tq->b, f);
		tp->a = blend_color( tp->a, tq->a, f);
		}
	else if (level_type == MM_LEVEL_LO)
		do_tile_sample( 0, tc->s, tc->t, tp);
	} /* end en_tc_lod */
else do_tile_sample( 0, tc->s, tc->t, tp);
}
/*------------------------------*/
do_tile_sample( level, s, t, tp)
int level, s, t;
struct Tex_color *tp;
{
struct Image *im = &tex_image[0];
struct Tile *tile;
int sf, tf;
int si, ti;
int s4[4], t4[4];
int tex4[4];
int r0, g0, b0, a0;
int r1, g1, b1, a1;
int r2, g2, b2, a2;
int r3, g3, b3, a3;
int c0, c1;

int sin = s, tin = t;

/* XXX if tile, subtract first s, t of tile to normalize for now */
if (en_tramtile) {
	s -= im->s << TI_FRAC_SHFT;
	t -= im->t << TI_FRAC_SHFT;
	}
/* get pointer to tile */
	tile = &mipmap[level];
/* shift coordinate by level */
	s = s >> level;
	t = t >> level;
/* extract fractional coordinates */
	sf = s & TI_FRAC_MASK;
	tf = t & TI_FRAC_MASK;
/* extract integer coordinates */
	s = s >> TI_FRAC_SHFT;
	t = t >> TI_FRAC_SHFT;
/* increment for tile coords and clamp */
	si = s + 1;
	if (s < 0) {
/*
printf("s underflow tc->s %d im->s %d level %d s %d t->s %d.\n",
	sin, im->s, level, s, tile->s);
*/
		s = 0;
		si = s;
		sf = 0;
	} else if (s >= tile->s-1) {
/*
printf("s overflow tc->s %d im->s %d level %d s %d t->s %d.\n",
	sin, im->s, level, s, tile->s);
*/
		s = tile->s-1;
		si = s;
		sf = 0;
		}
	ti = t + 1;
	if (t < 0) {
		t = 0;
		ti = t;
		tf = 0;
	} else if (t >= tile->t-1) {
		t = tile->t-1;
		ti = t;
		tf = 0;
		}
/* construct array of texel coordinates of tile */
	s4[0] = s;	t4[0] = t;
	s4[1] = si;	t4[1] = t;
	s4[2] = s;	t4[2] = ti;
	s4[3] = si;	t4[3] = ti;
/* get tile of texels */
	if (en_tramtile) tram_tile( tile, s4, t4, tex4);
/* XXX 4/4/4/4 textures for now */
/* XXXX bypass tram and directly read image data for debugging */
	else {
struct Image *im = &tex_image[0];
char *tex;
int i;
	for (i=0; i<4; i++) {
		tex = im->base + (t4[i] * im->lsize) + (s4[i] << 1);
		tex4[i] = *(unsigned short *)tex;
		}
	} /* end read image direct */
/* bilinear filter tile */
if (en_tf_bilinear) {
	unpack_colora4( tex4[0], r0, g0, b0, a0);
	unpack_colora4( tex4[1], r1, g1, b1, a1);
	unpack_colora4( tex4[2], r2, g2, b2, a2);
	unpack_colora4( tex4[3], r3, g3, b3, a3);
/* linearly interpolate each channel */
	c0 = filter_color( r0, r1, sf);
	c1 = filter_color( r2, r3, sf);
	tp->r = filter_color( c0, c1, tf);
	c0 = filter_color( g0, g1, sf);
	c1 = filter_color( g2, g3, sf);
	tp->g = filter_color( c0, c1, tf);
	c0 = filter_color( b0, b1, sf);
	c1 = filter_color( b2, b3, sf);
	tp->b = filter_color( c0, c1, tf);
	c0 = filter_color( a0, a1, sf);
	c1 = filter_color( a2, a3, sf);
	tp->a = filter_color( c0, c1, tf);
} else {	 /* point sample */
	unpack_colora4( tex4[0], tp->r, tp->g, tp->b, tp->a);
	}
}
/*------------------------------*/

/*
 * Texture Memory Simulator
 */


tram_load(struct Image *im)
{
	char	*iaddr, *taddr;
	int	b, h;
	int flip;
	int	im_bytes, tr_bytes;

	txlsize = IM_BYTE(im->type);

	/* XXX do precision mask later */
	iaddr = (im->t * im->lsize) + (im->s * txlsize) + im->base;
	im_bytes = im->w * txlsize;
	tr_bytes = im_bytes / TRAM_LSIZE;
	tr_bytes = tr_bytes * TRAM_LSIZE;
	if (im_bytes > tr_bytes) tr_bytes += TRAM_LSIZE;

	taddr = &(tram[im->addr]);
	for (h=0; h<im->h; h++) {
		flip =  (h & 1) << 2;
		for (b=0; b<im_bytes; b++) 
			 *(taddr+(b^flip)) = *(iaddr+b);
		/* pick up trailing bytes */
		for (b=im_bytes; b<tr_bytes; b++)
			 *(taddr+(b^flip)) = 0;
		iaddr += im->lsize;
		taddr += tr_bytes;
		}

/* save tile attributes in top mipmap */
mipmap[0].s = im->w;
mipmap[0].t = im->h;
mipmap[0].w = tr_bytes / txlsize;
mipmap[0].addr = im->addr;
max_mipmap = MM_MAX_LEVEL;

if (en_tc_lod && en_mipmap) {/* generate mip map for this tile */
int level;
ubyte *taddr, *saddr;
int s, t, si, ti;
int s4[4];
int t4[4];
int tex4[4];
int r0, g0, b0, a0, r1, g1, b1, a1;
int texel;
int i;

for (level=1; level<=MM_MAX_LEVEL; level++) {
	mipmap[level].addr = mipmap[level-1].addr +
		mipmap[level-1].w * txlsize * mipmap[level-1].t;
	taddr = &(tram[ mipmap[level].addr ]);
/* downfilter by 2X, bump odd size */
	mipmap[level].s = (mipmap[0].s + (1<<(level-1))) >> level;
	mipmap[level].t = (mipmap[0].t + (1<<(level-1))) >> level;
/* width must be a multiple of 4 texels */
	mipmap[level].w = ((mipmap[level].s + 3) >> 2) << 2;
	for (t=0; t<mipmap[level-1].t; t+=2) {
		flip =  (t & 2) << 1;	/* invert bit 4 on odd line */
		ti = t + 1;
		if (ti >= mipmap[level-1].t) ti = t;
		saddr = taddr;
		taddr += mipmap[level].w * txlsize;
	for (s=0; s<mipmap[level-1].s; s+=2) {
		si = s + 1;
		if (si >= mipmap[level-1].s) si = s;
		s4[0] = s;	t4[0] = t;
		s4[1] = si;	t4[1] = t;
		s4[2] = s;	t4[2] = ti;
		s4[3] = si;	t4[3] = ti;
		tram_tile( &mipmap[level-1], s4, t4, tex4);
		r1 = g1 = b1 = a1 = 0;
		for (i=0; i<4; i++) {
			unpack_colora4( tex4[i], r0, g0, b0, a0);
			r1 += r0; g1 += g0; b1 += b0; a1 += a0; 
			}
		r1 = r1 >> 2; g1 = g1 >> 2; b1 = b1 >> 2; a1 = a1 >> 2; 
		texel = pack_colora4( r1, g1, b1, a1);
		*(short *)((int)saddr^flip) = texel;
		saddr += txlsize;
		} /* end s */
		} /* end t */
	if (mipmap[level].s <= MM_MIN_SIZE &&
		mipmap[level].t <= MM_MIN_SIZE) {
			max_mipmap = level;
			break;
			}
	} /* end level */
}/* end generate mipmap */
}
/*----------------------------------------------------*/
tram_tile(struct Tile *tile, int *s, int *t, unsigned long *texel)
{
	int		i;
	int		bank, row;
	unsigned int	addr;
	int		overlap;
	unsigned char	r, g, b, a;
	unsigned long	tex;
	struct Image *im;

	/* XXX 4 16 bit 4/4/4/4 samples for now */
	for (i=0; i<4; i++) {

		/* bank and row indexing */
		bank = (s[i] & 0x3 ^ ((t[i] & 0x1) << 1)) << 1;
		row = ((t[i] * tile->w + s[i]) * txlsize) / TRAM_LSIZE;
		addr = tile->addr + row * TRAM_WSIZE + bank;

		overlap = (i == 0) ? bank : overlap ^ bank;

		/* XXX sort for output texture quad 0:0,0 1:1,0 2:1,0 */
		/* for now, out sort in the same order as in sort */
if ((addr < 0) || (addr > TRAM_SIZE-1))
printf("tram addr error.\n");
else
		texel[i] = (tram[addr] << 8) | tram[addr+1];

#ifdef 0
printf("%1d: s:%3d t:%3d bank:%3d row:%3d addr:%3d tex:%4x\n",
 i, s[i], t[i], bank, row, addr, tex);
#endif
	}

	if (overlap)
		printf("TRAM bank overlap\n");

}

tram_span()
{
}