1 #include <stdint.h>
2 
3 #include <retro_miscellaneous.h>
4 
5 #include "osal_preproc.h"
6 #include "float.h"
7 #include "ConvertImage.h"
8 #include "DeviceBuilder.h"
9 #include "FrameBuffer.h"
10 #include "Render.h"
11 #include "Timing.h"
12 
13 #include "../../Graphics/GBI.h"
14 #include "../../Graphics/RDP/gDP_funcs_prot.h"
15 #include "../../Graphics/image_convert.h"
16 
17 extern TMEMLoadMapInfo g_tmemLoadAddrMap[0x200]; /* Totally 4KB TMEM */
18 extern TMEMLoadMapInfo g_tmemInfo0;              /* Info for Tmem=0 */
19 extern TMEMLoadMapInfo g_tmemInfo1;              /* Info for Tmem=0x100 */
20 extern uint32_t g_TmemFlag[16];
21 extern uint32_t g_TxtLoadBy;
22 
UnswapCopy(void * src,void * dest,uint32_t numBytes)23 static inline void UnswapCopy( void *src, void *dest, uint32_t numBytes )
24 {
25    // copy leading bytes
26    int leadingBytes = ((uintptr_t)src) & 3;
27    if (leadingBytes != 0)
28    {
29       leadingBytes = 4-leadingBytes;
30       if ((unsigned int)leadingBytes > numBytes)
31          leadingBytes = numBytes;
32       numBytes -= leadingBytes;
33 
34 #ifdef MSB_FIRST
35       src = (void *)((uintptr_t)src);
36 #else
37       src = (void *)((uintptr_t)src ^ 3);
38 #endif
39       for (int i = 0; i < leadingBytes; i++)
40       {
41          *(uint8_t *)(dest) = *(uint8_t *)(src);
42          dest = (void *)((uintptr_t)dest+1);
43          src  = (void *)((uintptr_t)src -1);
44       }
45       src = (void *)((uintptr_t)src+5);
46    }
47 
48    // copy dwords
49    int numDWords = numBytes >> 2;
50    while (numDWords--)
51    {
52       uint32_t dword = *(uint32_t *)src;
53       dword = ((dword<<24)|((dword<<8)&0x00FF0000)|((dword>>8)&0x0000FF00)|(dword>>24));
54       *(uint32_t *)dest = dword;
55       dest = (void *)((uintptr_t)dest+4);
56       src  = (void *)((uintptr_t)src +4);
57    }
58 
59    // copy trailing bytes
60    int trailingBytes = numBytes & 3;
61    if (trailingBytes)
62    {
63 #ifdef MSB_FIRST
64       src = (void *)((uintptr_t)src);
65 #else
66       src = (void *)((uintptr_t)src ^ 3);
67 #endif
68       for (int i = 0; i < trailingBytes; i++)
69       {
70          *(uint8_t *)(dest) = *(uint8_t *)(src);
71          dest = (void *)((uintptr_t)dest+1);
72          src  = (void *)((uintptr_t)src -1);
73       }
74    }
75 }
76 
DWordInterleave(void * mem,uint32_t numDWords)77 static inline void DWordInterleave( void *mem, uint32_t numDWords )
78 {
79     int tmp;
80     while( numDWords-- )
81     {
82         tmp = *(int *)((uintptr_t)mem + 0);
83         *(int *)((uintptr_t)mem + 0) = *(int *)((uintptr_t)mem + 4);
84         *(int *)((uintptr_t)mem + 4) = tmp;
85         mem = (void *)((uintptr_t)mem + 8);
86     }
87 }
88 
QWordInterleave(void * mem,uint32_t numDWords)89 static inline void QWordInterleave( void *mem, uint32_t numDWords )
90 {
91    numDWords >>= 1; // qwords
92    while( numDWords-- )
93    {
94       int tmp0, tmp1;
95       tmp0 = *(int *)((uintptr_t)mem + 0);
96       tmp1 = *(int *)((uintptr_t)mem + 4);
97       *(int *)((uintptr_t)mem + 0) = *(int *)((uintptr_t)mem + 8);
98       *(int *)((uintptr_t)mem + 8) = tmp0;
99       *(int *)((uintptr_t)mem + 4) = *(int *)((uintptr_t)mem + 12);
100       *(int *)((uintptr_t)mem + 12) = tmp1;
101       mem = (void *)((uintptr_t)mem + 16);
102    }
103 }
104 
SetTmemFlag(uint32_t tmemAddr,uint32_t size)105 static void SetTmemFlag(uint32_t tmemAddr, uint32_t size)
106 {
107     uint32_t index    = tmemAddr>>5;
108     uint32_t bitIndex = (tmemAddr&0x1F);
109 
110     if( bitIndex == 0 )
111     {
112         uint32_t i;
113         for( i=0; i< (size>>5); i++ )
114         {
115             g_TmemFlag[index+i] = 0;
116         }
117 
118         if( (size&0x1F) != 0 )
119         {
120             //ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size);
121             g_TmemFlag[index+i] &= ~((1<<(size&0x1F))-1);
122         }
123 
124         g_TmemFlag[index] |= 1;
125     }
126     else
127     {
128         if( bitIndex + size <= 0x1F )
129         {
130             uint32_t val = g_TmemFlag[index];
131             uint32_t mask = (1<<(bitIndex))-1;
132             mask |= ~((1<<(bitIndex + size))-1);
133             val &= mask;
134             val |= (1<<bitIndex);
135             g_TmemFlag[index] = val;
136         }
137         else
138         {
139             //ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size);
140             uint32_t val = g_TmemFlag[index];
141             uint32_t mask = (1<<bitIndex)-1;
142             val &= mask;
143             val |= (1<<bitIndex);
144             g_TmemFlag[index] = val;
145             index++;
146             size -= (0x20-bitIndex);
147 
148             uint32_t i;
149             for( i=0; i< (size>>5); i++ )
150             {
151                 g_TmemFlag[index+i] = 0;
152             }
153 
154             if( (size&0x1F) != 0 )
155             {
156                 //ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size);
157                 g_TmemFlag[index+i] &= ~((1<<(size&0x1F))-1);
158             }
159         }
160     }
161 }
162 
ricegDPSetScissor(void * data,uint32_t mode,float ulx,float uly,float lrx,float lry)163 void ricegDPSetScissor(void *data,
164       uint32_t mode, float ulx, float uly, float lrx, float lry )
165 {
166    ScissorType *tempScissor = (ScissorType*)data;
167 
168    tempScissor->mode = mode;
169    tempScissor->x0   = ulx;
170    tempScissor->y0   = uly;
171    tempScissor->x1   = lrx;
172    tempScissor->y1   = lry;
173 }
174 
ricegDPSetFillColor(uint32_t c)175 void ricegDPSetFillColor(uint32_t c)
176 {
177    DP_Timing(DLParser_SetFillColor);
178    gRDP.fillColor = Convert555ToRGBA(c);
179 }
180 
ricegDPSetFogColor(uint32_t r,uint32_t g,uint32_t b,uint32_t a)181 void ricegDPSetFogColor(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
182 {
183    DP_Timing(DLParser_SetFogColor);
184    CRender::g_pRender->SetFogColor(r, g, b, a );
185 }
186 
ricegDPFillRect(int32_t ulx,int32_t uly,int32_t lrx,int32_t lry)187 void ricegDPFillRect(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry )
188 {
189    uint8_t *rdram_u8 = (uint8_t*)gfx_info.RDRAM;
190 
191    /* Note, in some modes, the right/bottom lines aren't drawn */
192 
193    if( gRDP.otherMode.cycle_type >= G_CYC_COPY )
194    {
195       ++lrx;
196       ++lry;
197    }
198 
199    //TXTRBUF_DETAIL_DUMP(DebuggerAppendMsg("FillRect: X0=%d, Y0=%d, X1=%d, Y1=%d, Color=0x%08X", ulx, uly, lrx, lry, gRDP.originalFillColor););
200 
201    // Skip this
202    if( status.bHandleN64RenderTexture && options.enableHackForGames == HACK_FOR_BANJO_TOOIE )
203       return;
204 
205    if (IsUsedAsDI(g_CI.dwAddr))
206    {
207       // Clear the Z Buffer
208       if( ulx != 0 || uly != 0 || windowSetting.uViWidth- lrx > 1 || windowSetting.uViHeight - lry > 1)
209       {
210          if( options.enableHackForGames == HACK_FOR_GOLDEN_EYE )
211          {
212             // GoldenEye is using double zbuffer
213             if( g_CI.dwAddr == g_ZI.dwAddr )
214             {
215                // The zbuffer is the upper screen
216                COORDRECT rect={int(ulx * windowSetting.fMultX),int(uly * windowSetting.fMultY),int(lrx * windowSetting.fMultX),int(lry * windowSetting.fMultY)};
217                CRender::g_pRender->ClearBuffer(false,true,rect);   //Check me
218                LOG_UCODE("    Clearing ZBuffer");
219             }
220             else
221             {
222                // The zbuffer is the lower screen
223                int h = (g_CI.dwAddr-g_ZI.dwAddr)/g_CI.dwWidth/2;
224                COORDRECT rect={int(ulx * windowSetting.fMultX),int((uly + h)*windowSetting.fMultY),int(lrx * windowSetting.fMultX),int((lry + h)*windowSetting.fMultY)};
225                CRender::g_pRender->ClearBuffer(false,true,rect);   //Check me
226                LOG_UCODE("    Clearing ZBuffer");
227             }
228          }
229          else
230          {
231             COORDRECT rect={int(ulx * windowSetting.fMultX),int(uly * windowSetting.fMultY),int(lrx * windowSetting.fMultX),int(lry * windowSetting.fMultY)};
232             CRender::g_pRender->ClearBuffer(false,true,rect);   //Check me
233             LOG_UCODE("    Clearing ZBuffer");
234          }
235       }
236       else
237       {
238          CRender::g_pRender->ClearBuffer(false,true);    //Check me
239          LOG_UCODE("    Clearing ZBuffer");
240       }
241 
242       if( g_curRomInfo.bEmulateClear )
243       {
244          // Emulating Clear, by write the memory in RDRAM
245          uint16_t color = (uint16_t)gRDP.originalFillColor;
246          uint32_t pitch = g_CI.dwWidth<<1;
247          int64_t base   = (int64_t)(rdram_u8 + g_CI.dwAddr);
248 
249          for( uint32_t i = uly; i < lry; i++ )
250          {
251             for( uint32_t j= ulx; j < lrx; j++ )
252                *(uint16_t*)((base+pitch*i+j)^2) = color;
253          }
254       }
255    }
256    else if( status.bHandleN64RenderTexture )
257    {
258       if( !status.bCIBufferIsRendered )
259          g_pFrameBufferManager->ActiveTextureBuffer();
260 
261       int cond1 =  (((int)ulx < status.leftRendered)     ? ((int)ulx) : (status.leftRendered));
262       int cond2 =  (((int)uly < status.topRendered)      ? ((int)uly) : (status.topRendered));
263       int cond3 =  ((status.rightRendered > ((int)lrx))  ? ((int)lrx) : (status.rightRendered));
264       int cond4 =  ((status.bottomRendered > ((int)lry)) ? ((int)lry) : (status.bottomRendered));
265       int cond5 =  ((g_pRenderTextureInfo->maxUsedHeight > ((int)lry)) ? ((int)lry) : (g_pRenderTextureInfo->maxUsedHeight));
266 
267       status.leftRendered = status.leftRendered < 0   ? ulx  : cond1;
268       status.topRendered = status.topRendered<0       ? uly : cond2;
269       status.rightRendered = status.rightRendered<0   ? lrx : cond3;
270       status.bottomRendered = status.bottomRendered<0 ? lry : cond4;
271 
272       g_pRenderTextureInfo->maxUsedHeight = cond5;
273 
274       if( status.bDirectWriteIntoRDRAM || ( ulx ==0 && uly == 0 && (lrx == g_pRenderTextureInfo->N64Width || lrx == g_pRenderTextureInfo->N64Width-1 ) ) )
275       {
276          if( g_pRenderTextureInfo->CI_Info.dwSize == G_IM_SIZ_16b )
277          {
278             uint16_t color = (uint16_t)gRDP.originalFillColor;
279             uint32_t pitch = g_pRenderTextureInfo->N64Width<<1;
280             int64_t base   = (int64_t)(rdram_u8 + g_pRenderTextureInfo->CI_Info.dwAddr);
281             for( uint32_t i = uly; i < lry; i++ )
282             {
283                for( uint32_t j= ulx; j< lrx; j++ )
284                   *(uint16_t*)((base+pitch*i+j)^2) = color;
285             }
286          }
287          else
288          {
289             uint8_t color  = (uint8_t)gRDP.originalFillColor;
290             uint32_t pitch = g_pRenderTextureInfo->N64Width;
291             int64_t base   = (int64_t) (rdram_u8 + g_pRenderTextureInfo->CI_Info.dwAddr);
292             for( uint32_t i= uly; i< lry; i++ )
293             {
294                for( uint32_t j= ulx; j< lrx; j++ )
295                   *(uint8_t*)((base+pitch*i+j)^3) = color;
296             }
297          }
298 
299          status.bFrameBufferDrawnByTriangles = false;
300       }
301       else
302       {
303          status.bFrameBufferDrawnByTriangles = true;
304       }
305       status.bFrameBufferDrawnByTriangles = true;
306 
307       if( !status.bDirectWriteIntoRDRAM )
308       {
309          status.bFrameBufferIsDrawn = true;
310 
311          //if( ulx ==0 && uly ==0 && (lrx == g_pRenderTextureInfo->N64Width || lrx == g_pRenderTextureInfo->N64Width-1 ) && gRDP.fillColor == 0)
312          //{
313          //  CRender::g_pRender->ClearBuffer(true,false);
314          //}
315          //else
316          {
317             if( gRDP.otherMode.cycle_type == G_CYC_FILL )
318             {
319                CRender::g_pRender->FillRect(ulx, uly, lrx, lry, gRDP.fillColor);
320             }
321             else
322             {
323                COLOR primColor = GetPrimitiveColor();
324                CRender::g_pRender->FillRect(ulx, uly, lrx, lry, primColor);
325             }
326          }
327       }
328    }
329    else
330    {
331       LOG_UCODE("    Filling Rectangle");
332       if( frameBufferOptions.bSupportRenderTextures || frameBufferOptions.bCheckBackBufs )
333       {
334          int cond1 =  (((int)ulx < status.leftRendered)     ? ((int)ulx) : (status.leftRendered));
335          int cond2 =  (((int)uly < status.topRendered)      ? ((int)uly) : (status.topRendered));
336          int cond3 =  ((status.rightRendered > ((int)lrx))  ? ((int)lrx) : (status.rightRendered));
337          int cond4 =  ((status.bottomRendered > ((int)lry)) ? ((int)lry) : (status.bottomRendered));
338          int cond5 =  ((g_pRenderTextureInfo->maxUsedHeight > ((int)lry)) ? ((int)lry) : (g_pRenderTextureInfo->maxUsedHeight));
339 
340          if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer();
341 
342          status.leftRendered = status.leftRendered<0     ? ulx  : cond1;
343          status.topRendered = status.topRendered<0       ? uly  : cond2;
344          status.rightRendered = status.rightRendered<0   ? lrx  : cond3;
345          status.bottomRendered = status.bottomRendered<0 ? lry  : cond4;
346       }
347 
348       if( gRDP.otherMode.cycle_type == G_CYC_FILL )
349       {
350          if( !status.bHandleN64RenderTexture || g_pRenderTextureInfo->CI_Info.dwSize == G_IM_SIZ_16b )
351             CRender::g_pRender->FillRect(ulx, uly, lrx, lry, gRDP.fillColor);
352       }
353       else
354       {
355          COLOR primColor = GetPrimitiveColor();
356          //if( RGBA_GETALPHA(primColor) != 0 )
357          {
358             CRender::g_pRender->FillRect(ulx, uly, lrx, lry, primColor);
359          }
360       }
361    }
362 }
363 
ricegDPSetEnvColor(uint32_t r,uint32_t g,uint32_t b,uint32_t a)364 void ricegDPSetEnvColor(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
365 {
366    gRDP.colorsAreReloaded = true;
367    gRDP.envColor = COLOR_RGBA(r, g, b, a);
368    gRDP.fvEnvColor[0] = r / 255.0f;
369    gRDP.fvEnvColor[1] = g / 255.0f;
370    gRDP.fvEnvColor[2] = b / 255.0f;
371    gRDP.fvEnvColor[3] = a / 255.0f;
372 }
373 
ricegDPLoadBlock(uint32_t tileno,uint32_t uls,uint32_t ult,uint32_t lrs,uint32_t dxt)374 void ricegDPLoadBlock( uint32_t tileno, uint32_t uls, uint32_t ult,
375       uint32_t lrs, uint32_t dxt )
376 {
377    TileAdditionalInfo *tileinfo   = &gRDP.tilesinfo[tileno];
378    gDPTile            *tile       = &gDP.tiles[tileno];
379 
380    tileinfo->bForceWrapS = tileinfo->bForceWrapT = tileinfo->bForceClampS = tileinfo->bForceClampT = false;
381 
382    uint32_t size     = lrs+1;
383 
384    if( tile->size == G_IM_SIZ_32b )
385       size<<=1;
386 
387    SetTmemFlag(tile->tmem, size>>2);
388 
389    TMEMLoadMapInfo &info = g_tmemLoadAddrMap[tile->tmem];
390 
391    info.bSwapped = (dxt == 0? true : false);
392 
393    info.sl = tileinfo->hilite_sl = tile->lrs = uls;
394    info.sh = tileinfo->hilite_sh  = tile->uls = lrs;
395    info.tl = tile->lrt = ult;
396    info.th = tile->ult = dxt;
397 
398    tileinfo->bSizeIsValid = false;
399 
400    for( int i=0; i<8; i++ )
401    {
402       if( gDP.tiles[i].tmem == tile->tmem )
403          tileinfo->lastTileCmd = CMD_LOADBLOCK;
404    }
405 
406    info.dwLoadAddress = g_TI.dwAddr;
407    info.bSetBy        = CMD_LOADBLOCK;
408    info.dxt           = dxt;
409    info.dwLine        = tile->line;
410 
411    info.dwFormat      = g_TI.dwFormat;
412    info.dwSize        = g_TI.dwSize;
413    info.dwWidth       = g_TI.dwWidth;
414    info.dwTotalWords  = size;
415    info.dwTmem        = tile->tmem;
416 
417    if( gDP.tiles[tileno].tmem == 0 )
418    {
419       if( size >= 1024 )
420       {
421          memcpy(&g_tmemInfo0, &info, sizeof(TMEMLoadMapInfo) );
422          g_tmemInfo0.dwTotalWords = size>>2;
423       }
424 
425       if( size == 2048 )
426       {
427          memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) );
428          g_tmemInfo1.dwTotalWords = size>>2;
429       }
430    }
431    else if( tile->tmem == 0x100 )
432    {
433       if( size == 1024 )
434       {
435          memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) );
436          g_tmemInfo1.dwTotalWords = size>>2;
437       }
438    }
439 
440    g_TxtLoadBy = CMD_LOADBLOCK;
441 
442 
443    if( options.bUseFullTMEM )
444    {
445       uint8_t *rdram_u8 = (uint8_t*)gfx_info.RDRAM;
446       uint32_t bytes = (lrs + 1) << tile->size >> 1;
447       uint32_t address = g_TI.dwAddr + ult * g_TI.bpl + (uls << g_TI.dwSize >> 1);
448       if ((bytes == 0) || ((address + bytes) > g_dwRamSize) || (((tile->tmem << 3) + bytes) > 4096))
449       {
450          return;
451       }
452       uint64_t* src = (uint64_t*)(rdram_u8 + address);
453       uint64_t* dest = &g_Tmem.g_Tmem64bit[tile->tmem];
454 
455       if( dxt > 0)
456       {
457          void (*Interleave)( void *mem, uint32_t numDWords );
458 
459          uint32_t line = (2047 + dxt) / dxt;
460          uint32_t bpl = line << 3;
461          uint32_t height = bytes / bpl;
462 
463          if (tile->size == G_IM_SIZ_32b)
464             Interleave = QWordInterleave;
465          else
466             Interleave = DWordInterleave;
467 
468          for (uint32_t y = 0; y < height; y++)
469          {
470             UnswapCopy( src, dest, bpl );
471             if (y & 1) Interleave( dest, line );
472 
473             src += line;
474             dest += line;
475          }
476       }
477       else
478       {
479          UnswapCopy( src, dest, bytes );
480       }
481    }
482 }
483 
ricegDPLoadTile(uint32_t tileno,uint32_t uls,uint32_t ult,uint32_t lrs,uint32_t lrt)484 void ricegDPLoadTile(uint32_t tileno, uint32_t uls, uint32_t ult,
485       uint32_t lrs, uint32_t lrt)
486 {
487    TileAdditionalInfo *tileinfo = &gRDP.tilesinfo[tileno];
488    gDPTile                *tile = &gDP.tiles[tileno];
489    tileinfo->bForceWrapS = tileinfo->bForceWrapT = tileinfo->bForceClampS = tileinfo->bForceClampT = false;
490 
491    if (lrt < ult)
492       swapdword(&lrt, &ult);
493    if (lrs < uls)
494       swapdword(&lrs, &uls);
495 
496    tileinfo->hilite_sl = tile->lrs = uls;
497    tileinfo->hilite_tl = tile->lrt = ult;
498    tileinfo->hilite_sh = tile->uls = lrs;
499    tileinfo->hilite_th = tile->ult = lrt;
500    tileinfo->bSizeIsValid = true;
501 
502    // compute block height, and bpl of source and destination
503    uint32_t bpl    = (lrs - uls + 1) << tile->size >> 1;
504    uint32_t height = lrt - ult + 1;
505    uint32_t line   = tile->line;
506    if (tile->size == G_IM_SIZ_32b)
507       line <<= 1;
508 
509    if (((tile->tmem << 3) + line * height) > 4096)  // check destination ending point (TMEM is 4k bytes)
510       return;
511 
512    if( options.bUseFullTMEM )
513    {
514       uint8_t *rdram_u8 = (uint8_t*)gfx_info.RDRAM;
515       void (*Interleave)( void *mem, uint32_t numDWords );
516 
517       if( g_TI.bpl == 0 )
518       {
519          if( options.enableHackForGames == HACK_FOR_BUST_A_MOVE )
520          {
521             g_TI.bpl = 1024;        // Hack for Bust-A-Move
522          }
523          else
524          {
525             TRACE0("Warning: g_TI.bpl = 0" );
526          }
527       }
528 
529       uint32_t address = g_TI.dwAddr + tile->lrt * g_TI.bpl + (tile->lrs << g_TI.dwSize >> 1);
530       uint64_t* src = (uint64_t*)&rdram_u8[address];
531       uint8_t* dest = (uint8_t*)&g_Tmem.g_Tmem64bit[tile->tmem];
532 
533       if ((address + height * bpl) > g_dwRamSize) // check source ending point
534       {
535          return;
536       }
537 
538       // Line given for 32-bit is half what it seems it should since they split the
539       // high and low words. I'm cheating by putting them together.
540       if (tile->size == G_IM_SIZ_32b)
541       {
542          Interleave = QWordInterleave;
543       }
544       else
545       {
546          Interleave = DWordInterleave;
547       }
548 
549       if( tile->line == 0 )
550       {
551          //tile->line = 1;
552          return;
553       }
554 
555       for (uint32_t y = 0; y < height; y++)
556       {
557          UnswapCopy( src, dest, bpl );
558          if (y & 1) Interleave( dest, line );
559 
560          src += g_TI.bpl;
561          dest += line;
562       }
563    }
564 
565 
566    for( int i=0; i<8; i++ )
567    {
568       if( gDP.tiles[i].tmem == tile->tmem )
569          gRDP.tilesinfo[i].lastTileCmd = CMD_LOADTILE;
570    }
571 
572    uint32_t size = line * height;
573    SetTmemFlag(tile->tmem, size );
574 
575    TMEMLoadMapInfo &info = g_tmemLoadAddrMap[tile->tmem];
576 
577    info.dwLoadAddress = g_TI.dwAddr;
578    info.dwFormat = g_TI.dwFormat;
579    info.dwSize = g_TI.dwSize;
580    info.dwWidth = g_TI.dwWidth;
581 
582    info.sl = uls;
583    info.sh = lrs;
584    info.tl = ult;
585    info.th = lrt;
586 
587    info.dxt = 0;
588    info.dwLine = tile->line;
589    info.dwTmem = tile->tmem;
590    info.dwTotalWords = size<<2;
591 
592    info.bSetBy = CMD_LOADTILE;
593    info.bSwapped =false;
594 
595    g_TxtLoadBy = CMD_LOADTILE;
596 
597    if( tile->tmem == 0 )
598    {
599       if( size >= 256 )
600       {
601          memcpy(&g_tmemInfo0, &info, sizeof(TMEMLoadMapInfo) );
602          g_tmemInfo0.dwTotalWords = size;
603       }
604 
605       if( size == 512 )
606       {
607          memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) );
608          g_tmemInfo1.dwTotalWords = size;
609       }
610    }
611    else if( tile->tmem == 0x100 )
612    {
613       if( size == 256 )
614       {
615          memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) );
616          g_tmemInfo1.dwTotalWords = size;
617       }
618    }
619 }
620 
ricegDPLoadTLUT(uint16_t dwCount,uint32_t tileno,uint32_t uls,uint32_t ult,uint32_t lrs,uint32_t lrt)621 void ricegDPLoadTLUT(uint16_t dwCount, uint32_t tileno, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t lrt)
622 {
623    uint8_t *rdram_u8      = (uint8_t*)gfx_info.RDRAM;
624    /* Starting location in the palettes */
625    uint32_t dwTMEMOffset  = gDP.tiles[tileno].tmem - 256;
626    /* Number to copy */
627    uint32_t dwRDRAMOffset = 0;
628 
629    TileAdditionalInfo *tileinfo = &gRDP.tilesinfo[tileno];
630    gDPTile            *tile     = &gDP.tiles[tileno];
631 
632    tileinfo->bForceWrapS = tileinfo->bForceWrapT = tileinfo->bForceClampS = tileinfo->bForceClampT = false;
633 
634    tileinfo->hilite_sl = tile->lrs = uls;
635    tileinfo->hilite_tl = tile->lrt = ult;
636    tile->uls = lrs;
637    tile->ult = lrt;
638    tileinfo->bSizeIsValid = true;
639 
640    tileinfo->lastTileCmd = CMD_LOADTLUT;
641 
642    dwCount = (lrs - uls)+1;
643    dwRDRAMOffset = (uls + ult*g_TI.dwWidth )*2;
644    uint32_t dwPalAddress = g_TI.dwAddr + dwRDRAMOffset;
645 
646    /* Copy PAL to the PAL memory */
647    uint16_t *srcPal = (uint16_t*)(rdram_u8 + (dwPalAddress& (g_dwRamSize-1)) );
648    for (uint32_t i=0; i<dwCount && i<0x100; i++)
649       g_wRDPTlut[(i+dwTMEMOffset)^1] = srcPal[i^1];
650 
651    if( options.bUseFullTMEM )
652    {
653       for (uint32_t i=0; i<dwCount && i+tile->tmem < 0x200; i++)
654          *(uint16_t*)(&g_Tmem.g_Tmem64bit[tile->tmem + i]) = srcPal[i^1];
655    }
656 
657    extern bool RevTlutTableNeedUpdate;
658    RevTlutTableNeedUpdate = true;
659    g_TxtLoadBy = CMD_LOADTLUT;
660 }
661