2009-07-28 21:32:10 +00:00
// Copyright (C) 2003 Dolphin Project.
2008-12-08 05:30:24 +00:00
// 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 <stdio.h>
# include <cmath>
# include <assert.h>
2009-10-14 01:58:39 +00:00
# include <locale.h>
2008-12-08 05:30:24 +00:00
2011-02-05 23:57:12 +00:00
# include "LightingShaderGen.h"
2008-12-26 17:33:53 +00:00
# include "PixelShaderGen.h"
2008-12-08 05:30:24 +00:00
# include "XFMemory.h" // for texture projection mode
2009-06-22 09:31:30 +00:00
# include "BPMemory.h"
2010-09-23 02:17:48 +00:00
# include "VideoConfig.h"
# include "NativeVertexFormat.h"
2012-08-10 18:57:37 +02:00
2011-09-29 21:52:13 +02:00
2013-01-11 19:38:04 -05:00
static void StageHash ( u32 stage , u32 * out )
2011-09-29 21:52:13 +02:00
{
out [ 0 ] | = bpmem . combiners [ stage ] . colorC . hex & 0xFFFFFF ; // 24
u32 alphaC = bpmem . combiners [ stage ] . alphaC . hex & 0xFFFFF0 ; // 24, strip out tswap and rswap for now
out [ 0 ] | = ( alphaC & 0xF0 ) < < 24 ; // 8
out [ 1 ] | = alphaC > > 8 ; // 16
// reserve 3 bits for bpmem.tevorders[stage/2].getTexMap
out [ 1 ] | = bpmem . tevorders [ stage / 2 ] . getTexCoord ( stage & 1 ) < < 19 ; // 3
out [ 1 ] | = bpmem . tevorders [ stage / 2 ] . getEnable ( stage & 1 ) < < 22 ; // 1
// reserve 3 bits for bpmem.tevorders[stage/2].getColorChan
bool bHasIndStage = bpmem . tevind [ stage ] . IsActive ( ) & & bpmem . tevind [ stage ] . bt < bpmem . genMode . numindstages ;
out [ 2 ] | = bHasIndStage < < 2 ; // 1
bool needstexcoord = false ;
if ( bHasIndStage )
{
out [ 2 ] | = ( bpmem . tevind [ stage ] . hex & 0x17FFFF ) < < 3 ; // 21, TODO: needs an explanation
needstexcoord = true ;
}
TevStageCombiner : : ColorCombiner & cc = bpmem . combiners [ stage ] . colorC ;
TevStageCombiner : : AlphaCombiner & ac = bpmem . combiners [ stage ] . alphaC ;
if ( cc . a = = TEVCOLORARG_RASA | | cc . a = = TEVCOLORARG_RASC
| | cc . b = = TEVCOLORARG_RASA | | cc . b = = TEVCOLORARG_RASC
| | cc . c = = TEVCOLORARG_RASA | | cc . c = = TEVCOLORARG_RASC
| | cc . d = = TEVCOLORARG_RASA | | cc . d = = TEVCOLORARG_RASC
| | ac . a = = TEVALPHAARG_RASA | | ac . b = = TEVALPHAARG_RASA
| | ac . c = = TEVALPHAARG_RASA | | ac . d = = TEVALPHAARG_RASA )
{
out [ 0 ] | = bpmem . combiners [ stage ] . alphaC . rswap ;
out [ 2 ] | = bpmem . tevksel [ bpmem . combiners [ stage ] . alphaC . rswap * 2 ] . swap1 < < 24 ; // 2
out [ 2 ] | = bpmem . tevksel [ bpmem . combiners [ stage ] . alphaC . rswap * 2 ] . swap2 < < 26 ; // 2
out [ 2 ] | = bpmem . tevksel [ bpmem . combiners [ stage ] . alphaC . rswap * 2 + 1 ] . swap1 < < 28 ; // 2
out [ 2 ] | = bpmem . tevksel [ bpmem . combiners [ stage ] . alphaC . rswap * 2 + 1 ] . swap2 < < 30 ; // 2
out [ 1 ] | = ( bpmem . tevorders [ stage / 2 ] . getColorChan ( stage & 1 ) & 1 ) < < 23 ;
out [ 2 ] | = ( bpmem . tevorders [ stage / 2 ] . getColorChan ( stage & 1 ) & 0x6 ) > > 1 ;
}
out [ 3 ] | = bpmem . tevorders [ stage / 2 ] . getEnable ( stage & 1 ) ;
if ( bpmem . tevorders [ stage / 2 ] . getEnable ( stage & 1 ) )
{
if ( bHasIndStage ) needstexcoord = true ;
out [ 0 ] | = bpmem . combiners [ stage ] . alphaC . tswap ;
out [ 3 ] | = bpmem . tevksel [ bpmem . combiners [ stage ] . alphaC . tswap * 2 ] . swap1 < < 1 ; // 2
out [ 3 ] | = bpmem . tevksel [ bpmem . combiners [ stage ] . alphaC . tswap * 2 ] . swap2 < < 3 ; // 2
out [ 3 ] | = bpmem . tevksel [ bpmem . combiners [ stage ] . alphaC . tswap * 2 + 1 ] . swap1 < < 5 ; // 2
out [ 3 ] | = bpmem . tevksel [ bpmem . combiners [ stage ] . alphaC . tswap * 2 + 1 ] . swap2 < < 7 ; // 2
out [ 1 ] | = bpmem . tevorders [ stage / 2 ] . getTexMap ( stage & 1 ) < < 16 ;
}
if ( cc . a = = TEVCOLORARG_KONST | | cc . b = = TEVCOLORARG_KONST | | cc . c = = TEVCOLORARG_KONST | | cc . d = = TEVCOLORARG_KONST
| | ac . a = = TEVALPHAARG_KONST | | ac . b = = TEVALPHAARG_KONST | | ac . c = = TEVALPHAARG_KONST | | ac . d = = TEVALPHAARG_KONST )
{
out [ 3 ] | = bpmem . tevksel [ stage / 2 ] . getKC ( stage & 1 ) < < 9 ; // 5
out [ 3 ] | = bpmem . tevksel [ stage / 2 ] . getKA ( stage & 1 ) < < 14 ; // 5
}
if ( needstexcoord )
{
out [ 1 ] | = bpmem . tevorders [ stage / 2 ] . getTexCoord ( stage & 1 ) < < 16 ;
}
}
2009-09-10 03:36:32 +00:00
2008-12-26 10:43:18 +00:00
// Mash together all the inputs that contribute to the code of a generated pixel shader into
// a unique identifier, basically containing all the bits. Yup, it's a lot ....
2009-07-03 18:33:28 +00:00
// It would likely be a lot more efficient to build this incrementally as the attributes
// are set...
2012-08-10 18:57:37 +02:00
void GetPixelShaderId ( PIXELSHADERUID * uid , DSTALPHA_MODE dstAlphaMode , u32 components )
2008-12-26 10:43:18 +00:00
{
2011-09-29 23:32:05 +02:00
memset ( uid - > values , 0 , sizeof ( uid - > values ) ) ;
2011-09-29 21:52:13 +02:00
uid - > values [ 0 ] | = bpmem . genMode . numtevstages ; // 4
uid - > values [ 0 ] | = bpmem . genMode . numtexgens < < 4 ; // 4
2012-08-10 18:57:37 +02:00
uid - > values [ 0 ] | = dstAlphaMode < < 8 ; // 2
bool enablePL = g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting ;
2013-01-08 16:40:15 +01:00
uid - > values [ 0 ] | = enablePL < < 10 ; // 1
2012-08-10 18:57:37 +02:00
2013-01-08 16:40:15 +01:00
if ( ! enablePL ) uid - > values [ 0 ] | = xfregs . numTexGen . numTexGens < < 11 ; // 4
2012-08-10 18:57:37 +02:00
2013-01-08 17:18:45 +01:00
AlphaTest : : TEST_RESULT alphaPreTest = bpmem . alpha_test . TestResult ( ) ;
2013-01-08 16:40:15 +01:00
uid - > values [ 0 ] | = alphaPreTest < < 15 ; // 2
2008-12-26 10:43:18 +00:00
2012-12-10 16:13:22 +01:00
// numtexgens should be <= 8
2011-09-29 21:52:13 +02:00
for ( unsigned int i = 0 ; i < bpmem . genMode . numtexgens ; + + i )
2013-01-08 16:40:15 +01:00
uid - > values [ 0 ] | = xfregs . texMtxInfo [ i ] . projection < < ( 17 + i ) ; // 1
2008-12-26 10:43:18 +00:00
2012-12-10 16:13:22 +01:00
uid - > values [ 1 ] = bpmem . genMode . numindstages ; // 3
2011-09-29 21:52:13 +02:00
u32 indirectStagesUsed = 0 ;
for ( unsigned int i = 0 ; i < bpmem . genMode . numindstages ; + + i )
if ( bpmem . tevind [ i ] . IsActive ( ) & & bpmem . tevind [ i ] . bt < bpmem . genMode . numindstages )
indirectStagesUsed | = ( 1 < < bpmem . tevind [ i ] . bt ) ;
2009-11-21 02:49:46 +00:00
2011-11-01 01:37:54 +01:00
assert ( indirectStagesUsed = = ( indirectStagesUsed & 0xF ) ) ;
2009-02-19 04:41:58 +00:00
2012-12-10 16:13:22 +01:00
uid - > values [ 1 ] | = indirectStagesUsed < < 3 ; // 4;
2011-09-29 21:52:13 +02:00
for ( unsigned int i = 0 ; i < bpmem . genMode . numindstages ; + + i )
2010-09-23 02:17:48 +00:00
{
2011-09-29 21:52:13 +02:00
if ( indirectStagesUsed & ( 1 < < i ) )
{
2012-12-10 16:13:22 +01:00
uid - > values [ 1 ] | = ( bpmem . tevindref . getTexCoord ( i ) < bpmem . genMode . numtexgens ) < < ( 7 + 3 * i ) ; // 1
2011-09-29 21:52:13 +02:00
if ( bpmem . tevindref . getTexCoord ( i ) < bpmem . genMode . numtexgens )
2012-12-10 16:13:22 +01:00
uid - > values [ 1 ] | = bpmem . tevindref . getTexCoord ( i ) < < ( 8 + 3 * i ) ; // 2
2010-09-23 02:17:48 +00:00
}
}
2011-09-29 21:52:13 +02:00
u32 * ptr = & uid - > values [ 2 ] ;
2013-01-11 22:00:36 -06:00
for ( unsigned int i = 0 ; i < bpmem . genMode . numtevstages + 1u ; + + i )
2009-07-26 09:52:35 +00:00
{
2011-09-29 21:52:13 +02:00
StageHash ( i , ptr ) ;
ptr + = 4 ; // max: ptr = &uid->values[66]
2008-12-26 10:43:18 +00:00
}
2013-01-08 17:18:45 +01:00
ptr [ 0 ] | = bpmem . alpha_test . comp0 ; // 3
ptr [ 0 ] | = bpmem . alpha_test . comp1 < < 3 ; // 3
ptr [ 0 ] | = bpmem . alpha_test . logic < < 6 ; // 2
2008-12-26 10:43:18 +00:00
2013-01-08 17:29:16 +01:00
ptr [ 0 ] | = bpmem . ztex2 . op < < 8 ; // 2
ptr [ 0 ] | = bpmem . zcontrol . early_ztest < < 10 ; // 1
ptr [ 0 ] | = bpmem . zmode . testenable < < 11 ; // 1
ptr [ 0 ] | = bpmem . zmode . updateenable < < 12 ; // 1
2008-12-26 10:43:18 +00:00
2012-08-10 18:57:37 +02:00
if ( dstAlphaMode ! = DSTALPHA_ALPHA_PASS )
2011-09-29 21:52:13 +02:00
{
2013-01-19 22:34:07 +01:00
ptr [ 0 ] | = bpmem . fog . c_proj_fsel . fsel < < 13 ; // 3
2011-09-29 21:52:13 +02:00
if ( bpmem . fog . c_proj_fsel . fsel ! = 0 )
2009-07-26 09:52:35 +00:00
{
2012-03-30 01:56:24 +02:00
ptr [ 0 ] | = bpmem . fog . c_proj_fsel . proj < < 16 ; // 1
ptr [ 0 ] | = bpmem . fogRange . Base . Enabled < < 17 ; // 1
2008-12-26 10:43:18 +00:00
}
}
2011-09-29 21:52:13 +02:00
+ + ptr ;
2012-08-10 18:57:37 +02:00
if ( enablePL )
2011-09-29 23:32:05 +02:00
{
2011-09-29 21:52:13 +02:00
ptr + = GetLightingShaderId ( ptr ) ;
2011-09-29 23:32:05 +02:00
* ptr + + = components ;
}
2008-12-26 10:43:18 +00:00
2012-10-26 11:34:02 -03:00
uid - > num_values = int ( ptr - uid - > values ) ;
2011-09-29 21:52:13 +02:00
}
2008-12-26 10:43:18 +00:00
2012-08-10 18:57:37 +02:00
void GetSafePixelShaderId ( PIXELSHADERUIDSAFE * uid , DSTALPHA_MODE dstAlphaMode , u32 components )
2011-09-29 21:52:13 +02:00
{
2011-09-29 23:32:05 +02:00
memset ( uid - > values , 0 , sizeof ( uid - > values ) ) ;
2011-09-29 21:52:13 +02:00
u32 * ptr = uid - > values ;
2012-08-10 18:57:37 +02:00
* ptr + + = dstAlphaMode ; // 0
2011-09-29 21:52:13 +02:00
* ptr + + = bpmem . genMode . hex ; // 1
* ptr + + = bpmem . ztex2 . hex ; // 2
* ptr + + = bpmem . zcontrol . hex ; // 3
* ptr + + = bpmem . zmode . hex ; // 4
2013-01-08 16:40:15 +01:00
* ptr + + = g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting ; // 5
* ptr + + = xfregs . numTexGen . hex ; // 6
2011-09-29 21:52:13 +02:00
2012-08-10 18:57:37 +02:00
if ( g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting )
2009-07-26 09:52:35 +00:00
{
2011-09-29 21:52:13 +02:00
* ptr + + = xfregs . color [ 0 ] . hex ;
* ptr + + = xfregs . alpha [ 0 ] . hex ;
* ptr + + = xfregs . color [ 1 ] . hex ;
* ptr + + = xfregs . alpha [ 1 ] . hex ;
2011-09-29 23:32:05 +02:00
* ptr + + = components ;
2011-09-29 21:52:13 +02:00
}
for ( unsigned int i = 0 ; i < 8 ; + + i )
2013-01-08 16:40:15 +01:00
* ptr + + = xfregs . texMtxInfo [ i ] . hex ; // 7-14
2011-09-29 21:52:13 +02:00
for ( unsigned int i = 0 ; i < 16 ; + + i )
2013-01-08 16:40:15 +01:00
* ptr + + = bpmem . tevind [ i ] . hex ; // 15-30
2011-09-29 21:52:13 +02:00
2013-01-08 16:40:15 +01:00
* ptr + + = bpmem . tevindref . hex ; // 31
2011-09-29 21:52:13 +02:00
2013-01-24 16:58:28 +01:00
for ( u32 i = 0 ; i < bpmem . genMode . numtevstages + 1u ; + + i ) // up to 16 times
2011-09-29 21:52:13 +02:00
{
2013-01-08 16:40:15 +01:00
* ptr + + = bpmem . combiners [ i ] . colorC . hex ; // 32+5*i
* ptr + + = bpmem . combiners [ i ] . alphaC . hex ; // 33+5*i
* ptr + + = bpmem . tevind [ i ] . hex ; // 34+5*i
* ptr + + = bpmem . tevksel [ i / 2 ] . hex ; // 35+5*i
* ptr + + = bpmem . tevorders [ i / 2 ] . hex ; // 36+5*i
2008-12-26 10:43:18 +00:00
}
2013-01-08 16:40:15 +01:00
ptr = & uid - > values [ 112 ] ;
2011-09-29 21:52:13 +02:00
2013-01-08 17:18:45 +01:00
* ptr + + = bpmem . alpha_test . hex ; // 112
2011-06-04 19:56:18 +00:00
2013-01-08 16:40:15 +01:00
* ptr + + = bpmem . fog . c_proj_fsel . hex ; // 113
* ptr + + = bpmem . fogRange . Base . hex ; // 114
2011-09-29 21:52:13 +02:00
_assert_ ( ( ptr - uid - > values ) = = uid - > GetNumValues ( ) ) ;
}
2012-08-10 18:57:37 +02:00
void ValidatePixelShaderIDs ( API_TYPE api , PIXELSHADERUIDSAFE old_id , const std : : string & old_code , DSTALPHA_MODE dstAlphaMode , u32 components )
2011-09-29 21:52:13 +02:00
{
if ( ! g_ActiveConfig . bEnableShaderDebugging )
return ;
PIXELSHADERUIDSAFE new_id ;
2012-08-10 18:57:37 +02:00
GetSafePixelShaderId ( & new_id , dstAlphaMode , components ) ;
2011-09-29 21:52:13 +02:00
if ( ! ( old_id = = new_id ) )
{
2012-08-10 18:57:37 +02:00
std : : string new_code ( GeneratePixelShaderCode ( dstAlphaMode , api , components ) ) ;
2011-09-29 21:52:13 +02:00
if ( old_code ! = new_code )
{
_assert_ ( old_id . GetNumValues ( ) = = new_id . GetNumValues ( ) ) ;
char msg [ 8192 ] ;
char * ptr = msg ;
ptr + = sprintf ( ptr , " Pixel shader IDs matched but unique IDs did not! \n Unique IDs (old <-> new): \n " ) ;
const int N = new_id . GetNumValues ( ) ;
for ( int i = 0 ; i < N / 2 ; + + i )
ptr + = sprintf ( ptr , " %02d, %08X %08X | %08X %08X \n " , 2 * i , old_id . values [ 2 * i ] , old_id . values [ 2 * i + 1 ] ,
new_id . values [ 2 * i ] , new_id . values [ 2 * i + 1 ] ) ;
if ( N % 2 )
ptr + = sprintf ( ptr , " %02d, %08X | %08X \n " , N - 1 , old_id . values [ N - 1 ] , new_id . values [ N - 1 ] ) ;
static int num_failures = 0 ;
char szTemp [ MAX_PATH ] ;
sprintf ( szTemp , " %spsuid_mismatch_%04i.txt " , File : : GetUserPath ( D_DUMP_IDX ) . c_str ( ) , num_failures + + ) ;
std : : ofstream file ( szTemp ) ;
file < < msg ;
file < < " \n \n Old shader code: \n " < < old_code ;
file < < " \n \n New shader code: \n " < < new_code ;
file . close ( ) ;
PanicAlert ( " Unique pixel shader ID mismatch! \n \n Report this to the devs, along with the contents of %s. " , szTemp ) ;
}
}
2008-12-26 10:43:18 +00:00
}
2008-12-08 05:30:24 +00:00
// old tev->pixelshader notes
//
2009-06-22 09:31:30 +00:00
// color for this stage (alpha, color) is given by bpmem.tevorders[0].colorchan0
2010-07-06 13:14:51 +00:00
// konstant for this stage (alpha, color) is given by bpmem.tevksel
2009-06-22 09:31:30 +00:00
// inputs are given by bpmem.combiners[0].colorC.a/b/c/d << could be current chan color
2008-12-08 05:30:24 +00:00
// according to GXTevColorArg table above
// output is given by .outreg
2011-06-04 19:56:18 +00:00
// tevtemp is set according to swapmodetables and
2008-12-08 05:30:24 +00:00
2011-01-09 14:13:24 +00:00
static void WriteStage ( char * & p , int n , API_TYPE ApiType ) ;
2010-08-29 19:34:54 +00:00
static void SampleTexture ( char * & p , const char * destination , const char * texcoords , const char * texswap , int texmap , API_TYPE ApiType ) ;
2010-02-24 03:38:36 +00:00
// static void WriteAlphaCompare(char *&p, int num, int comp);
2012-08-10 18:57:37 +02:00
static void WriteAlphaTest ( char * & p , API_TYPE ApiType , DSTALPHA_MODE dstAlphaMode ) ;
2009-05-15 02:39:55 +00:00
static void WriteFog ( char * & p ) ;
2008-12-08 05:30:24 +00:00
static const char * tevKSelTableC [ ] = // KCSEL
{
2010-07-06 13:14:51 +00:00
" 1.0f,1.0f,1.0f " , // 1 = 0x00
" 0.875f,0.875f,0.875f " , // 7_8 = 0x01
" 0.75f,0.75f,0.75f " , // 3_4 = 0x02
" 0.625f,0.625f,0.625f " , // 5_8 = 0x03
" 0.5f,0.5f,0.5f " , // 1_2 = 0x04
" 0.375f,0.375f,0.375f " , // 3_8 = 0x05
" 0.25f,0.25f,0.25f " , // 1_4 = 0x06
" 0.125f,0.125f,0.125f " , // 1_8 = 0x07
2013-01-11 15:47:38 +01:00
" ERROR1 " , // 0x08
" ERROR2 " , // 0x09
" ERROR3 " , // 0x0a
" ERROR4 " , // 0x0b
2010-07-06 13:14:51 +00:00
I_KCOLORS " [0].rgb " , // K0 = 0x0C
I_KCOLORS " [1].rgb " , // K1 = 0x0D
I_KCOLORS " [2].rgb " , // K2 = 0x0E
I_KCOLORS " [3].rgb " , // K3 = 0x0F
I_KCOLORS " [0].rrr " , // K0_R = 0x10
I_KCOLORS " [1].rrr " , // K1_R = 0x11
I_KCOLORS " [2].rrr " , // K2_R = 0x12
I_KCOLORS " [3].rrr " , // K3_R = 0x13
2011-06-04 19:56:18 +00:00
I_KCOLORS " [0].ggg " , // K0_G = 0x14
2010-07-06 13:14:51 +00:00
I_KCOLORS " [1].ggg " , // K1_G = 0x15
I_KCOLORS " [2].ggg " , // K2_G = 0x16
I_KCOLORS " [3].ggg " , // K3_G = 0x17
I_KCOLORS " [0].bbb " , // K0_B = 0x18
I_KCOLORS " [1].bbb " , // K1_B = 0x19
I_KCOLORS " [2].bbb " , // K2_B = 0x1A
I_KCOLORS " [3].bbb " , // K3_B = 0x1B
I_KCOLORS " [0].aaa " , // K0_A = 0x1C
I_KCOLORS " [1].aaa " , // K1_A = 0x1D
I_KCOLORS " [2].aaa " , // K2_A = 0x1E
I_KCOLORS " [3].aaa " , // K3_A = 0x1F
2008-12-08 05:30:24 +00:00
} ;
static const char * tevKSelTableA [ ] = // KASEL
{
2010-07-06 13:14:51 +00:00
" 1.0f " , // 1 = 0x00
" 0.875f " , // 7_8 = 0x01
" 0.75f " , // 3_4 = 0x02
" 0.625f " , // 5_8 = 0x03
" 0.5f " , // 1_2 = 0x04
" 0.375f " , // 3_8 = 0x05
" 0.25f " , // 1_4 = 0x06
" 0.125f " , // 1_8 = 0x07
2013-01-11 15:47:38 +01:00
" ERROR5 " , // 0x08
" ERROR6 " , // 0x09
" ERROR7 " , // 0x0a
" ERROR8 " , // 0x0b
" ERROR9 " , // 0x0c
" ERROR10 " , // 0x0d
" ERROR11 " , // 0x0e
" ERROR12 " , // 0x0f
2010-07-06 13:14:51 +00:00
I_KCOLORS " [0].r " , // K0_R = 0x10
I_KCOLORS " [1].r " , // K1_R = 0x11
I_KCOLORS " [2].r " , // K2_R = 0x12
I_KCOLORS " [3].r " , // K3_R = 0x13
I_KCOLORS " [0].g " , // K0_G = 0x14
I_KCOLORS " [1].g " , // K1_G = 0x15
I_KCOLORS " [2].g " , // K2_G = 0x16
I_KCOLORS " [3].g " , // K3_G = 0x17
I_KCOLORS " [0].b " , // K0_B = 0x18
I_KCOLORS " [1].b " , // K1_B = 0x19
I_KCOLORS " [2].b " , // K2_B = 0x1A
I_KCOLORS " [3].b " , // K3_B = 0x1B
I_KCOLORS " [0].a " , // K0_A = 0x1C
I_KCOLORS " [1].a " , // K1_A = 0x1D
I_KCOLORS " [2].a " , // K2_A = 0x1E
I_KCOLORS " [3].a " , // K3_A = 0x1F
2008-12-08 05:30:24 +00:00
} ;
static const char * tevScaleTable [ ] = // CS
{
2010-07-06 13:14:51 +00:00
" 1.0f " , // SCALE_1
" 2.0f " , // SCALE_2
" 4.0f " , // SCALE_4
" 0.5f " , // DIVIDE_2
2008-12-08 05:30:24 +00:00
} ;
static const char * tevBiasTable [ ] = // TB
{
2010-07-06 13:14:51 +00:00
" " , // ZERO,
" +0.5f " , // ADDHALF,
" -0.5f " , // SUBHALF,
" " ,
2008-12-08 05:30:24 +00:00
} ;
static const char * tevOpTable [ ] = { // TEV
2010-07-06 13:14:51 +00:00
" + " , // TEVOP_ADD = 0,
" - " , // TEVOP_SUB = 1,
2008-12-08 05:30:24 +00:00
} ;
static const char * tevCInputTable [ ] = // CC
{
2010-07-06 13:14:51 +00:00
" (prev.rgb) " , // CPREV,
" (prev.aaa) " , // APREV,
" (c0.rgb) " , // C0,
" (c0.aaa) " , // A0,
" (c1.rgb) " , // C1,
" (c1.aaa) " , // A1,
" (c2.rgb) " , // C2,
" (c2.aaa) " , // A2,
" (textemp.rgb) " , // TEXC,
" (textemp.aaa) " , // TEXA,
" (rastemp.rgb) " , // RASC,
" (rastemp.aaa) " , // RASA,
" float3(1.0f, 1.0f, 1.0f) " , // ONE
" float3(0.5f, 0.5f, 0.5f) " , // HALF
" (konsttemp.rgb) " , //"konsttemp.rgb", // KONST
" float3(0.0f, 0.0f, 0.0f) " , // ZERO
2010-05-27 21:43:07 +00:00
///aded extra values to map clamped values
" (cprev.rgb) " , // CPREV,
2010-07-06 13:14:51 +00:00
" (cprev.aaa) " , // APREV,
" (cc0.rgb) " , // C0,
" (cc0.aaa) " , // A0,
" (cc1.rgb) " , // C1,
" (cc1.aaa) " , // A1,
" (cc2.rgb) " , // C2,
" (cc2.aaa) " , // A2,
" (textemp.rgb) " , // TEXC,
" (textemp.aaa) " , // TEXA,
2010-08-16 22:37:04 +00:00
" (crastemp.rgb) " , // RASC,
" (crastemp.aaa) " , // RASA,
2010-07-06 13:14:51 +00:00
" float3(1.0f, 1.0f, 1.0f) " , // ONE
" float3(0.5f, 0.5f, 0.5f) " , // HALF
2010-08-16 22:37:04 +00:00
" (ckonsttemp.rgb) " , //"konsttemp.rgb", // KONST
2010-07-06 13:14:51 +00:00
" float3(0.0f, 0.0f, 0.0f) " , // ZERO
2013-01-11 15:47:38 +01:00
" PADERROR1 " , " PADERROR2 " , " PADERROR3 " , " PADERROR4 "
2008-12-08 05:30:24 +00:00
} ;
static const char * tevAInputTable [ ] = // CA
{
2010-07-06 13:14:51 +00:00
" prev " , // APREV,
" c0 " , // A0,
" c1 " , // A1,
" c2 " , // A2,
" textemp " , // TEXA,
" rastemp " , // RASA,
" konsttemp " , // KONST, (hw1 had quarter)
" float4(0.0f, 0.0f, 0.0f, 0.0f) " , // ZERO
///aded extra values to map clamped values
2010-05-27 21:43:07 +00:00
" cprev " , // APREV,
2010-07-06 13:14:51 +00:00
" cc0 " , // A0,
" cc1 " , // A1,
" cc2 " , // A2,
" textemp " , // TEXA,
2010-08-16 22:37:04 +00:00
" crastemp " , // RASA,
" ckonsttemp " , // KONST, (hw1 had quarter)
2010-07-06 13:14:51 +00:00
" float4(0.0f, 0.0f, 0.0f, 0.0f) " , // ZERO
2013-01-11 15:47:38 +01:00
" PADERROR5 " , " PADERROR6 " , " PADERROR7 " , " PADERROR8 " ,
" PADERROR9 " , " PADERROR10 " , " PADERROR11 " , " PADERROR12 " ,
2010-07-06 13:14:51 +00:00
} ;
2008-12-08 05:30:24 +00:00
static const char * tevRasTable [ ] =
{
2010-07-06 13:14:51 +00:00
" colors_0 " ,
" colors_1 " ,
2013-01-11 15:47:38 +01:00
" ERROR13 " , //2
" ERROR14 " , //3
" ERROR15 " , //4
2010-07-06 13:14:51 +00:00
" alphabump " , // use bump alpha
" (alphabump*(255.0f/248.0f)) " , //normalized
" float4(0.0f, 0.0f, 0.0f, 0.0f) " , // zero
2008-12-08 05:30:24 +00:00
} ;
//static const char *tevTexFunc[] = { "tex2D", "texRECT" };
static const char * tevCOutputTable [ ] = { " prev.rgb " , " c0.rgb " , " c1.rgb " , " c2.rgb " } ;
static const char * tevAOutputTable [ ] = { " prev.a " , " c0.a " , " c1.a " , " c2.a " } ;
2008-12-26 17:26:18 +00:00
static const char * tevIndAlphaSel [ ] = { " " , " x " , " y " , " z " } ;
2010-07-06 13:14:51 +00:00
//static const char *tevIndAlphaScale[] = {"", "*32", "*16", "*8"};
static const char * tevIndAlphaScale [ ] = { " *(248.0f/255.0f) " , " *(224.0f/255.0f) " , " *(240.0f/255.0f) " , " *(248.0f/255.0f) " } ;
2008-12-26 17:26:18 +00:00
static const char * tevIndBiasField [ ] = { " " , " x " , " y " , " xy " , " z " , " xz " , " yz " , " xyz " } ; // indexed by bias
static const char * tevIndBiasAdd [ ] = { " -128.0f " , " 1.0f " , " 1.0f " , " 1.0f " } ; // indexed by fmt
2010-04-03 22:22:55 +00:00
static const char * tevIndWrapStart [ ] = { " 0.0f " , " 256.0f " , " 128.0f " , " 64.0f " , " 32.0f " , " 16.0f " , " 0.001f " } ;
2009-04-15 03:55:38 +00:00
static const char * tevIndFmtScale [ ] = { " 255.0f " , " 31.0f " , " 15.0f " , " 7.0f " } ;
2008-12-08 05:30:24 +00:00
# define WRITE p+=sprintf
static char swapModeTable [ 4 ] [ 5 ] ;
static char text [ 16384 ] ;
2012-08-11 16:54:46 +02:00
struct RegisterState
{
bool ColorNeedOverflowControl ;
bool AlphaNeedOverflowControl ;
bool AuxStored ;
} ;
static RegisterState RegisterStates [ 4 ] ;
2008-12-08 05:30:24 +00:00
static void BuildSwapModeTable ( )
{
2011-09-29 21:52:13 +02:00
static const char * swapColors = " rgba " ;
2010-07-06 13:14:51 +00:00
for ( int i = 0 ; i < 4 ; i + + )
{
swapModeTable [ i ] [ 0 ] = swapColors [ bpmem . tevksel [ i * 2 ] . swap1 ] ;
swapModeTable [ i ] [ 1 ] = swapColors [ bpmem . tevksel [ i * 2 ] . swap2 ] ;
swapModeTable [ i ] [ 2 ] = swapColors [ bpmem . tevksel [ i * 2 + 1 ] . swap1 ] ;
swapModeTable [ i ] [ 3 ] = swapColors [ bpmem . tevksel [ i * 2 + 1 ] . swap2 ] ;
swapModeTable [ i ] [ 4 ] = 0 ;
}
2008-12-08 05:30:24 +00:00
}
2011-11-30 21:00:21 -06:00
const char * WriteRegister ( API_TYPE ApiType , const char * prefix , const u32 num )
2008-12-08 05:30:24 +00:00
{
2012-12-27 22:46:29 -06:00
if ( ApiType = = API_OPENGL )
2011-12-10 07:38:30 -06:00
return " " ; // Nothing to do here
static char result [ 64 ] ;
sprintf ( result , " : register(%s%d) " , prefix , num ) ;
return result ;
2011-11-30 21:00:21 -06:00
}
2011-12-26 00:15:54 -05:00
2011-12-09 21:15:15 -06:00
const char * WriteLocation ( API_TYPE ApiType )
{
2012-12-27 22:46:29 -06:00
if ( g_ActiveConfig . backend_info . bSupportsGLSLUBO )
2011-12-09 21:15:15 -06:00
return " " ;
2011-12-10 07:38:30 -06:00
static char result [ 64 ] ;
2011-12-09 21:15:15 -06:00
sprintf ( result , " uniform " ) ;
return result ;
}
2008-12-08 05:30:24 +00:00
2011-11-30 21:00:21 -06:00
const char * GeneratePixelShaderCode ( DSTALPHA_MODE dstAlphaMode , API_TYPE ApiType , u32 components )
{
2011-12-08 01:51:08 -06:00
setlocale ( LC_NUMERIC , " C " ) ; // Reset locale for compilation
text [ sizeof ( text ) - 1 ] = 0x7C ; // canary
BuildSwapModeTable ( ) ; // Needed for WriteStage
int numStages = bpmem . genMode . numtevstages + 1 ;
int numTexgen = bpmem . genMode . numtexgens ;
char * p = text ;
WRITE ( p , " //Pixel Shader for TEV stages \n " ) ;
WRITE ( p , " //%i TEV stages, %i texgens, XXX IND stages \n " ,
numStages , numTexgen /*, bpmem.genMode.numindstages*/ ) ;
int nIndirectStagesUsed = 0 ;
if ( bpmem . genMode . numindstages > 0 )
{
for ( int i = 0 ; i < numStages ; + + i )
{
if ( bpmem . tevind [ i ] . IsActive ( ) & & bpmem . tevind [ i ] . bt < bpmem . genMode . numindstages )
nIndirectStagesUsed | = 1 < < bpmem . tevind [ i ] . bt ;
}
}
2012-12-27 22:46:29 -06:00
if ( ApiType = = API_OPENGL )
2011-12-08 01:51:08 -06:00
{
2012-12-28 14:18:39 -06:00
// A function here
// Fmod implementation gleaned from Nvidia
// At http://http.developer.nvidia.com/Cg/fmod.html
WRITE ( p , " float fmod( float x, float y ) \n " ) ;
WRITE ( p , " { \n " ) ;
WRITE ( p , " \t float z = fract( abs( x / y) ) * abs( y ); \n " ) ;
WRITE ( p , " \t return (x < 0) ? -z : z; \n " ) ;
WRITE ( p , " } \n " ) ;
2011-12-11 07:02:13 -06:00
2011-12-08 01:51:08 -06:00
for ( int i = 0 ; i < 8 ; + + i )
2013-01-02 16:56:08 +01:00
WRITE ( p , " uniform sampler2D samp%d; \n " , i ) ;
2011-12-08 01:51:08 -06:00
}
else
{
// Declare samplers
2011-12-26 00:15:54 -05:00
if ( ApiType ! = API_D3D11 )
2011-12-08 01:51:08 -06:00
{
WRITE ( p , " uniform sampler2D " ) ;
}
else
{
WRITE ( p , " sampler " ) ;
}
bool bfirst = true ;
for ( int i = 0 ; i < 8 ; + + i )
{
WRITE ( p , " %s samp%d %s " , bfirst ? " " : " , " , i , WriteRegister ( ApiType , " s " , i ) ) ;
bfirst = false ;
}
WRITE ( p , " ; \n " ) ;
2011-12-26 00:15:54 -05:00
if ( ApiType = = API_D3D11 )
2011-12-08 01:51:08 -06:00
{
WRITE ( p , " Texture2D " ) ;
bfirst = true ;
for ( int i = 0 ; i < 8 ; + + i )
{
WRITE ( p , " %s Tex%d : register(t%d) " , bfirst ? " " : " , " , i , i ) ;
bfirst = false ;
}
WRITE ( p , " ; \n " ) ;
}
}
WRITE ( p , " \n " ) ;
2012-12-27 22:46:29 -06:00
if ( g_ActiveConfig . backend_info . bSupportsGLSLUBO )
2011-12-21 01:29:29 -06:00
WRITE ( p , " layout(std140) uniform PSBlock { \n " ) ;
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t %sfloat4 " I_COLORS " [4] %s; \n " , WriteLocation ( ApiType ) , WriteRegister ( ApiType , " c " , C_COLORS ) ) ;
WRITE ( p , " \t %sfloat4 " I_KCOLORS " [4] %s; \n " , WriteLocation ( ApiType ) , WriteRegister ( ApiType , " c " , C_KCOLORS ) ) ;
WRITE ( p , " \t %sfloat4 " I_ALPHA " [1] %s; \n " , WriteLocation ( ApiType ) , WriteRegister ( ApiType , " c " , C_ALPHA ) ) ;
WRITE ( p , " \t %sfloat4 " I_TEXDIMS " [8] %s; \n " , WriteLocation ( ApiType ) , WriteRegister ( ApiType , " c " , C_TEXDIMS ) ) ;
WRITE ( p , " \t %sfloat4 " I_ZBIAS " [2] %s; \n " , WriteLocation ( ApiType ) , WriteRegister ( ApiType , " c " , C_ZBIAS ) ) ;
WRITE ( p , " \t %sfloat4 " I_INDTEXSCALE " [2] %s; \n " , WriteLocation ( ApiType ) , WriteRegister ( ApiType , " c " , C_INDTEXSCALE ) ) ;
WRITE ( p , " \t %sfloat4 " I_INDTEXMTX " [6] %s; \n " , WriteLocation ( ApiType ) , WriteRegister ( ApiType , " c " , C_INDTEXMTX ) ) ;
WRITE ( p , " \t %sfloat4 " I_FOG " [3] %s; \n " , WriteLocation ( ApiType ) , WriteRegister ( ApiType , " c " , C_FOG ) ) ;
// For pixel lighting
WRITE ( p , " \t %sfloat4 " I_PLIGHTS " [40] %s; \n " , WriteLocation ( ApiType ) , WriteRegister ( ApiType , " c " , C_PLIGHTS ) ) ;
WRITE ( p , " \t %sfloat4 " I_PMATERIALS " [4] %s; \n " , WriteLocation ( ApiType ) , WriteRegister ( ApiType , " c " , C_PMATERIALS ) ) ;
2011-12-09 17:30:05 -06:00
2012-12-27 22:46:29 -06:00
if ( g_ActiveConfig . backend_info . bSupportsGLSLUBO )
2011-12-09 17:30:05 -06:00
WRITE ( p , " }; \n " ) ;
2011-06-04 19:56:18 +00:00
2012-12-28 14:18:39 -06:00
if ( ApiType = = API_OPENGL )
2010-10-21 05:22:18 +00:00
{
2013-01-02 16:56:08 +01:00
WRITE ( p , " out float4 ocol0; \n " ) ;
2011-12-26 00:15:54 -05:00
if ( dstAlphaMode = = DSTALPHA_DUAL_SOURCE_BLEND )
2013-01-02 16:56:08 +01:00
WRITE ( p , " out float4 ocol1; \n " ) ;
2013-01-24 16:58:28 +01:00
WRITE ( p , " float depth; \n " ) ;
2012-12-28 14:18:39 -06:00
WRITE ( p , " float4 rawpos = gl_FragCoord; \n " ) ;
2008-12-08 05:30:24 +00:00
2012-12-28 14:18:39 -06:00
WRITE ( p , " VARYIN float4 colors_02; \n " ) ;
WRITE ( p , " VARYIN float4 colors_12; \n " ) ;
WRITE ( p , " float4 colors_0 = colors_02; \n " ) ;
WRITE ( p , " float4 colors_1 = colors_12; \n " ) ;
2011-11-30 21:00:21 -06:00
// compute window position if needed because binding semantic WPOS is not widely supported
2012-01-11 01:18:54 -06:00
// Let's set up attributes
if ( xfregs . numTexGen . numTexGens < 7 )
2010-11-24 19:13:19 +00:00
{
2012-01-11 01:18:54 -06:00
for ( int i = 0 ; i < 8 ; + + i )
{
2012-12-28 14:18:39 -06:00
WRITE ( p , " VARYIN float3 uv%d_2; \n " , i ) ;
WRITE ( p , " float3 uv%d = uv%d_2; \n " , i , i ) ;
2012-01-11 01:18:54 -06:00
}
2012-12-28 14:18:39 -06:00
WRITE ( p , " VARYIN float4 clipPos_2; \n " ) ;
WRITE ( p , " float4 clipPos = clipPos_2; \n " ) ;
2011-12-26 00:15:54 -05:00
if ( g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting )
2012-01-11 01:18:54 -06:00
{
2012-12-28 14:18:39 -06:00
WRITE ( p , " VARYIN float4 Normal_2; \n " ) ;
WRITE ( p , " float4 Normal = Normal_2; \n " ) ;
2012-01-11 01:18:54 -06:00
}
2010-11-24 19:13:19 +00:00
}
else
{
2011-11-30 21:00:21 -06:00
// wpos is in w of first 4 texcoords
2011-12-26 00:15:54 -05:00
if ( g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting )
2011-11-30 21:00:21 -06:00
{
2011-12-18 21:06:28 -06:00
for ( int i = 0 ; i < 8 ; + + i )
2012-01-11 01:18:54 -06:00
{
2012-12-28 14:18:39 -06:00
WRITE ( p , " VARYIN float4 uv%d_2; \n " , i ) ;
WRITE ( p , " float4 uv%d = uv%d_2; \n " , i , i ) ;
2012-01-11 01:18:54 -06:00
}
2011-11-30 21:00:21 -06:00
}
else
{
2011-12-18 21:06:28 -06:00
for ( unsigned int i = 0 ; i < xfregs . numTexGen . numTexGens ; + + i )
2012-01-11 01:18:54 -06:00
{
2012-12-28 14:18:39 -06:00
WRITE ( p , " VARYIN float%d uv%d_2; \n " , i < 4 ? 4 : 3 , i ) ;
WRITE ( p , " float%d uv%d = uv%d_2; \n " , i < 4 ? 4 : 3 , i , i ) ;
2012-01-11 01:18:54 -06:00
}
2011-11-30 21:00:21 -06:00
}
2012-12-28 14:18:39 -06:00
WRITE ( p , " float4 clipPos; \n " ) ;
2010-11-24 19:13:19 +00:00
}
2011-11-30 21:00:21 -06:00
WRITE ( p , " void main() \n { \n " ) ;
2009-02-19 04:41:58 +00:00
}
2012-12-28 14:18:39 -06:00
else
{
WRITE ( p , " void main( \n " ) ;
if ( ApiType ! = API_D3D11 )
{
WRITE ( p , " out float4 ocol0 : COLOR0,%s%s \n in float4 rawpos : %s, \n " ,
dstAlphaMode = = DSTALPHA_DUAL_SOURCE_BLEND ? " \n out float4 ocol1 : COLOR1, " : " " ,
2013-01-24 16:58:28 +01:00
" \n out float depth : DEPTH, " ,
2012-12-28 14:18:39 -06:00
ApiType & API_D3D9_SM20 ? " POSITION " : " VPOS " ) ;
}
else
{
WRITE ( p , " out float4 ocol0 : SV_Target0,%s%s \n in float4 rawpos : SV_Position, \n " ,
dstAlphaMode = = DSTALPHA_DUAL_SOURCE_BLEND ? " \n out float4 ocol1 : SV_Target1, " : " " ,
2013-01-24 16:58:28 +01:00
" \n out float depth : SV_Depth, " ) ;
2012-12-28 14:18:39 -06:00
}
WRITE ( p , " in float4 colors_0 : COLOR0, \n " ) ;
WRITE ( p , " in float4 colors_1 : COLOR1 " ) ;
// compute window position if needed because binding semantic WPOS is not widely supported
if ( numTexgen < 7 )
{
for ( int i = 0 ; i < numTexgen ; + + i )
WRITE ( p , " , \n in float3 uv%d : TEXCOORD%d " , i , i ) ;
WRITE ( p , " , \n in float4 clipPos : TEXCOORD%d " , numTexgen ) ;
if ( g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting )
WRITE ( p , " , \n in float4 Normal : TEXCOORD%d " , numTexgen + 1 ) ;
2013-01-15 10:48:01 -06:00
WRITE ( p , " ) { \n " ) ;
2012-12-28 14:18:39 -06:00
}
else
{
// wpos is in w of first 4 texcoords
if ( g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting )
{
for ( int i = 0 ; i < 8 ; + + i )
WRITE ( p , " , \n in float4 uv%d : TEXCOORD%d " , i , i ) ;
}
else
{
for ( unsigned int i = 0 ; i < xfregs . numTexGen . numTexGens ; + + i )
WRITE ( p , " , \n in float%d uv%d : TEXCOORD%d " , i < 4 ? 4 : 3 , i , i ) ;
}
2013-01-15 10:48:01 -06:00
WRITE ( p , " ) { \n " ) ;
WRITE ( p , " \t float4 clipPos = float4(0.0f, 0.0f, 0.0f, 0.0f); " ) ;
2012-12-28 14:18:39 -06:00
}
}
2012-08-10 18:57:37 +02:00
2012-04-07 14:45:12 -05:00
WRITE ( p , " float4 c0 = " I_COLORS " [1], c1 = " I_COLORS " [2], c2 = " I_COLORS " [3], prev = float4(0.0f, 0.0f, 0.0f, 0.0f), textemp = float4(0.0f, 0.0f, 0.0f, 0.0f), rastemp = float4(0.0f, 0.0f, 0.0f, 0.0f), konsttemp = float4(0.0f, 0.0f, 0.0f, 0.0f); \n "
2010-07-06 13:14:51 +00:00
" float3 comp16 = float3(1.0f, 255.0f, 0.0f), comp24 = float3(1.0f, 255.0f, 255.0f*255.0f); \n "
2011-09-29 21:52:13 +02:00
" float4 alphabump=float4(0.0f,0.0f,0.0f,0.0f); \n "
" float3 tevcoord=float3(0.0f, 0.0f, 0.0f); \n "
" float2 wrappedcoord=float2(0.0f,0.0f), tempcoord=float2(0.0f,0.0f); \n "
" float4 cc0=float4(0.0f,0.0f,0.0f,0.0f), cc1=float4(0.0f,0.0f,0.0f,0.0f); \n "
" float4 cc2=float4(0.0f,0.0f,0.0f,0.0f), cprev=float4(0.0f,0.0f,0.0f,0.0f); \n "
" float4 crastemp=float4(0.0f,0.0f,0.0f,0.0f),ckonsttemp=float4(0.0f,0.0f,0.0f,0.0f); \n \n " ) ;
2011-06-04 19:56:18 +00:00
2011-12-26 00:15:54 -05:00
if ( g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting )
2010-09-23 02:17:48 +00:00
{
2012-08-10 18:57:37 +02:00
if ( xfregs . numTexGen . numTexGens < 7 )
2010-09-23 02:17:48 +00:00
{
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t float3 _norm0 = normalize(Normal.xyz); \n \n " ) ;
WRITE ( p , " \t float3 pos = float3(clipPos.x,clipPos.y,Normal.w); \n " ) ;
2011-06-04 19:56:18 +00:00
}
else
2010-09-23 02:17:48 +00:00
{
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t float3 _norm0 = normalize(float3(uv4.w,uv5.w,uv6.w)); \n \n " ) ;
WRITE ( p , " \t float3 pos = float3(uv0.w,uv1.w,uv7.w); \n " ) ;
2010-09-23 02:17:48 +00:00
}
2011-06-04 19:56:18 +00:00
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t float4 mat, lacc; \n "
" \t float3 ldir, h; \n "
" \t float dist, dist2, attn; \n " ) ;
2011-06-04 19:56:18 +00:00
2011-02-05 23:57:12 +00:00
p = GenerateLightingShader ( p , components , I_PMATERIALS , I_PLIGHTS , " colors_ " , " colors_ " ) ;
2010-09-23 02:17:48 +00:00
}
2009-04-15 03:55:38 +00:00
2010-09-23 02:17:48 +00:00
if ( numTexgen < 7 )
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t clipPos = float4(rawpos.x, rawpos.y, clipPos.z, clipPos.w); \n " ) ;
2010-09-23 02:17:48 +00:00
else
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t clipPos = float4(rawpos.x, rawpos.y, uv2.w, uv3.w); \n " ) ;
2011-06-04 19:56:18 +00:00
2010-01-12 03:39:14 +00:00
// HACK to handle cases where the tex gen is not enabled
2010-07-06 13:14:51 +00:00
if ( numTexgen = = 0 )
2010-01-12 03:39:14 +00:00
{
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t float3 uv0 = float3(0.0f, 0.0f, 0.0f); \n " ) ;
2010-01-12 03:39:14 +00:00
}
else
2009-07-26 09:52:35 +00:00
{
2010-07-06 13:14:51 +00:00
for ( int i = 0 ; i < numTexgen ; + + i )
2010-01-12 03:39:14 +00:00
{
// optional perspective divides
2011-02-05 18:25:34 +00:00
if ( xfregs . texMtxInfo [ i ] . projection = = XF_TEXPROJ_STQ )
2010-12-01 04:26:21 +00:00
{
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t if (uv%d.z != 0.0f) " , i ) ;
WRITE ( p , " \t \t uv%d.xy = uv%d.xy / uv%d.z; \n " , i , i , i ) ;
2010-12-01 04:26:21 +00:00
}
2011-06-04 19:56:18 +00:00
2012-04-07 14:45:12 -05:00
WRITE ( p , " uv%d.xy = uv%d.xy * " I_TEXDIMS " [%d].zw; \n " , i , i , i ) ;
2010-01-12 03:39:14 +00:00
}
}
2008-12-08 05:30:24 +00:00
2010-07-06 13:14:51 +00:00
// indirect texture map lookup
2011-12-26 00:15:54 -05:00
for ( u32 i = 0 ; i < bpmem . genMode . numindstages ; + + i )
2009-07-26 09:52:35 +00:00
{
2010-07-06 13:14:51 +00:00
if ( nIndirectStagesUsed & ( 1 < < i ) )
2009-07-26 09:52:35 +00:00
{
2010-07-06 13:14:51 +00:00
int texcoord = bpmem . tevindref . getTexCoord ( i ) ;
2008-12-08 05:30:24 +00:00
2011-01-09 14:13:24 +00:00
if ( texcoord < numTexgen )
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t tempcoord = uv%d.xy * " I_INDTEXSCALE " [%d].%s; \n " , texcoord , i / 2 , ( i & 1 ) ? " zw " : " xy " ) ;
2010-07-06 13:14:51 +00:00
else
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t tempcoord = float2(0.0f, 0.0f); \n " ) ;
2009-04-11 07:05:57 +00:00
2010-07-06 13:14:51 +00:00
char buffer [ 32 ] ;
sprintf ( buffer , " float3 indtex%d " , i ) ;
2010-08-29 19:34:54 +00:00
SampleTexture ( p , buffer , " tempcoord " , " abg " , bpmem . tevindref . getTexMap ( i ) , ApiType ) ;
2010-07-06 13:14:51 +00:00
}
}
2008-12-08 05:30:24 +00:00
2012-08-11 16:54:46 +02:00
RegisterStates [ 0 ] . AlphaNeedOverflowControl = false ;
RegisterStates [ 0 ] . ColorNeedOverflowControl = false ;
RegisterStates [ 0 ] . AuxStored = false ;
for ( int i = 1 ; i < 4 ; i + + )
{
RegisterStates [ i ] . AlphaNeedOverflowControl = true ;
RegisterStates [ i ] . ColorNeedOverflowControl = true ;
RegisterStates [ i ] . AuxStored = false ;
}
2010-01-12 03:39:14 +00:00
for ( int i = 0 ; i < numStages ; i + + )
2011-01-09 14:13:24 +00:00
WriteStage ( p , i , ApiType ) ; //build the equation for this stage
2010-06-29 14:40:37 +00:00
2011-12-26 00:15:54 -05:00
if ( numStages )
2010-05-22 19:55:07 +00:00
{
// The results of the last texenv stage are put onto the screen,
// regardless of the used destination register
2012-08-11 16:54:46 +02:00
if ( bpmem . combiners [ numStages - 1 ] . colorC . dest ! = 0 )
{
bool retrieveFromAuxRegister = ! RegisterStates [ bpmem . combiners [ numStages - 1 ] . colorC . dest ] . ColorNeedOverflowControl & & RegisterStates [ bpmem . combiners [ numStages - 1 ] . colorC . dest ] . AuxStored ;
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t prev.rgb = %s%s; \n " , retrieveFromAuxRegister ? " c " : " " , tevCOutputTable [ bpmem . combiners [ numStages - 1 ] . colorC . dest ] ) ;
2012-08-11 16:54:46 +02:00
RegisterStates [ 0 ] . ColorNeedOverflowControl = RegisterStates [ bpmem . combiners [ numStages - 1 ] . colorC . dest ] . ColorNeedOverflowControl ;
}
if ( bpmem . combiners [ numStages - 1 ] . alphaC . dest ! = 0 )
{
bool retrieveFromAuxRegister = ! RegisterStates [ bpmem . combiners [ numStages - 1 ] . alphaC . dest ] . AlphaNeedOverflowControl & & RegisterStates [ bpmem . combiners [ numStages - 1 ] . alphaC . dest ] . AuxStored ;
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t prev.a = %s%s; \n " , retrieveFromAuxRegister ? " c " : " " , tevAOutputTable [ bpmem . combiners [ numStages - 1 ] . alphaC . dest ] ) ;
2012-08-11 16:54:46 +02:00
RegisterStates [ 0 ] . AlphaNeedOverflowControl = RegisterStates [ bpmem . combiners [ numStages - 1 ] . alphaC . dest ] . AlphaNeedOverflowControl ;
}
2010-05-22 19:55:07 +00:00
}
2012-08-11 16:54:46 +02:00
// emulation of unsigned 8 overflow when casting if needed
if ( RegisterStates [ 0 ] . AlphaNeedOverflowControl | | RegisterStates [ 0 ] . ColorNeedOverflowControl )
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t prev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f); \n " ) ;
2011-06-04 19:56:18 +00:00
2013-01-08 17:18:45 +01:00
AlphaTest : : TEST_RESULT Pretest = bpmem . alpha_test . TestResult ( ) ;
if ( Pretest = = AlphaTest : : UNDETERMINED )
2012-08-10 18:57:37 +02:00
WriteAlphaTest ( p , ApiType , dstAlphaMode ) ;
2013-01-08 16:40:15 +01:00
// the screen space depth value = far z + (clip z / clip w) * z range
WRITE ( p , " float zCoord = " I_ZBIAS " [1].x + (clipPos.z / clipPos.w) * " I_ZBIAS " [1].y; \n " ) ;
2012-08-10 18:57:37 +02:00
2013-01-08 16:40:15 +01:00
// Note: depth textures are disabled if early depth test is enabled
if ( bpmem . ztex2 . op ! = ZTEXTURE_DISABLE & & ! bpmem . zcontrol . early_ztest & & bpmem . zmode . testenable )
2012-03-25 00:01:47 -03:00
{
// use the texture input of the last texture stage (textemp), hopefully this has been read and is in correct format...
2013-01-08 16:40:15 +01:00
WRITE ( p , " zCoord = dot( " I_ZBIAS " [0].xyzw, textemp.xyzw) + " I_ZBIAS " [1].w %s; \n " ,
( bpmem . ztex2 . op = = ZTEXTURE_ADD ) ? " + zCoord " : " " ) ;
2010-06-12 15:49:21 +00:00
2013-01-08 16:40:15 +01:00
// scale to make result from frac correct
WRITE ( p , " zCoord = zCoord * (16777215.0f/16777216.0f); \n " ) ;
WRITE ( p , " zCoord = frac(zCoord); \n " ) ;
WRITE ( p , " zCoord = zCoord * (16777216.0f/16777215.0f); \n " ) ;
2012-08-10 18:57:37 +02:00
}
2013-01-08 16:40:15 +01:00
WRITE ( p , " depth = zCoord; \n " ) ;
2010-10-20 03:11:22 +00:00
2013-02-15 15:46:31 +01:00
// mark all NaNs. Intel yield NaNs because of UBO driver bug. This here is a hack to blame the driver
WRITE ( p , " \t if(isnan(prev.x) || isinf(prev.x) || isnan(prev.y) || isinf(prev.y) || isnan(prev.z) || isinf(prev.z) || isnan(prev.w) || isinf(prev.w)) \n " ) ; // TODO: on intel/mesa, here will be a division by zero
WRITE ( p , " \t \t prev = float4(0.0f, 0.0f, 0.0f, 0.0f); \n " ) ;
2012-08-10 18:57:37 +02:00
if ( dstAlphaMode = = DSTALPHA_ALPHA_PASS )
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t ocol0 = float4(prev.rgb, " I_ALPHA " [0].a); \n " ) ;
2012-03-25 00:01:47 -03:00
else
{
WriteFog ( p ) ;
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t ocol0 = prev; \n " ) ;
2010-07-06 13:14:51 +00:00
}
2012-03-25 00:01:47 -03:00
// On D3D11, use dual-source color blending to perform dst alpha in a
// single pass
2012-08-10 18:57:37 +02:00
if ( dstAlphaMode = = DSTALPHA_DUAL_SOURCE_BLEND )
2012-03-25 00:01:47 -03:00
{
// Colors will be blended against the alpha from ocol1...
2013-01-02 16:56:08 +01:00
WRITE ( p , " \t ocol1 = prev; \n " ) ;
2012-03-25 00:01:47 -03:00
// ...and the alpha from ocol0 will be written to the framebuffer.
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t ocol0.a = " I_ALPHA " [0].a; \n " ) ;
2012-10-13 12:43:00 -05:00
}
2013-01-02 16:56:08 +01:00
2012-12-27 22:46:29 -06:00
if ( ApiType = = API_OPENGL )
2012-12-28 12:05:43 -06:00
{
2013-01-24 16:58:28 +01:00
WRITE ( p , " \t gl_FragDepth = depth; \n " ) ;
2012-12-28 12:05:43 -06:00
}
2010-07-06 17:21:24 +00:00
WRITE ( p , " } \n " ) ;
2008-12-08 05:30:24 +00:00
if ( text [ sizeof ( text ) - 1 ] ! = 0x7C )
PanicAlert ( " PixelShader generator - buffer too small, canary has been eaten! " ) ;
2009-07-26 09:52:35 +00:00
2009-10-14 01:58:39 +00:00
setlocale ( LC_NUMERIC , " " ) ; // restore locale
2010-07-06 13:14:51 +00:00
return text ;
2008-12-08 05:30:24 +00:00
}
2009-10-29 03:28:38 +00:00
//table with the color compare operations
static const char * TEVCMPColorOPTable [ 16 ] =
{
2010-07-06 13:14:51 +00:00
" float3(0.0f, 0.0f, 0.0f) " , //0
" float3(0.0f, 0.0f, 0.0f) " , //1
" float3(0.0f, 0.0f, 0.0f) " , //2
" float3(0.0f, 0.0f, 0.0f) " , //3
" float3(0.0f, 0.0f, 0.0f) " , //4
" float3(0.0f, 0.0f, 0.0f) " , //5
" float3(0.0f, 0.0f, 0.0f) " , //6
" float3(0.0f, 0.0f, 0.0f) " , //7
" %s + ((%s.r >= %s.r + (0.25f/255.0f)) ? %s : float3(0.0f, 0.0f, 0.0f)) " , //#define TEVCMP_R8_GT 8
" %s + ((abs(%s.r - %s.r) < (0.5f/255.0f)) ? %s : float3(0.0f, 0.0f, 0.0f)) " , //#define TEVCMP_R8_EQ 9
" %s + (( dot(%s.rgb, comp16) >= (dot(%s.rgb, comp16) + (0.25f/255.0f))) ? %s : float3(0.0f, 0.0f, 0.0f)) " , //#define TEVCMP_GR16_GT 10
" %s + (abs(dot(%s.rgb, comp16) - dot(%s.rgb, comp16)) < (0.5f/255.0f) ? %s : float3(0.0f, 0.0f, 0.0f)) " , //#define TEVCMP_GR16_EQ 11
" %s + (( dot(%s.rgb, comp24) >= (dot(%s.rgb, comp24) + (0.25f/255.0f))) ? %s : float3(0.0f, 0.0f, 0.0f)) " , //#define TEVCMP_BGR24_GT 12
" %s + (abs(dot(%s.rgb, comp24) - dot(%s.rgb, comp24)) < (0.5f/255.0f) ? %s : float3(0.0f, 0.0f, 0.0f)) " , //#define TEVCMP_BGR24_EQ 13
" %s + (max(sign(%s.rgb - %s.rgb - (0.25f/255.0f)), float3(0.0f, 0.0f, 0.0f)) * %s) " , //#define TEVCMP_RGB8_GT 14
" %s + ((float3(1.0f, 1.0f, 1.0f) - max(sign(abs(%s.rgb - %s.rgb) - (0.5f/255.0f)), float3(0.0f, 0.0f, 0.0f))) * %s) " //#define TEVCMP_RGB8_EQ 15
2009-10-29 03:28:38 +00:00
} ;
//table with the alpha compare operations
static const char * TEVCMPAlphaOPTable [ 16 ] =
{
" 0.0f " , //0
" 0.0f " , //1
" 0.0f " , //2
" 0.0f " , //3
" 0.0f " , //4
" 0.0f " , //5
" 0.0f " , //6
" 0.0f " , //7
2010-05-27 03:05:43 +00:00
" %s.a + ((%s.r >= (%s.r + (0.25f/255.0f))) ? %s.a : 0.0f) " , //#define TEVCMP_R8_GT 8
" %s.a + (abs(%s.r - %s.r) < (0.5f/255.0f) ? %s.a : 0.0f) " , //#define TEVCMP_R8_EQ 9
" %s.a + ((dot(%s.rgb, comp16) >= (dot(%s.rgb, comp16) + (0.25f/255.0f))) ? %s.a : 0.0f) " , //#define TEVCMP_GR16_GT 10
" %s.a + (abs(dot(%s.rgb, comp16) - dot(%s.rgb, comp16)) < (0.5f/255.0f) ? %s.a : 0.0f) " , //#define TEVCMP_GR16_EQ 11
" %s.a + ((dot(%s.rgb, comp24) >= (dot(%s.rgb, comp24) + (0.25f/255.0f))) ? %s.a : 0.0f) " , //#define TEVCMP_BGR24_GT 12
2011-06-04 19:56:18 +00:00
" %s.a + (abs(dot(%s.rgb, comp24) - dot(%s.rgb, comp24)) < (0.5f/255.0f) ? %s.a : 0.0f) " , //#define TEVCMP_BGR24_EQ 13
2010-05-27 03:05:43 +00:00
" %s.a + ((%s.a >= (%s.a + (0.25f/255.0f))) ? %s.a : 0.0f) " , //#define TEVCMP_A8_GT 14
" %s.a + (abs(%s.a - %s.a) < (0.5f/255.0f) ? %s.a : 0.0f) " //#define TEVCMP_A8_EQ 15
2009-10-29 03:28:38 +00:00
} ;
2011-01-09 14:13:24 +00:00
static void WriteStage ( char * & p , int n , API_TYPE ApiType )
2008-12-08 05:30:24 +00:00
{
2010-07-06 13:14:51 +00:00
int texcoord = bpmem . tevorders [ n / 2 ] . getTexCoord ( n & 1 ) ;
bool bHasTexCoord = ( u32 ) texcoord < bpmem . genMode . numtexgens ;
bool bHasIndStage = bpmem . tevind [ n ] . IsActive ( ) & & bpmem . tevind [ n ] . bt < bpmem . genMode . numindstages ;
2008-12-08 05:30:24 +00:00
2010-07-06 13:14:51 +00:00
// HACK to handle cases where the tex gen is not enabled
if ( ! bHasTexCoord )
texcoord = 0 ;
2009-03-05 05:10:25 +00:00
2011-09-29 21:52:13 +02:00
WRITE ( p , " // TEV stage %d \n " , n ) ;
2010-07-06 13:14:51 +00:00
if ( bHasIndStage )
2009-07-26 09:52:35 +00:00
{
2011-09-29 21:52:13 +02:00
WRITE ( p , " // indirect op \n " ) ;
2010-07-06 13:14:51 +00:00
// perform the indirect op on the incoming regular coordinates using indtex%d as the offset coords
if ( bpmem . tevind [ n ] . bs ! = ITBA_OFF )
2009-07-26 09:52:35 +00:00
{
2011-06-04 19:56:18 +00:00
WRITE ( p , " alphabump = indtex%d.%s %s; \n " ,
bpmem . tevind [ n ] . bt ,
tevIndAlphaSel [ bpmem . tevind [ n ] . bs ] ,
2010-07-06 13:14:51 +00:00
tevIndAlphaScale [ bpmem . tevind [ n ] . fmt ] ) ;
}
// format
WRITE ( p , " float3 indtevcrd%d = indtex%d * %s; \n " , n , bpmem . tevind [ n ] . bt , tevIndFmtScale [ bpmem . tevind [ n ] . fmt ] ) ;
2009-04-15 03:55:38 +00:00
2010-07-06 13:14:51 +00:00
// bias
if ( bpmem . tevind [ n ] . bias ! = ITB_NONE )
WRITE ( p , " indtevcrd%d.%s += %s; \n " , n , tevIndBiasField [ bpmem . tevind [ n ] . bias ] , tevIndBiasAdd [ bpmem . tevind [ n ] . fmt ] ) ;
2008-12-08 05:30:24 +00:00
2010-07-06 13:14:51 +00:00
// multiply by offset matrix and scale
if ( bpmem . tevind [ n ] . mid ! = 0 )
2009-07-26 09:52:35 +00:00
{
2011-01-09 14:13:24 +00:00
if ( bpmem . tevind [ n ] . mid < = 3 )
2009-07-26 09:52:35 +00:00
{
2010-07-06 13:14:51 +00:00
int mtxidx = 2 * ( bpmem . tevind [ n ] . mid - 1 ) ;
2012-04-07 14:45:12 -05:00
WRITE ( p , " float2 indtevtrans%d = float2(dot( " I_INDTEXMTX " [%d].xyz, indtevcrd%d), dot( " I_INDTEXMTX " [%d].xyz, indtevcrd%d)); \n " ,
2010-07-06 13:14:51 +00:00
n , mtxidx , n , mtxidx + 1 , n ) ;
}
2011-01-09 14:13:24 +00:00
else if ( bpmem . tevind [ n ] . mid < = 7 & & bHasTexCoord )
2009-07-26 09:52:35 +00:00
{ // s matrix
2011-09-29 23:32:05 +02:00
_assert_ ( bpmem . tevind [ n ] . mid > = 5 ) ;
2010-07-06 13:14:51 +00:00
int mtxidx = 2 * ( bpmem . tevind [ n ] . mid - 5 ) ;
2012-04-07 14:45:12 -05:00
WRITE ( p , " float2 indtevtrans%d = " I_INDTEXMTX " [%d].ww * uv%d.xy * indtevcrd%d.xx; \n " , n , mtxidx , texcoord , n ) ;
2010-07-06 13:14:51 +00:00
}
2011-01-09 14:13:24 +00:00
else if ( bpmem . tevind [ n ] . mid < = 11 & & bHasTexCoord )
2009-07-26 09:52:35 +00:00
{ // t matrix
2011-09-29 23:32:05 +02:00
_assert_ ( bpmem . tevind [ n ] . mid > = 9 ) ;
2010-07-06 13:14:51 +00:00
int mtxidx = 2 * ( bpmem . tevind [ n ] . mid - 9 ) ;
2012-04-07 14:45:12 -05:00
WRITE ( p , " float2 indtevtrans%d = " I_INDTEXMTX " [%d].ww * uv%d.xy * indtevcrd%d.yy; \n " , n , mtxidx , texcoord , n ) ;
2010-07-06 13:14:51 +00:00
}
else
2011-12-08 05:32:17 -06:00
WRITE ( p , " float2 indtevtrans%d = float2(0.0f); \n " , n ) ;
2010-07-06 13:14:51 +00:00
}
else
2011-12-08 05:32:17 -06:00
WRITE ( p , " float2 indtevtrans%d = float2(0.0f); \n " , n ) ;
2010-07-06 13:14:51 +00:00
// ---------
2009-07-26 09:52:35 +00:00
// Wrapping
// ---------
2009-04-15 03:55:38 +00:00
2010-07-06 13:14:51 +00:00
// wrap S
if ( bpmem . tevind [ n ] . sw = = ITW_OFF )
WRITE ( p , " wrappedcoord.x = uv%d.x; \n " , texcoord ) ;
else if ( bpmem . tevind [ n ] . sw = = ITW_0 )
WRITE ( p , " wrappedcoord.x = 0.0f; \n " ) ;
else
WRITE ( p , " wrappedcoord.x = fmod( uv%d.x, %s ); \n " , texcoord , tevIndWrapStart [ bpmem . tevind [ n ] . sw ] ) ;
// wrap T
if ( bpmem . tevind [ n ] . tw = = ITW_OFF )
WRITE ( p , " wrappedcoord.y = uv%d.y; \n " , texcoord ) ;
else if ( bpmem . tevind [ n ] . tw = = ITW_0 )
WRITE ( p , " wrappedcoord.y = 0.0f; \n " ) ;
else
WRITE ( p , " wrappedcoord.y = fmod( uv%d.y, %s ); \n " , texcoord , tevIndWrapStart [ bpmem . tevind [ n ] . tw ] ) ;
if ( bpmem . tevind [ n ] . fb_addprev ) // add previous tevcoord
WRITE ( p , " tevcoord.xy += wrappedcoord + indtevtrans%d; \n " , n ) ;
else
WRITE ( p , " tevcoord.xy = wrappedcoord + indtevtrans%d; \n " , n ) ;
}
2010-08-16 22:37:04 +00:00
TevStageCombiner : : ColorCombiner & cc = bpmem . combiners [ n ] . colorC ;
TevStageCombiner : : AlphaCombiner & ac = bpmem . combiners [ n ] . alphaC ;
2011-09-29 21:52:13 +02:00
if ( cc . a = = TEVCOLORARG_RASA | | cc . a = = TEVCOLORARG_RASC
| | cc . b = = TEVCOLORARG_RASA | | cc . b = = TEVCOLORARG_RASC
| | cc . c = = TEVCOLORARG_RASA | | cc . c = = TEVCOLORARG_RASC
| | cc . d = = TEVCOLORARG_RASA | | cc . d = = TEVCOLORARG_RASC
| | ac . a = = TEVALPHAARG_RASA | | ac . b = = TEVALPHAARG_RASA
| | ac . c = = TEVALPHAARG_RASA | | ac . d = = TEVALPHAARG_RASA )
2010-08-16 22:37:04 +00:00
{
2011-09-29 21:52:13 +02:00
char * rasswap = swapModeTable [ bpmem . combiners [ n ] . alphaC . rswap ] ;
2010-08-16 22:37:04 +00:00
WRITE ( p , " rastemp = %s.%s; \n " , tevRasTable [ bpmem . tevorders [ n / 2 ] . getColorChan ( n & 1 ) ] , rasswap ) ;
2011-01-29 04:31:56 +00:00
WRITE ( p , " crastemp = frac(rastemp * (255.0f/256.0f)) * (256.0f/255.0f); \n " ) ;
2010-08-16 22:37:04 +00:00
}
2010-07-06 13:14:51 +00:00
if ( bpmem . tevorders [ n / 2 ] . getEnable ( n & 1 ) )
2009-07-26 09:52:35 +00:00
{
2011-12-26 00:15:54 -05:00
if ( ! bHasIndStage )
2009-07-26 09:52:35 +00:00
{
2010-07-06 13:14:51 +00:00
// calc tevcord
2011-12-26 00:15:54 -05:00
if ( bHasTexCoord )
2010-07-06 13:14:51 +00:00
WRITE ( p , " tevcoord.xy = uv%d.xy; \n " , texcoord ) ;
else
WRITE ( p , " tevcoord.xy = float2(0.0f, 0.0f); \n " ) ;
}
2008-12-08 05:30:24 +00:00
2011-09-29 21:52:13 +02:00
char * texswap = swapModeTable [ bpmem . combiners [ n ] . alphaC . tswap ] ;
int texmap = bpmem . tevorders [ n / 2 ] . getTexMap ( n & 1 ) ;
2010-08-29 19:34:54 +00:00
SampleTexture ( p , " textemp " , " tevcoord " , texswap , texmap , ApiType ) ;
2010-07-06 13:14:51 +00:00
}
else
WRITE ( p , " textemp = float4(1.0f, 1.0f, 1.0f, 1.0f); \n " ) ;
2008-12-08 05:30:24 +00:00
2011-06-04 19:56:18 +00:00
2011-09-29 21:52:13 +02:00
if ( cc . a = = TEVCOLORARG_KONST | | cc . b = = TEVCOLORARG_KONST | | cc . c = = TEVCOLORARG_KONST | | cc . d = = TEVCOLORARG_KONST
| | ac . a = = TEVALPHAARG_KONST | | ac . b = = TEVALPHAARG_KONST | | ac . c = = TEVALPHAARG_KONST | | ac . d = = TEVALPHAARG_KONST )
2010-08-16 22:37:04 +00:00
{
2011-09-29 21:52:13 +02:00
int kc = bpmem . tevksel [ n / 2 ] . getKC ( n & 1 ) ;
int ka = bpmem . tevksel [ n / 2 ] . getKA ( n & 1 ) ;
2010-07-06 13:14:51 +00:00
WRITE ( p , " konsttemp = float4(%s, %s); \n " , tevKSelTableC [ kc ] , tevKSelTableA [ ka ] ) ;
2011-12-26 00:15:54 -05:00
if ( kc > 7 | | ka > 7 )
2010-08-16 22:37:04 +00:00
{
2011-01-29 04:31:56 +00:00
WRITE ( p , " ckonsttemp = frac(konsttemp * (255.0f/256.0f)) * (256.0f/255.0f); \n " ) ;
2010-08-16 22:37:04 +00:00
}
else
{
WRITE ( p , " ckonsttemp = konsttemp; \n " ) ;
}
}
2008-12-08 05:30:24 +00:00
2011-09-29 21:52:13 +02:00
if ( cc . a = = TEVCOLORARG_CPREV | | cc . a = = TEVCOLORARG_APREV
| | cc . b = = TEVCOLORARG_CPREV | | cc . b = = TEVCOLORARG_APREV
| | cc . c = = TEVCOLORARG_CPREV | | cc . c = = TEVCOLORARG_APREV
| | ac . a = = TEVALPHAARG_APREV | | ac . b = = TEVALPHAARG_APREV | | ac . c = = TEVALPHAARG_APREV )
2012-08-11 16:54:46 +02:00
{
if ( RegisterStates [ 0 ] . AlphaNeedOverflowControl | | RegisterStates [ 0 ] . ColorNeedOverflowControl )
{
WRITE ( p , " cprev = frac(prev * (255.0f/256.0f)) * (256.0f/255.0f); \n " ) ;
RegisterStates [ 0 ] . AlphaNeedOverflowControl = false ;
RegisterStates [ 0 ] . ColorNeedOverflowControl = false ;
}
else
{
WRITE ( p , " cprev = prev; \n " ) ;
}
RegisterStates [ 0 ] . AuxStored = true ;
}
2010-06-05 00:01:18 +00:00
2011-09-29 21:52:13 +02:00
if ( cc . a = = TEVCOLORARG_C0 | | cc . a = = TEVCOLORARG_A0
| | cc . b = = TEVCOLORARG_C0 | | cc . b = = TEVCOLORARG_A0
| | cc . c = = TEVCOLORARG_C0 | | cc . c = = TEVCOLORARG_A0
| | ac . a = = TEVALPHAARG_A0 | | ac . b = = TEVALPHAARG_A0 | | ac . c = = TEVALPHAARG_A0 )
2012-08-11 16:54:46 +02:00
{
if ( RegisterStates [ 1 ] . AlphaNeedOverflowControl | | RegisterStates [ 1 ] . ColorNeedOverflowControl )
{
WRITE ( p , " cc0 = frac(c0 * (255.0f/256.0f)) * (256.0f/255.0f); \n " ) ;
RegisterStates [ 1 ] . AlphaNeedOverflowControl = false ;
RegisterStates [ 1 ] . ColorNeedOverflowControl = false ;
}
else
{
WRITE ( p , " cc0 = c0; \n " ) ;
}
RegisterStates [ 1 ] . AuxStored = true ;
}
2011-09-29 21:52:13 +02:00
if ( cc . a = = TEVCOLORARG_C1 | | cc . a = = TEVCOLORARG_A1
| | cc . b = = TEVCOLORARG_C1 | | cc . b = = TEVCOLORARG_A1
| | cc . c = = TEVCOLORARG_C1 | | cc . c = = TEVCOLORARG_A1
| | ac . a = = TEVALPHAARG_A1 | | ac . b = = TEVALPHAARG_A1 | | ac . c = = TEVALPHAARG_A1 )
2012-08-11 16:54:46 +02:00
{
if ( RegisterStates [ 2 ] . AlphaNeedOverflowControl | | RegisterStates [ 2 ] . ColorNeedOverflowControl )
{
WRITE ( p , " cc1 = frac(c1 * (255.0f/256.0f)) * (256.0f/255.0f); \n " ) ;
RegisterStates [ 2 ] . AlphaNeedOverflowControl = false ;
RegisterStates [ 2 ] . ColorNeedOverflowControl = false ;
}
else
{
WRITE ( p , " cc1 = c1; \n " ) ;
}
RegisterStates [ 2 ] . AuxStored = true ;
}
2011-09-29 21:52:13 +02:00
if ( cc . a = = TEVCOLORARG_C2 | | cc . a = = TEVCOLORARG_A2
| | cc . b = = TEVCOLORARG_C2 | | cc . b = = TEVCOLORARG_A2
| | cc . c = = TEVCOLORARG_C2 | | cc . c = = TEVCOLORARG_A2
| | ac . a = = TEVALPHAARG_A2 | | ac . b = = TEVALPHAARG_A2 | | ac . c = = TEVALPHAARG_A2 )
2012-08-11 16:54:46 +02:00
{
if ( RegisterStates [ 3 ] . AlphaNeedOverflowControl | | RegisterStates [ 3 ] . ColorNeedOverflowControl )
{
2011-01-29 04:31:56 +00:00
WRITE ( p , " cc2 = frac(c2 * (255.0f/256.0f)) * (256.0f/255.0f); \n " ) ;
2012-08-11 16:54:46 +02:00
RegisterStates [ 3 ] . AlphaNeedOverflowControl = false ;
RegisterStates [ 3 ] . ColorNeedOverflowControl = false ;
}
else
{
WRITE ( p , " cc2 = c2; \n " ) ;
}
RegisterStates [ 3 ] . AuxStored = true ;
}
2010-05-27 21:43:07 +00:00
2012-08-11 16:54:46 +02:00
RegisterStates [ cc . dest ] . ColorNeedOverflowControl = ( cc . clamp = = 0 ) ;
RegisterStates [ cc . dest ] . AuxStored = false ;
2011-09-29 21:52:13 +02:00
2012-08-11 16:54:46 +02:00
// combine the color channel
2011-09-29 21:52:13 +02:00
WRITE ( p , " // color combine \n " ) ;
2010-07-06 13:14:51 +00:00
if ( cc . clamp )
WRITE ( p , " %s = saturate( " , tevCOutputTable [ cc . dest ] ) ;
2009-08-31 04:23:30 +00:00
else
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s = " , tevCOutputTable [ cc . dest ] ) ;
2008-12-08 05:30:24 +00:00
2010-07-06 13:14:51 +00:00
// combine the color channel
2010-06-05 00:01:18 +00:00
if ( cc . bias ! = TevBias_COMPARE ) // if not compare
2009-07-26 09:52:35 +00:00
{
2010-07-06 13:14:51 +00:00
//normal color combiner goes here
2010-06-05 00:01:18 +00:00
if ( cc . shift > TEVSCALE_1 )
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s*( " , tevScaleTable [ cc . shift ] ) ;
2010-01-12 03:39:14 +00:00
2011-12-26 00:15:54 -05:00
if ( ! ( cc . d = = TEVCOLORARG_ZERO & & cc . op = = TEVOP_ADD ) )
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s%s " , tevCInputTable [ cc . d ] , tevOpTable [ cc . op ] ) ;
2009-08-31 04:23:30 +00:00
2010-05-23 22:46:13 +00:00
if ( cc . a = = cc . b )
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s " , tevCInputTable [ cc . a + 16 ] ) ;
2010-05-23 22:46:13 +00:00
else if ( cc . c = = TEVCOLORARG_ZERO )
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s " , tevCInputTable [ cc . a + 16 ] ) ;
2010-05-23 22:46:13 +00:00
else if ( cc . c = = TEVCOLORARG_ONE )
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s " , tevCInputTable [ cc . b + 16 ] ) ;
2010-05-22 20:40:43 +00:00
else if ( cc . a = = TEVCOLORARG_ZERO )
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s*%s " , tevCInputTable [ cc . b + 16 ] , tevCInputTable [ cc . c + 16 ] ) ;
2010-05-22 20:40:43 +00:00
else if ( cc . b = = TEVCOLORARG_ZERO )
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s*(float3(1.0f, 1.0f, 1.0f)-%s) " , tevCInputTable [ cc . a + 16 ] , tevCInputTable [ cc . c + 16 ] ) ;
2009-08-31 04:23:30 +00:00
else
2010-07-06 13:14:51 +00:00
WRITE ( p , " lerp(%s, %s, %s) " , tevCInputTable [ cc . a + 16 ] , tevCInputTable [ cc . b + 16 ] , tevCInputTable [ cc . c + 16 ] ) ;
2011-06-04 19:56:18 +00:00
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s " , tevBiasTable [ cc . bias ] ) ;
2011-06-04 19:56:18 +00:00
2011-09-29 21:52:13 +02:00
if ( cc . shift > TEVSCALE_1 )
2010-01-12 03:39:14 +00:00
WRITE ( p , " ) " ) ;
2010-07-06 13:14:51 +00:00
}
else
2009-07-26 09:52:35 +00:00
{
2010-07-06 13:14:51 +00:00
int cmp = ( cc . shift < < 1 ) | cc . op | 8 ; // comparemode stored here
2009-10-30 04:14:43 +00:00
WRITE ( p , TEVCMPColorOPTable [ cmp ] , //lookup the function from the op table
2011-06-04 19:56:18 +00:00
tevCInputTable [ cc . d ] ,
2010-05-27 21:43:07 +00:00
tevCInputTable [ cc . a + 16 ] ,
tevCInputTable [ cc . b + 16 ] ,
2010-07-06 13:14:51 +00:00
tevCInputTable [ cc . c + 16 ] ) ;
}
2010-01-12 03:39:14 +00:00
if ( cc . clamp )
2010-07-06 13:14:51 +00:00
WRITE ( p , " ) " ) ;
WRITE ( p , " ; \n " ) ;
2011-06-04 19:56:18 +00:00
2012-08-11 16:54:46 +02:00
RegisterStates [ ac . dest ] . AlphaNeedOverflowControl = ( ac . clamp = = 0 ) ;
RegisterStates [ ac . dest ] . AuxStored = false ;
2010-07-06 13:14:51 +00:00
// combine the alpha channel
2012-08-11 16:54:46 +02:00
WRITE ( p , " // alpha combine \n " ) ;
2010-07-06 13:14:51 +00:00
if ( ac . clamp )
WRITE ( p , " %s = saturate( " , tevAOutputTable [ ac . dest ] ) ;
2009-08-31 04:23:30 +00:00
else
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s = " , tevAOutputTable [ ac . dest ] ) ;
2008-12-08 05:30:24 +00:00
2010-07-06 13:14:51 +00:00
if ( ac . bias ! = TevBias_COMPARE ) // if not compare
2009-07-26 09:52:35 +00:00
{
2010-07-06 13:14:51 +00:00
//normal alpha combiner goes here
2010-06-05 00:01:18 +00:00
if ( ac . shift > TEVSCALE_1 )
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s*( " , tevScaleTable [ ac . shift ] ) ;
2010-01-12 03:39:14 +00:00
2011-12-26 00:15:54 -05:00
if ( ! ( ac . d = = TEVALPHAARG_ZERO & & ac . op = = TEVOP_ADD ) )
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s.a%s " , tevAInputTable [ ac . d ] , tevOpTable [ ac . op ] ) ;
2009-08-31 04:23:30 +00:00
2010-05-23 22:46:13 +00:00
if ( ac . a = = ac . b )
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s.a " , tevAInputTable [ ac . a + 8 ] ) ;
2010-05-23 22:46:13 +00:00
else if ( ac . c = = TEVALPHAARG_ZERO )
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s.a " , tevAInputTable [ ac . a + 8 ] ) ;
2010-05-22 20:40:43 +00:00
else if ( ac . a = = TEVALPHAARG_ZERO )
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s.a*%s.a " , tevAInputTable [ ac . b + 8 ] , tevAInputTable [ ac . c + 8 ] ) ;
2010-05-22 20:40:43 +00:00
else if ( ac . b = = TEVALPHAARG_ZERO )
2010-07-06 13:14:51 +00:00
WRITE ( p , " %s.a*(1.0f-%s.a) " , tevAInputTable [ ac . a + 8 ] , tevAInputTable [ ac . c + 8 ] ) ;
2009-08-31 04:23:30 +00:00
else
2010-07-06 13:14:51 +00:00
WRITE ( p , " lerp(%s.a, %s.a, %s.a) " , tevAInputTable [ ac . a + 8 ] , tevAInputTable [ ac . b + 8 ] , tevAInputTable [ ac . c + 8 ] ) ;
2011-06-04 19:56:18 +00:00
2010-01-12 03:39:14 +00:00
WRITE ( p , " %s " , tevBiasTable [ ac . bias ] ) ;
2011-06-04 19:56:18 +00:00
2011-12-26 00:15:54 -05:00
if ( ac . shift > 0 )
2010-01-12 03:39:14 +00:00
WRITE ( p , " ) " ) ;
2010-05-17 22:17:46 +00:00
2010-07-06 13:14:51 +00:00
}
else
2009-07-26 09:52:35 +00:00
{
2010-07-06 13:14:51 +00:00
//compare alpha combiner goes here
int cmp = ( ac . shift < < 1 ) | ac . op | 8 ; // comparemode stored here
2011-06-04 19:56:18 +00:00
WRITE ( p , TEVCMPAlphaOPTable [ cmp ] ,
tevAInputTable [ ac . d ] ,
tevAInputTable [ ac . a + 8 ] ,
tevAInputTable [ ac . b + 8 ] ,
2010-07-06 13:14:51 +00:00
tevAInputTable [ ac . c + 8 ] ) ;
}
2010-01-12 03:39:14 +00:00
if ( ac . clamp )
WRITE ( p , " ) " ) ;
2010-07-06 13:14:51 +00:00
WRITE ( p , " ; \n \n " ) ;
2011-09-29 21:52:13 +02:00
WRITE ( p , " // TEV done \n " ) ;
2008-12-08 05:30:24 +00:00
}
2010-08-29 19:34:54 +00:00
void SampleTexture ( char * & p , const char * destination , const char * texcoords , const char * texswap , int texmap , API_TYPE ApiType )
2008-12-08 05:30:24 +00:00
{
2010-08-29 19:34:54 +00:00
if ( ApiType = = API_D3D11 )
2012-04-07 14:45:12 -05:00
WRITE ( p , " %s=Tex%d.Sample(samp%d,%s.xy * " I_TEXDIMS " [%d].xy).%s; \n " , destination , texmap , texmap , texcoords , texmap , texswap ) ;
2010-07-06 13:14:51 +00:00
else
2013-01-19 11:07:06 +01:00
WRITE ( p , " %s=%s(samp%d,%s.xy * " I_TEXDIMS " [%d].xy).%s; \n " , destination , ApiType = = API_OPENGL ? " texture " : " tex2D " , texmap , texcoords , texmap , texswap ) ;
2008-12-08 05:30:24 +00:00
}
2010-07-06 13:14:51 +00:00
static const char * tevAlphaFuncsTable [ ] =
2008-12-08 05:30:24 +00:00
{
2010-07-06 13:14:51 +00:00
" (false) " , //ALPHACMP_NEVER 0
2010-01-19 15:00:45 +00:00
" (prev.a <= %s - (0.25f/255.0f)) " , //ALPHACMP_LESS 1
" (abs( prev.a - %s ) < (0.5f/255.0f)) " , //ALPHACMP_EQUAL 2
" (prev.a < %s + (0.25f/255.0f)) " , //ALPHACMP_LEQUAL 3
" (prev.a >= %s + (0.25f/255.0f)) " , //ALPHACMP_GREATER 4
" (abs( prev.a - %s ) >= (0.5f/255.0f)) " , //ALPHACMP_NEQUAL 5
" (prev.a > %s - (0.25f/255.0f)) " , //ALPHACMP_GEQUAL 6
2009-10-29 03:28:38 +00:00
" (true) " //ALPHACMP_ALWAYS 7
2009-10-25 02:35:21 +00:00
} ;
static const char * tevAlphaFunclogicTable [ ] =
{
" && " , // and
2010-07-06 13:14:51 +00:00
" || " , // or
" != " , // xor
" == " // xnor
2009-10-25 02:35:21 +00:00
} ;
2012-08-10 18:57:37 +02:00
static void WriteAlphaTest ( char * & p , API_TYPE ApiType , DSTALPHA_MODE dstAlphaMode )
2010-10-10 14:35:31 +00:00
{
2011-09-29 21:52:13 +02:00
static const char * alphaRef [ 2 ] =
{
I_ALPHA " [0].r " ,
I_ALPHA " [0].g "
2012-03-25 00:01:47 -03:00
} ;
2010-10-10 14:35:31 +00:00
2011-12-26 00:15:54 -05:00
2010-06-14 03:09:44 +00:00
// using discard then return works the same in cg and dx9 but not in dx11
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t if(!( " ) ;
2009-07-26 09:52:35 +00:00
2013-01-08 17:18:45 +01:00
int compindex = bpmem . alpha_test . comp0 ;
2012-08-10 18:57:37 +02:00
WRITE ( p , tevAlphaFuncsTable [ compindex ] , alphaRef [ 0 ] ) ; //lookup the first component from the alpha function table
2011-06-04 19:56:18 +00:00
2013-01-08 17:18:45 +01:00
WRITE ( p , " %s " , tevAlphaFunclogicTable [ bpmem . alpha_test . logic ] ) ; //lookup the logic op
2011-06-04 19:56:18 +00:00
2013-01-08 17:18:45 +01:00
compindex = bpmem . alpha_test . comp1 ;
2012-08-10 18:57:37 +02:00
WRITE ( p , tevAlphaFuncsTable [ compindex ] , alphaRef [ 1 ] ) ; //lookup the second component from the alpha function table
2011-09-04 04:44:50 +02:00
WRITE ( p , " )) { \n " ) ;
2013-01-14 19:17:07 +01:00
WRITE ( p , " \t \t ocol0 = float4(0.0f, 0.0f, 0.0f, 0.0f); \n " ) ;
2012-08-10 18:57:37 +02:00
if ( dstAlphaMode = = DSTALPHA_DUAL_SOURCE_BLEND )
2013-01-14 19:17:07 +01:00
WRITE ( p , " \t \t ocol1 = float4(0.0f, 0.0f, 0.0f, 0.0f); \n " ) ;
2013-01-08 16:40:15 +01:00
WRITE ( p , " depth = 1.f; \n " ) ;
2012-08-10 18:57:37 +02:00
2013-01-08 16:51:01 +01:00
// HAXX: zcomploc (aka early_ztest) is a way to control whether depth test is done before
// or after texturing and alpha test. PC GPUs have no way to support this
// feature properly as of 2012: depth buffer and depth test are not
// programmable and the depth test is always done after texturing.
// Most importantly, PC GPUs do not allow writing to the z buffer without
// writing a color value (unless color writing is disabled altogether).
2012-08-10 18:57:37 +02:00
// We implement "depth test before texturing" by discarding the fragment
// when the alpha test fail. This is not a correct implementation because
2013-01-08 16:51:01 +01:00
// even if the depth test fails the fragment could be alpha blended, but
// we don't have a choice.
2013-01-08 16:01:15 +01:00
if ( ! ( bpmem . zcontrol . early_ztest & & bpmem . zmode . updateenable ) )
2012-08-10 18:57:37 +02:00
{
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t \t discard; \n " ) ;
2012-08-10 18:57:37 +02:00
if ( ApiType ! = API_D3D11 )
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t \t return; \n " ) ;
2012-08-10 18:57:37 +02:00
}
2011-09-04 04:44:50 +02:00
WRITE ( p , " } \n " ) ;
2008-12-08 05:30:24 +00:00
}
2009-02-19 04:41:58 +00:00
2009-10-25 02:35:21 +00:00
static const char * tevFogFuncsTable [ ] =
{
" " , //No Fog
" " , //?
" " , //Linear
" " , //?
2012-12-28 14:18:39 -06:00
" \t fog = 1.0f - pow(2.0f, -8.0f * fog); \n " , //exp
" \t fog = 1.0f - pow(2.0f, -8.0f * fog * fog); \n " , //exp2
" \t fog = pow(2.0f, -8.0f * (1.0f - fog)); \n " , //backward exp
" \t fog = 1.0f - fog; \n fog = pow(2.0f, -8.0f * fog * fog); \n " //backward exp2
2009-10-25 02:35:21 +00:00
} ;
2009-05-15 02:39:55 +00:00
static void WriteFog ( char * & p )
2009-02-19 04:41:58 +00:00
{
2011-12-26 00:15:54 -05:00
if ( bpmem . fog . c_proj_fsel . fsel = = 0 )
return ; // no Fog
2009-02-19 04:41:58 +00:00
2011-06-04 19:56:18 +00:00
if ( bpmem . fog . c_proj_fsel . proj = = 0 )
2009-07-26 09:52:35 +00:00
{
2010-07-06 13:14:51 +00:00
// perspective
2010-11-23 13:57:01 +00:00
// ze = A/(B - (Zs >> B_SHF)
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t float ze = " I_FOG " [1].x / ( " I_FOG " [1].y - (zCoord / " I_FOG " [1].w)); \n " ) ;
2010-07-06 13:14:51 +00:00
}
else
2009-10-25 02:35:21 +00:00
{
2010-07-06 13:14:51 +00:00
// orthographic
2010-11-23 13:57:01 +00:00
// ze = a*Zs (here, no B_SHF)
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t float ze = " I_FOG " [1].x * zCoord; \n " ) ;
2010-07-06 13:14:51 +00:00
}
2011-06-04 19:56:18 +00:00
2010-11-23 13:57:01 +00:00
// x_adjust = sqrt((x-center)^2 + k^2)/k
// ze *= x_adjust
2011-01-29 04:31:56 +00:00
//this is complitly teorical as the real hard seems to use a table intead of calculate the values.
2011-12-26 00:15:54 -05:00
if ( bpmem . fogRange . Base . Enabled )
2011-01-29 04:31:56 +00:00
{
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t float x_adjust = (2.0f * (clipPos.x / " I_FOG " [2].y)) - 1.0f - " I_FOG " [2].x; \n " ) ;
WRITE ( p , " \t x_adjust = sqrt(x_adjust * x_adjust + " I_FOG " [2].z * " I_FOG " [2].z) / " I_FOG " [2].z; \n " ) ;
WRITE ( p , " \t ze *= x_adjust; \n " ) ;
2011-01-29 04:31:56 +00:00
}
2009-02-19 04:41:58 +00:00
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t float fog = saturate(ze - " I_FOG " [1].z); \n " ) ;
2009-02-19 04:41:58 +00:00
2011-12-26 00:15:54 -05:00
if ( bpmem . fog . c_proj_fsel . fsel > 3 )
2009-10-25 02:35:21 +00:00
{
2010-02-24 03:38:36 +00:00
WRITE ( p , " %s " , tevFogFuncsTable [ bpmem . fog . c_proj_fsel . fsel ] ) ;
2009-10-25 02:35:21 +00:00
}
else
{
2011-12-26 00:15:54 -05:00
if ( bpmem . fog . c_proj_fsel . fsel ! = 2 )
2009-10-25 02:35:21 +00:00
WARN_LOG ( VIDEO , " Unknown Fog Type! %08x " , bpmem . fog . c_proj_fsel . fsel ) ;
2010-07-06 13:14:51 +00:00
}
2009-02-19 04:41:58 +00:00
2012-12-28 14:18:39 -06:00
WRITE ( p , " \t prev.rgb = lerp(prev.rgb, " I_FOG " [0].rgb, fog); \n " ) ;
2009-02-19 04:41:58 +00:00
}