Glide Plugin GLES2 port from mupen64plus-ae, but with special FrameSkip code
[mupen64plus-pandora.git] / source / gles2glide64 / src / Glide64 / TexCache.cpp
1 /*
2 * Glide64 - Glide video plugin for Nintendo 64 emulators.
3 * Copyright (c) 2002  Dave2001
4 * Copyright (c) 2003-2009  Sergey 'Gonetz' Lipski
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 //****************************************************************
22 //
23 // Glide64 - Glide Plugin for Nintendo 64 emulators
24 // Project started on December 29th, 2001
25 //
26 // Authors:
27 // Dave2001, original author, founded the project in 2001, left it in 2002
28 // Gugaman, joined the project in 2002, left it in 2002
29 // Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 2002
30 // Hiroshi 'KoolSmoky' Morii, joined the project in 2007
31 //
32 //****************************************************************
33 //
34 // To modify Glide64:
35 // * Write your name and (optional)email, commented by your work, so I know who did it, and so that you can find which parts you modified when it comes time to send it to me.
36 // * Do NOT send me the whole project or file that you modified.  Take out your modified code sections, and tell me where to put them.  If people sent the whole thing, I would have many different versions, but no idea how to combine them all.
37 //
38 //****************************************************************
39
40 #include <SDL.h>
41 #include "Gfx_1.3.h"
42 #include "TexCache.h"
43 #include "Combine.h"
44 #include "Util.h"
45
46 void LoadTex (int id, int tmu);
47
48 wxUint8 tex1[1024*1024*4];              // temporary texture
49 wxUint8 tex2[1024*1024*4];
50 wxUint8 *texture;
51 wxUint8 *texture_buffer = tex1;
52
53 #include "TexLoad.h"    // texture loading functions, ONLY INCLUDE IN THIS FILE!!!
54 #include "MiClWr32b.h"
55 #include "MiClWr16b.h"  // Mirror/Clamp/Wrap functions, ONLY INCLUDE IN THIS FILE!!!
56 #include "MiClWr8b.h"   // Mirror/Clamp/Wrap functions, ONLY INCLUDE IN THIS FILE!!!
57 #include "TexConv.h"    // texture conversions, ONLY INCLUDE IN THIS FILE!!!
58 #include "TexMod.h"
59 #include "TexModCI.h"
60 #include "CRC.h"
61 #ifdef TEXTURE_FILTER // Hiroshi Morii <koolsmoky@users.sourceforge.net>
62 extern int ghq_dmptex_toggle_key;
63 #endif
64
65 typedef struct TEXINFO_t {
66   int real_image_width, real_image_height;      // FOR ALIGNMENT PURPOSES ONLY!!!
67   int tile_width, tile_height;
68   int mask_width, mask_height;
69   int width, height;
70   int wid_64, line;
71   wxUint32 crc;
72   wxUint32 flags;
73   int splits, splitheight;
74 #ifdef TEXTURE_FILTER
75   uint64 ricecrc;
76 #endif
77 } TEXINFO;
78
79 TEXINFO texinfo[2];
80 int tex_found[2][MAX_TMU];
81
82 #ifdef TEXTURE_FILTER
83 typedef struct HIRESTEX_t {
84   int width, height;
85   wxUint16 format;
86   wxUint8 *data;
87 } HIRESTEX;
88 #endif
89
90 //****************************************************************
91 // List functions
92
93 typedef struct NODE_t {
94   wxUint32      crc;
95   wxUIntPtr     data;
96   int           tmu;
97   int           number;
98   NODE_t        *pNext;
99 } NODE;
100
101 NODE *cachelut[65536];
102
103 void AddToList (NODE **list, wxUint32 crc, wxUIntPtr data, int tmu, int number)
104 {
105   NODE *node = new NODE;
106   node->crc = crc;
107   node->data = data;
108   node->tmu = tmu;
109   node->number = number;
110   node->pNext = *list;
111   *list = node;
112   rdp.n_cached[tmu] ++;
113   if (voodoo.tex_UMA)
114     rdp.n_cached[tmu^1] = rdp.n_cached[tmu];
115 }
116
117 void DeleteList (NODE **list)
118 {
119   while (*list)
120   {
121     NODE *next = (*list)->pNext;
122     delete (*list);
123     *list = next;
124   }
125 }
126
127 void TexCacheInit ()
128 {
129   for (int i=0; i<65536; i++)
130   {
131     cachelut[i] = NULL;
132   }
133 }
134
135 //****************************************************************
136 // ClearCache - clear the texture cache for BOTH tmus
137
138 void ClearCache ()
139 {
140   voodoo.tmem_ptr[0] = offset_textures;
141   rdp.n_cached[0] = 0;
142   voodoo.tmem_ptr[1] = voodoo.tex_UMA ? offset_textures : offset_texbuf1;
143   rdp.n_cached[1] = 0;
144
145   for (int i=0; i<65536; i++)
146   {
147     DeleteList (&cachelut[i]);
148   }
149 }
150
151 //****************************************************************
152 uint32_t textureCRC(uint8_t *addr, int width, int height, int line)
153 {
154   uint32_t crc = 0;
155   uint32_t *pixelpos;
156   unsigned int i;
157   uint64_t twopixel_crc;
158
159   pixelpos = (uint32_t*)addr;
160   for (; height; height--) {
161     for (i = width; i; --i) {
162       twopixel_crc = i * (uint64_t)(pixelpos[1] + pixelpos[0] + crc);
163       crc = (uint32_t) ((twopixel_crc >> 32) + twopixel_crc);
164       pixelpos += 2;
165     }
166     crc = ((unsigned int)height * (uint64_t)crc >> 32) + height * crc;
167     pixelpos = (uint32_t *)((char *)pixelpos + line);
168   }
169
170   return crc;
171 }
172 // GetTexInfo - gets information for either t0 or t1, checks if in cache & fills tex_found
173
174 void GetTexInfo (int id, int tile)
175 {
176   FRDP (" | |-+ GetTexInfo (id: %d, tile: %d)\n", id, tile);
177
178   // this is the NEW cache searching, searches only textures with similar crc's
179   int t;
180   for (t=0; t<MAX_TMU; t++)
181     tex_found[id][t] = -1;
182
183   TBUFF_COLOR_IMAGE * pFBTex = 0;
184   if (rdp.aTBuffTex[0] && rdp.aTBuffTex[0]->tile == id)
185     pFBTex = rdp.aTBuffTex[0];
186   else if (rdp.aTBuffTex[1] && rdp.aTBuffTex[1]->tile == id)
187     pFBTex = rdp.aTBuffTex[1];
188   if (pFBTex && pFBTex->cache)
189     return;
190
191   TEXINFO *info = &texinfo[id];
192
193   int tile_width, tile_height;
194   int mask_width, mask_height;
195   int width, height;
196   int wid_64, line, bpl;
197
198   // Get width and height
199   tile_width = rdp.tiles[tile].lr_s - rdp.tiles[tile].ul_s + 1;
200   tile_height = rdp.tiles[tile].lr_t - rdp.tiles[tile].ul_t + 1;
201
202   mask_width = (rdp.tiles[tile].mask_s==0)?(tile_width):(1 << rdp.tiles[tile].mask_s);
203   mask_height = (rdp.tiles[tile].mask_t==0)?(tile_height):(1 << rdp.tiles[tile].mask_t);
204
205   if (settings.alt_tex_size)
206   {
207     // ** ALTERNATE TEXTURE SIZE METHOD **
208     // Helps speed in some games that loaded weird-sized textures, but could break other
209     //  textures.
210
211     // Get the width/height to load
212     if ((rdp.tiles[tile].clamp_s && tile_width <= 256) || (mask_width > 256))
213     {
214       // loading width
215       width = min(mask_width, tile_width);
216       // actual width
217       rdp.tiles[tile].width = tile_width;
218     }
219     else
220     {
221       // wrap all the way
222       width = min(mask_width, tile_width);      // changed from mask_width only
223       rdp.tiles[tile].width = width;
224     }
225
226     if ((rdp.tiles[tile].clamp_t && tile_height <= 256) || (mask_height > 256))
227     {
228       // loading height
229       height = min(mask_height, tile_height);
230       // actual height
231       rdp.tiles[tile].height = tile_height;
232     }
233     else
234     {
235       // wrap all the way
236       height = min(mask_height, tile_height);
237       rdp.tiles[tile].height = height;
238     }
239   }
240   else
241   {
242     // ** NORMAL TEXTURE SIZE METHOD **
243     // This is the 'correct' method for determining texture size, but may cause certain
244     //  textures to load too large & make the whole game go slow.
245
246     if (mask_width > 256 && mask_height > 256)
247     {
248       mask_width = tile_width;
249       mask_height = tile_height;
250     }
251
252     // Get the width/height to load
253     if ((rdp.tiles[tile].clamp_s && tile_width <= 256) )//|| (mask_width > 256))
254     {
255       // loading width
256       width = min(mask_width, tile_width);
257       // actual width
258       rdp.tiles[tile].width = tile_width;
259     }
260     else
261     {
262       // wrap all the way
263       width = mask_width;
264       rdp.tiles[tile].width = mask_width;
265     }
266
267     if ((rdp.tiles[tile].clamp_t && tile_height <= 256) || (mask_height > 256))
268     {
269       // loading height
270       height = min(mask_height, tile_height);
271       // actual height
272       rdp.tiles[tile].height = tile_height;
273     }
274     else
275     {
276       // wrap all the way
277       height = mask_height;
278       rdp.tiles[tile].height = mask_height;
279     }
280   }
281
282   // without any large texture fixing-up; for alignment
283   int real_image_width = rdp.tiles[tile].width;
284   int real_image_height = rdp.tiles[tile].height;
285   int crc_height = height;
286   if (rdp.timg.set_by == 1)
287     crc_height = tile_height;
288
289   bpl = width << rdp.tiles[tile].size >> 1;
290
291   // ** COMMENT THIS TO DISABLE LARGE TEXTURES
292 #ifdef LARGE_TEXTURE_HANDLING
293   if (!voodoo.sup_large_tex && width > 256)
294   {
295     info->splits = ((width-1)>>8)+1;
296     info->splitheight = rdp.tiles[tile].height;
297     rdp.tiles[tile].height *= info->splits;
298     rdp.tiles[tile].width = 256;
299     width = 256;
300   }
301   else
302 #endif
303     // **
304   {
305     info->splits = 1;
306   }
307
308   LRDP(" | | |-+ Texture approved:\n");
309   FRDP (" | | | |- tmem: %08lx\n", rdp.tiles[tile].t_mem);
310   FRDP (" | | | |- load width: %d\n", width);
311   FRDP (" | | | |- load height: %d\n", height);
312   FRDP (" | | | |- actual width: %d\n", rdp.tiles[tile].width);
313   FRDP (" | | | |- actual height: %d\n", rdp.tiles[tile].height);
314   FRDP (" | | | |- size: %d\n", rdp.tiles[tile].size);
315   FRDP (" | | | +- format: %d\n", rdp.tiles[tile].format);
316   LRDP(" | | |- Calculating CRC... ");
317
318   // ** CRC CHECK
319
320   wid_64 = width << (rdp.tiles[tile].size) >> 1;
321   if (rdp.tiles[tile].size == 3)
322   {
323     if (wid_64 & 15) wid_64 += 16;
324     wid_64 &= 0xFFFFFFF0;
325   }
326   else
327   {
328     if (wid_64 & 7) wid_64 += 8;        // round up
329   }
330   wid_64 = wid_64>>3;
331
332   // Texture too big for tmem & needs to wrap? (trees in mm)
333   if (rdp.tiles[tile].t_mem + min(height, tile_height) * (rdp.tiles[tile].line<<3) > 4096)
334   {
335     LRDP("TEXTURE WRAPS TMEM!!! ");
336
337     // calculate the y value that intersects at 4096 bytes
338     int y = (4096 - rdp.tiles[tile].t_mem) / (rdp.tiles[tile].line<<3);
339
340     rdp.tiles[tile].clamp_t = 0;
341     rdp.tiles[tile].lr_t = rdp.tiles[tile].ul_t + y - 1;
342
343     // calc mask
344     int shift;
345     for (shift=0; (1<<shift)<y; shift++);
346     rdp.tiles[tile].mask_t = shift;
347
348     // restart the function
349     LRDP("restarting...\n");
350     GetTexInfo (id, tile);
351     return;
352   }
353
354   line = rdp.tiles[tile].line;
355   if (rdp.tiles[tile].size == 3)
356     line <<= 1;
357   wxUint32 crc = 0;
358   if (settings.fast_crc)
359   {
360     line = (line - wid_64) << 3;
361     if (wid_64 < 1) wid_64 = 1;
362     uint8_t * addr = (((uint8_t*)rdp.tmem) + (rdp.tiles[tile].t_mem<<3));
363     if (crc_height > 0) // Check the CRC
364     {
365       if (rdp.tiles[tile].size < 3)
366         crc = textureCRC(addr, wid_64, crc_height, line);
367       else //32b texture
368       {
369         int line_2 = line >> 1;
370         int wid_64_2 = max(1, wid_64 >> 1);
371         crc = textureCRC(addr, wid_64_2, crc_height, line_2);
372         crc += textureCRC(addr+0x800, wid_64_2, crc_height, line_2);
373       }
374     }
375   }
376   else
377   {
378     crc = 0xFFFFFFFF;
379     wxUIntPtr addr = wxPtrToUInt(rdp.tmem) + (rdp.tiles[tile].t_mem<<3);
380     wxUint32 line2 = max(line,1);
381     if (rdp.tiles[tile].size < 3)
382     {
383       line2 <<= 3;
384       for (int y = 0; y < crc_height; y++)
385       {
386         crc = CRC32( crc, reinterpret_cast<void*>(addr), bpl );
387         addr += line2;
388       }
389     }
390     else //32b texture
391     {
392       line2 <<= 2;
393       //32b texel is split in two 16b parts, so bpl/2 and line/2.
394       //Min value for bpl is 4, because when width==1 first 2 bytes of tmem will not be used.
395       bpl = max(bpl >> 1, 4);
396       for (int y = 0; y < crc_height; y++)
397       {
398         crc = CRC32( crc, reinterpret_cast<void*>(addr), bpl);
399         crc = CRC32( crc, reinterpret_cast<void*>(addr + 0x800), bpl);
400         addr += line2;
401       }
402     }
403     line = (line - wid_64) << 3;
404     if (wid_64 < 1) wid_64 = 1;
405   }
406   if ((rdp.tiles[tile].size < 2) && (rdp.tlut_mode || rdp.tiles[tile].format == 2))
407   {
408     if (rdp.tiles[tile].size == 0)
409       crc += rdp.pal_8_crc[rdp.tiles[tile].palette];
410     else
411       crc += rdp.pal_256_crc;
412   }
413
414   FRDP ("Done.  CRC is: %08lx.\n", crc);
415
416   wxUint32 flags = (rdp.tiles[tile].clamp_s << 23) | (rdp.tiles[tile].mirror_s << 22) |
417     (rdp.tiles[tile].mask_s << 18) | (rdp.tiles[tile].clamp_t << 17) |
418     (rdp.tiles[tile].mirror_t << 16) | (rdp.tiles[tile].mask_t << 12);
419
420   info->real_image_width = real_image_width;
421   info->real_image_height = real_image_height;
422   info->tile_width = tile_width;
423   info->tile_height = tile_height;
424   info->mask_width = mask_width;
425   info->mask_height = mask_height;
426   info->width = width;
427   info->height = height;
428   info->wid_64 = wid_64;
429   info->line = line;
430   info->crc = crc;
431   info->flags = flags;
432
433   // Search the texture cache for this texture
434   LRDP(" | | |-+ Checking cache...\n");
435
436   CACHE_LUT *cache;
437
438   if (rdp.noise == RDP::noise_texture)
439     return;
440
441   wxUint32 mod, modcolor, modcolor1, modcolor2, modfactor;
442   if (id == 0)
443   {
444     mod = cmb.mod_0;
445     modcolor = cmb.modcolor_0;
446     modcolor1 = cmb.modcolor1_0;
447     modcolor2 = cmb.modcolor2_0;
448     modfactor = cmb.modfactor_0;
449   }
450   else
451   {
452     mod = cmb.mod_1;
453     modcolor = cmb.modcolor_1;
454     modcolor1 = cmb.modcolor1_1;
455     modcolor2 = cmb.modcolor2_1;
456     modfactor = cmb.modfactor_1;
457   }
458
459   NODE *node = cachelut[crc>>16];
460   wxUint32 mod_mask = (rdp.tiles[tile].format == 2)?0xFFFFFFFF:0xF0F0F0F0;
461   while (node)
462   {
463     if (node->crc == crc)
464     {
465       cache = (CACHE_LUT*)node->data;
466       if (/*tex_found[id][node->tmu] == -1 &&
467           rdp.tiles[tile].palette == cache->palette &&
468           rdp.tiles[tile].format == cache->format &&
469           rdp.tiles[tile].size == cache->size &&*/
470           rdp.tiles[tile].width == cache->width &&
471           rdp.tiles[tile].height == cache->height &&
472           flags == cache->flags)
473       {
474         if (!(mod+cache->mod) || (cache->mod == mod &&
475           (cache->mod_color&mod_mask) == (modcolor&mod_mask) &&
476           (cache->mod_color1&mod_mask) == (modcolor1&mod_mask) &&
477           (cache->mod_color2&mod_mask) == (modcolor2&mod_mask) &&
478           abs((int)(cache->mod_factor - modfactor)) < 8))
479         {
480           FRDP (" | | | |- Texture found in cache (tmu=%d).\n", node->tmu);
481           tex_found[id][node->tmu] = node->number;
482           if (voodoo.tex_UMA)
483           {
484             tex_found[id][node->tmu^1] = node->number;
485             return;
486           }
487         }
488       }
489     }
490     node = node->pNext;
491   }
492
493   LRDP(" | | | +- Done.\n | | +- GetTexInfo end\n");
494 }
495
496 //****************************************************************
497 // ChooseBestTmu - chooses the best TMU to load to (the one with the most memory)
498
499 int ChooseBestTmu (int tmu1, int tmu2)
500 {
501   if (!fullscreen) return tmu1;
502   if (voodoo.tex_UMA) return 0;
503
504   if (tmu1 >= voodoo.num_tmu) return tmu2;
505   if (tmu2 >= voodoo.num_tmu) return tmu1;
506
507   if (voodoo.tex_max_addr[tmu1]-voodoo.tmem_ptr[tmu1] >
508     voodoo.tex_max_addr[tmu2]-voodoo.tmem_ptr[tmu2])
509     return tmu1;
510   else
511     return tmu2;
512 }
513
514 //****************************************************************
515 // SelectTBuffTex - select texture from texture buffer
516 static void SelectTBuffTex(TBUFF_COLOR_IMAGE * pTBuffTex)
517 {
518   FRDP ("SelectTBuffTex: tex: %d, tmu: %d, tile: %d\n", rdp.tex, pTBuffTex->tmu, pTBuffTex->tile);
519   grTexSource(pTBuffTex->tile, pTBuffTex->tex_addr, GR_MIPMAPLEVELMASK_BOTH, &(pTBuffTex->info) );
520 }
521
522 //****************************************************************
523 // TexCache - does texture loading after combiner is set
524 int SwapTextureBuffer();
525 void TexCache ()
526 {
527   LRDP(" |-+ TexCache called\n");
528
529 #ifdef TEXTURE_FILTER /* Hiroshi Morii <koolsmoky@users.sourceforge.net> */ // POSTNAPALM
530   if (settings.ghq_use && settings.ghq_hirs_dump) {
531     /* Force reload hi-res textures. Useful for texture artists */
532     if (CheckKeyPressed(G64_VK_R, 0x0001)) {
533       if (ext_ghq_reloadhirestex()) ClearCache();
534     }
535     /* Turn on texture dump */
536     else if (CheckKeyPressed(G64_VK_D, 0x0001)) {
537       extern void DisplayLoadProgress(const wchar_t *format, ...);
538       ghq_dmptex_toggle_key = !ghq_dmptex_toggle_key;
539       if (ghq_dmptex_toggle_key) {
540         DisplayLoadProgress(L"Texture dump - ON\n");
541         ClearCache();
542         SDL_Delay(1000);
543       } else {
544         DisplayLoadProgress(L"Texture dump - OFF\n");
545         SDL_Delay(1000);
546       }
547     }
548   }
549 #endif
550
551   if (rdp.tex & 1)
552     GetTexInfo (0, rdp.cur_tile);
553   if (rdp.tex & 2)
554     GetTexInfo (1, rdp.cur_tile+1);
555
556   TBUFF_COLOR_IMAGE * aTBuff[2] = {0, 0};
557   if (rdp.aTBuffTex[0])
558     aTBuff[rdp.aTBuffTex[0]->tile] = rdp.aTBuffTex[0];
559   if (rdp.aTBuffTex[1])
560     aTBuff[rdp.aTBuffTex[1]->tile] = rdp.aTBuffTex[1];
561
562 #define TMUMODE_NORMAL          0
563 #define TMUMODE_PASSTHRU        1
564 #define TMUMODE_NONE            2
565
566   int tmu_0, tmu_1;
567   int tmu_0_mode=0, tmu_1_mode=0;
568
569   // Select the best TMUs to use (removed 3 tmu support, unnecessary)
570   if (rdp.tex == 3)     // T0 and T1
571   {
572     tmu_0 = 0;
573     tmu_1 = 1;
574   }
575   else if (rdp.tex == 2)        // T1
576   {
577     if (tex_found[1][0] != -1)  // T1 found in tmu 0
578       tmu_1 = 0;
579     else if (tex_found[1][1] != -1)     // T1 found in tmu 1
580       tmu_1 = 1;
581     else        // T1 not found
582       tmu_1 = ChooseBestTmu (0, 1);
583
584     tmu_0 = !tmu_1;
585     tmu_0_mode = (tmu_0==1)?TMUMODE_NONE:TMUMODE_PASSTHRU;
586   }
587   else if (rdp.tex == 1)        // T0
588   {
589     if (tex_found[0][0] != -1)  // T0 found in tmu 0
590       tmu_0 = 0;
591     else if (tex_found[0][1] != -1)     // T0 found in tmu 1
592       tmu_0 = 1;
593     else        // T0 not found
594       tmu_0 = ChooseBestTmu (0, 1);
595
596     tmu_1 = !tmu_0;
597     tmu_1_mode = (tmu_1==1)?TMUMODE_NONE:TMUMODE_PASSTHRU;
598   }
599   else  // no texture
600   {
601     tmu_0 = 0;
602     tmu_0_mode = TMUMODE_NONE;
603     tmu_1 = 0;
604     tmu_1_mode = TMUMODE_NONE;
605   }
606
607   FRDP (" | |-+ Modes set:\n | | |- tmu_0 = %d\n | | |- tmu_1 = %d\n",
608     tmu_0, tmu_1);
609   FRDP (" | | |- tmu_0_mode = %d\n | | |- tmu_1_mode = %d\n",
610     tmu_0_mode, tmu_1_mode);
611
612   if (tmu_0_mode == TMUMODE_PASSTHRU) {
613     cmb.tmu0_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_SCALE_OTHER;
614     cmb.tmu0_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_ONE;
615     if (cmb.tex_cmb_ext_use)
616     {
617       cmb.t0c_ext_a = GR_CMBX_OTHER_TEXTURE_RGB;
618       cmb.t0c_ext_a_mode = GR_FUNC_MODE_X;
619       cmb.t0c_ext_b = GR_CMBX_LOCAL_TEXTURE_RGB;
620       cmb.t0c_ext_b_mode = GR_FUNC_MODE_ZERO;
621       cmb.t0c_ext_c = GR_CMBX_ZERO;
622       cmb.t0c_ext_c_invert = 1;
623       cmb.t0c_ext_d = GR_CMBX_ZERO;
624       cmb.t0c_ext_d_invert = 0;
625       cmb.t0a_ext_a = GR_CMBX_OTHER_TEXTURE_ALPHA;
626       cmb.t0a_ext_a_mode = GR_FUNC_MODE_X;
627       cmb.t0a_ext_b = GR_CMBX_LOCAL_TEXTURE_ALPHA;
628       cmb.t0a_ext_b_mode = GR_FUNC_MODE_ZERO;
629       cmb.t0a_ext_c = GR_CMBX_ZERO;
630       cmb.t0a_ext_c_invert = 1;
631       cmb.t0a_ext_d = GR_CMBX_ZERO;
632       cmb.t0a_ext_d_invert = 0;
633     }
634   }
635   else if (tmu_0_mode == TMUMODE_NONE) {
636     cmb.tmu0_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_NONE;
637     cmb.tmu0_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_NONE;
638     if (cmb.tex_cmb_ext_use)
639     {
640       cmb.t0c_ext_a = GR_CMBX_LOCAL_TEXTURE_RGB;
641       cmb.t0c_ext_a_mode = GR_FUNC_MODE_ZERO;
642       cmb.t0c_ext_b = GR_CMBX_LOCAL_TEXTURE_RGB;
643       cmb.t0c_ext_b_mode = GR_FUNC_MODE_ZERO;
644       cmb.t0c_ext_c = GR_CMBX_ZERO;
645       cmb.t0c_ext_c_invert = 0;
646       cmb.t0c_ext_d = GR_CMBX_ZERO;
647       cmb.t0c_ext_d_invert = 0;
648       cmb.t0a_ext_a = GR_CMBX_LOCAL_TEXTURE_ALPHA;
649       cmb.t0a_ext_a_mode = GR_FUNC_MODE_ZERO;
650       cmb.t0a_ext_b = GR_CMBX_LOCAL_TEXTURE_ALPHA;
651       cmb.t0a_ext_b_mode = GR_FUNC_MODE_ZERO;
652       cmb.t0a_ext_c = GR_CMBX_ZERO;
653       cmb.t0a_ext_c_invert = 0;
654       cmb.t0a_ext_d = GR_CMBX_ZERO;
655       cmb.t0a_ext_d_invert = 0;
656     }
657   }
658   if (tmu_1_mode == TMUMODE_PASSTHRU) {
659     cmb.tmu1_func = cmb.tmu1_a_func = GR_COMBINE_FUNCTION_SCALE_OTHER;
660     cmb.tmu1_fac = cmb.tmu1_a_fac = GR_COMBINE_FACTOR_ONE;
661     if (cmb.tex_cmb_ext_use)
662     {
663       cmb.t1c_ext_a = GR_CMBX_OTHER_TEXTURE_RGB;
664       cmb.t1c_ext_a_mode = GR_FUNC_MODE_X;
665       cmb.t1c_ext_b = GR_CMBX_LOCAL_TEXTURE_RGB;
666       cmb.t1c_ext_b_mode = GR_FUNC_MODE_ZERO;
667       cmb.t1c_ext_c = GR_CMBX_ZERO;
668       cmb.t1c_ext_c_invert = 1;
669       cmb.t1c_ext_d = GR_CMBX_ZERO;
670       cmb.t1c_ext_d_invert = 0;
671       cmb.t1a_ext_a = GR_CMBX_OTHER_TEXTURE_ALPHA;
672       cmb.t1a_ext_a_mode = GR_FUNC_MODE_X;
673       cmb.t1a_ext_b = GR_CMBX_LOCAL_TEXTURE_ALPHA;
674       cmb.t1a_ext_b_mode = GR_FUNC_MODE_ZERO;
675       cmb.t1a_ext_c = GR_CMBX_ZERO;
676       cmb.t1a_ext_c_invert = 1;
677       cmb.t1a_ext_d = GR_CMBX_ZERO;
678       cmb.t1a_ext_d_invert = 0;
679     }
680   }
681   else if (tmu_1_mode == TMUMODE_NONE) {
682     cmb.tmu1_func = cmb.tmu1_a_func = GR_COMBINE_FUNCTION_NONE;
683     cmb.tmu1_fac = cmb.tmu1_a_fac = GR_COMBINE_FACTOR_NONE;
684     if (cmb.tex_cmb_ext_use)
685     {
686       cmb.t1c_ext_a = GR_CMBX_LOCAL_TEXTURE_RGB;
687       cmb.t1c_ext_a_mode = GR_FUNC_MODE_ZERO;
688       cmb.t1c_ext_b = GR_CMBX_LOCAL_TEXTURE_RGB;
689       cmb.t1c_ext_b_mode = GR_FUNC_MODE_ZERO;
690       cmb.t1c_ext_c = GR_CMBX_ZERO;
691       cmb.t1c_ext_c_invert = 0;
692       cmb.t1c_ext_d = GR_CMBX_ZERO;
693       cmb.t1c_ext_d_invert = 0;
694       cmb.t1a_ext_a = GR_CMBX_LOCAL_TEXTURE_ALPHA;
695       cmb.t1a_ext_a_mode = GR_FUNC_MODE_ZERO;
696       cmb.t1a_ext_b = GR_CMBX_LOCAL_TEXTURE_ALPHA;
697       cmb.t1a_ext_b_mode = GR_FUNC_MODE_ZERO;
698       cmb.t1a_ext_c = GR_CMBX_ZERO;
699       cmb.t1a_ext_c_invert = 0;
700       cmb.t1a_ext_d = GR_CMBX_ZERO;
701       cmb.t1a_ext_d_invert = 0;
702     }
703   }
704
705   // little change to make single-tmu cards look better, use first texture no matter what
706
707   if (voodoo.num_tmu == 1)
708   {
709     if (rdp.best_tex == 0)
710     {
711       cmb.tmu0_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_LOCAL;
712       cmb.tmu0_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_NONE;
713       tmu_0 = 0;
714       tmu_1 = 1;
715     }
716     else
717     {
718       cmb.tmu1_func = cmb.tmu1_a_func = GR_COMBINE_FUNCTION_LOCAL;
719       cmb.tmu1_fac = cmb.tmu1_a_fac = GR_COMBINE_FACTOR_NONE;
720       tmu_1 = 0;
721       tmu_0 = 1;
722     }
723   }
724
725
726   rdp.t0 = tmu_0;
727   rdp.t1 = tmu_1;
728
729   // SET the combiner
730   if (fullscreen)
731   {
732     if (rdp.allow_combine)
733     {
734       // Now actually combine
735       if (cmb.cmb_ext_use)
736       {
737         LRDP(" | | | |- combiner extension\n");
738         if (!(cmb.cmb_ext_use & COMBINE_EXT_COLOR))
739           ColorCombinerToExtension ();
740         if (!(cmb.cmb_ext_use & COMBINE_EXT_ALPHA))
741           AlphaCombinerToExtension ();
742         cmb.grColorCombineExt(cmb.c_ext_a, cmb.c_ext_a_mode,
743           cmb.c_ext_b, cmb.c_ext_b_mode,
744           cmb.c_ext_c, cmb.c_ext_c_invert,
745           cmb.c_ext_d, cmb.c_ext_d_invert, 0, 0);
746         cmb.grAlphaCombineExt(cmb.a_ext_a, cmb.a_ext_a_mode,
747           cmb.a_ext_b, cmb.a_ext_b_mode,
748           cmb.a_ext_c, cmb.a_ext_c_invert,
749           cmb.a_ext_d, cmb.a_ext_d_invert, 0, 0);
750       }
751       else
752       {
753         grColorCombine (cmb.c_fnc, cmb.c_fac, cmb.c_loc, cmb.c_oth, FXFALSE);
754         grAlphaCombine (cmb.a_fnc, cmb.a_fac, cmb.a_loc, cmb.a_oth, FXFALSE);
755       }
756       grConstantColorValue (cmb.ccolor);
757       grAlphaBlendFunction (cmb.abf1, cmb.abf2, GR_BLEND_ZERO, GR_BLEND_ZERO);
758       if (!rdp.tex) //nothing more to do
759         return;
760     }
761
762     if (tmu_1 < voodoo.num_tmu)
763     {
764       if (cmb.tex_cmb_ext_use)
765       {
766         LRDP(" | | | |- combiner extension tmu1\n");
767         if (!(cmb.tex_cmb_ext_use & TEX_COMBINE_EXT_COLOR))
768           TexColorCombinerToExtension (GR_TMU1);
769         if (!(cmb.tex_cmb_ext_use & TEX_COMBINE_EXT_ALPHA))
770           TexAlphaCombinerToExtension (GR_TMU1);
771         cmb.grTexColorCombineExt(tmu_1, cmb.t1c_ext_a, cmb.t1c_ext_a_mode,
772           cmb.t1c_ext_b, cmb.t1c_ext_b_mode,
773           cmb.t1c_ext_c, cmb.t1c_ext_c_invert,
774           cmb.t1c_ext_d, cmb.t1c_ext_d_invert, 0, 0);
775         cmb.grTexAlphaCombineExt(tmu_1, cmb.t1a_ext_a, cmb.t1a_ext_a_mode,
776           cmb.t1a_ext_b, cmb.t1a_ext_b_mode,
777           cmb.t1a_ext_c, cmb.t1a_ext_c_invert,
778           cmb.t1a_ext_d, cmb.t1a_ext_d_invert, 0, 0);
779         cmb.grConstantColorValueExt(tmu_1, cmb.tex_ccolor);
780       }
781       else
782       {
783         grTexCombine (tmu_1, cmb.tmu1_func, cmb.tmu1_fac, cmb.tmu1_a_func, cmb.tmu1_a_fac, cmb.tmu1_invert, cmb.tmu1_a_invert);
784         if (cmb.combine_ext)
785           cmb.grConstantColorValueExt(tmu_1, 0);
786       }
787       grTexDetailControl (tmu_1, cmb.dc1_lodbias, cmb.dc1_detailscale, cmb.dc1_detailmax);
788       grTexLodBiasValue (tmu_1, cmb.lodbias1);
789     }
790     if (tmu_0 < voodoo.num_tmu)
791     {
792       if (cmb.tex_cmb_ext_use)
793       {
794         LRDP(" | | | |- combiner extension tmu0\n");
795         if (!(cmb.tex_cmb_ext_use & TEX_COMBINE_EXT_COLOR))
796           TexColorCombinerToExtension (GR_TMU0);
797         if (!(cmb.tex_cmb_ext_use & TEX_COMBINE_EXT_ALPHA))
798           TexAlphaCombinerToExtension (GR_TMU0);
799         cmb.grTexColorCombineExt(tmu_0, cmb.t0c_ext_a, cmb.t0c_ext_a_mode,
800           cmb.t0c_ext_b, cmb.t0c_ext_b_mode,
801           cmb.t0c_ext_c, cmb.t0c_ext_c_invert,
802           cmb.t0c_ext_d, cmb.t0c_ext_d_invert, 0, 0);
803         cmb.grTexAlphaCombineExt(tmu_0, cmb.t0a_ext_a, cmb.t0a_ext_a_mode,
804           cmb.t0a_ext_b, cmb.t0a_ext_b_mode,
805           cmb.t0a_ext_c, cmb.t0a_ext_c_invert,
806           cmb.t0a_ext_d, cmb.t0a_ext_d_invert, 0, 0);
807         cmb.grConstantColorValueExt(tmu_0, cmb.tex_ccolor);
808       }
809       else
810       {
811         grTexCombine (tmu_0, cmb.tmu0_func, cmb.tmu0_fac, cmb.tmu0_a_func, cmb.tmu0_a_fac, cmb.tmu0_invert, cmb.tmu0_a_invert);
812         if (cmb.combine_ext)
813           cmb.grConstantColorValueExt(tmu_0, 0);
814       }
815       grTexDetailControl (tmu_0, cmb.dc0_lodbias, cmb.dc0_detailscale, cmb.dc0_detailmax);
816       grTexLodBiasValue (tmu_0, cmb.lodbias0);
817     }
818   }
819
820   if ((rdp.tex & 1) && tmu_0 < voodoo.num_tmu)
821   {
822     if (aTBuff[0] && aTBuff[0]->cache)
823     {
824       LRDP(" | |- Hires tex T0 found in cache.\n");
825       if (fullscreen)
826       {
827         rdp.cur_cache[0] = aTBuff[0]->cache;
828         rdp.cur_cache[0]->last_used = frame_count;
829         rdp.cur_cache[0]->uses = rdp.debug_n;
830       }
831     }
832     else if (tex_found[0][tmu_0] != -1)
833     {
834       LRDP(" | |- T0 found in cache.\n");
835       if (fullscreen)
836       {
837         CACHE_LUT *cache = voodoo.tex_UMA?&rdp.cache[0][tex_found[0][0]]:&rdp.cache[tmu_0][tex_found[0][tmu_0]];
838         rdp.cur_cache_n[0] = tex_found[0][tmu_0];
839         rdp.cur_cache[0] = cache;
840         rdp.cur_cache[0]->last_used = frame_count;
841         rdp.cur_cache[0]->uses = rdp.debug_n;
842         grTexSource (tmu_0,
843           (voodoo.tex_min_addr[tmu_0] + cache->tmem_addr),
844           GR_MIPMAPLEVELMASK_BOTH,
845           &cache->t_info);
846       }
847     }
848     else
849       LoadTex (0, tmu_0);
850   }
851   if ((rdp.tex & 2) && tmu_1 < voodoo.num_tmu)
852   {
853     if (aTBuff[1] && aTBuff[1]->cache)
854     {
855       LRDP(" | |- Hires tex T1 found in cache.\n");
856       if (fullscreen)
857       {
858         rdp.cur_cache[1] = aTBuff[1]->cache;
859         rdp.cur_cache[1]->last_used = frame_count;
860         rdp.cur_cache[1]->uses = rdp.debug_n;
861       }
862     }
863     else if (tex_found[1][tmu_1] != -1)
864     {
865       LRDP(" | |- T1 found in cache.\n");
866       if (fullscreen)
867       {
868         CACHE_LUT *cache = voodoo.tex_UMA?&rdp.cache[0][tex_found[1][0]]:&rdp.cache[tmu_1][tex_found[1][tmu_1]];
869         rdp.cur_cache_n[1] = tex_found[1][tmu_1];
870         rdp.cur_cache[1] = cache;
871         rdp.cur_cache[1]->last_used = frame_count;
872         rdp.cur_cache[1]->uses = rdp.debug_n;
873         grTexSource (tmu_1,
874           (voodoo.tex_min_addr[tmu_1] + cache->tmem_addr),
875           GR_MIPMAPLEVELMASK_BOTH,
876           &cache->t_info);
877       }
878     }
879     else
880       LoadTex (1, tmu_1);
881   }
882
883   if (fullscreen)
884   {
885     for (int i=0; i<2; i++)
886     {
887       int tmu;
888       if (i==0) tmu=tmu_0;
889       else if (i==1) tmu=tmu_1;
890
891       if (tmu >= voodoo.num_tmu) continue;
892
893       int tile = rdp.cur_tile + i;
894
895       if (settings.filtering == 0)
896       {
897         int filter = (rdp.filter_mode!=2)?GR_TEXTUREFILTER_POINT_SAMPLED:GR_TEXTUREFILTER_BILINEAR;
898         grTexFilterMode (tmu, filter, filter);
899       }
900       else
901       {
902         int filter = (settings.filtering==1)?GR_TEXTUREFILTER_BILINEAR:GR_TEXTUREFILTER_POINT_SAMPLED;
903         grTexFilterMode (tmu, filter, filter);
904       }
905
906       if (rdp.cur_cache[i])
907       {
908         wxUint32 mode_s, mode_t;
909         int clamp_s, clamp_t;
910         if (rdp.force_wrap && !rdp.texrecting)
911         {
912           clamp_s = rdp.tiles[tile].clamp_s && rdp.tiles[tile].lr_s-rdp.tiles[tile].ul_s < 256;
913           clamp_t = rdp.tiles[tile].clamp_t && rdp.tiles[tile].lr_t-rdp.tiles[tile].ul_t < 256;
914         }
915         else
916         {
917           clamp_s = (rdp.tiles[tile].clamp_s || rdp.tiles[tile].mask_s == 0) &&
918             rdp.tiles[tile].lr_s-rdp.tiles[tile].ul_s < 256;
919           clamp_t = (rdp.tiles[tile].clamp_t || rdp.tiles[tile].mask_t == 0) &&
920             rdp.tiles[tile].lr_t-rdp.tiles[tile].ul_t < 256;
921         }
922
923         if (rdp.cur_cache[i]->f_mirror_s)
924           mode_s = GR_TEXTURECLAMP_MIRROR_EXT;
925         else if (rdp.cur_cache[i]->f_wrap_s)
926           mode_s = GR_TEXTURECLAMP_WRAP;
927         else if (clamp_s)
928           mode_s = GR_TEXTURECLAMP_CLAMP;
929         else
930         {
931           if (rdp.tiles[tile].mirror_s && voodoo.sup_mirroring)
932             mode_s = GR_TEXTURECLAMP_MIRROR_EXT;
933           else
934             mode_s = GR_TEXTURECLAMP_WRAP;
935         }
936
937         if (rdp.cur_cache[i]->f_mirror_t)
938           mode_t = GR_TEXTURECLAMP_MIRROR_EXT;
939         else if (rdp.cur_cache[i]->f_wrap_t)
940           mode_t = GR_TEXTURECLAMP_WRAP;
941         else if (clamp_t)
942           mode_t = GR_TEXTURECLAMP_CLAMP;
943         else
944         {
945           if (rdp.tiles[tile].mirror_t && voodoo.sup_mirroring)
946             mode_t = GR_TEXTURECLAMP_MIRROR_EXT;
947           else
948             mode_t = GR_TEXTURECLAMP_WRAP;
949         }
950
951         grTexClampMode (tmu,
952           mode_s,
953           mode_t);
954       }
955       if (aTBuff[i] && (rdp.tex&(i+1)))
956         SelectTBuffTex(aTBuff[i]);
957     }
958   }
959
960   LRDP(" | +- TexCache End\n");
961 }
962
963
964 #ifdef TEXTURE_FILTER
965 /** cite from RiceVideo */
966 inline wxUint32 CalculateDXT(wxUint32 txl2words)
967 {
968   if( txl2words == 0 ) return 1;
969   else return (2048+txl2words-1)/txl2words;
970 }
971
972 wxUint32 sizeBytes[4] = {0,1,2,4};
973
974 inline wxUint32 Txl2Words(wxUint32 width, wxUint32 size)
975 {
976   if( size == 0 )
977     return max(1, width/16);
978   else
979     return max(1, width*sizeBytes[size]/8);
980 }
981
982 inline wxUint32 ReverseDXT(wxUint32 val, wxUint32 lrs, wxUint32 width, wxUint32 size)
983 {
984   if( val == 0x800 ) return 1;
985
986   int low = 2047/val;
987   if( CalculateDXT(low) > val ) low++;
988   int high = 2047/(val-1);
989
990   if( low == high )     return low;
991
992   for( int i=low; i<=high; i++ )
993   {
994     if( Txl2Words(width, size) == (wxUint32)i )
995       return i;
996   }
997
998   return        (low+high)/2;
999 }
1000 /** end RiceVideo cite */
1001 #endif
1002
1003 //****************************************************************
1004 // LoadTex - does the actual texture loading after everything is prepared
1005
1006 void LoadTex (int id, int tmu)
1007 {
1008   FRDP (" | |-+ LoadTex (id: %d, tmu: %d)\n", id, tmu);
1009
1010   int td = rdp.cur_tile + id;
1011   int lod, aspect;
1012   CACHE_LUT *cache;
1013
1014   if (texinfo[id].width < 0 || texinfo[id].height < 0)
1015     return;
1016
1017   // Clear the cache if it's full
1018   if (rdp.n_cached[tmu] >= MAX_CACHE)
1019   {
1020     LRDP("Cache count reached, clearing...\n");
1021     ClearCache ();
1022     if (id == 1 && rdp.tex == 3)
1023       LoadTex (0, rdp.t0);
1024   }
1025
1026   // Get this cache object
1027   cache = voodoo.tex_UMA?&rdp.cache[0][rdp.n_cached[0]]:&rdp.cache[tmu][rdp.n_cached[tmu]];
1028   rdp.cur_cache[id] = cache;
1029   rdp.cur_cache_n[id] = rdp.n_cached[tmu];
1030
1031   //!Hackalert
1032   //GoldenEye water texture. It has CI format in fact, but the game set it to RGBA
1033   if ((settings.hacks&hack_GoldenEye) && rdp.tiles[td].format == 0 && rdp.tlut_mode == 2 && rdp.tiles[td].size == 2)
1034   {
1035     rdp.tiles[td].format = 2;
1036     rdp.tiles[td].size = 1;
1037   }
1038
1039   // Set the data
1040   cache->line = rdp.tiles[td].line;
1041   cache->addr = rdp.addr[rdp.tiles[td].t_mem];
1042   cache->crc = texinfo[id].crc;
1043   cache->palette = rdp.tiles[td].palette;
1044   cache->width = rdp.tiles[td].width;
1045   cache->height = rdp.tiles[td].height;
1046   cache->format = rdp.tiles[td].format;
1047   cache->size = rdp.tiles[td].size;
1048   cache->tmem_addr = voodoo.tmem_ptr[tmu];
1049   cache->set_by = rdp.timg.set_by;
1050   cache->texrecting = rdp.texrecting;
1051   cache->last_used = frame_count;
1052   cache->uses = rdp.debug_n;
1053   cache->flags = texinfo[id].flags;
1054   cache->f_mirror_s = FALSE;
1055   cache->f_mirror_t = FALSE;
1056   cache->f_wrap_s = FALSE;
1057   cache->f_wrap_t = FALSE;
1058 #ifdef TEXTURE_FILTER
1059   cache->is_hires_tex = FALSE;
1060   cache->ricecrc    = texinfo[id].ricecrc;
1061 #endif
1062
1063   // Add this cache to the list
1064   AddToList (&cachelut[cache->crc>>16], cache->crc, wxPtrToUInt(cache), tmu, rdp.n_cached[tmu]);
1065
1066   // temporary
1067   cache->t_info.format = GR_TEXFMT_ARGB_1555;
1068
1069   // Calculate lod and aspect
1070   wxUint32 size_x = rdp.tiles[td].width;
1071   wxUint32 size_y = rdp.tiles[td].height;
1072
1073   // make size_x and size_y both powers of two
1074   if (!voodoo.sup_large_tex)
1075   {
1076     if (size_x > 256) size_x = 256;
1077     if (size_y > 256) size_y = 256;
1078   }
1079
1080   int shift;
1081   for (shift=0; (1<<shift) < (int)size_x; shift++);
1082   size_x = 1 << shift;
1083   for (shift=0; (1<<shift) < (int)size_y; shift++);
1084   size_y = 1 << shift;
1085
1086   // Voodoo 1 support is all here, it will automatically mirror to the full extent.
1087   if (!voodoo.sup_mirroring)
1088   {
1089     if (rdp.tiles[td].mirror_s && !rdp.tiles[td].clamp_s && (voodoo.sup_large_tex || size_x <= 128))
1090       size_x <<= 1;
1091     if (rdp.tiles[td].mirror_t && !rdp.tiles[td].clamp_t && (voodoo.sup_large_tex || size_y <= 128))
1092       size_y <<= 1;
1093   }
1094
1095   // Calculate the maximum size
1096   int size_max = max (size_x, size_y);
1097   wxUint32 real_x=size_max, real_y=size_max;
1098   switch (size_max)
1099   {
1100   case 1:
1101     lod = GR_LOD_LOG2_1;
1102     cache->scale = 256.0f;
1103     break;
1104   case 2:
1105     lod = GR_LOD_LOG2_2;
1106     cache->scale = 128.0f;
1107     break;
1108   case 4:
1109     lod = GR_LOD_LOG2_4;
1110     cache->scale = 64.0f;
1111     break;
1112   case 8:
1113     lod = GR_LOD_LOG2_8;
1114     cache->scale = 32.0f;
1115     break;
1116   case 16:
1117     lod = GR_LOD_LOG2_16;
1118     cache->scale = 16.0f;
1119     break;
1120   case 32:
1121     lod = GR_LOD_LOG2_32;
1122     cache->scale = 8.0f;
1123     break;
1124   case 64:
1125     lod = GR_LOD_LOG2_64;
1126     cache->scale = 4.0f;
1127     break;
1128   case 128:
1129     lod = GR_LOD_LOG2_128;
1130     cache->scale = 2.0f;
1131     break;
1132   case 256:
1133     lod = GR_LOD_LOG2_256;
1134     cache->scale = 1.0f;
1135     break;
1136   case 512:
1137     lod = GR_LOD_LOG2_512;
1138     cache->scale = 0.5f;
1139     break;
1140   default:
1141     lod = GR_LOD_LOG2_1024;
1142     cache->scale = 0.25f;
1143     break;
1144   }
1145
1146   // Calculate the aspect ratio
1147   if (size_x >= size_y)
1148   {
1149     int ratio = size_x / size_y;
1150     switch (ratio)
1151     {
1152     case 1:
1153       aspect = GR_ASPECT_LOG2_1x1;
1154       cache->scale_x = 1.0f;
1155       cache->scale_y = 1.0f;
1156       break;
1157     case 2:
1158       aspect = GR_ASPECT_LOG2_2x1;
1159       cache->scale_x = 1.0f;
1160       cache->scale_y = 0.5f;
1161       real_y >>= 1;
1162       break;
1163     case 4:
1164       aspect = GR_ASPECT_LOG2_4x1;
1165       cache->scale_x = 1.0f;
1166       cache->scale_y = 0.25f;
1167       real_y >>= 2;
1168       break;
1169     default:
1170       aspect = GR_ASPECT_LOG2_8x1;
1171       cache->scale_x = 1.0f;
1172       cache->scale_y = 0.125f;
1173       real_y >>= 3;
1174       break;
1175     }
1176   }
1177   else
1178   {
1179     int ratio = size_y / size_x;
1180     switch (ratio)
1181     {
1182     case 2:
1183       aspect = GR_ASPECT_LOG2_1x2;
1184       cache->scale_x = 0.5f;
1185       cache->scale_y = 1.0f;
1186       real_x >>= 1;
1187       break;
1188     case 4:
1189       aspect = GR_ASPECT_LOG2_1x4;
1190       cache->scale_x = 0.25f;
1191       cache->scale_y = 1.0f;
1192       real_x >>= 2;
1193       break;
1194     default:
1195       aspect = GR_ASPECT_LOG2_1x8;
1196       cache->scale_x = 0.125f;
1197       cache->scale_y = 1.0f;
1198       real_x >>= 3;
1199       break;
1200     }
1201   }
1202
1203   if (real_x != cache->width || real_y != cache->height)
1204   {
1205     cache->scale_x *= (float)cache->width / (float)real_x;
1206     cache->scale_y *= (float)cache->height / (float)real_y;
1207   }
1208
1209   int splits = texinfo[id].splits;
1210   cache->splits = texinfo[id].splits;
1211   cache->splitheight = real_y / cache->splits;
1212   if (cache->splitheight < texinfo[id].splitheight)
1213     cache->splitheight = texinfo[id].splitheight;
1214
1215   // ** Calculate alignment values
1216   int wid = cache->width;
1217   int hei = cache->height;
1218
1219   if (splits > 1)
1220   {
1221     wid = texinfo[id].real_image_width;
1222     hei = texinfo[id].real_image_height;
1223   }
1224
1225   cache->c_off = cache->scale * 0.5f;
1226   if (wid != 1) cache->c_scl_x = cache->scale;
1227   else cache->c_scl_x = 0.0f;
1228   if (hei != 1) cache->c_scl_y = cache->scale;
1229   else cache->c_scl_y = 0.0f;
1230   // **
1231
1232   wxUint32 mod, modcolor, modcolor1, modcolor2, modfactor;
1233   if (id == 0)
1234   {
1235     mod = cmb.mod_0;
1236     modcolor = cmb.modcolor_0;
1237     modcolor1 = cmb.modcolor1_0;
1238     modcolor2 = cmb.modcolor2_0;
1239     modfactor = cmb.modfactor_0;
1240   }
1241   else
1242   {
1243     mod = cmb.mod_1;
1244     modcolor = cmb.modcolor_1;
1245     modcolor1 = cmb.modcolor1_1;
1246     modcolor2 = cmb.modcolor2_1;
1247     modfactor = cmb.modfactor_1;
1248   }
1249
1250   wxUint16 tmp_pal[256];
1251   int modifyPalette = (mod && (cache->format == 2) && (rdp.tlut_mode == 2));
1252
1253   if (modifyPalette)
1254   {
1255     memcpy(tmp_pal, rdp.pal_8, 512);
1256     ModifyPalette(mod, modcolor, modcolor1, modfactor);
1257   }
1258
1259   cache->mod = mod;
1260   cache->mod_color = modcolor;
1261   cache->mod_color1 = modcolor1;
1262   cache->mod_factor = modfactor;
1263
1264   for (int t = 0; t < 2; t++) {
1265     if (rdp.aTBuffTex[t] && rdp.aTBuffTex[t]->tile == id) //texture buffer will be used instead of frame buffer texture
1266     {
1267       rdp.aTBuffTex[t]->cache = cache;
1268       FRDP("tbuff_tex selected: %d, tile=%d\n", t, id);
1269       return;
1270     }
1271   }
1272
1273   wxUint32 result = 0;  // keep =0 so it doesn't mess up on the first split
1274
1275   texture = tex1;
1276
1277   // Hiroshi Morii <koolsmoky@users.sourceforge.net>
1278   // NOTE: Loading Hi-res texture packs and filtering should be done
1279   // before the texture is modified with color palettes, etc.
1280   //
1281   // Since the internal texture identification needs Glide64CRC, (RiceCRC
1282   // doesn't always return unique values) it seems reasonable that the
1283   // extra CRC calculation for hires textures should be executed only
1284   // when we get passed the texture ram cache and texture buffers for
1285   // minimal calculation overhead.
1286   //
1287 #ifdef TEXTURE_FILTER // Hiroshi Morii <koolsmoky@users.sourceforge.net>
1288   GHQTexInfo ghqTexInfo;
1289   memset(&ghqTexInfo, 0, sizeof(GHQTexInfo));
1290   wxUint32 g64_crc = cache->crc;
1291   if (settings.ghq_use)
1292   {
1293     int bpl;
1294     wxUint8* addr = (wxUint8*)(gfx.RDRAM+rdp.addr[rdp.tiles[td].t_mem]);
1295     int tile_width  = texinfo[id].width;
1296     int tile_height = texinfo[id].height;
1297     LOAD_TILE_INFO &info = rdp.load_info[rdp.tiles[td].t_mem];
1298     if (rdp.timg.set_by == 1)
1299     {
1300       bpl = info.tex_width << info.tex_size >> 1;
1301       addr += (info.tile_ul_t * bpl) + (((info.tile_ul_s<<info.tex_size)+1)>>1);
1302
1303       tile_width = min(info.tile_width, info.tex_width);
1304       if (info.tex_size > rdp.tiles[td].size)
1305         tile_width <<= info.tex_size - rdp.tiles[td].size;
1306
1307       if (rdp.tiles[td].lr_t > rdp.bg_image_height)
1308         tile_height = rdp.bg_image_height - rdp.tiles[td].ul_t;
1309       else
1310         tile_height = info.tile_height;
1311     }
1312     else
1313     {
1314       if (rdp.tiles[td].size == 3)
1315         bpl = rdp.tiles[td].line << 4;
1316       else if (info.dxt == 0)
1317         bpl = rdp.tiles[td].line << 3;
1318       else {
1319         wxUint32 dxt = info.dxt;
1320         if (dxt > 1)
1321           dxt = ReverseDXT(dxt, info.tile_width, texinfo[id].width, rdp.tiles[td].size);
1322         bpl = dxt << 3;
1323       }
1324     }
1325
1326     //    wxUint8* addr = (wxUint8*)(gfx.RDRAM+rdp.addr[rdp.tiles[td].t_mem] + (rdp.tiles[td].ul_t * bpl) + (((rdp.tiles[td].ul_s<<rdp.tiles[td].size)+1)>>1));
1327     wxUint8 * paladdr = 0;
1328     wxUint16 * palette = 0;
1329     if ((rdp.tiles[td].size < 2) && (rdp.tlut_mode || rdp.tiles[td].format == 2))
1330     {
1331       if (rdp.tiles[td].size == 1)
1332         paladdr = (wxUint8*)(rdp.pal_8_rice);
1333       else if (settings.ghq_hirs_altcrc)
1334         paladdr = (wxUint8*)(rdp.pal_8_rice + (rdp.tiles[td].palette << 5));
1335       else
1336         paladdr = (wxUint8*)(rdp.pal_8_rice + (rdp.tiles[td].palette << 4));
1337       palette = (rdp.pal_8 + (rdp.tiles[td].palette << 4));
1338     }
1339
1340     // XXX: Special combiner modes are ignored for hires textures
1341     // for now. Come back to this later!! The following is needed
1342     // for (2xSai, hq4x, etc) enhanced/filtered textures.
1343     g64_crc = CRC32( g64_crc, &cache->mod, 4 );
1344     g64_crc = CRC32( g64_crc, &cache->mod_color, 4 );
1345     g64_crc = CRC32( g64_crc, &cache->mod_color1, 4 );
1346     //g64_crc = CRC32( g64_crc, &cache->mod_color2, 4 ); // not used?
1347     g64_crc = CRC32( g64_crc, &cache->mod_factor, 4 );
1348
1349     cache->ricecrc = ext_ghq_checksum(addr, tile_width, tile_height, (unsigned short)(rdp.tiles[td].format << 8 | rdp.tiles[td].size), bpl, paladdr);
1350     FRDP("CI RICE CRC. format: %d, size: %d, CRC: %08lx, PalCRC: %08lx\n", rdp.tiles[td].format, rdp.tiles[td].size, (wxUint32)(cache->ricecrc&0xFFFFFFFF), (wxUint32)(cache->ricecrc>>32));
1351     if (ext_ghq_hirestex((uint64)g64_crc, cache->ricecrc, palette, &ghqTexInfo))
1352     {
1353       cache->is_hires_tex = ghqTexInfo.is_hires_tex;
1354       if (!ghqTexInfo.is_hires_tex && aspect != ghqTexInfo.aspectRatioLog2)
1355         ghqTexInfo.data = 0; //if aspects of current texture and found filtered texture are different, texture must be filtered again.
1356     }
1357   }
1358
1359
1360   // ** handle texture splitting **
1361   if (ghqTexInfo.data)
1362     ;//do nothing
1363   else
1364 #endif
1365     if (splits > 1)
1366     {
1367       cache->scale_y = 0.125f;
1368
1369       int i;
1370       for (i=0; i<splits; i++)
1371       {
1372         int start_dst = i * cache->splitheight * 256;   // start lower
1373         start_dst <<= HIWORD(result);   // 1st time, result is set to 0, but start_dst is 0 anyway so it doesn't matter
1374
1375         int start_src = i * 256;        // start 256 more to the right
1376         start_src = start_src << (rdp.tiles[td].size) >> 1;
1377         if (rdp.tiles[td].size == 3)
1378           start_src >>= 1;
1379
1380         result = load_table[rdp.tiles[td].size][rdp.tiles[td].format]
1381         (wxPtrToUInt(texture)+start_dst, wxPtrToUInt(rdp.tmem)+(rdp.tiles[td].t_mem<<3)+start_src,
1382           texinfo[id].wid_64, texinfo[id].height, texinfo[id].line, real_x, td);
1383
1384         wxUint32 size = HIWORD(result);
1385         // clamp so that it looks somewhat ok when wrapping
1386         if (size == 1)
1387           Clamp16bT ((texture)+start_dst, texinfo[id].height, real_x, cache->splitheight);
1388         else if (size != 2)
1389           Clamp8bT ((texture)+start_dst, texinfo[id].height, real_x, cache->splitheight);
1390         else
1391           Clamp32bT ((texture)+start_dst, texinfo[id].height, real_x, cache->splitheight);
1392       }
1393     }
1394     // ** end texture splitting **
1395     else
1396     {
1397       result = load_table[rdp.tiles[td].size][rdp.tiles[td].format]
1398       (wxPtrToUInt(texture), wxPtrToUInt(rdp.tmem)+(rdp.tiles[td].t_mem<<3),
1399         texinfo[id].wid_64, texinfo[id].height, texinfo[id].line, real_x, td);
1400
1401       wxUint32 size = HIWORD(result);
1402
1403       int min_x, min_y;
1404       if (rdp.tiles[td].mask_s != 0)
1405         min_x = min((int)real_x, 1<<rdp.tiles[td].mask_s);
1406       else
1407         min_x = real_x;
1408       if (rdp.tiles[td].mask_t != 0)
1409         min_y  = min((int)real_y, 1<<rdp.tiles[td].mask_t);
1410       else
1411         min_y = real_y;
1412
1413       // Load using mirroring/clamping
1414       if (min_x > texinfo[id].width)
1415       {
1416         if (size == 1)
1417           Clamp16bS ((texture), texinfo[id].width, min_x, real_x, texinfo[id].height);
1418         else if (size != 2)
1419           Clamp8bS ((texture), texinfo[id].width, min_x, real_x, texinfo[id].height);
1420         else
1421           Clamp32bS ((texture), texinfo[id].width, min_x, real_x, texinfo[id].height);
1422       }
1423
1424       if (texinfo[id].width < (int)real_x)
1425       {
1426         if (rdp.tiles[td].mirror_s)
1427         {
1428           if (size == 1)
1429             Mirror16bS ((texture), rdp.tiles[td].mask_s,
1430             real_x, real_x, texinfo[id].height);
1431           else if (size != 2)
1432             Mirror8bS ((texture), rdp.tiles[td].mask_s,
1433             real_x, real_x, texinfo[id].height);
1434           else
1435             Mirror32bS ((texture), rdp.tiles[td].mask_s,
1436             real_x, real_x, texinfo[id].height);
1437         }
1438         else
1439         {
1440           if (size == 1)
1441             Wrap16bS ((texture), rdp.tiles[td].mask_s,
1442             real_x, real_x, texinfo[id].height);
1443           else if (size != 2)
1444             Wrap8bS ((texture), rdp.tiles[td].mask_s,
1445             real_x, real_x, texinfo[id].height);
1446           else
1447             Wrap32bS ((texture), rdp.tiles[td].mask_s,
1448             real_x, real_x, texinfo[id].height);
1449         }
1450       }
1451
1452       if (min_y > texinfo[id].height)
1453       {
1454         if (size == 1)
1455           Clamp16bT ((texture), texinfo[id].height, real_x, min_y);
1456         else if (size != 2)
1457           Clamp8bT ((texture), texinfo[id].height, real_x, min_y);
1458         else
1459           Clamp32bT ((texture), texinfo[id].height, real_x, min_y);
1460       }
1461
1462       if (texinfo[id].height < (int)real_y)
1463       {
1464         if (rdp.tiles[td].mirror_t)
1465         {
1466           if (size == 1)
1467             Mirror16bT ((texture), rdp.tiles[td].mask_t,
1468             real_y, real_x);
1469           else if (size != 2)
1470             Mirror8bT ((texture), rdp.tiles[td].mask_t,
1471             real_y, real_x);
1472           else
1473             Mirror32bT ((texture), rdp.tiles[td].mask_t,
1474             real_y, real_x);
1475         }
1476         else
1477         {
1478           if (size == 1)
1479             Wrap16bT ((texture), rdp.tiles[td].mask_t,
1480             real_y, real_x);
1481           else if (size != 2)
1482             Wrap8bT ((texture), rdp.tiles[td].mask_t,
1483             real_y, real_x);
1484           else
1485             Wrap32bT ((texture), rdp.tiles[td].mask_t,
1486             real_y, real_x);
1487         }
1488       }
1489     }
1490
1491     if (modifyPalette)
1492     {
1493       memcpy(rdp.pal_8, tmp_pal, 512);
1494     }
1495
1496 #ifdef TEXTURE_FILTER
1497     if (mod && !modifyPalette && !ghqTexInfo.data)
1498 #else
1499     if (mod && !modifyPalette)
1500 #endif
1501     {
1502       // Convert the texture to ARGB 4444
1503       if (LOWORD(result) == GR_TEXFMT_ARGB_1555)
1504       {
1505         TexConv_ARGB1555_ARGB4444 ((texture), (tex2), real_x, real_y);
1506         texture = tex2;
1507       }
1508       else if (LOWORD(result) == GR_TEXFMT_ALPHA_INTENSITY_88)
1509       {
1510         TexConv_AI88_ARGB4444 ((texture), (tex2), real_x, real_y);
1511         texture = tex2;
1512       }
1513       else if (LOWORD(result) == GR_TEXFMT_ALPHA_INTENSITY_44)
1514       {
1515         TexConv_AI44_ARGB4444 ((texture), (tex2), real_x, real_y);
1516         texture = tex2;
1517       }
1518       else if (LOWORD(result) == GR_TEXFMT_ALPHA_8)
1519       {
1520         TexConv_A8_ARGB4444 ((texture), (tex2), real_x, real_y);
1521         texture = tex2;
1522       }
1523       /*else if (LOWORD(result) == GR_TEXFMT_ARGB_4444)
1524       {
1525       memcpy (tex2, texture, (real_x*real_y) << 1);
1526       texture = tex2;
1527       }*/ // we can skip memcpy since "texture" won't be swapped between "tex1" and "tex2" after this.
1528       // Hiroshi Morii <koolsmoky@users.sourceoforge.net>
1529
1530       result = (1 << 16) | GR_TEXFMT_ARGB_4444;
1531
1532       // Now convert the color to the same
1533       modcolor = ((modcolor & 0xF0000000) >> 16) | ((modcolor & 0x00F00000) >> 12) |
1534         ((modcolor & 0x0000F000) >> 8) | ((modcolor & 0x000000F0) >> 4);
1535       modcolor1 = ((modcolor1 & 0xF0000000) >> 16) | ((modcolor1 & 0x00F00000) >> 12) |
1536         ((modcolor1 & 0x0000F000) >> 8) | ((modcolor1 & 0x000000F0) >> 4);
1537       modcolor2 = ((modcolor2 & 0xF0000000) >> 16) | ((modcolor2 & 0x00F00000) >> 12) |
1538         ((modcolor2 & 0x0000F000) >> 8) | ((modcolor2 & 0x000000F0) >> 4);
1539
1540       int size = (real_x * real_y) << 1;
1541
1542       switch (mod)
1543       {
1544       case TMOD_TEX_INTER_COLOR_USING_FACTOR:
1545         mod_tex_inter_color_using_factor ((wxUint16*)texture, size, modcolor, modfactor);
1546         break;
1547       case TMOD_TEX_INTER_COL_USING_COL1:
1548         mod_tex_inter_col_using_col1 ((wxUint16*)texture, size, modcolor, modcolor1);
1549         break;
1550       case TMOD_FULL_COLOR_SUB_TEX:
1551         mod_full_color_sub_tex ((wxUint16*)texture, size, modcolor);
1552         break;
1553       case TMOD_COL_INTER_COL1_USING_TEX:
1554         mod_col_inter_col1_using_tex ((wxUint16*)texture, size, modcolor, modcolor1);
1555         break;
1556       case TMOD_COL_INTER_COL1_USING_TEXA:
1557         mod_col_inter_col1_using_texa ((wxUint16*)texture, size, modcolor, modcolor1);
1558         break;
1559       case TMOD_COL_INTER_COL1_USING_TEXA__MUL_TEX:
1560         mod_col_inter_col1_using_texa__mul_tex ((wxUint16*)texture, size, modcolor, modcolor1);
1561         break;
1562       case TMOD_COL_INTER_TEX_USING_TEXA:
1563         mod_col_inter_tex_using_texa ((wxUint16*)texture, size, modcolor);
1564         break;
1565       case TMOD_COL2_INTER__COL_INTER_COL1_USING_TEX__USING_TEXA:
1566         mod_col2_inter__col_inter_col1_using_tex__using_texa ((wxUint16*)texture, size, modcolor, modcolor1, modcolor2);
1567         break;
1568       case TMOD_TEX_SCALE_FAC_ADD_FAC:
1569         mod_tex_scale_fac_add_fac ((wxUint16*)texture, size, modfactor);
1570         break;
1571       case TMOD_TEX_SUB_COL_MUL_FAC_ADD_TEX:
1572         mod_tex_sub_col_mul_fac_add_tex ((wxUint16*)texture, size, modcolor, modfactor);
1573         break;
1574       case TMOD_TEX_SCALE_COL_ADD_COL:
1575         mod_tex_scale_col_add_col ((wxUint16*)texture, size, modcolor, modcolor1);
1576         break;
1577       case TMOD_TEX_ADD_COL:
1578         mod_tex_add_col ((wxUint16*)texture, size, modcolor);
1579         break;
1580       case TMOD_TEX_SUB_COL:
1581         mod_tex_sub_col ((wxUint16*)texture, size, modcolor);
1582         break;
1583       case TMOD_TEX_SUB_COL_MUL_FAC:
1584         mod_tex_sub_col_mul_fac ((wxUint16*)texture, size, modcolor, modfactor);
1585         break;
1586       case TMOD_COL_INTER_TEX_USING_COL1:
1587         mod_col_inter_tex_using_col1 ((wxUint16*)texture, size, modcolor, modcolor1);
1588         break;
1589       case TMOD_COL_MUL_TEXA_ADD_TEX:
1590         mod_col_mul_texa_add_tex((wxUint16*)texture, size, modcolor);
1591         break;
1592       case TMOD_COL_INTER_TEX_USING_TEX:
1593         mod_col_inter_tex_using_tex ((wxUint16*)texture, size, modcolor);
1594         break;
1595       case TMOD_TEX_INTER_NOISE_USING_COL:
1596         mod_tex_inter_noise_using_col ((wxUint16*)texture, size, modcolor);
1597         break;
1598       case TMOD_TEX_INTER_COL_USING_TEXA:
1599         mod_tex_inter_col_using_texa ((wxUint16*)texture, size, modcolor);
1600         break;
1601       case TMOD_TEX_MUL_COL:
1602         mod_tex_mul_col ((wxUint16*)texture, size, modcolor);
1603         break;
1604       case TMOD_TEX_SCALE_FAC_ADD_COL:
1605         mod_tex_scale_fac_add_col ((wxUint16*)texture, size, modcolor, modfactor);
1606         break;
1607       default:
1608         ;
1609       }
1610     }
1611
1612
1613     cache->t_info.format = LOWORD(result);
1614
1615     cache->realwidth = real_x;
1616     cache->realheight = real_y;
1617     cache->lod = lod;
1618     cache->aspect = aspect;
1619
1620     if (fullscreen)
1621     {
1622 #ifdef TEXTURE_FILTER // Hiroshi Morii <koolsmoky@users.sourceforge.net>
1623       if (settings.ghq_use)
1624       {
1625         if (!ghqTexInfo.data && ghq_dmptex_toggle_key) {
1626           unsigned char *tmpbuf = (unsigned char*)texture;
1627           int tmpwidth = real_x;
1628           if (texinfo[id].splits > 1) {
1629             int dstpixoffset, srcpixoffset;
1630             int shift;
1631             switch (LOWORD(result) & 0x7fff) { // XXX is there a better way of determining the pixel color depth?
1632              case GR_TEXFMT_ARGB_8888:
1633                shift = 3;
1634                break;
1635              case GR_TEXFMT_ALPHA_INTENSITY_44:
1636              case GR_TEXFMT_ALPHA_8:
1637                shift = 0;
1638                break;
1639              default:
1640                shift = 1;
1641             }
1642             tmpwidth = texinfo[id].real_image_width;
1643             tmpbuf = (unsigned char*)malloc((256*256)<<3); // XXX performance overhead
1644             for (int i = 0; i < cache->splitheight; i++) {
1645               dstpixoffset = texinfo[id].real_image_width * i;
1646               srcpixoffset = 256 * i;
1647               for (int k = 0; k < texinfo[id].splits; k++) {
1648                 memcpy(tmpbuf + (dstpixoffset << shift), texture + (srcpixoffset << shift), (256 << shift));
1649                 dstpixoffset += 256;
1650                 srcpixoffset += (256 * cache->splitheight);
1651               }
1652             }
1653           }
1654           ext_ghq_dmptx(tmpbuf, (int)texinfo[id].real_image_width, (int)texinfo[id].real_image_height, (int)tmpwidth, (unsigned short)LOWORD(result), (unsigned short)((cache->format << 8) | (cache->size)), cache->ricecrc);
1655           if (tmpbuf != texture && tmpbuf) {
1656             free(tmpbuf);
1657           }
1658         }
1659
1660         if (!ghqTexInfo.data)
1661           if (!settings.ghq_enht_nobg || !rdp.texrecting || (texinfo[id].splits == 1 && texinfo[id].width <= 256))
1662             ext_ghq_txfilter((unsigned char*)texture, (int)real_x, (int)real_y, LOWORD(result), (uint64)g64_crc, &ghqTexInfo);
1663
1664         if (ghqTexInfo.data)
1665         {
1666           if (ghqTexInfo.aspectRatioLog2 < GR_ASPECT_LOG2_1x8 ||
1667             ghqTexInfo.aspectRatioLog2 > GR_ASPECT_LOG2_8x1 ||
1668             ghqTexInfo.largeLodLog2 > GR_LOD_LOG2_2048 ||
1669             ghqTexInfo.largeLodLog2 < GR_LOD_LOG2_1)
1670           {
1671             /* invalid dimensions */
1672           }
1673           else
1674           {
1675             texture = (wxUint8 *)ghqTexInfo.data;
1676             lod = ghqTexInfo.largeLodLog2;
1677             int splits = cache->splits;
1678             if (ghqTexInfo.is_hires_tex)
1679             {
1680               if (ghqTexInfo.tiles/*ghqTexInfo.untiled_width > max_tex_size*/)
1681               {
1682                 cache->scale = 1.0f;
1683                 cache->c_off = 0.5f;
1684                 cache->splits = ghqTexInfo.tiles;//((hirestex.width-1)>>8)+1;
1685                 cache->splitheight = ghqTexInfo.untiled_height;
1686                 cache->scale_x = 1.0f;
1687                 cache->scale_y = float(ghqTexInfo.untiled_height*ghqTexInfo.tiles)/float(ghqTexInfo.width);//*sy;
1688                 if (splits == 1)
1689                 {
1690                   int shift;
1691                   for (shift=9; (1<<shift) < ghqTexInfo.untiled_width; shift++);
1692                   float mult = float(1 << shift >> 8);
1693                   cache->c_scl_x *= mult;
1694                   cache->c_scl_y *= mult;
1695                 }
1696                 else
1697                 {
1698                   int tile_width = rdp.tiles[td].width;
1699                   if (rdp.timg.set_by == 1)
1700                     tile_width = rdp.load_info[rdp.tiles[td].t_mem].tex_width;
1701                   float mult = float(ghqTexInfo.untiled_width/tile_width);
1702                   cache->c_scl_x *= mult;
1703                   cache->c_scl_y *= mult;
1704                 }
1705               }
1706               else
1707               {
1708                 cache->scale = 256.0f / float(1<<lod);
1709                 cache->c_off = cache->scale * 0.5f;
1710                 cache->splits = 1;
1711                 if (aspect != ghqTexInfo.aspectRatioLog2)
1712                 {
1713                   float mscale = float(1<<abs(aspect - ghqTexInfo.aspectRatioLog2));
1714                   if (abs(aspect) > abs(ghqTexInfo.aspectRatioLog2))
1715                   {
1716                     cache->c_scl_y *= mscale;
1717                     cache->c_scl_x *= mscale;
1718                   }
1719                   /*
1720                   else
1721                   {
1722                   if (rdp.tiles[td].mirror_s && sup_mirroring)
1723                   cache->f_mirror_s = TRUE;
1724                   if (rdp.tiles[td].mirror_t && sup_mirroring)
1725                   cache->f_mirror_t = TRUE;
1726                   //cache->c_scl_y /= mscale;
1727                   //cache->c_scl_x /= mscale;
1728                   }
1729                   */
1730                   if (ghqTexInfo.aspectRatioLog2 >= 0)
1731                   {
1732                     cache->scale_x = 1.0f;
1733                     cache->scale_y = 1.0f/float(1<<ghqTexInfo.aspectRatioLog2);
1734                   }
1735                   else
1736                   {
1737                     cache->scale_y = 1.0f;
1738                     cache->scale_x = 1.0f/float(1<<(-ghqTexInfo.aspectRatioLog2));
1739                   }
1740                 }
1741                 else if (splits > 1)
1742                 {
1743                   cache->c_scl_x /= splits;
1744                   cache->c_scl_y /= splits;
1745                 }
1746               }
1747               if (voodoo.sup_mirroring)
1748               {
1749                 if (rdp.tiles[td].mirror_s && texinfo[id].tile_width == 2*texinfo[id].width)
1750                   cache->f_mirror_s = TRUE;
1751                 else if (texinfo[id].tile_width >= 2*texinfo[id].width)
1752                   cache->f_wrap_s = TRUE;
1753                 if (rdp.tiles[td].mirror_t && texinfo[id].tile_height == 2*texinfo[id].height)
1754                   cache->f_mirror_t = TRUE;
1755                 else if (texinfo[id].tile_height >= 2*texinfo[id].height)
1756                   cache->f_wrap_t = TRUE;
1757                 if (cache->f_mirror_s && cache->f_mirror_t)
1758                 {
1759                   cache->c_scl_x *= 2.0f;
1760                   cache->c_scl_y *= 2.0f;
1761                 }
1762               }
1763               aspect = ghqTexInfo.aspectRatioLog2;
1764               cache->lod = lod;
1765               cache->aspect = aspect;
1766             }
1767             else
1768             {
1769               //cache->scale = 256.0f / float(1<<lod);
1770               cache->c_off = 128.0f / float(1<<lod);
1771             }
1772             real_x = ghqTexInfo.width;
1773             real_y = ghqTexInfo.height;
1774             result = (1 << 16) | ghqTexInfo.format;
1775             cache->t_info.format = ghqTexInfo.format;
1776             cache->realwidth = real_x;
1777             cache->realheight = real_y;
1778           }
1779         }
1780       }
1781 #endif
1782
1783       // Load the texture into texture memory
1784       GrTexInfo *t_info = &cache->t_info;
1785       t_info->data = texture;
1786       t_info->smallLodLog2 = lod;
1787       t_info->largeLodLog2 = lod;
1788       t_info->aspectRatioLog2 = aspect;
1789
1790       wxUint32 texture_size = grTexTextureMemRequired (GR_MIPMAPLEVELMASK_BOTH, t_info);
1791
1792       // Check for 2mb boundary
1793       // Hiroshi Morii <koolsmoky@users.sourceforge.net> required only for V1,Rush, and V2
1794       if (voodoo.has_2mb_tex_boundary &&
1795         (voodoo.tmem_ptr[tmu] < TEXMEM_2MB_EDGE) && (voodoo.tmem_ptr[tmu]+texture_size > TEXMEM_2MB_EDGE))
1796       {
1797         voodoo.tmem_ptr[tmu] = TEXMEM_2MB_EDGE;
1798         cache->tmem_addr = voodoo.tmem_ptr[tmu];
1799       }
1800
1801       // Check for end of memory (too many textures to fit, clear cache)
1802       if (voodoo.tmem_ptr[tmu]+texture_size >= voodoo.tex_max_addr[tmu])
1803       {
1804         LRDP("Cache size reached, clearing...\n");
1805         ClearCache ();
1806
1807         if (id == 1 && rdp.tex == 3)
1808           LoadTex (0, rdp.t0);
1809
1810         LoadTex (id, tmu);
1811         return;
1812         // DON'T CONTINUE (already done)
1813       }
1814
1815       wxUint32 tex_addr = GetTexAddr(tmu, texture_size);
1816       grTexDownloadMipMap (tmu,
1817         tex_addr,
1818         GR_MIPMAPLEVELMASK_BOTH,
1819         t_info);
1820
1821       grTexSource (tmu,
1822         tex_addr,
1823         GR_MIPMAPLEVELMASK_BOTH,
1824         t_info);
1825     }
1826
1827     LRDP(" | | +- LoadTex end\n");
1828 }