6 #define min(a,b) ((a) < (b) ? (a) : (b))
21 //#include "FrameBuffer.h"
26 #define FORMAT_RGBA4444 3
27 #define FORMAT_RGBA5551 4
28 #define FORMAT_RGBA8888 5
30 //#define PRINT_TEXTUREFORMAT
34 typedef u32 (*GetTexelFunc)( void *src, u16 x, u16 i, u8 palette );
36 u32 GetNone( void *src, u16 x, u16 i, u8 palette )
41 u32 GetCI4IA_RGBA4444( void *src, u16 x, u16 i, u8 palette )
43 u8 color4B = ((u8*)src)[(x>>1)^(i<<1)];
45 return IA88_RGBA4444( *(u16*)&TMEM[256 + (palette << 4) + (color4B & 0x0F)] );
47 return IA88_RGBA4444( *(u16*)&TMEM[256 + (palette << 4) + (color4B >> 4)] );
50 u32 GetCI4IA_RGBA8888( void *src, u16 x, u16 i, u8 palette )
52 u8 color4B = ((u8*)src)[(x>>1)^(i<<1)];
54 return IA88_RGBA8888( *(u16*)&TMEM[256 + (palette << 4) + (color4B & 0x0F)] );
56 return IA88_RGBA8888( *(u16*)&TMEM[256 + (palette << 4) + (color4B >> 4)] );
59 u32 GetCI4RGBA_RGBA5551( void *src, u16 x, u16 i, u8 palette )
61 u8 color4B = ((u8*)src)[(x>>1)^(i<<1)];
63 return RGBA5551_RGBA5551( *(u16*)&TMEM[256 + (palette << 4) + (color4B & 0x0F)] );
65 return RGBA5551_RGBA5551( *(u16*)&TMEM[256 + (palette << 4) + (color4B >> 4)] );
68 u32 GetCI4RGBA_RGBA8888( void *src, u16 x, u16 i, u8 palette )
70 u8 color4B = ((u8*)src)[(x>>1)^(i<<1)];
72 return RGBA5551_RGBA8888( *(u16*)&TMEM[256 + (palette << 4) + (color4B & 0x0F)] );
74 return RGBA5551_RGBA8888( *(u16*)&TMEM[256 + (palette << 4) + (color4B >> 4)] );
77 u32 GetIA31_RGBA8888( void *src, u16 x, u16 i, u8 palette )
79 u8 color4B = ((u8*)src)[(x>>1)^(i<<1)];
80 return IA31_RGBA8888( (x & 1) ? (color4B & 0x0F) : (color4B >> 4) );
83 u32 GetIA31_RGBA4444( void *src, u16 x, u16 i, u8 palette )
85 u8 color4B = ((u8*)src)[(x>>1)^(i<<1)];
86 return IA31_RGBA4444( (x & 1) ? (color4B & 0x0F) : (color4B >> 4) );
89 u32 GetIA31_IA88( void *src, u16 x, u16 i, u8 palette )
91 u8 color4B = ((u8*)src)[(x>>1)^(i<<1)];
92 return IA31_IA88( (x & 1) ? (color4B & 0x0F) : (color4B >> 4) );
95 u32 GetI4_RGBA8888( void *src, u16 x, u16 i, u8 palette )
97 u8 color4B = ((u8*)src)[(x>>1)^(i<<1)];
98 return I4_RGBA8888( (x & 1) ? (color4B & 0x0F) : (color4B >> 4) );
101 u32 GetI4_RGBA4444( void *src, u16 x, u16 i, u8 palette )
103 u8 color4B = ((u8*)src)[(x>>1)^(i<<1)];
104 return I4_RGBA4444( (x & 1) ? (color4B & 0x0F) : (color4B >> 4) );
107 u32 GetI4_I8( void *src, u16 x, u16 i, u8 palette )
109 u8 color4B = ((u8*)src)[(x>>1)^(i<<1)];
110 return I4_I8( (x & 1) ? (color4B & 0x0F) : (color4B >> 4) );
114 u32 GetI4_IA88( void *src, u16 x, u16 i, u8 palette )
116 u8 color4B = ((u8*)src)[(x>>1)^(i<<1)];
117 return I4_IA88( (x & 1) ? (color4B & 0x0F) : (color4B >> 4) );
120 u32 GetCI8IA_RGBA4444( void *src, u16 x, u16 i, u8 palette )
122 return IA88_RGBA4444( *(u16*)&TMEM[256 + ((u8*)src)[x^(i<<1)]] );
125 u32 GetCI8IA_RGBA8888( void *src, u16 x, u16 i, u8 palette )
127 return IA88_RGBA8888( *(u16*)&TMEM[256 + ((u8*)src)[x^(i<<1)]] );
130 u32 GetCI8RGBA_RGBA5551( void *src, u16 x, u16 i, u8 palette )
132 return RGBA5551_RGBA5551( *(u16*)&TMEM[256 + ((u8*)src)[x^(i<<1)]] );
135 u32 GetCI8RGBA_RGBA8888( void *src, u16 x, u16 i, u8 palette )
137 return RGBA5551_RGBA8888( *(u16*)&TMEM[256 + ((u8*)src)[x^(i<<1)]] );
140 u32 GetIA44_RGBA8888( void *src, u16 x, u16 i, u8 palette )
142 return IA44_RGBA8888(((u8*)src)[x^(i<<1)]);
145 u32 GetIA44_RGBA4444( void *src, u16 x, u16 i, u8 palette )
147 return IA44_RGBA4444(((u8*)src)[x^(i<<1)]);
150 u32 GetIA44_IA88( void *src, u16 x, u16 i, u8 palette )
152 return IA44_IA88(((u8*)src)[x^(i<<1)]);
155 u32 GetI8_RGBA8888( void *src, u16 x, u16 i, u8 palette )
157 return I8_RGBA8888(((u8*)src)[x^(i<<1)]);
160 u32 GetI8_I8( void *src, u16 x, u16 i, u8 palette )
162 return ((u8*)src)[x^(i<<1)];
165 u32 GetI8_IA88( void *src, u16 x, u16 i, u8 palette )
167 return I8_IA88(((u8*)src)[x^(i<<1)]);
170 u32 GetI8_RGBA4444( void *src, u16 x, u16 i, u8 palette )
172 return I8_RGBA4444(((u8*)src)[x^(i<<1)]);
175 u32 GetRGBA5551_RGBA8888( void *src, u16 x, u16 i, u8 palette )
177 return RGBA5551_RGBA8888( ((u16*)src)[x^i] );
180 u32 GetRGBA5551_RGBA5551( void *src, u16 x, u16 i, u8 palette )
182 return RGBA5551_RGBA5551( ((u16*)src)[x^i] );
185 u32 GetIA88_RGBA8888( void *src, u16 x, u16 i, u8 palette )
187 return IA88_RGBA8888(((u16*)src)[x^i]);
190 u32 GetIA88_RGBA4444( void *src, u16 x, u16 i, u8 palette )
192 return IA88_RGBA4444(((u16*)src)[x^i]);
195 u32 GetIA88_IA88( void *src, u16 x, u16 i, u8 palette )
197 return IA88_IA88(((u16*)src)[x^i]);
200 u32 GetRGBA8888_RGBA8888( void *src, u16 x, u16 i, u8 palette )
202 return ((u32*)src)[x^i];
205 u32 GetRGBA8888_RGBA4444( void *src, u16 x, u16 i, u8 palette )
207 return RGBA8888_RGBA4444(((u32*)src)[x^i]);
214 GetTexelFunc getTexel;
215 int lineShift, maxTexels;
219 TextureFormat textureFormatIA[4*6] =
222 { FORMAT_RGBA5551, GetCI4RGBA_RGBA5551, 4, 4096 }, // RGBA (SELECT)
223 { FORMAT_NONE, GetNone, 4, 8192 }, // YUV
224 { FORMAT_RGBA5551, GetCI4RGBA_RGBA5551, 4, 4096 }, // CI
225 { FORMAT_IA88, GetIA31_IA88, 4, 8192 }, // IA
226 { FORMAT_IA88, GetI4_IA88, 4, 8192 }, // I
227 { FORMAT_RGBA8888, GetCI4IA_RGBA8888, 4, 4096 }, // IA Palette
229 { FORMAT_RGBA5551, GetCI8RGBA_RGBA5551, 3, 2048 }, // RGBA (SELECT)
230 { FORMAT_NONE, GetNone, 3, 4096 }, // YUV
231 { FORMAT_RGBA5551, GetCI8RGBA_RGBA5551, 3, 2048 }, // CI
232 { FORMAT_IA88, GetIA44_IA88, 3, 4096 }, // IA
233 { FORMAT_IA88, GetI8_IA88, 3, 4096 }, // I
234 { FORMAT_RGBA8888, GetCI8IA_RGBA8888, 3, 2048 }, // IA Palette
236 { FORMAT_RGBA5551, GetRGBA5551_RGBA5551, 2, 2048 }, // RGBA
237 { FORMAT_NONE, GetNone, 2, 2048 }, // YUV
238 { FORMAT_NONE, GetNone, 2, 2048 }, // CI
239 { FORMAT_IA88, GetIA88_IA88, 2, 2048 }, // IA
240 { FORMAT_NONE, GetNone, 2, 2048 }, // I
241 { FORMAT_NONE, GetNone, 2, 2048 }, // IA Palette
243 { FORMAT_RGBA8888, GetRGBA8888_RGBA8888, 2, 1024 }, // RGBA
244 { FORMAT_NONE, GetNone, 2, 1024 }, // YUV
245 { FORMAT_NONE, GetNone, 2, 1024 }, // CI
246 { FORMAT_NONE, GetNone, 2, 1024 }, // IA
247 { FORMAT_NONE, GetNone, 2, 1024 }, // I
248 { FORMAT_NONE, GetNone, 2, 1024 }, // IA Palette
251 TextureFormat textureFormatRGBA[4*6] =
254 { FORMAT_RGBA5551, GetCI4RGBA_RGBA5551, 4, 4096 }, // RGBA (SELECT)
255 { FORMAT_NONE, GetNone, 4, 8192 }, // YUV
256 { FORMAT_RGBA5551, GetCI4RGBA_RGBA5551, 4, 4096 }, // CI
257 { FORMAT_RGBA4444, GetIA31_RGBA4444, 4, 8192 }, // IA
258 { FORMAT_RGBA4444, GetI4_RGBA4444, 4, 8192 }, // I
259 { FORMAT_RGBA8888, GetCI4IA_RGBA8888, 4, 4096 }, // IA Palette
261 { FORMAT_RGBA5551, GetCI8RGBA_RGBA5551, 3, 2048 }, // RGBA (SELECT)
262 { FORMAT_NONE, GetNone, 3, 4096 }, // YUV
263 { FORMAT_RGBA5551, GetCI8RGBA_RGBA5551, 3, 2048 }, // CI
264 { FORMAT_RGBA4444, GetIA44_RGBA4444, 3, 4096 }, // IA
265 { FORMAT_RGBA8888, GetI8_RGBA8888, 3, 4096 }, // I
266 { FORMAT_RGBA8888, GetCI8IA_RGBA8888, 3, 2048 }, // IA Palette
268 { FORMAT_RGBA5551, GetRGBA5551_RGBA5551, 2, 2048 }, // RGBA
269 { FORMAT_NONE, GetNone, 2, 2048 }, // YUV
270 { FORMAT_NONE, GetNone, 2, 2048 }, // CI
271 { FORMAT_RGBA8888, GetIA88_RGBA8888, 2, 2048 }, // IA
272 { FORMAT_NONE, GetNone, 2, 2048 }, // I
273 { FORMAT_NONE, GetNone, 2, 2048 }, // IA Palette
275 { FORMAT_RGBA8888, GetRGBA8888_RGBA8888, 2, 1024 }, // RGBA
276 { FORMAT_NONE, GetNone, 2, 1024 }, // YUV
277 { FORMAT_NONE, GetNone, 2, 1024 }, // CI
278 { FORMAT_NONE, GetNone, 2, 1024 }, // IA
279 { FORMAT_NONE, GetNone, 2, 1024 }, // I
280 { FORMAT_NONE, GetNone, 2, 1024 }, // IA Palette
284 TextureFormat *textureFormat = textureFormatIA;
286 void __texture_format_rgba(int size, int format, TextureFormat *texFormat)
288 if (size < G_IM_SIZ_16b)
290 if (gDP.otherMode.textureLUT == G_TT_NONE)
291 *texFormat = textureFormat[size*6 + G_IM_FMT_I];
292 else if (gDP.otherMode.textureLUT == G_TT_RGBA16)
293 *texFormat = textureFormat[size*6 + G_IM_FMT_CI];
295 *texFormat = textureFormat[size*6 + G_IM_FMT_IA];
299 *texFormat = textureFormat[size*6 + G_IM_FMT_RGBA];
303 void __texture_format_ci(int size, int format, TextureFormat *texFormat)
308 if (gDP.otherMode.textureLUT == G_TT_IA16)
309 *texFormat = textureFormat[G_IM_SIZ_4b*6 + G_IM_FMT_CI_IA];
311 *texFormat = textureFormat[G_IM_SIZ_4b*6 + G_IM_FMT_CI];
315 if (gDP.otherMode.textureLUT == G_TT_NONE)
316 *texFormat = textureFormat[G_IM_SIZ_8b*6 + G_IM_FMT_I];
317 else if (gDP.otherMode.textureLUT == G_TT_IA16)
318 *texFormat = textureFormat[G_IM_SIZ_8b*6 + G_IM_FMT_CI_IA];
320 *texFormat = textureFormat[G_IM_SIZ_8b*6 + G_IM_FMT_CI];
324 *texFormat = textureFormat[size*6 + format];
328 void __texture_format(int size, int format, TextureFormat *texFormat)
330 if (format == G_IM_FMT_RGBA)
332 __texture_format_rgba(size, format, texFormat);
334 else if (format == G_IM_FMT_YUV)
336 *texFormat = textureFormat[size*6 + G_IM_FMT_YUV];
338 else if (format == G_IM_FMT_CI)
340 __texture_format_ci(size, format, texFormat);
342 else if (format == G_IM_FMT_IA)
344 if (gDP.otherMode.textureLUT != G_TT_NONE)
345 __texture_format_ci(size, format, texFormat);
347 *texFormat = textureFormat[size*6 + G_IM_FMT_IA];
349 else if (format == G_IM_FMT_I)
351 if (gDP.otherMode.textureLUT == G_TT_NONE)
352 *texFormat = textureFormat[size*6 + G_IM_FMT_I];
354 __texture_format_ci(size, format, texFormat);
359 int isTexCacheInit = 0;
361 void TextureCache_Init()
363 u32 dummyTexture[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
366 cache.current[0] = NULL;
367 cache.current[1] = NULL;
371 cache.cachedBytes = 0;
377 if (config.texture.useIA) textureFormat = textureFormatIA;
378 else textureFormat = textureFormatRGBA;
380 glPixelStorei(GL_PACK_ALIGNMENT, 1);
381 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
382 glGenTextures( 32, cache.glNoiseNames );
386 for (u32 i = 0; i < 32; i++)
388 glBindTexture( GL_TEXTURE_2D, cache.glNoiseNames[i] );
389 for (u32 y = 0; y < 64; y++)
391 for (u32 x = 0; x < 64; x++)
393 u32 r = (rand()&0xFF);
394 noise[y*64*2+x*2] = r;
395 noise[y*64*2+x*2+1] = r;
398 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, 64, 64, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, noise);
401 cache.dummy = TextureCache_AddTop();
402 cache.dummy->address = 0;
403 cache.dummy->clampS = 1;
404 cache.dummy->clampT = 1;
405 cache.dummy->clampWidth = 4;
406 cache.dummy->clampHeight = 4;
407 cache.dummy->crc = 0;
408 cache.dummy->format = 0;
409 cache.dummy->size = 0;
410 cache.dummy->width = 4;
411 cache.dummy->height = 4;
412 cache.dummy->realWidth = 0;
413 cache.dummy->realHeight = 0;
414 cache.dummy->maskS = 0;
415 cache.dummy->maskT = 0;
416 cache.dummy->scaleS = 0.5f;
417 cache.dummy->scaleT = 0.5f;
418 cache.dummy->shiftScaleS = 1.0f;
419 cache.dummy->shiftScaleT = 1.0f;
420 cache.dummy->textureBytes = 64;
421 cache.dummy->tMem = 0;
423 glBindTexture( GL_TEXTURE_2D, cache.dummy->glName );
424 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, dummyTexture);
426 cache.cachedBytes = cache.dummy->textureBytes;
427 TextureCache_ActivateDummy(0);
428 TextureCache_ActivateDummy(1);
432 bool TextureCache_Verify()
435 CachedTexture *current;
442 current = current->lower;
444 if (i != cache.numCached) return false;
447 current = cache.bottom;
451 current = current->higher;
453 if (i != cache.numCached) return false;
458 void TextureCache_RemoveBottom()
460 CachedTexture *newBottom = cache.bottom->higher;
463 CachedTexture* tex= cache.hash.find(cache.bottom->crc);
464 if (tex == cache.bottom)
465 cache.hash.insert(cache.bottom->crc, NULL);
468 glDeleteTextures( 1, &cache.bottom->glName );
469 cache.cachedBytes -= cache.bottom->textureBytes;
471 if (cache.bottom == cache.top)
474 free( cache.bottom );
476 cache.bottom = newBottom;
479 cache.bottom->lower = NULL;
484 void TextureCache_Remove( CachedTexture *texture )
486 if ((texture == cache.bottom) && (texture == cache.top))
491 else if (texture == cache.bottom)
493 cache.bottom = texture->higher;
496 cache.bottom->lower = NULL;
498 else if (texture == cache.top)
500 cache.top = texture->lower;
503 cache.top->higher = NULL;
507 texture->higher->lower = texture->lower;
508 texture->lower->higher = texture->higher;
512 CachedTexture* tex= cache.hash.find(texture->crc);
514 cache.hash.insert(texture->crc, NULL);
517 glDeleteTextures( 1, &texture->glName );
518 cache.cachedBytes -= texture->textureBytes;
524 CachedTexture *TextureCache_AddTop()
526 while (cache.cachedBytes > TEXTURECACHE_MAX)
528 if (cache.bottom != cache.dummy)
529 TextureCache_RemoveBottom();
530 else if (cache.dummy->higher)
531 TextureCache_Remove( cache.dummy->higher );
534 CachedTexture *newtop = (CachedTexture*)malloc( sizeof( CachedTexture ) );
536 glGenTextures( 1, &newtop->glName );
538 newtop->lower = cache.top;
539 newtop->higher = NULL;
542 cache.top->higher = newtop;
545 cache.bottom = newtop;
554 void TextureCache_MoveToTop( CachedTexture *newtop )
556 if (newtop == cache.top) return;
558 if (newtop == cache.bottom)
560 cache.bottom = newtop->higher;
561 cache.bottom->lower = NULL;
565 newtop->higher->lower = newtop->lower;
566 newtop->lower->higher = newtop->higher;
569 newtop->higher = NULL;
570 newtop->lower = cache.top;
571 cache.top->higher = newtop;
575 void TextureCache_Destroy()
578 TextureCache_RemoveBottom();
580 glDeleteTextures( 32, cache.glNoiseNames );
581 glDeleteTextures( 1, &cache.dummy->glName );
584 cache.hash.destroy();
593 void TextureCache_LoadBackground( CachedTexture *texInfo )
595 u32 *dest, *scaledDest;
599 u16 clampSClamp, clampTClamp;
602 TextureFormat texFormat;
603 GetTexelFunc getTexel;
604 GLint glWidth=0, glHeight=0;
608 __texture_format(texInfo->size, texInfo->format, &texFormat);
610 #ifdef PRINT_TEXTUREFORMAT
611 printf("BG LUT=%i, TEXTURE SIZE=%i, FORMAT=%i -> GL FORMAT=%i\n", gDP.otherMode.textureLUT, texInfo->size, texInfo->format, texFormat.format); fflush(stdout);
614 if (texFormat.format == FORMAT_NONE)
616 LOG(LOG_WARNING, "No Texture Conversion function available, size=%i format=%i\n", texInfo->size, texInfo->format);
619 switch(texFormat.format)
622 glFormat = GL_LUMINANCE;
623 glType = GL_UNSIGNED_BYTE;
627 glFormat = GL_LUMINANCE_ALPHA;
628 glType = GL_UNSIGNED_BYTE;
631 case FORMAT_RGBA4444:
633 glType = GL_UNSIGNED_SHORT_4_4_4_4;
636 case FORMAT_RGBA5551:
638 glType = GL_UNSIGNED_SHORT_5_5_5_1;
641 case FORMAT_RGBA8888:
643 glType = GL_UNSIGNED_BYTE;
648 glWidth = texInfo->realWidth;
649 glHeight = texInfo->realHeight;
650 texInfo->textureBytes = (glWidth * glHeight) * bytePerPixel;
651 getTexel = texFormat.getTexel;
653 bpl = gSP.bgImage.width << gSP.bgImage.size >> 1;
654 numBytes = bpl * gSP.bgImage.height;
655 swapped = (u8*) malloc(numBytes);
656 dest = (u32*) malloc(texInfo->textureBytes);
658 if (!dest || !swapped)
660 LOG(LOG_ERROR, "Malloc failed!\n");
664 UnswapCopy(&RDRAM[gSP.bgImage.address], swapped, numBytes);
666 clampSClamp = texInfo->width - 1;
667 clampTClamp = texInfo->height - 1;
670 for (y = 0; y < texInfo->realHeight; y++)
672 ty = min(y, clampTClamp);
673 src = &swapped[bpl * ty];
674 for (x = 0; x < texInfo->realWidth; x++)
676 tx = min(x, clampSClamp);
677 if (bytePerPixel == 4)
678 ((u32*)dest)[j++] = getTexel(src, tx, 0, texInfo->palette);
679 else if (bytePerPixel == 2)
680 ((u16*)dest)[j++] = getTexel(src, tx, 0, texInfo->palette);
681 else if (bytePerPixel == 1)
682 ((u8*)dest)[j++] = getTexel(src, tx, 0, texInfo->palette);
686 if (!config.texture.sai2x || (texFormat.format == FORMAT_I8 || texFormat.format == FORMAT_IA88))
688 glTexImage2D( GL_TEXTURE_2D, 0, glFormat, glWidth, glHeight, 0, glFormat, glType, dest);
692 LOG(LOG_VERBOSE, "Using 2xSAI Filter on Texture\n");
693 texInfo->textureBytes <<= 2;
695 scaledDest = (u32*) malloc( texInfo->textureBytes );
697 if (glType == GL_UNSIGNED_BYTE)
698 _2xSaI8888( (u32*)dest, (u32*)scaledDest, texInfo->realWidth, texInfo->realHeight, texInfo->clampS, texInfo->clampT );
699 if (glType == GL_UNSIGNED_SHORT_4_4_4_4)
700 _2xSaI4444( (u16*)dest, (u16*)scaledDest, texInfo->realWidth, texInfo->realHeight, texInfo->clampS, texInfo->clampT );
702 _2xSaI5551( (u16*)dest, (u16*)scaledDest, texInfo->realWidth, texInfo->realHeight, texInfo->clampS, texInfo->clampT );
704 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, texInfo->realWidth << 1, texInfo->realHeight << 1, 0, GL_RGBA, glType, scaledDest );
713 if (config.texture.enableMipmap)
714 glGenerateMipmap(GL_TEXTURE_2D);
717 void TextureCache_Load( CachedTexture *texInfo )
719 u32 *dest, *scaledDest;
722 u16 x, y, i, j, tx, ty, line;
723 u16 mirrorSBit, maskSMask, clampSClamp;
724 u16 mirrorTBit, maskTMask, clampTClamp;
727 TextureFormat texFormat;
728 GetTexelFunc getTexel;
729 GLint glWidth=0, glHeight=0;
733 __texture_format(texInfo->size, texInfo->format, &texFormat);
735 #ifdef PRINT_TEXTUREFORMAT
736 printf("TEX LUT=%i, TEXTURE SIZE=%i, FORMAT=%i -> GL FORMAT=%i\n", gDP.otherMode.textureLUT, texInfo->size, texInfo->format, texFormat.format); fflush(stdout);
739 if (texFormat.format == FORMAT_NONE)
741 LOG(LOG_WARNING, "No Texture Conversion function available, size=%i format=%i\n", texInfo->size, texInfo->format);
744 switch(texFormat.format)
747 glFormat = GL_LUMINANCE;
748 glType = GL_UNSIGNED_BYTE;
752 glFormat = GL_LUMINANCE_ALPHA;
753 glType = GL_UNSIGNED_BYTE;
756 case FORMAT_RGBA4444:
758 glType = GL_UNSIGNED_SHORT_4_4_4_4;
761 case FORMAT_RGBA5551:
763 glType = GL_UNSIGNED_SHORT_5_5_5_1;
766 case FORMAT_RGBA8888:
768 glType = GL_UNSIGNED_BYTE;
773 glWidth = texInfo->realWidth;
774 glHeight = texInfo->realHeight;
775 texInfo->textureBytes = (glWidth * glHeight) * bytePerPixel;
776 getTexel = texFormat.getTexel;
778 dest = (u32*)malloc(texInfo->textureBytes);
782 LOG(LOG_ERROR, "Malloc failed!\n");
787 line = texInfo->line;
789 if (texInfo->size == G_IM_SIZ_32b)
794 clampSClamp = texInfo->clampS ? texInfo->clampWidth - 1 : (texInfo->mirrorS ? (texInfo->width << 1) - 1 : texInfo->width - 1);
795 maskSMask = (1 << texInfo->maskS) - 1;
796 mirrorSBit = texInfo->mirrorS ? (1 << texInfo->maskS) : 0;
800 clampSClamp = min( texInfo->clampWidth, texInfo->width ) - 1;
807 clampTClamp = texInfo->clampT ? texInfo->clampHeight - 1 : (texInfo->mirrorT ? (texInfo->height << 1) - 1: texInfo->height - 1);
808 maskTMask = (1 << texInfo->maskT) - 1;
809 mirrorTBit = texInfo->mirrorT ? (1 << texInfo->maskT) : 0;
813 clampTClamp = min( texInfo->clampHeight, texInfo->height ) - 1;
818 // Hack for Zelda warp texture
819 if (((texInfo->tMem << 3) + (texInfo->width * texInfo->height << texInfo->size >> 1)) > 4096)
824 // limit clamp values to min-0 (Perfect Dark has height=0 textures, making negative clamps)
825 if (clampTClamp & 0x8000) clampTClamp = 0;
826 if (clampSClamp & 0x8000) clampSClamp = 0;
829 for (y = 0; y < texInfo->realHeight; y++)
831 ty = min(y, clampTClamp) & maskTMask;
832 if (y & mirrorTBit) ty ^= maskTMask;
833 src = &TMEM[(texInfo->tMem + line * ty) & 511];
835 for (x = 0; x < texInfo->realWidth; x++)
837 tx = min(x, clampSClamp) & maskSMask;
839 if (x & mirrorSBit) tx ^= maskSMask;
841 if (bytePerPixel == 4)
843 ((u32*)dest)[j] = getTexel(src, tx, i, texInfo->palette);
845 else if (bytePerPixel == 2)
847 ((u16*)dest)[j] = getTexel(src, tx, i, texInfo->palette);
849 else if (bytePerPixel == 1)
851 ((u8*)dest)[j] = getTexel(src, tx, i, texInfo->palette);
857 if (!config.texture.sai2x || (texFormat.format == FORMAT_I8) || (texFormat.format == FORMAT_IA88))
859 #ifdef PRINT_TEXTUREFORMAT
860 printf("j=%u DEST=0x%x SIZE=%i F=0x%x, W=%i, H=%i, T=0x%x\n", j, dest, texInfo->textureBytes,glFormat, glWidth, glHeight, glType); fflush(stdout);
862 glTexImage2D( GL_TEXTURE_2D, 0, glFormat, glWidth, glHeight, 0, glFormat, glType, dest);
866 LOG(LOG_VERBOSE, "Using 2xSAI Filter on Texture\n");
868 texInfo->textureBytes <<= 2;
870 scaledDest = (u32*)malloc( texInfo->textureBytes );
872 if (glType == GL_UNSIGNED_BYTE)
873 _2xSaI8888( (u32*)dest, (u32*)scaledDest, texInfo->realWidth, texInfo->realHeight, 1, 1 );
874 else if (glType == GL_UNSIGNED_SHORT_4_4_4_4)
875 _2xSaI4444( (u16*)dest, (u16*)scaledDest, texInfo->realWidth, texInfo->realHeight, 1, 1 );
877 _2xSaI5551( (u16*)dest, (u16*)scaledDest, texInfo->realWidth, texInfo->realHeight, 1, 1 );
879 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, texInfo->realWidth << 1, texInfo->realHeight << 1, 0, GL_RGBA, glType, scaledDest );
886 if (config.texture.enableMipmap)
887 glGenerateMipmap(GL_TEXTURE_2D);
891 #define max(a,b) ((a) > (b) ? (a) : (b))
893 u32 TextureCache_CalculateCRC( u32 t, u32 width, u32 height )
896 u32 y, /*i,*/ bpl, lineBytes, line;
899 bpl = width << gSP.textureTile[t]->size >> 1;
900 lineBytes = gSP.textureTile[t]->line << 3;
902 line = gSP.textureTile[t]->line;
903 if (gSP.textureTile[t]->size == G_IM_SIZ_32b)
909 unsigned n = (config.texture.fastCRC) ? max(1, height / 8) : 1;
914 for (y = 0; y < height; y += n)
916 src = (void*) &TMEM[(gSP.textureTile[t]->tmem + (y * line)) & 511];
917 crc = CRC_Calculate( crc, src, bpl );
920 if (gSP.textureTile[t]->format == G_IM_FMT_CI)
922 if (gSP.textureTile[t]->size == G_IM_SIZ_4b)
923 crc = CRC_Calculate( crc, &gDP.paletteCRC16[gSP.textureTile[t]->palette], 4 );
924 else if (gSP.textureTile[t]->size == G_IM_SIZ_8b)
925 crc = CRC_Calculate( crc, &gDP.paletteCRC256, 4 );
930 void TextureCache_ActivateTexture( u32 t, CachedTexture *texture )
934 cache.hash.insert(texture->crc, texture);
937 glActiveTexture( GL_TEXTURE0 + t );
938 glBindTexture( GL_TEXTURE_2D, texture->glName );
940 // Set filter mode. Almost always bilinear, but check anyways
941 if ((gDP.otherMode.textureFilter == G_TF_BILERP) || (gDP.otherMode.textureFilter == G_TF_AVERAGE) || (config.texture.forceBilinear))
943 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
944 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
948 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
949 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
952 // Set clamping modes
953 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (texture->clampS) ? GL_CLAMP_TO_EDGE : GL_REPEAT );
954 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (texture->clampT) ? GL_CLAMP_TO_EDGE : GL_REPEAT );
956 if (config.texture.maxAnisotropy > 0)
958 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, config.texture.maxAnisotropy);
961 texture->lastDList = RSP.DList;
962 TextureCache_MoveToTop( texture );
963 cache.current[t] = texture;
966 void TextureCache_ActivateDummy( u32 t)
968 glActiveTexture(GL_TEXTURE0 + t);
969 glBindTexture(GL_TEXTURE_2D, cache.dummy->glName );
970 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
971 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
974 int _background_compare(CachedTexture *current, u32 crc)
976 if ((current != NULL) &&
977 (current->crc == crc) &&
978 (current->width == gSP.bgImage.width) &&
979 (current->height == gSP.bgImage.height) &&
980 (current->format == gSP.bgImage.format) &&
981 (current->size == gSP.bgImage.size))
987 void TextureCache_UpdateBackground()
989 u32 numBytes = gSP.bgImage.width * gSP.bgImage.height << gSP.bgImage.size >> 1;
992 crc = CRC_Calculate( 0xFFFFFFFF, &RDRAM[gSP.bgImage.address], numBytes );
994 if (gSP.bgImage.format == G_IM_FMT_CI)
996 if (gSP.bgImage.size == G_IM_SIZ_4b)
997 crc = CRC_Calculate( crc, &gDP.paletteCRC16[gSP.bgImage.palette], 4 );
998 else if (gSP.bgImage.size == G_IM_SIZ_8b)
999 crc = CRC_Calculate( crc, &gDP.paletteCRC256, 4 );
1002 //before we traverse cache, check to see if texture is already bound:
1003 if (_background_compare(cache.current[0], crc))
1008 #ifdef __HASHMAP_OPT
1009 CachedTexture *tex = cache.hash.find(crc);
1012 if (_background_compare(tex, crc))
1014 TextureCache_ActivateTexture(0, tex);
1021 CachedTexture *current = cache.top;
1024 if (_background_compare(current, crc))
1026 TextureCache_ActivateTexture( 0, current );
1030 current = current->lower;
1034 glActiveTexture(GL_TEXTURE0);
1035 cache.current[0] = TextureCache_AddTop();
1037 glBindTexture( GL_TEXTURE_2D, cache.current[0]->glName );
1038 cache.current[0]->address = gSP.bgImage.address;
1039 cache.current[0]->crc = crc;
1040 cache.current[0]->format = gSP.bgImage.format;
1041 cache.current[0]->size = gSP.bgImage.size;
1042 cache.current[0]->width = gSP.bgImage.width;
1043 cache.current[0]->height = gSP.bgImage.height;
1044 cache.current[0]->clampWidth = gSP.bgImage.width;
1045 cache.current[0]->clampHeight = gSP.bgImage.height;
1046 cache.current[0]->palette = gSP.bgImage.palette;
1047 cache.current[0]->maskS = 0;
1048 cache.current[0]->maskT = 0;
1049 cache.current[0]->mirrorS = 0;
1050 cache.current[0]->mirrorT = 0;
1051 cache.current[0]->clampS = 1;
1052 cache.current[0]->clampT = 1;
1053 cache.current[0]->line = 0;
1054 cache.current[0]->tMem = 0;
1055 cache.current[0]->lastDList = RSP.DList;
1057 cache.current[0]->realWidth = (config.texture.pow2) ? pow2(gSP.bgImage.width ) : gSP.bgImage.width;
1058 cache.current[0]->realHeight = (config.texture.pow2) ? pow2(gSP.bgImage.height) : gSP.bgImage.height;
1060 cache.current[0]->scaleS = 1.0f / (f32)(cache.current[0]->realWidth);
1061 cache.current[0]->scaleT = 1.0f / (f32)(cache.current[0]->realHeight);
1062 cache.current[0]->shiftScaleS = 1.0f;
1063 cache.current[0]->shiftScaleT = 1.0f;
1065 TextureCache_LoadBackground( cache.current[0] );
1066 TextureCache_ActivateTexture( 0, cache.current[0] );
1068 cache.cachedBytes += cache.current[0]->textureBytes;
1071 int _texture_compare(u32 t, CachedTexture *current, u32 crc, u32 width, u32 height, u32 clampWidth, u32 clampHeight)
1073 if ((current != NULL) &&
1074 (current->crc == crc) &&
1075 (current->width == width) &&
1076 (current->height == height) &&
1077 (current->clampWidth == clampWidth) &&
1078 (current->clampHeight == clampHeight) &&
1079 (current->maskS == gSP.textureTile[t]->masks) &&
1080 (current->maskT == gSP.textureTile[t]->maskt) &&
1081 (current->mirrorS == gSP.textureTile[t]->mirrors) &&
1082 (current->mirrorT == gSP.textureTile[t]->mirrort) &&
1083 (current->clampS == gSP.textureTile[t]->clamps) &&
1084 (current->clampT == gSP.textureTile[t]->clampt) &&
1085 (current->format == gSP.textureTile[t]->format) &&
1086 (current->size == gSP.textureTile[t]->size))
1093 void TextureCache_Update( u32 t )
1095 CachedTexture *current;
1098 u32 tileWidth, maskWidth, loadWidth, lineWidth, clampWidth, height;
1099 u32 tileHeight, maskHeight, loadHeight, lineHeight, clampHeight, width;
1101 if (gDP.textureMode == TEXTUREMODE_BGIMAGE)
1103 TextureCache_UpdateBackground();
1107 TextureFormat texFormat;
1108 __texture_format(gSP.textureTile[t]->size, gSP.textureTile[t]->format, &texFormat);
1110 maxTexels = texFormat.maxTexels;
1112 // Here comes a bunch of code that just calculates the texture size...I wish there was an easier way...
1113 tileWidth = gSP.textureTile[t]->lrs - gSP.textureTile[t]->uls + 1;
1114 tileHeight = gSP.textureTile[t]->lrt - gSP.textureTile[t]->ult + 1;
1116 maskWidth = 1 << gSP.textureTile[t]->masks;
1117 maskHeight = 1 << gSP.textureTile[t]->maskt;
1119 loadWidth = gDP.loadTile->lrs - gDP.loadTile->uls + 1;
1120 loadHeight = gDP.loadTile->lrt - gDP.loadTile->ult + 1;
1122 lineWidth = gSP.textureTile[t]->line << texFormat.lineShift;
1124 if (lineWidth) // Don't allow division by zero
1125 lineHeight = min( maxTexels / lineWidth, tileHeight );
1129 if (gDP.textureMode == TEXTUREMODE_TEXRECT)
1131 u32 texRectWidth = gDP.texRect.width - gSP.textureTile[t]->uls;
1132 u32 texRectHeight = gDP.texRect.height - gSP.textureTile[t]->ult;
1134 if (gSP.textureTile[t]->masks && ((maskWidth * maskHeight) <= maxTexels))
1136 else if ((tileWidth * tileHeight) <= maxTexels)
1138 else if ((tileWidth * texRectHeight) <= maxTexels)
1140 else if ((texRectWidth * tileHeight) <= maxTexels)
1141 width = gDP.texRect.width;
1142 else if ((texRectWidth * texRectHeight) <= maxTexels)
1143 width = gDP.texRect.width;
1144 else if (gDP.loadType == LOADTYPE_TILE)
1149 if (gSP.textureTile[t]->maskt && ((maskWidth * maskHeight) <= maxTexels))
1150 height = maskHeight;
1151 else if ((tileWidth * tileHeight) <= maxTexels)
1152 height = tileHeight;
1153 else if ((tileWidth * texRectHeight) <= maxTexels)
1154 height = gDP.texRect.height;
1155 else if ((texRectWidth * tileHeight) <= maxTexels)
1156 height = tileHeight;
1157 else if ((texRectWidth * texRectHeight) <= maxTexels)
1158 height = gDP.texRect.height;
1159 else if (gDP.loadType == LOADTYPE_TILE)
1160 height = loadHeight;
1162 height = lineHeight;
1166 if (gSP.textureTile[t]->masks && ((maskWidth * maskHeight) <= maxTexels))
1168 else if ((tileWidth * tileHeight) <= maxTexels)
1170 else if (gDP.loadType == LOADTYPE_TILE)
1175 if (gSP.textureTile[t]->maskt && ((maskWidth * maskHeight) <= maxTexels))
1176 height = maskHeight;
1177 else if ((tileWidth * tileHeight) <= maxTexels)
1178 height = tileHeight;
1179 else if (gDP.loadType == LOADTYPE_TILE)
1180 height = loadHeight;
1182 height = lineHeight;
1185 clampWidth = gSP.textureTile[t]->clamps ? tileWidth : width;
1186 clampHeight = gSP.textureTile[t]->clampt ? tileHeight : height;
1188 if (clampWidth > 256)
1189 gSP.textureTile[t]->clamps = 0;
1190 if (clampHeight > 256)
1191 gSP.textureTile[t]->clampt = 0;
1193 // Make sure masking is valid
1194 if (maskWidth > width)
1196 gSP.textureTile[t]->masks = powof( width );
1197 maskWidth = 1 << gSP.textureTile[t]->masks;
1200 if (maskHeight > height)
1202 gSP.textureTile[t]->maskt = powof( height );
1203 maskHeight = 1 << gSP.textureTile[t]->maskt;
1206 crc = TextureCache_CalculateCRC( t, width, height );
1208 //before we traverse cache, check to see if texture is already bound:
1209 if (_texture_compare(t, cache.current[t], crc, width, height, clampWidth, clampHeight))
1215 #ifdef __HASHMAP_OPT
1216 CachedTexture *tex = cache.hash.find(crc);
1219 if (_texture_compare(t, tex, crc, width, height, clampWidth, clampHeight))
1221 TextureCache_ActivateTexture( t, tex);
1228 current = cache.top;
1231 if (_texture_compare(t, current, crc, width, height, clampWidth, clampHeight))
1233 TextureCache_ActivateTexture( t, current );
1238 current = current->lower;
1243 glActiveTexture( GL_TEXTURE0 + t);
1245 cache.current[t] = TextureCache_AddTop();
1247 if (cache.current[t] == NULL)
1249 LOG(LOG_ERROR, "Texture Cache Failure\n");
1252 glBindTexture( GL_TEXTURE_2D, cache.current[t]->glName );
1254 cache.current[t]->address = gDP.textureImage.address;
1255 cache.current[t]->crc = crc;
1257 cache.current[t]->format = gSP.textureTile[t]->format;
1258 cache.current[t]->size = gSP.textureTile[t]->size;
1260 cache.current[t]->width = width;
1261 cache.current[t]->height = height;
1262 cache.current[t]->clampWidth = clampWidth;
1263 cache.current[t]->clampHeight = clampHeight;
1264 cache.current[t]->palette = gSP.textureTile[t]->palette;
1265 cache.current[t]->maskS = gSP.textureTile[t]->masks;
1266 cache.current[t]->maskT = gSP.textureTile[t]->maskt;
1267 cache.current[t]->mirrorS = gSP.textureTile[t]->mirrors;
1268 cache.current[t]->mirrorT = gSP.textureTile[t]->mirrort;
1269 cache.current[t]->clampS = gSP.textureTile[t]->clamps;
1270 cache.current[t]->clampT = gSP.textureTile[t]->clampt;
1271 cache.current[t]->line = gSP.textureTile[t]->line;
1272 cache.current[t]->tMem = gSP.textureTile[t]->tmem;
1273 cache.current[t]->lastDList = RSP.DList;
1276 if (cache.current[t]->clampS)
1277 cache.current[t]->realWidth = (config.texture.pow2) ? pow2(clampWidth) : clampWidth;
1278 else if (cache.current[t]->mirrorS)
1279 cache.current[t]->realWidth = maskWidth << 1;
1281 cache.current[t]->realWidth = (config.texture.pow2) ? pow2(width) : width;
1283 if (cache.current[t]->clampT)
1284 cache.current[t]->realHeight = (config.texture.pow2) ? pow2(clampHeight) : clampHeight;
1285 else if (cache.current[t]->mirrorT)
1286 cache.current[t]->realHeight = maskHeight << 1;
1288 cache.current[t]->realHeight = (config.texture.pow2) ? pow2(height) : height;
1291 cache.current[t]->scaleS = 1.0f / (f32)(cache.current[t]->realWidth);
1292 cache.current[t]->scaleT = 1.0f / (f32)(cache.current[t]->realHeight);
1294 // Hack for Zelda Sun
1295 if ((config.hackZelda) && (gDP.combine.mux == 0x00262a60150c937fLL))
1297 if ((cache.current[t]->format = G_IM_FMT_I) && (cache.current[t]->size == G_IM_SIZ_8b) &&
1298 (cache.current[t]->width == 64))
1300 cache.current[t]->scaleS *= 0.5f;
1301 cache.current[t]->scaleT *= 0.5f;
1305 cache.current[t]->shiftScaleS = 1.0f;
1306 cache.current[t]->shiftScaleT = 1.0f;
1308 cache.current[t]->offsetS = config.texture.sai2x ? 0.25f : 0.5f;
1309 cache.current[t]->offsetT = config.texture.sai2x ? 0.25f : 0.5f;
1311 if (gSP.textureTile[t]->shifts > 10)
1312 cache.current[t]->shiftScaleS = (f32)(1 << (16 - gSP.textureTile[t]->shifts));
1313 else if (gSP.textureTile[t]->shifts > 0)
1314 cache.current[t]->shiftScaleS /= (f32)(1 << gSP.textureTile[t]->shifts);
1316 if (gSP.textureTile[t]->shiftt > 10)
1317 cache.current[t]->shiftScaleT = (f32)(1 << (16 - gSP.textureTile[t]->shiftt));
1318 else if (gSP.textureTile[t]->shiftt > 0)
1319 cache.current[t]->shiftScaleT /= (f32)(1 << gSP.textureTile[t]->shiftt);
1321 TextureCache_Load( cache.current[t] );
1322 TextureCache_ActivateTexture( t, cache.current[t] );
1324 cache.cachedBytes += cache.current[t]->textureBytes;
1327 void TextureCache_ActivateNoise(u32 t)
1329 glActiveTexture(GL_TEXTURE0 + t);
1330 glBindTexture(GL_TEXTURE_2D, cache.glNoiseNames[RSP.DList & 0x1F]);
1331 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
1332 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );