PANDORA: Make GLES context compatible with latest driver (FB only, no X11)
[mupen64plus-pandora.git] / source / rice_gles / src / RDP_Texture.h
CommitLineData
d07c171f 1/*
2Copyright (C) 2002 Rice1964
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18*/
19
20// Texture related ucode
21
22#include <algorithm>
23
24#include <stdlib.h>
25#include "Render.h"
26
27uint32 g_TmemFlag[16];
28void SetTmemFlag(uint32 tmemAddr, uint32 size);
29bool IsTmemFlagValid(uint32 tmemAddr);
30uint32 GetValidTmemInfoIndex(uint32 tmemAddr);
31
32void EnhanceTexture(TxtrCacheEntry *pEntry);
33void MirrorTexture(uint32 tileno, TxtrCacheEntry *pEntry);
34void LoadHiresTexture( TxtrCacheEntry &entry );
35
36
37extern TMEMLoadMapInfo g_tmemInfo0; // Info for Tmem=0
38extern TMEMLoadMapInfo g_tmemInfo1; // Info for Tmem=0x100
39
40TmemType g_Tmem;
41
42/************************************************************************/
43/* */
44/************************************************************************/
45uint32 sizeShift[4] = {2,1,0,0};
46uint32 sizeIncr[4] = {3,1,0,0};
47uint32 sizeBytes[4] = {0,1,2,4};
48
49inline uint32 Txl2Words(uint32 width, uint32 size)
50{
51 if( size == TXT_SIZE_4b )
52 return max(1, width/16);
53 else
54 return max(1, width*sizeBytes[size]/8);
55}
56
57inline uint32 CalculateImgSize(uint32 width, uint32 height, uint32 size)
58{
59 //(((width)*(height) + siz##_INCR) >> siz##_SHIFT) -1
60 return (((width)*(height) + sizeIncr[size]) >> sizeShift[size]) -1;
61}
62
63
64inline uint32 CalculateDXT(uint32 txl2words)
65{
66 //#define CALC_DXT(width, b_txl) ((2048 + TXL2WORDS(width, b_txl) - 1) / TXL2WORDS(width, b_txl))
67 if( txl2words == 0 ) return 1;
68 else return (2048+txl2words-1)/txl2words;
69}
70
71inline uint32 ReverseDXT(uint32 val, uint32 lrs, uint32 width, uint32 size)
72{
73 //#define TXL2WORDS(txls, b_txl) MAX(1, ((txls)*(b_txl)/8))
74 if( val == 0x800 ) return 1;
75
76 unsigned int low = 2047/val;
77 if( CalculateDXT(low) > val ) low++;
78 unsigned int high = 2047/(val-1);
79
80 if( low == high ) return low;
81
82 for( unsigned int i=low; i<=high; i++ )
83 {
84 if( Txl2Words(width, size) == i )
85 return i;
86 }
87
88 return (low+high)/2; //dxt = 2047 / (dxt-1);
89}
90
91// The following inline assemble routines are borrowed from glN64, I am too tired to
92// rewrite these routine by myself.
93// Rice, 02/24/2004
94
95inline void UnswapCopy( void *src, void *dest, uint32 numBytes )
96{
97#if !defined(__GNUC__) && !defined(NO_ASM)
98 __asm
99 {
100 mov ecx, 0
101 mov esi, dword ptr [src]
102 mov edi, dword ptr [dest]
103
104 mov ebx, esi
105 and ebx, 3 // ebx = number of leading bytes
106
107 cmp ebx, 0
108 jz StartDWordLoop
109 neg ebx
110 add ebx, 4
111
112 cmp ebx, [numBytes]
113 jle NotGreater
114 mov ebx, [numBytes]
115NotGreater:
116 mov ecx, ebx
117 xor esi, 3
118LeadingLoop: // Copies leading bytes, in reverse order (un-swaps)
119 mov al, byte ptr [esi]
120 mov byte ptr [edi], al
121 sub esi, 1
122 add edi, 1
123 loop LeadingLoop
124 add esi, 5
125
126StartDWordLoop:
127 mov ecx, dword ptr [numBytes]
128 sub ecx, ebx // Don't copy what's already been copied
129
130 mov ebx, ecx
131 and ebx, 3
132 // add ecx, 3 // Round up to nearest dword
133 shr ecx, 2
134
135 cmp ecx, 0 // If there's nothing to do, don't do it
136 jle StartTrailingLoop
137
138 // Copies from source to destination, bswap-ing first
139DWordLoop:
140 mov eax, dword ptr [esi]
141 bswap eax
142 mov dword ptr [edi], eax
143 add esi, 4
144 add edi, 4
145 loop DWordLoop
146StartTrailingLoop:
147 cmp ebx, 0
148 jz Done
149 mov ecx, ebx
150 xor esi, 3
151
152TrailingLoop:
153 mov al, byte ptr [esi]
154 mov byte ptr [edi], al
155 sub esi, 1
156 add edi, 1
157 loop TrailingLoop
158Done:
159 }
160#elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM)
161 asm volatile(" movl %k1, %%ebx \n"
162 " andl $3, %%ebx \n"
163 " cmpl $0, %%ebx \n"
164 " jz 2f \n"
165 " negl %%ebx \n"
166 " addl $4, %%ebx \n"
167 " cmpl %k2, %%ebx \n"
168 " jle 0f \n"
169 " movl %k2, %%ebx \n"
170 "0: \n"
171 " movl %%ebx, %%ecx \n"
172 " xor $3, %1 \n"
173 "1: \n"
174 " movb (%1), %%al \n"
175 " movb %%al, (%0) \n"
176 " sub $1, %1 \n"
177 " add $1, %0 \n"
178 " decl %%ecx \n"
179 " jne 1b \n"
180 " add $5, %1 \n"
181 "2: \n"
182 " movl %k2, %%ecx \n"
183 " subl %%ebx, %%ecx \n"
184 " movl %%ecx, %%ebx \n"
185 " andl $3, %%ebx \n"
186 " shrl $2, %%ecx \n"
187 " cmpl $0, %%ecx \n"
188 " jle 4f \n"
189 "3: \n"
190 " movl (%1), %%eax \n"
191 " bswapl %%eax \n"
192 " movl %%eax, (%0) \n"
193 " add $4, %1 \n"
194 " add $4, %0 \n"
195 " decl %%ecx \n"
196 " jne 3b \n"
197 "4: \n"
198 " cmpl $0, %%ebx \n"
199 " jz 6f \n"
200 " xor $3, %1 \n"
201 "5: \n"
202 " movb (%1), %%al \n"
203 " movb %%al, (%0) \n"
204 " sub $1, %1 \n"
205 " add $1, %0 \n"
206 " decl %%ebx \n"
207 " jne 5b \n"
208 "6: \n"
209 :"+r"(dest), "+r"(src)
210 :"r"(numBytes)
211 : "memory", "cc", "%rax", "%rbx", "%rcx"
212 );
213
214#elif !defined(NO_ASM)
215 unsigned int saveEBX;
216 asm volatile ("mov %%ebx, %2 \n"
217 "mov $0, %%ecx \n"
218 "mov %0, %%esi \n"
219 "mov %1, %%edi \n"
220
221 "mov %%esi, %%ebx \n"
222 "and $3, %%ebx \n" // ebx = number of leading bytes
223
224 "cmp $0, %%ebx \n"
225 "jz 2f \n" //jz StartDWordLoop
226 "neg %%ebx \n"
227 "add $4, %%ebx \n"
228
229 "cmp %3, %%ebx \n"
230 "jle 0f \n" //jle NotGreater
231 "mov %3, %%ebx \n"
232 "0: \n" //NotGreater:
233 "mov %%ebx, %%ecx \n"
234 "xor $3, %%esi \n"
235 "1: \n" //LeadingLoop: // Copies leading bytes, in reverse order (un-swaps)
236 "mov (%%esi), %%al \n"
237 "mov %%al, (%%edi) \n"
238 "sub $1, %%esi \n"
239 "add $1, %%edi \n"
240 "loop 1b \n" //loop LeadingLoop
241 "add $5, %%esi \n"
242
243 "2: \n" //StartDWordLoop:
244 "mov %3, %%ecx \n"
245 "sub %%ebx, %%ecx \n" // Don't copy what's already been copied
246
247 "mov %%ecx, %%ebx \n"
248 "and $3, %%ebx \n"
249 // add ecx, 3 // Round up to nearest dword
250 "shr $2, %%ecx \n"
251
252 "cmp $0, %%ecx \n" // If there's nothing to do, don't do it
253 "jle 4f \n" //jle StartTrailingLoop
254
255 // Copies from source to destination, bswap-ing first
256 "3: \n" //DWordLoop:
257 "mov (%%esi), %%eax \n"
258 "bswap %%eax \n"
259 "mov %%eax, (%%edi) \n"
260 "add $4, %%esi \n"
261 "add $4, %%edi \n"
262 "loop 3b \n" //loop DWordLoop
263 "4: \n" //StartTrailingLoop:
264 "cmp $0, %%ebx \n"
265 "jz 6f \n" //jz Done
266 "mov %%ebx, %%ecx \n"
267 "xor $3, %%esi \n"
268
269 "5: \n" //TrailingLoop:
270 "mov (%%esi), %%al \n"
271 "mov %%al, (%%edi) \n"
272 "sub $1, %%esi \n"
273 "add $1, %%edi \n"
274 "loop 5b \n" //loop TrailingLoop
275 "6: \n" //Done:
276 "mov %2, %%ebx \n"
277 :
278 : "m"(src), "m"(dest), "m"(saveEBX), "m"(numBytes)
279 : "memory", "cc", "%ecx", "%esi", "%edi", "%eax"
280 );
281#endif
282}
283
284inline void DWordInterleave( void *mem, uint32 numDWords )
285{
286#if !defined(__GNUC__) && !defined(NO_ASM)
287 __asm {
288 mov esi, dword ptr [mem]
289 mov edi, dword ptr [mem]
290 add edi, 4
291 mov ecx, dword ptr [numDWords]
292DWordInterleaveLoop:
293 mov eax, dword ptr [esi]
294 mov ebx, dword ptr [edi]
295 mov dword ptr [esi], ebx
296 mov dword ptr [edi], eax
297 add esi, 8
298 add edi, 8
299 loop DWordInterleaveLoop
300 }
301#elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM)
302 asm volatile("0: \n"
303 " movl (%0), %%eax \n"
304 " movl 8(%0), %%ebx \n"
305 " movl %%eax, 8(%0) \n"
306 " movl %%ebx, (%0) \n"
307 " add $8, %0 \n"
308 " decl %k1 \n"
309 " jne 0b \n"
310 : "+r"(mem), "+r"(numDWords)
311 :
312 : "memory", "cc", "%rax", "%rbx"
313 );
314#elif !defined(NO_ASM)
315 unsigned int saveEBX;
316 asm volatile ("mov %%ebx, %2 \n"
317 "mov %0, %%esi \n"
318 "mov %0, %%edi \n"
319 "add $4, %%edi \n"
320 "mov %1, %%ecx \n"
321 "0: \n" //DWordInterleaveLoop:
322 "mov (%%esi), %%eax \n"
323 "mov (%%edi), %%ebx \n"
324 "mov %%ebx, (%%esi) \n"
325 "mov %%eax, (%%edi) \n"
326 "add $8, %%esi \n"
327 "add $8, %%edi \n"
328 "loop 0b \n" //loop DWordInterleaveLoop
329 "mov %2, %%ebx \n"
330 :
331 : "m"(mem), "m"(numDWords), "m"(saveEBX)
332 : "memory", "cc", "%esi", "%edi", "%ecx", "%eax"
333 );
334#endif
335}
336
337inline void QWordInterleave( void *mem, uint32 numDWords )
338{
339#if !defined(__GNUC__) && !defined(NO_ASM)
340 __asm
341 {
342 // Interleave the line on the qword
343 mov esi, dword ptr [mem]
344 mov edi, dword ptr [mem]
345 add edi, 8
346 mov ecx, dword ptr [numDWords]
347 shr ecx, 1
348QWordInterleaveLoop:
349 mov eax, dword ptr [esi]
350 mov ebx, dword ptr [edi]
351 mov dword ptr [esi], ebx
352 mov dword ptr [edi], eax
353 add esi, 4
354 add edi, 4
355 mov eax, dword ptr [esi]
356 mov ebx, dword ptr [edi]
357 mov dword ptr [esi], ebx
358 mov dword ptr [edi], eax
359 add esi, 12
360 add edi, 12
361 loop QWordInterleaveLoop
362 }
363#elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM)
364 asm volatile(" shr $1, %k1 \n"
365 "0: \n"
366 " mov (%0), %%rax \n"
367 " mov 8(%0), %%rbx \n"
368 " mov %%rax, 8(%0) \n"
369 " mov %%rbx, (%0) \n"
370 " add $16, %0 \n"
371 " decl %k1 \n"
372 " jne 0b \n"
373 : "+r"(mem), "+r"(numDWords)
374 :
375 : "memory", "cc", "%rax", "%rbx"
376 );
377#elif !defined(NO_ASM) // GCC assumed
378
379 unsigned int saveEBX;
380 asm volatile("mov %%ebx, %2 \n"
381 // Interleave the line on the qword
382 "mov %0, %%esi \n"
383 "mov %0, %%edi \n"
384 "add $8, %%edi \n"
385 "mov %1, %%ecx \n"
386 "shr $1, %%ecx \n"
387 "0: \n" //QWordInterleaveLoop:
388 "mov (%%esi), %%eax \n"
389 "mov (%%edi), %%ebx \n"
390 "mov %%ebx, (%%esi) \n"
391 "mov %%eax, (%%edi) \n"
392 "add $4, %%esi \n"
393 "add $4, %%edi \n"
394 "mov (%%esi), %%eax \n"
395 "mov (%%edi), %%ebx \n"
396 "mov %%ebx, (%%esi) \n"
397 "mov %%eax, (%%edi) \n"
398 "add $12, %%esi \n"
399 "add $12, %%edi \n"
400 "loop 0b \n" //loop QWordInterleaveLoop
401 "mov %2, %%ebx \n"
402 :
403 : "m"(mem), "m"(numDWords), "m"(saveEBX)
404 : "memory", "cc", "%esi", "%edi", "%ecx", "%eax"
405 );
406#endif
407}
408
409inline uint32 swapdword( uint32 value )
410{
411#if defined(__INTEL_COMPILER) && !defined(NO_ASM)
412 __asm
413 {
414 mov eax, dword ptr [value]
415 bswap eax
416 }
417#elif defined(__GNUC__) && defined(__x86_64__) && !defined(NO_ASM)
418 asm volatile(" bswapl %k0 \n"
419 : "+r"(value)
420 :
421 :
422 );
423 return value;
424#elif defined(__GNUC__) && defined(__i386__) && !defined(NO_ASM)
425 asm volatile("bswapl %0 \n"
426 : "+r"(value)
427 :
428 :
429 );
430 return value;
431#else
432 return ((value & 0xff000000) >> 24) |
433 ((value & 0x00ff0000) >> 8) |
434 ((value & 0x0000ff00) << 8) |
435 ((value & 0x000000ff) << 24);
436#endif
437}
438
439inline uint16 swapword( uint16 value )
440{
441#if defined(__INTEL_COMPILER) && !defined(NO_ASM)
442 __asm
443 {
444 mov ax, word ptr [value]
445 xchg ah, al
446 }
447#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) && !defined(NO_ASM)
448 asm volatile("xchg %%al, %%ah \n"
449 : "+a"(value)
450 :
451 :
452 );
453 return value;
454#else
455 return ((value & 0xff00) >> 8) |
456 ((value & 0x00ff) << 8);
457#endif
458}
459
460
461void ComputeTileDimension(int mask, int clamp, int mirror, int width, uint32 &widthToCreate, uint32 &widthToLoad)
462{
463 int maskwidth = mask > 0 ? (1<<mask) : 0;
464 widthToCreate = widthToLoad = width;
465
466 if( mask > 0 )
467 {
468 if( width > maskwidth )
469 {
470 if( clamp == 0 )
471 {
472 // clamp is not used, so just use the dwTileMaskWidth as the real width
473 widthToCreate = widthToLoad = maskwidth;
474 }
475 else
476 {
477 widthToLoad = maskwidth;
478 //gti.WidthToCreate = dwTileWidth;
479 // keep the current WidthToCreate, we will do mirror/wrap
480 // during texture loading, not during rendering
481 }
482 }
483 else if( width < maskwidth )
484 {
485 // dwTileWidth < dwTileMaskWidth
486
487 if( clamp == 0 )
488 {
489 if( maskwidth%width == 0 )
490 {
491 if( (maskwidth/width)%2 == 0 || mirror == 0 )
492 {
493 // Do nothing
494 // gti.WidthToLoad = gti.WidthToCreate = gRDP.tiles[tileno].dwWidth = dwTileWidth
495 }
496 else
497 {
498 widthToCreate = maskwidth;
499 }
500 }
501 else
502 {
503 widthToCreate = maskwidth;
504 //widthToLoad = maskwidth;
505 }
506 }
507 else
508 {
509 widthToCreate = maskwidth;
510 //widthToLoad = maskwidth;
511 }
512 }
513 else // dwTileWidth == dwTileMaskWidth
514 {
515 }
516
517 // Some hacks, to limit the image size
518 if( mask >= 8 )
519 {
520 if( maskwidth / width >= 2 )
521 {
522 widthToCreate = width;
523 }
524 }
525 }
526}
527
528bool conkerSwapHack=false;
529
530bool CalculateTileSizes_method_2(int tileno, TMEMLoadMapInfo *info, TxtrInfo &gti)
531{
532 Tile &tile = gRDP.tiles[tileno];
533 Tile &loadtile = gRDP.tiles[RDP_TXT_LOADTILE];
534
535 uint32 dwPitch;
536
537 // Now Initialize the texture dimension
538 int dwTileWidth;
539 int dwTileHeight;
540 if( info->bSetBy == CMD_LOADTILE )
541 {
542 if( tile.sl >= tile.sh )
543 {
544 dwTileWidth = info->dwWidth; // From SetTImage
545 dwTileWidth = dwTileWidth << info->dwSize >> tile.dwSize;
546 }
547 else
548 {
549 dwTileWidth= tile.sh - tile.sl + 1;
550 }
551
552 if( tile.tl >= tile.th )
553 {
554 dwTileHeight= info->th - info->tl + 1;
555 }
556 else
557 {
558 dwTileHeight= tile.th - tile.tl + 1;
559 }
560 }
561 else
562 {
563 if( tile.dwMaskS == 0 || tile.bClampS )
564 {
565 dwTileWidth = tile.hilite_sh - tile.hilite_sl +1;
566 if( dwTileWidth < tile.sh - tile.sl +1 )
567 dwTileWidth = tile.sh - tile.sl +1;
568 if( dwTileWidth <= 0 )
569 {
570 DebuggerAppendMsg("Error");
571 }
572 }
573 else
574 {
575 if( tile.dwMaskS < 8 )
576 dwTileWidth = (1 << tile.dwMaskS );
577 else if( tile.dwLine )
578 {
579 dwTileWidth = (tile.dwLine<<5)>>tile.dwSize;
580 }
581 else
582 {
583 if( tile.sl <= tile.sh )
584 {
585 dwTileWidth = tile.sh - tile.sl +1;
586 }
587 else if( loadtile.sl <= loadtile.sh )
588 {
589 dwTileWidth = loadtile.sh - loadtile.sl +1;
590 }
591 else
592 {
593 dwTileWidth = tile.sh - tile.sl +1;
594 }
595 }
596 }
597
598 if( tile.dwMaskT == 0 || tile.bClampT )
599 {
600 dwTileHeight= tile.hilite_th - tile.hilite_tl +1;
601 if( dwTileHeight < tile.th - tile.tl +1 )
602 dwTileHeight = tile.th - tile.tl +1;
603
604 if( dwTileHeight <= 0 )
605 {
606 DebuggerAppendMsg("Error");
607 }
608 }
609 else
610 {
611 if( tile.dwMaskT < 8 )
612 dwTileHeight = (1 << tile.dwMaskT );
613 else if( tile.tl <= tile.th )
614 {
615 dwTileHeight = tile.th - tile.tl +1;
616 }
617 else if( loadtile.tl <= loadtile.th )
618 {
619 dwTileHeight = loadtile.th - loadtile.tl +1;
620 }
621 else
622 {
623 dwTileHeight = tile.th - tile.tl +1;
624 }
625 }
626 }
627
628 int dwTileMaskWidth = tile.dwMaskS > 0 ? (1 << tile.dwMaskS ) : 0;
629 int dwTileMaskHeight = tile.dwMaskT > 0 ? (1 << tile.dwMaskT ) : 0;
630
631 if( dwTileWidth < 0 || dwTileHeight < 0)
632 {
633 if( dwTileMaskWidth > 0 )
634 dwTileWidth = dwTileMaskWidth;
635 else if( dwTileWidth < 0 )
636 dwTileWidth = -dwTileWidth;
637
638 if( dwTileMaskHeight > 0 )
639 dwTileHeight = dwTileMaskHeight;
640 else if( dwTileHeight < 0 )
641 dwTileHeight = -dwTileHeight;
642 }
643
644
645
646 if( dwTileWidth-dwTileMaskWidth == 1 && dwTileMaskWidth && dwTileHeight-dwTileMaskHeight == 1 && dwTileMaskHeight )
647 {
648 // Hack for Mario Kart
649 dwTileWidth--;
650 dwTileHeight--;
651 }
652
653 ComputeTileDimension(tile.dwMaskS, tile.bClampS,
654 tile.bMirrorS, dwTileWidth, gti.WidthToCreate, gti.WidthToLoad);
655 tile.dwWidth = gti.WidthToCreate;
656
657 ComputeTileDimension(tile.dwMaskT, tile.bClampT,
658 tile.bMirrorT, dwTileHeight, gti.HeightToCreate, gti.HeightToLoad);
659 tile.dwHeight = gti.HeightToCreate;
660
661#ifdef DEBUGGER
662 if( gti.WidthToCreate < gti.WidthToLoad )
663 TRACE2("Check me, width to create = %d, width to load = %d", gti.WidthToCreate, gti.WidthToLoad);
664 if( gti.HeightToCreate < gti.HeightToLoad )
665 TRACE2("Check me, height to create = %d, height to load = %d", gti.HeightToCreate, gti.HeightToLoad);
666#endif
667
668
669 gti.bSwapped = info->bSwapped;
670
671 if( info->bSetBy == CMD_LOADTILE )
672 {
673 // It was a tile - the pitch is set by LoadTile
674 dwPitch = info->dwWidth<<(info->dwSize-1);
675
676 if( dwPitch == 0 )
677 {
678 dwPitch = 1024; // Hack for Bust-A-Move
679 }
680 }
681 else //Set by LoadBlock
682 {
683 // It was a block load - the pitch is determined by the tile size
684 if (info->dxt == 0 || info->dwTmem != tile.dwTMem )
685 {
686 dwPitch = tile.dwLine << 3;
687 gti.bSwapped = TRUE;
688 if( info->dwTmem != tile.dwTMem && info->dxt != 0 && info->dwSize == TXT_SIZE_16b && tile.dwSize == TXT_SIZE_4b )
689 conkerSwapHack = true;
690 }
691 else
692 {
693 uint32 DXT = info->dxt;
694 if( info->dxt > 1 )
695 {
696 DXT = ReverseDXT(info->dxt, info->sh, dwTileWidth, tile.dwSize);
697 }
698 dwPitch = DXT << 3;
699 }
700
701 if (tile.dwSize == TXT_SIZE_32b)
702 dwPitch = tile.dwLine << 4;
703 }
704
705 gti.Pitch = tile.dwPitch = dwPitch;
706
707 if( (gti.WidthToLoad < gti.WidthToCreate || tile.bSizeIsValid == false) && tile.dwMaskS > 0 && gti.WidthToLoad != (unsigned int)dwTileMaskWidth &&
708 info->bSetBy == CMD_LOADBLOCK )
709 //if( (gti.WidthToLoad < gti.WidthToCreate ) && tile.dwMaskS > 0 && gti.WidthToLoad != dwTileMaskWidth &&
710 // info->bSetBy == CMD_LOADBLOCK )
711 {
712 // We have got the pitch now, recheck the width_to_load
713 uint32 pitchwidth = dwPitch<<1>>tile.dwSize;
714 if( pitchwidth == (unsigned int)dwTileMaskWidth )
715 {
716 gti.WidthToLoad = pitchwidth;
717 }
718 }
719 if( (gti.HeightToLoad < gti.HeightToCreate || tile.bSizeIsValid == false) && tile.dwMaskT > 0 && gti.HeightToLoad != (unsigned int)dwTileMaskHeight &&
720 info->bSetBy == CMD_LOADBLOCK )
721 //if( (gti.HeightToLoad < gti.HeightToCreate ) && tile.dwMaskT > 0 && gti.HeightToLoad != dwTileMaskHeight &&
722 // info->bSetBy == CMD_LOADBLOCK )
723 {
724 //uint32 pitchwidth = dwPitch<<1>>tile.dwSize;
725 uint32 pitchHeight = (info->dwTotalWords<<1)/dwPitch;
726 if( pitchHeight == (unsigned int)dwTileMaskHeight || gti.HeightToLoad == 1 )
727 {
728 gti.HeightToLoad = pitchHeight;
729 }
730 }
731 if( gti.WidthToCreate < gti.WidthToLoad ) gti.WidthToCreate = gti.WidthToLoad;
732 if( gti.HeightToCreate < gti.HeightToLoad ) gti.HeightToCreate = gti.HeightToLoad;
733
734 if( info->bSetBy == CMD_LOADTILE )
735 {
736 gti.LeftToLoad = (info->sl<<info->dwSize)>>tile.dwSize;
737 gti.TopToLoad = info->tl;
738 }
739 else
740 {
741 gti.LeftToLoad = (info->sl<<info->dwSize)>>tile.dwSize;
742 gti.TopToLoad = (info->tl<<info->dwSize)>>tile.dwSize;
743 }
744
745 uint32 total64BitWordsToLoad = (gti.HeightToLoad*gti.WidthToLoad)>>(4-tile.dwSize);
746 if( total64BitWordsToLoad + tile.dwTMem > 0x200 )
747 {
748 //TRACE0("Warning: texture loading tmem is over range");
749 if( gti.WidthToLoad > gti.HeightToLoad )
750 {
751 uint32 newheight = (dwPitch << 1 )>> tile.dwSize;
752 tile.dwWidth = gti.WidthToLoad = gti.WidthToCreate = min(newheight, (gti.WidthToLoad&0xFFFFFFFE));
753 tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = ((0x200 - tile.dwTMem) << (4-tile.dwSize)) / gti.WidthToLoad;
754 }
755 else
756 {
757 tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = info->dwTotalWords / ((gti.WidthToLoad << tile.dwSize) >> 1);
758 }
759 }
760
761 // Check the info
762 if( (info->dwTotalWords>>2) < total64BitWordsToLoad+tile.dwTMem-info->dwTmem - 4 )
763 {
764 // Hack here
765 if( (options.enableHackForGames == HACK_FOR_ZELDA||options.enableHackForGames == HACK_FOR_ZELDA_MM) && (unsigned int)tileno != gRSP.curTile )
766 {
767 return false;
768 }
769
770 if( total64BitWordsToLoad+tile.dwTMem-info->dwTmem <= 0x200 )
771 {
772 LOG_TEXTURE(TRACE4("Fix me, info is not covering this Tmem address,Info start: 0x%x, total=0x%x, Tmem start: 0x%x, total=0x%x",
773 info->dwTmem,info->dwTotalWords>>2, tile.dwTMem, total64BitWordsToLoad));
774 }
775 }
776
777 //Check memory boundary
778 if( gti.Address + gti.HeightToLoad*gti.Pitch >= g_dwRamSize )
779 {
780 WARNING(TRACE0("Warning: texture loading tmem is over range 3"));
781 gti.HeightToCreate = gti.HeightToLoad = tile.dwHeight = (g_dwRamSize-gti.Address)/gti.Pitch;
782 }
783
784 return true;
785}
786
787bool CalculateTileSizes_method_1(int tileno, TMEMLoadMapInfo *info, TxtrInfo &gti)
788{
789 Tile &tile = gRDP.tiles[tileno];
790 //Tile &loadtile = gRDP.tiles[RDP_TXT_LOADTILE];
791
792 // Now Initialize the texture dimension
793 int loadwidth, loadheight;
794
795 int maskwidth = tile.dwMaskS ? (1 << tile.dwMaskS ) : 0;
796 int maskheight = tile.dwMaskT ? (1 << tile.dwMaskT ) : 0;
797 int clampwidth = abs(tile.hilite_sh - tile.hilite_sl) +1;
798 int clampheight = abs(tile.hilite_th - tile.hilite_tl) +1;
799 int linewidth = tile.dwLine << (5 - tile.dwSize);
800
801 gti.bSwapped = info->bSwapped;
802
803 if( info->bSetBy == CMD_LOADTILE )
804 {
805 loadwidth = (abs(info->sh - info->sl) + 1) << info->dwSize >> tile.dwSize;
806 loadheight = (abs(info->th - info->tl) + 1) << info->dwSize >> tile.dwSize;
807
808 tile.dwPitch = info->dwWidth << info->dwSize >> 1;
809 if( tile.dwPitch == 0 ) tile.dwPitch = 1024; // Hack for Bust-A-Move
810
811 gti.LeftToLoad = (info->sl<<info->dwSize)>>tile.dwSize;
812 gti.TopToLoad = info->tl;
813 }
814 else
815 {
816 loadwidth = abs(tile.sh - tile.sl) +1;
817 if( tile.dwMaskS )
818 {
819 loadwidth = maskwidth;
820 }
821
822 loadheight = abs(tile.th - tile.tl) +1;
823 if( tile.dwMaskT )
824 {
825 loadheight = maskheight;
826 }
827
828
829 // It was a block load - the pitch is determined by the tile size
830 if (tile.dwSize == TXT_SIZE_32b)
831 tile.dwPitch = tile.dwLine << 4;
832 else if (info->dxt == 0 )
833 {
834 tile.dwPitch = tile.dwLine << 3;
835 gti.bSwapped = TRUE;
836 if( info->dwTmem != tile.dwTMem && info->dxt != 0 && info->dwSize == TXT_SIZE_16b && tile.dwSize == TXT_SIZE_4b )
837 conkerSwapHack = true;
838 }
839 else
840 {
841 uint32 DXT = info->dxt;
842 if( info->dxt > 1 )
843 {
844 DXT = ReverseDXT(info->dxt, info->sh, loadwidth, tile.dwSize);
845 }
846 tile.dwPitch = DXT << 3;
847 }
848
849 gti.LeftToLoad = (info->sl<<info->dwSize)>>tile.dwSize;
850 gti.TopToLoad = (info->tl<<info->dwSize)>>tile.dwSize;
851 }
852
853 if( options.enableHackForGames == HACK_FOR_MARIO_KART )
854 {
855 if( loadwidth-maskwidth == 1 && tile.dwMaskS )
856 {
857 loadwidth--;
858 if( loadheight%2 ) loadheight--;
859 }
860
861 if( loadheight-maskheight == 1 && tile.dwMaskT )
862 {
863 loadheight--;
864 if(loadwidth%2) loadwidth--;
865 }
866
867 if( loadwidth - ((g_TI.dwWidth<<g_TI.dwSize)>>tile.dwSize) == 1 )
868 {
869 loadwidth--;
870 if( loadheight%2 ) loadheight--;
871 }
872 }
873
874
875 // Limit the texture size
876 if( g_curRomInfo.bUseSmallerTexture )
877 {
878 if( tile.dwMaskS && tile.bClampS )
879 {
880 if( !tile.bMirrorS )
881 {
882 if( clampwidth/maskwidth >= 2 )
883 {
884 clampwidth = maskwidth;
885 tile.bForceWrapS = true;
886 }
887 else if( clampwidth && maskwidth/clampwidth >= 2 )
888 {
889 maskwidth = clampwidth;
890 tile.bForceClampS = true;
891 }
892 }
893 else
894 {
895 if( clampwidth/maskwidth == 2 )
896 {
897 clampwidth = maskwidth*2;
898 tile.bForceWrapS = false;
899 }
900 else if( clampwidth/maskwidth > 2 )
901 {
902 clampwidth = maskwidth*2;
903 tile.bForceWrapS = true;
904 }
905 }
906 }
907
908 if( tile.dwMaskT && tile.bClampT )
909 {
910 if( !tile.bMirrorT )
911 {
912 if( clampheight/maskheight >= 2 )
913 {
914 clampheight = maskheight;
915 tile.bForceWrapT = true;
916 }
917 else if( clampheight && maskheight/clampheight >= 2 )
918 {
919 maskwidth = clampwidth;
920 tile.bForceClampT = true;
921 }
922 }
923 else
924 {
925 if( clampheight/maskheight == 2 )
926 {
927 clampheight = maskheight*2;
928 tile.bForceWrapT = false;
929 }
930 else if( clampheight/maskheight >= 2 )
931 {
932 clampheight = maskheight*2;
933 tile.bForceWrapT = true;
934 }
935 }
936 }
937 }
938 else
939 {
940 //if( clampwidth > linewidth ) clampwidth = linewidth;
941 if( clampwidth > 512 && clampheight > 512 )
942 {
943 if( clampwidth > maskwidth && maskwidth && clampheight > 256 ) clampwidth = maskwidth;
944 if( clampheight > maskheight && maskheight && clampheight > 256 ) clampheight = maskheight;
945 }
946
947 if( tile.dwMaskS > 8 && tile.dwMaskT > 8 )
948 {
949 maskwidth = loadwidth;
950 maskheight = loadheight;
951 }
952 else
953 {
954 if( tile.dwMaskS > 10 )
955 maskwidth = loadwidth;
956 if( tile.dwMaskT > 10 )
957 maskheight = loadheight;
958 }
959 }
960
961 gti.Pitch = tile.dwPitch;
962
963 if( tile.dwMaskS == 0 || tile.bClampS )
964 {
965 gti.WidthToLoad = linewidth ? min( linewidth, maskwidth ? min(clampwidth,maskwidth) : clampwidth ) : clampwidth;
966 if( tile.dwMaskS && clampwidth < maskwidth )
967 tile.dwWidth = gti.WidthToCreate = clampwidth;
968 else
969 tile.dwWidth = gti.WidthToCreate = max(clampwidth,maskwidth);
970 }
971 else
972 {
973 gti.WidthToLoad = loadwidth > 2 ? min(loadwidth,maskwidth) : maskwidth;
974 if( linewidth ) gti.WidthToLoad = min( linewidth, (int)gti.WidthToLoad );
975 tile.dwWidth = gti.WidthToCreate = maskwidth;
976 }
977
978 if( tile.dwMaskT == 0 || tile.bClampT )
979 {
980 gti.HeightToLoad = maskheight ? min(clampheight,maskheight) : clampheight;
981 if( tile.dwMaskT && clampheight < maskheight )
982 tile.dwHeight = gti.HeightToCreate = clampheight;
983 else
984 tile.dwHeight = gti.HeightToCreate = max(clampheight,maskheight);
985 }
986 else
987 {
988 gti.HeightToLoad = loadheight > 2 ? min(loadheight,maskheight) : maskheight;
989 tile.dwHeight = gti.HeightToCreate = maskheight;
990 }
991
992 if( options.enableHackForGames == HACK_FOR_MARIO_KART )
993 {
994 if( gti.WidthToLoad - ((g_TI.dwWidth<<g_TI.dwSize)>>tile.dwSize) == 1 )
995 {
996 gti.WidthToLoad--;
997 if( gti.HeightToLoad%2 ) gti.HeightToLoad--;
998 }
999 }
1000
1001 // Double check
1002 uint32 total64BitWordsToLoad = (gti.HeightToLoad*gti.WidthToLoad)>>(4-tile.dwSize);
1003 if( total64BitWordsToLoad + tile.dwTMem > 0x200 )
1004 {
1005 //TRACE0("Warning: texture loading tmem is over range");
1006 if( gti.WidthToLoad > gti.HeightToLoad )
1007 {
1008 uint32 newheight = (tile.dwPitch << 1 )>> tile.dwSize;
1009 tile.dwWidth = gti.WidthToLoad = gti.WidthToCreate = min(newheight, (gti.WidthToLoad&0xFFFFFFFE));
1010 tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = ((0x200 - tile.dwTMem) << (4-tile.dwSize)) / gti.WidthToLoad;
1011 }
1012 else
1013 {
1014 tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = info->dwTotalWords / ((gti.WidthToLoad << tile.dwSize) >> 1);
1015 }
1016 }
1017
1018 // Check the info
1019 if( (info->dwTotalWords>>2) < total64BitWordsToLoad+tile.dwTMem-info->dwTmem - 4 )
1020 {
1021 // Hack here
1022 if( (options.enableHackForGames == HACK_FOR_ZELDA||options.enableHackForGames == HACK_FOR_ZELDA_MM) && (unsigned int)tileno != gRSP.curTile )
1023 {
1024 return false;
1025 }
1026
1027 if( total64BitWordsToLoad+tile.dwTMem-info->dwTmem <= 0x200 )
1028 {
1029 LOG_TEXTURE(TRACE4("Fix me, info is not covering this Tmem address,Info start: 0x%x, total=0x%x, Tmem start: 0x%x, total=0x%x",
1030 info->dwTmem,info->dwTotalWords>>2, tile.dwTMem, total64BitWordsToLoad));
1031 }
1032 }
1033
1034 //Check memory boundary
1035 if( gti.Address + gti.HeightToLoad*gti.Pitch >= g_dwRamSize )
1036 {
1037 WARNING(TRACE0("Warning: texture loading tmem is over range 3"));
1038 gti.HeightToCreate = gti.HeightToLoad = tile.dwHeight = (g_dwRamSize-gti.Address)/gti.Pitch;
1039 }
1040
1041 return true;
1042}
1043
1044TxtrCacheEntry* LoadTexture(uint32 tileno)
1045{
1046 //TxtrCacheEntry *pEntry = NULL;
1047 TxtrInfo gti;
1048
1049 Tile &tile = gRDP.tiles[tileno];
1050
1051 // Retrieve the tile loading info
1052 uint32 infoTmemAddr = tile.dwTMem;
1053 TMEMLoadMapInfo *info = &g_tmemLoadAddrMap[infoTmemAddr];
1054 if( !IsTmemFlagValid(infoTmemAddr) )
1055 {
1056 infoTmemAddr = GetValidTmemInfoIndex(infoTmemAddr);
1057 info = &g_tmemLoadAddrMap[infoTmemAddr];
1058 }
1059
1060 if( info->dwFormat != tile.dwFormat )
1061 {
1062 // Check the tile format, hack for Zelda's road
1063 if( tileno != gRSP.curTile && tile.dwTMem == gRDP.tiles[gRSP.curTile].dwTMem &&
1064 tile.dwFormat != gRDP.tiles[gRSP.curTile].dwFormat )
1065 {
1066 //TRACE1("Tile %d format is not matching the loaded texture format", tileno);
1067 return NULL;
1068 }
1069 }
1070
1071 gti = tile; // Copy tile info to textureInfo entry
1072
1073 gti.TLutFmt = gRDP.otherMode.text_tlut <<RSP_SETOTHERMODE_SHIFT_TEXTLUT;
1074 if (gti.Format == TXT_FMT_CI && gti.TLutFmt == TLUT_FMT_NONE )
1075 gti.TLutFmt = TLUT_FMT_RGBA16; // Force RGBA
1076
1077 gti.PalAddress = (uchar *) (&g_wRDPTlut[0]);
1078 if( !options.bUseFullTMEM && tile.dwSize == TXT_SIZE_4b )
1079 gti.PalAddress += 16 * 2 * tile.dwPalette;
1080
1081 gti.Address = (info->dwLoadAddress+(tile.dwTMem-infoTmemAddr)*8) & (g_dwRamSize-1) ;
1082 gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address;
1083 gti.tileNo = tileno;
1084
1085 if( g_curRomInfo.bTxtSizeMethod2 )
1086 {
1087 if( !CalculateTileSizes_method_2(tileno, info, gti) )
1088 return NULL;
1089 }
1090 else
1091 {
1092 if( !CalculateTileSizes_method_1(tileno, info, gti) )
1093 return NULL;
1094 }
1095
1096 LOG_TEXTURE(
1097 {
1098 TRACE0("Loading texture:\n");
1099 DebuggerAppendMsg("Left: %d, Top: %d, Width: %d, Height: %d, Size to Load (%d, %d)",
1100 gti.LeftToLoad, gti.TopToLoad, gti.WidthToCreate, gti.HeightToCreate, gti.WidthToLoad, gti.HeightToLoad);
1101 DebuggerAppendMsg("Pitch: %d, Addr: 0x%08x", gti.Pitch, gti.Address);
1102 });
1103
1104 // Option for faster loading tiles
1105 if( g_curRomInfo.bFastLoadTile && info->bSetBy == CMD_LOADTILE && ((gti.Pitch<<1)>>gti.Size) <= 0x400
1106 //&& ((gti.Pitch<<1)>>gti.Size) > 128 && status.primitiveType == PRIM_TEXTRECT
1107 )
1108 {
1109 uint32 idx = tileno-gRSP.curTile;
1110 status.LargerTileRealLeft[idx] = gti.LeftToLoad;
1111 gti.LeftToLoad=0;
1112 gti.WidthToLoad = gti.WidthToCreate = ((gti.Pitch<<1)>>gti.Size);
1113 status.UseLargerTile[idx]=true;
1114 }
1115
1116 // Loading the textures by using texture cache manager
1117 return gTextureManager.GetTexture(&gti, true, true, true); // Load the texture by using texture cache
1118}
1119
1120void PrepareTextures()
1121{
1122 if( gRDP.textureIsChanged || !currentRomOptions.bFastTexCRC ||
1123 CRender::g_pRender->m_pColorCombiner->m_pDecodedMux->m_ColorTextureFlag[0] ||
1124 CRender::g_pRender->m_pColorCombiner->m_pDecodedMux->m_ColorTextureFlag[1] )
1125 {
1126 status.UseLargerTile[0]=false;
1127 status.UseLargerTile[1]=false;
1128
1129 int tilenos[2];
1130 if( CRender::g_pRender->IsTexel0Enable() || gRDP.otherMode.cycle_type == CYCLE_TYPE_COPY )
1131 tilenos[0] = gRSP.curTile;
1132 else
1133 tilenos[0] = -1;
1134
1135 if( gRSP.curTile<7 && CRender::g_pRender->IsTexel1Enable() )
1136 tilenos[1] = gRSP.curTile+1;
1137 else
1138 tilenos[1] = -1;
1139
1140
1141 for( int i=0; i<2; i++ )
1142 {
1143 if( tilenos[i] < 0 ) continue;
1144
1145 if( CRender::g_pRender->m_pColorCombiner->m_pDecodedMux->m_ColorTextureFlag[i] )
1146 {
1147 TxtrCacheEntry *pEntry = gTextureManager.GetConstantColorTexture(CRender::g_pRender->m_pColorCombiner->m_pDecodedMux->m_ColorTextureFlag[i]);
1148 CRender::g_pRender->SetCurrentTexture( tilenos[i], pEntry->pTexture, 4, 4, pEntry);
1149 }
1150 else
1151 {
1152 TxtrCacheEntry *pEntry = LoadTexture(tilenos[i]);
1153 if (pEntry && pEntry->pTexture )
1154 {
1155 if( pEntry->txtrBufIdx <= 0 )
1156 {
1157 if( pEntry->pEnhancedTexture && pEntry->dwEnhancementFlag == TEXTURE_EXTERNAL && !options.bLoadHiResTextures )
1158 {
1159 SAFE_DELETE(pEntry->pEnhancedTexture);
1160 }
1161
1162 if( pEntry->pEnhancedTexture == NULL )
1163 {
1164 MirrorTexture(tilenos[i], pEntry);;
1165 }
1166
1167 if( options.bLoadHiResTextures && (pEntry->pEnhancedTexture == NULL || pEntry->dwEnhancementFlag < TEXTURE_EXTERNAL ) )
1168 {
1169 LoadHiresTexture(*pEntry);
1170 }
1171
1172 if( pEntry->pEnhancedTexture == NULL || (pEntry->dwEnhancementFlag != options.textureEnhancement && pEntry->dwEnhancementFlag < TEXTURE_EXTERNAL ) )
1173 {
1174 EnhanceTexture(pEntry);
1175 }
1176 }
1177
1178 CRender::g_pRender->SetCurrentTexture( tilenos[i],
1179 (pEntry->pEnhancedTexture)?pEntry->pEnhancedTexture:pEntry->pTexture,
1180 pEntry->ti.WidthToLoad, pEntry->ti.HeightToLoad, pEntry);
1181 }
1182 else
1183 {
1184 pEntry = gTextureManager.GetBlackTexture();
1185 CRender::g_pRender->SetCurrentTexture( tilenos[i], pEntry->pTexture, 4, 4, pEntry);
1186 _VIDEO_DisplayTemporaryMessage("Fail to load texture, use black to replace");
1187 }
1188
1189 }
1190 }
1191
1192 gRDP.textureIsChanged = false;
1193 }
1194}
1195
1196extern uint32 g_TxtLoadBy;;
1197
1198void DLParser_LoadTLut(Gfx *gfx)
1199{
1200gRDP.textureIsChanged = true;
1201
1202uint32 tileno = gfx->loadtile.tile;
1203uint32 uls = gfx->loadtile.sl/4;
1204uint32 ult = gfx->loadtile.tl/4;
1205uint32 lrs = gfx->loadtile.sh/4;
1206uint32 lrt = gfx->loadtile.th/4;
1207
1208#ifdef DEBUGGER
1209uint32 dwTLutFmt = (gRDP.otherModeH >> RSP_SETOTHERMODE_SHIFT_TEXTLUT)&0x3;
1210#endif
1211
1212uint32 dwCount;
1213// starting location in the palettes
1214uint32 dwTMEMOffset = gRDP.tiles[tileno].dwTMem - 256;
1215// number to copy
1216dwCount = ((uint16)((gfx->words.w1) >> 14) & 0x03FF) + 1;
1217uint32 dwRDRAMOffset = 0;
1218
1219Tile &tile = gRDP.tiles[tileno];
1220tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false;
1221
1222tile.hilite_sl = tile.sl = uls;
1223tile.hilite_tl = tile.tl = ult;
1224tile.sh = lrs;
1225tile.th = lrt;
1226tile.bSizeIsValid = true;
1227
1228tile.lastTileCmd = CMD_LOADTLUT;
1229
1230#ifdef DEBUGGER
1231/*
1232if((((gfx->words.w0)>>12)&0x3) != 0 || (((gfx->words.w0))&0x3) != 0 || (((gfx->words.w1)>>12)&0x3) != 0 || (((gfx->words.w1))&0x3) != 0)
1233 TRACE0("Load tlut, sl,tl,sh,th are not integers");
1234*/
1235#endif
1236
1237dwCount = (lrs - uls)+1;
1238dwRDRAMOffset = (uls + ult*g_TI.dwWidth )*2;
1239uint32 dwPalAddress = g_TI.dwAddr + dwRDRAMOffset;
1240
1241//Copy PAL to the PAL memory
1242uint16 *srcPal = (uint16*)(g_pRDRAMu8 + (dwPalAddress& (g_dwRamSize-1)) );
1243for (uint32 i=0; i<dwCount && i<0x100; i++)
1244 g_wRDPTlut[(i+dwTMEMOffset)^1] = srcPal[i^1];
1245
1246if( options.bUseFullTMEM )
1247 {
1248 for (uint32 i=0; i<dwCount && i+tile.dwTMem<0x200; i++)
1249 *(uint16*)(&g_Tmem.g_Tmem64bit[tile.dwTMem+i]) = srcPal[i^1];
1250 }
1251
1252LOG_TEXTURE(
1253{
1254DebuggerAppendMsg("LoadTLut Tile: %d Start: 0x%X+0x%X, Count: 0x%X\nFmt is %s, TMEM=0x%X\n",
1255 tileno, g_TI.dwAddr, dwRDRAMOffset, dwCount,textluttype[dwTLutFmt],
1256 dwTMEMOffset);
1257
1258DebuggerAppendMsg(" :ULS: 0x%X, ULT:0x%X, LRS: 0x%X, LRT:0x%X\n", uls, ult, lrs,lrt);
1259
1260if( pauseAtNext && eventToPause == NEXT_LOADTLUT && dwCount == 16 )
1261 {
1262 char buf[2000];
1263 strcpy(buf, "Data:\n");
1264 for(uint32 i=0; i<16; i++ )
1265 {
1266 sprintf(buf+strlen(buf), "%04X ", g_wRDPTlut[dwTMEMOffset+i]);
1267 if(i%4 == 3)
1268 sprintf(buf+strlen(buf), "\n");
1269 }
1270 sprintf(buf+strlen(buf), "\n");
1271 TRACE0(buf);
1272 }
1273});
1274
1275DEBUGGER_PAUSE_COUNT_N(NEXT_LOADTLUT);
1276
1277extern bool RevTlutTableNeedUpdate;
1278RevTlutTableNeedUpdate = true;
1279g_TxtLoadBy = CMD_LOADTLUT;
1280}
1281
1282
1283void DLParser_LoadBlock(Gfx *gfx)
1284{
1285 gRDP.textureIsChanged = true;
1286
1287 uint32 tileno = gfx->loadtile.tile;
1288 uint32 uls = gfx->loadtile.sl;
1289 uint32 ult = gfx->loadtile.tl;
1290 uint32 lrs = gfx->loadtile.sh;
1291 uint32 dxt = gfx->loadtile.th; // 1.11 fixed point
1292
1293 Tile &tile = gRDP.tiles[tileno];
1294 tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false;
1295
1296 uint32 size = lrs+1;
1297 if( tile.dwSize == TXT_SIZE_32b ) size<<=1;
1298
1299 SetTmemFlag(tile.dwTMem, size>>2);
1300
1301 TMEMLoadMapInfo &info = g_tmemLoadAddrMap[tile.dwTMem];
1302
1303 info.bSwapped = (dxt == 0? TRUE : FALSE);
1304
1305 info.sl = tile.hilite_sl = tile.sl = uls;
1306 info.sh = tile.hilite_sh = tile.sh = lrs;
1307 info.tl = tile.tl = ult;
1308 info.th = tile.th = dxt;
1309 tile.bSizeIsValid = false;
1310
1311 for( int i=0; i<8; i++ )
1312 {
1313 if( tile.dwTMem == tile.dwTMem )
1314 tile.lastTileCmd = CMD_LOADBLOCK;
1315 }
1316
1317 info.dwLoadAddress = g_TI.dwAddr;
1318 info.bSetBy = CMD_LOADBLOCK;
1319 info.dxt = dxt;
1320 info.dwLine = tile.dwLine;
1321
1322 info.dwFormat = g_TI.dwFormat;
1323 info.dwSize = g_TI.dwSize;
1324 info.dwWidth = g_TI.dwWidth;
1325 info.dwTotalWords = size;
1326 info.dwTmem = tile.dwTMem;
1327
1328 if( gRDP.tiles[tileno].dwTMem == 0 )
1329 {
1330 if( size >= 1024 )
1331 {
1332 memcpy(&g_tmemInfo0, &info, sizeof(TMEMLoadMapInfo) );
1333 g_tmemInfo0.dwTotalWords = size>>2;
1334 }
1335
1336 if( size == 2048 )
1337 {
1338 memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) );
1339 g_tmemInfo1.dwTotalWords = size>>2;
1340 }
1341 }
1342 else if( tile.dwTMem == 0x100 )
1343 {
1344 if( size == 1024 )
1345 {
1346 memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) );
1347 g_tmemInfo1.dwTotalWords = size>>2;
1348 }
1349 }
1350
1351 g_TxtLoadBy = CMD_LOADBLOCK;
1352
1353
1354 if( options.bUseFullTMEM )
1355 {
1356 uint32 bytes = (lrs + 1) << tile.dwSize >> 1;
1357 uint32 address = g_TI.dwAddr + ult * g_TI.bpl + (uls << g_TI.dwSize >> 1);
1358 if ((bytes == 0) || ((address + bytes) > g_dwRamSize) || (((tile.dwTMem << 3) + bytes) > 4096))
1359 {
1360 return;
1361 }
1362 uint64* src = (uint64*)(g_pRDRAMu8+address);
1363 uint64* dest = &g_Tmem.g_Tmem64bit[tile.dwTMem];
1364
1365 if( dxt > 0)
1366 {
1367 void (*Interleave)( void *mem, uint32 numDWords );
1368
1369 uint32 line = (2047 + dxt) / dxt;
1370 uint32 bpl = line << 3;
1371 uint32 height = bytes / bpl;
1372
1373 if (tile.dwSize == TXT_SIZE_32b)
1374 Interleave = QWordInterleave;
1375 else
1376 Interleave = DWordInterleave;
1377
1378 for (uint32 y = 0; y < height; y++)
1379 {
1380 UnswapCopy( src, dest, bpl );
1381 if (y & 1) Interleave( dest, line );
1382
1383 src += line;
1384 dest += line;
1385 }
1386 }
1387 else
1388 UnswapCopy( src, dest, bytes );
1389 }
1390
1391
1392 LOG_UCODE(" Tile:%d (%d,%d - %d) DXT:0x%04x\n", tileno, uls, ult, lrs, dxt);
1393
1394 LOG_TEXTURE(
1395 {
1396 DebuggerAppendMsg("LoadBlock:%d (%d,%d,%d) DXT:0x%04x(%X)\n",
1397 tileno, uls, ult, (((gfx->words.w1)>>12)&0x0FFF), dxt, ((gfx->words.w1)&0x0FFF));
1398 });
1399
1400 DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD);
1401}
1402
1403void swap(uint32 &a, uint32 &b)
1404{
1405 uint32 temp = a;
1406 a = b;
1407 b = temp;
1408}
1409void DLParser_LoadTile(Gfx *gfx)
1410{
1411 gRDP.textureIsChanged = true;
1412
1413 uint32 tileno = gfx->loadtile.tile;
1414 uint32 uls = gfx->loadtile.sl/4;
1415 uint32 ult = gfx->loadtile.tl/4;
1416 uint32 lrs = gfx->loadtile.sh/4;
1417 uint32 lrt = gfx->loadtile.th/4;
1418
1419 Tile &tile = gRDP.tiles[tileno];
1420 tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false;
1421
1422 if (lrt < ult) swap(lrt, ult);
1423 if (lrs < uls) swap(lrs, uls);
1424
1425 tile.hilite_sl = tile.sl = uls;
1426 tile.hilite_tl = tile.tl = ult;
1427 tile.hilite_sh = tile.sh = lrs;
1428 tile.hilite_th = tile.th = lrt;
1429 tile.bSizeIsValid = true;
1430
1431 // compute block height, and bpl of source and destination
1432 uint32 bpl = (lrs - uls + 1) << tile.dwSize >> 1;
1433 uint32 height = lrt - ult + 1;
1434 uint32 line = tile.dwLine;
1435 if (tile.dwSize == TXT_SIZE_32b) line <<= 1;
1436
1437 if (((tile.dwTMem << 3) + line * height) > 4096) // check destination ending point (TMEM is 4k bytes)
1438 return;
1439
1440 if( options.bUseFullTMEM )
1441 {
1442 void (*Interleave)( void *mem, uint32 numDWords );
1443 uint32 address, y;
1444 uint64 *dest;
1445 uint8 *src;
1446
1447 if( g_TI.bpl == 0 )
1448 {
1449 if( options.enableHackForGames == HACK_FOR_BUST_A_MOVE )
1450 {
1451 g_TI.bpl = 1024; // Hack for Bust-A-Move
1452 }
1453 else
1454 {
1455 TRACE0("Warning: g_TI.bpl = 0" );
1456 }
1457 }
1458
1459 address = g_TI.dwAddr + tile.tl * g_TI.bpl + (tile.sl << g_TI.dwSize >> 1);
1460 src = &g_pRDRAMu8[address];
1461 dest = &g_Tmem.g_Tmem64bit[tile.dwTMem];
1462
1463 if ((address + height * bpl) > g_dwRamSize) // check source ending point
1464 {
1465 return;
1466 }
1467
1468 // Line given for 32-bit is half what it seems it should since they split the
1469 // high and low words. I'm cheating by putting them together.
1470 if (tile.dwSize == TXT_SIZE_32b)
1471 {
1472 Interleave = QWordInterleave;
1473 }
1474 else
1475 {
1476 Interleave = DWordInterleave;
1477 }
1478
1479 if( tile.dwLine == 0 )
1480 {
1481 //tile.dwLine = 1;
1482 return;
1483 }
1484
1485 for (y = 0; y < height; y++)
1486 {
1487 UnswapCopy( src, dest, bpl );
1488 if (y & 1) Interleave( dest, line );
1489
1490 src += g_TI.bpl;
1491 dest += line;
1492 }
1493 }
1494
1495
1496 for( int i=0; i<8; i++ )
1497 {
1498 if( gRDP.tiles[i].dwTMem == tile.dwTMem )
1499 gRDP.tiles[i].lastTileCmd = CMD_LOADTILE;
1500 }
1501
1502 uint32 size = line * height;
1503 SetTmemFlag(tile.dwTMem,size );
1504
1505 LOG_TEXTURE(
1506 {
1507 DebuggerAppendMsg("LoadTile:%d (%d,%d) -> (%d,%d) [%d x %d]\n",
1508 tileno, uls, ult, lrs, lrt,
1509 (lrs - uls)+1, (lrt - ult)+1);
1510 });
1511
1512
1513 DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD);
1514
1515 LOG_UCODE(" Tile:%d (%d,%d) -> (%d,%d) [%d x %d]",
1516 tileno, uls, ult, lrs, lrt,
1517 (lrs - uls)+1, (lrt - ult)+1);
1518
1519 TMEMLoadMapInfo &info = g_tmemLoadAddrMap[tile.dwTMem];
1520
1521 info.dwLoadAddress = g_TI.dwAddr;
1522 info.dwFormat = g_TI.dwFormat;
1523 info.dwSize = g_TI.dwSize;
1524 info.dwWidth = g_TI.dwWidth;
1525
1526 info.sl = uls;
1527 info.sh = lrs;
1528 info.tl = ult;
1529 info.th = lrt;
1530
1531 info.dxt = 0;
1532 info.dwLine = tile.dwLine;
1533 info.dwTmem = tile.dwTMem;
1534 info.dwTotalWords = size<<2;
1535
1536 info.bSetBy = CMD_LOADTILE;
1537 info.bSwapped =FALSE;
1538
1539 g_TxtLoadBy = CMD_LOADTILE;
1540
1541 if( tile.dwTMem == 0 )
1542 {
1543 if( size >= 256 )
1544 {
1545 memcpy(&g_tmemInfo0, &info, sizeof(TMEMLoadMapInfo) );
1546 g_tmemInfo0.dwTotalWords = size;
1547 }
1548
1549 if( size == 512 )
1550 {
1551 memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) );
1552 g_tmemInfo1.dwTotalWords = size;
1553 }
1554 }
1555 else if( tile.dwTMem == 0x100 )
1556 {
1557 if( size == 256 )
1558 {
1559 memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) );
1560 g_tmemInfo1.dwTotalWords = size;
1561 }
1562 }
1563}
1564
1565
1566const char *pszOnOff[2] = {"Off", "On"};
1567uint32 lastSetTile;
1568void DLParser_SetTile(Gfx *gfx)
1569{
1570 gRDP.textureIsChanged = true;
1571
1572 uint32 tileno = gfx->settile.tile;
1573 Tile &tile = gRDP.tiles[tileno];
1574 tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false;
1575
1576 lastSetTile = tileno;
1577
1578 tile.dwFormat = gfx->settile.fmt;
1579 tile.dwSize = gfx->settile.siz;
1580 tile.dwLine = gfx->settile.line;
1581 tile.dwTMem = gfx->settile.tmem;
1582
1583 tile.dwPalette = gfx->settile.palette;
1584 tile.bClampT = gfx->settile.ct;
1585 tile.bMirrorT = gfx->settile.mt;
1586 tile.dwMaskT = gfx->settile.maskt;
1587 tile.dwShiftT = gfx->settile.shiftt;
1588 tile.bClampS = gfx->settile.cs;
1589 tile.bMirrorS = gfx->settile.ms;
1590 tile.dwMaskS = gfx->settile.masks;
1591 tile.dwShiftS = gfx->settile.shifts;
1592
1593
1594 tile.fShiftScaleS = 1.0f;
1595 if( tile.dwShiftS )
1596 {
1597 if( tile.dwShiftS > 10 )
1598 {
1599 tile.fShiftScaleS = (float)(1 << (16 - tile.dwShiftS));
1600 }
1601 else
1602 {
1603 tile.fShiftScaleS = (float)1.0f/(1 << tile.dwShiftS);
1604 }
1605 }
1606
1607 tile.fShiftScaleT = 1.0f;
1608 if( tile.dwShiftT )
1609 {
1610 if( tile.dwShiftT > 10 )
1611 {
1612 tile.fShiftScaleT = (float)(1 << (16 - tile.dwShiftT));
1613 }
1614 else
1615 {
1616 tile.fShiftScaleT = (float)1.0f/(1 << tile.dwShiftT);
1617 }
1618 }
1619
1620 // Hack for DK64
1621 /*
1622 if( tile.dwMaskS > 0 && tile.dwMaskT > 0 && tile.dwMaskS < 8 && tile.dwMaskT < 8 )
1623 {
1624 tile.sh = tile.sl + (1<<tile.dwMaskS);
1625 tile.th = tile.tl + (1<<tile.dwMaskT);
1626 tile.hilite_sl = tile.sl;
1627 tile.hilite_tl = tile.tl;
1628 }
1629 */
1630
1631 tile.lastTileCmd = CMD_SETTILE;
1632
1633 LOG_TEXTURE(
1634 {
1635 DebuggerAppendMsg("SetTile:%d Fmt: %s/%s Line:%d TMem:0x%04x Palette:%d\n",
1636 tileno, pszImgFormat[tile.dwFormat], pszImgSize[tile.dwSize],
1637 tile.dwLine, tile.dwTMem, tile.dwPalette);
1638 DebuggerAppendMsg(" S: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x\n",
1639 pszOnOff[tile.bClampS],pszOnOff[tile.bMirrorS],
1640 tile.dwMaskS, tile.dwShiftS);
1641 DebuggerAppendMsg(" T: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x\n",
1642 pszOnOff[tile.bClampT],pszOnOff[tile.bMirrorT],
1643 tile.dwMaskT, tile.dwShiftT);
1644 });
1645
1646 DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD);
1647
1648 LOG_UCODE(" Tile:%d Fmt: %s/%s Line:%d TMem:0x%04x Palette:%d",
1649 tileno, pszImgFormat[tile.dwFormat], pszImgSize[tile.dwSize],
1650 tile.dwLine, tile.dwTMem, tile.dwPalette);
1651 LOG_UCODE(" S: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x",
1652 pszOnOff[tile.bClampS],pszOnOff[tile.bMirrorS],
1653 tile.dwMaskS, tile.dwShiftS);
1654 LOG_UCODE(" T: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x",
1655 pszOnOff[tile.bClampT],pszOnOff[tile.bMirrorT],
1656 tile.dwMaskT, tile.dwShiftT);
1657}
1658
1659void DLParser_SetTileSize(Gfx *gfx)
1660{
1661 gRDP.textureIsChanged = true;
1662
1663 uint32 tileno = gfx->loadtile.tile;
1664 int sl = gfx->loadtile.sl;
1665 int tl = gfx->loadtile.tl;
1666 int sh = gfx->loadtile.sh;
1667 int th = gfx->loadtile.th;
1668
1669 Tile &tile = gRDP.tiles[tileno];
1670 tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false;
1671
1672 if( options.bUseFullTMEM )
1673 {
1674 tile.bSizeIsValid = true;
1675 tile.hilite_sl = tile.sl = sl / 4;
1676 tile.hilite_tl = tile.tl = tl / 4;
1677 tile.hilite_sh = tile.sh = sh / 4;
1678 tile.hilite_th = tile.th = th / 4;
1679
1680 tile.fhilite_sl = tile.fsl = sl / 4.0f;
1681 tile.fhilite_tl = tile.ftl = tl / 4.0f;
1682 tile.fhilite_sh = tile.fsh = sh / 4.0f;
1683 tile.fhilite_th = tile.fth = th / 4.0f;
1684
1685 tile.lastTileCmd = CMD_SETTILE_SIZE;
1686 }
1687 else
1688 {
1689 if( tile.lastTileCmd != CMD_SETTILE_SIZE )
1690 {
1691 tile.bSizeIsValid = true;
1692 if( sl/4 > sh/4 || tl/4 > th/4 || (sh == 0 && tile.dwShiftS==0 && th == 0 && tile.dwShiftT ==0 ) )
1693 {
1694#ifdef DEBUGGER
1695 if( sl != 0 || tl != 0 || sh != 0 || th != 0 )
1696 {
1697 if( tile.dwMaskS==0 || tile.dwMaskT==0 )
1698 TRACE0("Check me, setTileSize is not correct");
1699 }
1700#endif
1701 tile.bSizeIsValid = false;
1702 }
1703 tile.hilite_sl = tile.sl = sl / 4;
1704 tile.hilite_tl = tile.tl = tl / 4;
1705 tile.hilite_sh = tile.sh = sh / 4;
1706 tile.hilite_th = tile.th = th / 4;
1707
1708 tile.fhilite_sl = tile.fsl = sl / 4.0f;
1709 tile.fhilite_tl = tile.ftl = tl / 4.0f;
1710 tile.fhilite_sh = tile.fsh = sh / 4.0f;
1711 tile.fhilite_th = tile.fth = th / 4.0f;
1712
1713 tile.lastTileCmd = CMD_SETTILE_SIZE;
1714 }
1715 else
1716 {
1717 tile.fhilite_sh = tile.fsh;
1718 tile.fhilite_th = tile.fth;
1719 tile.fhilite_sl = tile.fsl = (sl>0x7ff ? (sl-0xfff) : sl)/4.0f;
1720 tile.fhilite_tl = tile.ftl = (tl>0x7ff ? (tl-0xfff) : tl)/4.0f;
1721
1722 tile.hilite_sl = sl>0x7ff ? (sl-0xfff) : sl;
1723 tile.hilite_tl = tl>0x7ff ? (tl-0xfff) : tl;
1724 tile.hilite_sl /= 4;
1725 tile.hilite_tl /= 4;
1726 tile.hilite_sh = sh/4;
1727 tile.hilite_th = th/4;
1728
1729 tile.lastTileCmd = CMD_SETTILE_SIZE;
1730 }
1731 }
1732
1733 LOG_TEXTURE(
1734 {
1735 DebuggerAppendMsg("SetTileSize:%d (%d/4,%d/4) -> (%d/4,%d/4) [%d x %d]\n",
1736 tileno, sl, tl, sh, th,
1737 ((sh/4) - (sl/4)) + 1, ((th/4) - (tl/4)) + 1);
1738 });
1739 DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD);
1740
1741 LOG_UCODE(" Tile:%d (%d,%d) -> (%d,%d) [%d x %d]",
1742 tileno, sl/4, tl/4, sh/4, th/4,
1743 ((sh/4) - (sl/4)) + 1, ((th/4) - (tl/4)) + 1);
1744}
1745
1746extern const char *pszImgFormat[8];// = {"RGBA", "YUV", "CI", "IA", "I", "?1", "?2", "?3"};
1747extern const char *pszImgSize[4];// = {"4", "8", "16", "32"};
1748void DLParser_SetTImg(Gfx *gfx)
1749{
1750 gRDP.textureIsChanged = true;
1751
1752 g_TI.dwFormat = gfx->setimg.fmt;
1753 g_TI.dwSize = gfx->setimg.siz;
1754 g_TI.dwWidth = gfx->setimg.width + 1;
1755 g_TI.dwAddr = RSPSegmentAddr((gfx->setimg.addr));
1756 g_TI.bpl = g_TI.dwWidth << g_TI.dwSize >> 1;
1757
1758#ifdef DEBUGGER
1759 if( g_TI.dwAddr == 0x00ffffff)
1760 {
1761 TRACE0("Check me here in setTimg");
1762 }
1763
1764 LOG_TEXTURE(TRACE4("SetTImage: 0x%08x Fmt: %s/%s Width in Pixel: %d\n", g_TI.dwAddr,
1765 pszImgFormat[g_TI.dwFormat], pszImgSize[g_TI.dwSize], g_TI.dwWidth));
1766
1767 DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD);
1768
1769 LOG_UCODE("Image: 0x%08x Fmt: %s/%s Width in Pixel: %d", g_TI.dwAddr,
1770 pszImgFormat[g_TI.dwFormat], pszImgSize[g_TI.dwSize], g_TI.dwWidth);
1771#endif
1772}
1773
1774void DLParser_TexRect(Gfx *gfx)
1775{
1776 //Gtexrect *gtextrect = (Gtexrect *)gfx;
1777
1778 if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer();
1779
1780 status.primitiveType = PRIM_TEXTRECT;
1781
1782 // This command used 128bits, and not 64 bits. This means that we have to look one
1783 // Command ahead in the buffer, and update the PC.
1784 uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction
1785 uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+4);
1786 uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4+8);
1787 uint32 dwHalf1 = *(uint32 *)(g_pRDRAMu8 + dwPC);
1788 uint32 dwHalf2 = *(uint32 *)(g_pRDRAMu8 + dwPC+8);
1789
1790 if( options.enableHackForGames == HACK_FOR_ALL_STAR_BASEBALL || options.enableHackForGames == HACK_FOR_MLB )
1791 {
1792 if( ((dwHalf1>>24) == 0xb4 || (dwHalf1>>24) == 0xb3 || (dwHalf1>>24) == 0xb2 || (dwHalf1>>24) == 0xe1) &&
1793 ((dwHalf2>>24) == 0xb4 || (dwHalf2>>24) == 0xb3 || (dwHalf2>>24) == 0xb2 || (dwHalf2>>24) == 0xf1) )
1794 {
1795 // Increment PC so that it points to the right place
1796 gDlistStack[gDlistStackPointer].pc += 16;
1797 }
1798 else
1799 {
1800 // Hack for some games, All_Star_Baseball_2000
1801 gDlistStack[gDlistStackPointer].pc += 8;
1802 dwCmd3 = dwCmd2;
1803 //dwCmd2 = dwHalf1;
1804 //dwCmd2 = 0;
1805
1806 // fix me here
1807 dwCmd2 = (((dwHalf1>>12)&0x03FF)<<17) | (((dwHalf1)&0x03FF)<<1);
1808 }
1809 }
1810 else
1811 {
1812 gDlistStack[gDlistStackPointer].pc += 16;
1813 }
1814
1815
1816 // Hack for Mario Tennis
1817 if( !status.bHandleN64RenderTexture && g_CI.dwAddr == g_ZI.dwAddr )
1818 {
1819 return;
1820 }
1821
1822
1823 LOG_UCODE("0x%08x: %08x %08x", dwPC, *(uint32 *)(g_pRDRAMu8 + dwPC+0), *(uint32 *)(g_pRDRAMu8 + dwPC+4));
1824 LOG_UCODE("0x%08x: %08x %08x", dwPC+8, *(uint32 *)(g_pRDRAMu8 + dwPC+8), *(uint32 *)(g_pRDRAMu8 + dwPC+8+4));
1825
1826 uint32 dwXH = (((gfx->words.w0)>>12)&0x0FFF)/4;
1827 uint32 dwYH = (((gfx->words.w0) )&0x0FFF)/4;
1828 uint32 tileno = ((gfx->words.w1)>>24)&0x07;
1829 uint32 dwXL = (((gfx->words.w1)>>12)&0x0FFF)/4;
1830 uint32 dwYL = (((gfx->words.w1) )&0x0FFF)/4;
1831 uint16 uS = (uint16)( dwCmd2>>16)&0xFFFF;
1832 uint16 uT = (uint16)( dwCmd2 )&0xFFFF;
1833 uint16 uDSDX = (uint16)(( dwCmd3>>16)&0xFFFF);
1834 uint16 uDTDY = (uint16)(( dwCmd3 )&0xFFFF);
1835
1836
1837 if( (int)dwXL >= gRDP.scissor.right || (int)dwYL >= gRDP.scissor.bottom || (int)dwXH < gRDP.scissor.left || (int)dwYH < gRDP.scissor.top )
1838 {
1839 // Clipping
1840 return;
1841 }
1842
1843 short s16S = *(short*)(&uS);
1844 short s16T = *(short*)(&uT);
1845
1846 short s16DSDX = *(short*)(&uDSDX);
1847 short s16DTDY = *(short*)(&uDTDY);
1848
1849 uint32 curTile = gRSP.curTile;
1850 ForceMainTextureIndex(tileno);
1851
1852 float fS0 = s16S / 32.0f;
1853 float fT0 = s16T / 32.0f;
1854
1855 float fDSDX = s16DSDX / 1024.0f;
1856 float fDTDY = s16DTDY / 1024.0f;
1857
1858 uint32 cycletype = gRDP.otherMode.cycle_type;
1859
1860 if (cycletype == CYCLE_TYPE_COPY)
1861 {
1862 fDSDX /= 4.0f; // In copy mode 4 pixels are copied at once.
1863 dwXH++;
1864 dwYH++;
1865 }
1866 else if (cycletype == CYCLE_TYPE_FILL)
1867 {
1868 dwXH++;
1869 dwYH++;
1870 }
1871
1872 if( fDSDX == 0 ) fDSDX = 1;
1873 if( fDTDY == 0 ) fDTDY = 1;
1874
1875 float fS1 = fS0 + (fDSDX * (dwXH - dwXL));
1876 float fT1 = fT0 + (fDTDY * (dwYH - dwYL));
1877
1878 LOG_UCODE(" Tile:%d Screen(%d,%d) -> (%d,%d)", tileno, dwXL, dwYL, dwXH, dwYH);
1879 LOG_UCODE(" Tex:(%#5f,%#5f) -> (%#5f,%#5f) (DSDX:%#5f DTDY:%#5f)",
1880 fS0, fT0, fS1, fT1, fDSDX, fDTDY);
1881 LOG_UCODE("");
1882
1883 float t0u0 = (fS0-gRDP.tiles[tileno].hilite_sl) * gRDP.tiles[tileno].fShiftScaleS;
1884 float t0v0 = (fT0-gRDP.tiles[tileno].hilite_tl) * gRDP.tiles[tileno].fShiftScaleT;
1885 float t0u1 = t0u0 + (fDSDX * (dwXH - dwXL))*gRDP.tiles[tileno].fShiftScaleS;
1886 float t0v1 = t0v0 + (fDTDY * (dwYH - dwYL))*gRDP.tiles[tileno].fShiftScaleT;
1887
1888 if( dwXL==0 && dwYL==0 && dwXH==windowSetting.fViWidth-1 && dwYH==windowSetting.fViHeight-1 &&
1889 t0u0 == 0 && t0v0==0 && t0u1==0 && t0v1==0 )
1890 {
1891 //Using TextRect to clear the screen
1892 }
1893 else
1894 {
1895 if( status.bHandleN64RenderTexture && //status.bDirectWriteIntoRDRAM &&
1896 g_pRenderTextureInfo->CI_Info.dwFormat == gRDP.tiles[tileno].dwFormat &&
1897 g_pRenderTextureInfo->CI_Info.dwSize == gRDP.tiles[tileno].dwSize &&
1898 gRDP.tiles[tileno].dwFormat == TXT_FMT_CI && gRDP.tiles[tileno].dwSize == TXT_SIZE_8b )
1899 {
1900 if( options.enableHackForGames == HACK_FOR_YOSHI )
1901 {
1902 // Hack for Yoshi background image
1903 PrepareTextures();
1904 TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno);
1905 DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_FLUSH_TRI || eventToPause == NEXT_TEXTRECT), {
1906 DebuggerAppendMsg("TexRect: tile=%d, X0=%d, Y0=%d, X1=%d, Y1=%d,\nfS0=%f, fT0=%f, ScaleS=%f, ScaleT=%f\n",
1907 gRSP.curTile, dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY);
1908 DebuggerAppendMsg("Pause after TexRect for Yoshi\n");
1909 });
1910
1911 }
1912 else
1913 {
1914 if( frameBufferOptions.bUpdateCIInfo )
1915 {
1916 PrepareTextures();
1917 TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno);
1918 }
1919
1920 if( !status.bDirectWriteIntoRDRAM )
1921 {
1922 CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY);
1923
1924 status.dwNumTrisRendered += 2;
1925 }
1926 }
1927 }
1928 else
1929 {
1930 CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY);
1931 status.bFrameBufferDrawnByTriangles = true;
1932
1933 status.dwNumTrisRendered += 2;
1934 }
1935 }
1936
1937 if( status.bHandleN64RenderTexture ) g_pRenderTextureInfo->maxUsedHeight = max(g_pRenderTextureInfo->maxUsedHeight,(int)dwYH);
1938
1939 ForceMainTextureIndex(curTile);
1940}
1941
1942
1943void DLParser_TexRectFlip(Gfx *gfx)
1944{
1945 status.bCIBufferIsRendered = true;
1946 status.primitiveType = PRIM_TEXTRECTFLIP;
1947
1948 // This command used 128bits, and not 64 bits. This means that we have to look one
1949 // Command ahead in the buffer, and update the PC.
1950 uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction
1951 uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+4);
1952 uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4+8);
1953
1954 // Increment PC so that it points to the right place
1955 gDlistStack[gDlistStackPointer].pc += 16;
1956
1957 uint32 dwXH = (((gfx->words.w0)>>12)&0x0FFF)/4;
1958 uint32 dwYH = (((gfx->words.w0) )&0x0FFF)/4;
1959 uint32 tileno = ((gfx->words.w1)>>24)&0x07;
1960 uint32 dwXL = (((gfx->words.w1)>>12)&0x0FFF)/4;
1961 uint32 dwYL = (((gfx->words.w1) )&0x0FFF)/4;
1962 uint32 dwS = ( dwCmd2>>16)&0xFFFF;
1963 uint32 dwT = ( dwCmd2 )&0xFFFF;
1964 int nDSDX = (int)(short)(( dwCmd3>>16)&0xFFFF);
1965 int nDTDY = (int)(short)(( dwCmd3 )&0xFFFF);
1966
1967 uint32 curTile = gRSP.curTile;
1968 ForceMainTextureIndex(tileno);
1969
1970 float fS0 = (float)dwS / 32.0f;
1971 float fT0 = (float)dwT / 32.0f;
1972
1973 float fDSDX = (float)nDSDX / 1024.0f;
1974 float fDTDY = (float)nDTDY / 1024.0f;
1975
1976 uint32 cycletype = gRDP.otherMode.cycle_type;
1977
1978 if (cycletype == CYCLE_TYPE_COPY)
1979 {
1980 fDSDX /= 4.0f; // In copy mode 4 pixels are copied at once.
1981 dwXH++;
1982 dwYH++;
1983 }
1984 else if (cycletype == CYCLE_TYPE_FILL)
1985 {
1986 dwXH++;
1987 dwYH++;
1988 }
1989
1990 float fS1 = fS0 + (fDSDX * (dwYH - dwYL));
1991 float fT1 = fT0 + (fDTDY * (dwXH - dwXL));
1992
1993 LOG_UCODE(" Tile:%d (%d,%d) -> (%d,%d)",
1994 tileno, dwXL, dwYL, dwXH, dwYH);
1995 LOG_UCODE(" Tex:(%#5f,%#5f) -> (%#5f,%#5f) (DSDX:%#5f DTDY:%#5f)",
1996 fS0, fT0, fS1, fT1, fDSDX, fDTDY);
1997 LOG_UCODE("");
1998
1999 float t0u0 = (fS0) * gRDP.tiles[tileno].fShiftScaleS-gRDP.tiles[tileno].sl;
2000 float t0v0 = (fT0) * gRDP.tiles[tileno].fShiftScaleT-gRDP.tiles[tileno].tl;
2001 float t0u1 = t0u0 + (fDSDX * (dwYH - dwYL))*gRDP.tiles[tileno].fShiftScaleS;
2002 float t0v1 = t0v0 + (fDTDY * (dwXH - dwXL))*gRDP.tiles[tileno].fShiftScaleT;
2003
2004 CRender::g_pRender->TexRectFlip(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1);
2005 status.dwNumTrisRendered += 2;
2006
2007 if( status.bHandleN64RenderTexture ) g_pRenderTextureInfo->maxUsedHeight = max(g_pRenderTextureInfo->maxUsedHeight,int(dwYL+(dwXH-dwXL)));
2008
2009 ForceMainTextureIndex(curTile);
2010}
2011
2012/************************************************************************/
2013/* */
2014/************************************************************************/
2015/*
2016 * TMEM emulation
2017 * There are 0x200's 64bits entry in TMEM
2018 * Usually, textures are loaded into TMEM at 0x0, and TLUT is loaded at 0x100
2019 * of course, the whole TMEM can be used by textures if TLUT is not used, and TLUT
2020 * can be at other address of TMEM.
2021 *
2022 * We don't want to emulate TMEM by creating a block of memory for TMEM and load
2023 * everything into the block of memory, this will be slow.
2024 */
2025typedef struct TmemInfoEntry{
2026 uint32 start;
2027 uint32 length;
2028 uint32 rdramAddr;
2029 TmemInfoEntry* next;
2030} TmemInfoEntry;
2031
2032const int tmenMaxEntry=20;
2033TmemInfoEntry tmenEntryBuffer[20]={{0}};
2034TmemInfoEntry *g_pTMEMInfo=NULL;
2035TmemInfoEntry *g_pTMEMFreeList=tmenEntryBuffer;
2036
2037void TMEM_Init()
2038{
2039 g_pTMEMInfo=NULL;
2040 g_pTMEMFreeList=tmenEntryBuffer;
2041 int i;
2042 for( i=0; i<tmenMaxEntry; i++ )
2043 {
2044 tmenEntryBuffer[i].start=0;
2045 tmenEntryBuffer[i].length=0;
2046 tmenEntryBuffer[i].rdramAddr=0;
2047 tmenEntryBuffer[i].next = &(tmenEntryBuffer[i+1]);
2048 }
2049 tmenEntryBuffer[i-1].next = NULL;
2050}
2051
2052void TMEM_SetBlock(uint32 tmemstart, uint32 length, uint32 rdramaddr)
2053{
2054 TmemInfoEntry *p=g_pTMEMInfo;
2055
2056 if( p == NULL )
2057 {
2058 // Move an entry from freelist and link it to the header
2059 p = g_pTMEMFreeList;
2060 g_pTMEMFreeList = g_pTMEMFreeList->next;
2061
2062 p->start = tmemstart;
2063 p->length = length;
2064 p->rdramAddr = rdramaddr;
2065 p->next = NULL;
2066 }
2067 else
2068 {
2069 while ( tmemstart > (p->start+p->length) )
2070 {
2071 if( p->next != NULL ) {
2072 p = p->next;
2073 continue;
2074 }
2075 else {
2076 break;
2077 }
2078 }
2079
2080 if ( p->start == tmemstart )
2081 {
2082 // need to replace the block of 'p'
2083 // or append a new block depend the block lengths
2084 if( length == p->length )
2085 {
2086 p->rdramAddr = rdramaddr;
2087 return;
2088 }
2089 else if( length < p->length )
2090 {
2091 TmemInfoEntry *newentry = g_pTMEMFreeList;
2092 g_pTMEMFreeList = g_pTMEMFreeList->next;
2093
2094 newentry->length = p->length - length;
2095 newentry->next = p->next;
2096 newentry->rdramAddr = p->rdramAddr + p->length;
2097 newentry->start = p->start + p->length;
2098
2099 p->length = length;
2100 p->next = newentry;
2101 p->rdramAddr = rdramaddr;
2102 }
2103 }
2104 else if( p->start > tmemstart )
2105 {
2106 // p->start > tmemstart, need to insert the new block before 'p'
2107 TmemInfoEntry *newentry = g_pTMEMFreeList;
2108 g_pTMEMFreeList = g_pTMEMFreeList->next;
2109
2110 if( length+tmemstart < p->start+p->length )
2111 {
2112 newentry->length = p->length - length;
2113 newentry->next = p->next;
2114 newentry->rdramAddr = p->rdramAddr + p->length;
2115 newentry->start = p->start + p->length;
2116
2117 p->length = length;
2118 p->next = newentry;
2119 p->rdramAddr = rdramaddr;
2120 p->start = tmemstart;
2121 }
2122 else if( length+tmemstart == p->start+p->length )
2123 {
2124
2125 }
2126 }
2127 else
2128 {
2129 }
2130 }
2131}
2132
2133uint32 TMEM_GetRdramAddr(uint32 tmemstart, uint32 length)
2134{
2135 return 0;
2136}
2137
2138
2139/*
2140 * New implementation of texture loading
2141 */
2142
2143bool IsTmemFlagValid(uint32 tmemAddr)
2144{
2145 uint32 index = tmemAddr>>5;
2146 uint32 bitIndex = (tmemAddr&0x1F);
2147 return ((g_TmemFlag[index] & (1<<bitIndex))!=0);
2148}
2149
2150uint32 GetValidTmemInfoIndex(uint32 tmemAddr)
2151{
2152 return 0;
2153 uint32 index = tmemAddr>>5;
2154 uint32 bitIndex = (tmemAddr&0x1F);
2155
2156 if ((g_TmemFlag[index] & (1<<bitIndex))!=0 ) //This address is valid
2157 return tmemAddr;
2158 else
2159 {
2160 for( uint32 x=index+1; x != 0; x-- )
2161 {
2162 uint32 i = x - 1;
2163 if( g_TmemFlag[i] != 0 )
2164 {
2165 for( uint32 y=0x20; y != 0; y-- )
2166 {
2167 uint32 j = y - 1;
2168 if( (g_TmemFlag[i] & (1<<j)) != 0 )
2169 {
2170 return ((i<<5)+j);
2171 }
2172 }
2173 }
2174 }
2175 TRACE0("Error, check me");
2176 return 0;
2177 }
2178}
2179
2180
2181void SetTmemFlag(uint32 tmemAddr, uint32 size)
2182{
2183 uint32 index = tmemAddr>>5;
2184 uint32 bitIndex = (tmemAddr&0x1F);
2185
2186#ifdef DEBUGGER
2187 if( size > 0x200 )
2188 {
2189 DebuggerAppendMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size);
2190 size = 0x200-tmemAddr;
2191 }
2192#endif
2193
2194 if( bitIndex == 0 )
2195 {
2196 uint32 i;
2197 for( i=0; i< (size>>5); i++ )
2198 {
2199 g_TmemFlag[index+i] = 0;
2200 }
2201
2202 if( (size&0x1F) != 0 )
2203 {
2204 //ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size);
2205 g_TmemFlag[index+i] &= ~((1<<(size&0x1F))-1);
2206 }
2207
2208 g_TmemFlag[index] |= 1;
2209 }
2210 else
2211 {
2212 if( bitIndex + size <= 0x1F )
2213 {
2214 uint32 val = g_TmemFlag[index];
2215 uint32 mask = (1<<(bitIndex))-1;
2216 mask |= ~((1<<(bitIndex + size))-1);
2217 val &= mask;
2218 val |= (1<<bitIndex);
2219 g_TmemFlag[index] = val;
2220 }
2221 else
2222 {
2223 //ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size);
2224 uint32 val = g_TmemFlag[index];
2225 uint32 mask = (1<<bitIndex)-1;
2226 val &= mask;
2227 val |= (1<<bitIndex);
2228 g_TmemFlag[index] = val;
2229 index++;
2230 size -= (0x20-bitIndex);
2231
2232 uint32 i;
2233 for( i=0; i< (size>>5); i++ )
2234 {
2235 g_TmemFlag[index+i] = 0;
2236 }
2237
2238 if( (size&0x1F) != 0 )
2239 {
2240 //ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size);
2241 g_TmemFlag[index+i] &= ~((1<<(size&0x1F))-1);
2242 }
2243 }
2244 }
2245}
2246