2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2012-12-14 13:21:50 +00:00
Copyright ( C ) 2012 Robert Beckebans
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code 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 , either version 3 of the License , or
( at your option ) any later version .
Doom 3 BFG Edition Source Code 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 for more details .
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# pragma hdrstop
2012-12-22 15:18:19 +00:00
# include "precompiled.h"
2012-11-26 18:58:24 +00:00
# include "tr_local.h"
idCVar r_skipStripDeadCode ( " r_skipStripDeadCode " , " 0 " , CVAR_BOOL , " Skip stripping dead code " ) ;
idCVar r_useUniformArrays ( " r_useUniformArrays " , " 1 " , CVAR_BOOL , " " ) ;
2013-03-16 01:07:59 +00:00
// DG: the AMD drivers output a lot of useless warnings which are fscking annoying, added this CVar to suppress them
idCVar r_displayGLSLCompilerMessages ( " r_displayGLSLCompilerMessages " , " 1 " , CVAR_BOOL | CVAR_ARCHIVE , " Show info messages the GPU driver outputs when compiling the shaders " ) ;
// DG end
2012-11-26 18:58:24 +00:00
# define VERTEX_UNIFORM_ARRAY_NAME "_va_"
# define FRAGMENT_UNIFORM_ARRAY_NAME "_fa_"
static const int AT_VS_IN = BIT ( 1 ) ;
static const int AT_VS_OUT = BIT ( 2 ) ;
static const int AT_PS_IN = BIT ( 3 ) ;
static const int AT_PS_OUT = BIT ( 4 ) ;
2012-11-28 15:47:07 +00:00
struct idCGBlock
{
2012-11-26 18:58:24 +00:00
idStr prefix ; // tokens that comes before the name
idStr name ; // the name
idStr postfix ; // tokens that comes after the name
bool used ; // whether or not this block is referenced anywhere
} ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
attribInfo_t
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
struct attribInfo_t
{
const char * type ;
const char * name ;
const char * semantic ;
const char * glsl ;
2012-11-26 18:58:24 +00:00
int bind ;
int flags ;
int vertexMask ;
} ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
vertexMask_t
NOTE : There is a PS3 dependency between the bit flag specified here and the vertex
attribute index and attribute semantic specified in DeclRenderProg . cpp because the
stored render prog vertexMask is initialized with cellCgbGetVertexConfiguration ( ) .
The ATTRIB_INDEX_ defines are used to make sure the vertexMask_t and attrib assignment
in DeclRenderProg . cpp are in sync .
Even though VERTEX_MASK_XYZ_SHORT and VERTEX_MASK_ST_SHORT are not real attributes ,
they come before the VERTEX_MASK_MORPH to reduce the range of vertex program
permutations defined by the vertexMask_t bits on the Xbox 360 ( see MAX_VERTEX_DECLARATIONS ) .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
enum vertexMask_t
{
2012-11-26 18:58:24 +00:00
VERTEX_MASK_XYZ = BIT ( PC_ATTRIB_INDEX_VERTEX ) ,
VERTEX_MASK_ST = BIT ( PC_ATTRIB_INDEX_ST ) ,
VERTEX_MASK_NORMAL = BIT ( PC_ATTRIB_INDEX_NORMAL ) ,
VERTEX_MASK_COLOR = BIT ( PC_ATTRIB_INDEX_COLOR ) ,
VERTEX_MASK_TANGENT = BIT ( PC_ATTRIB_INDEX_TANGENT ) ,
VERTEX_MASK_COLOR2 = BIT ( PC_ATTRIB_INDEX_COLOR2 ) ,
} ;
2012-11-28 15:47:07 +00:00
attribInfo_t attribsPC [ ] =
{
2012-11-26 18:58:24 +00:00
// vertex attributes
{ " float4 " , " position " , " POSITION " , " in_Position " , PC_ATTRIB_INDEX_VERTEX , AT_VS_IN , VERTEX_MASK_XYZ } ,
{ " float2 " , " texcoord " , " TEXCOORD0 " , " in_TexCoord " , PC_ATTRIB_INDEX_ST , AT_VS_IN , VERTEX_MASK_ST } ,
{ " float4 " , " normal " , " NORMAL " , " in_Normal " , PC_ATTRIB_INDEX_NORMAL , AT_VS_IN , VERTEX_MASK_NORMAL } ,
{ " float4 " , " tangent " , " TANGENT " , " in_Tangent " , PC_ATTRIB_INDEX_TANGENT , AT_VS_IN , VERTEX_MASK_TANGENT } ,
{ " float4 " , " color " , " COLOR0 " , " in_Color " , PC_ATTRIB_INDEX_COLOR , AT_VS_IN , VERTEX_MASK_COLOR } ,
{ " float4 " , " color2 " , " COLOR1 " , " in_Color2 " , PC_ATTRIB_INDEX_COLOR2 , AT_VS_IN , VERTEX_MASK_COLOR2 } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// pre-defined vertex program output
{ " float4 " , " position " , " POSITION " , " gl_Position " , 0 , AT_VS_OUT , 0 } ,
{ " float " , " clip0 " , " CLP0 " , " gl_ClipDistance[0] " , 0 , AT_VS_OUT , 0 } ,
{ " float " , " clip1 " , " CLP1 " , " gl_ClipDistance[1] " , 0 , AT_VS_OUT , 0 } ,
{ " float " , " clip2 " , " CLP2 " , " gl_ClipDistance[2] " , 0 , AT_VS_OUT , 0 } ,
{ " float " , " clip3 " , " CLP3 " , " gl_ClipDistance[3] " , 0 , AT_VS_OUT , 0 } ,
{ " float " , " clip4 " , " CLP4 " , " gl_ClipDistance[4] " , 0 , AT_VS_OUT , 0 } ,
{ " float " , " clip5 " , " CLP5 " , " gl_ClipDistance[5] " , 0 , AT_VS_OUT , 0 } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// pre-defined fragment program input
{ " float4 " , " position " , " WPOS " , " gl_FragCoord " , 0 , AT_PS_IN , 0 } ,
{ " half4 " , " hposition " , " WPOS " , " gl_FragCoord " , 0 , AT_PS_IN , 0 } ,
{ " float " , " facing " , " FACE " , " gl_FrontFacing " , 0 , AT_PS_IN , 0 } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// fragment program output
{ " float4 " , " color " , " COLOR " , " gl_FragColor " , 0 , AT_PS_OUT , 0 } , // GLSL version 1.2 doesn't allow for custom color name mappings
{ " half4 " , " hcolor " , " COLOR " , " gl_FragColor " , 0 , AT_PS_OUT , 0 } ,
{ " float4 " , " color0 " , " COLOR0 " , " gl_FragColor " , 0 , AT_PS_OUT , 0 } ,
{ " float4 " , " color1 " , " COLOR1 " , " gl_FragColor " , 1 , AT_PS_OUT , 0 } ,
{ " float4 " , " color2 " , " COLOR2 " , " gl_FragColor " , 2 , AT_PS_OUT , 0 } ,
{ " float4 " , " color3 " , " COLOR3 " , " gl_FragColor " , 3 , AT_PS_OUT , 0 } ,
{ " float " , " depth " , " DEPTH " , " gl_FragDepth " , 4 , AT_PS_OUT , 0 } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// vertex to fragment program pass through
{ " float4 " , " color " , " COLOR " , " gl_FrontColor " , 0 , AT_VS_OUT , 0 } ,
{ " float4 " , " color0 " , " COLOR0 " , " gl_FrontColor " , 0 , AT_VS_OUT , 0 } ,
{ " float4 " , " color1 " , " COLOR1 " , " gl_FrontSecondaryColor " , 0 , AT_VS_OUT , 0 } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " float4 " , " color " , " COLOR " , " gl_Color " , 0 , AT_PS_IN , 0 } ,
{ " float4 " , " color0 " , " COLOR0 " , " gl_Color " , 0 , AT_PS_IN , 0 } ,
{ " float4 " , " color1 " , " COLOR1 " , " gl_SecondaryColor " , 0 , AT_PS_IN , 0 } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " half4 " , " hcolor " , " COLOR " , " gl_Color " , 0 , AT_PS_IN , 0 } ,
{ " half4 " , " hcolor0 " , " COLOR0 " , " gl_Color " , 0 , AT_PS_IN , 0 } ,
{ " half4 " , " hcolor1 " , " COLOR1 " , " gl_SecondaryColor " , 0 , AT_PS_IN , 0 } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " float4 " , " texcoord0 " , " TEXCOORD0_centroid " , " vofi_TexCoord0 " , 0 , AT_PS_IN , 0 } ,
{ " float4 " , " texcoord1 " , " TEXCOORD1_centroid " , " vofi_TexCoord1 " , 0 , AT_PS_IN , 0 } ,
{ " float4 " , " texcoord2 " , " TEXCOORD2_centroid " , " vofi_TexCoord2 " , 0 , AT_PS_IN , 0 } ,
{ " float4 " , " texcoord3 " , " TEXCOORD3_centroid " , " vofi_TexCoord3 " , 0 , AT_PS_IN , 0 } ,
{ " float4 " , " texcoord4 " , " TEXCOORD4_centroid " , " vofi_TexCoord4 " , 0 , AT_PS_IN , 0 } ,
{ " float4 " , " texcoord5 " , " TEXCOORD5_centroid " , " vofi_TexCoord5 " , 0 , AT_PS_IN , 0 } ,
{ " float4 " , " texcoord6 " , " TEXCOORD6_centroid " , " vofi_TexCoord6 " , 0 , AT_PS_IN , 0 } ,
{ " float4 " , " texcoord7 " , " TEXCOORD7_centroid " , " vofi_TexCoord7 " , 0 , AT_PS_IN , 0 } ,
{ " float4 " , " texcoord8 " , " TEXCOORD8_centroid " , " vofi_TexCoord8 " , 0 , AT_PS_IN , 0 } ,
{ " float4 " , " texcoord9 " , " TEXCOORD9_centroid " , " vofi_TexCoord9 " , 0 , AT_PS_IN , 0 } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " float4 " , " texcoord0 " , " TEXCOORD0 " , " vofi_TexCoord0 " , 0 , AT_VS_OUT | AT_PS_IN , 0 } ,
{ " float4 " , " texcoord1 " , " TEXCOORD1 " , " vofi_TexCoord1 " , 0 , AT_VS_OUT | AT_PS_IN , 0 } ,
{ " float4 " , " texcoord2 " , " TEXCOORD2 " , " vofi_TexCoord2 " , 0 , AT_VS_OUT | AT_PS_IN , 0 } ,
{ " float4 " , " texcoord3 " , " TEXCOORD3 " , " vofi_TexCoord3 " , 0 , AT_VS_OUT | AT_PS_IN , 0 } ,
{ " float4 " , " texcoord4 " , " TEXCOORD4 " , " vofi_TexCoord4 " , 0 , AT_VS_OUT | AT_PS_IN , 0 } ,
{ " float4 " , " texcoord5 " , " TEXCOORD5 " , " vofi_TexCoord5 " , 0 , AT_VS_OUT | AT_PS_IN , 0 } ,
{ " float4 " , " texcoord6 " , " TEXCOORD6 " , " vofi_TexCoord6 " , 0 , AT_VS_OUT | AT_PS_IN , 0 } ,
{ " float4 " , " texcoord7 " , " TEXCOORD7 " , " vofi_TexCoord7 " , 0 , AT_VS_OUT | AT_PS_IN , 0 } ,
{ " float4 " , " texcoord8 " , " TEXCOORD8 " , " vofi_TexCoord8 " , 0 , AT_VS_OUT | AT_PS_IN , 0 } ,
{ " float4 " , " texcoord9 " , " TEXCOORD9 " , " vofi_TexCoord9 " , 0 , AT_VS_OUT | AT_PS_IN , 0 } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " half4 " , " htexcoord0 " , " TEXCOORD0 " , " vofi_TexCoord0 " , 0 , AT_PS_IN , 0 } ,
{ " half4 " , " htexcoord1 " , " TEXCOORD1 " , " vofi_TexCoord1 " , 0 , AT_PS_IN , 0 } ,
{ " half4 " , " htexcoord2 " , " TEXCOORD2 " , " vofi_TexCoord2 " , 0 , AT_PS_IN , 0 } ,
{ " half4 " , " htexcoord3 " , " TEXCOORD3 " , " vofi_TexCoord3 " , 0 , AT_PS_IN , 0 } ,
{ " half4 " , " htexcoord4 " , " TEXCOORD4 " , " vofi_TexCoord4 " , 0 , AT_PS_IN , 0 } ,
{ " half4 " , " htexcoord5 " , " TEXCOORD5 " , " vofi_TexCoord5 " , 0 , AT_PS_IN , 0 } ,
{ " half4 " , " htexcoord6 " , " TEXCOORD6 " , " vofi_TexCoord6 " , 0 , AT_PS_IN , 0 } ,
{ " half4 " , " htexcoord7 " , " TEXCOORD7 " , " vofi_TexCoord7 " , 0 , AT_PS_IN , 0 } ,
{ " half4 " , " htexcoord8 " , " TEXCOORD8 " , " vofi_TexCoord8 " , 0 , AT_PS_IN , 0 } ,
{ " half4 " , " htexcoord9 " , " TEXCOORD9 " , " vofi_TexCoord9 " , 0 , AT_PS_IN , 0 } ,
{ " float " , " fog " , " FOG " , " gl_FogFragCoord " , 0 , AT_VS_OUT , 0 } ,
{ " float4 " , " fog " , " FOG " , " gl_FogFragCoord " , 0 , AT_PS_IN , 0 } ,
{ NULL , NULL , NULL , NULL , 0 , 0 , 0 }
} ;
2012-11-28 15:47:07 +00:00
const char * types [ ] =
{
2012-11-26 18:58:24 +00:00
" int " ,
" float " ,
" half " ,
" fixed " ,
" bool " ,
" cint " ,
" cfloat " ,
" void "
} ;
static const int numTypes = sizeof ( types ) / sizeof ( types [ 0 ] ) ;
2012-11-28 15:47:07 +00:00
const char * typePosts [ ] =
{
2012-11-26 18:58:24 +00:00
" 1 " , " 2 " , " 3 " , " 4 " ,
" 1x1 " , " 1x2 " , " 1x3 " , " 1x4 " ,
" 2x1 " , " 2x2 " , " 2x3 " , " 2x4 " ,
" 3x1 " , " 3x2 " , " 3x3 " , " 3x4 " ,
" 4x1 " , " 4x2 " , " 4x3 " , " 4x4 "
} ;
static const int numTypePosts = sizeof ( typePosts ) / sizeof ( typePosts [ 0 ] ) ;
2012-11-28 15:47:07 +00:00
const char * prefixes [ ] =
{
2012-11-26 18:58:24 +00:00
" static " ,
" const " ,
" uniform " ,
" struct " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" sampler " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" sampler1D " ,
" sampler2D " ,
" sampler3D " ,
" samplerCUBE " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" sampler1DShadow " , // GLSL
" sampler2DShadow " , // GLSL
" sampler3DShadow " , // GLSL
" samplerCubeShadow " , // GLSL
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" sampler2DMS " , // GLSL
} ;
static const int numPrefixes = sizeof ( prefixes ) / sizeof ( prefixes [ 0 ] ) ;
// For GLSL we need to have the names for the renderparms so we can look up their run time indices within the renderprograms
2012-11-28 15:47:07 +00:00
static const char * GLSLParmNames [ ] =
{
2012-11-26 18:58:24 +00:00
" rpScreenCorrectionFactor " ,
" rpWindowCoord " ,
" rpDiffuseModifier " ,
" rpSpecularModifier " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpLocalLightOrigin " ,
" rpLocalViewOrigin " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpLightProjectionS " ,
" rpLightProjectionT " ,
" rpLightProjectionQ " ,
" rpLightFalloffS " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpBumpMatrixS " ,
" rpBumpMatrixT " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpDiffuseMatrixS " ,
" rpDiffuseMatrixT " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpSpecularMatrixS " ,
" rpSpecularMatrixT " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpVertexColorModulate " ,
" rpVertexColorAdd " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpColor " ,
" rpViewOrigin " ,
" rpGlobalEyePos " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpMVPmatrixX " ,
" rpMVPmatrixY " ,
" rpMVPmatrixZ " ,
" rpMVPmatrixW " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpModelMatrixX " ,
" rpModelMatrixY " ,
" rpModelMatrixZ " ,
" rpModelMatrixW " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpProjectionMatrixX " ,
" rpProjectionMatrixY " ,
" rpProjectionMatrixZ " ,
" rpProjectionMatrixW " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpModelViewMatrixX " ,
" rpModelViewMatrixY " ,
" rpModelViewMatrixZ " ,
" rpModelViewMatrixW " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpTextureMatrixS " ,
" rpTextureMatrixT " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpTexGen0S " ,
" rpTexGen0T " ,
" rpTexGen0Q " ,
" rpTexGen0Enabled " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpTexGen1S " ,
" rpTexGen1T " ,
" rpTexGen1Q " ,
" rpTexGen1Enabled " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpWobbleSkyX " ,
" rpWobbleSkyY " ,
" rpWobbleSkyZ " ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
" rpOverbright " ,
" rpEnableSkinning " ,
" rpAlphaTest "
} ;
/*
= = = = = = = = = = = = = = = = = = = = = = = =
StripDeadCode
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idStr StripDeadCode ( const idStr & in , const char * name )
{
if ( r_skipStripDeadCode . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
return in ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//idLexer src( LEXFL_NOFATALERRORS );
idParser src ( LEXFL_NOFATALERRORS ) ;
src . LoadMemory ( in . c_str ( ) , in . Length ( ) , name ) ;
2012-11-28 15:47:07 +00:00
src . AddDefine ( " PC " ) ;
2012-11-26 18:58:24 +00:00
idList < idCGBlock , TAG_RENDERPROG > blocks ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
blocks . SetNum ( 100 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idToken token ;
2012-11-28 15:47:07 +00:00
while ( ! src . EndOfFile ( ) )
{
idCGBlock & block = blocks . Alloc ( ) ;
2012-11-26 18:58:24 +00:00
// read prefix
2012-11-28 15:47:07 +00:00
while ( src . ReadToken ( & token ) )
{
2012-11-26 18:58:24 +00:00
bool found = false ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < numPrefixes ; i + + )
{
if ( token = = prefixes [ i ] )
{
2012-11-26 18:58:24 +00:00
found = true ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! found )
{
for ( int i = 0 ; i < numTypes ; i + + )
{
if ( token = = types [ i ] )
{
2012-11-26 18:58:24 +00:00
found = true ;
break ;
}
int typeLen = idStr : : Length ( types [ i ] ) ;
2012-11-28 15:47:07 +00:00
if ( token . Cmpn ( types [ i ] , typeLen ) = = 0 )
{
for ( int j = 0 ; j < numTypePosts ; j + + )
{
if ( idStr : : Cmp ( token . c_str ( ) + typeLen , typePosts [ j ] ) = = 0 )
{
2012-11-26 18:58:24 +00:00
found = true ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( found )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
}
}
2012-11-28 15:47:07 +00:00
if ( found )
{
if ( block . prefix . Length ( ) > 0 & & token . WhiteSpaceBeforeToken ( ) )
{
2012-11-26 18:58:24 +00:00
block . prefix + = ' ' ;
}
block . prefix + = token ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
src . UnreadToken ( & token ) ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! src . ReadToken ( & token ) )
{
2012-11-26 18:58:24 +00:00
blocks . SetNum ( blocks . Num ( ) - 1 ) ;
break ;
}
block . name = token ;
2012-11-28 15:47:07 +00:00
if ( src . PeekTokenString ( " = " ) | | src . PeekTokenString ( " : " ) | | src . PeekTokenString ( " [ " ) )
{
2012-11-26 18:58:24 +00:00
src . ReadToken ( & token ) ;
block . postfix = token ;
2012-11-28 15:47:07 +00:00
while ( src . ReadToken ( & token ) )
{
if ( token = = " ; " )
{
2012-11-26 18:58:24 +00:00
block . postfix + = ' ; ' ;
break ;
2012-11-28 15:47:07 +00:00
}
else
{
if ( token . WhiteSpaceBeforeToken ( ) )
{
2012-11-26 18:58:24 +00:00
block . postfix + = ' ' ;
}
block . postfix + = token ;
}
}
2012-11-28 15:47:07 +00:00
}
else if ( src . PeekTokenString ( " ( " ) )
{
2012-11-26 18:58:24 +00:00
idStr parms , body ;
src . ParseBracedSection ( parms , - 1 , true , ' ( ' , ' ) ' ) ;
2012-11-28 15:47:07 +00:00
if ( src . CheckTokenString ( " ; " ) )
{
2012-11-26 18:58:24 +00:00
block . postfix = parms + " ; " ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
src . ParseBracedSection ( body , - 1 , true , ' { ' , ' } ' ) ;
block . postfix = parms + " " + body ;
}
2012-11-28 15:47:07 +00:00
}
else if ( src . PeekTokenString ( " { " ) )
{
2012-11-26 18:58:24 +00:00
src . ParseBracedSection ( block . postfix , - 1 , true , ' { ' , ' } ' ) ;
2012-11-28 15:47:07 +00:00
if ( src . CheckTokenString ( " ; " ) )
{
2012-11-26 18:58:24 +00:00
block . postfix + = ' ; ' ;
}
2012-11-28 15:47:07 +00:00
}
else if ( src . CheckTokenString ( " ; " ) )
{
2012-11-26 18:58:24 +00:00
block . postfix = idStr ( ' ; ' ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
src . Warning ( " Could not strip dead code -- unknown token %s \n " , token . c_str ( ) ) ;
return in ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idList < int , TAG_RENDERPROG > stack ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < blocks . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
blocks [ i ] . used = ( ( blocks [ i ] . name = = " main " )
2012-11-28 15:47:07 +00:00
| | blocks [ i ] . name . Right ( 4 ) = = " _ubo "
) ;
if ( blocks [ i ] . name = = " include " )
{
2012-11-26 18:58:24 +00:00
blocks [ i ] . used = true ;
blocks [ i ] . name = " " ; // clear out the include tag
}
2012-11-28 15:47:07 +00:00
if ( blocks [ i ] . used )
{
2012-11-26 18:58:24 +00:00
stack . Append ( i ) ;
}
}
2012-11-28 15:47:07 +00:00
while ( stack . Num ( ) > 0 )
{
2012-11-26 18:58:24 +00:00
int i = stack [ stack . Num ( ) - 1 ] ;
stack . SetNum ( stack . Num ( ) - 1 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLexer src ( LEXFL_NOFATALERRORS ) ;
src . LoadMemory ( blocks [ i ] . postfix . c_str ( ) , blocks [ i ] . postfix . Length ( ) , name ) ;
2012-11-28 15:47:07 +00:00
while ( src . ReadToken ( & token ) )
{
for ( int j = 0 ; j < blocks . Num ( ) ; j + + )
{
if ( ! blocks [ j ] . used )
{
if ( token = = blocks [ j ] . name )
{
2012-11-26 18:58:24 +00:00
blocks [ j ] . used = true ;
stack . Append ( j ) ;
}
}
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idStr out ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < blocks . Num ( ) ; i + + )
{
if ( blocks [ i ] . used )
{
2012-11-26 18:58:24 +00:00
out + = blocks [ i ] . prefix ;
out + = ' ' ;
out + = blocks [ i ] . name ;
out + = ' ' ;
out + = blocks [ i ] . postfix ;
out + = ' \n ' ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return out ;
}
2012-11-28 15:47:07 +00:00
struct typeConversion_t
{
const char * typeCG ;
const char * typeGLSL ;
} typeConversion [ ] =
{
2012-11-26 18:58:24 +00:00
{ " void " , " void " } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " fixed " , " float " } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " float " , " float " } ,
{ " float2 " , " vec2 " } ,
{ " float3 " , " vec3 " } ,
{ " float4 " , " vec4 " } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " half " , " float " } ,
{ " half2 " , " vec2 " } ,
{ " half3 " , " vec3 " } ,
{ " half4 " , " vec4 " } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " int " , " int " } ,
{ " int2 " , " ivec2 " } ,
{ " int3 " , " ivec3 " } ,
{ " int4 " , " ivec4 " } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " bool " , " bool " } ,
{ " bool2 " , " bvec2 " } ,
{ " bool3 " , " bvec3 " } ,
{ " bool4 " , " bvec4 " } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " float2x2 " , " mat2x2 " } ,
{ " float2x3 " , " mat2x3 " } ,
{ " float2x4 " , " mat2x4 " } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " float3x2 " , " mat3x2 " } ,
{ " float3x3 " , " mat3x3 " } ,
{ " float3x4 " , " mat3x4 " } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " float4x2 " , " mat4x2 " } ,
{ " float4x3 " , " mat4x3 " } ,
{ " float4x4 " , " mat4x4 " } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " sampler1D " , " sampler1D " } ,
{ " sampler2D " , " sampler2D " } ,
{ " sampler3D " , " sampler3D " } ,
{ " samplerCUBE " , " samplerCube " } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " sampler1DShadow " , " sampler1DShadow " } ,
{ " sampler2DShadow " , " sampler2DShadow " } ,
{ " sampler3DShadow " , " sampler3DShadow " } ,
{ " samplerCubeShadow " , " samplerCubeShadow " } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ " sampler2DMS " , " sampler2DMS " } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ NULL , NULL }
} ;
2012-11-28 15:47:07 +00:00
const char * vertexInsert =
{
2012-11-26 18:58:24 +00:00
" #version 150 \n "
" #define PC \n "
" \n "
" float saturate( float v ) { return clamp( v, 0.0, 1.0 ); } \n "
" vec2 saturate( vec2 v ) { return clamp( v, 0.0, 1.0 ); } \n "
" vec3 saturate( vec3 v ) { return clamp( v, 0.0, 1.0 ); } \n "
" vec4 saturate( vec4 v ) { return clamp( v, 0.0, 1.0 ); } \n "
" vec4 tex2Dlod( sampler2D sampler, vec4 texcoord ) { return textureLod( sampler, texcoord.xy, texcoord.w ); } \n "
" \n "
} ;
2012-11-28 15:47:07 +00:00
const char * fragmentInsert =
{
2012-11-26 18:58:24 +00:00
" #version 150 \n "
" #define PC \n "
" \n "
" void clip( float v ) { if ( v < 0.0 ) { discard; } } \n "
" void clip( vec2 v ) { if ( any( lessThan( v, vec2( 0.0 ) ) ) ) { discard; } } \n "
" void clip( vec3 v ) { if ( any( lessThan( v, vec3( 0.0 ) ) ) ) { discard; } } \n "
" void clip( vec4 v ) { if ( any( lessThan( v, vec4( 0.0 ) ) ) ) { discard; } } \n "
" \n "
" float saturate( float v ) { return clamp( v, 0.0, 1.0 ); } \n "
" vec2 saturate( vec2 v ) { return clamp( v, 0.0, 1.0 ); } \n "
" vec3 saturate( vec3 v ) { return clamp( v, 0.0, 1.0 ); } \n "
" vec4 saturate( vec4 v ) { return clamp( v, 0.0, 1.0 ); } \n "
" \n "
" vec4 tex2D( sampler2D sampler, vec2 texcoord ) { return texture( sampler, texcoord.xy ); } \n "
" vec4 tex2D( sampler2DShadow sampler, vec3 texcoord ) { return vec4( texture( sampler, texcoord.xyz ) ); } \n "
" \n "
" vec4 tex2D( sampler2D sampler, vec2 texcoord, vec2 dx, vec2 dy ) { return textureGrad( sampler, texcoord.xy, dx, dy ); } \n "
" vec4 tex2D( sampler2DShadow sampler, vec3 texcoord, vec2 dx, vec2 dy ) { return vec4( textureGrad( sampler, texcoord.xyz, dx, dy ) ); } \n "
" \n "
" vec4 texCUBE( samplerCube sampler, vec3 texcoord ) { return texture( sampler, texcoord.xyz ); } \n "
" vec4 texCUBE( samplerCubeShadow sampler, vec4 texcoord ) { return vec4( texture( sampler, texcoord.xyzw ) ); } \n "
" \n "
" vec4 tex1Dproj( sampler1D sampler, vec2 texcoord ) { return textureProj( sampler, texcoord ); } \n "
" vec4 tex2Dproj( sampler2D sampler, vec3 texcoord ) { return textureProj( sampler, texcoord ); } \n "
" vec4 tex3Dproj( sampler3D sampler, vec4 texcoord ) { return textureProj( sampler, texcoord ); } \n "
" \n "
" vec4 tex1Dbias( sampler1D sampler, vec4 texcoord ) { return texture( sampler, texcoord.x, texcoord.w ); } \n "
" vec4 tex2Dbias( sampler2D sampler, vec4 texcoord ) { return texture( sampler, texcoord.xy, texcoord.w ); } \n "
" vec4 tex3Dbias( sampler3D sampler, vec4 texcoord ) { return texture( sampler, texcoord.xyz, texcoord.w ); } \n "
" vec4 texCUBEbias( samplerCube sampler, vec4 texcoord ) { return texture( sampler, texcoord.xyz, texcoord.w ); } \n "
" \n "
" vec4 tex1Dlod( sampler1D sampler, vec4 texcoord ) { return textureLod( sampler, texcoord.x, texcoord.w ); } \n "
" vec4 tex2Dlod( sampler2D sampler, vec4 texcoord ) { return textureLod( sampler, texcoord.xy, texcoord.w ); } \n "
" vec4 tex3Dlod( sampler3D sampler, vec4 texcoord ) { return textureLod( sampler, texcoord.xyz, texcoord.w ); } \n "
" vec4 texCUBElod( samplerCube sampler, vec4 texcoord ) { return textureLod( sampler, texcoord.xyz, texcoord.w ); } \n "
" \n "
} ;
2012-11-28 15:47:07 +00:00
struct builtinConversion_t
{
const char * nameCG ;
const char * nameGLSL ;
} builtinConversion [ ] =
{
2012-11-26 18:58:24 +00:00
{ " frac " , " fract " } ,
{ " lerp " , " mix " } ,
{ " rsqrt " , " inversesqrt " } ,
{ " ddx " , " dFdx " } ,
{ " ddy " , " dFdy " } ,
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{ NULL , NULL }
} ;
2012-11-28 15:47:07 +00:00
struct inOutVariable_t
{
2012-11-26 18:58:24 +00:00
idStr type ;
idStr nameCg ;
idStr nameGLSL ;
bool declareInOut ;
} ;
/*
= = = = = = = = = = = = = = = = = = = = = = = =
ParseInOutStruct
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void ParseInOutStruct ( idLexer & src , int attribType , idList < inOutVariable_t > & inOutVars )
{
2012-11-26 18:58:24 +00:00
src . ExpectTokenString ( " { " ) ;
2012-11-28 15:47:07 +00:00
while ( ! src . CheckTokenString ( " } " ) )
{
2012-11-26 18:58:24 +00:00
inOutVariable_t var ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idToken token ;
src . ReadToken ( & token ) ;
var . type = token ;
src . ReadToken ( & token ) ;
var . nameCg = token ;
2012-11-28 15:47:07 +00:00
if ( ! src . CheckTokenString ( " : " ) )
{
2012-11-26 18:58:24 +00:00
src . SkipUntilString ( " ; " ) ;
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
src . ReadToken ( & token ) ;
var . nameGLSL = token ;
src . ExpectTokenString ( " ; " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// convert the type
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; typeConversion [ i ] . typeCG ! = NULL ; i + + )
{
if ( var . type . Cmp ( typeConversion [ i ] . typeCG ) = = 0 )
{
2012-11-26 18:58:24 +00:00
var . type = typeConversion [ i ] . typeGLSL ;
break ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// convert the semantic to a GLSL name
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; attribsPC [ i ] . semantic ! = NULL ; i + + )
{
if ( ( attribsPC [ i ] . flags & attribType ) ! = 0 )
{
if ( var . nameGLSL . Cmp ( attribsPC [ i ] . semantic ) = = 0 )
{
2012-11-26 18:58:24 +00:00
var . nameGLSL = attribsPC [ i ] . glsl ;
break ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check if it was defined previously
var . declareInOut = true ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < inOutVars . Num ( ) ; i + + )
{
if ( var . nameGLSL = = inOutVars [ i ] . nameGLSL )
{
2012-11-26 18:58:24 +00:00
var . declareInOut = false ;
break ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
inOutVars . Append ( var ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
src . ExpectTokenString ( " ; " ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
ConvertCG2GLSL
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idStr ConvertCG2GLSL ( const idStr & in , const char * name , bool isVertexProgram , idStr & uniforms )
{
2012-11-26 18:58:24 +00:00
idStr program ;
program . ReAllocate ( in . Length ( ) * 2 , false ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idList < inOutVariable_t , TAG_RENDERPROG > varsIn ;
idList < inOutVariable_t , TAG_RENDERPROG > varsOut ;
idList < idStr > uniformList ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLexer src ( LEXFL_NOFATALERRORS ) ;
src . LoadMemory ( in . c_str ( ) , in . Length ( ) , name ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool inMain = false ;
2012-11-28 15:47:07 +00:00
const char * uniformArrayName = isVertexProgram ? VERTEX_UNIFORM_ARRAY_NAME : FRAGMENT_UNIFORM_ARRAY_NAME ;
2012-11-26 18:58:24 +00:00
char newline [ 128 ] = { " \n " } ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idToken token ;
2012-11-28 15:47:07 +00:00
while ( src . ReadToken ( & token ) )
{
2012-11-26 18:58:24 +00:00
// check for uniforms
2012-11-28 15:47:07 +00:00
while ( token = = " uniform " & & src . CheckTokenString ( " float4 " ) )
{
2012-11-26 18:58:24 +00:00
src . ReadToken ( & token ) ;
uniformList . Append ( token ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// strip ': register()' from uniforms
2012-11-28 15:47:07 +00:00
if ( src . CheckTokenString ( " : " ) )
{
if ( src . CheckTokenString ( " register " ) )
{
2012-11-26 18:58:24 +00:00
src . SkipUntilString ( " ; " ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
src . ReadToken ( & token ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// convert the in/out structs
2012-11-28 15:47:07 +00:00
if ( token = = " struct " )
{
if ( src . CheckTokenString ( " VS_IN " ) )
{
2012-11-26 18:58:24 +00:00
ParseInOutStruct ( src , AT_VS_IN , varsIn ) ;
program + = " \n \n " ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < varsIn . Num ( ) ; i + + )
{
if ( varsIn [ i ] . declareInOut )
{
2012-11-26 18:58:24 +00:00
program + = " in " + varsIn [ i ] . type + " " + varsIn [ i ] . nameGLSL + " ; \n " ;
}
}
continue ;
2012-11-28 15:47:07 +00:00
}
else if ( src . CheckTokenString ( " VS_OUT " ) )
{
2012-11-26 18:58:24 +00:00
ParseInOutStruct ( src , AT_VS_OUT , varsOut ) ;
program + = " \n " ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < varsOut . Num ( ) ; i + + )
{
if ( varsOut [ i ] . declareInOut )
{
2012-11-26 18:58:24 +00:00
program + = " out " + varsOut [ i ] . type + " " + varsOut [ i ] . nameGLSL + " ; \n " ;
}
}
continue ;
2012-11-28 15:47:07 +00:00
}
else if ( src . CheckTokenString ( " PS_IN " ) )
{
2012-11-26 18:58:24 +00:00
ParseInOutStruct ( src , AT_PS_IN , varsIn ) ;
program + = " \n \n " ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < varsIn . Num ( ) ; i + + )
{
if ( varsIn [ i ] . declareInOut )
{
2012-11-26 18:58:24 +00:00
program + = " in " + varsIn [ i ] . type + " " + varsIn [ i ] . nameGLSL + " ; \n " ;
}
}
inOutVariable_t var ;
var . type = " vec4 " ;
var . nameCg = " position " ;
var . nameGLSL = " gl_FragCoord " ;
varsIn . Append ( var ) ;
continue ;
2012-11-28 15:47:07 +00:00
}
else if ( src . CheckTokenString ( " PS_OUT " ) )
{
2012-11-26 18:58:24 +00:00
ParseInOutStruct ( src , AT_PS_OUT , varsOut ) ;
program + = " \n " ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < varsOut . Num ( ) ; i + + )
{
if ( varsOut [ i ] . declareInOut )
{
2012-11-26 18:58:24 +00:00
program + = " out " + varsOut [ i ] . type + " " + varsOut [ i ] . nameGLSL + " ; \n " ;
}
}
continue ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// strip 'static'
2012-11-28 15:47:07 +00:00
if ( token = = " static " )
{
2012-11-26 18:58:24 +00:00
program + = ( token . linesCrossed > 0 ) ? newline : ( token . WhiteSpaceBeforeToken ( ) > 0 ? " " : " " ) ;
src . SkipWhiteSpace ( true ) ; // remove white space between 'static' and the next token
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// strip ': register()' from uniforms
2012-11-28 15:47:07 +00:00
if ( token = = " : " )
{
if ( src . CheckTokenString ( " register " ) )
{
2012-11-26 18:58:24 +00:00
src . SkipUntilString ( " ; " ) ;
program + = " ; " ;
continue ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// strip in/program parameters from main
2012-11-28 15:47:07 +00:00
if ( token = = " void " & & src . CheckTokenString ( " main " ) )
{
2012-11-26 18:58:24 +00:00
src . ExpectTokenString ( " ( " ) ;
2012-11-28 15:47:07 +00:00
while ( src . ReadToken ( & token ) )
{
if ( token = = " ) " )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
program + = " \n void main() " ;
inMain = true ;
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// strip 'const' from local variables in main()
2012-11-28 15:47:07 +00:00
if ( token = = " const " & & inMain )
{
2012-11-26 18:58:24 +00:00
program + = ( token . linesCrossed > 0 ) ? newline : ( token . WhiteSpaceBeforeToken ( ) > 0 ? " " : " " ) ;
src . SkipWhiteSpace ( true ) ; // remove white space between 'const' and the next token
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// maintain indentation
2012-11-28 15:47:07 +00:00
if ( token = = " { " )
{
2012-11-26 18:58:24 +00:00
program + = ( token . linesCrossed > 0 ) ? newline : ( token . WhiteSpaceBeforeToken ( ) > 0 ? " " : " " ) ;
program + = " { " ;
2012-11-28 15:47:07 +00:00
int len = Min ( idStr : : Length ( newline ) + 1 , ( int ) sizeof ( newline ) - 1 ) ;
2012-11-26 18:58:24 +00:00
newline [ len - 1 ] = ' \t ' ;
newline [ len - 0 ] = ' \0 ' ;
continue ;
}
2012-11-28 15:47:07 +00:00
if ( token = = " } " )
{
2012-11-26 18:58:24 +00:00
int len = Max ( idStr : : Length ( newline ) - 1 , 0 ) ;
newline [ len ] = ' \0 ' ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
program + = ( token . linesCrossed > 0 ) ? newline : ( token . WhiteSpaceBeforeToken ( ) > 0 ? " " : " " ) ;
program + = " } " ;
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check for a type conversion
bool foundType = false ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; typeConversion [ i ] . typeCG ! = NULL ; i + + )
{
if ( token . Cmp ( typeConversion [ i ] . typeCG ) = = 0 )
{
2012-11-26 18:58:24 +00:00
program + = ( token . linesCrossed > 0 ) ? newline : ( token . WhiteSpaceBeforeToken ( ) > 0 ? " " : " " ) ;
program + = typeConversion [ i ] . typeGLSL ;
foundType = true ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( foundType )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( r_useUniformArrays . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
// check for uniforms that need to be converted to the array
bool isUniform = false ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < uniformList . Num ( ) ; i + + )
{
if ( token = = uniformList [ i ] )
{
2012-11-26 18:58:24 +00:00
program + = ( token . linesCrossed > 0 ) ? newline : ( token . WhiteSpaceBeforeToken ( ) > 0 ? " " : " " ) ;
program + = va ( " %s[%d /* %s */] " , uniformArrayName , i , uniformList [ i ] . c_str ( ) ) ;
isUniform = true ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( isUniform )
{
2012-11-26 18:58:24 +00:00
continue ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check for input/output parameters
2012-11-28 15:47:07 +00:00
if ( src . CheckTokenString ( " . " ) )
{
if ( token = = " vertex " | | token = = " fragment " )
{
2012-11-26 18:58:24 +00:00
idToken member ;
src . ReadToken ( & member ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool foundInOut = false ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < varsIn . Num ( ) ; i + + )
{
if ( member . Cmp ( varsIn [ i ] . nameCg ) = = 0 )
{
2012-11-26 18:58:24 +00:00
program + = ( token . linesCrossed > 0 ) ? newline : ( token . WhiteSpaceBeforeToken ( ) > 0 ? " " : " " ) ;
program + = varsIn [ i ] . nameGLSL ;
foundInOut = true ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! foundInOut )
{
2012-11-26 18:58:24 +00:00
src . Error ( " invalid input parameter %s.%s " , token . c_str ( ) , member . c_str ( ) ) ;
program + = ( token . linesCrossed > 0 ) ? newline : ( token . WhiteSpaceBeforeToken ( ) > 0 ? " " : " " ) ;
program + = token ;
program + = " . " ;
program + = member ;
}
continue ;
}
2012-11-28 15:47:07 +00:00
if ( token = = " result " )
{
2012-11-26 18:58:24 +00:00
idToken member ;
src . ReadToken ( & member ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool foundInOut = false ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < varsOut . Num ( ) ; i + + )
{
if ( member . Cmp ( varsOut [ i ] . nameCg ) = = 0 )
{
2012-11-26 18:58:24 +00:00
program + = ( token . linesCrossed > 0 ) ? newline : ( token . WhiteSpaceBeforeToken ( ) > 0 ? " " : " " ) ;
program + = varsOut [ i ] . nameGLSL ;
foundInOut = true ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! foundInOut )
{
2012-11-26 18:58:24 +00:00
src . Error ( " invalid output parameter %s.%s " , token . c_str ( ) , member . c_str ( ) ) ;
program + = ( token . linesCrossed > 0 ) ? newline : ( token . WhiteSpaceBeforeToken ( ) > 0 ? " " : " " ) ;
program + = token ;
program + = " . " ;
program + = member ;
}
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
program + = ( token . linesCrossed > 0 ) ? newline : ( token . WhiteSpaceBeforeToken ( ) > 0 ? " " : " " ) ;
program + = token ;
program + = " . " ;
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check for a function conversion
bool foundFunction = false ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; builtinConversion [ i ] . nameCG ! = NULL ; i + + )
{
if ( token . Cmp ( builtinConversion [ i ] . nameCG ) = = 0 )
{
2012-11-26 18:58:24 +00:00
program + = ( token . linesCrossed > 0 ) ? newline : ( token . WhiteSpaceBeforeToken ( ) > 0 ? " " : " " ) ;
program + = builtinConversion [ i ] . nameGLSL ;
foundFunction = true ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( foundFunction )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
program + = ( token . linesCrossed > 0 ) ? newline : ( token . WhiteSpaceBeforeToken ( ) > 0 ? " " : " " ) ;
program + = token ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idStr out ;
2012-11-28 15:47:07 +00:00
if ( isVertexProgram )
{
2012-11-26 18:58:24 +00:00
out . ReAllocate ( idStr : : Length ( vertexInsert ) + in . Length ( ) * 2 , false ) ;
out + = vertexInsert ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
out . ReAllocate ( idStr : : Length ( fragmentInsert ) + in . Length ( ) * 2 , false ) ;
out + = fragmentInsert ;
}
2012-11-28 15:47:07 +00:00
if ( uniformList . Num ( ) > 0 )
{
if ( r_useUniformArrays . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
out + = va ( " \n uniform vec4 %s[%d]; \n " , uniformArrayName , uniformList . Num ( ) ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
out + = " \n " ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < uniformList . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
out + = " uniform vec4 " ;
out + = uniformList [ i ] ;
out + = " ; \n " ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
out + = program ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < uniformList . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
uniforms + = uniformList [ i ] ;
uniforms + = " \n " ;
}
uniforms + = " \n " ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return out ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idRenderProgManager : : LoadGLSLShader
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
GLuint idRenderProgManager : : LoadGLSLShader ( GLenum target , const char * name , idList < int > & uniforms )
{
2012-11-26 18:58:24 +00:00
idStr inFile ;
idStr outFileHLSL ;
idStr outFileGLSL ;
idStr outFileUniforms ;
2012-12-14 13:21:50 +00:00
// RB: replaced backslashes
inFile . Format ( " renderprogs/%s " , name ) ;
2012-11-26 18:58:24 +00:00
inFile . StripFileExtension ( ) ;
2012-12-14 13:21:50 +00:00
outFileHLSL . Format ( " renderprogs/hlsl/%s " , name ) ;
2012-11-26 18:58:24 +00:00
outFileHLSL . StripFileExtension ( ) ;
2012-12-14 13:21:50 +00:00
outFileGLSL . Format ( " renderprogs/glsl/%s " , name ) ;
2012-11-26 18:58:24 +00:00
outFileGLSL . StripFileExtension ( ) ;
2012-12-14 13:21:50 +00:00
outFileUniforms . Format ( " renderprogs/glsl/%s " , name ) ;
2012-11-26 18:58:24 +00:00
outFileUniforms . StripFileExtension ( ) ;
2012-12-14 13:21:50 +00:00
// RB end
2012-11-28 15:47:07 +00:00
if ( target = = GL_FRAGMENT_SHADER )
{
2012-11-26 18:58:24 +00:00
inFile + = " .pixel " ;
outFileHLSL + = " _fragment.hlsl " ;
outFileGLSL + = " _fragment.glsl " ;
outFileUniforms + = " _fragment.uniforms " ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
inFile + = " .vertex " ;
outFileHLSL + = " _vertex.hlsl " ;
outFileGLSL + = " _vertex.glsl " ;
outFileUniforms + = " _vertex.uniforms " ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// first check whether we already have a valid GLSL file and compare it to the hlsl timestamp;
ID_TIME_T hlslTimeStamp ;
int hlslFileLength = fileSystem - > ReadFile ( inFile . c_str ( ) , NULL , & hlslTimeStamp ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ID_TIME_T glslTimeStamp ;
int glslFileLength = fileSystem - > ReadFile ( outFileGLSL . c_str ( ) , NULL , & glslTimeStamp ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if the glsl file doesn't exist or we have a newer HLSL file we need to recreate the glsl file.
idStr programGLSL ;
idStr programUniforms ;
2012-11-28 15:47:07 +00:00
if ( ( glslFileLength < = 0 ) | | ( hlslTimeStamp > glslTimeStamp ) )
{
if ( hlslFileLength < = 0 )
{
2012-11-26 18:58:24 +00:00
// hlsl file doesn't even exist bail out
return false ;
}
2012-11-28 15:47:07 +00:00
void * hlslFileBuffer = NULL ;
2012-11-26 18:58:24 +00:00
int len = fileSystem - > ReadFile ( inFile . c_str ( ) , & hlslFileBuffer ) ;
2012-11-28 15:47:07 +00:00
if ( len < = 0 )
{
2012-11-26 18:58:24 +00:00
return false ;
}
idStr hlslCode ( ( const char * ) hlslFileBuffer ) ;
idStr programHLSL = StripDeadCode ( hlslCode , inFile ) ;
programGLSL = ConvertCG2GLSL ( programHLSL , inFile , target = = GL_VERTEX_SHADER , programUniforms ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
fileSystem - > WriteFile ( outFileHLSL , programHLSL . c_str ( ) , programHLSL . Length ( ) , " fs_basepath " ) ;
fileSystem - > WriteFile ( outFileGLSL , programGLSL . c_str ( ) , programGLSL . Length ( ) , " fs_basepath " ) ;
2012-11-28 15:47:07 +00:00
if ( r_useUniformArrays . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
fileSystem - > WriteFile ( outFileUniforms , programUniforms . c_str ( ) , programUniforms . Length ( ) , " fs_basepath " ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// read in the glsl file
2012-11-28 15:47:07 +00:00
void * fileBufferGLSL = NULL ;
2012-11-26 18:58:24 +00:00
int lengthGLSL = fileSystem - > ReadFile ( outFileGLSL . c_str ( ) , & fileBufferGLSL ) ;
2012-11-28 15:47:07 +00:00
if ( lengthGLSL < = 0 )
{
2012-11-26 18:58:24 +00:00
idLib : : Error ( " GLSL file %s could not be loaded and may be corrupt " , outFileGLSL . c_str ( ) ) ;
}
2012-11-28 15:47:07 +00:00
programGLSL = ( const char * ) fileBufferGLSL ;
2012-11-26 18:58:24 +00:00
Mem_Free ( fileBufferGLSL ) ;
2012-11-28 15:47:07 +00:00
if ( r_useUniformArrays . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
// read in the uniform file
2012-11-28 15:47:07 +00:00
void * fileBufferUniforms = NULL ;
2012-11-26 18:58:24 +00:00
int lengthUniforms = fileSystem - > ReadFile ( outFileUniforms . c_str ( ) , & fileBufferUniforms ) ;
2012-11-28 15:47:07 +00:00
if ( lengthUniforms < = 0 )
{
2012-11-26 18:58:24 +00:00
idLib : : Error ( " uniform file %s could not be loaded and may be corrupt " , outFileUniforms . c_str ( ) ) ;
}
programUniforms = ( const char * ) fileBufferUniforms ;
Mem_Free ( fileBufferUniforms ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// find the uniforms locations in either the vertex or fragment uniform array
2012-11-28 15:47:07 +00:00
if ( r_useUniformArrays . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
uniforms . Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLexer src ( programUniforms , programUniforms . Length ( ) , " uniforms " ) ;
idToken token ;
2012-11-28 15:47:07 +00:00
while ( src . ReadToken ( & token ) )
{
2012-11-26 18:58:24 +00:00
int index = - 1 ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < RENDERPARM_TOTAL & & index = = - 1 ; i + + )
{
const char * parmName = GetGLSLParmName ( i ) ;
if ( token = = parmName )
{
2012-11-26 18:58:24 +00:00
index = i ;
}
}
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < MAX_GLSL_USER_PARMS & & index = = - 1 ; i + + )
{
const char * parmName = GetGLSLParmName ( RENDERPARM_USER + i ) ;
if ( token = = parmName )
{
2012-11-26 18:58:24 +00:00
index = RENDERPARM_USER + i ;
}
}
2012-11-28 15:47:07 +00:00
if ( index = = - 1 )
{
2012-11-26 18:58:24 +00:00
idLib : : Error ( " couldn't find uniform %s for %s " , token . c_str ( ) , outFileGLSL . c_str ( ) ) ;
}
uniforms . Append ( index ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// create and compile the shader
const GLuint shader = qglCreateShader ( target ) ;
2012-11-28 15:47:07 +00:00
if ( shader )
{
const char * source [ 1 ] = { programGLSL . c_str ( ) } ;
2012-11-26 18:58:24 +00:00
qglShaderSource ( shader , 1 , source , NULL ) ;
qglCompileShader ( shader ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int infologLength = 0 ;
qglGetShaderiv ( shader , GL_INFO_LOG_LENGTH , & infologLength ) ;
2012-11-28 15:47:07 +00:00
if ( infologLength > 1 )
{
2012-11-26 18:58:24 +00:00
idTempArray < char > infoLog ( infologLength ) ;
int charsWritten = 0 ;
qglGetShaderInfoLog ( shader , infologLength , & charsWritten , infoLog . Ptr ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// catch the strings the ATI and Intel drivers output on success
2012-11-28 15:47:07 +00:00
if ( strstr ( infoLog . Ptr ( ) , " successfully compiled to run on hardware " ) ! = NULL | |
strstr ( infoLog . Ptr ( ) , " No errors. " ) ! = NULL )
{
2012-11-26 18:58:24 +00:00
//idLib::Printf( "%s program %s from %s compiled to run on hardware\n", typeName, GetName(), GetFileName() );
2012-11-28 15:47:07 +00:00
}
2013-03-16 01:07:59 +00:00
else if ( r_displayGLSLCompilerMessages . GetBool ( ) ) // DG: check for the CVar I added above
2012-11-28 15:47:07 +00:00
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " While compiling %s program %s \n " , ( target = = GL_FRAGMENT_SHADER ) ? " fragment " : " vertex " , inFile . c_str ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const char separator = ' \n ' ;
idList < idStr > lines ;
lines . Clear ( ) ;
idStr source ( programGLSL ) ;
lines . Append ( source ) ;
2012-11-28 15:47:07 +00:00
for ( int index = 0 , ofs = lines [ index ] . Find ( separator ) ; ofs ! = - 1 ; index + + , ofs = lines [ index ] . Find ( separator ) )
{
2012-11-26 18:58:24 +00:00
lines . Append ( lines [ index ] . c_str ( ) + ofs + 1 ) ;
lines [ index ] . CapLength ( ofs ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " ----------------- \n " ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < lines . Num ( ) ; i + + )
{
idLib : : Printf ( " %3d: %s \n " , i + 1 , lines [ i ] . c_str ( ) ) ;
2012-11-26 18:58:24 +00:00
}
idLib : : Printf ( " ----------------- \n " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " %s \n " , infoLog . Ptr ( ) ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GLint compiled = GL_FALSE ;
qglGetShaderiv ( shader , GL_COMPILE_STATUS , & compiled ) ;
2012-11-28 15:47:07 +00:00
if ( compiled = = GL_FALSE )
{
2012-11-26 18:58:24 +00:00
qglDeleteShader ( shader ) ;
return INVALID_PROGID ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return shader ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idRenderProgManager : : FindGLSLProgram
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idRenderProgManager : : FindGLSLProgram ( const char * name , int vIndex , int fIndex )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < glslPrograms . Num ( ) ; + + i )
{
if ( ( glslPrograms [ i ] . vertexShaderIndex = = vIndex ) & & ( glslPrograms [ i ] . fragmentShaderIndex = = fIndex ) )
{
2012-11-26 18:58:24 +00:00
LoadGLSLProgram ( i , vIndex , fIndex ) ;
return i ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
glslProgram_t program ;
program . name = name ;
int index = glslPrograms . Append ( program ) ;
LoadGLSLProgram ( index , vIndex , fIndex ) ;
return index ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idRenderProgManager : : GetGLSLParmName
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idRenderProgManager : : GetGLSLParmName ( int rp ) const
{
if ( rp > = RENDERPARM_USER )
{
2012-11-26 18:58:24 +00:00
int userParmIndex = rp - RENDERPARM_USER ;
2012-11-28 15:47:07 +00:00
return va ( " rpUser%d " , userParmIndex ) ;
2012-11-26 18:58:24 +00:00
}
assert ( rp < RENDERPARM_TOTAL ) ;
return GLSLParmNames [ rp ] ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idRenderProgManager : : SetUniformValue
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idRenderProgManager : : SetUniformValue ( const renderParm_t rp , const float * value )
{
for ( int i = 0 ; i < 4 ; i + + )
{
2012-11-26 18:58:24 +00:00
glslUniforms [ rp ] [ i ] = value [ i ] ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idRenderProgManager : : CommitUnforms
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idRenderProgManager : : CommitUniforms ( )
{
2012-11-26 18:58:24 +00:00
const int progID = GetGLSLCurrentProgram ( ) ;
2012-11-28 15:47:07 +00:00
const glslProgram_t & prog = glslPrograms [ progID ] ;
if ( r_useUniformArrays . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
ALIGNTYPE16 idVec4 localVectors [ RENDERPARM_USER + MAX_GLSL_USER_PARMS ] ;
2012-11-28 15:47:07 +00:00
if ( prog . vertexShaderIndex > = 0 )
{
const idList < int > & vertexUniforms = vertexShaders [ prog . vertexShaderIndex ] . uniforms ;
if ( prog . vertexUniformArray ! = - 1 & & vertexUniforms . Num ( ) > 0 )
{
for ( int i = 0 ; i < vertexUniforms . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
localVectors [ i ] = glslUniforms [ vertexUniforms [ i ] ] ;
}
qglUniform4fv ( prog . vertexUniformArray , vertexUniforms . Num ( ) , localVectors - > ToFloatPtr ( ) ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( prog . fragmentShaderIndex > = 0 )
{
const idList < int > & fragmentUniforms = fragmentShaders [ prog . fragmentShaderIndex ] . uniforms ;
if ( prog . fragmentUniformArray ! = - 1 & & fragmentUniforms . Num ( ) > 0 )
{
for ( int i = 0 ; i < fragmentUniforms . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
localVectors [ i ] = glslUniforms [ fragmentUniforms [ i ] ] ;
}
qglUniform4fv ( prog . fragmentUniformArray , fragmentUniforms . Num ( ) , localVectors - > ToFloatPtr ( ) ) ;
}
}
2012-11-28 15:47:07 +00:00
}
else
{
for ( int i = 0 ; i < prog . uniformLocations . Num ( ) ; i + + )
{
const glslUniformLocation_t & uniformLocation = prog . uniformLocations [ i ] ;
2012-11-26 18:58:24 +00:00
qglUniform4fv ( uniformLocation . uniformIndex , 1 , glslUniforms [ uniformLocation . parmIndex ] . ToFloatPtr ( ) ) ;
}
}
}
2012-11-28 15:47:07 +00:00
class idSort_QuickUniforms : public idSort_Quick < glslUniformLocation_t , idSort_QuickUniforms >
{
2012-11-26 18:58:24 +00:00
public :
2012-11-28 15:47:07 +00:00
int Compare ( const glslUniformLocation_t & a , const glslUniformLocation_t & b ) const
{
return a . uniformIndex - b . uniformIndex ;
}
2012-11-26 18:58:24 +00:00
} ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idRenderProgManager : : LoadGLSLProgram
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idRenderProgManager : : LoadGLSLProgram ( const int programIndex , const int vertexShaderIndex , const int fragmentShaderIndex )
{
glslProgram_t & prog = glslPrograms [ programIndex ] ;
if ( prog . progId ! = INVALID_PROGID )
{
2012-11-26 18:58:24 +00:00
return ; // Already loaded
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
GLuint vertexProgID = ( vertexShaderIndex ! = - 1 ) ? vertexShaders [ vertexShaderIndex ] . progId : INVALID_PROGID ;
GLuint fragmentProgID = ( fragmentShaderIndex ! = - 1 ) ? fragmentShaders [ fragmentShaderIndex ] . progId : INVALID_PROGID ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const GLuint program = qglCreateProgram ( ) ;
2012-11-28 15:47:07 +00:00
if ( program )
{
if ( vertexProgID ! = INVALID_PROGID )
{
2012-11-26 18:58:24 +00:00
qglAttachShader ( program , vertexProgID ) ;
}
2012-11-28 15:47:07 +00:00
if ( fragmentProgID ! = INVALID_PROGID )
{
2012-11-26 18:58:24 +00:00
qglAttachShader ( program , fragmentProgID ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// bind vertex attribute locations
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; attribsPC [ i ] . glsl ! = NULL ; i + + )
{
if ( ( attribsPC [ i ] . flags & AT_VS_IN ) ! = 0 )
{
2012-11-26 18:58:24 +00:00
qglBindAttribLocation ( program , attribsPC [ i ] . bind , attribsPC [ i ] . glsl ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
qglLinkProgram ( program ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int infologLength = 0 ;
qglGetProgramiv ( program , GL_INFO_LOG_LENGTH , & infologLength ) ;
2012-11-28 15:47:07 +00:00
if ( infologLength > 1 )
{
char * infoLog = ( char * ) malloc ( infologLength ) ;
2012-11-26 18:58:24 +00:00
int charsWritten = 0 ;
qglGetProgramInfoLog ( program , infologLength , & charsWritten , infoLog ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// catch the strings the ATI and Intel drivers output on success
2012-11-28 15:47:07 +00:00
if ( strstr ( infoLog , " Vertex shader(s) linked, fragment shader(s) linked. " ) ! = NULL | | strstr ( infoLog , " No errors. " ) ! = NULL )
{
2012-11-26 18:58:24 +00:00
//idLib::Printf( "render prog %s from %s linked\n", GetName(), GetFileName() );
2012-11-28 15:47:07 +00:00
}
else
{
idLib : : Printf ( " While linking GLSL program %d with vertexShader %s and fragmentShader %s \n " ,
programIndex ,
( vertexShaderIndex > = 0 ) ? vertexShaders [ vertexShaderIndex ] . name . c_str ( ) : " <Invalid> " ,
( fragmentShaderIndex > = 0 ) ? fragmentShaders [ fragmentShaderIndex ] . name . c_str ( ) : " <Invalid> " ) ;
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " %s \n " , infoLog ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
free ( infoLog ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int linked = GL_FALSE ;
qglGetProgramiv ( program , GL_LINK_STATUS , & linked ) ;
2012-11-28 15:47:07 +00:00
if ( linked = = GL_FALSE )
{
2012-11-26 18:58:24 +00:00
qglDeleteProgram ( program ) ;
2012-11-28 15:47:07 +00:00
idLib : : Error ( " While linking GLSL program %d with vertexShader %s and fragmentShader %s \n " ,
programIndex ,
( vertexShaderIndex > = 0 ) ? vertexShaders [ vertexShaderIndex ] . name . c_str ( ) : " <Invalid> " ,
( fragmentShaderIndex > = 0 ) ? fragmentShaders [ fragmentShaderIndex ] . name . c_str ( ) : " <Invalid> " ) ;
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( r_useUniformArrays . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
prog . vertexUniformArray = qglGetUniformLocation ( program , VERTEX_UNIFORM_ARRAY_NAME ) ;
prog . fragmentUniformArray = qglGetUniformLocation ( program , FRAGMENT_UNIFORM_ARRAY_NAME ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( prog . vertexUniformArray ! = - 1 | | vertexShaderIndex < 0 | | vertexShaders [ vertexShaderIndex ] . uniforms . Num ( ) = = 0 ) ;
assert ( prog . fragmentUniformArray ! = - 1 | | fragmentShaderIndex < 0 | | fragmentShaders [ fragmentShaderIndex ] . uniforms . Num ( ) = = 0 ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// store the uniform locations after we have linked the GLSL program
prog . uniformLocations . Clear ( ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < RENDERPARM_TOTAL ; i + + )
{
const char * parmName = GetGLSLParmName ( i ) ;
2012-11-26 18:58:24 +00:00
GLint loc = qglGetUniformLocation ( program , parmName ) ;
2012-11-28 15:47:07 +00:00
if ( loc ! = - 1 )
{
2012-11-26 18:58:24 +00:00
glslUniformLocation_t uniformLocation ;
uniformLocation . parmIndex = i ;
uniformLocation . uniformIndex = loc ;
prog . uniformLocations . Append ( uniformLocation ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// store the USER uniform locations
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < MAX_GLSL_USER_PARMS ; i + + )
{
const char * parmName = GetGLSLParmName ( RENDERPARM_USER + i ) ;
2012-11-26 18:58:24 +00:00
GLint loc = qglGetUniformLocation ( program , parmName ) ;
2012-11-28 15:47:07 +00:00
if ( loc ! = - 1 )
{
2012-11-26 18:58:24 +00:00
glslUniformLocation_t uniformLocation ;
uniformLocation . parmIndex = RENDERPARM_USER + i ;
uniformLocation . uniformIndex = loc ;
prog . uniformLocations . Append ( uniformLocation ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// sort the uniforms based on index
prog . uniformLocations . SortWithTemplate ( idSort_QuickUniforms ( ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// get the uniform buffer binding for skinning joint matrices
GLint blockIndex = qglGetUniformBlockIndex ( program , " matrices_ubo " ) ;
2012-11-28 15:47:07 +00:00
if ( blockIndex ! = - 1 )
{
2012-11-26 18:58:24 +00:00
qglUniformBlockBinding ( program , blockIndex , 0 ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the texture unit locations once for the render program. We only need to do this once since we only link the program once
qglUseProgram ( program ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < MAX_PROG_TEXTURE_PARMS ; + + i )
{
2012-11-26 18:58:24 +00:00
GLint loc = qglGetUniformLocation ( program , va ( " samp%d " , i ) ) ;
2012-11-28 15:47:07 +00:00
if ( loc ! = - 1 )
{
2012-11-26 18:58:24 +00:00
qglUniform1i ( loc , i ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idStr programName = vertexShaders [ vertexShaderIndex ] . name ;
programName . StripFileExtension ( ) ;
prog . name = programName ;
prog . progId = program ;
prog . fragmentShaderIndex = fragmentShaderIndex ;
prog . vertexShaderIndex = vertexShaderIndex ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idRenderProgManager : : ZeroUniforms
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idRenderProgManager : : ZeroUniforms ( )
{
2012-11-26 18:58:24 +00:00
memset ( glslUniforms . Ptr ( ) , 0 , glslUniforms . Allocated ( ) ) ;
}