Path: blob/master/libmupen64plus/mupen64plus-video-glide64/src/TexCache.cpp
2 views
/*1* Glide64 - Glide video plugin for Nintendo 64 emulators.2* Copyright (c) 2002 Dave20013* Copyright (c) 2008 Günther <[email protected]>4*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 Public16* Licence along with this program; if not, write to the Free17* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,18* Boston, MA 02110-1301, USA19*/2021//****************************************************************22//23// Glide64 - Glide Plugin for Nintendo 64 emulators (tested mostly with Project64)24// Project started on December 29th, 200125//26// To modify Glide64:27// * 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.28// * 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.29//30// Official Glide64 development channel: #Glide64 on EFnet31//32// Original author: Dave2001 ([email protected])33// Other authors: Gonetz, Gugaman34//35//****************************************************************3637#define M64P_PLUGIN_PROTOTYPES 138#include "m64p_types.h"39#include "m64p_plugin.h"40#include "m64p_config.h"41#include "m64p_vidext.h"42#include "TexCache.h"43#include "Combine.h"4445void LoadTex (int id, int tmu);4647BYTE tex1[512*512*4]; // temporary texture48BYTE tex2[512*512*4];49BYTE *texture;5051#include "TexLoad.h" // texture loading functions, ONLY INCLUDE IN THIS FILE!!!52#include "MiClWr16b.h" // Mirror/Clamp/Wrap functions, ONLY INCLUDE IN THIS FILE!!!53#include "MiClWr8b.h" // Mirror/Clamp/Wrap functions, ONLY INCLUDE IN THIS FILE!!!54#include "TexConv.h" // texture conversions, ONLY INCLUDE IN THIS FILE!!!55#include "TexMod.h"56#include "TexModCI.h"57#include "CRC.h"5859#ifndef _WIN3260#include <stdlib.h>61#endif // _WIN326263typedef struct TEXINFO_t {64int real_image_width, real_image_height; // FOR ALIGNMENT PURPOSES ONLY!!!65int tile_width, tile_height;66int mask_width, mask_height;67int width, height;68int wid_64, line;69DWORD crc;70DWORD flags;71int splits, splitheight;72} TEXINFO;7374TEXINFO texinfo[2];75int tex_found[2][MAX_TMU];7677//****************************************************************78// List functions7980typedef struct NODE_t {81DWORD crc;82CACHE_LUT* data;83int tmu;84int number;85NODE_t *pNext;86} NODE;8788NODE *cachelut[256];8990void AddToList (NODE **list, DWORD crc, CACHE_LUT* data, int tmu, int number)91{92NODE *node = new NODE;93node->crc = crc;94node->data = data;95node->tmu = tmu;96node->number = number;97node->pNext = *list;98*list = node;99}100101void DeleteList (NODE **list)102{103while (*list)104{105NODE *next = (*list)->pNext;106delete (*list);107*list = next;108}109}110111void TexCacheInit ()112{113for (int i=0; i<256; i++)114{115cachelut[i] = NULL;116}117}118119//****************************************************************120// GetTexInfo - gets information for either t0 or t1, checks if in cache & fills tex_found121122void GetTexInfo (int id, int tile)123{124FRDP (" | |-+ GetTexInfo (id: %d, tile: %d)\n", id, tile);125126TEXINFO *info = &texinfo[id];127128int tile_width, tile_height;129int mask_width, mask_height;130int width, height;131int wid_64, line, bpl;132133// Get width and height134tile_width = rdp.tiles[tile].lr_s - rdp.tiles[tile].ul_s + 1;135tile_height = rdp.tiles[tile].lr_t - rdp.tiles[tile].ul_t + 1;136137mask_width = (rdp.tiles[tile].mask_s==0)?(tile_width):(1 << rdp.tiles[tile].mask_s);138mask_height = (rdp.tiles[tile].mask_t==0)?(tile_height):(1 << rdp.tiles[tile].mask_t);139140if (settings.alt_tex_size)141{142// ** ALTERNATE TEXTURE SIZE METHOD **143// Helps speed in some games that loaded weird-sized textures, but could break other144// textures.145146// Get the width/height to load147if ((rdp.tiles[tile].clamp_s && tile_width <= 256) || (mask_width > 256))148{149// loading width150width = min(mask_width, tile_width);151// actual width152rdp.tiles[tile].width = tile_width;153}154else155{156// wrap all the way157width = min(mask_width, tile_width); // changed from mask_width only158rdp.tiles[tile].width = width;159}160161if ((rdp.tiles[tile].clamp_t && tile_height <= 256) || (mask_height > 256))162{163// loading height164height = min(mask_height, tile_height);165// actual height166rdp.tiles[tile].height = tile_height;167}168else169{170// wrap all the way171height = min(mask_height, tile_height);172rdp.tiles[tile].height = height;173}174}175else176{177// ** NORMAL TEXTURE SIZE METHOD **178// This is the 'correct' method for determining texture size, but may cause certain179// textures to load too large & make the whole game go slow.180181// Get the width/height to load182if ((rdp.tiles[tile].clamp_s && tile_width <= 256) || (mask_width > 256))183{184// loading width185width = min(mask_width, tile_width);186// actual width187rdp.tiles[tile].width = tile_width;188}189else190{191// wrap all the way192width = mask_width;193rdp.tiles[tile].width = mask_width;194}195196if ((rdp.tiles[tile].clamp_t && tile_height <= 256) || (mask_height > 256))197{198// loading height199height = min(mask_height, tile_height);200// actual height201rdp.tiles[tile].height = tile_height;202}203else204{205// wrap all the way206height = mask_height;207rdp.tiles[tile].height = mask_height;208}209}210211// without any large texture fixing-up; for alignment212int real_image_width = rdp.tiles[tile].width;213int real_image_height = rdp.tiles[tile].height;214bpl = width << rdp.tiles[tile].size >> 1;215216// ** COMMENT THIS TO DISABLE LARGE TEXTURES217#ifdef LARGE_TEXTURE_HANDLING218if (width > 256)219{220info->splits = ((width-1)>>8)+1;221info->splitheight = rdp.tiles[tile].height;222rdp.tiles[tile].height *= info->splits;223rdp.tiles[tile].width = 256;224width = 256;225}226else227#endif228// **229{230info->splits = 1;231}232233RDP (" | | |-+ Texture approved:\n");234FRDP (" | | | |- tmem: %08lx\n", rdp.tiles[tile].t_mem);235FRDP (" | | | |- load width: %d\n", width);236FRDP (" | | | |- load height: %d\n", height);237FRDP (" | | | |- actual width: %d\n", rdp.tiles[tile].width);238FRDP (" | | | |- actual height: %d\n", rdp.tiles[tile].height);239FRDP (" | | | |- size: %d\n", rdp.tiles[tile].size);240FRDP (" | | | +- format: %d\n", rdp.tiles[tile].format);241RDP (" | | |- Calculating CRC... ");242243// ** CRC CHECK244245wid_64 = width << (rdp.tiles[tile].size) >> 1;246if (rdp.tiles[tile].size == 3)247{248if (wid_64 & 15) wid_64 += 16;249wid_64 &= 0xFFFFFFF0;250}251else252{253if (wid_64 & 7) wid_64 += 8; // round up254}255wid_64 = wid_64>>3;256257// Texture too big for tmem & needs to wrap? (trees in mm)258259if (settings.wrap_big_tex && (rdp.tiles[tile].t_mem + min(height, tile_height) * (rdp.tiles[tile].line<<3) > 4096))260{261RDP ("TEXTURE WRAPS TMEM!!! ");262263// calculate the y value that intersects at 4096 bytes264int y = (4096 - rdp.tiles[tile].t_mem) / (rdp.tiles[tile].line<<3);265266rdp.tiles[tile].clamp_t = 0;267rdp.tiles[tile].lr_t = rdp.tiles[tile].ul_t + y - 1;268269// calc mask270int shift;271for (shift=0; (1<<shift)<y; shift++);272rdp.tiles[tile].mask_t = shift;273274// restart the function275RDP ("restarting...\n");276GetTexInfo (id, tile);277return;278}279280line = rdp.tiles[tile].line;281if (rdp.tiles[tile].size == 3) line <<= 1;282DWORD crc = 0;283if (settings.fast_crc || bpl < 2 )284{285line = (line - wid_64) << 3;286287if (wid_64 < 1) wid_64 = 1;288unsigned char * addr = rdp.tmem + (rdp.tiles[tile].t_mem<<3);289if (height > 0)290{291292// Check the CRC293#if !defined(__GNUC__) && !defined(NO_ASM)294__asm {295xor eax,eax // eax is final result296mov ebx,dword ptr [line]297mov ecx,dword ptr [height] // ecx is height counter298mov edi,dword ptr [addr] // edi is ptr to texture memory299crc_loop_y:300push ecx301302mov ecx,dword ptr [wid_64]303crc_loop_x:304305add eax,dword ptr [edi] // MUST be 64-bit aligned, so manually unroll306add eax,dword ptr [edi+4]307mov edx,ecx308mul edx309add eax,edx310add edi,8311312dec ecx313jnz crc_loop_x314315pop ecx316317mov edx,ecx318mul edx319add eax,edx320321add edi,ebx322323dec ecx324jnz crc_loop_y325326mov dword ptr [crc],eax // store the result327}328#elif !defined(NO_ASM)329int i;330int tempheight = height;331asm volatile (332"xor %[crc], %[crc] \n" // eax is final result333"crc_loop_y: \n"334335"mov %[wid_64], %[i] \n"336"crc_loop_x: \n"337338"add (%[addr]), %[crc] \n" // MUST be 64-bit aligned, so manually unroll339"add 4(%[addr]), %[crc] \n"340"mov %[i], %%edx \n"341"mul %%edx \n" // edx:eax/crc := eax/crc * edx342"add %%edx, %[crc] \n"343"add $8, %[addr] \n"344345"dec %[i] \n"346"jnz crc_loop_x \n"347348"mov %[tempheight], %%edx \n"349"mul %%edx \n"350"add %%edx, %[crc] \n"351352"add %[line], %[addr] \n"353354"dec %[tempheight] \n"355"jnz crc_loop_y \n"356: [crc] "=&a"(crc), [i] "=&r" (i), [tempheight] "+r"(tempheight), [addr]"+r"(addr)357: [line] "g" ((intptr_t)line), [wid_64] "g" (wid_64)358: "memory", "cc", "edx"359);360#endif361// ** END CRC CHECK362}363}364else365{366crc = 0xFFFFFFFF;367// unsigned __int64 * addr = (unsigned __int64 *)&rdp.tmem[rdp.tiles[tile].t_mem];368BYTE * addr = rdp.tmem + (rdp.tiles[tile].t_mem<<3);369DWORD line2 = max(line,1);370line2 <<= 3;371for (int y = 0; y < height; y++)372{373crc = CRC_Calculate( crc, (void*)addr, bpl );374addr += line2;375}376line = (line - wid_64) << 3;377if (wid_64 < 1) wid_64 = 1;378}379if ((rdp.tiles[tile].size < 2) && (rdp.tlut_mode != 0))380{381if (rdp.tiles[tile].size == 0)382crc += rdp.pal_8_crc[rdp.tiles[tile].palette];383else384crc += rdp.pal_256_crc;385}386387388FRDP ("Done. CRC is: %08lx.\n", crc);389390DWORD flags = (rdp.tiles[tile].clamp_s << 23) | (rdp.tiles[tile].mirror_s << 22) |391(rdp.tiles[tile].mask_s << 18) | (rdp.tiles[tile].clamp_t << 17) |392(rdp.tiles[tile].mirror_t << 16) | (rdp.tiles[tile].mask_t << 12);393394info->real_image_width = real_image_width;395info->real_image_height = real_image_height;396info->tile_width = tile_width;397info->tile_height = tile_height;398info->mask_width = mask_width;399info->mask_height = mask_height;400info->width = width;401info->height = height;402info->wid_64 = wid_64;403info->line = line;404info->crc = crc;405info->flags = flags;406407// Search the texture cache for this texture408RDP (" | | |-+ Checking cache...\n");409410int t;411CACHE_LUT *cache;412413// this is the OLD cache searching, searches ALL textures414/* for (t=0; t<num_tmu; t++)415{416tex_found[id][t] = -1; // default, overwrite if found417418for (i=0; i<rdp.n_cached[t]; i++)419{420cache = &rdp.cache[t][i];421if (crc == cache->crc &&422//rdp.timg.addr == cache->addr && // not totally correct, but will help423//rdp.addr[rdp.tiles[tile].t_mem] == cache->addr && // more correct424rdp.tiles[tile].width == cache->width &&425rdp.tiles[tile].height == cache->height &&426rdp.tiles[tile].format == cache->format &&427rdp.tiles[tile].size == cache->size &&428rdp.tiles[tile].palette == cache->palette &&429pal_crc == cache->pal_crc &&430flags == cache->flags)431{432FRDP (" | | | |- Texture found in cache (tmu=%d).\n", t);433tex_found[id][t] = i;434break;435}436}437}438for (; t<MAX_TMU; t++)439{440tex_found[id][t] = -1;441}*/442443// this is the NEW cache searching, searches only textures with similar crc's444for (t=0; t<MAX_TMU; t++)445tex_found[id][t] = -1;446447if (rdp.noise == noise_texture)448return;449450DWORD mod, modcolor, modcolor1, modcolor2, modfactor;451if (id == 0)452{453mod = cmb.mod_0;454modcolor = cmb.modcolor_0;455modcolor1 = cmb.modcolor1_0;456modcolor2 = cmb.modcolor2_0;457modfactor = cmb.modfactor_0;458}459else460{461mod = cmb.mod_1;462modcolor = cmb.modcolor_1;463modcolor1 = cmb.modcolor1_1;464modcolor2 = cmb.modcolor2_1;465modfactor = cmb.modfactor_1;466}467468NODE *node = cachelut[crc>>24];469DWORD mod_mask = (rdp.tiles[tile].format == 2)?0xFFFFFFFF:0xF0F0F0F0;470while (node)471{472if (node->crc == crc)473{474cache = (CACHE_LUT*)node->data;475if (tex_found[id][node->tmu] == -1 &&476rdp.tiles[tile].width == cache->width &&477rdp.tiles[tile].height == cache->height &&478rdp.tiles[tile].format == cache->format &&479rdp.tiles[tile].size == cache->size &&480rdp.tiles[tile].palette == cache->palette &&481flags == cache->flags)482{483if (cache->mod == mod &&484(cache->mod_color&mod_mask) == (modcolor&mod_mask) &&485(cache->mod_color1&mod_mask) == (modcolor1&mod_mask) &&486(cache->mod_color2&mod_mask) == (modcolor2&mod_mask) &&487abs(static_cast<int>(cache->mod_factor - modfactor)) < 8)488{489FRDP (" | | | |- Texture found in cache (tmu=%d).\n", node->tmu);490tex_found[id][node->tmu] = node->number;491// if (rdp.addr[rdp.tiles[tile].t_mem] == cache->addr)492// return;493}494}495}496node = node->pNext;497}498499RDP (" | | | +- Done.\n | | +- GetTexInfo end\n");500}501502//****************************************************************503// ChooseBestTmu - chooses the best TMU to load to (the one with the most memory)504505int ChooseBestTmu (int tmu1, int tmu2)506{507if (!fullscreen) return tmu1;508509if (tmu1 >= num_tmu) return tmu2;510if (tmu2 >= num_tmu) return tmu1;511512if (grTexMaxAddress(tmu1)-rdp.tmem_ptr[tmu1] >513grTexMaxAddress(tmu2)-rdp.tmem_ptr[tmu2])514return tmu1;515else516return tmu2;517}518519//****************************************************************520// SelectHiresTex - select texture from texture buffer521522static void SelectHiresTex()523{524FRDP ("SelectHiresTex: tex: %d, tmu: %d, tile: %d\n", rdp.tex, rdp.hires_tex->tmu, rdp.hires_tex->tile);525grTexSource( rdp.hires_tex->tmu, rdp.hires_tex->tex_addr, GR_MIPMAPLEVELMASK_BOTH, &(rdp.hires_tex->info) );526if (rdp.tex == 3 && rdp.hires_tex->tmu == rdp.hires_tex->tile)527return;528GrCombineFunction_t color_source =529(rdp.hires_tex->info.format == GR_TEXFMT_RGB_565) ? GR_COMBINE_FUNCTION_LOCAL : GR_COMBINE_FUNCTION_LOCAL_ALPHA;530if (rdp.hires_tex->tmu == GR_TMU0)531{532grTexCombine( GR_TMU1,533GR_COMBINE_FUNCTION_NONE,534GR_COMBINE_FACTOR_NONE,535GR_COMBINE_FUNCTION_NONE,536GR_COMBINE_FACTOR_NONE,537FXFALSE,538FXFALSE );539grTexCombine( GR_TMU0,540color_source,541GR_COMBINE_FACTOR_NONE,542GR_COMBINE_FUNCTION_LOCAL,543GR_COMBINE_FACTOR_NONE,544FXFALSE,545FXFALSE);546}547else548{549grTexCombine( GR_TMU1,550color_source,551GR_COMBINE_FACTOR_NONE,552GR_COMBINE_FUNCTION_LOCAL,553GR_COMBINE_FACTOR_NONE,554FXFALSE,555FXFALSE);556grTexCombine( GR_TMU0,557GR_COMBINE_FUNCTION_SCALE_OTHER,558GR_COMBINE_FACTOR_ONE,559GR_COMBINE_FUNCTION_SCALE_OTHER,560GR_COMBINE_FACTOR_ONE,561FXFALSE,562FXFALSE );563}564}565566//****************************************************************567// TexCache - does texture loading after combiner is set568569void TexCache ()570{571RDP (" |-+ TexCache called\n");572573if (rdp.tex & 1)574GetTexInfo (0, rdp.cur_tile);575if (rdp.tex & 2)576GetTexInfo (1, rdp.cur_tile+1);577578#define TMUMODE_NORMAL 0579#define TMUMODE_PASSTHRU 1580#define TMUMODE_NONE 2581582int tmu_0, tmu_1;583int tmu_0_mode=0, tmu_1_mode=0;584585// Select the best TMUs to use (removed 3 tmu support, unnecessary)586if (rdp.tex == 3) // T0 and T1587{588tmu_0 = 0;589tmu_1 = 1;590}591else if (rdp.tex == 2) // T1592{593if (tex_found[1][0] != -1) // T1 found in tmu 0594tmu_1 = 0;595else if (tex_found[1][1] != -1) // T1 found in tmu 1596tmu_1 = 1;597else // T1 not found598tmu_1 = ChooseBestTmu (0, 1);599600tmu_0 = !tmu_1;601tmu_0_mode = (tmu_0==1)?TMUMODE_NONE:TMUMODE_PASSTHRU;602}603else if (rdp.tex == 1) // T0604{605if (tex_found[0][0] != -1) // T0 found in tmu 0606tmu_0 = 0;607else if (tex_found[0][1] != -1) // T0 found in tmu 1608tmu_0 = 1;609else // T0 not found610tmu_0 = ChooseBestTmu (0, 1);611612tmu_1 = !tmu_0;613tmu_1_mode = (tmu_1==1)?TMUMODE_NONE:TMUMODE_PASSTHRU;614}615else // no texture616{617tmu_0 = 0;618tmu_0_mode = TMUMODE_NONE;619tmu_1 = 0;620tmu_1_mode = TMUMODE_NONE;621}622623FRDP (" | |-+ Modes set:\n | | |- tmu_0 = %d\n | | |- tmu_1 = %d\n",624tmu_0, tmu_1);625FRDP (" | | |- tmu_0_mode = %d\n | | |- tmu_1_mode = %d\n",626tmu_0_mode, tmu_1_mode);627628if (tmu_0_mode == TMUMODE_PASSTHRU) {629cmb.tmu0_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_SCALE_OTHER;630cmb.tmu0_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_ONE;631if (cmb.tex_cmb_ext_use)632{633cmb.t0c_ext_a = GR_CMBX_OTHER_TEXTURE_RGB;634cmb.t0c_ext_a_mode = GR_FUNC_MODE_X;635cmb.t0c_ext_b = GR_CMBX_LOCAL_TEXTURE_RGB;636cmb.t0c_ext_b_mode = GR_FUNC_MODE_ZERO;637cmb.t0c_ext_c = GR_CMBX_ZERO;638cmb.t0c_ext_c_invert = 1;639cmb.t0c_ext_d = GR_CMBX_ZERO;640cmb.t0c_ext_d_invert = 0;641cmb.t0a_ext_a = GR_CMBX_OTHER_TEXTURE_ALPHA;642cmb.t0a_ext_a_mode = GR_FUNC_MODE_X;643cmb.t0a_ext_b = GR_CMBX_LOCAL_TEXTURE_ALPHA;644cmb.t0a_ext_b_mode = GR_FUNC_MODE_ZERO;645cmb.t0a_ext_c = GR_CMBX_ZERO;646cmb.t0a_ext_c_invert = 1;647cmb.t0a_ext_d = GR_CMBX_ZERO;648cmb.t0a_ext_d_invert = 0;649}650}651else if (tmu_0_mode == TMUMODE_NONE) {652cmb.tmu0_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_NONE;653cmb.tmu0_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_NONE;654if (cmb.tex_cmb_ext_use)655{656cmb.t0c_ext_a = GR_CMBX_LOCAL_TEXTURE_RGB;657cmb.t0c_ext_a_mode = GR_FUNC_MODE_ZERO;658cmb.t0c_ext_b = GR_CMBX_LOCAL_TEXTURE_RGB;659cmb.t0c_ext_b_mode = GR_FUNC_MODE_ZERO;660cmb.t0c_ext_c = GR_CMBX_ZERO;661cmb.t0c_ext_c_invert = 0;662cmb.t0c_ext_d = GR_CMBX_ZERO;663cmb.t0c_ext_d_invert = 0;664cmb.t0a_ext_a = GR_CMBX_LOCAL_TEXTURE_ALPHA;665cmb.t0a_ext_a_mode = GR_FUNC_MODE_ZERO;666cmb.t0a_ext_b = GR_CMBX_LOCAL_TEXTURE_ALPHA;667cmb.t0a_ext_b_mode = GR_FUNC_MODE_ZERO;668cmb.t0a_ext_c = GR_CMBX_ZERO;669cmb.t0a_ext_c_invert = 0;670cmb.t0a_ext_d = GR_CMBX_ZERO;671cmb.t0a_ext_d_invert = 0;672}673}674if (tmu_1_mode == TMUMODE_PASSTHRU) {675cmb.tmu1_func = cmb.tmu1_a_func = GR_COMBINE_FUNCTION_SCALE_OTHER;676cmb.tmu1_fac = cmb.tmu1_a_fac = GR_COMBINE_FACTOR_ONE;677if (cmb.tex_cmb_ext_use)678{679cmb.t1c_ext_a = GR_CMBX_OTHER_TEXTURE_RGB;680cmb.t1c_ext_a_mode = GR_FUNC_MODE_X;681cmb.t1c_ext_b = GR_CMBX_LOCAL_TEXTURE_RGB;682cmb.t1c_ext_b_mode = GR_FUNC_MODE_ZERO;683cmb.t1c_ext_c = GR_CMBX_ZERO;684cmb.t1c_ext_c_invert = 1;685cmb.t1c_ext_d = GR_CMBX_ZERO;686cmb.t1c_ext_d_invert = 0;687cmb.t1a_ext_a = GR_CMBX_OTHER_TEXTURE_ALPHA;688cmb.t1a_ext_a_mode = GR_FUNC_MODE_X;689cmb.t1a_ext_b = GR_CMBX_LOCAL_TEXTURE_ALPHA;690cmb.t1a_ext_b_mode = GR_FUNC_MODE_ZERO;691cmb.t1a_ext_c = GR_CMBX_ZERO;692cmb.t1a_ext_c_invert = 1;693cmb.t1a_ext_d = GR_CMBX_ZERO;694cmb.t1a_ext_d_invert = 0;695}696}697else if (tmu_1_mode == TMUMODE_NONE) {698cmb.tmu1_func = cmb.tmu1_a_func = GR_COMBINE_FUNCTION_NONE;699cmb.tmu1_fac = cmb.tmu1_a_fac = GR_COMBINE_FACTOR_NONE;700if (cmb.tex_cmb_ext_use)701{702cmb.t1c_ext_a = GR_CMBX_LOCAL_TEXTURE_RGB;703cmb.t1c_ext_a_mode = GR_FUNC_MODE_ZERO;704cmb.t1c_ext_b = GR_CMBX_LOCAL_TEXTURE_RGB;705cmb.t1c_ext_b_mode = GR_FUNC_MODE_ZERO;706cmb.t1c_ext_c = GR_CMBX_ZERO;707cmb.t1c_ext_c_invert = 0;708cmb.t1c_ext_d = GR_CMBX_ZERO;709cmb.t1c_ext_d_invert = 0;710cmb.t1a_ext_a = GR_CMBX_LOCAL_TEXTURE_ALPHA;711cmb.t1a_ext_a_mode = GR_FUNC_MODE_ZERO;712cmb.t1a_ext_b = GR_CMBX_LOCAL_TEXTURE_ALPHA;713cmb.t1a_ext_b_mode = GR_FUNC_MODE_ZERO;714cmb.t1a_ext_c = GR_CMBX_ZERO;715cmb.t1a_ext_c_invert = 0;716cmb.t1a_ext_d = GR_CMBX_ZERO;717cmb.t1a_ext_d_invert = 0;718}719}720721// little change to make single-tmu cards look better, use first texture no matter what722723if (num_tmu == 1)724{725if (rdp.best_tex == 0)726{727cmb.tmu0_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_LOCAL;728cmb.tmu0_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_NONE;729tmu_0 = 0;730tmu_1 = 1;731}732else733{734cmb.tmu1_func = cmb.tmu1_a_func = GR_COMBINE_FUNCTION_LOCAL;735cmb.tmu1_fac = cmb.tmu1_a_fac = GR_COMBINE_FACTOR_NONE;736tmu_1 = 0;737tmu_0 = 1;738}739}740741742rdp.t0 = tmu_0;743rdp.t1 = tmu_1;744745// SET the combiner746if (fullscreen)747{748if (rdp.allow_combine)749{750// Now actually combine751if (cmb.cmb_ext_use)752{753RDP (" | | | |- combiner extension\n");754if (!(cmb.cmb_ext_use & COMBINE_EXT_COLOR))755ColorCombinerToExtension ();756if (!(cmb.cmb_ext_use & COMBINE_EXT_ALPHA))757AlphaCombinerToExtension ();758cmb.grColorCombineExt(cmb.c_ext_a, cmb.c_ext_a_mode,759cmb.c_ext_b, cmb.c_ext_b_mode,760cmb.c_ext_c, cmb.c_ext_c_invert,761cmb.c_ext_d, cmb.c_ext_d_invert, 0, 0);762cmb.grAlphaCombineExt(cmb.a_ext_a, cmb.a_ext_a_mode,763cmb.a_ext_b, cmb.a_ext_b_mode,764cmb.a_ext_c, cmb.a_ext_c_invert,765cmb.a_ext_d, cmb.a_ext_d_invert, 0, 0);766}767else768{769grColorCombine (cmb.c_fnc, cmb.c_fac, cmb.c_loc, cmb.c_oth, FXFALSE);770grAlphaCombine (cmb.a_fnc, cmb.a_fac, cmb.a_loc, cmb.a_oth, FXFALSE);771}772grConstantColorValue (cmb.ccolor);773grAlphaBlendFunction (cmb.abf1, cmb.abf2, GR_BLEND_ZERO, GR_BLEND_ZERO);774}775776if (tmu_1 < num_tmu)777{778if (cmb.tex_cmb_ext_use)779{780RDP (" | | | |- combiner extension tmu1\n");781if (!(cmb.tex_cmb_ext_use & TEX_COMBINE_EXT_COLOR))782TexColorCombinerToExtension (GR_TMU1);783if (!(cmb.tex_cmb_ext_use & TEX_COMBINE_EXT_ALPHA))784TexAlphaCombinerToExtension (GR_TMU1);785cmb.grTexColorCombineExt(tmu_1, cmb.t1c_ext_a, cmb.t1c_ext_a_mode,786cmb.t1c_ext_b, cmb.t1c_ext_b_mode,787cmb.t1c_ext_c, cmb.t1c_ext_c_invert,788cmb.t1c_ext_d, cmb.t1c_ext_d_invert, 0, 0);789cmb.grTexAlphaCombineExt(tmu_1, cmb.t1a_ext_a, cmb.t1a_ext_a_mode,790cmb.t1a_ext_b, cmb.t1a_ext_b_mode,791cmb.t1a_ext_c, cmb.t1a_ext_c_invert,792cmb.t1a_ext_d, cmb.t1a_ext_d_invert, 0, 0);793cmb.grConstantColorValueExt(tmu_1, cmb.tex_ccolor);794}795else796{797grTexCombine (tmu_1, cmb.tmu1_func, cmb.tmu1_fac, cmb.tmu1_a_func, cmb.tmu1_a_fac, cmb.tmu1_invert, cmb.tmu1_a_invert);798if (cmb.combine_ext)799cmb.grConstantColorValueExt(tmu_1, 0);800}801grTexDetailControl (tmu_1, cmb.dc1_lodbias, cmb.dc1_detailscale, cmb.dc1_detailmax);802grTexLodBiasValue (tmu_1, cmb.lodbias1);803}804if (tmu_0 < num_tmu)805{806if (cmb.tex_cmb_ext_use)807{808RDP (" | | | |- combiner extension tmu0\n");809if (!(cmb.tex_cmb_ext_use & TEX_COMBINE_EXT_COLOR))810TexColorCombinerToExtension (GR_TMU0);811if (!(cmb.tex_cmb_ext_use & TEX_COMBINE_EXT_ALPHA))812TexAlphaCombinerToExtension (GR_TMU0);813cmb.grTexColorCombineExt(tmu_0, cmb.t0c_ext_a, cmb.t0c_ext_a_mode,814cmb.t0c_ext_b, cmb.t0c_ext_b_mode,815cmb.t0c_ext_c, cmb.t0c_ext_c_invert,816cmb.t0c_ext_d, cmb.t0c_ext_d_invert, 0, 0);817cmb.grTexAlphaCombineExt(tmu_0, cmb.t0a_ext_a, cmb.t0a_ext_a_mode,818cmb.t0a_ext_b, cmb.t0a_ext_b_mode,819cmb.t0a_ext_c, cmb.t0a_ext_c_invert,820cmb.t0a_ext_d, cmb.t0a_ext_d_invert, 0, 0);821cmb.grConstantColorValueExt(tmu_0, cmb.tex_ccolor);822}823else824{825grTexCombine (tmu_0, cmb.tmu0_func, cmb.tmu0_fac, cmb.tmu0_a_func, cmb.tmu0_a_fac, cmb.tmu0_invert, cmb.tmu0_a_invert);826if (cmb.combine_ext)827cmb.grConstantColorValueExt(tmu_0, 0);828}829grTexDetailControl (tmu_0, cmb.dc0_lodbias, cmb.dc0_detailscale, cmb.dc0_detailmax);830grTexLodBiasValue (tmu_0, cmb.lodbias0);831}832}833834if ((rdp.tex & 1) && tmu_0 < num_tmu)835{836if (tex_found[0][tmu_0] != -1)837{838RDP (" | |- T0 found in cache.\n");839if (fullscreen)840{841CACHE_LUT *cache = &rdp.cache[tmu_0][tex_found[0][tmu_0]];842rdp.cur_cache_n[0] = tex_found[0][tmu_0];843rdp.cur_cache[0] = cache;844rdp.cur_cache[0]->last_used = frame_count;845rdp.cur_cache[0]->uses = rdp.debug_n;846grTexSource (tmu_0,847(grTexMinAddress(tmu_0) + cache->tmem_addr),848GR_MIPMAPLEVELMASK_BOTH,849&cache->t_info);850}851}852else853LoadTex (0, tmu_0);854}855if ((rdp.tex & 2) && tmu_1 < num_tmu)856{857if (tex_found[1][tmu_1] != -1)858{859if (fullscreen)860{861CACHE_LUT *cache = &rdp.cache[tmu_1][tex_found[1][tmu_1]];862rdp.cur_cache_n[1] = tex_found[1][tmu_1];863rdp.cur_cache[1] = cache;864rdp.cur_cache[1]->last_used = frame_count;865rdp.cur_cache[1]->uses = rdp.debug_n;866grTexSource (tmu_1,867(grTexMinAddress(tmu_1) + cache->tmem_addr),868GR_MIPMAPLEVELMASK_BOTH,869&cache->t_info);870}871}872else873LoadTex (1, tmu_1);874}875876if (fullscreen)877{878for (int i=0; i<2; i++)879{880int tmu;881if (i==0) tmu=tmu_0;882else tmu=tmu_1;883884if (tmu >= num_tmu) continue;885886int tile = rdp.cur_tile + i;887888if (settings.filtering == 0)889{890int filter = (rdp.filter_mode!=2)?GR_TEXTUREFILTER_POINT_SAMPLED:GR_TEXTUREFILTER_BILINEAR;891grTexFilterMode (tmu, filter, filter);892}893else894{895int filter = (settings.filtering==1)?GR_TEXTUREFILTER_BILINEAR:GR_TEXTUREFILTER_POINT_SAMPLED;896grTexFilterMode (tmu, filter, filter);897}898899DWORD mode_s, mode_t;900901if ((rdp.tiles[tile].clamp_s || rdp.tiles[tile].mask_s == 0) &&902rdp.tiles[tile].lr_s-rdp.tiles[tile].ul_s < 256)903mode_s = GR_TEXTURECLAMP_CLAMP;904else905{906if (rdp.tiles[tile].mirror_s && sup_mirroring)907mode_s = GR_TEXTURECLAMP_MIRROR_EXT;908else909mode_s = GR_TEXTURECLAMP_WRAP;910}911912if ((rdp.tiles[tile].clamp_t || rdp.tiles[tile].mask_t == 0) &&913rdp.tiles[tile].lr_t-rdp.tiles[tile].ul_t < 256)914mode_t = GR_TEXTURECLAMP_CLAMP;915else916{917if (rdp.tiles[tile].mirror_t && sup_mirroring)918mode_t = GR_TEXTURECLAMP_MIRROR_EXT;919else920mode_t = GR_TEXTURECLAMP_WRAP;921}922923grTexClampMode (tmu,924mode_s,925mode_t);926}927if (rdp.hires_tex)928SelectHiresTex();929}930931RDP (" | +- TexCache End\n");932}933934//****************************************************************935// ClearCache - clear the texture cache for BOTH tmus936937void ClearCache ()938{939rdp.tmem_ptr[0] = offset_textures;940rdp.n_cached[0] = 0;941rdp.tmem_ptr[1] = offset_texbuf1;942rdp.n_cached[1] = 0;943944for (int i=0; i<256; i++)945{946DeleteList (&cachelut[i]);947}948}949950//****************************************************************951// LoadTex - does the actual texture loading after everything is prepared952953void LoadTex (int id, int tmu)954{955FRDP (" | |-+ LoadTex (id: %d, tmu: %d)\n", id, tmu);956957int td = rdp.cur_tile + id;958int lod, aspect;959CACHE_LUT *cache;960961if (texinfo[id].width < 0 ||962texinfo[id].height < 0) return;963964// Clear the cache if it's full965if (rdp.n_cached[tmu] >= MAX_CACHE)966{967RDP ("Cache count reached, clearing...\n");968ClearCache ();969if (id == 1 && rdp.tex == 3)970LoadTex (0, rdp.t0);971}972973// Get this cache object974cache = &rdp.cache[tmu][rdp.n_cached[tmu]];975rdp.cur_cache[id] = cache;976rdp.cur_cache_n[id] = rdp.n_cached[tmu];977978// Set the data979cache->line = rdp.tiles[td].line;980cache->addr = rdp.addr[rdp.tiles[td].t_mem];981cache->crc = texinfo[id].crc;982cache->palette = rdp.tiles[td].palette;983cache->width = rdp.tiles[td].width;984cache->height = rdp.tiles[td].height;985cache->format = rdp.tiles[td].format;986cache->size = rdp.tiles[td].size;987cache->tmem_addr = rdp.tmem_ptr[tmu];988cache->set_by = rdp.timg.set_by;989cache->texrecting = rdp.texrecting;990cache->last_used = frame_count;991cache->uses = rdp.debug_n;992cache->flags = texinfo[id].flags;993994// Add this cache to the list995AddToList (&cachelut[cache->crc>>24], cache->crc, cache, tmu, rdp.n_cached[tmu]);996997rdp.n_cached[tmu] ++;998999// temporary1000cache->t_info.format = GR_TEXFMT_ARGB_1555;10011002// Calculate lod and aspect1003DWORD size_x = rdp.tiles[td].width;1004DWORD size_y = rdp.tiles[td].height;10051006// make size_x and size_y both powers of two1007if (size_x > 256) size_x = 256;1008if (size_y > 256) size_y = 256;10091010int shift;1011for (shift=0; (1<<shift) < (int)size_x; shift++);1012size_x = 1 << shift;1013for (shift=0; (1<<shift) < (int)size_y; shift++);1014size_y = 1 << shift;10151016// Voodoo 1 support is all here, it will automatically mirror to the full extent.1017if (!sup_mirroring)1018{1019if (rdp.tiles[td].mirror_s && !rdp.tiles[td].clamp_s && size_x <= 128)1020size_x <<= 1;1021if (rdp.tiles[td].mirror_t && !rdp.tiles[td].clamp_t && size_y <= 128)1022size_y <<= 1;1023}10241025// Calculate the maximum size1026int size_max = max (size_x, size_y);1027DWORD real_x=size_max, real_y=size_max;1028switch (size_max)1029{1030case 1:1031lod = GR_LOD_LOG2_1;1032cache->scale = 256.0f;1033break;1034case 2:1035lod = GR_LOD_LOG2_2;1036cache->scale = 128.0f;1037break;1038case 4:1039lod = GR_LOD_LOG2_4;1040cache->scale = 64.0f;1041break;1042case 8:1043lod = GR_LOD_LOG2_8;1044cache->scale = 32.0f;1045break;1046case 16:1047lod = GR_LOD_LOG2_16;1048cache->scale = 16.0f;1049break;1050case 32:1051lod = GR_LOD_LOG2_32;1052cache->scale = 8.0f;1053break;1054case 64:1055lod = GR_LOD_LOG2_64;1056cache->scale = 4.0f;1057break;1058case 128:1059lod = GR_LOD_LOG2_128;1060cache->scale = 2.0f;1061break;1062//case 256:1063default:1064lod = GR_LOD_LOG2_256;1065cache->scale = 1.0f;1066break;10671068// No default here, can't be a non-power of two, see above1069}10701071// Calculate the aspect ratio1072if (size_x >= size_y)1073{1074int ratio = size_x / size_y;1075switch (ratio)1076{1077case 1:1078aspect = GR_ASPECT_LOG2_1x1;1079cache->scale_x = 1.0f;1080cache->scale_y = 1.0f;1081break;1082case 2:1083aspect = GR_ASPECT_LOG2_2x1;1084cache->scale_x = 1.0f;1085cache->scale_y = 0.5f;1086real_y >>= 1;1087break;1088case 4:1089aspect = GR_ASPECT_LOG2_4x1;1090cache->scale_x = 1.0f;1091cache->scale_y = 0.25f;1092real_y >>= 2;1093break;1094//case 8:1095default:1096aspect = GR_ASPECT_LOG2_8x1;1097cache->scale_x = 1.0f;1098cache->scale_y = 0.125f;1099real_y >>= 3;1100break;1101}1102}1103else1104{1105int ratio = size_y / size_x;1106switch (ratio)1107{1108case 2:1109aspect = GR_ASPECT_LOG2_1x2;1110cache->scale_x = 0.5f;1111cache->scale_y = 1.0f;1112real_x >>= 1;1113break;1114case 4:1115aspect = GR_ASPECT_LOG2_1x4;1116cache->scale_x = 0.25f;1117cache->scale_y = 1.0f;1118real_x >>= 2;1119break;1120//case 8:1121default:1122aspect = GR_ASPECT_LOG2_1x8;1123cache->scale_x = 0.125f;1124cache->scale_y = 1.0f;1125real_x >>= 3;1126break;1127}1128}11291130if (real_x != cache->width || real_y != cache->height)1131{1132cache->scale_x *= (float)cache->width / (float)real_x;1133cache->scale_y *= (float)cache->height / (float)real_y;1134}11351136int splits = texinfo[id].splits;1137cache->splits = texinfo[id].splits;1138cache->splitheight = real_y / cache->splits;1139if (cache->splitheight < texinfo[id].splitheight)1140cache->splitheight = texinfo[id].splitheight;11411142// ** Calculate alignment values1143int wid = cache->width;1144int hei = cache->height;11451146if (splits > 1)1147{1148wid = texinfo[id].real_image_width;1149hei = texinfo[id].real_image_height;1150}11511152float center_off = cache->scale / 2.0f;1153float c_lr_x = (float)real_x*cache->scale - center_off;1154float c_lr_y = (float)real_y*cache->scale - center_off;1155float c_scl_x;1156if (real_x != 1) c_scl_x = (c_lr_x - center_off) / (real_x-1);1157else c_scl_x = 0.0f;1158float c_scl_y;1159if (real_y != 1) c_scl_y = (c_lr_y - center_off) / (real_y-1);1160else c_scl_y = 0.0f;1161c_lr_x = center_off + c_scl_x * (wid-1);1162c_lr_y = center_off + c_scl_y * (hei-1);1163cache->c_off = center_off;1164if (wid != 1) cache->c_scl_x = (c_lr_x - center_off) / (float)(wid-1);1165else cache->c_scl_x = 0.0f;1166if (hei != 1) cache->c_scl_y = (c_lr_y - center_off) / (float)(hei-1);1167else cache->c_scl_y = 0.0f;1168// **11691170DWORD mod, modcolor, modcolor1, modcolor2, modfactor;1171if (id == 0)1172{1173mod = cmb.mod_0;1174modcolor = cmb.modcolor_0;1175modcolor1 = cmb.modcolor1_0;1176modcolor2 = cmb.modcolor2_0;1177modfactor = cmb.modfactor_0;1178}1179else1180{1181mod = cmb.mod_1;1182modcolor = cmb.modcolor_1;1183modcolor1 = cmb.modcolor1_1;1184modcolor2 = cmb.modcolor2_1;1185modfactor = cmb.modfactor_1;1186}11871188WORD tmp_pal[256];1189BOOL modifyPalette = (mod && (cache->format == 2) && (rdp.tlut_mode == 2));11901191if (modifyPalette)1192{1193memcpy(tmp_pal, rdp.pal_8, 512);1194ModifyPalette(mod, modcolor, modcolor1, modfactor);1195}11961197cache->mod = mod;1198cache->mod_color = modcolor;1199cache->mod_color1 = modcolor1;1200cache->mod_factor = modfactor;12011202if (rdp.hires_tex && rdp.hires_tex->tile == id) //texture buffer will be used instead of frame buffer texture1203{1204RDP("hires_tex selected\n");1205return;1206}12071208DWORD result = 0; // keep =0 so it doesn't mess up on the first split12091210texture = tex1;12111212// ** handle texture splitting **1213if (splits > 1)1214{1215cache->scale_y = 0.125f;12161217int i;1218for (i=0; i<splits; i++)1219{1220int start_dst = i * cache->splitheight * 256; // start lower1221start_dst <<= HIWORD(result); // 1st time, result is set to 0, but start_dst is 0 anyway so it doesn't matter12221223int start_src = i * 256; // start 256 more to the right1224start_src = start_src << (rdp.tiles[td].size) >> 1;12251226result = load_table[rdp.tiles[td].size][rdp.tiles[td].format]1227(texture+start_dst, rdp.tmem+(rdp.tiles[td].t_mem<<3)+start_src,1228texinfo[id].wid_64, texinfo[id].height, texinfo[id].line, real_x, td);12291230DWORD size = HIWORD(result);1231// clamp so that it looks somewhat ok when wrapping1232if (size == 1)1233Clamp16bT (texture+start_dst, texinfo[id].height, real_x, cache->splitheight);1234else1235Clamp8bT (texture+start_dst, texinfo[id].height, real_x, cache->splitheight);1236}1237}1238// ** end texture splitting **1239else1240{1241result = load_table[rdp.tiles[td].size][rdp.tiles[td].format]1242(texture, rdp.tmem+(rdp.tiles[td].t_mem<<3),1243texinfo[id].wid_64, texinfo[id].height, texinfo[id].line, real_x, td);12441245DWORD size = HIWORD(result);12461247int min_x, min_y;1248if (rdp.tiles[td].mask_s != 0)1249min_x = min((int)real_x, 1<<rdp.tiles[td].mask_s);1250else1251min_x = real_x;1252if (rdp.tiles[td].mask_t != 0)1253min_y = min((int)real_y, 1<<rdp.tiles[td].mask_t);1254else1255min_y = real_y;12561257// Load using mirroring/clamping1258if (min_x > texinfo[id].width)1259{1260if (size == 1)1261Clamp16bS (texture, texinfo[id].width, min_x, real_x, texinfo[id].height);1262else1263Clamp8bS (texture, texinfo[id].width, min_x, real_x, texinfo[id].height);1264}12651266if (texinfo[id].width < (int)real_x)1267{1268if (rdp.tiles[td].mirror_s)1269{1270if (size == 1)1271Mirror16bS (texture, rdp.tiles[td].mask_s,1272real_x, real_x, texinfo[id].height);1273else1274Mirror8bS (texture, rdp.tiles[td].mask_s,1275real_x, real_x, texinfo[id].height);1276}1277else1278{1279if (size == 1)1280Wrap16bS (texture, rdp.tiles[td].mask_s,1281real_x, real_x, texinfo[id].height);1282else1283Wrap8bS (texture, rdp.tiles[td].mask_s,1284real_x, real_x, texinfo[id].height);1285}1286}12871288if (min_y > texinfo[id].height)1289{1290if (size == 1)1291Clamp16bT (texture, texinfo[id].height, real_x, min_y);1292else1293Clamp8bT (texture, texinfo[id].height, real_x, min_y);1294}12951296if (texinfo[id].height < (int)real_y)1297{1298if (rdp.tiles[td].mirror_t)1299{1300if (size == 1)1301Mirror16bT (texture, rdp.tiles[td].mask_t,1302real_y, real_x);1303else1304Mirror8bT (texture, rdp.tiles[td].mask_t,1305real_y, real_x);1306}1307else1308{1309if (size == 1)1310Wrap16bT (texture, rdp.tiles[td].mask_t,1311real_y, real_x);1312else1313Wrap8bT (texture, rdp.tiles[td].mask_t,1314real_y, real_x);1315}1316}1317}13181319if (modifyPalette)1320{1321memcpy(rdp.pal_8, tmp_pal, 512);1322}13231324if (mod && !modifyPalette)1325{1326// Convert the texture to ARGB 44441327if (LOWORD(result) == GR_TEXFMT_ARGB_1555)1328TexConv_ARGB1555_ARGB4444 (tex1, tex2, real_x, real_y);1329if (LOWORD(result) == GR_TEXFMT_ALPHA_INTENSITY_88)1330TexConv_AI88_ARGB4444 (tex1, tex2, real_x, real_y);1331if (LOWORD(result) == GR_TEXFMT_ALPHA_INTENSITY_44)1332TexConv_AI44_ARGB4444 (tex1, tex2, real_x, real_y);1333if (LOWORD(result) == GR_TEXFMT_ALPHA_8)1334TexConv_A8_ARGB4444 (tex1, tex2, real_x, real_y);1335if (LOWORD(result) == GR_TEXFMT_ARGB_4444)1336memcpy (tex2, tex1, (real_x*real_y) << 1);1337texture = tex2;1338result = (1 << 16) | GR_TEXFMT_ARGB_4444;13391340// Now convert the color to the same1341modcolor = ((modcolor & 0xF0000000) >> 16) | ((modcolor & 0x00F00000) >> 12) |1342((modcolor & 0x0000F000) >> 8) | ((modcolor & 0x000000F0) >> 4);1343modcolor1 = ((modcolor1 & 0xF0000000) >> 16) | ((modcolor1 & 0x00F00000) >> 12) |1344((modcolor1 & 0x0000F000) >> 8) | ((modcolor1 & 0x000000F0) >> 4);1345modcolor2 = ((modcolor2 & 0xF0000000) >> 16) | ((modcolor2 & 0x00F00000) >> 12) |1346((modcolor2 & 0x0000F000) >> 8) | ((modcolor2 & 0x000000F0) >> 4);13471348int size = (real_x * real_y) << 1;13491350switch (mod)1351{1352case TMOD_TEX_INTER_COLOR_USING_FACTOR:1353mod_tex_inter_color_using_factor ((WORD*)tex2, size, modcolor, modfactor);1354break;1355case TMOD_TEX_INTER_COL_USING_COL1:1356mod_tex_inter_col_using_col1 ((WORD*)tex2, size, modcolor, modcolor1);1357break;1358case TMOD_FULL_COLOR_SUB_TEX:1359mod_full_color_sub_tex ((WORD*)tex2, size, modcolor);1360break;1361case TMOD_COL_INTER_COL1_USING_TEX:1362mod_col_inter_col1_using_tex ((WORD*)tex2, size, modcolor, modcolor1);1363break;1364case TMOD_COL_INTER_COL1_USING_TEXA:1365mod_col_inter_col1_using_texa ((WORD*)tex2, size, modcolor, modcolor1);1366break;1367case TMOD_COL_INTER_COL1_USING_TEXA__MUL_TEX:1368mod_col_inter_col1_using_texa__mul_tex ((WORD*)tex2, size, modcolor, modcolor1);1369break;1370case TMOD_COL_INTER_TEX_USING_TEXA:1371mod_col_inter_tex_using_texa ((WORD*)tex2, size, modcolor);1372break;1373case TMOD_COL2_INTER__COL_INTER_COL1_USING_TEX__USING_TEXA:1374mod_col2_inter__col_inter_col1_using_tex__using_texa ((WORD*)tex2, size, modcolor, modcolor1, modcolor2);1375break;1376case TMOD_TEX_SCALE_FAC_ADD_FAC:1377mod_tex_scale_fac_add_fac ((WORD*)tex2, size, modfactor);1378break;1379case TMOD_TEX_SUB_COL_MUL_FAC_ADD_TEX:1380mod_tex_sub_col_mul_fac_add_tex ((WORD*)tex2, size, modcolor, modfactor);1381break;1382case TMOD_TEX_SCALE_COL_ADD_COL:1383mod_tex_scale_col_add_col ((WORD*)tex2, size, modcolor, modfactor);1384break;1385case TMOD_TEX_ADD_COL:1386mod_tex_add_col ((WORD*)tex2, size, modcolor);1387break;1388case TMOD_TEX_SUB_COL:1389mod_tex_sub_col ((WORD*)tex2, size, modcolor);1390break;1391case TMOD_TEX_SUB_COL_MUL_FAC:1392mod_tex_sub_col_mul_fac ((WORD*)tex2, size, modcolor, modfactor);1393break;1394case TMOD_COL_INTER_TEX_USING_COL1:1395mod_col_inter_tex_using_col1 ((WORD*)tex2, size, modcolor, modcolor1);1396break;1397case TMOD_COL_MUL_TEXA_ADD_TEX:1398mod_col_mul_texa_add_tex((WORD*)tex2, size, modcolor);1399break;1400case TMOD_COL_INTER_TEX_USING_TEX:1401mod_col_inter_tex_using_tex ((WORD*)tex2, size, modcolor);1402break;1403case TMOD_TEX_INTER_NOISE_USING_COL:1404mod_tex_inter_noise_using_col ((WORD*)tex2, size, modcolor);1405break;1406case TMOD_TEX_INTER_COL_USING_TEXA:1407mod_tex_inter_col_using_texa ((WORD*)tex2, size, modcolor);1408break;1409case TMOD_TEX_MUL_COL:1410mod_tex_mul_col ((WORD*)tex2, size, modcolor);1411break;1412case TMOD_TEX_SCALE_FAC_ADD_COL:1413mod_tex_scale_fac_add_col ((WORD*)tex2, size, modcolor, modfactor);1414break;1415default:1416;1417}1418}141914201421cache->t_info.format = LOWORD(result);14221423cache->realwidth = real_x;1424cache->realheight = real_y;1425cache->lod = lod;1426cache->aspect = aspect;14271428if (fullscreen)1429{1430// Load the texture into texture memory1431GrTexInfo *t_info = &cache->t_info;1432t_info->data = texture;1433t_info->smallLodLog2 = lod;1434t_info->largeLodLog2 = lod;1435t_info->aspectRatioLog2 = aspect;14361437DWORD texture_size = grTexTextureMemRequired (GR_MIPMAPLEVELMASK_BOTH, t_info);14381439// Check for 2mb boundary1440if ((rdp.tmem_ptr[tmu] < TEXMEM_2MB_EDGE) && (rdp.tmem_ptr[tmu]+texture_size > TEXMEM_2MB_EDGE))1441{1442rdp.tmem_ptr[tmu] = TEXMEM_2MB_EDGE;1443cache->tmem_addr = rdp.tmem_ptr[tmu];1444}14451446// Check for end of memory (too many textures to fit, clear cache)1447if (rdp.tmem_ptr[tmu]+texture_size >= grTexMaxAddress(tmu))1448{1449RDP ("Cache size reached, clearing...\n");1450ClearCache ();14511452if (id == 1 && rdp.tex == 3)1453LoadTex (0, rdp.t0);14541455LoadTex (id, tmu);1456return;1457// DON'T CONTINUE (already done)1458}14591460grTexDownloadMipMap (tmu,1461grTexMinAddress(tmu) + rdp.tmem_ptr[tmu],1462GR_MIPMAPLEVELMASK_BOTH,1463t_info);14641465grTexSource (tmu,1466grTexMinAddress(tmu) + rdp.tmem_ptr[tmu],1467GR_MIPMAPLEVELMASK_BOTH,1468t_info);1469rdp.tmem_ptr[tmu] += texture_size;1470}14711472RDP (" | | +- LoadTex end\n");1473}1474147514761477