Path: blob/master/libmupen64plus/mupen64plus-video-glide64mk2/src/Glide64/TexCache.cpp
2 views
/*1* Glide64 - Glide video plugin for Nintendo 64 emulators.2* Copyright (c) 2002 Dave20013* Copyright (c) 2003-2009 Sergey 'Gonetz' Lipski4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*/1920//****************************************************************21//22// Glide64 - Glide Plugin for Nintendo 64 emulators23// Project started on December 29th, 200124//25// Authors:26// Dave2001, original author, founded the project in 2001, left it in 200227// Gugaman, joined the project in 2002, left it in 200228// Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 200229// Hiroshi 'KoolSmoky' Morii, joined the project in 200730//31//****************************************************************32//33// To modify Glide64:34// * 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.35// * 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.36//37//****************************************************************3839#include <SDL.h>40#include "Gfx_1.3.h"41#include "TexCache.h"42#include "Combine.h"43#include "Util.h"4445void LoadTex (int id, int tmu);4647wxUint8 tex1[1024*1024*4]; // temporary texture48wxUint8 tex2[1024*1024*4];49wxUint8 *texture;50wxUint8 *texture_buffer = tex1;5152#include "TexLoad.h" // texture loading functions, ONLY INCLUDE IN THIS FILE!!!53#include "MiClWr32b.h"54#include "MiClWr16b.h" // Mirror/Clamp/Wrap functions, ONLY INCLUDE IN THIS FILE!!!55#include "MiClWr8b.h" // Mirror/Clamp/Wrap functions, ONLY INCLUDE IN THIS FILE!!!56#include "TexConv.h" // texture conversions, ONLY INCLUDE IN THIS FILE!!!57#include "TexMod.h"58#include "TexModCI.h"59#include "CRC.h"60#ifdef TEXTURE_FILTER // Hiroshi Morii <[email protected]>61extern int ghq_dmptex_toggle_key;62#endif6364typedef struct TEXINFO_t {65int real_image_width, real_image_height; // FOR ALIGNMENT PURPOSES ONLY!!!66int tile_width, tile_height;67int mask_width, mask_height;68int width, height;69int wid_64, line;70wxUint32 crc;71wxUint32 flags;72int splits, splitheight;73#ifdef TEXTURE_FILTER74uint64 ricecrc;75#endif76} TEXINFO;7778TEXINFO texinfo[2];79int tex_found[2][MAX_TMU];8081#ifdef TEXTURE_FILTER82typedef struct HIRESTEX_t {83int width, height;84wxUint16 format;85wxUint8 *data;86} HIRESTEX;87#endif8889//****************************************************************90// List functions9192typedef struct NODE_t {93wxUint32 crc;94wxUIntPtr data;95int tmu;96int number;97NODE_t *pNext;98} NODE;99100NODE *cachelut[65536];101102void AddToList (NODE **list, wxUint32 crc, wxUIntPtr data, int tmu, int number)103{104NODE *node = new NODE;105node->crc = crc;106node->data = data;107node->tmu = tmu;108node->number = number;109node->pNext = *list;110*list = node;111rdp.n_cached[tmu] ++;112if (voodoo.tex_UMA)113rdp.n_cached[tmu^1] = rdp.n_cached[tmu];114}115116void DeleteList (NODE **list)117{118while (*list)119{120NODE *next = (*list)->pNext;121delete (*list);122*list = next;123}124}125126void TexCacheInit ()127{128for (int i=0; i<65536; i++)129{130cachelut[i] = NULL;131}132}133134//****************************************************************135// ClearCache - clear the texture cache for BOTH tmus136137void ClearCache ()138{139voodoo.tmem_ptr[0] = offset_textures;140rdp.n_cached[0] = 0;141voodoo.tmem_ptr[1] = voodoo.tex_UMA ? offset_textures : offset_texbuf1;142rdp.n_cached[1] = 0;143144for (int i=0; i<65536; i++)145{146DeleteList (&cachelut[i]);147}148}149150//****************************************************************151uint32_t textureCRC(uint8_t *addr, int width, int height, int line)152{153uint32_t crc = 0;154uint32_t *pixelpos;155unsigned int i;156uint64_t twopixel_crc;157158pixelpos = (uint32_t*)addr;159for (; height; height--) {160for (i = width; i; --i) {161twopixel_crc = i * (uint64_t)(pixelpos[1] + pixelpos[0] + crc);162crc = (uint32_t) ((twopixel_crc >> 32) + twopixel_crc);163pixelpos += 2;164}165crc = ((unsigned int)height * (uint64_t)crc >> 32) + height * crc;166pixelpos = (uint32_t *)((char *)pixelpos + line);167}168169return crc;170}171// GetTexInfo - gets information for either t0 or t1, checks if in cache & fills tex_found172173void GetTexInfo (int id, int tile)174{175FRDP (" | |-+ GetTexInfo (id: %d, tile: %d)\n", id, tile);176177// this is the NEW cache searching, searches only textures with similar crc's178int t;179for (t=0; t<MAX_TMU; t++)180tex_found[id][t] = -1;181182TBUFF_COLOR_IMAGE * pFBTex = 0;183if (rdp.aTBuffTex[0] && rdp.aTBuffTex[0]->tile == id)184pFBTex = rdp.aTBuffTex[0];185else if (rdp.aTBuffTex[1] && rdp.aTBuffTex[1]->tile == id)186pFBTex = rdp.aTBuffTex[1];187if (pFBTex && pFBTex->cache)188return;189190TEXINFO *info = &texinfo[id];191192int tile_width, tile_height;193int mask_width, mask_height;194int width, height;195int wid_64, line, bpl;196197// Get width and height198tile_width = rdp.tiles[tile].lr_s - rdp.tiles[tile].ul_s + 1;199tile_height = rdp.tiles[tile].lr_t - rdp.tiles[tile].ul_t + 1;200201mask_width = (rdp.tiles[tile].mask_s==0)?(tile_width):(1 << rdp.tiles[tile].mask_s);202mask_height = (rdp.tiles[tile].mask_t==0)?(tile_height):(1 << rdp.tiles[tile].mask_t);203204if (settings.alt_tex_size)205{206// ** ALTERNATE TEXTURE SIZE METHOD **207// Helps speed in some games that loaded weird-sized textures, but could break other208// textures.209210// Get the width/height to load211if ((rdp.tiles[tile].clamp_s && tile_width <= 256) || (mask_width > 256))212{213// loading width214width = min(mask_width, tile_width);215// actual width216rdp.tiles[tile].width = tile_width;217}218else219{220// wrap all the way221width = min(mask_width, tile_width); // changed from mask_width only222rdp.tiles[tile].width = width;223}224225if ((rdp.tiles[tile].clamp_t && tile_height <= 256) || (mask_height > 256))226{227// loading height228height = min(mask_height, tile_height);229// actual height230rdp.tiles[tile].height = tile_height;231}232else233{234// wrap all the way235height = min(mask_height, tile_height);236rdp.tiles[tile].height = height;237}238}239else240{241// ** NORMAL TEXTURE SIZE METHOD **242// This is the 'correct' method for determining texture size, but may cause certain243// textures to load too large & make the whole game go slow.244245if (mask_width > 256 && mask_height > 256)246{247mask_width = tile_width;248mask_height = tile_height;249}250251// Get the width/height to load252if ((rdp.tiles[tile].clamp_s && tile_width <= 256) )//|| (mask_width > 256))253{254// loading width255width = min(mask_width, tile_width);256// actual width257rdp.tiles[tile].width = tile_width;258}259else260{261// wrap all the way262width = mask_width;263rdp.tiles[tile].width = mask_width;264}265266if ((rdp.tiles[tile].clamp_t && tile_height <= 256) || (mask_height > 256))267{268// loading height269height = min(mask_height, tile_height);270// actual height271rdp.tiles[tile].height = tile_height;272}273else274{275// wrap all the way276height = mask_height;277rdp.tiles[tile].height = mask_height;278}279}280281// without any large texture fixing-up; for alignment282int real_image_width = rdp.tiles[tile].width;283int real_image_height = rdp.tiles[tile].height;284int crc_height = height;285if (rdp.timg.set_by == 1)286crc_height = tile_height;287288bpl = width << rdp.tiles[tile].size >> 1;289290// ** COMMENT THIS TO DISABLE LARGE TEXTURES291#ifdef LARGE_TEXTURE_HANDLING292if (!voodoo.sup_large_tex && width > 256)293{294info->splits = ((width-1)>>8)+1;295info->splitheight = rdp.tiles[tile].height;296rdp.tiles[tile].height *= info->splits;297rdp.tiles[tile].width = 256;298width = 256;299}300else301#endif302// **303{304info->splits = 1;305}306307LRDP(" | | |-+ Texture approved:\n");308FRDP (" | | | |- tmem: %08lx\n", rdp.tiles[tile].t_mem);309FRDP (" | | | |- load width: %d\n", width);310FRDP (" | | | |- load height: %d\n", height);311FRDP (" | | | |- actual width: %d\n", rdp.tiles[tile].width);312FRDP (" | | | |- actual height: %d\n", rdp.tiles[tile].height);313FRDP (" | | | |- size: %d\n", rdp.tiles[tile].size);314FRDP (" | | | +- format: %d\n", rdp.tiles[tile].format);315LRDP(" | | |- Calculating CRC... ");316317// ** CRC CHECK318319wid_64 = width << (rdp.tiles[tile].size) >> 1;320if (rdp.tiles[tile].size == 3)321{322if (wid_64 & 15) wid_64 += 16;323wid_64 &= 0xFFFFFFF0;324}325else326{327if (wid_64 & 7) wid_64 += 8; // round up328}329wid_64 = wid_64>>3;330331// Texture too big for tmem & needs to wrap? (trees in mm)332if (rdp.tiles[tile].t_mem + min(height, tile_height) * (rdp.tiles[tile].line<<3) > 4096)333{334LRDP("TEXTURE WRAPS TMEM!!! ");335336// calculate the y value that intersects at 4096 bytes337int y = (4096 - rdp.tiles[tile].t_mem) / (rdp.tiles[tile].line<<3);338339rdp.tiles[tile].clamp_t = 0;340rdp.tiles[tile].lr_t = rdp.tiles[tile].ul_t + y - 1;341342// calc mask343int shift;344for (shift=0; (1<<shift)<y; shift++);345rdp.tiles[tile].mask_t = shift;346347// restart the function348LRDP("restarting...\n");349GetTexInfo (id, tile);350return;351}352353line = rdp.tiles[tile].line;354if (rdp.tiles[tile].size == 3)355line <<= 1;356wxUint32 crc = 0;357if (settings.fast_crc)358{359line = (line - wid_64) << 3;360if (wid_64 < 1) wid_64 = 1;361uint8_t * addr = (((uint8_t*)rdp.tmem) + (rdp.tiles[tile].t_mem<<3));362if (crc_height > 0) // Check the CRC363{364if (rdp.tiles[tile].size < 3)365crc = textureCRC(addr, wid_64, crc_height, line);366else //32b texture367{368int line_2 = line >> 1;369int wid_64_2 = max(1, wid_64 >> 1);370crc = textureCRC(addr, wid_64_2, crc_height, line_2);371crc += textureCRC(addr+0x800, wid_64_2, crc_height, line_2);372}373}374}375else376{377crc = 0xFFFFFFFF;378wxUIntPtr addr = wxPtrToUInt(rdp.tmem) + (rdp.tiles[tile].t_mem<<3);379wxUint32 line2 = max(line,1);380if (rdp.tiles[tile].size < 3)381{382line2 <<= 3;383for (int y = 0; y < crc_height; y++)384{385crc = CRC32( crc, reinterpret_cast<void*>(addr), bpl );386addr += line2;387}388}389else //32b texture390{391line2 <<= 2;392//32b texel is split in two 16b parts, so bpl/2 and line/2.393//Min value for bpl is 4, because when width==1 first 2 bytes of tmem will not be used.394bpl = max(bpl >> 1, 4);395for (int y = 0; y < crc_height; y++)396{397crc = CRC32( crc, reinterpret_cast<void*>(addr), bpl);398crc = CRC32( crc, reinterpret_cast<void*>(addr + 0x800), bpl);399addr += line2;400}401}402line = (line - wid_64) << 3;403if (wid_64 < 1) wid_64 = 1;404}405if ((rdp.tiles[tile].size < 2) && (rdp.tlut_mode || rdp.tiles[tile].format == 2))406{407if (rdp.tiles[tile].size == 0)408crc += rdp.pal_8_crc[rdp.tiles[tile].palette];409else410crc += rdp.pal_256_crc;411}412413FRDP ("Done. CRC is: %08lx.\n", crc);414415wxUint32 flags = (rdp.tiles[tile].clamp_s << 23) | (rdp.tiles[tile].mirror_s << 22) |416(rdp.tiles[tile].mask_s << 18) | (rdp.tiles[tile].clamp_t << 17) |417(rdp.tiles[tile].mirror_t << 16) | (rdp.tiles[tile].mask_t << 12);418419info->real_image_width = real_image_width;420info->real_image_height = real_image_height;421info->tile_width = tile_width;422info->tile_height = tile_height;423info->mask_width = mask_width;424info->mask_height = mask_height;425info->width = width;426info->height = height;427info->wid_64 = wid_64;428info->line = line;429info->crc = crc;430info->flags = flags;431432// Search the texture cache for this texture433LRDP(" | | |-+ Checking cache...\n");434435CACHE_LUT *cache;436437if (rdp.noise == RDP::noise_texture)438return;439440wxUint32 mod, modcolor, modcolor1, modcolor2, modfactor;441if (id == 0)442{443mod = cmb.mod_0;444modcolor = cmb.modcolor_0;445modcolor1 = cmb.modcolor1_0;446modcolor2 = cmb.modcolor2_0;447modfactor = cmb.modfactor_0;448}449else450{451mod = cmb.mod_1;452modcolor = cmb.modcolor_1;453modcolor1 = cmb.modcolor1_1;454modcolor2 = cmb.modcolor2_1;455modfactor = cmb.modfactor_1;456}457458NODE *node = cachelut[crc>>16];459wxUint32 mod_mask = (rdp.tiles[tile].format == 2)?0xFFFFFFFF:0xF0F0F0F0;460while (node)461{462if (node->crc == crc)463{464cache = (CACHE_LUT*)node->data;465if (/*tex_found[id][node->tmu] == -1 &&466rdp.tiles[tile].palette == cache->palette &&467rdp.tiles[tile].format == cache->format &&468rdp.tiles[tile].size == cache->size &&*/469rdp.tiles[tile].width == cache->width &&470rdp.tiles[tile].height == cache->height &&471flags == cache->flags)472{473if (!(mod+cache->mod) || (cache->mod == mod &&474(cache->mod_color&mod_mask) == (modcolor&mod_mask) &&475(cache->mod_color1&mod_mask) == (modcolor1&mod_mask) &&476(cache->mod_color2&mod_mask) == (modcolor2&mod_mask) &&477abs((int)(cache->mod_factor - modfactor)) < 8))478{479FRDP (" | | | |- Texture found in cache (tmu=%d).\n", node->tmu);480tex_found[id][node->tmu] = node->number;481if (voodoo.tex_UMA)482{483tex_found[id][node->tmu^1] = node->number;484return;485}486}487}488}489node = node->pNext;490}491492LRDP(" | | | +- Done.\n | | +- GetTexInfo end\n");493}494495//****************************************************************496// ChooseBestTmu - chooses the best TMU to load to (the one with the most memory)497498int ChooseBestTmu (int tmu1, int tmu2)499{500if (!fullscreen) return tmu1;501if (voodoo.tex_UMA) return 0;502503if (tmu1 >= voodoo.num_tmu) return tmu2;504if (tmu2 >= voodoo.num_tmu) return tmu1;505506if (voodoo.tex_max_addr[tmu1]-voodoo.tmem_ptr[tmu1] >507voodoo.tex_max_addr[tmu2]-voodoo.tmem_ptr[tmu2])508return tmu1;509else510return tmu2;511}512513//****************************************************************514// SelectTBuffTex - select texture from texture buffer515static void SelectTBuffTex(TBUFF_COLOR_IMAGE * pTBuffTex)516{517FRDP ("SelectTBuffTex: tex: %d, tmu: %d, tile: %d\n", rdp.tex, pTBuffTex->tmu, pTBuffTex->tile);518grTexSource(pTBuffTex->tile, pTBuffTex->tex_addr, GR_MIPMAPLEVELMASK_BOTH, &(pTBuffTex->info) );519}520521//****************************************************************522// TexCache - does texture loading after combiner is set523int SwapTextureBuffer();524void TexCache ()525{526LRDP(" |-+ TexCache called\n");527528#ifdef TEXTURE_FILTER /* Hiroshi Morii <[email protected]> */ // POSTNAPALM529if (settings.ghq_use && settings.ghq_hirs_dump) {530/* Force reload hi-res textures. Useful for texture artists */531if (CheckKeyPressed(G64_VK_R, 0x0001)) {532if (ext_ghq_reloadhirestex()) ClearCache();533}534/* Turn on texture dump */535else if (CheckKeyPressed(G64_VK_D, 0x0001)) {536extern void DisplayLoadProgress(const wchar_t *format, ...);537ghq_dmptex_toggle_key = !ghq_dmptex_toggle_key;538if (ghq_dmptex_toggle_key) {539DisplayLoadProgress(L"Texture dump - ON\n");540ClearCache();541SDL_Delay(1000);542} else {543DisplayLoadProgress(L"Texture dump - OFF\n");544SDL_Delay(1000);545}546}547}548#endif549550if (rdp.tex & 1)551GetTexInfo (0, rdp.cur_tile);552if (rdp.tex & 2)553GetTexInfo (1, rdp.cur_tile+1);554555TBUFF_COLOR_IMAGE * aTBuff[2] = {0, 0};556if (rdp.aTBuffTex[0])557aTBuff[rdp.aTBuffTex[0]->tile] = rdp.aTBuffTex[0];558if (rdp.aTBuffTex[1])559aTBuff[rdp.aTBuffTex[1]->tile] = rdp.aTBuffTex[1];560561#define TMUMODE_NORMAL 0562#define TMUMODE_PASSTHRU 1563#define TMUMODE_NONE 2564565int tmu_0, tmu_1;566int tmu_0_mode=0, tmu_1_mode=0;567568// Select the best TMUs to use (removed 3 tmu support, unnecessary)569if (rdp.tex == 3) // T0 and T1570{571tmu_0 = 0;572tmu_1 = 1;573}574else if (rdp.tex == 2) // T1575{576if (tex_found[1][0] != -1) // T1 found in tmu 0577tmu_1 = 0;578else if (tex_found[1][1] != -1) // T1 found in tmu 1579tmu_1 = 1;580else // T1 not found581tmu_1 = ChooseBestTmu (0, 1);582583tmu_0 = !tmu_1;584tmu_0_mode = (tmu_0==1)?TMUMODE_NONE:TMUMODE_PASSTHRU;585}586else if (rdp.tex == 1) // T0587{588if (tex_found[0][0] != -1) // T0 found in tmu 0589tmu_0 = 0;590else if (tex_found[0][1] != -1) // T0 found in tmu 1591tmu_0 = 1;592else // T0 not found593tmu_0 = ChooseBestTmu (0, 1);594595tmu_1 = !tmu_0;596tmu_1_mode = (tmu_1==1)?TMUMODE_NONE:TMUMODE_PASSTHRU;597}598else // no texture599{600tmu_0 = 0;601tmu_0_mode = TMUMODE_NONE;602tmu_1 = 0;603tmu_1_mode = TMUMODE_NONE;604}605606FRDP (" | |-+ Modes set:\n | | |- tmu_0 = %d\n | | |- tmu_1 = %d\n",607tmu_0, tmu_1);608FRDP (" | | |- tmu_0_mode = %d\n | | |- tmu_1_mode = %d\n",609tmu_0_mode, tmu_1_mode);610611if (tmu_0_mode == TMUMODE_PASSTHRU) {612cmb.tmu0_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_SCALE_OTHER;613cmb.tmu0_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_ONE;614if (cmb.tex_cmb_ext_use)615{616cmb.t0c_ext_a = GR_CMBX_OTHER_TEXTURE_RGB;617cmb.t0c_ext_a_mode = GR_FUNC_MODE_X;618cmb.t0c_ext_b = GR_CMBX_LOCAL_TEXTURE_RGB;619cmb.t0c_ext_b_mode = GR_FUNC_MODE_ZERO;620cmb.t0c_ext_c = GR_CMBX_ZERO;621cmb.t0c_ext_c_invert = 1;622cmb.t0c_ext_d = GR_CMBX_ZERO;623cmb.t0c_ext_d_invert = 0;624cmb.t0a_ext_a = GR_CMBX_OTHER_TEXTURE_ALPHA;625cmb.t0a_ext_a_mode = GR_FUNC_MODE_X;626cmb.t0a_ext_b = GR_CMBX_LOCAL_TEXTURE_ALPHA;627cmb.t0a_ext_b_mode = GR_FUNC_MODE_ZERO;628cmb.t0a_ext_c = GR_CMBX_ZERO;629cmb.t0a_ext_c_invert = 1;630cmb.t0a_ext_d = GR_CMBX_ZERO;631cmb.t0a_ext_d_invert = 0;632}633}634else if (tmu_0_mode == TMUMODE_NONE) {635cmb.tmu0_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_NONE;636cmb.tmu0_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_NONE;637if (cmb.tex_cmb_ext_use)638{639cmb.t0c_ext_a = GR_CMBX_LOCAL_TEXTURE_RGB;640cmb.t0c_ext_a_mode = GR_FUNC_MODE_ZERO;641cmb.t0c_ext_b = GR_CMBX_LOCAL_TEXTURE_RGB;642cmb.t0c_ext_b_mode = GR_FUNC_MODE_ZERO;643cmb.t0c_ext_c = GR_CMBX_ZERO;644cmb.t0c_ext_c_invert = 0;645cmb.t0c_ext_d = GR_CMBX_ZERO;646cmb.t0c_ext_d_invert = 0;647cmb.t0a_ext_a = GR_CMBX_LOCAL_TEXTURE_ALPHA;648cmb.t0a_ext_a_mode = GR_FUNC_MODE_ZERO;649cmb.t0a_ext_b = GR_CMBX_LOCAL_TEXTURE_ALPHA;650cmb.t0a_ext_b_mode = GR_FUNC_MODE_ZERO;651cmb.t0a_ext_c = GR_CMBX_ZERO;652cmb.t0a_ext_c_invert = 0;653cmb.t0a_ext_d = GR_CMBX_ZERO;654cmb.t0a_ext_d_invert = 0;655}656}657if (tmu_1_mode == TMUMODE_PASSTHRU) {658cmb.tmu1_func = cmb.tmu1_a_func = GR_COMBINE_FUNCTION_SCALE_OTHER;659cmb.tmu1_fac = cmb.tmu1_a_fac = GR_COMBINE_FACTOR_ONE;660if (cmb.tex_cmb_ext_use)661{662cmb.t1c_ext_a = GR_CMBX_OTHER_TEXTURE_RGB;663cmb.t1c_ext_a_mode = GR_FUNC_MODE_X;664cmb.t1c_ext_b = GR_CMBX_LOCAL_TEXTURE_RGB;665cmb.t1c_ext_b_mode = GR_FUNC_MODE_ZERO;666cmb.t1c_ext_c = GR_CMBX_ZERO;667cmb.t1c_ext_c_invert = 1;668cmb.t1c_ext_d = GR_CMBX_ZERO;669cmb.t1c_ext_d_invert = 0;670cmb.t1a_ext_a = GR_CMBX_OTHER_TEXTURE_ALPHA;671cmb.t1a_ext_a_mode = GR_FUNC_MODE_X;672cmb.t1a_ext_b = GR_CMBX_LOCAL_TEXTURE_ALPHA;673cmb.t1a_ext_b_mode = GR_FUNC_MODE_ZERO;674cmb.t1a_ext_c = GR_CMBX_ZERO;675cmb.t1a_ext_c_invert = 1;676cmb.t1a_ext_d = GR_CMBX_ZERO;677cmb.t1a_ext_d_invert = 0;678}679}680else if (tmu_1_mode == TMUMODE_NONE) {681cmb.tmu1_func = cmb.tmu1_a_func = GR_COMBINE_FUNCTION_NONE;682cmb.tmu1_fac = cmb.tmu1_a_fac = GR_COMBINE_FACTOR_NONE;683if (cmb.tex_cmb_ext_use)684{685cmb.t1c_ext_a = GR_CMBX_LOCAL_TEXTURE_RGB;686cmb.t1c_ext_a_mode = GR_FUNC_MODE_ZERO;687cmb.t1c_ext_b = GR_CMBX_LOCAL_TEXTURE_RGB;688cmb.t1c_ext_b_mode = GR_FUNC_MODE_ZERO;689cmb.t1c_ext_c = GR_CMBX_ZERO;690cmb.t1c_ext_c_invert = 0;691cmb.t1c_ext_d = GR_CMBX_ZERO;692cmb.t1c_ext_d_invert = 0;693cmb.t1a_ext_a = GR_CMBX_LOCAL_TEXTURE_ALPHA;694cmb.t1a_ext_a_mode = GR_FUNC_MODE_ZERO;695cmb.t1a_ext_b = GR_CMBX_LOCAL_TEXTURE_ALPHA;696cmb.t1a_ext_b_mode = GR_FUNC_MODE_ZERO;697cmb.t1a_ext_c = GR_CMBX_ZERO;698cmb.t1a_ext_c_invert = 0;699cmb.t1a_ext_d = GR_CMBX_ZERO;700cmb.t1a_ext_d_invert = 0;701}702}703704// little change to make single-tmu cards look better, use first texture no matter what705706if (voodoo.num_tmu == 1)707{708if (rdp.best_tex == 0)709{710cmb.tmu0_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_LOCAL;711cmb.tmu0_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_NONE;712tmu_0 = 0;713tmu_1 = 1;714}715else716{717cmb.tmu1_func = cmb.tmu1_a_func = GR_COMBINE_FUNCTION_LOCAL;718cmb.tmu1_fac = cmb.tmu1_a_fac = GR_COMBINE_FACTOR_NONE;719tmu_1 = 0;720tmu_0 = 1;721}722}723724725rdp.t0 = tmu_0;726rdp.t1 = tmu_1;727728// SET the combiner729if (fullscreen)730{731if (rdp.allow_combine)732{733// Now actually combine734if (cmb.cmb_ext_use)735{736LRDP(" | | | |- combiner extension\n");737if (!(cmb.cmb_ext_use & COMBINE_EXT_COLOR))738ColorCombinerToExtension ();739if (!(cmb.cmb_ext_use & COMBINE_EXT_ALPHA))740AlphaCombinerToExtension ();741cmb.grColorCombineExt(cmb.c_ext_a, cmb.c_ext_a_mode,742cmb.c_ext_b, cmb.c_ext_b_mode,743cmb.c_ext_c, cmb.c_ext_c_invert,744cmb.c_ext_d, cmb.c_ext_d_invert, 0, 0);745cmb.grAlphaCombineExt(cmb.a_ext_a, cmb.a_ext_a_mode,746cmb.a_ext_b, cmb.a_ext_b_mode,747cmb.a_ext_c, cmb.a_ext_c_invert,748cmb.a_ext_d, cmb.a_ext_d_invert, 0, 0);749}750else751{752grColorCombine (cmb.c_fnc, cmb.c_fac, cmb.c_loc, cmb.c_oth, FXFALSE);753grAlphaCombine (cmb.a_fnc, cmb.a_fac, cmb.a_loc, cmb.a_oth, FXFALSE);754}755grConstantColorValue (cmb.ccolor);756grAlphaBlendFunction (cmb.abf1, cmb.abf2, GR_BLEND_ZERO, GR_BLEND_ZERO);757if (!rdp.tex) //nothing more to do758return;759}760761if (tmu_1 < voodoo.num_tmu)762{763if (cmb.tex_cmb_ext_use)764{765LRDP(" | | | |- combiner extension tmu1\n");766if (!(cmb.tex_cmb_ext_use & TEX_COMBINE_EXT_COLOR))767TexColorCombinerToExtension (GR_TMU1);768if (!(cmb.tex_cmb_ext_use & TEX_COMBINE_EXT_ALPHA))769TexAlphaCombinerToExtension (GR_TMU1);770cmb.grTexColorCombineExt(tmu_1, cmb.t1c_ext_a, cmb.t1c_ext_a_mode,771cmb.t1c_ext_b, cmb.t1c_ext_b_mode,772cmb.t1c_ext_c, cmb.t1c_ext_c_invert,773cmb.t1c_ext_d, cmb.t1c_ext_d_invert, 0, 0);774cmb.grTexAlphaCombineExt(tmu_1, cmb.t1a_ext_a, cmb.t1a_ext_a_mode,775cmb.t1a_ext_b, cmb.t1a_ext_b_mode,776cmb.t1a_ext_c, cmb.t1a_ext_c_invert,777cmb.t1a_ext_d, cmb.t1a_ext_d_invert, 0, 0);778cmb.grConstantColorValueExt(tmu_1, cmb.tex_ccolor);779}780else781{782grTexCombine (tmu_1, cmb.tmu1_func, cmb.tmu1_fac, cmb.tmu1_a_func, cmb.tmu1_a_fac, cmb.tmu1_invert, cmb.tmu1_a_invert);783if (cmb.combine_ext)784cmb.grConstantColorValueExt(tmu_1, 0);785}786grTexDetailControl (tmu_1, cmb.dc1_lodbias, cmb.dc1_detailscale, cmb.dc1_detailmax);787grTexLodBiasValue (tmu_1, cmb.lodbias1);788}789if (tmu_0 < voodoo.num_tmu)790{791if (cmb.tex_cmb_ext_use)792{793LRDP(" | | | |- combiner extension tmu0\n");794if (!(cmb.tex_cmb_ext_use & TEX_COMBINE_EXT_COLOR))795TexColorCombinerToExtension (GR_TMU0);796if (!(cmb.tex_cmb_ext_use & TEX_COMBINE_EXT_ALPHA))797TexAlphaCombinerToExtension (GR_TMU0);798cmb.grTexColorCombineExt(tmu_0, cmb.t0c_ext_a, cmb.t0c_ext_a_mode,799cmb.t0c_ext_b, cmb.t0c_ext_b_mode,800cmb.t0c_ext_c, cmb.t0c_ext_c_invert,801cmb.t0c_ext_d, cmb.t0c_ext_d_invert, 0, 0);802cmb.grTexAlphaCombineExt(tmu_0, cmb.t0a_ext_a, cmb.t0a_ext_a_mode,803cmb.t0a_ext_b, cmb.t0a_ext_b_mode,804cmb.t0a_ext_c, cmb.t0a_ext_c_invert,805cmb.t0a_ext_d, cmb.t0a_ext_d_invert, 0, 0);806cmb.grConstantColorValueExt(tmu_0, cmb.tex_ccolor);807}808else809{810grTexCombine (tmu_0, cmb.tmu0_func, cmb.tmu0_fac, cmb.tmu0_a_func, cmb.tmu0_a_fac, cmb.tmu0_invert, cmb.tmu0_a_invert);811if (cmb.combine_ext)812cmb.grConstantColorValueExt(tmu_0, 0);813}814grTexDetailControl (tmu_0, cmb.dc0_lodbias, cmb.dc0_detailscale, cmb.dc0_detailmax);815grTexLodBiasValue (tmu_0, cmb.lodbias0);816}817}818819if ((rdp.tex & 1) && tmu_0 < voodoo.num_tmu)820{821if (aTBuff[0] && aTBuff[0]->cache)822{823LRDP(" | |- Hires tex T0 found in cache.\n");824if (fullscreen)825{826rdp.cur_cache[0] = aTBuff[0]->cache;827rdp.cur_cache[0]->last_used = frame_count;828rdp.cur_cache[0]->uses = rdp.debug_n;829}830}831else if (tex_found[0][tmu_0] != -1)832{833LRDP(" | |- T0 found in cache.\n");834if (fullscreen)835{836CACHE_LUT *cache = voodoo.tex_UMA?&rdp.cache[0][tex_found[0][0]]:&rdp.cache[tmu_0][tex_found[0][tmu_0]];837rdp.cur_cache_n[0] = tex_found[0][tmu_0];838rdp.cur_cache[0] = cache;839rdp.cur_cache[0]->last_used = frame_count;840rdp.cur_cache[0]->uses = rdp.debug_n;841grTexSource (tmu_0,842(voodoo.tex_min_addr[tmu_0] + cache->tmem_addr),843GR_MIPMAPLEVELMASK_BOTH,844&cache->t_info);845}846}847else848LoadTex (0, tmu_0);849}850if ((rdp.tex & 2) && tmu_1 < voodoo.num_tmu)851{852if (aTBuff[1] && aTBuff[1]->cache)853{854LRDP(" | |- Hires tex T1 found in cache.\n");855if (fullscreen)856{857rdp.cur_cache[1] = aTBuff[1]->cache;858rdp.cur_cache[1]->last_used = frame_count;859rdp.cur_cache[1]->uses = rdp.debug_n;860}861}862else if (tex_found[1][tmu_1] != -1)863{864LRDP(" | |- T1 found in cache.\n");865if (fullscreen)866{867CACHE_LUT *cache = voodoo.tex_UMA?&rdp.cache[0][tex_found[1][0]]:&rdp.cache[tmu_1][tex_found[1][tmu_1]];868rdp.cur_cache_n[1] = tex_found[1][tmu_1];869rdp.cur_cache[1] = cache;870rdp.cur_cache[1]->last_used = frame_count;871rdp.cur_cache[1]->uses = rdp.debug_n;872grTexSource (tmu_1,873(voodoo.tex_min_addr[tmu_1] + cache->tmem_addr),874GR_MIPMAPLEVELMASK_BOTH,875&cache->t_info);876}877}878else879LoadTex (1, tmu_1);880}881882if (fullscreen)883{884for (int i=0; i<2; i++)885{886int tmu;887if (i==0) tmu=tmu_0;888else if (i==1) tmu=tmu_1;889890if (tmu >= voodoo.num_tmu) continue;891892int tile = rdp.cur_tile + i;893894if (settings.filtering == 0)895{896int filter = (rdp.filter_mode!=2)?GR_TEXTUREFILTER_POINT_SAMPLED:GR_TEXTUREFILTER_BILINEAR;897grTexFilterMode (tmu, filter, filter);898}899else900{901int filter = (settings.filtering==1)?GR_TEXTUREFILTER_BILINEAR:GR_TEXTUREFILTER_POINT_SAMPLED;902grTexFilterMode (tmu, filter, filter);903}904905if (rdp.cur_cache[i])906{907wxUint32 mode_s, mode_t;908int clamp_s, clamp_t;909if (rdp.force_wrap && !rdp.texrecting)910{911clamp_s = rdp.tiles[tile].clamp_s && rdp.tiles[tile].lr_s-rdp.tiles[tile].ul_s < 256;912clamp_t = rdp.tiles[tile].clamp_t && rdp.tiles[tile].lr_t-rdp.tiles[tile].ul_t < 256;913}914else915{916clamp_s = (rdp.tiles[tile].clamp_s || rdp.tiles[tile].mask_s == 0) &&917rdp.tiles[tile].lr_s-rdp.tiles[tile].ul_s < 256;918clamp_t = (rdp.tiles[tile].clamp_t || rdp.tiles[tile].mask_t == 0) &&919rdp.tiles[tile].lr_t-rdp.tiles[tile].ul_t < 256;920}921922if (rdp.cur_cache[i]->f_mirror_s)923mode_s = GR_TEXTURECLAMP_MIRROR_EXT;924else if (rdp.cur_cache[i]->f_wrap_s)925mode_s = GR_TEXTURECLAMP_WRAP;926else if (clamp_s)927mode_s = GR_TEXTURECLAMP_CLAMP;928else929{930if (rdp.tiles[tile].mirror_s && voodoo.sup_mirroring)931mode_s = GR_TEXTURECLAMP_MIRROR_EXT;932else933mode_s = GR_TEXTURECLAMP_WRAP;934}935936if (rdp.cur_cache[i]->f_mirror_t)937mode_t = GR_TEXTURECLAMP_MIRROR_EXT;938else if (rdp.cur_cache[i]->f_wrap_t)939mode_t = GR_TEXTURECLAMP_WRAP;940else if (clamp_t)941mode_t = GR_TEXTURECLAMP_CLAMP;942else943{944if (rdp.tiles[tile].mirror_t && voodoo.sup_mirroring)945mode_t = GR_TEXTURECLAMP_MIRROR_EXT;946else947mode_t = GR_TEXTURECLAMP_WRAP;948}949950grTexClampMode (tmu,951mode_s,952mode_t);953}954if (aTBuff[i] && (rdp.tex&(i+1)))955SelectTBuffTex(aTBuff[i]);956}957}958959LRDP(" | +- TexCache End\n");960}961962963#ifdef TEXTURE_FILTER964/** cite from RiceVideo */965inline wxUint32 CalculateDXT(wxUint32 txl2words)966{967if( txl2words == 0 ) return 1;968else return (2048+txl2words-1)/txl2words;969}970971wxUint32 sizeBytes[4] = {0,1,2,4};972973inline wxUint32 Txl2Words(wxUint32 width, wxUint32 size)974{975if( size == 0 )976return max(1, width/16);977else978return max(1, width*sizeBytes[size]/8);979}980981inline wxUint32 ReverseDXT(wxUint32 val, wxUint32 lrs, wxUint32 width, wxUint32 size)982{983if( val == 0x800 ) return 1;984985int low = 2047/val;986if( CalculateDXT(low) > val ) low++;987int high = 2047/(val-1);988989if( low == high ) return low;990991for( int i=low; i<=high; i++ )992{993if( Txl2Words(width, size) == (wxUint32)i )994return i;995}996997return (low+high)/2;998}999/** end RiceVideo cite */1000#endif10011002//****************************************************************1003// LoadTex - does the actual texture loading after everything is prepared10041005void LoadTex (int id, int tmu)1006{1007FRDP (" | |-+ LoadTex (id: %d, tmu: %d)\n", id, tmu);10081009int td = rdp.cur_tile + id;1010int lod, aspect;1011CACHE_LUT *cache;10121013if (texinfo[id].width < 0 || texinfo[id].height < 0)1014return;10151016// Clear the cache if it's full1017if (rdp.n_cached[tmu] >= MAX_CACHE)1018{1019LRDP("Cache count reached, clearing...\n");1020ClearCache ();1021if (id == 1 && rdp.tex == 3)1022LoadTex (0, rdp.t0);1023}10241025// Get this cache object1026cache = voodoo.tex_UMA?&rdp.cache[0][rdp.n_cached[0]]:&rdp.cache[tmu][rdp.n_cached[tmu]];1027rdp.cur_cache[id] = cache;1028rdp.cur_cache_n[id] = rdp.n_cached[tmu];10291030//!Hackalert1031//GoldenEye water texture. It has CI format in fact, but the game set it to RGBA1032if ((settings.hacks&hack_GoldenEye) && rdp.tiles[td].format == 0 && rdp.tlut_mode == 2 && rdp.tiles[td].size == 2)1033{1034rdp.tiles[td].format = 2;1035rdp.tiles[td].size = 1;1036}10371038// Set the data1039cache->line = rdp.tiles[td].line;1040cache->addr = rdp.addr[rdp.tiles[td].t_mem];1041cache->crc = texinfo[id].crc;1042cache->palette = rdp.tiles[td].palette;1043cache->width = rdp.tiles[td].width;1044cache->height = rdp.tiles[td].height;1045cache->format = rdp.tiles[td].format;1046cache->size = rdp.tiles[td].size;1047cache->tmem_addr = voodoo.tmem_ptr[tmu];1048cache->set_by = rdp.timg.set_by;1049cache->texrecting = rdp.texrecting;1050cache->last_used = frame_count;1051cache->uses = rdp.debug_n;1052cache->flags = texinfo[id].flags;1053cache->f_mirror_s = FALSE;1054cache->f_mirror_t = FALSE;1055cache->f_wrap_s = FALSE;1056cache->f_wrap_t = FALSE;1057#ifdef TEXTURE_FILTER1058cache->is_hires_tex = FALSE;1059cache->ricecrc = texinfo[id].ricecrc;1060#endif10611062// Add this cache to the list1063AddToList (&cachelut[cache->crc>>16], cache->crc, wxPtrToUInt(cache), tmu, rdp.n_cached[tmu]);10641065// temporary1066cache->t_info.format = GR_TEXFMT_ARGB_1555;10671068// Calculate lod and aspect1069wxUint32 size_x = rdp.tiles[td].width;1070wxUint32 size_y = rdp.tiles[td].height;10711072// make size_x and size_y both powers of two1073if (!voodoo.sup_large_tex)1074{1075if (size_x > 256) size_x = 256;1076if (size_y > 256) size_y = 256;1077}10781079int shift;1080for (shift=0; (1<<shift) < (int)size_x; shift++);1081size_x = 1 << shift;1082for (shift=0; (1<<shift) < (int)size_y; shift++);1083size_y = 1 << shift;10841085// Voodoo 1 support is all here, it will automatically mirror to the full extent.1086if (!voodoo.sup_mirroring)1087{1088if (rdp.tiles[td].mirror_s && !rdp.tiles[td].clamp_s && (voodoo.sup_large_tex || size_x <= 128))1089size_x <<= 1;1090if (rdp.tiles[td].mirror_t && !rdp.tiles[td].clamp_t && (voodoo.sup_large_tex || size_y <= 128))1091size_y <<= 1;1092}10931094// Calculate the maximum size1095int size_max = max (size_x, size_y);1096wxUint32 real_x=size_max, real_y=size_max;1097switch (size_max)1098{1099case 1:1100lod = GR_LOD_LOG2_1;1101cache->scale = 256.0f;1102break;1103case 2:1104lod = GR_LOD_LOG2_2;1105cache->scale = 128.0f;1106break;1107case 4:1108lod = GR_LOD_LOG2_4;1109cache->scale = 64.0f;1110break;1111case 8:1112lod = GR_LOD_LOG2_8;1113cache->scale = 32.0f;1114break;1115case 16:1116lod = GR_LOD_LOG2_16;1117cache->scale = 16.0f;1118break;1119case 32:1120lod = GR_LOD_LOG2_32;1121cache->scale = 8.0f;1122break;1123case 64:1124lod = GR_LOD_LOG2_64;1125cache->scale = 4.0f;1126break;1127case 128:1128lod = GR_LOD_LOG2_128;1129cache->scale = 2.0f;1130break;1131case 256:1132lod = GR_LOD_LOG2_256;1133cache->scale = 1.0f;1134break;1135case 512:1136lod = GR_LOD_LOG2_512;1137cache->scale = 0.5f;1138break;1139default:1140lod = GR_LOD_LOG2_1024;1141cache->scale = 0.25f;1142break;1143}11441145// Calculate the aspect ratio1146if (size_x >= size_y)1147{1148int ratio = size_x / size_y;1149switch (ratio)1150{1151case 1:1152aspect = GR_ASPECT_LOG2_1x1;1153cache->scale_x = 1.0f;1154cache->scale_y = 1.0f;1155break;1156case 2:1157aspect = GR_ASPECT_LOG2_2x1;1158cache->scale_x = 1.0f;1159cache->scale_y = 0.5f;1160real_y >>= 1;1161break;1162case 4:1163aspect = GR_ASPECT_LOG2_4x1;1164cache->scale_x = 1.0f;1165cache->scale_y = 0.25f;1166real_y >>= 2;1167break;1168default:1169aspect = GR_ASPECT_LOG2_8x1;1170cache->scale_x = 1.0f;1171cache->scale_y = 0.125f;1172real_y >>= 3;1173break;1174}1175}1176else1177{1178int ratio = size_y / size_x;1179switch (ratio)1180{1181case 2:1182aspect = GR_ASPECT_LOG2_1x2;1183cache->scale_x = 0.5f;1184cache->scale_y = 1.0f;1185real_x >>= 1;1186break;1187case 4:1188aspect = GR_ASPECT_LOG2_1x4;1189cache->scale_x = 0.25f;1190cache->scale_y = 1.0f;1191real_x >>= 2;1192break;1193default:1194aspect = GR_ASPECT_LOG2_1x8;1195cache->scale_x = 0.125f;1196cache->scale_y = 1.0f;1197real_x >>= 3;1198break;1199}1200}12011202if (real_x != cache->width || real_y != cache->height)1203{1204cache->scale_x *= (float)cache->width / (float)real_x;1205cache->scale_y *= (float)cache->height / (float)real_y;1206}12071208int splits = texinfo[id].splits;1209cache->splits = texinfo[id].splits;1210cache->splitheight = real_y / cache->splits;1211if (cache->splitheight < texinfo[id].splitheight)1212cache->splitheight = texinfo[id].splitheight;12131214// ** Calculate alignment values1215int wid = cache->width;1216int hei = cache->height;12171218if (splits > 1)1219{1220wid = texinfo[id].real_image_width;1221hei = texinfo[id].real_image_height;1222}12231224cache->c_off = cache->scale * 0.5f;1225if (wid != 1) cache->c_scl_x = cache->scale;1226else cache->c_scl_x = 0.0f;1227if (hei != 1) cache->c_scl_y = cache->scale;1228else cache->c_scl_y = 0.0f;1229// **12301231wxUint32 mod, modcolor, modcolor1, modcolor2, modfactor;1232if (id == 0)1233{1234mod = cmb.mod_0;1235modcolor = cmb.modcolor_0;1236modcolor1 = cmb.modcolor1_0;1237modcolor2 = cmb.modcolor2_0;1238modfactor = cmb.modfactor_0;1239}1240else1241{1242mod = cmb.mod_1;1243modcolor = cmb.modcolor_1;1244modcolor1 = cmb.modcolor1_1;1245modcolor2 = cmb.modcolor2_1;1246modfactor = cmb.modfactor_1;1247}12481249wxUint16 tmp_pal[256];1250int modifyPalette = (mod && (cache->format == 2) && (rdp.tlut_mode == 2));12511252if (modifyPalette)1253{1254memcpy(tmp_pal, rdp.pal_8, 512);1255ModifyPalette(mod, modcolor, modcolor1, modfactor);1256}12571258cache->mod = mod;1259cache->mod_color = modcolor;1260cache->mod_color1 = modcolor1;1261cache->mod_factor = modfactor;12621263for (int t = 0; t < 2; t++) {1264if (rdp.aTBuffTex[t] && rdp.aTBuffTex[t]->tile == id) //texture buffer will be used instead of frame buffer texture1265{1266rdp.aTBuffTex[t]->cache = cache;1267FRDP("tbuff_tex selected: %d, tile=%d\n", t, id);1268return;1269}1270}12711272wxUint32 result = 0; // keep =0 so it doesn't mess up on the first split12731274texture = tex1;12751276// Hiroshi Morii <[email protected]>1277// NOTE: Loading Hi-res texture packs and filtering should be done1278// before the texture is modified with color palettes, etc.1279//1280// Since the internal texture identification needs Glide64CRC, (RiceCRC1281// doesn't always return unique values) it seems reasonable that the1282// extra CRC calculation for hires textures should be executed only1283// when we get passed the texture ram cache and texture buffers for1284// minimal calculation overhead.1285//1286#ifdef TEXTURE_FILTER // Hiroshi Morii <[email protected]>1287GHQTexInfo ghqTexInfo;1288memset(&ghqTexInfo, 0, sizeof(GHQTexInfo));1289wxUint32 g64_crc = cache->crc;1290if (settings.ghq_use)1291{1292int bpl;1293wxUint8* addr = (wxUint8*)(gfx.RDRAM+rdp.addr[rdp.tiles[td].t_mem]);1294int tile_width = texinfo[id].width;1295int tile_height = texinfo[id].height;1296LOAD_TILE_INFO &info = rdp.load_info[rdp.tiles[td].t_mem];1297if (rdp.timg.set_by == 1)1298{1299bpl = info.tex_width << info.tex_size >> 1;1300addr += (info.tile_ul_t * bpl) + (((info.tile_ul_s<<info.tex_size)+1)>>1);13011302tile_width = min(info.tile_width, info.tex_width);1303if (info.tex_size > rdp.tiles[td].size)1304tile_width <<= info.tex_size - rdp.tiles[td].size;13051306if (rdp.tiles[td].lr_t > rdp.bg_image_height)1307tile_height = rdp.bg_image_height - rdp.tiles[td].ul_t;1308else1309tile_height = info.tile_height;1310}1311else1312{1313if (rdp.tiles[td].size == 3)1314bpl = rdp.tiles[td].line << 4;1315else if (info.dxt == 0)1316bpl = rdp.tiles[td].line << 3;1317else {1318wxUint32 dxt = info.dxt;1319if (dxt > 1)1320dxt = ReverseDXT(dxt, info.tile_width, texinfo[id].width, rdp.tiles[td].size);1321bpl = dxt << 3;1322}1323}13241325// 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));1326wxUint8 * paladdr = 0;1327wxUint16 * palette = 0;1328if ((rdp.tiles[td].size < 2) && (rdp.tlut_mode || rdp.tiles[td].format == 2))1329{1330if (rdp.tiles[td].size == 1)1331paladdr = (wxUint8*)(rdp.pal_8_rice);1332else if (settings.ghq_hirs_altcrc)1333paladdr = (wxUint8*)(rdp.pal_8_rice + (rdp.tiles[td].palette << 5));1334else1335paladdr = (wxUint8*)(rdp.pal_8_rice + (rdp.tiles[td].palette << 4));1336palette = (rdp.pal_8 + (rdp.tiles[td].palette << 4));1337}13381339// XXX: Special combiner modes are ignored for hires textures1340// for now. Come back to this later!! The following is needed1341// for (2xSai, hq4x, etc) enhanced/filtered textures.1342g64_crc = CRC32( g64_crc, &cache->mod, 4 );1343g64_crc = CRC32( g64_crc, &cache->mod_color, 4 );1344g64_crc = CRC32( g64_crc, &cache->mod_color1, 4 );1345//g64_crc = CRC32( g64_crc, &cache->mod_color2, 4 ); // not used?1346g64_crc = CRC32( g64_crc, &cache->mod_factor, 4 );13471348cache->ricecrc = ext_ghq_checksum(addr, tile_width, tile_height, (unsigned short)(rdp.tiles[td].format << 8 | rdp.tiles[td].size), bpl, paladdr);1349FRDP("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));1350if (ext_ghq_hirestex((uint64)g64_crc, cache->ricecrc, palette, &ghqTexInfo))1351{1352cache->is_hires_tex = ghqTexInfo.is_hires_tex;1353if (!ghqTexInfo.is_hires_tex && aspect != ghqTexInfo.aspectRatioLog2)1354ghqTexInfo.data = 0; //if aspects of current texture and found filtered texture are different, texture must be filtered again.1355}1356}135713581359// ** handle texture splitting **1360if (ghqTexInfo.data)1361;//do nothing1362else1363#endif1364if (splits > 1)1365{1366cache->scale_y = 0.125f;13671368int i;1369for (i=0; i<splits; i++)1370{1371int start_dst = i * cache->splitheight * 256; // start lower1372start_dst <<= HIWORD(result); // 1st time, result is set to 0, but start_dst is 0 anyway so it doesn't matter13731374int start_src = i * 256; // start 256 more to the right1375start_src = start_src << (rdp.tiles[td].size) >> 1;1376if (rdp.tiles[td].size == 3)1377start_src >>= 1;13781379result = load_table[rdp.tiles[td].size][rdp.tiles[td].format]1380(wxPtrToUInt(texture)+start_dst, wxPtrToUInt(rdp.tmem)+(rdp.tiles[td].t_mem<<3)+start_src,1381texinfo[id].wid_64, texinfo[id].height, texinfo[id].line, real_x, td);13821383wxUint32 size = HIWORD(result);1384// clamp so that it looks somewhat ok when wrapping1385if (size == 1)1386Clamp16bT ((texture)+start_dst, texinfo[id].height, real_x, cache->splitheight);1387else if (size != 2)1388Clamp8bT ((texture)+start_dst, texinfo[id].height, real_x, cache->splitheight);1389else1390Clamp32bT ((texture)+start_dst, texinfo[id].height, real_x, cache->splitheight);1391}1392}1393// ** end texture splitting **1394else1395{1396result = load_table[rdp.tiles[td].size][rdp.tiles[td].format]1397(wxPtrToUInt(texture), wxPtrToUInt(rdp.tmem)+(rdp.tiles[td].t_mem<<3),1398texinfo[id].wid_64, texinfo[id].height, texinfo[id].line, real_x, td);13991400wxUint32 size = HIWORD(result);14011402int min_x, min_y;1403if (rdp.tiles[td].mask_s != 0)1404min_x = min((int)real_x, 1<<rdp.tiles[td].mask_s);1405else1406min_x = real_x;1407if (rdp.tiles[td].mask_t != 0)1408min_y = min((int)real_y, 1<<rdp.tiles[td].mask_t);1409else1410min_y = real_y;14111412// Load using mirroring/clamping1413if (min_x > texinfo[id].width)1414{1415if (size == 1)1416Clamp16bS ((texture), texinfo[id].width, min_x, real_x, texinfo[id].height);1417else if (size != 2)1418Clamp8bS ((texture), texinfo[id].width, min_x, real_x, texinfo[id].height);1419else1420Clamp32bS ((texture), texinfo[id].width, min_x, real_x, texinfo[id].height);1421}14221423if (texinfo[id].width < (int)real_x)1424{1425if (rdp.tiles[td].mirror_s)1426{1427if (size == 1)1428Mirror16bS ((texture), rdp.tiles[td].mask_s,1429real_x, real_x, texinfo[id].height);1430else if (size != 2)1431Mirror8bS ((texture), rdp.tiles[td].mask_s,1432real_x, real_x, texinfo[id].height);1433else1434Mirror32bS ((texture), rdp.tiles[td].mask_s,1435real_x, real_x, texinfo[id].height);1436}1437else1438{1439if (size == 1)1440Wrap16bS ((texture), rdp.tiles[td].mask_s,1441real_x, real_x, texinfo[id].height);1442else if (size != 2)1443Wrap8bS ((texture), rdp.tiles[td].mask_s,1444real_x, real_x, texinfo[id].height);1445else1446Wrap32bS ((texture), rdp.tiles[td].mask_s,1447real_x, real_x, texinfo[id].height);1448}1449}14501451if (min_y > texinfo[id].height)1452{1453if (size == 1)1454Clamp16bT ((texture), texinfo[id].height, real_x, min_y);1455else if (size != 2)1456Clamp8bT ((texture), texinfo[id].height, real_x, min_y);1457else1458Clamp32bT ((texture), texinfo[id].height, real_x, min_y);1459}14601461if (texinfo[id].height < (int)real_y)1462{1463if (rdp.tiles[td].mirror_t)1464{1465if (size == 1)1466Mirror16bT ((texture), rdp.tiles[td].mask_t,1467real_y, real_x);1468else if (size != 2)1469Mirror8bT ((texture), rdp.tiles[td].mask_t,1470real_y, real_x);1471else1472Mirror32bT ((texture), rdp.tiles[td].mask_t,1473real_y, real_x);1474}1475else1476{1477if (size == 1)1478Wrap16bT ((texture), rdp.tiles[td].mask_t,1479real_y, real_x);1480else if (size != 2)1481Wrap8bT ((texture), rdp.tiles[td].mask_t,1482real_y, real_x);1483else1484Wrap32bT ((texture), rdp.tiles[td].mask_t,1485real_y, real_x);1486}1487}1488}14891490if (modifyPalette)1491{1492memcpy(rdp.pal_8, tmp_pal, 512);1493}14941495#ifdef TEXTURE_FILTER1496if (mod && !modifyPalette && !ghqTexInfo.data)1497#else1498if (mod && !modifyPalette)1499#endif1500{1501// Convert the texture to ARGB 44441502if (LOWORD(result) == GR_TEXFMT_ARGB_1555)1503{1504TexConv_ARGB1555_ARGB4444 ((texture), (tex2), real_x, real_y);1505texture = tex2;1506}1507else if (LOWORD(result) == GR_TEXFMT_ALPHA_INTENSITY_88)1508{1509TexConv_AI88_ARGB4444 ((texture), (tex2), real_x, real_y);1510texture = tex2;1511}1512else if (LOWORD(result) == GR_TEXFMT_ALPHA_INTENSITY_44)1513{1514TexConv_AI44_ARGB4444 ((texture), (tex2), real_x, real_y);1515texture = tex2;1516}1517else if (LOWORD(result) == GR_TEXFMT_ALPHA_8)1518{1519TexConv_A8_ARGB4444 ((texture), (tex2), real_x, real_y);1520texture = tex2;1521}1522/*else if (LOWORD(result) == GR_TEXFMT_ARGB_4444)1523{1524memcpy (tex2, texture, (real_x*real_y) << 1);1525texture = tex2;1526}*/ // we can skip memcpy since "texture" won't be swapped between "tex1" and "tex2" after this.1527// Hiroshi Morii <[email protected]>15281529result = (1 << 16) | GR_TEXFMT_ARGB_4444;15301531// Now convert the color to the same1532modcolor = ((modcolor & 0xF0000000) >> 16) | ((modcolor & 0x00F00000) >> 12) |1533((modcolor & 0x0000F000) >> 8) | ((modcolor & 0x000000F0) >> 4);1534modcolor1 = ((modcolor1 & 0xF0000000) >> 16) | ((modcolor1 & 0x00F00000) >> 12) |1535((modcolor1 & 0x0000F000) >> 8) | ((modcolor1 & 0x000000F0) >> 4);1536modcolor2 = ((modcolor2 & 0xF0000000) >> 16) | ((modcolor2 & 0x00F00000) >> 12) |1537((modcolor2 & 0x0000F000) >> 8) | ((modcolor2 & 0x000000F0) >> 4);15381539int size = (real_x * real_y) << 1;15401541switch (mod)1542{1543case TMOD_TEX_INTER_COLOR_USING_FACTOR:1544mod_tex_inter_color_using_factor ((wxUint16*)texture, size, modcolor, modfactor);1545break;1546case TMOD_TEX_INTER_COL_USING_COL1:1547mod_tex_inter_col_using_col1 ((wxUint16*)texture, size, modcolor, modcolor1);1548break;1549case TMOD_FULL_COLOR_SUB_TEX:1550mod_full_color_sub_tex ((wxUint16*)texture, size, modcolor);1551break;1552case TMOD_COL_INTER_COL1_USING_TEX:1553mod_col_inter_col1_using_tex ((wxUint16*)texture, size, modcolor, modcolor1);1554break;1555case TMOD_COL_INTER_COL1_USING_TEXA:1556mod_col_inter_col1_using_texa ((wxUint16*)texture, size, modcolor, modcolor1);1557break;1558case TMOD_COL_INTER_COL1_USING_TEXA__MUL_TEX:1559mod_col_inter_col1_using_texa__mul_tex ((wxUint16*)texture, size, modcolor, modcolor1);1560break;1561case TMOD_COL_INTER_TEX_USING_TEXA:1562mod_col_inter_tex_using_texa ((wxUint16*)texture, size, modcolor);1563break;1564case TMOD_COL2_INTER__COL_INTER_COL1_USING_TEX__USING_TEXA:1565mod_col2_inter__col_inter_col1_using_tex__using_texa ((wxUint16*)texture, size, modcolor, modcolor1, modcolor2);1566break;1567case TMOD_TEX_SCALE_FAC_ADD_FAC:1568mod_tex_scale_fac_add_fac ((wxUint16*)texture, size, modfactor);1569break;1570case TMOD_TEX_SUB_COL_MUL_FAC_ADD_TEX:1571mod_tex_sub_col_mul_fac_add_tex ((wxUint16*)texture, size, modcolor, modfactor);1572break;1573case TMOD_TEX_SCALE_COL_ADD_COL:1574mod_tex_scale_col_add_col ((wxUint16*)texture, size, modcolor, modcolor1);1575break;1576case TMOD_TEX_ADD_COL:1577mod_tex_add_col ((wxUint16*)texture, size, modcolor);1578break;1579case TMOD_TEX_SUB_COL:1580mod_tex_sub_col ((wxUint16*)texture, size, modcolor);1581break;1582case TMOD_TEX_SUB_COL_MUL_FAC:1583mod_tex_sub_col_mul_fac ((wxUint16*)texture, size, modcolor, modfactor);1584break;1585case TMOD_COL_INTER_TEX_USING_COL1:1586mod_col_inter_tex_using_col1 ((wxUint16*)texture, size, modcolor, modcolor1);1587break;1588case TMOD_COL_MUL_TEXA_ADD_TEX:1589mod_col_mul_texa_add_tex((wxUint16*)texture, size, modcolor);1590break;1591case TMOD_COL_INTER_TEX_USING_TEX:1592mod_col_inter_tex_using_tex ((wxUint16*)texture, size, modcolor);1593break;1594case TMOD_TEX_INTER_NOISE_USING_COL:1595mod_tex_inter_noise_using_col ((wxUint16*)texture, size, modcolor);1596break;1597case TMOD_TEX_INTER_COL_USING_TEXA:1598mod_tex_inter_col_using_texa ((wxUint16*)texture, size, modcolor);1599break;1600case TMOD_TEX_MUL_COL:1601mod_tex_mul_col ((wxUint16*)texture, size, modcolor);1602break;1603case TMOD_TEX_SCALE_FAC_ADD_COL:1604mod_tex_scale_fac_add_col ((wxUint16*)texture, size, modcolor, modfactor);1605break;1606default:1607;1608}1609}161016111612cache->t_info.format = LOWORD(result);16131614cache->realwidth = real_x;1615cache->realheight = real_y;1616cache->lod = lod;1617cache->aspect = aspect;16181619if (fullscreen)1620{1621#ifdef TEXTURE_FILTER // Hiroshi Morii <[email protected]>1622if (settings.ghq_use)1623{1624if (!ghqTexInfo.data && ghq_dmptex_toggle_key) {1625unsigned char *tmpbuf = (unsigned char*)texture;1626int tmpwidth = real_x;1627if (texinfo[id].splits > 1) {1628int dstpixoffset, srcpixoffset;1629int shift;1630switch (LOWORD(result) & 0x7fff) { // XXX is there a better way of determining the pixel color depth?1631case GR_TEXFMT_ARGB_8888:1632shift = 3;1633break;1634case GR_TEXFMT_ALPHA_INTENSITY_44:1635case GR_TEXFMT_ALPHA_8:1636shift = 0;1637break;1638default:1639shift = 1;1640}1641tmpwidth = texinfo[id].real_image_width;1642tmpbuf = (unsigned char*)malloc((256*256)<<3); // XXX performance overhead1643for (int i = 0; i < cache->splitheight; i++) {1644dstpixoffset = texinfo[id].real_image_width * i;1645srcpixoffset = 256 * i;1646for (int k = 0; k < texinfo[id].splits; k++) {1647memcpy(tmpbuf + (dstpixoffset << shift), texture + (srcpixoffset << shift), (256 << shift));1648dstpixoffset += 256;1649srcpixoffset += (256 * cache->splitheight);1650}1651}1652}1653ext_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);1654if (tmpbuf != texture && tmpbuf) {1655free(tmpbuf);1656}1657}16581659if (!ghqTexInfo.data)1660if (!settings.ghq_enht_nobg || !rdp.texrecting || (texinfo[id].splits == 1 && texinfo[id].width <= 256))1661ext_ghq_txfilter((unsigned char*)texture, (int)real_x, (int)real_y, LOWORD(result), (uint64)g64_crc, &ghqTexInfo);16621663if (ghqTexInfo.data)1664{1665if (ghqTexInfo.aspectRatioLog2 < GR_ASPECT_LOG2_1x8 ||1666ghqTexInfo.aspectRatioLog2 > GR_ASPECT_LOG2_8x1 ||1667ghqTexInfo.largeLodLog2 > GR_LOD_LOG2_2048 ||1668ghqTexInfo.largeLodLog2 < GR_LOD_LOG2_1)1669{1670/* invalid dimensions */1671}1672else1673{1674texture = (wxUint8 *)ghqTexInfo.data;1675lod = ghqTexInfo.largeLodLog2;1676int splits = cache->splits;1677if (ghqTexInfo.is_hires_tex)1678{1679if (ghqTexInfo.tiles/*ghqTexInfo.untiled_width > max_tex_size*/)1680{1681cache->scale = 1.0f;1682cache->c_off = 0.5f;1683cache->splits = ghqTexInfo.tiles;//((hirestex.width-1)>>8)+1;1684cache->splitheight = ghqTexInfo.untiled_height;1685cache->scale_x = 1.0f;1686cache->scale_y = float(ghqTexInfo.untiled_height*ghqTexInfo.tiles)/float(ghqTexInfo.width);//*sy;1687if (splits == 1)1688{1689int shift;1690for (shift=9; (1<<shift) < ghqTexInfo.untiled_width; shift++);1691float mult = float(1 << shift >> 8);1692cache->c_scl_x *= mult;1693cache->c_scl_y *= mult;1694}1695else1696{1697int tile_width = rdp.tiles[td].width;1698if (rdp.timg.set_by == 1)1699tile_width = rdp.load_info[rdp.tiles[td].t_mem].tex_width;1700float mult = float(ghqTexInfo.untiled_width/tile_width);1701cache->c_scl_x *= mult;1702cache->c_scl_y *= mult;1703}1704}1705else1706{1707cache->scale = 256.0f / float(1<<lod);1708cache->c_off = cache->scale * 0.5f;1709cache->splits = 1;1710if (aspect != ghqTexInfo.aspectRatioLog2)1711{1712float mscale = float(1<<abs(aspect - ghqTexInfo.aspectRatioLog2));1713if (abs(aspect) > abs(ghqTexInfo.aspectRatioLog2))1714{1715cache->c_scl_y *= mscale;1716cache->c_scl_x *= mscale;1717}1718/*1719else1720{1721if (rdp.tiles[td].mirror_s && sup_mirroring)1722cache->f_mirror_s = TRUE;1723if (rdp.tiles[td].mirror_t && sup_mirroring)1724cache->f_mirror_t = TRUE;1725//cache->c_scl_y /= mscale;1726//cache->c_scl_x /= mscale;1727}1728*/1729if (ghqTexInfo.aspectRatioLog2 >= 0)1730{1731cache->scale_x = 1.0f;1732cache->scale_y = 1.0f/float(1<<ghqTexInfo.aspectRatioLog2);1733}1734else1735{1736cache->scale_y = 1.0f;1737cache->scale_x = 1.0f/float(1<<(-ghqTexInfo.aspectRatioLog2));1738}1739}1740else if (splits > 1)1741{1742cache->c_scl_x /= splits;1743cache->c_scl_y /= splits;1744}1745}1746if (voodoo.sup_mirroring)1747{1748if (rdp.tiles[td].mirror_s && texinfo[id].tile_width == 2*texinfo[id].width)1749cache->f_mirror_s = TRUE;1750else if (texinfo[id].tile_width >= 2*texinfo[id].width)1751cache->f_wrap_s = TRUE;1752if (rdp.tiles[td].mirror_t && texinfo[id].tile_height == 2*texinfo[id].height)1753cache->f_mirror_t = TRUE;1754else if (texinfo[id].tile_height >= 2*texinfo[id].height)1755cache->f_wrap_t = TRUE;1756if (cache->f_mirror_s && cache->f_mirror_t)1757{1758cache->c_scl_x *= 2.0f;1759cache->c_scl_y *= 2.0f;1760}1761}1762aspect = ghqTexInfo.aspectRatioLog2;1763cache->lod = lod;1764cache->aspect = aspect;1765}1766else1767{1768//cache->scale = 256.0f / float(1<<lod);1769cache->c_off = 128.0f / float(1<<lod);1770}1771real_x = ghqTexInfo.width;1772real_y = ghqTexInfo.height;1773result = (1 << 16) | ghqTexInfo.format;1774cache->t_info.format = ghqTexInfo.format;1775cache->realwidth = real_x;1776cache->realheight = real_y;1777}1778}1779}1780#endif17811782// Load the texture into texture memory1783GrTexInfo *t_info = &cache->t_info;1784t_info->data = texture;1785t_info->smallLodLog2 = lod;1786t_info->largeLodLog2 = lod;1787t_info->aspectRatioLog2 = aspect;17881789wxUint32 texture_size = grTexTextureMemRequired (GR_MIPMAPLEVELMASK_BOTH, t_info);17901791// Check for 2mb boundary1792// Hiroshi Morii <[email protected]> required only for V1,Rush, and V21793if (voodoo.has_2mb_tex_boundary &&1794(voodoo.tmem_ptr[tmu] < TEXMEM_2MB_EDGE) && (voodoo.tmem_ptr[tmu]+texture_size > TEXMEM_2MB_EDGE))1795{1796voodoo.tmem_ptr[tmu] = TEXMEM_2MB_EDGE;1797cache->tmem_addr = voodoo.tmem_ptr[tmu];1798}17991800// Check for end of memory (too many textures to fit, clear cache)1801if (voodoo.tmem_ptr[tmu]+texture_size >= voodoo.tex_max_addr[tmu])1802{1803LRDP("Cache size reached, clearing...\n");1804ClearCache ();18051806if (id == 1 && rdp.tex == 3)1807LoadTex (0, rdp.t0);18081809LoadTex (id, tmu);1810return;1811// DON'T CONTINUE (already done)1812}18131814wxUint32 tex_addr = GetTexAddr(tmu, texture_size);1815grTexDownloadMipMap (tmu,1816tex_addr,1817GR_MIPMAPLEVELMASK_BOTH,1818t_info);18191820grTexSource (tmu,1821tex_addr,1822GR_MIPMAPLEVELMASK_BOTH,1823t_info);1824}18251826LRDP(" | | +- LoadTex end\n");1827}182818291830