public Material CreateAsMaterial( int lightmapNumber )
{
string materialName = String.Format( "{0}#{1}", Name, lightmapNumber );
string groupName = ResourceGroupManager.Instance.WorldResourceGroupName;
Material material = (Material)MaterialManager.Instance.Create( materialName, groupName );
Pass pass = material.GetTechnique( 0 ).GetPass( 0 );
LogManager.Instance.Write( "Using Q3 shader {0}", Name );
for ( int p = 0; p < _pass.Count; ++p )
{
TextureUnitState t;
// Create basic texture
if ( _pass[ p ].textureName == "$lightmap" )
{
string lightmapName = String.Format( "@lightmap{0}", lightmapNumber );
t = pass.CreateTextureUnitState( lightmapName );
}
// Animated texture support
else if ( _pass[ p ].animNumFrames > 0 )
{
float sequenceTime = _pass[ p ].animNumFrames / _pass[ p ].animFps;
/* Pre-load textures
We need to know if each one was loaded OK since extensions may change for each
Quake3 can still include alternate extension filenames e.g. jpg instead of tga
Pain in the arse - have to check for each frame as letters<n>.tga for example
is different per frame!
*/
for ( uint alt = 0; alt < _pass[ p ].animNumFrames; ++alt )
{
if ( !ResourceGroupManager.Instance.ResourceExists( groupName, _pass[ p ].frames[ alt ] ) )
{
// Try alternate extension
_pass[ p ].frames[ alt ] = GetAlternateName( _pass[ p ].frames[ alt ] );
if ( !ResourceGroupManager.Instance.ResourceExists( groupName, _pass[ p ].frames[ alt ] ) )
{
// stuffed - no texture
continue;
}
}
}
t = pass.CreateTextureUnitState( "" );
t.SetAnimatedTextureName( _pass[ p ].frames, _pass[ p ].animNumFrames, sequenceTime );
if ( t.IsBlank )
{
for ( int alt = 0; alt < _pass[ p ].animNumFrames; alt++ )
_pass[ p ].frames[ alt ] = GetAlternateName( _pass[ p ].frames[ alt ] );
t.SetAnimatedTextureName( _pass[ p ].frames, _pass[ p ].animNumFrames, sequenceTime );
}
}
else
{
// Quake3 can still include alternate extension filenames e.g. jpg instead of tga
// Pain in the arse - have to check for failure
if ( !ResourceGroupManager.Instance.ResourceExists( groupName, _pass[ p ].textureName ) )
{
// Try alternate extension
_pass[ p ].textureName = GetAlternateName( _pass[ p ].textureName );
if ( !ResourceGroupManager.Instance.ResourceExists( groupName, _pass[ p ].textureName ) )
{
// stuffed - no texture
continue;
}
}
t = pass.CreateTextureUnitState( _pass[ p ].textureName );
}
// Blending
if ( p == 0 )
{
// scene blend
material.SetSceneBlending( _pass[ p ].blendSrc, _pass[ p ].blendDest );
if ( material.IsTransparent && ( _pass[ p ].blendSrc != SceneBlendFactor.SourceAlpha ) )
material.DepthWrite = false;
t.SetColorOperation( LayerBlendOperation.Replace );
// Alpha Settings
pass.SetAlphaRejectSettings( _pass[ p ].alphaFunc, _pass[ p ].alphaVal );
}
else
{
if ( _pass[ p ].customBlend )
{
// Fallback for now
t.SetColorOperation( LayerBlendOperation.Modulate );
}
else
{
t.SetColorOperation( _pass[ p ].blend );
}
// Alpha mode, prefer 'most alphary'
CompareFunction currFunc = pass.AlphaRejectFunction;
int currValue = pass.AlphaRejectValue;
if ( _pass[ p ].alphaFunc > currFunc
|| ( _pass[ p ].alphaFunc == currFunc && _pass[ p ].alphaVal < currValue ) )
{
pass.SetAlphaRejectSettings( _pass[ p ].alphaFunc, _pass[ p ].alphaVal );
}
}
// Tex coords
if ( _pass[ p ].texGen == ShaderTextureGen.Base )
t.TextureCoordSet = 0;
else if ( _pass[ p ].texGen == ShaderTextureGen.Lightmap )
t.TextureCoordSet = 1;
else if ( _pass[ p ].texGen == ShaderTextureGen.Environment )
t.SetEnvironmentMap( true, EnvironmentMap.Planar );
// Tex mod
// Scale
t.SetTextureScaleU( _pass[ p ].tcModScale[ 0 ] );
t.SetTextureScaleV( _pass[ p ].tcModScale[ 1 ] );
// Procedural mods
// Custom - don't use mod if generating environment
// Because I do env a different way it look horrible
if ( _pass[ p ].texGen != ShaderTextureGen.Environment )
{
if ( _pass[ p ].tcModRotate != 0.0f )
t.SetRotateAnimation( _pass[ p ].tcModRotate );
if ( ( _pass[ p ].tcModScroll[ 0 ] != 0.0f ) || ( _pass[ p ].tcModScroll[ 1 ] != 0.0f ) )
{
if ( _pass[ p ].tcModTurbOn )
{
// Turbulent scroll
if ( _pass[ p ].tcModScroll[ 0 ] != 0.0f )
{
t.SetTransformAnimation( TextureTransform.TranslateU, WaveformType.Sine,
_pass[ p ].tcModTurb[ 0 ], _pass[ p ].tcModTurb[ 3 ], _pass[ p ].tcModTurb[ 2 ], _pass[ p ].tcModTurb[ 1 ] );
}
if ( _pass[ p ].tcModScroll[ 1 ] != 0.0f )
{
t.SetTransformAnimation( TextureTransform.TranslateV, WaveformType.Sine,
_pass[ p ].tcModTurb[ 0 ], _pass[ p ].tcModTurb[ 3 ], _pass[ p ].tcModTurb[ 2 ], _pass[ p ].tcModTurb[ 1 ] );
}
}
else
{
// Constant scroll
t.SetScrollAnimation( _pass[ p ].tcModScroll[ 0 ], _pass[ p ].tcModScroll[ 1 ] );
}
}
if ( _pass[ p ].tcModStretchWave != ShaderWaveType.None )
{
WaveformType wft = WaveformType.Sine;
switch ( _pass[ p ].tcModStretchWave )
{
case ShaderWaveType.Sin:
wft = WaveformType.Sine;
break;
case ShaderWaveType.Triangle:
wft = WaveformType.Triangle;
break;
case ShaderWaveType.Square:
wft = WaveformType.Square;
break;
case ShaderWaveType.SawTooth:
wft = WaveformType.Sawtooth;
break;
case ShaderWaveType.InverseSawtooth:
wft = WaveformType.InverseSawtooth;
break;
}
// Create wave-based stretcher
t.SetTransformAnimation( TextureTransform.ScaleU, wft, _pass[ p ].tcModStretchParams[ 3 ],
_pass[ p ].tcModStretchParams[ 0 ], _pass[ p ].tcModStretchParams[ 2 ], _pass[ p ].tcModStretchParams[ 1 ] );
t.SetTransformAnimation( TextureTransform.ScaleV, wft, _pass[ p ].tcModStretchParams[ 3 ],
_pass[ p ].tcModStretchParams[ 0 ], _pass[ p ].tcModStretchParams[ 2 ], _pass[ p ].tcModStretchParams[ 1 ] );
}
}
// Address mode
t.SetTextureAddressingMode( _pass[ p ].addressMode );
}
// Do farbox (create new material)
// Do skydome (use this material)
//if ( _skyDome )
//{
// float halfAngle = 0.5f * ( 0.5f * ( 4.0f * (float)System.Math.Atan( 1.0f ) ) );
// float sin = (float)Utility.Sin( halfAngle );
// // Quake3 is always aligned with Z upwards
// Quaternion q = new Quaternion(
// (float)Utility.Cos( halfAngle ),
// sin * Vector3.UnitX.x,
// sin * Vector3.UnitY.y,
// sin * Vector3.UnitX.z
// );
// // Also draw last, and make close to camera (far clip plane is shorter)
// sm.SetSkyDome( true, materialName, 20 - ( _cloudHeight / 256 * 18 ), 12, 2000, false, q );
//}
material.CullingMode = Axiom.Graphics.CullingMode.None;
material.ManualCullingMode = _cullingMode;
material.Lighting = false;
material.Load();
return material;
}
#endregion Methods