forked from dolphin-emu/dolphin
		
	
		
			
				
	
	
		
			225 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			225 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (C) 2003-2009 Dolphin Project.
 | |
| 
 | |
| // This program is free software: you can redistribute it and/or modify
 | |
| // it under the terms of the GNU General Public License as published by
 | |
| // the Free Software Foundation, version 2.0.
 | |
| // This program is distributed in the hope that it will be useful,
 | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| // GNU General Public License 2.0 for more details.
 | |
| 
 | |
| // A copy of the GPL 2.0 should have been included with the program.
 | |
| // If not, see http://www.gnu.org/licenses/
 | |
| 
 | |
| // Official SVN repository and contact information can be found at
 | |
| // http://code.google.com/p/dolphin-emu/
 | |
| 
 | |
| 
 | |
| #include "TextureSampler.h"
 | |
| 
 | |
| #include "BPMemLoader.h"
 | |
| #include "TextureDecoder.h"
 | |
| #include "HW/Memmap.h"
 | |
| 
 | |
| #include <cmath>
 | |
| 
 | |
| #define ALLOW_MIPMAP 1
 | |
| 
 | |
| namespace TextureSampler
 | |
| {
 | |
| 
 | |
| inline void WrapCoord(int &coord, int wrapMode, int imageSize)
 | |
| {
 | |
|     switch (wrapMode)
 | |
|     {
 | |
|         case 0: // clamp
 | |
|             coord = (coord>imageSize)?imageSize:(coord<0)?0:coord;
 | |
|             break;
 | |
|         case 1: // wrap
 | |
|             coord = coord % (imageSize + 1);
 | |
|             coord = (coord<0)?imageSize+coord:coord;
 | |
|             break;
 | |
|         case 2: // mirror
 | |
|             {
 | |
|                 int sizePlus1 = imageSize + 1;
 | |
|                 int div = coord / sizePlus1;
 | |
|                 coord = coord - (div * sizePlus1);
 | |
|                 coord = (coord<0)?-coord:coord;
 | |
|                 coord = (div&1)?imageSize - coord:coord;
 | |
|             }
 | |
|             break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| inline void SetTexel(u8 *inTexel, u32 *outTexel, u32 fract)
 | |
| {
 | |
|     outTexel[0] = inTexel[0] * fract;
 | |
|     outTexel[1] = inTexel[1] * fract;
 | |
|     outTexel[2] = inTexel[2] * fract;
 | |
|     outTexel[3] = inTexel[3] * fract;
 | |
| }
 | |
| 
 | |
| inline void AddTexel(u8 *inTexel, u32 *outTexel, u32 fract)
 | |
| {
 | |
|     outTexel[0] += inTexel[0] * fract;
 | |
|     outTexel[1] += inTexel[1] * fract;
 | |
|     outTexel[2] += inTexel[2] * fract;
 | |
|     outTexel[3] += inTexel[3] * fract;
 | |
| }
 | |
| 
 | |
| void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8 *sample)
 | |
| {
 | |
|     int baseMip = 0;
 | |
| 	bool mipLinear = false;
 | |
| 
 | |
| #if (ALLOW_MIPMAP)
 | |
| 	FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
 | |
|     TexMode0& tm0 = texUnit.texMode0[texmap & 3];
 | |
| 
 | |
| 	s32 lodFract = lod & 0xf;
 | |
| 
 | |
| 	if (lod > 0 && tm0.min_filter & 3)
 | |
| 	{
 | |
| 		// use mipmap
 | |
| 		baseMip = lod >> 4;
 | |
| 		mipLinear = (lodFract && tm0.min_filter & 2);
 | |
| 
 | |
| 		// if using nearest mip filter and lodFract >= 0.5 round up to next mip
 | |
| 		baseMip += (lodFract >> 3) & (tm0.min_filter & 1);
 | |
| 	}
 | |
| 
 | |
| 	if (mipLinear)
 | |
| 	{
 | |
| 		u8 sampledTex[4];
 | |
|         u32 texel[4];
 | |
| 
 | |
| 		SampleMip(s, t, baseMip, linear, texmap, sampledTex);
 | |
| 		SetTexel(sampledTex, texel, (16 - lodFract));
 | |
| 
 | |
| 		SampleMip(s, t, baseMip + 1, linear, texmap, sampledTex);
 | |
| 		AddTexel(sampledTex, texel, lodFract);
 | |
| 
 | |
| 		sample[0] = (u8)(texel[0] >> 4);
 | |
|         sample[1] = (u8)(texel[1] >> 4);
 | |
|         sample[2] = (u8)(texel[2] >> 4);
 | |
|         sample[3] = (u8)(texel[3] >> 4);
 | |
| 	}
 | |
| 	else
 | |
| #endif
 | |
| 	{
 | |
| 		SampleMip(s, t, baseMip, linear, texmap, sample);
 | |
| 	}	
 | |
| }
 | |
| 
 | |
| void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8 *sample)
 | |
| {
 | |
| 	FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
 | |
|     u8 subTexmap = texmap & 3;
 | |
| 
 | |
|     TexMode0& tm0 = texUnit.texMode0[subTexmap];
 | |
|     TexImage0& ti0 = texUnit.texImage0[subTexmap];
 | |
|     TexTLUT& texTlut = texUnit.texTlut[subTexmap];
 | |
| 
 | |
| 	u8 *imageSrc;
 | |
| 	if (texUnit.texImage1[subTexmap].image_type)
 | |
| 	{
 | |
| 		imageSrc = &texMem[texUnit.texImage1[subTexmap].tmem_even * TMEM_LINE_SIZE];
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		u32 imageBase = texUnit.texImage3[subTexmap].image_base << 5;    
 | |
| 		imageSrc = Memory::GetPointer(imageBase);
 | |
| 	}
 | |
| 
 | |
| 	int imageWidth = ti0.width;
 | |
| 	int imageHeight = ti0.height;
 | |
| 
 | |
| 	int tlutAddress = texTlut.tmem_offset << 9;
 | |
| 	
 | |
| 	// reduce sample location and texture size to mip level
 | |
| 	// move texture pointer to mip location
 | |
| 	if (mip)
 | |
| 	{
 | |
| 		int mipWidth = imageWidth + 1;
 | |
| 		int mipHeight = imageHeight + 1;
 | |
| 
 | |
| 		int fmtWidth = TexDecoder_GetBlockWidthInTexels(ti0.format);
 | |
| 		int fmtHeight = TexDecoder_GetBlockHeightInTexels(ti0.format);
 | |
| 		int fmtDepth = TexDecoder_GetTexelSizeInNibbles(ti0.format);
 | |
| 
 | |
| 		imageWidth >>= mip;
 | |
| 		imageHeight >>= mip;
 | |
| 		s >>= mip;
 | |
| 		t >>= mip;
 | |
| 
 | |
| 		while (mip)
 | |
| 		{
 | |
| 			mipWidth = max(mipWidth, fmtWidth);
 | |
| 			mipHeight = max(mipHeight, fmtHeight);
 | |
| 			u32 size = (mipWidth * mipHeight * fmtDepth) >> 1;
 | |
| 
 | |
| 			imageSrc += size;
 | |
| 			mipWidth >>= 1;
 | |
| 			mipHeight >>= 1;
 | |
| 			mip--;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
|     if (linear)
 | |
|     {
 | |
| 		// offset linear sampling
 | |
| 		s -= 64;
 | |
| 		t -= 64;
 | |
| 
 | |
| 		// integer part of sample location
 | |
| 		int imageS = s >> 7;
 | |
| 		int imageT = t >> 7;
 | |
| 
 | |
| 		// linear sampling
 | |
| 		int imageSPlus1 = imageS + 1;
 | |
|         int fractS = s & 0x7f;
 | |
|         
 | |
|         int imageTPlus1 = imageT + 1;
 | |
|         int fractT = t & 0x7f;
 | |
| 
 | |
|         u8 sampledTex[4];
 | |
|         u32 texel[4];
 | |
| 
 | |
|         WrapCoord(imageS, tm0.wrap_s, imageWidth);
 | |
|         WrapCoord(imageT, tm0.wrap_t, imageHeight);
 | |
|         WrapCoord(imageSPlus1, tm0.wrap_s, imageWidth);
 | |
|         WrapCoord(imageTPlus1, tm0.wrap_t, imageHeight);
 | |
| 
 | |
|         TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
 | |
|         SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT));
 | |
| 
 | |
|         TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageT, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
 | |
|         AddTexel(sampledTex, texel, (fractS) * (128 - fractT));
 | |
| 
 | |
|         TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageTPlus1, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
 | |
|         AddTexel(sampledTex, texel, (128 - fractS) * (fractT));
 | |
| 
 | |
|         TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageTPlus1, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
 | |
|         AddTexel(sampledTex, texel, (fractS) * (fractT));
 | |
| 
 | |
|         sample[0] = (u8)(texel[0] >> 14);
 | |
|         sample[1] = (u8)(texel[1] >> 14);
 | |
|         sample[2] = (u8)(texel[2] >> 14);
 | |
|         sample[3] = (u8)(texel[3] >> 14);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 		// integer part of sample location
 | |
| 		int imageS = s >> 7;
 | |
| 		int imageT = t >> 7;
 | |
| 
 | |
|         // nearest neighbor sampling
 | |
| 		WrapCoord(imageS, tm0.wrap_s, imageWidth);
 | |
|         WrapCoord(imageT, tm0.wrap_t, imageHeight);
 | |
| 
 | |
|         TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);   
 | |
|     }
 | |
| }
 | |
| 
 | |
| }
 |