| 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 | } |