2015-05-24 06:55:12 +02:00
// Copyright 2009 Dolphin Emulator Project
2015-05-18 01:08:10 +02:00
// Licensed under GPLv2+
2013-04-17 23:29:41 -04:00
// Refer to the license.txt file included.
2010-06-09 01:37:08 +00:00
2013-03-25 21:43:32 +00:00
#include <cmath>
2010-06-09 01:37:08 +00:00
2014-07-29 20:55:07 -04:00
#include "Common/ChunkFile.h"
2014-09-07 20:06:58 -05:00
#include "Common/CommonTypes.h"
2014-02-17 05:18:15 -05:00
#include "VideoBackends/Software/DebugUtil.h"
#include "VideoBackends/Software/EfbInterface.h"
#include "VideoBackends/Software/SWStatistics.h"
#include "VideoBackends/Software/SWVideoConfig.h"
#include "VideoBackends/Software/Tev.h"
#include "VideoBackends/Software/TextureSampler.h"
#include "VideoBackends/Software/XFMemLoader.h"
2014-09-14 17:52:51 +01:00
#include "VideoCommon/BoundingBox.h"
2014-02-17 05:18:15 -05:00
2010-12-02 05:38:48 +00:00
#ifdef _DEBUG
#define ALLOW_TEV_DUMPS 1
#else
#define ALLOW_TEV_DUMPS 0
#endif
2010-06-09 01:37:08 +00:00
void Tev :: Init ()
{
2013-04-13 23:54:02 -04:00
FixedConstants [ 0 ] = 0 ;
2014-05-14 13:27:00 -07:00
FixedConstants [ 1 ] = 32 ;
FixedConstants [ 2 ] = 64 ;
FixedConstants [ 3 ] = 96 ;
FixedConstants [ 4 ] = 128 ;
2013-04-13 23:54:02 -04:00
FixedConstants [ 5 ] = 159 ;
FixedConstants [ 6 ] = 191 ;
FixedConstants [ 7 ] = 223 ;
FixedConstants [ 8 ] = 255 ;
2010-06-09 01:37:08 +00:00
2014-03-03 06:25:15 +01:00
for ( s16 & comp : Zero16 )
{
comp = 0 ;
}
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
m_ColorInputLUT [ 0 ][ RED_INP ] = & Reg [ 0 ][ RED_C ]; m_ColorInputLUT [ 0 ][ GRN_INP ] = & Reg [ 0 ][ GRN_C ]; m_ColorInputLUT [ 0 ][ BLU_INP ] = & Reg [ 0 ][ BLU_C ]; // prev.rgb
m_ColorInputLUT [ 1 ][ RED_INP ] = & Reg [ 0 ][ ALP_C ]; m_ColorInputLUT [ 1 ][ GRN_INP ] = & Reg [ 0 ][ ALP_C ]; m_ColorInputLUT [ 1 ][ BLU_INP ] = & Reg [ 0 ][ ALP_C ]; // prev.aaa
m_ColorInputLUT [ 2 ][ RED_INP ] = & Reg [ 1 ][ RED_C ]; m_ColorInputLUT [ 2 ][ GRN_INP ] = & Reg [ 1 ][ GRN_C ]; m_ColorInputLUT [ 2 ][ BLU_INP ] = & Reg [ 1 ][ BLU_C ]; // c0.rgb
m_ColorInputLUT [ 3 ][ RED_INP ] = & Reg [ 1 ][ ALP_C ]; m_ColorInputLUT [ 3 ][ GRN_INP ] = & Reg [ 1 ][ ALP_C ]; m_ColorInputLUT [ 3 ][ BLU_INP ] = & Reg [ 1 ][ ALP_C ]; // c0.aaa
m_ColorInputLUT [ 4 ][ RED_INP ] = & Reg [ 2 ][ RED_C ]; m_ColorInputLUT [ 4 ][ GRN_INP ] = & Reg [ 2 ][ GRN_C ]; m_ColorInputLUT [ 4 ][ BLU_INP ] = & Reg [ 2 ][ BLU_C ]; // c1.rgb
m_ColorInputLUT [ 5 ][ RED_INP ] = & Reg [ 2 ][ ALP_C ]; m_ColorInputLUT [ 5 ][ GRN_INP ] = & Reg [ 2 ][ ALP_C ]; m_ColorInputLUT [ 5 ][ BLU_INP ] = & Reg [ 2 ][ ALP_C ]; // c1.aaa
m_ColorInputLUT [ 6 ][ RED_INP ] = & Reg [ 3 ][ RED_C ]; m_ColorInputLUT [ 6 ][ GRN_INP ] = & Reg [ 3 ][ GRN_C ]; m_ColorInputLUT [ 6 ][ BLU_INP ] = & Reg [ 3 ][ BLU_C ]; // c2.rgb
m_ColorInputLUT [ 7 ][ RED_INP ] = & Reg [ 3 ][ ALP_C ]; m_ColorInputLUT [ 7 ][ GRN_INP ] = & Reg [ 3 ][ ALP_C ]; m_ColorInputLUT [ 7 ][ BLU_INP ] = & Reg [ 3 ][ ALP_C ]; // c2.aaa
m_ColorInputLUT [ 8 ][ RED_INP ] = & TexColor [ RED_C ]; m_ColorInputLUT [ 8 ][ GRN_INP ] = & TexColor [ GRN_C ]; m_ColorInputLUT [ 8 ][ BLU_INP ] = & TexColor [ BLU_C ]; // tex.rgb
m_ColorInputLUT [ 9 ][ RED_INP ] = & TexColor [ ALP_C ]; m_ColorInputLUT [ 9 ][ GRN_INP ] = & TexColor [ ALP_C ]; m_ColorInputLUT [ 9 ][ BLU_INP ] = & TexColor [ ALP_C ]; // tex.aaa
m_ColorInputLUT [ 10 ][ RED_INP ] = & RasColor [ RED_C ]; m_ColorInputLUT [ 10 ][ GRN_INP ] = & RasColor [ GRN_C ]; m_ColorInputLUT [ 10 ][ BLU_INP ] = & RasColor [ BLU_C ]; // ras.rgb
m_ColorInputLUT [ 11 ][ RED_INP ] = & RasColor [ ALP_C ]; m_ColorInputLUT [ 11 ][ GRN_INP ] = & RasColor [ ALP_C ]; m_ColorInputLUT [ 11 ][ BLU_INP ] = & RasColor [ ALP_C ]; // ras.rgb
m_ColorInputLUT [ 12 ][ RED_INP ] = & FixedConstants [ 8 ]; m_ColorInputLUT [ 12 ][ GRN_INP ] = & FixedConstants [ 8 ]; m_ColorInputLUT [ 12 ][ BLU_INP ] = & FixedConstants [ 8 ]; // one
m_ColorInputLUT [ 13 ][ RED_INP ] = & FixedConstants [ 4 ]; m_ColorInputLUT [ 13 ][ GRN_INP ] = & FixedConstants [ 4 ]; m_ColorInputLUT [ 13 ][ BLU_INP ] = & FixedConstants [ 4 ]; // half
m_ColorInputLUT [ 14 ][ RED_INP ] = & StageKonst [ RED_C ]; m_ColorInputLUT [ 14 ][ GRN_INP ] = & StageKonst [ GRN_C ]; m_ColorInputLUT [ 14 ][ BLU_INP ] = & StageKonst [ BLU_C ]; // konst
m_ColorInputLUT [ 15 ][ RED_INP ] = & FixedConstants [ 0 ]; m_ColorInputLUT [ 15 ][ GRN_INP ] = & FixedConstants [ 0 ]; m_ColorInputLUT [ 15 ][ BLU_INP ] = & FixedConstants [ 0 ]; // zero
2010-06-09 01:37:08 +00:00
2014-03-24 14:42:04 +01:00
m_AlphaInputLUT [ 0 ] = & Reg [ 0 ][ ALP_C ]; // prev
m_AlphaInputLUT [ 1 ] = & Reg [ 1 ][ ALP_C ]; // c0
m_AlphaInputLUT [ 2 ] = & Reg [ 2 ][ ALP_C ]; // c1
m_AlphaInputLUT [ 3 ] = & Reg [ 3 ][ ALP_C ]; // c2
m_AlphaInputLUT [ 4 ] = & TexColor [ ALP_C ]; // tex
m_AlphaInputLUT [ 5 ] = & RasColor [ ALP_C ]; // ras
m_AlphaInputLUT [ 6 ] = & StageKonst [ ALP_C ]; // konst
m_AlphaInputLUT [ 7 ] = & Zero16 [ ALP_C ]; // zero
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
for ( int comp = 0 ; comp < 4 ; comp ++ )
{
m_KonstLUT [ 0 ][ comp ] = & FixedConstants [ 8 ];
m_KonstLUT [ 1 ][ comp ] = & FixedConstants [ 7 ];
m_KonstLUT [ 2 ][ comp ] = & FixedConstants [ 6 ];
m_KonstLUT [ 3 ][ comp ] = & FixedConstants [ 5 ];
m_KonstLUT [ 4 ][ comp ] = & FixedConstants [ 4 ];
m_KonstLUT [ 5 ][ comp ] = & FixedConstants [ 3 ];
m_KonstLUT [ 6 ][ comp ] = & FixedConstants [ 2 ];
m_KonstLUT [ 7 ][ comp ] = & FixedConstants [ 1 ];
2010-06-09 01:37:08 +00:00
2014-05-14 13:27:00 -07:00
// These are "invalid" values, not meant to be used. On hardware,
// they all output zero.
for ( int i = 8 ; i < 16 ; ++ i )
{
m_KonstLUT [ i ][ comp ] = & FixedConstants [ 0 ];
}
if ( comp != ALP_C )
{
m_KonstLUT [ 12 ][ comp ] = & KonstantColors [ 0 ][ comp ];
m_KonstLUT [ 13 ][ comp ] = & KonstantColors [ 1 ][ comp ];
m_KonstLUT [ 14 ][ comp ] = & KonstantColors [ 2 ][ comp ];
m_KonstLUT [ 15 ][ comp ] = & KonstantColors [ 3 ][ comp ];
}
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
m_KonstLUT [ 16 ][ comp ] = & KonstantColors [ 0 ][ RED_C ];
m_KonstLUT [ 17 ][ comp ] = & KonstantColors [ 1 ][ RED_C ];
m_KonstLUT [ 18 ][ comp ] = & KonstantColors [ 2 ][ RED_C ];
m_KonstLUT [ 19 ][ comp ] = & KonstantColors [ 3 ][ RED_C ];
m_KonstLUT [ 20 ][ comp ] = & KonstantColors [ 0 ][ GRN_C ];
m_KonstLUT [ 21 ][ comp ] = & KonstantColors [ 1 ][ GRN_C ];
m_KonstLUT [ 22 ][ comp ] = & KonstantColors [ 2 ][ GRN_C ];
m_KonstLUT [ 23 ][ comp ] = & KonstantColors [ 3 ][ GRN_C ];
m_KonstLUT [ 24 ][ comp ] = & KonstantColors [ 0 ][ BLU_C ];
m_KonstLUT [ 25 ][ comp ] = & KonstantColors [ 1 ][ BLU_C ];
m_KonstLUT [ 26 ][ comp ] = & KonstantColors [ 2 ][ BLU_C ];
m_KonstLUT [ 27 ][ comp ] = & KonstantColors [ 3 ][ BLU_C ];
m_KonstLUT [ 28 ][ comp ] = & KonstantColors [ 0 ][ ALP_C ];
m_KonstLUT [ 29 ][ comp ] = & KonstantColors [ 1 ][ ALP_C ];
m_KonstLUT [ 30 ][ comp ] = & KonstantColors [ 2 ][ ALP_C ];
m_KonstLUT [ 31 ][ comp ] = & KonstantColors [ 3 ][ ALP_C ];
}
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
m_BiasLUT [ 0 ] = 0 ;
m_BiasLUT [ 1 ] = 128 ;
m_BiasLUT [ 2 ] = - 128 ;
m_BiasLUT [ 3 ] = 0 ;
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
m_ScaleLShiftLUT [ 0 ] = 0 ;
m_ScaleLShiftLUT [ 1 ] = 1 ;
m_ScaleLShiftLUT [ 2 ] = 2 ;
m_ScaleLShiftLUT [ 3 ] = 0 ;
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
m_ScaleRShiftLUT [ 0 ] = 0 ;
m_ScaleRShiftLUT [ 1 ] = 0 ;
m_ScaleRShiftLUT [ 2 ] = 0 ;
m_ScaleRShiftLUT [ 3 ] = 1 ;
2010-06-09 01:37:08 +00:00
}
2014-08-10 21:51:05 -04:00
static inline s16 Clamp255 ( s16 in )
2010-06-09 01:37:08 +00:00
{
2013-04-13 23:54:02 -04:00
return in > 255 ? 255 : ( in < 0 ? 0 : in );
2010-06-09 01:37:08 +00:00
}
2014-08-10 21:51:05 -04:00
static inline s16 Clamp1024 ( s16 in )
2010-06-09 01:37:08 +00:00
{
2014-02-16 15:30:18 -05:00
return in > 1023 ? 1023 : ( in <- 1024 ?- 1024 : in );
2010-06-09 01:37:08 +00:00
}
2011-02-06 01:56:45 +00:00
void Tev :: SetRasColor ( int colorChan , int swaptable )
2010-06-09 01:37:08 +00:00
{
2014-03-11 00:30:55 +13:00
switch ( colorChan )
2013-04-13 23:54:02 -04:00
{
case 0 : // Color0
{
u8 * color = Color [ 0 ];
RasColor [ RED_C ] = color [ bpmem . tevksel [ swaptable ]. swap1 ];
RasColor [ GRN_C ] = color [ bpmem . tevksel [ swaptable ]. swap2 ];
swaptable ++ ;
RasColor [ BLU_C ] = color [ bpmem . tevksel [ swaptable ]. swap1 ];
RasColor [ ALP_C ] = color [ bpmem . tevksel [ swaptable ]. swap2 ];
}
break ;
case 1 : // Color1
{
u8 * color = Color [ 1 ];
RasColor [ RED_C ] = color [ bpmem . tevksel [ swaptable ]. swap1 ];
RasColor [ GRN_C ] = color [ bpmem . tevksel [ swaptable ]. swap2 ];
swaptable ++ ;
RasColor [ BLU_C ] = color [ bpmem . tevksel [ swaptable ]. swap1 ];
RasColor [ ALP_C ] = color [ bpmem . tevksel [ swaptable ]. swap2 ];
}
break ;
2014-09-14 17:52:51 +01:00
case 5 : // alpha bump
2013-04-13 23:54:02 -04:00
{
2014-03-03 06:25:15 +01:00
for ( s16 & comp : RasColor )
{
comp = AlphaBump ;
}
2013-04-13 23:54:02 -04:00
}
break ;
case 6 : // alpha bump normalized
{
u8 normalized = AlphaBump | AlphaBump >> 5 ;
2014-03-03 06:25:15 +01:00
for ( s16 & comp : RasColor )
{
comp = normalized ;
}
2013-04-13 23:54:02 -04:00
}
break ;
default : // zero
{
2014-03-03 06:25:15 +01:00
for ( s16 & comp : RasColor )
{
comp = 0 ;
}
2013-04-13 23:54:02 -04:00
}
break ;
}
2010-06-09 01:37:08 +00:00
}
2014-03-24 14:42:04 +01:00
void Tev :: DrawColorRegular ( TevStageCombiner :: ColorCombiner & cc , const InputRegType inputs [ 4 ])
2010-06-09 01:37:08 +00:00
{
2013-04-13 23:54:02 -04:00
for ( int i = 0 ; i < 3 ; i ++ )
{
2014-03-24 14:42:04 +01:00
const InputRegType & InputReg = inputs [ BLU_C + i ];
2010-06-09 01:37:08 +00:00
2013-10-29 01:23:17 -04:00
u16 c = InputReg . c + ( InputReg . c >> 7 );
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
s32 temp = InputReg . a * ( 256 - c ) + ( InputReg . b * c );
2014-03-24 14:54:17 +01:00
temp <<= m_ScaleLShiftLUT [ cc . shift ];
2014-04-15 14:01:22 -07:00
temp += ( cc . shift == 3 ) ? 0 : ( cc . op == 1 ) ? 127 : 128 ;
temp >>= 8 ;
temp = cc . op ? - temp : temp ;
2010-06-09 01:37:08 +00:00
2014-03-24 14:54:17 +01:00
s32 result = (( InputReg . d + m_BiasLUT [ cc . bias ]) << m_ScaleLShiftLUT [ cc . shift ]) + temp ;
2013-04-13 23:54:02 -04:00
result = result >> m_ScaleRShiftLUT [ cc . shift ];
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
Reg [ cc . dest ][ BLU_C + i ] = result ;
}
2010-06-09 01:37:08 +00:00
}
2014-03-24 14:42:04 +01:00
void Tev :: DrawColorCompare ( TevStageCombiner :: ColorCombiner & cc , const InputRegType inputs [ 4 ])
2010-06-09 01:37:08 +00:00
{
2014-04-15 14:05:12 -07:00
for ( int i = BLU_C ; i <= RED_C ; i ++ )
2014-03-24 14:42:04 +01:00
{
switch (( cc . shift << 1 ) | cc . op | 8 ) // encoded compare mode
{
case TEVCMP_R8_GT :
Reg [ cc . dest ][ i ] = inputs [ i ]. d + (( inputs [ RED_C ]. a > inputs [ RED_C ]. b ) ? inputs [ i ]. c : 0 );
break ;
2010-06-09 01:37:08 +00:00
2014-03-24 14:42:04 +01:00
case TEVCMP_R8_EQ :
Reg [ cc . dest ][ i ] = inputs [ i ]. d + (( inputs [ RED_C ]. a == inputs [ RED_C ]. b ) ? inputs [ i ]. c : 0 );
break ;
2010-06-09 01:37:08 +00:00
2014-03-24 14:42:04 +01:00
case TEVCMP_GR16_GT :
{
u32 a = ( inputs [ GRN_C ]. a << 8 ) | inputs [ RED_C ]. a ;
u32 b = ( inputs [ GRN_C ]. b << 8 ) | inputs [ RED_C ]. b ;
Reg [ cc . dest ][ i ] = inputs [ i ]. d + (( a > b ) ? inputs [ i ]. c : 0 );
}
break ;
2010-06-09 01:37:08 +00:00
2014-03-24 14:42:04 +01:00
case TEVCMP_GR16_EQ :
2013-04-13 23:54:02 -04:00
{
2014-03-24 14:42:04 +01:00
u32 a = ( inputs [ GRN_C ]. a << 8 ) | inputs [ RED_C ]. a ;
u32 b = ( inputs [ GRN_C ]. b << 8 ) | inputs [ RED_C ]. b ;
Reg [ cc . dest ][ i ] = inputs [ i ]. d + (( a == b ) ? inputs [ i ]. c : 0 );
2013-04-13 23:54:02 -04:00
}
2014-03-24 14:42:04 +01:00
break ;
2010-06-09 01:37:08 +00:00
2014-03-24 14:42:04 +01:00
case TEVCMP_BGR24_GT :
2013-04-13 23:54:02 -04:00
{
2014-03-24 14:42:04 +01:00
u32 a = ( inputs [ BLU_C ]. a << 16 ) | ( inputs [ GRN_C ]. a << 8 ) | inputs [ RED_C ]. a ;
u32 b = ( inputs [ BLU_C ]. b << 16 ) | ( inputs [ GRN_C ]. b << 8 ) | inputs [ RED_C ]. b ;
Reg [ cc . dest ][ i ] = inputs [ i ]. d + (( a > b ) ? inputs [ i ]. c : 0 );
2013-04-13 23:54:02 -04:00
}
2014-03-24 14:42:04 +01:00
break ;
case TEVCMP_BGR24_EQ :
2013-04-13 23:54:02 -04:00
{
2014-03-24 14:42:04 +01:00
u32 a = ( inputs [ BLU_C ]. a << 16 ) | ( inputs [ GRN_C ]. a << 8 ) | inputs [ RED_C ]. a ;
u32 b = ( inputs [ BLU_C ]. b << 16 ) | ( inputs [ GRN_C ]. b << 8 ) | inputs [ RED_C ]. b ;
Reg [ cc . dest ][ i ] = inputs [ i ]. d + (( a == b ) ? inputs [ i ]. c : 0 );
2013-04-13 23:54:02 -04:00
}
2014-03-24 14:42:04 +01:00
break ;
case TEVCMP_RGB8_GT :
Reg [ cc . dest ][ i ] = inputs [ i ]. d + (( inputs [ i ]. a > inputs [ i ]. b ) ? inputs [ i ]. c : 0 );
break ;
case TEVCMP_RGB8_EQ :
Reg [ cc . dest ][ i ] = inputs [ i ]. d + (( inputs [ i ]. a == inputs [ i ]. b ) ? inputs [ i ]. c : 0 );
break ;
2013-04-13 23:54:02 -04:00
}
}
2010-06-09 01:37:08 +00:00
}
2014-03-24 14:42:04 +01:00
void Tev :: DrawAlphaRegular ( TevStageCombiner :: AlphaCombiner & ac , const InputRegType inputs [ 4 ])
2010-06-09 01:37:08 +00:00
{
2014-03-24 14:42:04 +01:00
const InputRegType & InputReg = inputs [ ALP_C ];
2010-06-09 01:37:08 +00:00
2013-10-29 01:23:17 -04:00
u16 c = InputReg . c + ( InputReg . c >> 7 );
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
s32 temp = InputReg . a * ( 256 - c ) + ( InputReg . b * c );
2014-03-24 14:54:17 +01:00
temp <<= m_ScaleLShiftLUT [ ac . shift ];
temp += ( ac . shift != 3 ) ? 0 : ( ac . op == 1 ) ? 127 : 128 ;
temp = ac . op ? ( - temp >> 8 ) : ( temp >> 8 );
2010-06-09 01:37:08 +00:00
2014-03-24 14:54:17 +01:00
s32 result = (( InputReg . d + m_BiasLUT [ ac . bias ]) << m_ScaleLShiftLUT [ ac . shift ]) + temp ;
2013-04-13 23:54:02 -04:00
result = result >> m_ScaleRShiftLUT [ ac . shift ];
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
Reg [ ac . dest ][ ALP_C ] = result ;
2010-06-09 01:37:08 +00:00
}
2014-03-24 14:42:04 +01:00
void Tev :: DrawAlphaCompare ( TevStageCombiner :: AlphaCombiner & ac , const InputRegType inputs [ 4 ])
2010-06-09 01:37:08 +00:00
{
2014-03-24 14:42:04 +01:00
switch (( ac . shift << 1 ) | ac . op | 8 ) // encoded compare mode
{
2013-04-13 23:54:02 -04:00
case TEVCMP_R8_GT :
2014-03-24 14:42:04 +01:00
Reg [ ac . dest ][ ALP_C ] = inputs [ ALP_C ]. d + (( inputs [ RED_C ]. a > inputs [ RED_C ]. b ) ? inputs [ ALP_C ]. c : 0 );
2013-04-13 23:54:02 -04:00
break ;
case TEVCMP_R8_EQ :
2014-03-24 14:42:04 +01:00
Reg [ ac . dest ][ ALP_C ] = inputs [ ALP_C ]. d + (( inputs [ RED_C ]. a == inputs [ RED_C ]. b ) ? inputs [ ALP_C ]. c : 0 );
2013-04-13 23:54:02 -04:00
break ;
2014-03-24 14:42:04 +01:00
2013-04-13 23:54:02 -04:00
case TEVCMP_GR16_GT :
{
2014-03-24 14:42:04 +01:00
u32 a = ( inputs [ GRN_C ]. a << 8 ) | inputs [ RED_C ]. a ;
u32 b = ( inputs [ GRN_C ]. b << 8 ) | inputs [ RED_C ]. b ;
Reg [ ac . dest ][ ALP_C ] = inputs [ ALP_C ]. d + (( a > b ) ? inputs [ ALP_C ]. c : 0 );
2013-04-13 23:54:02 -04:00
}
break ;
2014-03-24 14:42:04 +01:00
2013-04-13 23:54:02 -04:00
case TEVCMP_GR16_EQ :
{
2014-03-24 14:42:04 +01:00
u32 a = ( inputs [ GRN_C ]. a << 8 ) | inputs [ RED_C ]. a ;
u32 b = ( inputs [ GRN_C ]. b << 8 ) | inputs [ RED_C ]. b ;
Reg [ ac . dest ][ ALP_C ] = inputs [ ALP_C ]. d + (( a == b ) ? inputs [ ALP_C ]. c : 0 );
2013-04-13 23:54:02 -04:00
}
break ;
2014-03-24 14:42:04 +01:00
2013-04-13 23:54:02 -04:00
case TEVCMP_BGR24_GT :
{
2014-03-24 14:42:04 +01:00
u32 a = ( inputs [ BLU_C ]. a << 16 ) | ( inputs [ GRN_C ]. a << 8 ) | inputs [ RED_C ]. a ;
u32 b = ( inputs [ BLU_C ]. b << 16 ) | ( inputs [ GRN_C ]. b << 8 ) | inputs [ RED_C ]. b ;
Reg [ ac . dest ][ ALP_C ] = inputs [ ALP_C ]. d + (( a > b ) ? inputs [ ALP_C ]. c : 0 );
2013-04-13 23:54:02 -04:00
}
break ;
2014-03-24 14:42:04 +01:00
2013-04-13 23:54:02 -04:00
case TEVCMP_BGR24_EQ :
{
2014-03-24 14:42:04 +01:00
u32 a = ( inputs [ BLU_C ]. a << 16 ) | ( inputs [ GRN_C ]. a << 8 ) | inputs [ RED_C ]. a ;
u32 b = ( inputs [ BLU_C ]. b << 16 ) | ( inputs [ GRN_C ]. b << 8 ) | inputs [ RED_C ]. b ;
Reg [ ac . dest ][ ALP_C ] = inputs [ ALP_C ]. d + (( a == b ) ? inputs [ ALP_C ]. c : 0 );
2013-04-13 23:54:02 -04:00
}
break ;
2014-03-24 14:42:04 +01:00
2013-04-13 23:54:02 -04:00
case TEVCMP_A8_GT :
2014-03-24 14:42:04 +01:00
Reg [ ac . dest ][ ALP_C ] = inputs [ ALP_C ]. d + (( inputs [ ALP_C ]. a > inputs [ ALP_C ]. b ) ? inputs [ ALP_C ]. c : 0 );
2013-04-13 23:54:02 -04:00
break ;
2014-03-24 14:42:04 +01:00
2013-04-13 23:54:02 -04:00
case TEVCMP_A8_EQ :
2014-03-24 14:42:04 +01:00
Reg [ ac . dest ][ ALP_C ] = inputs [ ALP_C ]. d + (( inputs [ ALP_C ]. a == inputs [ ALP_C ]. b ) ? inputs [ ALP_C ]. c : 0 );
2013-04-13 23:54:02 -04:00
break ;
}
2010-06-09 01:37:08 +00:00
}
2014-03-24 20:21:34 +01:00
static bool AlphaCompare ( int alpha , int ref , AlphaTest :: CompareMode comp )
2010-06-09 01:37:08 +00:00
{
2014-08-10 21:18:38 -04:00
switch ( comp )
{
2014-03-24 20:21:34 +01:00
case AlphaTest :: ALWAYS : return true ;
case AlphaTest :: NEVER : return false ;
case AlphaTest :: LEQUAL : return alpha <= ref ;
case AlphaTest :: LESS : return alpha < ref ;
case AlphaTest :: GEQUAL : return alpha >= ref ;
case AlphaTest :: GREATER : return alpha > ref ;
case AlphaTest :: EQUAL : return alpha == ref ;
case AlphaTest :: NEQUAL : return alpha != ref ;
2014-12-02 18:20:52 -06:00
default : return true ;
2013-04-13 23:54:02 -04:00
}
2010-06-09 01:37:08 +00:00
}
2013-01-31 15:29:29 -06:00
static bool TevAlphaTest ( int alpha )
2010-06-09 01:37:08 +00:00
{
2013-04-13 23:54:02 -04:00
bool comp0 = AlphaCompare ( alpha , bpmem . alpha_test . ref0 , bpmem . alpha_test . comp0 );
bool comp1 = AlphaCompare ( alpha , bpmem . alpha_test . ref1 , bpmem . alpha_test . comp1 );
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
switch ( bpmem . alpha_test . logic )
{
case 0 : return comp0 && comp1 ; // and
case 1 : return comp0 || comp1 ; // or
case 2 : return comp0 ^ comp1 ; // xor
case 3 : return ! ( comp0 ^ comp1 ); // xnor
2014-12-02 18:20:52 -06:00
default : return true ;
2013-04-13 23:54:02 -04:00
}
2010-06-09 01:37:08 +00:00
}
2014-08-10 21:51:05 -04:00
static inline s32 WrapIndirectCoord ( s32 coord , int wrapMode )
2010-06-09 01:37:08 +00:00
{
2013-04-13 23:54:02 -04:00
switch ( wrapMode )
{
case ITW_OFF :
return coord ;
case ITW_256 :
return ( coord % ( 256 << 7 ));
case ITW_128 :
return ( coord % ( 128 << 7 ));
case ITW_64 :
return ( coord % ( 64 << 7 ));
case ITW_32 :
return ( coord % ( 32 << 7 ));
case ITW_16 :
return ( coord % ( 16 << 7 ));
case ITW_0 :
return 0 ;
2014-12-02 18:20:52 -06:00
default :
return 0 ;
2013-04-13 23:54:02 -04:00
}
2010-06-09 01:37:08 +00:00
}
void Tev :: Indirect ( unsigned int stageNum , s32 s , s32 t )
{
2013-04-13 23:54:02 -04:00
TevStageIndirect & indirect = bpmem . tevind [ stageNum ];
u8 * indmap = IndirectTex [ indirect . bt ];
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
s32 indcoord [ 3 ];
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
// alpha bump select
switch ( indirect . bs )
{
case ITBA_OFF :
AlphaBump = 0 ;
break ;
2013-09-12 13:55:38 +02:00
case ITBA_S :
2010-12-31 06:45:18 +00:00
AlphaBump = indmap [ TextureSampler :: ALP_SMP ];
2013-04-13 23:54:02 -04:00
break ;
case ITBA_T :
AlphaBump = indmap [ TextureSampler :: BLU_SMP ];
break ;
case ITBA_U :
AlphaBump = indmap [ TextureSampler :: GRN_SMP ];
break ;
}
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
// bias select
s16 biasValue = indirect . fmt == ITF_8 ?- 128 : 1 ;
s16 bias [ 3 ];
bias [ 0 ] = indirect . bias & 1 ? biasValue : 0 ;
bias [ 1 ] = indirect . bias & 2 ? biasValue : 0 ;
bias [ 2 ] = indirect . bias & 4 ? biasValue : 0 ;
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
// format
2014-03-11 00:30:55 +13:00
switch ( indirect . fmt )
2013-04-13 23:54:02 -04:00
{
case ITF_8 :
indcoord [ 0 ] = indmap [ TextureSampler :: ALP_SMP ] + bias [ 0 ];
indcoord [ 1 ] = indmap [ TextureSampler :: BLU_SMP ] + bias [ 1 ];
indcoord [ 2 ] = indmap [ TextureSampler :: GRN_SMP ] + bias [ 2 ];
AlphaBump = AlphaBump & 0xf8 ;
break ;
case ITF_5 :
indcoord [ 0 ] = ( indmap [ TextureSampler :: ALP_SMP ] & 0x1f ) + bias [ 0 ];
indcoord [ 1 ] = ( indmap [ TextureSampler :: BLU_SMP ] & 0x1f ) + bias [ 1 ];
indcoord [ 2 ] = ( indmap [ TextureSampler :: GRN_SMP ] & 0x1f ) + bias [ 2 ];
AlphaBump = AlphaBump & 0xe0 ;
break ;
case ITF_4 :
indcoord [ 0 ] = ( indmap [ TextureSampler :: ALP_SMP ] & 0x0f ) + bias [ 0 ];
indcoord [ 1 ] = ( indmap [ TextureSampler :: BLU_SMP ] & 0x0f ) + bias [ 1 ];
indcoord [ 2 ] = ( indmap [ TextureSampler :: GRN_SMP ] & 0x0f ) + bias [ 2 ];
AlphaBump = AlphaBump & 0xf0 ;
break ;
case ITF_3 :
indcoord [ 0 ] = ( indmap [ TextureSampler :: ALP_SMP ] & 0x07 ) + bias [ 0 ];
indcoord [ 1 ] = ( indmap [ TextureSampler :: BLU_SMP ] & 0x07 ) + bias [ 1 ];
indcoord [ 2 ] = ( indmap [ TextureSampler :: GRN_SMP ] & 0x07 ) + bias [ 2 ];
AlphaBump = AlphaBump & 0xf8 ;
break ;
default :
PanicAlert ( "Tev::Indirect" );
return ;
}
2010-06-09 01:37:08 +00:00
2013-11-02 11:42:30 +01:00
s32 indtevtrans [ 2 ] = { 0 , 0 };
2010-06-09 01:37:08 +00:00
2013-11-02 11:42:30 +01:00
// matrix multiply - results might overflow, but we don't care since we only use the lower 24 bits of the result.
2013-04-13 23:54:02 -04:00
int indmtxid = indirect . mid & 3 ;
if ( indmtxid )
{
IND_MTX & indmtx = bpmem . indmtx [ indmtxid - 1 ];
int scale = (( u32 ) indmtx . col0 . s0 << 0 ) |
(( u32 ) indmtx . col1 . s1 << 2 ) |
(( u32 ) indmtx . col2 . s2 << 4 );
2010-06-09 01:37:08 +00:00
int shift ;
2013-04-13 23:54:02 -04:00
switch ( indirect . mid & 12 )
{
case 0 :
2013-10-10 21:09:00 +02:00
// matrix values are S0.10, output format is S17.7, so divide by 8
shift = ( 17 - scale );
indtevtrans [ 0 ] = ( indmtx . col0 . ma * indcoord [ 0 ] + indmtx . col1 . mc * indcoord [ 1 ] + indmtx . col2 . me * indcoord [ 2 ]) >> 3 ;
indtevtrans [ 1 ] = ( indmtx . col0 . mb * indcoord [ 0 ] + indmtx . col1 . md * indcoord [ 1 ] + indmtx . col2 . mf * indcoord [ 2 ]) >> 3 ;
2013-04-13 23:54:02 -04:00
break ;
case 4 : // s matrix
2013-10-10 21:09:00 +02:00
// s is S17.7, matrix elements are divided by 256, output is S17.7, so divide by 256. - TODO: Maybe, since s is actually stored as S24, we should divide by 256*64?
shift = ( 17 - scale );
indtevtrans [ 0 ] = s * indcoord [ 0 ] / 256 ;
indtevtrans [ 1 ] = t * indcoord [ 0 ] / 256 ;
2013-04-13 23:54:02 -04:00
break ;
case 8 : // t matrix
2013-10-10 21:09:00 +02:00
shift = ( 17 - scale );
indtevtrans [ 0 ] = s * indcoord [ 1 ] / 256 ;
indtevtrans [ 1 ] = t * indcoord [ 1 ] / 256 ;
2013-04-13 23:54:02 -04:00
break ;
default :
return ;
}
2010-06-09 01:37:08 +00:00
indtevtrans [ 0 ] = shift >= 0 ? indtevtrans [ 0 ] >> shift : indtevtrans [ 0 ] << - shift ;
indtevtrans [ 1 ] = shift >= 0 ? indtevtrans [ 1 ] >> shift : indtevtrans [ 1 ] << - shift ;
2013-04-13 23:54:02 -04:00
}
2010-06-09 01:37:08 +00:00
if ( indirect . fb_addprev )
2013-04-13 23:54:02 -04:00
{
TexCoord . s += ( int )( WrapIndirectCoord ( s , indirect . sw ) + indtevtrans [ 0 ]);
TexCoord . t += ( int )( WrapIndirectCoord ( t , indirect . tw ) + indtevtrans [ 1 ]);
}
else
{
TexCoord . s = ( int )( WrapIndirectCoord ( s , indirect . sw ) + indtevtrans [ 0 ]);
TexCoord . t = ( int )( WrapIndirectCoord ( t , indirect . tw ) + indtevtrans [ 1 ]);
}
2010-06-09 01:37:08 +00:00
}
void Tev :: Draw ()
{
2013-04-13 23:54:02 -04:00
_assert_ ( Position [ 0 ] >= 0 && Position [ 0 ] < EFB_WIDTH );
_assert_ ( Position [ 1 ] >= 0 && Position [ 1 ] < EFB_HEIGHT );
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
INCSTAT ( swstats . thisFrame . tevPixelsIn );
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
for ( unsigned int stageNum = 0 ; stageNum < bpmem . genMode . numindstages ; stageNum ++ )
{
int stageNum2 = stageNum >> 1 ;
int stageOdd = stageNum & 1 ;
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
u32 texcoordSel = bpmem . tevindref . getTexCoord ( stageNum );
u32 texmap = bpmem . tevindref . getTexMap ( stageNum );
2010-06-09 01:37:08 +00:00
const TEXSCALE & texscale = bpmem . texscale [ stageNum2 ];
s32 scaleS = stageOdd ? texscale . ss1 : texscale . ss0 ;
2013-04-13 23:54:02 -04:00
s32 scaleT = stageOdd ? texscale . ts1 : texscale . ts0 ;
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
TextureSampler :: Sample ( Uv [ texcoordSel ]. s >> scaleS , Uv [ texcoordSel ]. t >> scaleT ,
2010-06-09 01:37:08 +00:00
IndirectLod [ stageNum ], IndirectLinear [ stageNum ], texmap , IndirectTex [ stageNum ]);
2010-12-02 05:38:48 +00:00
#if ALLOW_TEV_DUMPS
2013-04-13 23:54:02 -04:00
if ( g_SWVideoConfig . bDumpTevStages )
{
2014-03-29 11:05:44 +01:00
u8 stage [ 4 ] = {
2014-02-16 15:30:18 -05:00
IndirectTex [ stageNum ][ TextureSampler :: ALP_SMP ],
IndirectTex [ stageNum ][ TextureSampler :: BLU_SMP ],
IndirectTex [ stageNum ][ TextureSampler :: GRN_SMP ],
255
};
2010-12-02 05:38:48 +00:00
DebugUtil :: DrawTempBuffer ( stage , INDIRECT + stageNum );
2013-04-13 23:54:02 -04:00
}
2010-06-09 01:37:08 +00:00
#endif
2013-04-13 23:54:02 -04:00
}
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
for ( unsigned int stageNum = 0 ; stageNum <= bpmem . genMode . numtevstages ; stageNum ++ )
{
int stageNum2 = stageNum >> 1 ;
int stageOdd = stageNum & 1 ;
TwoTevStageOrders & order = bpmem . tevorders [ stageNum2 ];
TevKSel & kSel = bpmem . tevksel [ stageNum2 ];
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
// stage combiners
TevStageCombiner :: ColorCombiner & cc = bpmem . combiners [ stageNum ]. colorC ;
TevStageCombiner :: AlphaCombiner & ac = bpmem . combiners [ stageNum ]. alphaC ;
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
int texcoordSel = order . getTexCoord ( stageOdd );
int texmap = order . getTexMap ( stageOdd );
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
Indirect ( stageNum , Uv [ texcoordSel ]. s , Uv [ texcoordSel ]. t );
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
// sample texture
if ( order . getEnable ( stageOdd ))
{
// RGBA
2010-12-31 06:45:18 +00:00
u8 texel [ 4 ];
2013-04-13 23:54:02 -04:00
2010-06-09 01:37:08 +00:00
TextureSampler :: Sample ( TexCoord . s , TexCoord . t , TextureLod [ stageNum ], TextureLinear [ stageNum ], texmap , texel );
2010-12-02 05:38:48 +00:00
#if ALLOW_TEV_DUMPS
2011-01-29 04:52:19 +00:00
if ( g_SWVideoConfig . bDumpTevTextureFetches )
2010-12-02 05:38:48 +00:00
DebugUtil :: DrawTempBuffer ( texel , DIRECT_TFETCH + stageNum );
#endif
2013-04-13 23:54:02 -04:00
int swaptable = ac . tswap * 2 ;
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
TexColor [ RED_C ] = texel [ bpmem . tevksel [ swaptable ]. swap1 ];
TexColor [ GRN_C ] = texel [ bpmem . tevksel [ swaptable ]. swap2 ];
swaptable ++ ;
TexColor [ BLU_C ] = texel [ bpmem . tevksel [ swaptable ]. swap1 ];
TexColor [ ALP_C ] = texel [ bpmem . tevksel [ swaptable ]. swap2 ];
}
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
// set konst for this stage
int kc = kSel . getKC ( stageOdd );
int ka = kSel . getKA ( stageOdd );
StageKonst [ RED_C ] = * ( m_KonstLUT [ kc ][ RED_C ]);
StageKonst [ GRN_C ] = * ( m_KonstLUT [ kc ][ GRN_C ]);
StageKonst [ BLU_C ] = * ( m_KonstLUT [ kc ][ BLU_C ]);
StageKonst [ ALP_C ] = * ( m_KonstLUT [ ka ][ ALP_C ]);
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
// set color
SetRasColor ( order . getColorChan ( stageOdd ), ac . rswap * 2 );
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
// combine inputs
2014-03-24 14:42:04 +01:00
InputRegType inputs [ 4 ];
for ( int i = 0 ; i < 3 ; i ++ )
{
inputs [ BLU_C + i ]. a = * m_ColorInputLUT [ cc . a ][ i ];
inputs [ BLU_C + i ]. b = * m_ColorInputLUT [ cc . b ][ i ];
inputs [ BLU_C + i ]. c = * m_ColorInputLUT [ cc . c ][ i ];
inputs [ BLU_C + i ]. d = * m_ColorInputLUT [ cc . d ][ i ];
}
inputs [ ALP_C ]. a = * m_AlphaInputLUT [ ac . a ];
inputs [ ALP_C ]. b = * m_AlphaInputLUT [ ac . b ];
inputs [ ALP_C ]. c = * m_AlphaInputLUT [ ac . c ];
inputs [ ALP_C ]. d = * m_AlphaInputLUT [ ac . d ];
2013-04-13 23:54:02 -04:00
if ( cc . bias != 3 )
2014-03-24 14:42:04 +01:00
DrawColorRegular ( cc , inputs );
2013-04-13 23:54:02 -04:00
else
2014-03-24 14:42:04 +01:00
DrawColorCompare ( cc , inputs );
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
if ( cc . clamp )
{
Reg [ cc . dest ][ RED_C ] = Clamp255 ( Reg [ cc . dest ][ RED_C ]);
Reg [ cc . dest ][ GRN_C ] = Clamp255 ( Reg [ cc . dest ][ GRN_C ]);
Reg [ cc . dest ][ BLU_C ] = Clamp255 ( Reg [ cc . dest ][ BLU_C ]);
}
else
{
Reg [ cc . dest ][ RED_C ] = Clamp1024 ( Reg [ cc . dest ][ RED_C ]);
Reg [ cc . dest ][ GRN_C ] = Clamp1024 ( Reg [ cc . dest ][ GRN_C ]);
Reg [ cc . dest ][ BLU_C ] = Clamp1024 ( Reg [ cc . dest ][ BLU_C ]);
}
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
if ( ac . bias != 3 )
2014-03-24 14:42:04 +01:00
DrawAlphaRegular ( ac , inputs );
2013-04-13 23:54:02 -04:00
else
2014-03-24 14:42:04 +01:00
DrawAlphaCompare ( ac , inputs );
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
if ( ac . clamp )
Reg [ ac . dest ][ ALP_C ] = Clamp255 ( Reg [ ac . dest ][ ALP_C ]);
else
Reg [ ac . dest ][ ALP_C ] = Clamp1024 ( Reg [ ac . dest ][ ALP_C ]);
2010-06-09 01:37:08 +00:00
2010-12-02 05:38:48 +00:00
#if ALLOW_TEV_DUMPS
2013-04-13 23:54:02 -04:00
if ( g_SWVideoConfig . bDumpTevStages )
{
u8 stage [ 4 ] = {( u8 ) Reg [ 0 ][ RED_C ], ( u8 ) Reg [ 0 ][ GRN_C ], ( u8 ) Reg [ 0 ][ BLU_C ], ( u8 ) Reg [ 0 ][ ALP_C ]};
2010-12-02 05:38:48 +00:00
DebugUtil :: DrawTempBuffer ( stage , DIRECT + stageNum );
2013-04-13 23:54:02 -04:00
}
2010-06-09 01:37:08 +00:00
#endif
2013-04-13 23:54:02 -04:00
}
2013-04-07 16:50:58 +02:00
// convert to 8 bits per component
// the results of the last tev stage are put onto the screen,
// regardless of the used destination register - TODO: Verify!
u32 color_index = bpmem . combiners [ bpmem . genMode . numtevstages ]. colorC . dest ;
u32 alpha_index = bpmem . combiners [ bpmem . genMode . numtevstages ]. alphaC . dest ;
u8 output [ 4 ] = {( u8 ) Reg [ alpha_index ][ ALP_C ], ( u8 ) Reg [ color_index ][ BLU_C ], ( u8 ) Reg [ color_index ][ GRN_C ], ( u8 ) Reg [ color_index ][ RED_C ]};
2010-06-09 01:37:08 +00:00
2013-04-13 23:54:02 -04:00
if ( ! TevAlphaTest ( output [ ALP_C ]))
return ;
2010-06-09 01:37:08 +00:00
2015-09-17 18:19:47 +02:00
// z texture
if ( bpmem . ztex2 . op )
2013-04-13 23:54:02 -04:00
{
2015-09-17 18:19:47 +02:00
u32 ztex = bpmem . ztex1 . bias ;
switch ( bpmem . ztex2 . type )
2013-04-13 23:54:02 -04:00
{
2015-09-17 18:19:47 +02:00
case 0 : // 8 bit
ztex += TexColor [ ALP_C ];
break ;
case 1 : // 16 bit
ztex += TexColor [ ALP_C ] << 8 | TexColor [ RED_C ];
break ;
case 2 : // 24 bit
ztex += TexColor [ RED_C ] << 16 | TexColor [ GRN_C ] << 8 | TexColor [ BLU_C ];
break ;
2013-04-13 23:54:02 -04:00
}
2010-06-09 01:37:08 +00:00
2015-09-17 18:19:47 +02:00
if ( bpmem . ztex2 . op == ZTEXTURE_ADD )
ztex += Position [ 2 ];
Position [ 2 ] = ztex & 0x00ffffff ;
}
// fog
if ( bpmem . fog . c_proj_fsel . fsel )
{
float ze ;
if ( bpmem . fog . c_proj_fsel . proj == 0 )
2014-09-14 17:52:51 +01:00
{
2015-09-17 18:19:47 +02:00
// perspective
// ze = A/(B - (Zs >> B_SHF))
s32 denom = bpmem . fog . b_magnitude - ( Position [ 2 ] >> bpmem . fog . b_shift );
//in addition downscale magnitude and zs to 0.24 bits
ze = ( bpmem . fog . a . GetA () * 16777215.0f ) / ( float ) denom ;
}
else
{
// orthographic
// ze = a*Zs
//in addition downscale zs to 0.24 bits
ze = bpmem . fog . a . GetA () * (( float ) Position [ 2 ] / 16777215.0f );
2010-06-09 01:37:08 +00:00
2014-09-14 17:52:51 +01:00
}
2015-09-17 18:19:47 +02:00
if ( bpmem . fogRange . Base . Enabled )
2014-09-14 17:52:51 +01:00
{
2015-09-17 18:19:47 +02:00
// TODO: This is untested and should definitely be checked against real hw.
// - No idea if offset is really normalized against the viewport width or against the projection matrix or yet something else
// - scaling of the "k" coefficient isn't clear either.
2014-09-14 17:52:51 +01:00
2015-09-17 18:19:47 +02:00
// First, calculate the offset from the viewport center (normalized to 0..1)
float offset = ( Position [ 0 ] - ( bpmem . fogRange . Base . Center - 342 )) / ( float ) xfmem . viewport . wd ;
2014-09-14 17:52:51 +01:00
2015-09-17 18:19:47 +02:00
// Based on that, choose the index such that points which are far away from the z-axis use the 10th "k" value and such that central points use the first value.
float floatindex = 9.f - std :: abs ( offset ) * 9.f ;
floatindex = ( floatindex < 0.f ) ? 0.f : ( floatindex > 9.f ) ? 9.f : floatindex ; // TODO: This shouldn't be necessary!
// Get the two closest integer indices, look up the corresponding samples
int indexlower = ( int ) floor ( floatindex );
int indexupper = indexlower + 1 ;
// Look up coefficient... Seems like multiplying by 4 makes Fortune Street work properly (fog is too strong without the factor)
float klower = bpmem . fogRange . K [ indexlower / 2 ]. GetValue ( indexlower % 2 ) * 4.f ;
float kupper = bpmem . fogRange . K [ indexupper / 2 ]. GetValue ( indexupper % 2 ) * 4.f ;
// linearly interpolate the samples and multiple ze by the resulting adjustment factor
float factor = indexupper - floatindex ;
float k = klower * factor + kupper * ( 1.f - factor );
float x_adjust = sqrt ( offset * offset + k * k ) / k ;
ze *= x_adjust ; // NOTE: This is basically dividing by a cosine (hidden behind GXInitFogAdjTable): 1/cos = c/b = sqrt(a^2+b^2)/b
2014-09-14 17:52:51 +01:00
}
2015-09-17 18:19:47 +02:00
ze -= bpmem . fog . c_proj_fsel . GetC ();
// clamp 0 to 1
float fog = ( ze < 0.0f ) ? 0.0f : (( ze > 1.0f ) ? 1.0f : ze );
switch ( bpmem . fog . c_proj_fsel . fsel )
{
case 4 : // exp
fog = 1.0f - pow ( 2.0f , - 8.0f * fog );
break ;
case 5 : // exp2
fog = 1.0f - pow ( 2.0f , - 8.0f * fog * fog );
break ;
case 6 : // backward exp
fog = 1.0f - fog ;
fog = pow ( 2.0f , - 8.0f * fog );
break ;
case 7 : // backward exp2
fog = 1.0f - fog ;
fog = pow ( 2.0f , - 8.0f * fog * fog );
break ;
}
// lerp from output to fog color
u32 fogInt = ( u32 )( fog * 256 );
u32 invFog = 256 - fogInt ;
output [ RED_C ] = ( output [ RED_C ] * invFog + fogInt * bpmem . fog . color . r ) >> 8 ;
output [ GRN_C ] = ( output [ GRN_C ] * invFog + fogInt * bpmem . fog . color . g ) >> 8 ;
output [ BLU_C ] = ( output [ BLU_C ] * invFog + fogInt * bpmem . fog . color . b ) >> 8 ;
}
bool late_ztest = ! bpmem . zcontrol . early_ztest || ! g_SWVideoConfig . bZComploc ;
if ( late_ztest && bpmem . zmode . testenable )
{
// TODO: Check against hw if these values get incremented even if depth testing is disabled
EfbInterface :: IncPerfCounterQuadCount ( PQ_ZCOMP_INPUT );
if ( ! EfbInterface :: ZCompare ( Position [ 0 ], Position [ 1 ], Position [ 2 ]))
return ;
EfbInterface :: IncPerfCounterQuadCount ( PQ_ZCOMP_OUTPUT );
2013-04-13 23:54:02 -04:00
}
2010-06-09 01:37:08 +00:00
2014-09-14 17:52:51 +01:00
// branchless bounding box update
BoundingBox :: coords [ BoundingBox :: LEFT ] = std :: min (( u16 ) Position [ 0 ], BoundingBox :: coords [ BoundingBox :: LEFT ]);
BoundingBox :: coords [ BoundingBox :: RIGHT ] = std :: max (( u16 ) Position [ 0 ], BoundingBox :: coords [ BoundingBox :: RIGHT ]);
BoundingBox :: coords [ BoundingBox :: TOP ] = std :: min (( u16 ) Position [ 1 ], BoundingBox :: coords [ BoundingBox :: TOP ]);
BoundingBox :: coords [ BoundingBox :: BOTTOM ] = std :: max (( u16 ) Position [ 1 ], BoundingBox :: coords [ BoundingBox :: BOTTOM ]);
2010-06-09 01:37:08 +00:00
2010-12-02 05:38:48 +00:00
#if ALLOW_TEV_DUMPS
2011-01-29 04:52:19 +00:00
if ( g_SWVideoConfig . bDumpTevStages )
2010-12-02 05:38:48 +00:00
{
for ( u32 i = 0 ; i < bpmem . genMode . numindstages ; ++ i )
DebugUtil :: CopyTempBuffer ( Position [ 0 ], Position [ 1 ], INDIRECT , i , "Indirect" );
for ( u32 i = 0 ; i <= bpmem . genMode . numtevstages ; ++ i )
DebugUtil :: CopyTempBuffer ( Position [ 0 ], Position [ 1 ], DIRECT , i , "Stage" );
}
2011-01-29 04:52:19 +00:00
if ( g_SWVideoConfig . bDumpTevTextureFetches )
2010-12-02 05:38:48 +00:00
{
for ( u32 i = 0 ; i <= bpmem . genMode . numtevstages ; ++ i )
{
TwoTevStageOrders & order = bpmem . tevorders [ i >> 1 ];
if ( order . getEnable ( i & 1 ))
DebugUtil :: CopyTempBuffer ( Position [ 0 ], Position [ 1 ], DIRECT_TFETCH , i , "TFetch" );
}
}
#endif
2013-04-13 23:54:02 -04:00
INCSTAT ( swstats . thisFrame . tevPixelsOut );
2014-03-28 19:22:15 -07:00
EfbInterface :: IncPerfCounterQuadCount ( PQ_BLEND_INPUT );
2012-06-17 19:49:48 +02:00
2013-04-13 23:54:02 -04:00
EfbInterface :: BlendTev ( Position [ 0 ], Position [ 1 ], output );
2010-06-09 01:37:08 +00:00
}
void Tev :: SetRegColor ( int reg , int comp , bool konst , s16 color )
{
2013-04-13 23:54:02 -04:00
if ( konst )
{
KonstantColors [ reg ][ comp ] = color ;
}
else
{
Reg [ reg ][ comp ] = color ;
}
2010-06-09 01:37:08 +00:00
}
2013-02-25 23:49:24 -05:00
void Tev :: DoState ( PointerWrap & p )
{
2015-09-29 12:35:30 -04:00
p . DoArray ( Reg );
2013-10-29 01:23:17 -04:00
2015-09-29 12:35:30 -04:00
p . DoArray ( KonstantColors );
p . DoArray ( TexColor );
p . DoArray ( RasColor );
p . DoArray ( StageKonst );
2013-04-13 23:54:02 -04:00
2015-09-29 12:35:30 -04:00
p . DoArray ( FixedConstants );
2013-02-25 23:49:24 -05:00
p . Do ( AlphaBump );
2015-09-29 12:35:30 -04:00
p . DoArray ( IndirectTex );
2013-02-25 23:49:24 -05:00
p . Do ( TexCoord );
2015-09-29 12:35:30 -04:00
p . DoArray ( m_BiasLUT );
p . DoArray ( m_ScaleLShiftLUT );
p . DoArray ( m_ScaleRShiftLUT );
2013-02-25 23:49:24 -05:00
2015-09-29 12:35:30 -04:00
p . DoArray ( Position );
p . DoArray ( Color );
p . DoArray ( Uv );
p . DoArray ( IndirectLod );
p . DoArray ( IndirectLinear );
p . DoArray ( TextureLod );
p . DoArray ( TextureLinear );
2013-02-25 23:49:24 -05:00
}