| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | // 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 "main.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BPMemLoader.h"
 | 
					
						
							|  |  |  | #include "../../../Core/VideoCommon/Src/TextureDecoder.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]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     u32 imageBase = texUnit.texImage3[subTexmap].image_base << 5;     | 
					
						
							|  |  |  |     u8 *imageSrc = g_VideoInitialize.pGetMemoryPointer(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);    | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |