1 // license:BSD-3-Clause
2 // copyright-holders:Ryan Holtz
3 /******************************************************************************
4 
5 
6     SGI/Nintendo Reality Display Texture Fetch Unit (TF)
7     -------------------
8 
9     by Ryan Holtz
10     based on initial C code by Ville Linde
11     contains additional improvements from angrylion, Ziggy, Gonetz and Orkin
12 
13 
14 ******************************************************************************/
15 
16 #include "emu.h"
17 #include "includes/n64.h"
18 #include "video/rdptpipe.h"
19 #include "video/n64.h"
20 #include "video/rgbutil.h"
21 
22 #define RELATIVE(x, y)  ((((x) >> 3) - (y)) << 3) | (x & 7);
23 
set_machine(running_machine & machine)24 void n64_texture_pipe_t::set_machine(running_machine &machine)
25 {
26 	n64_state* state = machine.driver_data<n64_state>();
27 
28 	m_rdp = state->rdp();
29 
30 	for(int32_t i = 0; i < 0x10000; i++)
31 	{
32 		m_expand_16to32_table[i] = color_t((i & 1) ? 0xff : 0x00, m_rdp->m_replicated_rgba[(i >> 11) & 0x1f], m_rdp->m_replicated_rgba[(i >>  6) & 0x1f], m_rdp->m_replicated_rgba[(i >>  1) & 0x1f]);
33 	}
34 
35 	for(uint32_t i = 0; i < 0x80000; i++)
36 	{
37 		if (i & 0x40000)
38 		{
39 			m_lod_lookup[i] = 0x7fff;
40 		}
41 		else if (i & 0x20000)
42 		{
43 			m_lod_lookup[i] = 0x8000;
44 		}
45 		else
46 		{
47 			if ((i & 0x18000) == 0x8000)
48 			{
49 				m_lod_lookup[i] = 0x7fff;
50 			}
51 			else if ((i & 0x18000) == 0x10000)
52 			{
53 				m_lod_lookup[i] = 0x8000;
54 			}
55 			else
56 			{
57 				m_lod_lookup[i] = i & 0xffff;
58 			}
59 		}
60 	}
61 
62 	m_st2_add.set(1, 0, 1, 0);
63 	m_v1.set(1, 1, 1, 1);
64 }
65 
mask(rgbaint_t & sstt,const n64_tile_t & tile)66 void n64_texture_pipe_t::mask(rgbaint_t& sstt, const n64_tile_t& tile)
67 {
68 	uint32_t s_mask_bits = m_maskbits_table[tile.mask_s];
69 	uint32_t t_mask_bits = m_maskbits_table[tile.mask_t];
70 	rgbaint_t maskbits(s_mask_bits, s_mask_bits, t_mask_bits, t_mask_bits);
71 
72 	rgbaint_t do_wrap(sstt);
73 	do_wrap.sra(tile.wrapped_mask);
74 	do_wrap.and_reg(m_v1);
75 	do_wrap.cmpeq(m_v1);
76 	do_wrap.and_reg(tile.mm);
77 
78 	rgbaint_t wrapped(sstt);
79 	wrapped.xor_reg(do_wrap);
80 	wrapped.and_reg(maskbits);
81 	wrapped.and_reg(tile.mask);
82 	sstt.and_reg(tile.invmask);
83 	sstt.or_reg(wrapped);
84 }
85 
shift_cycle(rgbaint_t & st,const n64_tile_t & tile)86 rgbaint_t n64_texture_pipe_t::shift_cycle(rgbaint_t& st, const n64_tile_t& tile)
87 {
88 	st.sign_extend(0x00008000, 0xffff8000);
89 	st.sra(tile.rshift);
90 	st.shl(tile.lshift);
91 
92 	rgbaint_t maxst(st);
93 	maxst.sra_imm(3);
94 	rgbaint_t maxst_eq(maxst);
95 	maxst.cmpgt(tile.sth);
96 	maxst_eq.cmpeq(tile.sth);
97 	maxst.or_reg(maxst_eq);
98 
99 	rgbaint_t stlsb(st);
100 	stlsb.and_imm(7);
101 
102 	st.sra_imm(3);
103 	st.sub(tile.stl);
104 	st.shl_imm(3);
105 	st.or_reg(stlsb);
106 
107 	return maxst;
108 }
109 
shift_copy(rgbaint_t & st,const n64_tile_t & tile)110 inline void n64_texture_pipe_t::shift_copy(rgbaint_t& st, const n64_tile_t& tile)
111 {
112 	st.shr(tile.rshift);
113 	st.shl(tile.lshift);
114 }
115 
clamp_cycle(rgbaint_t & st,rgbaint_t & stfrac,rgbaint_t & maxst,const int32_t tilenum,const n64_tile_t & tile,rdp_span_aux * userdata)116 void n64_texture_pipe_t::clamp_cycle(rgbaint_t& st, rgbaint_t& stfrac, rgbaint_t& maxst, const int32_t tilenum, const n64_tile_t& tile, rdp_span_aux* userdata)
117 {
118 	rgbaint_t not_clamp(tile.clamp_st);
119 	not_clamp.xor_imm(0xffffffff);
120 
121 	rgbaint_t highbit_mask(0x10000, 0x10000, 0x10000, 0x10000);
122 	rgbaint_t highbit(st);
123 	highbit.and_reg(highbit_mask);
124 	highbit.cmpeq(highbit_mask);
125 
126 	rgbaint_t not_highbit(highbit);
127 	not_highbit.xor_imm(0xffffffff);
128 
129 	rgbaint_t not_maxst(maxst);
130 	not_maxst.xor_imm(0xffffffff);
131 	not_maxst.and_reg(not_highbit);
132 	not_maxst.or_reg(not_clamp);
133 
134 	rgbaint_t shifted_st(st);
135 	shifted_st.sign_extend(0x00010000, 0xffff0000);
136 	shifted_st.shr_imm(5);
137 	shifted_st.and_imm(0x1fff);
138 	shifted_st.and_reg(not_maxst);
139 	stfrac.and_reg(not_maxst);
140 
141 	rgbaint_t clamp_diff(userdata->m_clamp_diff[tilenum]);
142 	clamp_diff.and_reg(tile.clamp_st);
143 	clamp_diff.and_reg(maxst);
144 
145 	st.set(shifted_st);
146 	st.or_reg(clamp_diff);
147 }
148 
clamp_cycle_light(rgbaint_t & st,rgbaint_t & maxst,const int32_t tilenum,const n64_tile_t & tile,rdp_span_aux * userdata)149 void n64_texture_pipe_t::clamp_cycle_light(rgbaint_t& st, rgbaint_t& maxst, const int32_t tilenum, const n64_tile_t& tile, rdp_span_aux* userdata)
150 {
151 	rgbaint_t not_clamp(tile.clamp_st);
152 	not_clamp.xor_imm(0xffffffff);
153 
154 	rgbaint_t highbit_mask(0x10000, 0x10000, 0x10000, 0x10000);
155 	rgbaint_t highbit(st);
156 	highbit.and_reg(highbit_mask);
157 	highbit.cmpeq(highbit_mask);
158 
159 	rgbaint_t not_highbit(highbit);
160 	not_highbit.xor_imm(0xffffffff);
161 
162 	rgbaint_t not_maxst(maxst);
163 	not_maxst.xor_imm(0xffffffff);
164 	not_maxst.and_reg(not_highbit);
165 	not_maxst.or_reg(not_clamp);
166 
167 	rgbaint_t shifted_st(st);
168 	shifted_st.sign_extend(0x00010000, 0xffff0000);
169 	shifted_st.shr_imm(5);
170 	shifted_st.and_imm(0x1fff);
171 	shifted_st.and_reg(not_maxst);
172 
173 	rgbaint_t clamp_diff(userdata->m_clamp_diff[tilenum]);
174 	clamp_diff.and_reg(tile.clamp_st);
175 	clamp_diff.and_reg(maxst);
176 
177 	st.set(shifted_st);
178 	st.or_reg(clamp_diff);
179 }
180 
cycle_nearest(color_t * TEX,color_t * prev,int32_t SSS,int32_t SST,uint32_t tilenum,uint32_t cycle,rdp_span_aux * userdata,const rdp_poly_state & object)181 void n64_texture_pipe_t::cycle_nearest(color_t* TEX, color_t* prev, int32_t SSS, int32_t SST, uint32_t tilenum, uint32_t cycle, rdp_span_aux* userdata, const rdp_poly_state& object)
182 {
183 	const n64_tile_t& tile = object.m_tiles[tilenum];
184 	const uint32_t index = (tile.format << 4) | (tile.size << 2) | ((uint32_t) object.m_other_modes.en_tlut << 1) | (uint32_t) object.m_other_modes.tlut_type;
185 
186 	rgbaint_t st(0, SSS, 0, SST);
187 	rgbaint_t maxst = shift_cycle(st, tile);
188 	clamp_cycle_light(st, maxst, tilenum, tile, userdata);
189 	mask(st, tile);
190 
191 	uint32_t tbase = tile.tmem + ((tile.line * st.get_b32()) & 0x1ff);
192 
193 	rgbaint_t t0;
194 	((this)->*(m_texel_fetch[index]))(t0, st.get_r32(), st.get_b32(), tbase, tile.palette, userdata);
195 	if (object.m_other_modes.convert_one && cycle)
196 	{
197 		t0.set(*prev);
198 	}
199 
200 	t0.sign_extend(0x00000100, 0xffffff00);
201 
202 	rgbaint_t k1r(m_rdp->get_k1());
203 	k1r.mul_imm(t0.get_r32());
204 
205 	TEX->set(m_rdp->get_k023());
206 	TEX->mul_imm(t0.get_g32());
207 	TEX->add(k1r);
208 	TEX->add_imm(0x80);
209 	TEX->shr_imm(8);
210 	TEX->add_imm(t0.get_b32());
211 	TEX->and_imm(0x1ff);
212 }
213 
cycle_nearest_lerp(color_t * TEX,color_t * prev,int32_t SSS,int32_t SST,uint32_t tilenum,uint32_t cycle,rdp_span_aux * userdata,const rdp_poly_state & object)214 void n64_texture_pipe_t::cycle_nearest_lerp(color_t* TEX, color_t* prev, int32_t SSS, int32_t SST, uint32_t tilenum, uint32_t cycle, rdp_span_aux* userdata, const rdp_poly_state& object)
215 {
216 	const n64_tile_t& tile = object.m_tiles[tilenum];
217 	const uint32_t index = (tile.format << 4) | (tile.size << 2) | ((uint32_t) object.m_other_modes.en_tlut << 1) | (uint32_t) object.m_other_modes.tlut_type;
218 
219 	rgbaint_t st(0, SSS, 0, SST);
220 	rgbaint_t maxst = shift_cycle(st, tile);
221 	clamp_cycle_light(st, maxst, tilenum, tile, userdata);
222 	mask(st, tile);
223 
224 	uint32_t tbase = tile.tmem + ((tile.line * st.get_b32()) & 0x1ff);
225 
226 	((this)->*(m_texel_fetch[index]))(*TEX, st.get_r32(), st.get_b32(), tbase, tile.palette, userdata);
227 }
228 
cycle_linear(color_t * TEX,color_t * prev,int32_t SSS,int32_t SST,uint32_t tilenum,uint32_t cycle,rdp_span_aux * userdata,const rdp_poly_state & object)229 void n64_texture_pipe_t::cycle_linear(color_t* TEX, color_t* prev, int32_t SSS, int32_t SST, uint32_t tilenum, uint32_t cycle, rdp_span_aux* userdata, const rdp_poly_state& object)
230 {
231 	const n64_tile_t& tile = object.m_tiles[tilenum];
232 	const uint32_t index = (tile.format << 4) | (tile.size << 2) | ((uint32_t) object.m_other_modes.en_tlut << 1) | (uint32_t) object.m_other_modes.tlut_type;
233 
234 	rgbaint_t st(0, SSS, 0, SST);
235 	rgbaint_t maxst = shift_cycle(st, tile);
236 
237 	clamp_cycle_light(st, maxst, tilenum, tile, userdata);
238 
239 	mask(st, tile);
240 
241 	const uint32_t tbase = tile.tmem + ((tile.line * st.get_b32()) & 0x1ff);
242 
243 	rgbaint_t t0;
244 	((this)->*(m_texel_fetch[index]))(t0, st.get_r32(), st.get_b32(), tbase, tile.palette, userdata);
245 	if (object.m_other_modes.convert_one && cycle)
246 	{
247 		t0.set(*prev);
248 	}
249 
250 	t0.sign_extend(0x00000100, 0xffffff00);
251 
252 	rgbaint_t k1r(m_rdp->get_k1());
253 	k1r.mul_imm(t0.get_r32());
254 
255 	TEX->set(m_rdp->get_k023());
256 	TEX->mul_imm(t0.get_g32());
257 	TEX->add(k1r);
258 	TEX->add_imm(0x80);
259 	TEX->shr_imm(8);
260 	TEX->add_imm(t0.get_b32());
261 	TEX->and_imm(0x1ff);
262 }
263 
cycle_linear_lerp(color_t * TEX,color_t * prev,int32_t SSS,int32_t SST,uint32_t tilenum,uint32_t cycle,rdp_span_aux * userdata,const rdp_poly_state & object)264 void n64_texture_pipe_t::cycle_linear_lerp(color_t* TEX, color_t* prev, int32_t SSS, int32_t SST, uint32_t tilenum, uint32_t cycle, rdp_span_aux* userdata, const rdp_poly_state& object)
265 {
266 	const n64_tile_t& tile = object.m_tiles[tilenum];
267 
268 	uint32_t tpal = tile.palette;
269 	uint32_t index = (tile.format << 4) | (tile.size << 2) | ((uint32_t) object.m_other_modes.en_tlut << 1) | (uint32_t) object.m_other_modes.tlut_type;
270 
271 	rgbaint_t sstt(SSS, SSS, SST, SST);
272 	rgbaint_t maxst = shift_cycle(sstt, tile);
273 	rgbaint_t stfrac = sstt;
274 	stfrac.and_imm(0x1f);
275 
276 	clamp_cycle(sstt, stfrac, maxst, tilenum, tile, userdata);
277 
278 	sstt.add(m_st2_add);
279 
280 	mask(sstt, tile);
281 
282 	const uint32_t tbase1 = tile.tmem + ((tile.line * sstt.get_b32()) & 0x1ff);
283 	const uint32_t tbase2 = tile.tmem + ((tile.line * sstt.get_g32()) & 0x1ff);
284 
285 	bool upper = ((stfrac.get_r32() + stfrac.get_b32()) >= 0x20);
286 
287 	rgbaint_t invstf(stfrac);
288 	if (upper)
289 	{
290 		invstf.subr_imm(0x20);
291 		invstf.shl_imm(3);
292 	}
293 
294 	stfrac.shl_imm(3);
295 
296 	bool center = (stfrac.get_r32() == 0x10) && (stfrac.get_b32() == 0x10) && object.m_other_modes.mid_texel;
297 
298 	rgbaint_t t2;
299 	((this)->*(m_texel_fetch[index]))(*TEX, sstt.get_a32(), sstt.get_b32(), tbase1, tpal, userdata);
300 	((this)->*(m_texel_fetch[index]))(t2, sstt.get_r32(), sstt.get_g32(), tbase2, tpal, userdata);
301 
302 	if (!center)
303 	{
304 		if (upper)
305 		{
306 			rgbaint_t t3;
307 			((this)->*(m_texel_fetch[index]))(t3, sstt.get_a32(), sstt.get_g32(), tbase2, tpal, userdata);
308 
309 			TEX->sub(t3);
310 			t2.sub(t3);
311 
312 			TEX->mul_imm(invstf.get_b32());
313 			t2.mul_imm(invstf.get_r32());
314 
315 			TEX->add(t2);
316 			TEX->add_imm(0x0080);
317 			TEX->sra_imm(8);
318 			TEX->add(t3);
319 		}
320 		else
321 		{
322 			rgbaint_t t0;
323 			((this)->*(m_texel_fetch[index]))(t0, sstt.get_r32(), sstt.get_b32(), tbase1, tpal, userdata);
324 
325 			TEX->sub(t0);
326 			t2.sub(t0);
327 
328 			TEX->mul_imm(stfrac.get_r32());
329 			t2.mul_imm(stfrac.get_b32());
330 
331 			TEX->add(t2);
332 			TEX->add_imm(0x80);
333 			TEX->sra_imm(8);
334 			TEX->add(t0);
335 		}
336 	}
337 	else
338 	{
339 		rgbaint_t t0, t3;
340 		((this)->*(m_texel_fetch[index]))(t0, sstt.get_r32(), sstt.get_b32(), tbase1, tpal, userdata);
341 		((this)->*(m_texel_fetch[index]))(t3, sstt.get_a32(), sstt.get_g32(), tbase2, tpal, userdata);
342 		TEX->add(t0);
343 		TEX->add(t2);
344 		TEX->add(t3);
345 		TEX->sra_imm(2);
346 	}
347 }
348 
copy(color_t * TEX,int32_t SSS,int32_t SST,uint32_t tilenum,const rdp_poly_state & object,rdp_span_aux * userdata)349 void n64_texture_pipe_t::copy(color_t* TEX, int32_t SSS, int32_t SST, uint32_t tilenum, const rdp_poly_state& object, rdp_span_aux* userdata)
350 {
351 	const n64_tile_t* tiles = object.m_tiles;
352 	const n64_tile_t& tile = tiles[tilenum];
353 
354 	rgbaint_t st(0, SSS, 0, SST);
355 	shift_copy(st, tile);
356 	rgbaint_t stlsb(st);
357 	stlsb.and_imm(7);
358 	st.shr_imm(3);
359 	st.sub(rgbaint_t(0, tile.sl, 0, tile.tl));
360 	st.shl_imm(3);
361 	st.add(stlsb);
362 	st.sign_extend(0x00010000, 0xffff0000);
363 	st.shr_imm(5);
364 	st.and_imm(0x1fff);
365 	mask(st, tile);
366 
367 	const uint32_t index = (tile.format << 4) | (tile.size << 2) | ((uint32_t) object.m_other_modes.en_tlut << 1) | (uint32_t) object.m_other_modes.tlut_type;
368 	const uint32_t tbase = tile.tmem + ((tile.line * st.get_b32()) & 0x1ff);
369 	((this)->*(m_texel_fetch[index]))(*TEX, st.get_r32(), st.get_b32(), tbase, tile.palette, userdata);
370 }
371 
lod_1cycle(int32_t * sss,int32_t * sst,const int32_t s,const int32_t t,const int32_t w,const int32_t dsinc,const int32_t dtinc,const int32_t dwinc,rdp_span_aux * userdata,const rdp_poly_state & object)372 void n64_texture_pipe_t::lod_1cycle(int32_t* sss, int32_t* sst, const int32_t s, const int32_t t, const int32_t w, const int32_t dsinc, const int32_t dtinc, const int32_t dwinc, rdp_span_aux* userdata, const rdp_poly_state& object)
373 {
374 	const int32_t nextsw = (w + dwinc) >> 16;
375 	int32_t nexts = (s + dsinc) >> 16;
376 	int32_t nextt = (t + dtinc) >> 16;
377 
378 	if (object.m_other_modes.persp_tex_en)
379 	{
380 		m_rdp->tc_div(nexts, nextt, nextsw, &nexts, &nextt);
381 	}
382 	else
383 	{
384 		m_rdp->tc_div_no_perspective(nexts, nextt, nextsw, &nexts, &nextt);
385 	}
386 
387 	userdata->m_start_span = false;
388 	userdata->m_precomp_s = nexts;
389 	userdata->m_precomp_t = nextt;
390 
391 	const int32_t lodclamp = (((*sst & 0x60000) > 0) | ((nextt & 0x60000) > 0)) || (((*sss & 0x60000) > 0) | ((nexts & 0x60000) > 0));
392 
393 	int32_t horstep = SIGN17(nexts & 0x1ffff) - SIGN17(*sss & 0x1ffff);
394 	int32_t vertstep = SIGN17(nextt & 0x1ffff) - SIGN17(*sst & 0x1ffff);
395 	if (horstep & 0x20000)
396 	{
397 		horstep = ~horstep & 0x1ffff;
398 	}
399 	if (vertstep & 0x20000)
400 	{
401 		vertstep = ~vertstep & 0x1ffff;
402 	}
403 
404 	int32_t lod = (horstep >= vertstep) ? horstep : vertstep;
405 
406 	*sss = m_lod_lookup[*sss & 0x7ffff];
407 	*sst = m_lod_lookup[*sst & 0x7ffff];
408 
409 	if ((lod & 0x4000) || lodclamp)
410 	{
411 		lod = 0x7fff;
412 	}
413 	else if (lod < object.m_misc_state.m_min_level)
414 	{
415 		lod = object.m_misc_state.m_min_level;
416 	}
417 
418 	int32_t l_tile = m_rdp->get_log2((lod >> 5) & 0xff);
419 	const bool magnify = (lod < 32);
420 	const bool distant = ((lod & 0x6000) || (l_tile >= object.m_misc_state.m_max_level));
421 
422 	uint8_t lod_fraction = ((lod << 3) >> l_tile) & 0xff;
423 
424 	if(!object.m_other_modes.sharpen_tex_en && !object.m_other_modes.detail_tex_en)
425 	{
426 		if (distant)
427 		{
428 			lod_fraction = 0xff;
429 		}
430 		else if (magnify)
431 		{
432 			lod_fraction = 0;
433 		}
434 	}
435 
436 	userdata->m_lod_fraction.set(lod_fraction, lod_fraction, lod_fraction, lod_fraction);
437 	/* FIXME: ???
438 	if(object.m_other_modes.sharpen_tex_en && magnify)
439 	{
440 	    userdata->m_lod_fraction |= 0x100;
441 	}
442 	*/
443 }
444 
lod_2cycle(int32_t * sss,int32_t * sst,const int32_t s,const int32_t t,const int32_t w,const int32_t dsinc,const int32_t dtinc,const int32_t dwinc,const int32_t prim_tile,int32_t * t1,int32_t * t2,rdp_span_aux * userdata,const rdp_poly_state & object)445 void n64_texture_pipe_t::lod_2cycle(int32_t* sss, int32_t* sst, const int32_t s, const int32_t t, const int32_t w, const int32_t dsinc, const int32_t dtinc, const int32_t dwinc, const int32_t prim_tile, int32_t* t1, int32_t* t2, rdp_span_aux* userdata, const rdp_poly_state& object)
446 {
447 	const int32_t nextsw = (w + dwinc) >> 16;
448 	int32_t nexts = (s + dsinc) >> 16;
449 	int32_t nextt = (t + dtinc) >> 16;
450 
451 	if (object.m_other_modes.persp_tex_en)
452 	{
453 		m_rdp->tc_div(nexts, nextt, nextsw, &nexts, &nextt);
454 	}
455 	else
456 	{
457 		m_rdp->tc_div_no_perspective(nexts, nextt, nextsw, &nexts, &nextt);
458 	}
459 
460 	userdata->m_start_span = false;
461 	userdata->m_precomp_s = nexts;
462 	userdata->m_precomp_t = nextt;
463 
464 	const int32_t lodclamp = (((*sst & 0x60000) > 0) | ((nextt & 0x60000) > 0)) || (((*sss & 0x60000) > 0) | ((nexts & 0x60000) > 0));
465 
466 	int32_t horstep = SIGN17(nexts & 0x1ffff) - SIGN17(*sss & 0x1ffff);
467 	int32_t vertstep = SIGN17(nextt & 0x1ffff) - SIGN17(*sst & 0x1ffff);
468 	if (horstep & 0x20000)
469 	{
470 		horstep = ~horstep & 0x1ffff;
471 	}
472 	if (vertstep & 0x20000)
473 	{
474 		vertstep = ~vertstep & 0x1ffff;
475 	}
476 
477 	int32_t lod = (horstep >= vertstep) ? horstep : vertstep;
478 
479 	*sss = m_lod_lookup[*sss & 0x7ffff];
480 	*sst = m_lod_lookup[*sst & 0x7ffff];
481 
482 	if ((lod & 0x4000) || lodclamp)
483 	{
484 		lod = 0x7fff;
485 	}
486 	else if (lod < object.m_misc_state.m_min_level)
487 	{
488 		lod = object.m_misc_state.m_min_level;
489 	}
490 
491 	int32_t l_tile = m_rdp->get_log2((lod >> 5) & 0xff);
492 	const bool magnify = (lod < 32);
493 	const bool distant = ((lod & 0x6000) || (l_tile >= object.m_misc_state.m_max_level));
494 
495 	uint8_t lod_fraction = ((lod << 3) >> l_tile) & 0xff;
496 
497 	if(!object.m_other_modes.sharpen_tex_en && !object.m_other_modes.detail_tex_en)
498 	{
499 		if (distant)
500 		{
501 			lod_fraction = 0xff;
502 		}
503 		else if (magnify)
504 		{
505 			lod_fraction = 0;
506 		}
507 	}
508 
509 	userdata->m_lod_fraction.set(lod_fraction, lod_fraction, lod_fraction, lod_fraction);
510 
511 	/* FIXME: ???
512 	if(object.m_other_modes.sharpen_tex_en && magnify)
513 	{
514 	    userdata->m_lod_fraction |= 0x100;
515 	}*/
516 
517 	if (object.m_other_modes.tex_lod_en)
518 	{
519 		if (distant)
520 		{
521 			l_tile = object.m_misc_state.m_max_level;
522 		}
523 		if (!object.m_other_modes.detail_tex_en)
524 		{
525 			*t1 = (prim_tile + l_tile) & 7;
526 			if (!(distant || (!object.m_other_modes.sharpen_tex_en && magnify)))
527 			{
528 				*t2 = (*t1 + 1) & 7;
529 			}
530 			else
531 			{
532 				*t2 = *t1; // World Driver Championship, Stunt Race 64, Beetle Adventure Racing
533 			}
534 		}
535 		else // Beetle Adventure Racing, World Driver Championship (ingame_, NFL Blitz 2001, Pilotwings
536 		{
537 			if (!magnify)
538 			{
539 				*t1 = (prim_tile + l_tile + 1);
540 			}
541 			else
542 			{
543 				*t1 = (prim_tile + l_tile);
544 			}
545 			*t1 &= 7;
546 			if (!distant && !magnify)
547 			{
548 				*t2 = (prim_tile + l_tile + 2) & 7;
549 			}
550 			else
551 			{
552 				*t2 = (prim_tile + l_tile + 1) & 7;
553 			}
554 		}
555 	}
556 }
557 
lod_2cycle_limited(int32_t * sss,int32_t * sst,const int32_t s,const int32_t t,const int32_t w,const int32_t dsinc,const int32_t dtinc,const int32_t dwinc,const int32_t prim_tile,int32_t * t1,const rdp_poly_state & object)558 void n64_texture_pipe_t::lod_2cycle_limited(int32_t* sss, int32_t* sst, const int32_t s, const int32_t t, const int32_t w, const int32_t dsinc, const int32_t dtinc, const int32_t dwinc, const int32_t prim_tile, int32_t* t1, const rdp_poly_state& object)
559 {
560 	const int32_t nextsw = (w + dwinc) >> 16;
561 	int32_t nexts = (s + dsinc) >> 16;
562 	int32_t nextt = (t + dtinc) >> 16;
563 
564 	if (object.m_other_modes.persp_tex_en)
565 	{
566 		m_rdp->tc_div(nexts, nextt, nextsw, &nexts, &nextt);
567 	}
568 	else
569 	{
570 		m_rdp->tc_div_no_perspective(nexts, nextt, nextsw, &nexts, &nextt);
571 	}
572 
573 	const int32_t lodclamp = (((*sst & 0x60000) > 0) | ((nextt & 0x60000) > 0)) || (((*sss & 0x60000) > 0) | ((nexts & 0x60000) > 0));
574 
575 	int32_t horstep = SIGN17(nexts & 0x1ffff) - SIGN17(*sss & 0x1ffff);
576 	int32_t vertstep = SIGN17(nextt & 0x1ffff) - SIGN17(*sst & 0x1ffff);
577 	if (horstep & 0x20000)
578 	{
579 		horstep = ~horstep & 0x1ffff;
580 	}
581 	if (vertstep & 0x20000)
582 	{
583 		vertstep = ~vertstep & 0x1ffff;
584 	}
585 
586 	int32_t lod = (horstep >= vertstep) ? horstep : vertstep;
587 
588 	*sss = m_lod_lookup[*sss & 0x7ffff];
589 	*sst = m_lod_lookup[*sst & 0x7ffff];
590 
591 	if ((lod & 0x4000) || lodclamp)
592 	{
593 		lod = 0x7fff;
594 	}
595 	else if (lod < object.m_misc_state.m_min_level)
596 	{
597 		lod = object.m_misc_state.m_min_level;
598 	}
599 
600 	int32_t l_tile = m_rdp->get_log2((lod >> 5) & 0xff);
601 	const bool magnify = (lod < 32);
602 	const bool distant = (lod & 0x6000) || (l_tile >= object.m_misc_state.m_max_level);
603 
604 	if (object.m_other_modes.tex_lod_en)
605 	{
606 		if (distant)
607 		{
608 			l_tile = object.m_misc_state.m_max_level;
609 		}
610 		if (!object.m_other_modes.detail_tex_en)
611 		{
612 			*t1 = (prim_tile + l_tile) & 7;
613 		}
614 		else
615 		{
616 			if (!magnify)
617 			{
618 				*t1 = (prim_tile + l_tile + 1);
619 			}
620 			else
621 			{
622 				*t1 = (prim_tile + l_tile);
623 			}
624 			*t1 &= 7;
625 		}
626 	}
627 }
628 
calculate_clamp_diffs(uint32_t prim_tile,rdp_span_aux * userdata,const rdp_poly_state & object)629 void n64_texture_pipe_t::calculate_clamp_diffs(uint32_t prim_tile, rdp_span_aux* userdata, const rdp_poly_state& object)
630 {
631 	const n64_tile_t* tiles = object.m_tiles;
632 	if (object.m_other_modes.cycle_type == CYCLE_TYPE_2)
633 	{
634 		if (object.m_other_modes.tex_lod_en)
635 		{
636 			for (int32_t start = 0; start <= 7; start++)
637 			{
638 				userdata->m_clamp_diff[start].set((tiles[start].sh >> 2) - (tiles[start].sl >> 2), (tiles[start].sh >> 2) - (tiles[start].sl >> 2), (tiles[start].th >> 2) - (tiles[start].tl >> 2), (tiles[start].th >> 2) - (tiles[start].tl >> 2));
639 			}
640 		}
641 		else
642 		{
643 			const int32_t start = prim_tile;
644 			const int32_t end = (prim_tile + 1) & 7;
645 			userdata->m_clamp_diff[start].set((tiles[start].sh >> 2) - (tiles[start].sl >> 2), (tiles[start].sh >> 2) - (tiles[start].sl >> 2), (tiles[start].th >> 2) - (tiles[start].tl >> 2), (tiles[start].th >> 2) - (tiles[start].tl >> 2));
646 			userdata->m_clamp_diff[end].set((tiles[end].sh >> 2) - (tiles[end].sl >> 2), (tiles[end].sh >> 2) - (tiles[end].sl >> 2), (tiles[end].th >> 2) - (tiles[end].tl >> 2), (tiles[end].th >> 2) - (tiles[end].tl >> 2));
647 		}
648 	}
649 	else//1-cycle or copy
650 	{
651 		userdata->m_clamp_diff[prim_tile].set((tiles[prim_tile].sh >> 2) - (tiles[prim_tile].sl >> 2), (tiles[prim_tile].sh >> 2) - (tiles[prim_tile].sl >> 2), (tiles[prim_tile].th >> 2) - (tiles[prim_tile].tl >> 2), (tiles[prim_tile].th >> 2) - (tiles[prim_tile].tl >> 2));
652 	}
653 }
654 
655 #define USE_64K_LUT (1)
656 
657 static int32_t sTexAddrSwap16[2] = { WORD_ADDR_XOR, WORD_XOR_DWORD_SWAP };
658 static int32_t sTexAddrSwap8[2] = { BYTE_ADDR_XOR, BYTE_XOR_DWORD_SWAP };
659 
fetch_rgba16_tlut0(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)660 void n64_texture_pipe_t::fetch_rgba16_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
661 {
662 	int32_t taddr = (((tbase << 2) + s) ^ sTexAddrSwap16[t & 1]) & 0x7ff;
663 
664 	uint16_t c = ((uint16_t*)userdata->m_tmem)[taddr];
665 	c = ((uint16_t*)(userdata->m_tmem + 0x800))[(c >> 8) << 2];
666 
667 #if USE_64K_LUT
668 	out.set(m_expand_16to32_table[c]);
669 #else
670 	out.set((c & 1) * 0xff, GET_HI_RGBA16_TMEM(c), GET_MED_RGBA16_TMEM(c), GET_LOW_RGBA16_TMEM(c));
671 #endif
672 }
673 
fetch_rgba16_tlut1(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)674 void n64_texture_pipe_t::fetch_rgba16_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
675 {
676 	const int32_t taddr = (((tbase << 2) + s) ^ sTexAddrSwap16[t & 1]) & 0x7ff;
677 
678 	uint16_t c = ((uint16_t*)userdata->m_tmem)[taddr];
679 	c = ((uint16_t*)(userdata->m_tmem + 0x800))[(c >> 8) << 2];
680 
681 	const uint8_t k = (c >> 8) & 0xff;
682 	out.set(c & 0xff, k, k, k);
683 }
684 
fetch_rgba16_raw(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)685 void n64_texture_pipe_t::fetch_rgba16_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
686 {
687 	const int32_t taddr = (((tbase << 2) + s) ^ sTexAddrSwap16[t & 1]) & 0x7ff;
688 
689 	const uint16_t c = ((uint16_t*)userdata->m_tmem)[taddr];
690 
691 #if USE_64K_LUT
692 	out.set(m_expand_16to32_table[c]);
693 #else
694 	out.set((c & 1) * 0xff, GET_HI_RGBA16_TMEM(c), GET_MED_RGBA16_TMEM(c), GET_LOW_RGBA16_TMEM(c));
695 #endif
696 }
697 
fetch_rgba32_tlut0(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)698 void n64_texture_pipe_t::fetch_rgba32_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
699 {
700 	const uint32_t *tc = ((uint32_t*)userdata->m_tmem);
701 	const int32_t taddr = (((tbase << 2) + s) ^ sTexAddrSwap16[t & 1]) & 0x3ff;
702 
703 	uint32_t c = tc[taddr];
704 	c = ((uint16_t*)(userdata->m_tmem + 0x800))[(c >> 24) << 2];
705 
706 #if USE_64K_LUT
707 	out.set(m_expand_16to32_table[c]);
708 #else
709 	out.set((c & 1) * 0xff, GET_HI_RGBA16_TMEM(c), GET_MED_RGBA16_TMEM(c), GET_LOW_RGBA16_TMEM(c));
710 #endif
711 }
712 
fetch_rgba32_tlut1(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)713 void n64_texture_pipe_t::fetch_rgba32_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
714 {
715 	const uint32_t *tc = ((uint32_t*)userdata->m_tmem);
716 	const int32_t taddr = (((tbase << 2) + s) ^ sTexAddrSwap16[t & 1]) & 0x3ff;
717 
718 	uint32_t c = tc[taddr];
719 	c = ((uint16_t*)(userdata->m_tmem + 0x800))[(c >> 24) << 2];
720 
721 	const uint8_t k = (c >> 8) & 0xff;
722 	out.set(c & 0xff, k, k, k);
723 }
724 
fetch_rgba32_raw(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)725 void n64_texture_pipe_t::fetch_rgba32_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
726 {
727 	const int32_t taddr = (((tbase << 2) + s) ^ sTexAddrSwap16[t & 1]) & 0x3ff;
728 
729 	const uint16_t cl = ((uint16_t*)userdata->m_tmem)[taddr];
730 	const uint16_t ch = ((uint16_t*)userdata->m_tmem)[taddr | 0x400];
731 
732 	out.set(ch & 0xff, cl >> 8, cl & 0xff, ch >> 8);
733 }
734 
fetch_nop(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)735 void n64_texture_pipe_t::fetch_nop(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata) { }
736 
fetch_yuv(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)737 void n64_texture_pipe_t::fetch_yuv(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
738 {
739 	const uint16_t *tc = ((uint16_t*)userdata->m_tmem);
740 
741 	const int32_t taddr = (((tbase << 3) + s) ^ sTexAddrSwap8[t & 1]) & 0x7ff;
742 	const int32_t taddrlow = ((taddr >> 1) ^ sTexAddrSwap16[t & 1]) & 0x3ff;
743 
744 	const uint16_t c = tc[taddrlow];
745 
746 	int32_t y = userdata->m_tmem[taddr | 0x800];
747 	int32_t u = c >> 8;
748 	int32_t v = c & 0xff;
749 
750 	v ^= 0x80; u ^= 0x80;
751 	u |= ((u & 0x80) << 1);
752 	v |= ((v & 0x80) << 1);
753 
754 	out.set(y & 0xff, y & 0xff, u & 0xff, v & 0xff);
755 }
756 
fetch_ci4_tlut0(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)757 void n64_texture_pipe_t::fetch_ci4_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
758 {
759 	const uint8_t *tc = userdata->m_tmem;
760 	const int32_t taddr = ((((tbase << 4) + s) >> 1) ^ sTexAddrSwap8[t & 1]) & 0x7ff;
761 
762 	const uint8_t p = (s & 1) ? (tc[taddr] & 0xf) : (tc[taddr] >> 4);
763 	const uint16_t c = ((uint16_t*)(userdata->m_tmem + 0x800))[((tpal << 4) | p) << 2];
764 
765 #if USE_64K_LUT
766 	out.set(m_expand_16to32_table[c]);
767 #else
768 	out.set((c & 1) * 0xff, GET_HI_RGBA16_TMEM(c), GET_MED_RGBA16_TMEM(c), GET_LOW_RGBA16_TMEM(c));
769 #endif
770 }
771 
fetch_ci4_tlut1(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)772 void n64_texture_pipe_t::fetch_ci4_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
773 {
774 	const uint8_t *tc = userdata->m_tmem;
775 	int32_t taddr = ((((tbase << 4) + s) >> 1) ^ sTexAddrSwap8[t & 1]) & 0x7ff;
776 
777 	const uint8_t p = (s & 1) ? (tc[taddr] & 0xf) : (tc[taddr] >> 4);
778 	const uint16_t c = ((uint16_t*)(userdata->m_tmem + 0x800))[((tpal << 4) | p) << 2];
779 
780 	const uint8_t k = (c >> 8) & 0xff;
781 	out.set(c & 0xff, k, k, k);
782 }
783 
fetch_ci4_raw(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)784 void n64_texture_pipe_t::fetch_ci4_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
785 {
786 	const uint8_t *tc = userdata->m_tmem;
787 	const int32_t taddr = ((((tbase << 4) + s) >> 1) ^ sTexAddrSwap8[t & 1]) & 0xfff;
788 
789 	uint8_t p = (s & 1) ? (tc[taddr] & 0xf) : (tc[taddr] >> 4);
790 	p = (tpal << 4) | p;
791 
792 	out.set(p, p, p, p);
793 }
794 
fetch_ci8_tlut0(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)795 void n64_texture_pipe_t::fetch_ci8_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
796 {
797 	const uint8_t *tc = userdata->m_tmem;
798 	const int32_t taddr = (((tbase << 3) + s) ^ sTexAddrSwap8[t & 1]) & 0x7ff;
799 
800 	const uint8_t p = tc[taddr];
801 	const uint16_t c = ((uint16_t*)(userdata->m_tmem + 0x800))[p << 2];
802 
803 #if USE_64K_LUT
804 	out.set(m_expand_16to32_table[c]);
805 #else
806 	out.set((c & 1) * 0xff, GET_HI_RGBA16_TMEM(c), GET_MED_RGBA16_TMEM(c), GET_LOW_RGBA16_TMEM(c));
807 #endif
808 }
809 
fetch_ci8_tlut1(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)810 void n64_texture_pipe_t::fetch_ci8_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
811 {
812 	const uint8_t *tc = userdata->m_tmem;
813 	const int32_t taddr = (((tbase << 3) + s) ^ sTexAddrSwap8[t & 1]) & 0x7ff;
814 
815 	const uint8_t p = tc[taddr];
816 	const uint16_t c = ((uint16_t*)(userdata->m_tmem + 0x800))[p << 2];
817 
818 	const uint8_t k = (c >> 8) & 0xff;
819 	out.set(c & 0xff, k, k, k);
820 }
821 
fetch_ci8_raw(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)822 void n64_texture_pipe_t::fetch_ci8_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
823 {
824 	const uint8_t *tc = userdata->m_tmem;
825 	const int32_t taddr = (((tbase << 3) + s) ^ sTexAddrSwap8[t & 1]) & 0xfff;
826 
827 	const uint8_t p = tc[taddr];
828 	out.set(p, p, p, p);
829 }
830 
fetch_ia4_tlut0(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)831 void n64_texture_pipe_t::fetch_ia4_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
832 {
833 	const uint8_t *tc = userdata->m_tmem;
834 	const int32_t taddr = ((((tbase << 4) + s) >> 1) ^ sTexAddrSwap8[t & 1]) & 0x7ff;
835 
836 	const uint8_t p = ((s) & 1) ? (tc[taddr] & 0xf) : (tc[taddr] >> 4);
837 	const uint16_t c = ((uint16_t*)(userdata->m_tmem + 0x800))[((tpal << 4) | p) << 2];
838 
839 #if USE_64K_LUT
840 	out.set(m_expand_16to32_table[c]);
841 #else
842 	out.set((c & 1) * 0xff, GET_HI_RGBA16_TMEM(c), GET_MED_RGBA16_TMEM(c), GET_LOW_RGBA16_TMEM(c));
843 #endif
844 }
845 
fetch_ia4_tlut1(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)846 void n64_texture_pipe_t::fetch_ia4_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
847 {
848 	const uint8_t *tc = userdata->m_tmem;
849 	const int32_t taddr = ((((tbase << 4) + s) >> 1) ^ sTexAddrSwap8[t & 1]) & 0x7ff;
850 
851 	const uint8_t p = ((s) & 1) ? (tc[taddr] & 0xf) : (tc[taddr] >> 4);
852 	const uint16_t c = ((uint16_t*)(userdata->m_tmem + 0x800))[((tpal << 4) | p) << 2];
853 
854 	const uint8_t k = (c >> 8) & 0xff;
855 	out.set(c & 0xff, k, k, k);
856 }
857 
fetch_ia4_raw(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)858 void n64_texture_pipe_t::fetch_ia4_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
859 {
860 	const uint8_t *tc = userdata->m_tmem;
861 	const int32_t taddr = ((((tbase << 4) + s) >> 1) ^ sTexAddrSwap8[t & 1]) & 0xfff;
862 
863 	const uint8_t p = ((s) & 1) ? (tc[taddr] & 0xf) : (tc[taddr] >> 4);
864 	uint8_t i = p & 0xe;
865 	i = (i << 4) | (i << 1) | (i >> 2);
866 
867 	out.set((p & 1) * 0xff, i, i, i);
868 }
869 
fetch_ia8_tlut0(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)870 void n64_texture_pipe_t::fetch_ia8_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
871 {
872 	const uint8_t *tc = userdata->m_tmem;
873 	const int32_t taddr = (((tbase << 3) + s) ^ sTexAddrSwap8[t & 1]) & 0x7ff;
874 
875 	const uint8_t p = tc[taddr];
876 	const uint16_t c = ((uint16_t*)(userdata->m_tmem + 0x800))[p << 2];
877 
878 #if USE_64K_LUT
879 	out.set(m_expand_16to32_table[c]);
880 #else
881 	out.set((c & 1) * 0xff, GET_HI_RGBA16_TMEM(c), GET_MED_RGBA16_TMEM(c), GET_LOW_RGBA16_TMEM(c));
882 #endif
883 }
884 
fetch_ia8_tlut1(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)885 void n64_texture_pipe_t::fetch_ia8_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
886 {
887 	const uint8_t *tc = userdata->m_tmem;
888 	const int32_t taddr = (((tbase << 3) + s) ^ sTexAddrSwap8[t & 1]) & 0x7ff;
889 
890 	const uint8_t p = tc[taddr];
891 	const uint16_t c = ((uint16_t*)(userdata->m_tmem + 0x800))[p << 2];
892 
893 	const uint8_t k = (c >> 8) & 0xff;
894 	out.set(c & 0xff, k, k, k);
895 }
896 
fetch_ia8_raw(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)897 void n64_texture_pipe_t::fetch_ia8_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
898 {
899 	const uint8_t *tc = userdata->m_tmem;
900 	const int32_t taddr = (((tbase << 3) + s) ^ sTexAddrSwap8[t & 1]) & 0xfff;
901 
902 	const uint8_t p = tc[taddr];
903 	uint8_t i = p & 0xf0;
904 	i |= (i >> 4);
905 
906 	out.set(((p << 4) | (p & 0xf)) & 0xff, i, i, i);
907 }
908 
fetch_ia16_tlut0(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)909 void n64_texture_pipe_t::fetch_ia16_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
910 {
911 	const uint16_t *tc = ((uint16_t*)userdata->m_tmem);
912 	const int32_t taddr = (((tbase << 2) + s) ^ sTexAddrSwap16[t & 1]) & 0x3ff;
913 
914 	uint16_t c = tc[taddr];
915 	c = ((uint16_t*)(userdata->m_tmem + 0x800))[(c >> 8) << 2];
916 
917 #if USE_64K_LUT
918 	out.set(m_expand_16to32_table[c]);
919 #else
920 	out.set((c & 1) * 0xff, GET_HI_RGBA16_TMEM(c), GET_MED_RGBA16_TMEM(c), GET_LOW_RGBA16_TMEM(c));
921 #endif
922 }
923 
fetch_ia16_tlut1(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)924 void n64_texture_pipe_t::fetch_ia16_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
925 {
926 	const uint16_t *tc = ((uint16_t*)userdata->m_tmem);
927 	const int32_t taddr = (((tbase << 2) + s) ^ sTexAddrSwap16[t & 1]) & 0x3ff;
928 
929 	uint16_t c = tc[taddr];
930 	c = ((uint16_t*)(userdata->m_tmem + 0x800))[(c >> 8) << 2];
931 
932 	const uint8_t k = (c >> 8) & 0xff;
933 	out.set(c & 0xff, k, k, k);
934 }
935 
fetch_ia16_raw(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)936 void n64_texture_pipe_t::fetch_ia16_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
937 {
938 	const uint16_t *tc = ((uint16_t*)userdata->m_tmem);
939 	const int32_t taddr = (((tbase << 2) + s) ^ sTexAddrSwap16[t & 1]) & 0x7ff;
940 
941 	const uint16_t c = tc[taddr];
942 	const uint8_t i = (c >> 8);
943 	out.set(c & 0xff, i, i, i);
944 }
945 
fetch_i4_tlut0(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)946 void n64_texture_pipe_t::fetch_i4_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
947 {
948 	const uint8_t *tc = userdata->m_tmem;
949 	const int32_t taddr = ((((tbase << 4) + s) >> 1) ^ sTexAddrSwap8[t & 1]) & 0x7ff;
950 
951 	const uint8_t byteval = tc[taddr];
952 	const uint8_t c = ((s & 1)) ? (byteval & 0xf) : ((byteval >> 4) & 0xf);
953 	const uint16_t k = ((uint16_t*)(userdata->m_tmem + 0x800))[((tpal << 4) | c) << 2];
954 
955 #if USE_64K_LUT
956 	out.set(m_expand_16to32_table[k]);
957 #else
958 	out.set((c & 1) * 0xff, GET_HI_RGBA16_TMEM(c), GET_MED_RGBA16_TMEM(c), GET_LOW_RGBA16_TMEM(c));
959 #endif
960 }
961 
fetch_i4_tlut1(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)962 void n64_texture_pipe_t::fetch_i4_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
963 {
964 	const uint8_t *tc = userdata->m_tmem;
965 	const int32_t taddr = ((((tbase << 4) + s) >> 1) ^ sTexAddrSwap8[t & 1]) & 0x7ff;
966 
967 	const uint8_t byteval = tc[taddr];
968 	const uint8_t c = ((s & 1)) ? (byteval & 0xf) : ((byteval >> 4) & 0xf);
969 	const uint16_t k = ((uint16_t*)(userdata->m_tmem + 0x800))[((tpal << 4) | c) << 2];
970 
971 	const uint8_t i = (k >> 8) & 0xff;
972 	out.set(k & 0xff, i, i, i);
973 }
974 
fetch_i4_raw(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)975 void n64_texture_pipe_t::fetch_i4_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
976 {
977 	const uint8_t *tc = userdata->m_tmem;
978 	const int32_t taddr = ((((tbase << 4) + s) >> 1) ^ sTexAddrSwap8[t & 1]) & 0xfff;
979 
980 	const uint8_t byteval = tc[taddr];
981 	uint8_t c = ((s & 1)) ? (byteval & 0xf) : ((byteval >> 4) & 0xf);
982 	c |= (c << 4);
983 
984 	out.set(c, c, c, c);
985 }
986 
fetch_i8_tlut0(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)987 void n64_texture_pipe_t::fetch_i8_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
988 {
989 	const uint8_t *tc = userdata->m_tmem;
990 	const int32_t taddr = (((tbase << 3) + s) ^ sTexAddrSwap8[t & 1]) & 0x7ff;
991 
992 	const uint8_t c = tc[taddr];
993 	const uint16_t k = ((uint16_t*)(userdata->m_tmem + 0x800))[c << 2];
994 
995 #if USE_64K_LUT
996 	out.set(m_expand_16to32_table[k]);
997 #else
998 	out.set((c & 1) * 0xff, GET_HI_RGBA16_TMEM(c), GET_MED_RGBA16_TMEM(c), GET_LOW_RGBA16_TMEM(c));
999 #endif
1000 }
1001 
fetch_i8_tlut1(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)1002 void n64_texture_pipe_t::fetch_i8_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
1003 {
1004 	const uint8_t *tc = userdata->m_tmem;
1005 	const int32_t taddr = (((tbase << 3) + s) ^ sTexAddrSwap8[t & 1]) & 0x7ff;
1006 
1007 	const uint8_t c = tc[taddr];
1008 	const uint16_t k = ((uint16_t*)(userdata->m_tmem + 0x800))[c << 2];
1009 
1010 	const uint8_t i = (k >> 8) & 0xff;
1011 	out.set(k & 0xff, i, i, i);
1012 }
1013 
fetch_i8_raw(rgbaint_t & out,int32_t s,int32_t t,int32_t tbase,int32_t tpal,rdp_span_aux * userdata)1014 void n64_texture_pipe_t::fetch_i8_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata)
1015 {
1016 	const uint8_t *tc = userdata->m_tmem;
1017 	const int32_t taddr = (((tbase << 3) + s) ^ sTexAddrSwap8[t & 1]) & 0xfff;
1018 
1019 	const uint8_t c = tc[taddr];
1020 
1021 	out.set(c, c, c, c);
1022 }
1023