2013-04-18 03:29:41 +00:00
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
2010-06-09 01:37:08 +00:00
2014-02-17 10:18:15 +00:00
# include <cmath>
2010-06-09 01:37:08 +00:00
2014-07-30 00:55:07 +00:00
# include "Common/ChunkFile.h"
2014-09-08 01:06:58 +00:00
# include "Common/CommonTypes.h"
2014-02-17 10:18:15 +00: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 16:52:51 +00:00
# include "VideoCommon/BoundingBox.h"
2010-06-09 01:37:08 +00: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-14 03:54:02 +00:00
FixedConstants [ 0 ] = 0 ;
2014-05-14 20:27:00 +00:00
FixedConstants [ 1 ] = 32 ;
FixedConstants [ 2 ] = 64 ;
FixedConstants [ 3 ] = 96 ;
FixedConstants [ 4 ] = 128 ;
2013-04-14 03:54:02 +00:00
FixedConstants [ 5 ] = 159 ;
FixedConstants [ 6 ] = 191 ;
FixedConstants [ 7 ] = 223 ;
FixedConstants [ 8 ] = 255 ;
2014-03-03 05:25:15 +00:00
for ( s16 & comp : Zero16 )
{
comp = 0 ;
}
2013-04-14 03:54:02 +00: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
2014-03-24 13:42:04 +00: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
2013-04-14 03:54:02 +00: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 ] ;
2014-05-14 20:27:00 +00: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 ] ;
}
2013-04-14 03:54:02 +00: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 ] ;
}
m_BiasLUT [ 0 ] = 0 ;
m_BiasLUT [ 1 ] = 128 ;
m_BiasLUT [ 2 ] = - 128 ;
m_BiasLUT [ 3 ] = 0 ;
m_ScaleLShiftLUT [ 0 ] = 0 ;
m_ScaleLShiftLUT [ 1 ] = 1 ;
m_ScaleLShiftLUT [ 2 ] = 2 ;
m_ScaleLShiftLUT [ 3 ] = 0 ;
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-11 01:51:05 +00:00
static inline s16 Clamp255 ( s16 in )
2010-06-09 01:37:08 +00:00
{
2013-04-14 03:54:02 +00:00
return in > 255 ? 255 : ( in < 0 ? 0 : in ) ;
2010-06-09 01:37:08 +00:00
}
2014-08-11 01:51:05 +00:00
static inline s16 Clamp1024 ( s16 in )
2010-06-09 01:37:08 +00:00
{
2014-02-16 20:30:18 +00: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-10 11:30:55 +00:00
switch ( colorChan )
2013-04-14 03:54:02 +00: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 16:52:51 +00:00
case 5 : // alpha bump
2013-04-14 03:54:02 +00:00
{
2014-03-03 05:25:15 +00:00
for ( s16 & comp : RasColor )
{
comp = AlphaBump ;
}
2013-04-14 03:54:02 +00:00
}
break ;
case 6 : // alpha bump normalized
{
u8 normalized = AlphaBump | AlphaBump > > 5 ;
2014-03-03 05:25:15 +00:00
for ( s16 & comp : RasColor )
{
comp = normalized ;
}
2013-04-14 03:54:02 +00:00
}
break ;
default : // zero
{
2014-03-03 05:25:15 +00:00
for ( s16 & comp : RasColor )
{
comp = 0 ;
}
2013-04-14 03:54:02 +00:00
}
break ;
}
2010-06-09 01:37:08 +00:00
}
2014-03-24 13:42:04 +00:00
void Tev : : DrawColorRegular ( TevStageCombiner : : ColorCombiner & cc , const InputRegType inputs [ 4 ] )
2010-06-09 01:37:08 +00:00
{
2013-04-14 03:54:02 +00:00
for ( int i = 0 ; i < 3 ; i + + )
{
2014-03-24 13:42:04 +00:00
const InputRegType & InputReg = inputs [ BLU_C + i ] ;
2010-06-09 01:37:08 +00:00
2013-10-29 05:23:17 +00:00
u16 c = InputReg . c + ( InputReg . c > > 7 ) ;
2010-06-09 01:37:08 +00:00
2013-04-14 03:54:02 +00:00
s32 temp = InputReg . a * ( 256 - c ) + ( InputReg . b * c ) ;
2014-03-24 13:54:17 +00:00
temp < < = m_ScaleLShiftLUT [ cc . shift ] ;
2014-04-15 21:01:22 +00: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 13:54:17 +00:00
s32 result = ( ( InputReg . d + m_BiasLUT [ cc . bias ] ) < < m_ScaleLShiftLUT [ cc . shift ] ) + temp ;
2013-04-14 03:54:02 +00:00
result = result > > m_ScaleRShiftLUT [ cc . shift ] ;
2010-06-09 01:37:08 +00:00
2013-04-14 03:54:02 +00:00
Reg [ cc . dest ] [ BLU_C + i ] = result ;
}
2010-06-09 01:37:08 +00:00
}
2014-03-24 13:42:04 +00:00
void Tev : : DrawColorCompare ( TevStageCombiner : : ColorCombiner & cc , const InputRegType inputs [ 4 ] )
2010-06-09 01:37:08 +00:00
{
2014-04-15 21:05:12 +00:00
for ( int i = BLU_C ; i < = RED_C ; i + + )
2014-03-24 13:42:04 +00: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 ;
2013-04-14 03:54:02 +00:00
2014-03-24 13:42:04 +00: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 ;
2013-04-14 03:54:02 +00:00
2014-03-24 13:42:04 +00:00
case TEVCMP_GR16_GT :
2013-04-14 03:54:02 +00:00
{
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
}
2014-03-24 13:42:04 +00:00
break ;
2013-04-14 03:54:02 +00:00
2014-03-24 13:42:04 +00:00
case TEVCMP_GR16_EQ :
2013-04-14 03:54:02 +00:00
{
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
}
2014-03-24 13:42:04 +00:00
break ;
case TEVCMP_BGR24_GT :
2013-04-14 03:54:02 +00:00
{
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
}
2014-03-24 13:42:04 +00:00
break ;
case TEVCMP_BGR24_EQ :
2013-04-14 03:54:02 +00:00
{
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
}
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
}
}
2010-06-09 01:37:08 +00:00
}
2014-03-24 13:42:04 +00:00
void Tev : : DrawAlphaRegular ( TevStageCombiner : : AlphaCombiner & ac , const InputRegType inputs [ 4 ] )
2010-06-09 01:37:08 +00:00
{
2014-03-24 13:42:04 +00:00
const InputRegType & InputReg = inputs [ ALP_C ] ;
2010-06-09 01:37:08 +00:00
2013-10-29 05:23:17 +00:00
u16 c = InputReg . c + ( InputReg . c > > 7 ) ;
2010-06-09 01:37:08 +00:00
2013-04-14 03:54:02 +00:00
s32 temp = InputReg . a * ( 256 - c ) + ( InputReg . b * c ) ;
2014-03-24 13:54:17 +00: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 13:54:17 +00:00
s32 result = ( ( InputReg . d + m_BiasLUT [ ac . bias ] ) < < m_ScaleLShiftLUT [ ac . shift ] ) + temp ;
2013-04-14 03:54:02 +00:00
result = result > > m_ScaleRShiftLUT [ ac . shift ] ;
2010-06-09 01:37:08 +00:00
2013-04-14 03:54:02 +00:00
Reg [ ac . dest ] [ ALP_C ] = result ;
2010-06-09 01:37:08 +00:00
}
2014-03-24 13:42:04 +00:00
void Tev : : DrawAlphaCompare ( TevStageCombiner : : AlphaCombiner & ac , const InputRegType inputs [ 4 ] )
2010-06-09 01:37:08 +00:00
{
2014-03-24 13:42:04 +00:00
switch ( ( ac . shift < < 1 ) | ac . op | 8 ) // encoded compare mode
{
2013-04-14 03:54:02 +00:00
case TEVCMP_R8_GT :
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
break ;
case TEVCMP_R8_EQ :
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
break ;
2014-03-24 13:42:04 +00:00
2013-04-14 03:54:02 +00:00
case TEVCMP_GR16_GT :
{
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
}
break ;
2014-03-24 13:42:04 +00:00
2013-04-14 03:54:02 +00:00
case TEVCMP_GR16_EQ :
{
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
}
break ;
2014-03-24 13:42:04 +00:00
2013-04-14 03:54:02 +00:00
case TEVCMP_BGR24_GT :
{
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
}
break ;
2014-03-24 13:42:04 +00:00
2013-04-14 03:54:02 +00:00
case TEVCMP_BGR24_EQ :
{
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
}
break ;
2014-03-24 13:42:04 +00:00
2013-04-14 03:54:02 +00:00
case TEVCMP_A8_GT :
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
break ;
2014-03-24 13:42:04 +00:00
2013-04-14 03:54:02 +00:00
case TEVCMP_A8_EQ :
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
break ;
}
2010-06-09 01:37:08 +00:00
}
2014-03-24 19:21:34 +00:00
static bool AlphaCompare ( int alpha , int ref , AlphaTest : : CompareMode comp )
2010-06-09 01:37:08 +00:00
{
2014-08-11 01:18:38 +00:00
switch ( comp )
{
2014-03-24 19:21:34 +00: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 ;
2013-04-14 03:54:02 +00:00
}
2014-08-11 01:18:38 +00:00
2013-04-14 03:54:02 +00:00
return true ;
2010-06-09 01:37:08 +00:00
}
2013-01-31 21:29:29 +00:00
static bool TevAlphaTest ( int alpha )
2010-06-09 01:37:08 +00:00
{
2013-04-14 03:54:02 +00: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 ) ;
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
}
return true ;
2010-06-09 01:37:08 +00:00
}
2014-08-11 01:51:05 +00:00
static inline s32 WrapIndirectCoord ( s32 coord , int wrapMode )
2010-06-09 01:37:08 +00:00
{
2013-04-14 03:54:02 +00: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 ;
}
return 0 ;
2010-06-09 01:37:08 +00:00
}
void Tev : : Indirect ( unsigned int stageNum , s32 s , s32 t )
{
2013-04-14 03:54:02 +00:00
TevStageIndirect & indirect = bpmem . tevind [ stageNum ] ;
u8 * indmap = IndirectTex [ indirect . bt ] ;
2010-06-09 01:37:08 +00:00
2013-04-14 03:54:02 +00:00
s32 indcoord [ 3 ] ;
2010-06-09 01:37:08 +00:00
2013-04-14 03:54:02 +00:00
// alpha bump select
switch ( indirect . bs )
{
case ITBA_OFF :
AlphaBump = 0 ;
break ;
2013-09-12 11:55:38 +00:00
case ITBA_S :
2010-12-31 06:45:18 +00:00
AlphaBump = indmap [ TextureSampler : : ALP_SMP ] ;
2013-04-14 03:54:02 +00:00
break ;
case ITBA_T :
AlphaBump = indmap [ TextureSampler : : BLU_SMP ] ;
break ;
case ITBA_U :
AlphaBump = indmap [ TextureSampler : : GRN_SMP ] ;
break ;
}
// 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 ;
// format
2014-03-10 11:30:55 +00:00
switch ( indirect . fmt )
2013-04-14 03:54:02 +00: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 ;
}
2013-11-02 10:42:30 +00:00
s32 indtevtrans [ 2 ] = { 0 , 0 } ;
2013-04-14 03:54:02 +00:00
2013-11-02 10:42:30 +00:00
// matrix multiply - results might overflow, but we don't care since we only use the lower 24 bits of the result.
2013-04-14 03:54:02 +00: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-14 03:54:02 +00:00
switch ( indirect . mid & 12 )
{
case 0 :
2013-10-10 19:09:00 +00: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-14 03:54:02 +00:00
break ;
case 4 : // s matrix
2013-10-10 19:09:00 +00: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-14 03:54:02 +00:00
break ;
case 8 : // t matrix
2013-10-10 19:09:00 +00:00
shift = ( 17 - scale ) ;
indtevtrans [ 0 ] = s * indcoord [ 1 ] / 256 ;
indtevtrans [ 1 ] = t * indcoord [ 1 ] / 256 ;
2013-04-14 03:54:02 +00: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-14 03:54:02 +00:00
}
2010-06-09 01:37:08 +00:00
if ( indirect . fb_addprev )
2013-04-14 03:54:02 +00: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-14 03:54:02 +00: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-14 03:54:02 +00:00
INCSTAT ( swstats . thisFrame . tevPixelsIn ) ;
2010-06-09 01:37:08 +00:00
2013-04-14 03:54:02 +00: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-14 03:54:02 +00: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-14 03:54:02 +00:00
s32 scaleT = stageOdd ? texscale . ts1 : texscale . ts0 ;
2010-06-09 01:37:08 +00:00
2013-04-14 03:54:02 +00: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-14 03:54:02 +00:00
if ( g_SWVideoConfig . bDumpTevStages )
{
2014-03-29 10:05:44 +00:00
u8 stage [ 4 ] = {
2014-02-16 20:30:18 +00: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-14 03:54:02 +00:00
}
2010-06-09 01:37:08 +00:00
# endif
2013-04-14 03:54:02 +00:00
}
2010-06-09 01:37:08 +00:00
2013-04-14 03:54:02 +00: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-14 03:54:02 +00: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-14 03:54:02 +00:00
int texcoordSel = order . getTexCoord ( stageOdd ) ;
int texmap = order . getTexMap ( stageOdd ) ;
2010-06-09 01:37:08 +00:00
2013-04-14 03:54:02 +00:00
Indirect ( stageNum , Uv [ texcoordSel ] . s , Uv [ texcoordSel ] . t ) ;
2010-06-09 01:37:08 +00:00
2013-04-14 03:54:02 +00:00
// sample texture
if ( order . getEnable ( stageOdd ) )
{
// RGBA
2010-12-31 06:45:18 +00:00
u8 texel [ 4 ] ;
2013-04-14 03:54:02 +00: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-14 03:54:02 +00:00
int swaptable = ac . tswap * 2 ;
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 ] ;
}
// 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 ] ) ;
// set color
SetRasColor ( order . getColorChan ( stageOdd ) , ac . rswap * 2 ) ;
// combine inputs
2014-03-24 13:42:04 +00: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-14 03:54:02 +00:00
if ( cc . bias ! = 3 )
2014-03-24 13:42:04 +00:00
DrawColorRegular ( cc , inputs ) ;
2013-04-14 03:54:02 +00:00
else
2014-03-24 13:42:04 +00:00
DrawColorCompare ( cc , inputs ) ;
2013-04-14 03:54:02 +00: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 ] ) ;
}
if ( ac . bias ! = 3 )
2014-03-24 13:42:04 +00:00
DrawAlphaRegular ( ac , inputs ) ;
2013-04-14 03:54:02 +00:00
else
2014-03-24 13:42:04 +00:00
DrawAlphaCompare ( ac , inputs ) ;
2013-04-14 03:54:02 +00: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-14 03:54:02 +00: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-14 03:54:02 +00:00
}
2010-06-09 01:37:08 +00:00
# endif
2013-04-14 03:54:02 +00:00
}
2013-04-07 14:50:58 +00: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-14 03:54:02 +00:00
if ( ! TevAlphaTest ( output [ ALP_C ] ) )
return ;
2014-09-14 16:52:51 +00:00
// This part is only needed if we are not simply computing bbox
// (i. e., only needed when using the SW renderer)
if ( ! BoundingBox : : active )
2013-04-14 03:54:02 +00:00
{
2014-09-14 16:52:51 +00:00
// z texture
if ( bpmem . ztex2 . op )
2013-04-14 03:54:02 +00:00
{
2014-09-14 16:52:51 +00:00
u32 ztex = bpmem . ztex1 . bias ;
switch ( bpmem . ztex2 . type )
{
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 ;
}
if ( bpmem . ztex2 . op = = ZTEXTURE_ADD )
ztex + = Position [ 2 ] ;
Position [ 2 ] = ztex & 0x00ffffff ;
2013-04-14 03:54:02 +00:00
}
2014-09-14 16:52:51 +00:00
// fog
if ( bpmem . fog . c_proj_fsel . fsel )
{
float ze ;
2013-04-14 03:54:02 +00:00
2014-09-14 16:52:51 +00:00
if ( bpmem . fog . c_proj_fsel . proj = = 0 )
{
// 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 16:52:51 +00:00
}
2010-06-09 01:37:08 +00:00
2014-09-14 16:52:51 +00:00
if ( bpmem . fogRange . Base . Enabled )
{
// 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.
// 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 ;
// 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
}
2010-11-23 13:57:01 +00:00
2014-09-14 16:52:51 +00:00
ze - = bpmem . fog . c_proj_fsel . GetC ( ) ;
2010-06-09 01:37:08 +00:00
2014-09-14 16:52:51 +00:00
// clamp 0 to 1
float fog = ( ze < 0.0f ) ? 0.0f : ( ( ze > 1.0f ) ? 1.0f : ze ) ;
2010-11-23 13:57:01 +00:00
2014-09-14 16:52:51 +00:00
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 ;
}
2010-06-09 01:37:08 +00:00
2014-09-14 16:52:51 +00:00
// lerp from output to fog color
u32 fogInt = ( u32 ) ( fog * 256 ) ;
u32 invFog = 256 - fogInt ;
2010-06-09 01:37:08 +00:00
2014-09-14 16:52:51 +00:00
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 ;
2010-06-09 01:37:08 +00:00
}
2014-09-14 16:52:51 +00:00
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 ) ;
2010-06-09 01:37:08 +00:00
2014-09-14 16:52:51 +00:00
if ( ! EfbInterface : : ZCompare ( Position [ 0 ] , Position [ 1 ] , Position [ 2 ] ) )
return ;
EfbInterface : : IncPerfCounterQuadCount ( PQ_ZCOMP_OUTPUT ) ;
}
2010-06-09 01:37:08 +00:00
}
2014-09-14 16:52:51 +00: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 ] ) ;
2013-03-01 00:07:34 +00:00
2014-09-14 16:52:51 +00:00
// if we are only calculating the bounding box,
// there's no need to actually draw anything
if ( BoundingBox : : active )
return ;
2013-03-01 00:07:34 +00:00
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-14 03:54:02 +00:00
INCSTAT ( swstats . thisFrame . tevPixelsOut ) ;
2014-03-29 02:22:15 +00:00
EfbInterface : : IncPerfCounterQuadCount ( PQ_BLEND_INPUT ) ;
2012-06-17 17:49:48 +00:00
2013-04-14 03:54:02 +00: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-14 03:54:02 +00:00
if ( konst )
{
KonstantColors [ reg ] [ comp ] = color ;
}
else
{
Reg [ reg ] [ comp ] = color ;
}
2010-06-09 01:37:08 +00:00
}
2013-02-26 04:49:24 +00:00
void Tev : : DoState ( PointerWrap & p )
{
p . DoArray ( Reg , sizeof ( Reg ) ) ;
2013-10-29 05:23:17 +00:00
2013-02-26 04:49:24 +00:00
p . DoArray ( KonstantColors , sizeof ( KonstantColors ) ) ;
p . DoArray ( TexColor , 4 ) ;
p . DoArray ( RasColor , 4 ) ;
p . DoArray ( StageKonst , 4 ) ;
2013-04-14 03:54:02 +00:00
p . DoArray ( Zero16 , 4 ) ;
2013-02-26 04:49:24 +00:00
p . DoArray ( FixedConstants , 9 ) ;
p . Do ( AlphaBump ) ;
p . DoArray ( IndirectTex , sizeof ( IndirectTex ) ) ;
p . Do ( TexCoord ) ;
p . DoArray ( m_BiasLUT , 4 ) ;
2013-04-14 03:54:02 +00:00
p . DoArray ( m_ScaleLShiftLUT , 4 ) ;
p . DoArray ( m_ScaleRShiftLUT , 4 ) ;
2013-02-26 04:49:24 +00:00
p . DoArray ( Position , 3 ) ;
2013-04-14 03:54:02 +00:00
p . DoArray ( Color , sizeof ( Color ) ) ;
p . DoArray ( Uv , 8 ) ;
p . DoArray ( IndirectLod , 4 ) ;
2013-02-26 04:49:24 +00:00
p . DoArray ( IndirectLinear , 4 ) ;
p . DoArray ( TextureLod , 16 ) ;
p . DoArray ( TextureLinear , 16 ) ;
}