2012-05-29 13:31:11 +00:00
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "stdafx.h"
# include "export_nel.h"
# include "../tile_utility/tile_utility.h"
# include "nel/3d/texture_file.h"
# include "nel/3d/texture_multi_file.h"
# include "nel/3d/texture_cube.h"
# include "nel/3d/tangent_space_build.h"
# include "nel/3d/meshvp_per_pixel_light.h"
# include <vector>
# include <string>
using namespace NLMISC ;
using namespace NL3D ;
using namespace std ;
// Name of animatable values
# define BMTEX_CROP_APPLY "apply"
# define BMTEX_CROP_U_NAME "clipu"
# define BMTEX_CROP_V_NAME "clipv"
# define BMTEX_CROP_W_NAME "clipw"
# define BMTEX_CROP_H_NAME "cliph"
# define MAT_SLOTS 4
# define SHADER_NORMAL 1
# define SHADER_BUMP 2
# define SHADER_USER_COLOR 3
# define SHADER_LIGHTMAP 4
# define SHADER_SPECULAR 5
# define SHADER_WATER 6
# define SHADER_PER_PIXEL_LIGHTING 7
# define SHADER_PER_PIXEL_LIGHTING_NO_SPEC 8
# define NEL_BITMAP_TEXTURE_CLASS_ID_A 0x5a8003f9
# define NEL_BITMAP_TEXTURE_CLASS_ID_B 0x43e0955
/** Test wether the given max material is a water material. A water object should only have one material, and must have planar, convex geometry.
* Morevover , the mapping should only have scale and offsets , no rotation
*/
bool CExportNel : : hasWaterMaterial ( INode & node , TimeValue time )
{
// Get primary material pointer of the node
Mtl * pNodeMat = node . GetMtl ( ) ;
// If NULL, no material at all at this node
if ( pNodeMat = = NULL ) return false ;
if ( pNodeMat - > NumSubMtls ( ) ! = 0 ) return 0 ; // subMaterials not supported for water
int bWater = 0 ; // false
CExportNel : : getValueByNameUsingParamBlock2 ( * pNodeMat , " bWater " , ( ParamType2 ) TYPE_BOOL , & bWater , time ) ;
return bWater ! = 0 ;
}
///===================================================================================================
bool CExportNel : : hasMaterialWithShaderForVP ( INode & node , TimeValue time , NL3D : : CMaterial : : TShader & shader )
{
// Get primary material pointer of the node
Mtl * pNodeMat = node . GetMtl ( ) ;
// If NULL, no material at all at this node
if ( pNodeMat = = NULL ) return false ;
return CExportNel : : needVP ( * pNodeMat , time , shader ) ;
}
///===================================================================================================
bool CExportNel : : needVP ( Mtl & mat , TimeValue time , NL3D : : CMaterial : : TShader & shader )
{
if ( mat . NumSubMtls ( ) ! = 0 ) // look at sub materials
{
for ( uint k = 0 ; k < ( uint ) mat . NumSubMtls ( ) ; + + k )
{
if ( CExportNel : : needVP ( * ( mat . GetSubMtl ( k ) ) , time , shader ) ) return true ;
}
return false ;
}
int shaderType = 0 ; // false
CExportNel : : getValueByNameUsingParamBlock2 ( mat , " iShaderType " , ( ParamType2 ) TYPE_INT , & shaderType , time ) ;
switch ( shaderType )
{
case 7 : // per pixel lighting (shader 7) need a specific VP
shader = CMaterial : : PerPixelLighting ;
return true ;
break ;
case 8 : // per pixel lighting, no specular
shader = CMaterial : : PerPixelLightingNoSpec ;
return true ;
break ;
default :
return false ;
break ;
}
}
///===================================================================================================
/// Build a per-pixel vertex program
static NL3D : : CMeshVPPerPixelLight * BuildPerPixelLightingVP ( NL3D : : CMesh : : CMeshBuild * mb , bool wantSpecular )
{
// We need at least one texture set to be able to build the tangent space information.
// In this version, we support only one texture coordinate for the input. If there are more the result is undefined.
NL3D : : CMesh : : CMeshBuild otherMb ;
if ( NL3D : : BuildTangentSpace ( otherMb , * mb ) ) // build succesful ?
{
* mb = otherMb ;
CMeshVPPerPixelLight * vp = new CMeshVPPerPixelLight ;
vp - > SpecularLighting = wantSpecular ;
return vp ;
}
else
{
return NULL ;
}
return NULL ;
}
///===================================================================================================
IMeshVertexProgram * CExportNel : : buildMeshMaterialShaderVP ( NL3D : : CMaterial : : TShader shader , NL3D : : CMesh : : CMeshBuild * mb )
{
nlassert ( shader < CMaterial : : shaderCount ) ;
switch ( shader )
{
case CMaterial : : PerPixelLighting :
return BuildPerPixelLightingVP ( mb , true /* with specular */ ) ;
break ;
case CMaterial : : PerPixelLightingNoSpec :
return BuildPerPixelLightingVP ( mb , false /* no spec */ ) ;
break ;
default : return NULL ; // no need for a vp
}
}
// Build an array of NeL material corresponding with max material at this node. Return the number of material exported.
// Fill an array to remap the 3ds vertexMap channels for each materials. maxBaseBuild.RemapChannel.size() must be == to materials.size().
// maxBaseBuild.RemapChannel[mat].size() is the final count of NeL vertexMap channels used for the material nb mat.
// For each NeL channel of a material, copy the 3ds channel maxBaseBuild.RemapChannel[nelChannel]._IndexInMaxMaterial using the transformation matrix
// maxBaseBuild.RemapChannel[nelChannel]._UVMatrix.
// maxBaseBuild.NeedVertexColor will be true if at least one material need vertex color. Forced to true if lightmaps are used.
// maxBaseBuild.AlphaVertex[mat] will be true if the material use per vertex alpha.
// maxBaseBuild.AlphaVertexChannel[mat] will be the channel to use to get the alpha if the material use per vertex alpha.
// This method append the node material to the vector passed.
void CExportNel : : buildMaterials ( std : : vector < NL3D : : CMaterial > & materials , CMaxMeshBaseBuild & maxBaseBuild , INode & node ,
TimeValue time )
{
// Material count
maxBaseBuild . FirstMaterial = materials . size ( ) ;
int nMaterialCount = 0 ;
// Get primary material pointer of the node
Mtl * pNodeMat = node . GetMtl ( ) ;
// If NULL, no material at all at this node
if ( pNodeMat ! = NULL )
{
// Number of sub material at in this material
nMaterialCount = pNodeMat - > NumSubMtls ( ) ;
// If it is a multisub object, export all its sub materials
if ( nMaterialCount > 0 )
{
// Resize the destination array
materials . resize ( materials . size ( ) + nMaterialCount ) ;
// Resize the vertMap remap table
maxBaseBuild . MaterialInfo . resize ( nMaterialCount ) ;
// Export all the sub materials
for ( int nSub = 0 ; nSub < nMaterialCount ; nSub + + )
{
// Get a pointer on the sub material
Mtl * pSub = pNodeMat - > GetSubMtl ( nSub ) ;
// Should not be NULL
nlassert ( pSub ) ;
// Export it
buildAMaterial ( materials [ maxBaseBuild . FirstMaterial + nSub ] , maxBaseBuild . MaterialInfo [ nSub ] , * pSub , time ) ;
// Need vertex color ?
maxBaseBuild . NeedVertexColor | = maxBaseBuild . MaterialInfo [ nSub ] . AlphaVertex | maxBaseBuild . MaterialInfo [ nSub ] . ColorVertex ;
}
}
// Else export only this material, so, count is 1
else
{
// Only one material
nMaterialCount = 1 ;
// Resize the destination array
materials . resize ( materials . size ( ) + 1 ) ;
// Resize the vertMap remap table
maxBaseBuild . MaterialInfo . resize ( 1 ) ;
// Export the main material
buildAMaterial ( materials [ maxBaseBuild . FirstMaterial ] , maxBaseBuild . MaterialInfo [ 0 ] , * pNodeMat , time ) ;
// Need vertex color ?
maxBaseBuild . NeedVertexColor | = maxBaseBuild . MaterialInfo [ 0 ] . AlphaVertex | maxBaseBuild . MaterialInfo [ 0 ] . ColorVertex ;
}
}
// Normalize UVRouting
uint i ;
for ( i = 0 ; i < maxBaseBuild . MaterialInfo . size ( ) ; i + + )
{
uint j ;
for ( j = 0 ; j < MAX_MAX_TEXTURE ; j + + )
{
uint8 routing = maxBaseBuild . MaterialInfo [ i ] . UVRouting [ j ] ;
if ( maxBaseBuild . UVRouting [ j ] = = 0xff )
{
maxBaseBuild . UVRouting [ j ] = routing ;
}
else
{
if ( routing ! = 0xff )
{
if ( routing ! = maxBaseBuild . UVRouting [ j ] )
{
// Active the channel because someone need it
maxBaseBuild . UVRouting [ j ] = j ;
}
}
}
}
}
// If no material exported
if ( nMaterialCount = = 0 )
{
// Insert at least a material
materials . resize ( materials . size ( ) + 1 ) ;
nMaterialCount = 1 ;
// Resize the vertMap remap table
maxBaseBuild . MaterialInfo . resize ( 1 ) ;
// Init the first material
materials [ maxBaseBuild . FirstMaterial ] . initLighted ( ) ;
// Default mat
materials [ maxBaseBuild . FirstMaterial ] . setLighting ( true , CRGBA : : Black , CRGBA : : White , CRGBA : : White , CRGBA : : Black ) ;
// Export the main material
maxBaseBuild . MaterialInfo [ 0 ] . MaterialName = " Default " ;
}
// Return the count of material
maxBaseBuild . NumMaterials = nMaterialCount ;
}
// Build a NeL material corresponding with a max material.
void CExportNel : : buildAMaterial ( NL3D : : CMaterial & material , CMaxMaterialInfo & materialInfo , Mtl & mtl , TimeValue time )
{
// It is a NeL material ?
if ( isClassIdCompatible ( mtl , Class_ID ( NEL_MTL_A , NEL_MTL_B ) ) )
{
// Get the shader value now
int iShaderType = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " iShaderType " , ( ParamType2 ) TYPE_INT , & iShaderType , time ) ;
// Carefule with options
if ( ( iShaderType = = SHADER_LIGHTMAP ) & & ( ! _Options . bExportLighting ) )
iShaderType = SHADER_NORMAL ;
// Water or lightmap ??
bool isWaterOrLightmap = iShaderType = = SHADER_WATER | | iShaderType = = SHADER_LIGHTMAP ;
bool isLightmap = iShaderType = = SHADER_LIGHTMAP ;
// *** Init lighted or unlighted ?
// Get unlighted flag
int bUnlighted = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bUnlighted " , ( ParamType2 ) TYPE_BOOL , & bUnlighted , 0 ) ;
// force unlighted in case of lightmap.
if ( isLightmap )
bUnlighted = 1 ;
// Init the material
if ( bUnlighted )
material . initUnlit ( ) ;
else
material . initLighted ( ) ;
// *** Choose a shader
switch ( iShaderType )
{
case SHADER_NORMAL :
case SHADER_BUMP :
case SHADER_USER_COLOR :
case SHADER_LIGHTMAP :
case SHADER_SPECULAR :
case SHADER_PER_PIXEL_LIGHTING :
case SHADER_PER_PIXEL_LIGHTING_NO_SPEC :
material . setShader ( ( CMaterial : : TShader ) ( iShaderType - 1 ) ) ;
break ;
case SHADER_WATER :
material . setShader ( CMaterial : : Normal ) ;
break ;
default :
nlassert ( 0 ) ;
break ;
}
// Stain glass window flag
int bStainGlass = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bStainedGlassWindow " , ( ParamType2 ) TYPE_BOOL , & bStainGlass , time ) ;
material . setStainedGlassWindow ( bStainGlass ! = 0 ) ;
// *** Alpha
// Alpha blend ?
int bAlphaBlend = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bAlphaBlend " , ( ParamType2 ) TYPE_BOOL , & bAlphaBlend , time ) ;
// Set the blend
material . setBlend ( bAlphaBlend ! = 0 ) ;
// Blend function
int blendFunc = 1 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " iBlendSrcFunc " , ( ParamType2 ) TYPE_INT , & blendFunc , time ) ;
material . setSrcBlend ( ( CMaterial : : TBlend ) ( blendFunc - 1 ) ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " iBlendDestFunc " , ( ParamType2 ) TYPE_INT , & blendFunc , time ) ;
material . setDstBlend ( ( CMaterial : : TBlend ) ( blendFunc - 1 ) ) ;
// if water or lightMap, force std blend.
if ( isWaterOrLightmap )
material . setBlendFunc ( CMaterial : : srcalpha , CMaterial : : invsrcalpha ) ;
// Set the alpha test flag
int bAlphaTest = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bAlphaTest " , ( ParamType2 ) TYPE_BOOL , & bAlphaTest , time ) ;
material . setAlphaTest ( bAlphaTest ! = 0 ) ;
// Vertex alpha
int bAlphaVertex = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bAlphaVertex " , ( ParamType2 ) TYPE_BOOL , & bAlphaVertex , time ) ;
// if water or lightMap, disable alphaVertex
if ( isWaterOrLightmap )
bAlphaVertex = 0 ;
// Active vertex alpha if in alpha test or alpha blend mode
materialInfo . AlphaVertex = ( bAlphaBlend | | bAlphaTest ) & & ( bAlphaVertex ! = 0 ) ;
// Get channel to use for alpha vertex
materialInfo . AlphaVertexChannel = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " iAlphaVertexChannel " , ( ParamType2 ) TYPE_INT , & materialInfo . AlphaVertexChannel , time ) ;
// *** Zbuffer
// ZBias
float zBias = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " fZBias " , ( ParamType2 ) TYPE_FLOAT , & zBias , time ) ;
material . setZBias ( zBias ) ;
// Alpha blend ?
if ( bAlphaBlend )
{
// Force z write ?
int bForceZWrite = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bForceZWrite " , ( ParamType2 ) TYPE_BOOL , & bForceZWrite , time ) ;
material . setZWrite ( bForceZWrite ! = 0 ) ;
}
else
{
// Force no z write ?
int bForceNoZWrite = 0 ; // false
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bForceNoZWrite " , ( ParamType2 ) TYPE_BOOL , & bForceNoZWrite , time ) ;
material . setZWrite ( bForceNoZWrite = = 0 ) ;
}
// *** Colors
// * Vertex color ?
int bColorVertex = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bColorVertex " , ( ParamType2 ) TYPE_BOOL , & bColorVertex , time ) ;
material . setLightedVertexColor ( material . isLighted ( ) & & ( bColorVertex ! = 0 ) ) ;
// Ok, color vertex
materialInfo . ColorVertex = bColorVertex ! = 0 ;
// * Diffuse
// Get from max
Point3 maxDiffuse ;
CRGBA nelDiffuse ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " cDiffuse " , ( ParamType2 ) TYPE_RGBA , & maxDiffuse , time )
| | CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " diffuse " , ( ParamType2 ) TYPE_RGBA , & maxDiffuse , time ) ;
// Convert to NeL color
convertColor ( nelDiffuse , maxDiffuse ) ;
// Set the opacity
float fOp = 0.0f ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " pOpacity " , ( ParamType2 ) TYPE_PCNT_FRAC , & fOp , time )
| | CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " opacity " , ( ParamType2 ) TYPE_PCNT_FRAC , & fOp , time ) ;
// Add alpha to the value
float fA = ( fOp * 255.f + 0.5f ) ;
clamp ( fA , 0.f , 255.f ) ;
nelDiffuse . A = ( uint8 ) fA ;
// Set le NeL diffuse color material
if ( bUnlighted )
{
material . setColor ( nelDiffuse ) ;
// For the lightmap
material . setDiffuse ( nelDiffuse ) ;
}
else
{
material . setDiffuse ( nelDiffuse ) ;
material . setOpacity ( nelDiffuse . A ) ;
}
// * Self illum color
CRGBA nelEmissive ;
int bSelfIllumColorOn ;
Point3 maxSelfIllum ;
float fTemp ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bUseSelfIllumColor " , ( ParamType2 ) TYPE_BOOL , & bSelfIllumColorOn , time )
| | CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " useSelfIllumColor " , ( ParamType2 ) TYPE_BOOL , & bSelfIllumColorOn , time ) ;
if ( bSelfIllumColorOn )
{
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " cSelfIllumColor " , ( ParamType2 ) TYPE_RGBA , & maxSelfIllum , time )
| | CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " selfIllumColor " , ( ParamType2 ) TYPE_RGBA , & maxSelfIllum , time ) ;
}
else
{
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " pSelfIllumAmount " , ( ParamType2 ) TYPE_PCNT_FRAC , & fTemp , time )
| | CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " selfIllumAmount " , ( ParamType2 ) TYPE_PCNT_FRAC , & fTemp , time ) ;
maxSelfIllum = maxDiffuse * fTemp ;
}
convertColor ( nelEmissive , maxSelfIllum ) ;
material . setEmissive ( nelEmissive ) ;
// * Ambient
CRGBA nelAmbient ;
Point3 maxAmbient ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " cAmbient " , ( ParamType2 ) TYPE_RGBA , & maxAmbient , time )
| | CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " ambient " , ( ParamType2 ) TYPE_RGBA , & maxAmbient , time ) ;
convertColor ( nelAmbient , maxAmbient ) ;
material . setAmbient ( nelAmbient ) ;
// * Specular
CRGBA nelSpecular ;
Point3 maxSpecular ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " cSpecular " , ( ParamType2 ) TYPE_RGBA , & maxSpecular , time )
| | CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " specular " , ( ParamType2 ) TYPE_RGBA , & maxSpecular , time ) ;
convertColor ( nelSpecular , maxSpecular ) ;
// Get specular level
float shininess ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " pSpecularLevel " , ( ParamType2 ) TYPE_PCNT_FRAC , & shininess , time )
| | CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " specularLevel " , ( ParamType2 ) TYPE_PCNT_FRAC , & shininess , time ) ;
clamp ( shininess , 0.f , 1.f ) ;
CRGBAF fColor = nelSpecular ;
fColor * = shininess ;
nelSpecular = fColor ;
material . setSpecular ( nelSpecular ) ;
// * Get specular shininess
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " pGlossiness " , ( ParamType2 ) TYPE_PCNT_FRAC , & shininess , time )
| | CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " glossiness " , ( ParamType2 ) TYPE_PCNT_FRAC , & shininess , time ) ;
shininess = ( float ) pow ( 2.0 , shininess * 10.0 ) * 4.f ;
material . setShininess ( shininess ) ;
// * Usercolor
if ( iShaderType = = SHADER_USER_COLOR )
{
CRGBA nelUserColor ;
Point3 maxUserColor ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " cUserColor " , ( ParamType2 ) TYPE_RGBA , & maxUserColor , time ) ;
convertColor ( nelUserColor , maxUserColor ) ;
material . setUserColor ( nelUserColor ) ;
}
// * Double sided flag
int bDoubleSided ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bTwoSided " , ( ParamType2 ) TYPE_BOOL , & bDoubleSided , time )
| | CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " twoSided " , ( ParamType2 ) TYPE_BOOL , & bDoubleSided , time ) ;
material . setDoubleSided ( bDoubleSided ! = 0 ) ;
// *** Textures
/// test wether texture matrix animation should be exported
int bExportTexMatAnim = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bExportTextureMatrix " , ( ParamType2 ) TYPE_BOOL , & bExportTexMatAnim , 0 ) ;
materialInfo . TextureMatrixEnabled = ( bExportTexMatAnim ! = 0 ) ;
// Reset info
materialInfo . RemapChannel . clear ( ) ;
// For each textures
uint i ;
for ( i = 0 ; i < IDRV_MAT_MAXTEXTURES ; i + + )
{
// Lightmap, only one texture
if ( ( iShaderType = = SHADER_USER_COLOR ) & & ( i > 0 ) ) break ;
if ( ( iShaderType = = SHADER_LIGHTMAP ) & & ( i > 0 ) ) break ;
if ( ( iShaderType = = SHADER_SPECULAR ) & & ( i > 1 ) ) break ;
// Get the enable flag name
char enableSlotName [ 100 ] ;
smprintf ( enableSlotName , 100 , " bEnableSlot_%d " , i + 1 ) ;
// Get the enable flag
int bEnableSlot = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , enableSlotName , ( ParamType2 ) TYPE_BOOL , & bEnableSlot , time ) ;
if ( bEnableSlot )
{
// Get the texture arg name
char textureName [ 100 ] ;
smprintf ( textureName , 100 , " tTexture_%d " , i + 1 ) ;
// Get the texture pointer
Texmap * pTexmap = NULL ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , textureName , ( ParamType2 ) TYPE_TEXMAP , & pTexmap , time ) ;
if ( pTexmap )
{
// Pointer on the diffuse texture
static ITexture * pTexture = NULL ;
// Ok export the texture in NeL format
CMaterialDesc materialDesc ;
pTexture = buildATexture ( * pTexmap , materialDesc , time , ( i = = 1 ) & & ( iShaderType = = SHADER_SPECULAR ) ) ;
// Get the gen texture coord flag
char texGenName [ 100 ] ;
smprintf ( texGenName , 100 , " bTexGen_%d " , i + 1 ) ;
int bTexGen = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , texGenName , ( ParamType2 ) TYPE_BOOL , & bTexGen , time ) ;
// If specular shader, set uv channel to reflexion
if ( ( ( i = = 1 ) & & ( iShaderType = = SHADER_SPECULAR ) ) | | bTexGen )
{
materialDesc . _IndexInMaxMaterial = UVGEN_REFLEXION ;
}
materialInfo . RemapChannel . push_back ( materialDesc ) ;
// Add flags if mapping coodinates are used..
if ( materialDesc . _IndexInMaxMaterial > = 0 )
{
uint j ;
for ( j = 0 ; j < i ; j + + )
{
// Same UV channel ?
if ( materialInfo . RemapChannel [ j ] . _IndexInMaxMaterial = = materialDesc . _IndexInMaxMaterial )
break ;
}
// Channel routing
materialInfo . UVRouting [ i ] = ( j = = i ) ? i : j ;
}
// Add the texture if it exist
material . setTexture ( i , pTexture ) ;
// Envmap gen ?
material . setTexCoordGen ( i , materialDesc . _IndexInMaxMaterial < 0 ) ;
/// texture matrix animation ?
if ( bExportTexMatAnim ! = 0 )
{
/// and activate flag
material . enableUserTexMat ( i ) ;
/// setup the uv matrix
CMatrix uvMat ;
CExportNel : : uvMatrix2NelUVMatrix ( materialDesc . getUVMatrix ( ) , uvMat ) ;
material . setUserTexMat ( i , uvMat ) ;
}
}
}
}
// Export mapping channel 2 if lightmap asked.
if ( iShaderType = = SHADER_LIGHTMAP ) // lightmap enabled ?
{
// Get the lightmap UV channel
int iLightMapChannel = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " iLightMapChannel " , ( ParamType2 ) TYPE_INT , & iLightMapChannel , time ) ;
// Resize it
uint size = materialInfo . RemapChannel . size ( ) ;
materialInfo . RemapChannel . resize ( size + 1 ) ;
// Copy information from channel 0
if ( materialInfo . RemapChannel . size ( ) > 1 )
materialInfo . RemapChannel [ size ] = materialInfo . RemapChannel [ 0 ] ;
// Source lightmap mapping channel
materialInfo . RemapChannel [ size ] . _IndexInMaxMaterial = iLightMapChannel ;
// Backup old mapping channel
materialInfo . RemapChannel [ size ] . _IndexInMaxMaterialAlternative = materialInfo . RemapChannel [ 0 ] . _IndexInMaxMaterial ;
}
// For each slot
uint stage ;
for ( stage = 0 ; stage < std : : min ( ( uint ) MAT_SLOTS , ( uint ) IDRV_MAT_MAXTEXTURES ) ; stage + + )
{
// Make a post fixe
char postfixC [ 10 ] ;
smprintf ( postfixC , 10 , " _%d " , stage + 1 ) ;
string postfix = postfixC ;
// Shader normal ?
if ( iShaderType = = SHADER_NORMAL )
{
// RGB, get the values
int opRGB = 0 ;
int opRGBBlend = 0 ;
int opRGBArg0 = 0 ;
int opRGBArg1 = 0 ;
int opRGBArg2 = 0 ;
int opRGBArg0Operand = 0 ;
int opRGBArg1Operand = 0 ;
int opRGBArg2Operand = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iRgbOperation " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opRGB , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iRgbBlendSource " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opRGBBlend , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iRgbArg0 " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opRGBArg0 , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iRgbArg1 " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opRGBArg1 , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iRgbArg2 " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opRGBArg2 , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iRgbArg0Operand " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opRGBArg0Operand , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iRgbArg1Operand " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opRGBArg1Operand , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iRgbArg2Operand " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opRGBArg2Operand , time ) ;
// Setup the value
if ( opRGB < 5 )
material . texEnvOpRGB ( stage , ( CMaterial : : TTexOperator ) ( opRGB - 1 ) ) ;
else
{
if ( opRGB = = 6 )
{
material . texEnvOpRGB ( stage , CMaterial : : Mad ) ;
}
else
{
material . texEnvOpRGB ( stage , ( CMaterial : : TTexOperator ) ( opRGBBlend + 3 ) ) ;
}
}
material . texEnvArg0RGB ( stage , ( CMaterial : : TTexSource ) ( opRGBArg0 - 1 ) , ( CMaterial : : TTexOperand ) ( opRGBArg0Operand - 1 ) ) ;
if ( opRGBArg1 = = 4 )
{
material . texEnvArg1RGB ( stage , CMaterial : : Texture , ( CMaterial : : TTexOperand ) ( opRGBArg1Operand - 1 ) ) ;
}
else
{
material . texEnvArg1RGB ( stage , ( CMaterial : : TTexSource ) ( opRGBArg1 ) , ( CMaterial : : TTexOperand ) ( opRGBArg1Operand - 1 ) ) ;
}
if ( opRGBArg2 = = 4 )
{
material . texEnvArg2RGB ( stage , CMaterial : : Texture , ( CMaterial : : TTexOperand ) ( opRGBArg2Operand - 1 ) ) ;
}
else
{
material . texEnvArg2RGB ( stage , ( CMaterial : : TTexSource ) ( opRGBArg2 ) , ( CMaterial : : TTexOperand ) ( opRGBArg2Operand - 1 ) ) ;
}
// Alpha, get the values
int opAlpha = 0 ;
int opAlphaBlend = 0 ;
int opAlphaArg0 = 0 ;
int opAlphaArg1 = 0 ;
int opAlphaArg2 = 0 ;
int opAlphaArg0Operand = 0 ;
int opAlphaArg1Operand = 0 ;
int opAlphaArg2Operand = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iAlphaOperation " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opAlpha , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iAlphaBlendSource " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opAlphaBlend , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iAlphaArg0 " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opAlphaArg0 , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iAlphaArg1 " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opAlphaArg1 , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iAlphaArg2 " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opAlphaArg2 , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iAlphaArg0Operand " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opAlphaArg0Operand , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iAlphaArg1Operand " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opAlphaArg1Operand , time ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iAlphaArg2Operand " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & opAlphaArg2Operand , time ) ;
// Setup the value
if ( opAlpha < 5 )
material . texEnvOpAlpha ( stage , ( CMaterial : : TTexOperator ) ( opAlpha - 1 ) ) ;
else
{
if ( opAlpha = = 6 )
{
material . texEnvOpAlpha ( stage , CMaterial : : Mad ) ;
}
else
{
material . texEnvOpAlpha ( stage , ( CMaterial : : TTexOperator ) ( opAlphaBlend + 3 ) ) ;
}
}
material . texEnvArg0Alpha ( stage , ( CMaterial : : TTexSource ) ( opAlphaArg0 - 1 ) , ( CMaterial : : TTexOperand ) ( opAlphaArg0Operand - 1 ) ) ;
if ( opAlphaArg1 = = 4 )
{
material . texEnvArg1Alpha ( stage , CMaterial : : Texture , ( CMaterial : : TTexOperand ) ( opAlphaArg1Operand - 1 ) ) ;
}
else
{
material . texEnvArg1Alpha ( stage , ( CMaterial : : TTexSource ) ( opAlphaArg1 ) , ( CMaterial : : TTexOperand ) ( opAlphaArg1Operand - 1 ) ) ;
}
if ( opAlphaArg2 = = 4 )
{
material . texEnvArg2Alpha ( stage , CMaterial : : Texture , ( CMaterial : : TTexOperand ) ( opAlphaArg2Operand - 1 ) ) ;
}
else
{
material . texEnvArg2Alpha ( stage , ( CMaterial : : TTexSource ) ( opAlphaArg2 ) , ( CMaterial : : TTexOperand ) ( opAlphaArg2Operand - 1 ) ) ;
}
// Constant color
Point3 constantColor ;
CRGBA nelConstantColor ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " cConstant " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_RGBA , & constantColor , time ) ;
// Convert to NeL color
convertColor ( nelConstantColor , constantColor ) ;
// Constant alpha
int constantAlpha = 255 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iConstantAlpha " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & constantAlpha , time ) ;
nelConstantColor . A = ( uint8 ) constantAlpha ;
// Setup the constant color
material . texConstantColor ( stage , nelConstantColor ) ;
// Texenv mode
int texEnvMode = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , ( " iTextureShader " + postfix ) . c_str ( ) , ( ParamType2 ) TYPE_INT , & texEnvMode , time ) ;
if ( texEnvMode > 1 )
{
// Enable and setup it
material . enableTexAddrMode ( ) ;
material . setTexAddressingMode ( stage , ( CMaterial : : TTexAddressingMode ) ( texEnvMode - 2 ) ) ;
}
}
}
// Set material name
TSTR name = mtl . GetName ( ) ;
materialInfo . MaterialName = ( const char * ) name ;
}
else
{
// Not a nel material, try to get something near...
// Init the material lighted
material . initLighted ( ) ;
// *** ***************
// *** Export Textures
// *** ***************
/// TODO: Only one texture for the time. Add multitexture support, and shaders support.
// Look for a diffuse texmap
vector < bool > mapEnables ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " mapEnables " , ( ParamType2 ) TYPE_BOOL_TAB , & mapEnables , time , false ) ;
Texmap * pDifTexmap = NULL ;
Texmap * pOpaTexmap = NULL ;
Texmap * pSpeTexmap = NULL ;
if ( mapEnables [ ID_DI ] )
pDifTexmap = mtl . GetSubTexmap ( ID_DI ) ;
if ( mapEnables [ ID_OP ] )
pOpaTexmap = mtl . GetSubTexmap ( ID_OP ) ;
if ( mapEnables [ ID_SP ] )
pSpeTexmap = mtl . GetSubTexmap ( ID_SP ) ;
// Is there a lightmap handling wanted
int bLightMap = 0 ; // false
int bAlphaTest = 1 ; // true
int bForceZWrite = 0 ; // false
int bForceNoZWrite = 0 ; // false
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bForceZWrite " , ( ParamType2 ) TYPE_BOOL , & bForceZWrite , time , false ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bForceNoZWrite " , ( ParamType2 ) TYPE_BOOL , & bForceNoZWrite , time , false ) ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bAlphaTest " , ( ParamType2 ) TYPE_BOOL , & bAlphaTest , time , false ) ;
if ( pSpeTexmap ! = NULL )
{
material . setShader ( CMaterial : : Specular ) ;
}
else
{
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bLightMap " , ( ParamType2 ) TYPE_BOOL , & bLightMap , time , false ) ;
if ( bLightMap )
{
material . setShader ( CMaterial : : LightMap ) ;
}
else
{
material . setShader ( CMaterial : : Normal ) ;
}
}
int bStainedGlassWindow = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bStainedGlassWindow " , ( ParamType2 ) TYPE_BOOL , & bStainedGlassWindow , time , false ) ;
material . setStainedGlassWindow ( bStainedGlassWindow ! = 0 ) ;
material . setAlphaTest ( false ) ;
// By default set blend to false
material . setBlend ( false ) ;
// Diffuse texmap is present ?
if ( pDifTexmap )
{
// Pointer on the diffuse texture
static ITexture * pTexture = NULL ;
// Is it a simple file ?
if ( isClassIdCompatible ( * pDifTexmap , Class_ID ( BMTEX_CLASS_ID , 0 ) )
| | isClassIdCompatible ( * pDifTexmap , Class_ID ( NEL_BITMAP_TEXTURE_CLASS_ID_A , NEL_BITMAP_TEXTURE_CLASS_ID_B ) )
)
{
// List of channels used by this texture
CMaterialDesc _3dsTexChannel ;
// Ok export the texture in NeL format
pTexture = buildATexture ( * pDifTexmap , _3dsTexChannel , time ) ;
// For this shader, only need a texture channel.
materialInfo . RemapChannel . resize ( 1 ) ;
// Need an explicit channel, not generated
if ( _3dsTexChannel . _IndexInMaxMaterial < 0 )
{
materialInfo . RemapChannel [ 0 ] . _IndexInMaxMaterial = UVGEN_MISSING ;
materialInfo . RemapChannel [ 0 ] . _UVMatrix . IdentityMatrix ( ) ;
}
// Else copy it
else
materialInfo . RemapChannel [ 0 ] = _3dsTexChannel ;
// Add the texture if it exist
material . setTexture ( 0 , pTexture ) ;
// Active blend if texture in opacity
if ( pOpaTexmap ! = NULL )
{
if ( bAlphaTest )
{ // If Alpha Test enabled no blend required just check if we are forced to NOT write in the ZBuffer
material . setAlphaTest ( true ) ;
if ( bForceNoZWrite )
material . setZWrite ( false ) ;
else
material . setZWrite ( true ) ;
}
else
{ // No Alpha Test so we have to blend and check if we are forced to write in the ZBuffer
material . setBlend ( true ) ;
if ( bForceZWrite )
material . setZWrite ( true ) ;
else
material . setZWrite ( false ) ;
}
}
// Add flags if mapping coodinates are used..
if ( _3dsTexChannel . _IndexInMaxMaterial > = 0 )
{
// Channel routing
materialInfo . UVRouting [ 0 ] = 0 ;
}
// Export mapping channel 2 if lightmap asked.
if ( bLightMap ) // lightmap enabled ?
{
materialInfo . RemapChannel . resize ( 2 ) ;
// Copy information from channel 0
materialInfo . RemapChannel [ 1 ] = materialInfo . RemapChannel [ 0 ] ;
materialInfo . RemapChannel [ 1 ] . _IndexInMaxMaterial = 2 ;
materialInfo . RemapChannel [ 1 ] . _IndexInMaxMaterialAlternative = materialInfo . RemapChannel [ 0 ] . _IndexInMaxMaterial ;
// Add flags if mapping coodinates are used..
materialInfo . UVRouting [ 1 ] | = 1 ;
}
}
}
if ( pSpeTexmap )
{
// Pointer to the specular reflection texture
CTextureCube * pTextureCube = NULL ;
if ( isClassIdCompatible ( * pSpeTexmap , Class_ID ( ACUBIC_CLASS_ID , 0 ) ) )
{
pTextureCube = buildTextureCubeFromReflectRefract ( * pSpeTexmap , time ) ;
}
else if ( isClassIdCompatible ( * pSpeTexmap , Class_ID ( COMPOSITE_CLASS_ID , 0 ) ) )
{
pTextureCube = buildTextureCubeFromComposite ( * pSpeTexmap , time ) ;
}
else if ( isClassIdCompatible ( * pSpeTexmap , Class_ID ( BMTEX_CLASS_ID , 0 ) ) )
{
pTextureCube = buildTextureCubeFromTexture ( * pSpeTexmap , time ) ;
}
// Add the texture if it exist
material . setTexture ( 1 , pTextureCube ) ;
}
// Blend mode
int opacityType = 0 ; // 0-filter 1-substractive 2-additive
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " opacityType " , ( ParamType2 ) TYPE_INT , & opacityType , time , false ) ;
if ( opacityType = = 0 ) // Filter
material . setBlendFunc ( CMaterial : : srcalpha , CMaterial : : invsrcalpha ) ;
else
material . setBlendFunc ( CMaterial : : srcalpha , CMaterial : : one ) ;
// Z function by default. TODO.
material . setZFunc ( CMaterial : : lessequal ) ;
// Z bias by default. TODO.
material . setZBias ( 0.f ) ;
// Is the mtl a std material ?
// The class Id can be the StdMat one, or StdMat2
// It can be the superClassId if the mtl is derived from StdMat or StdMat2.
if (
isClassIdCompatible ( mtl , Class_ID ( DMTL_CLASS_ID , 0 ) ) | |
isClassIdCompatible ( mtl , Class_ID ( DMTL2_CLASS_ID , 0 ) )
)
{
// Get a pointer on a stdmat
//StdMat2* stdmat=(StdMat2*)&mtl;
// *****************************************
// *** Colors, self illumination and opacity
// *****************************************
// Get the diffuse color of the max material
//Color color=stdmat->GetDiffuse (time);
Point3 maxDiffuse ;
CRGBA nelDiffuse ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " diffuse " , ( ParamType2 ) TYPE_RGBA , & maxDiffuse , time , false ) ;
// Convert to NeL color
convertColor ( nelDiffuse , maxDiffuse ) ;
// Get the opacity value from the material
// float fOp=stdmat->GetOpacity (time);
float fOp = 0.0f ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " opacity " , ( ParamType2 ) TYPE_PCNT_FRAC , & fOp , time , false ) ;
// Add alpha to the value
float fA = ( fOp * 255.f + 0.5f ) ;
clamp ( fA , 0.f , 255.f ) ;
nelDiffuse . A = ( uint8 ) fA ;
// Set le NeL diffuse color material
material . setColor ( nelDiffuse ) ;
// Set the blend mode on if opacity is not 1.f
if ( fOp < 0.99f )
{
if ( bAlphaTest )
{ // If Alpha Test enabled no blend required just check if we are forced to NOT write in the ZBuffer
material . setAlphaTest ( true ) ;
if ( bForceNoZWrite )
material . setZWrite ( false ) ;
else
material . setZWrite ( true ) ;
}
else
{ // No Alpha Test so we have to blend and check if we are forced to write in the ZBuffer
material . setBlend ( true ) ;
if ( bForceZWrite )
material . setZWrite ( true ) ;
else
material . setZWrite ( false ) ;
}
}
// Get colors of 3dsmax material
CRGBA nelEmissive ;
CRGBA nelAmbient ;
CRGBA nelSpecular ;
//if (stdmat->GetSelfIllumColorOn())
// convertColor (emissiveColor, stdmat->GetSelfIllumColor (time));
//else
// convertColor (emissiveColor, stdmat->GetDiffuse (time)*stdmat->GetSelfIllum (time));
int bSelfIllumColorOn ;
Point3 maxSelfIllum ;
float fTemp ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " useSelfIllumColor " , ( ParamType2 ) TYPE_BOOL , & bSelfIllumColorOn , time , false ) ;
if ( bSelfIllumColorOn )
{
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " selfIllumColor " , ( ParamType2 ) TYPE_RGBA , & maxSelfIllum , time , false ) ;
}
else
{
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " selfIllumAmount " , ( ParamType2 ) TYPE_PCNT_FRAC , & fTemp , time , false ) ;
maxSelfIllum = maxDiffuse * fTemp ;
}
convertColor ( nelEmissive , maxSelfIllum ) ;
Point3 maxAmbient ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " ambient " , ( ParamType2 ) TYPE_RGBA , & maxAmbient , time , false ) ;
convertColor ( nelAmbient , maxAmbient ) ;
Point3 maxSpecular ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " specular " , ( ParamType2 ) TYPE_RGBA , & maxSpecular , time , false ) ;
convertColor ( nelSpecular , maxSpecular ) ;
// Specular level
float shininess ; //=stdmat->GetShinStr(time);
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " specularLevel " , ( ParamType2 ) TYPE_PCNT_FRAC , & shininess , time , false ) ;
CRGBAF fColor = nelSpecular ;
fColor * = shininess ;
nelSpecular = fColor ;
// Shininess
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " glossiness " , ( ParamType2 ) TYPE_PCNT_FRAC , & shininess , time , false ) ;
//shininess=stdmat->GetShader()->GetGlossiness(time);
shininess = ( float ) pow ( 2.0 , shininess * 10.0 ) * 4.f ;
// Light parameters
material . setLighting ( true , nelEmissive , nelAmbient , nelDiffuse , nelSpecular , shininess ) ;
// Double sided
int bDoubleSided ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " twoSided " , ( ParamType2 ) TYPE_BOOL , & bDoubleSided , time , false ) ;
//material.setDoubleSided (stdmat->GetTwoSided()!=FALSE);
material . setDoubleSided ( bDoubleSided ! = 0 ) ;
}
if ( ! bLightMap )
{
int bUnlighted = 0 ; // false
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bUnlighted " , ( ParamType2 ) TYPE_BOOL , & bUnlighted , 0 , false ) ;
if ( bUnlighted )
{
material . setLighting ( false ) ;
}
}
// Use alpha vertex ?
int bAlphaVertex = 0 ; // false
// Get the scripted value
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bAlphaVertex " , ( ParamType2 ) TYPE_BOOL , & bAlphaVertex , time , false ) ;
// Find ?
if ( bAlphaVertex )
{
// Ok, alpha vertex
materialInfo . AlphaVertex = true ;
if ( bAlphaTest )
{
// If Alpha Test enabled no blend required just check if we are forced to NOT write in the ZBuffer
material . setAlphaTest ( true ) ;
if ( bForceNoZWrite )
material . setZWrite ( false ) ;
else
material . setZWrite ( true ) ;
}
else
{ // No Alpha Test so we have to blend and check if we are forced to write in the ZBuffer
material . setBlend ( true ) ;
if ( bForceZWrite )
material . setZWrite ( true ) ;
else
material . setZWrite ( false ) ;
}
// Get the channel for alpha vertex
materialInfo . AlphaVertexChannel = 0 ;
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " iAlphaVertexChannel " , ( ParamType2 ) TYPE_INT , & materialInfo . AlphaVertexChannel , time , false ) ;
}
// Use color vertex ?
int bColorVertex = 0 ; // false
// Get the scripted value
CExportNel : : getValueByNameUsingParamBlock2 ( mtl , " bColorVertex " , ( ParamType2 ) TYPE_BOOL , & bColorVertex , time , false ) ;
// Find ?
if ( bColorVertex )
{
// Ok, color vertex
materialInfo . ColorVertex = true ;
// Active vertex color in lighted mode
material . setLightedVertexColor ( material . isLighted ( ) ) ;
}
// Set material name
TSTR name = mtl . GetName ( ) ;
materialInfo . MaterialName = ( const char * ) name ;
}
}
// Get 3ds channels uv used by a texmap and make a good index channel
int CExportNel : : getVertMapChannel ( Texmap & texmap , Matrix3 & channelMatrix , TimeValue time )
{
// *** Get the channel matrix
// Set to identity because deafult implementation of texmapGetUVTransform make nothing
channelMatrix . IdentityMatrix ( ) ;
// Get UV channel matrix
texmap . GetUVTransform ( channelMatrix ) ;
// Return the map channel
return texmap . GetMapChannel ( ) ;
}
// get the absolute or relative path from a texture filename
static std : : string ConvertTexFileName ( const char * src , bool _AbsolutePath )
{
// File name, maxlen 256 under windows
char sFileName [ 512 ] ;
strcpy ( sFileName , src ) ;
// Let absolute path ?
if ( ! _AbsolutePath )
{
// Decompose bitmap file name
char sName [ 256 ] ;
char sExt [ 256 ] ;
_splitpath ( sFileName , NULL , NULL , sName , sExt ) ;
// Make the final path
_makepath ( sFileName , NULL , NULL , sName , sExt ) ;
}
return std : : string ( sFileName ) ;
}
// Build a NeL texture corresponding with a max Texmap.
// Fill an array with the 3ds vertexMap used by this texture.
// Texture file uses only 1 channel.
ITexture * CExportNel : : buildATexture ( Texmap & texmap , CMaterialDesc & remap3dsTexChannel , TimeValue time , bool forceCubic )
{
/// TODO: support other texmap than Bitmap
// By default, not build
ITexture * pTexture = NULL ;
// Is it a bitmap texture file ?
if ( isClassIdCompatible ( texmap , Class_ID ( BMTEX_CLASS_ID , 0 ) )
| | isClassIdCompatible ( texmap , Class_ID ( NEL_BITMAP_TEXTURE_CLASS_ID_A , NEL_BITMAP_TEXTURE_CLASS_ID_B ) )
)
{
// Cast the pointer
BitmapTex * pBitmap = ( BitmapTex * ) & texmap ;
// Get the apply crop value
int bApply ;
bool bRes = getValueByNameUsingParamBlock2 ( texmap , BMTEX_CROP_APPLY , ( ParamType2 ) TYPE_BOOL , & bApply , time ) ;
nlassert ( bRes ) ;
// If a crop is applyed
if ( bApply )
{
// Get the crop value U
bRes = getValueByNameUsingParamBlock2 ( texmap , BMTEX_CROP_U_NAME , ( ParamType2 ) TYPE_FLOAT , & ( remap3dsTexChannel . _CropU ) , time ) ;
nlassert ( bRes ) ;
// Get the crop value V
bRes = getValueByNameUsingParamBlock2 ( texmap , BMTEX_CROP_V_NAME , ( ParamType2 ) TYPE_FLOAT , & ( remap3dsTexChannel . _CropV ) , time ) ;
nlassert ( bRes ) ;
// Get the crop value W
bRes = getValueByNameUsingParamBlock2 ( texmap , BMTEX_CROP_W_NAME , ( ParamType2 ) TYPE_FLOAT , & ( remap3dsTexChannel . _CropW ) , time ) ;
nlassert ( bRes ) ;
// Get the crop value H
bRes = getValueByNameUsingParamBlock2 ( texmap , BMTEX_CROP_H_NAME , ( ParamType2 ) TYPE_FLOAT , & ( remap3dsTexChannel . _CropH ) , time ) ;
nlassert ( bRes ) ;
}
// 1) build a texture that can either be a file texture or a multifile texture
ITexture * srcTex ;
const uint numNelTextureSlots = 8 ;
static const char * fileNamesTab [ ] = { " bitmap1FileName " ,
" bitmap2FileName " ,
" bitmap3FileName " ,
" bitmap4FileName " ,
" bitmap5FileName " ,
" bitmap6FileName " ,
" bitmap7FileName " ,
" bitmap8FileName "
} ;
if ( isClassIdCompatible ( texmap , Class_ID ( NEL_BITMAP_TEXTURE_CLASS_ID_A , NEL_BITMAP_TEXTURE_CLASS_ID_B ) ) ) // is it a set of textures ?
{
uint k ;
std : : string fileName [ numNelTextureSlots ] ;
for ( k = 0 ; k < numNelTextureSlots ; + + k ) // copy each texture of the set
{
nlassert ( k < sizeof ( fileNamesTab ) / sizeof ( const char * ) ) ;
/// get the file name from the parameter block
bRes = getValueByNameUsingParamBlock2 ( texmap , fileNamesTab [ k ] , ( ParamType2 ) TYPE_STRING , & fileName [ k ] , time ) ;
nlassert ( bRes ) ;
}
uint numUsedSlots = 0 ;
uint l ;
for ( l = 0 ; l < numNelTextureSlots ; + + l )
{
if ( ! fileName [ l ] . empty ( ) ) numUsedSlots = l + 1 ;
}
// if only the first slot is used we create a CTextureFile...
if ( l = = 1 & & ! fileName [ 0 ] . empty ( ) )
{
srcTex = new CTextureFile ;
static_cast < CTextureFile * > ( srcTex ) - > setFileName ( ConvertTexFileName ( fileName [ 0 ] . c_str ( ) , _AbsolutePath ) ) ;
}
else
{
srcTex = new CTextureMultiFile ( numUsedSlots ) ;
for ( k = 0 ; k < numUsedSlots ; + + k ) // copy each texture of the set
{
if ( ! fileName [ k ] . empty ( ) )
{
/// set the name of the texture after converting it
static_cast < CTextureMultiFile * > ( srcTex ) - > setFileName ( k , ConvertTexFileName ( fileName [ k ] . c_str ( ) , _AbsolutePath ) . c_str ( ) ) ;
}
}
}
}
else // standard texture
{
srcTex = new CTextureFile ;
static_cast < CTextureFile * > ( srcTex ) - > setFileName ( ConvertTexFileName ( pBitmap - > GetMapName ( ) , _AbsolutePath ) ) ;
}
// 2) Use this texture 'as it', or duplicate it to create the faces of a cube map
// Force cubic
if ( forceCubic )
{
// Cube side
const static CTextureCube : : TFace tfNewOrder [ 6 ] = { CTextureCube : : positive_z , CTextureCube : : negative_z ,
CTextureCube : : negative_x , CTextureCube : : positive_x ,
CTextureCube : : positive_y , CTextureCube : : negative_y } ;
// Alloc a cube texture
CTextureCube * pTextureCube = new CTextureCube ;
for ( uint side = 0 ; side < 6 ; side + + )
{
// Set a copy of the source texture in the cube
if ( dynamic_cast < CTextureMultiFile * > ( srcTex ) )
{
pTextureCube - > setTexture ( tfNewOrder [ side ] , new CTextureMultiFile ( * static_cast < CTextureMultiFile * > ( srcTex ) ) ) ;
}
else
{
pTextureCube - > setTexture ( tfNewOrder [ side ] , new CTextureFile ( * static_cast < CTextureFile * > ( srcTex ) ) ) ;
}
}
// Ok, good texture
pTexture = pTextureCube ;
delete srcTex ;
srcTex = NULL ;
}
else
{
/// just use the source texture
pTexture = srcTex ;
}
}
else if ( isClassIdCompatible ( texmap , Class_ID ( ACUBIC_CLASS_ID , 0 ) ) )
{
pTexture = buildTextureCubeFromReflectRefract ( texmap , time ) ;
}
else if ( isClassIdCompatible ( texmap , Class_ID ( COMPOSITE_CLASS_ID , 0 ) ) )
{
pTexture = buildTextureCubeFromComposite ( texmap , time ) ;
}
// Get the UVs channel and the channel matrix
Matrix3 channelMatrix ;
int nChannel = getVertMapChannel ( texmap , channelMatrix , time ) ;
// Add the UVs channel
remap3dsTexChannel . _IndexInMaxMaterial = nChannel ;
remap3dsTexChannel . _UVMatrix = channelMatrix ;
// check for tiling
if ( pTexture ! = NULL ) // avoid possible crash
{
if ( ! ( texmap . GetTextureTiling ( ) & U_WRAP ) ) pTexture - > setWrapS ( ITexture : : Clamp ) ;
if ( ! ( texmap . GetTextureTiling ( ) & V_WRAP ) ) pTexture - > setWrapT ( ITexture : : Clamp ) ;
}
// Return the texture pointer
return pTexture ;
}
/// Build a NeL texture cube from a Reflect/refract map containing 6 textures.
NL3D : : CTextureCube * CExportNel : : buildTextureCubeFromReflectRefract ( Texmap & texmap , TimeValue time )
{
if ( isClassIdCompatible ( texmap , Class_ID ( ACUBIC_CLASS_ID , 0 ) ) )
{
// texture cube
CTextureCube * pTextureCube = new CTextureCube ( ) ;
// set settings
pTextureCube - > setWrapS ( ITexture : : Clamp ) ;
pTextureCube - > setWrapT ( ITexture : : Clamp ) ;
pTextureCube - > setFilterMode ( ITexture : : Linear , ITexture : : LinearMipMapOff ) ;
// face order
const static CTextureCube : : TFace tfNewOrder [ 6 ] =
{ CTextureCube : : positive_z , CTextureCube : : negative_z , // up dn
CTextureCube : : negative_x , CTextureCube : : positive_x , // lf rt
// CTextureCube::positive_y, CTextureCube::negative_y };
CTextureCube : : negative_y , CTextureCube : : positive_y } ; // fr bk
// vector of bitmap names
vector < string > names ;
CExportNel : : getValueByNameUsingParamBlock2 ( texmap , " bitmapName " , ( ParamType2 ) TYPE_STRING_TAB , & names , time ) ;
uint nNbSubMap = std : : min < uint > ( ( uint ) names . size ( ) , 6 ) ;
for ( uint i = 0 ; i < nNbSubMap ; + + i )
{
// Create a texture file
CTextureFile * pT = new CTextureFile ( ) ;
// Set the file name
pT - > setFileName ( ConvertTexFileName ( names [ i ] . c_str ( ) , _AbsolutePath ) ) ;
// Set the texture
pTextureCube - > setTexture ( tfNewOrder [ i ] , pT ) ;
}
// return the texture cube
return pTextureCube ;
}
else return NULL ;
}
/// Build a NeL texture cube from a Composite map containing 6 textures (note: no re-ordering is done, because it didn't reorder composite cube in previous version either).
NL3D : : CTextureCube * CExportNel : : buildTextureCubeFromComposite ( Texmap & texmap , TimeValue time )
{
if ( isClassIdCompatible ( texmap , Class_ID ( COMPOSITE_CLASS_ID , 0 ) ) )
{
// texture cube
CTextureCube * pTextureCube = new CTextureCube ( ) ;
// set settings
pTextureCube - > setWrapS ( ITexture : : Clamp ) ;
pTextureCube - > setWrapT ( ITexture : : Clamp ) ;
pTextureCube - > setFilterMode ( ITexture : : Linear , ITexture : : LinearMipMapOff ) ;
// get number of maps
uint nNbSubMap = std : : min < uint > ( ( uint ) texmap . NumSubTexmaps ( ) , 6 ) ;
for ( uint i = 0 ; i < nNbSubMap ; + + i )
{
std : : vector < CMaterialDesc > _3dsTexChannel ;
Texmap * pSubMap = texmap . GetSubTexmap ( i ) ;
if ( pSubMap ! = NULL & & isClassIdCompatible ( * pSubMap , Class_ID ( BMTEX_CLASS_ID , 0 ) ) )
{
CMaterialDesc _3dsTexChannel ;
ITexture * pTexture = buildATexture ( * pSubMap , _3dsTexChannel , time ) ;
pTextureCube - > setTexture ( ( CTextureCube : : TFace ) i , pTexture ) ;
}
}
// return the texture cube
return pTextureCube ;
}
else return NULL ;
}
/// Build a NeL texture cube from a single texture.
NL3D : : CTextureCube * CExportNel : : buildTextureCubeFromTexture ( Texmap & texmap , TimeValue time )
{
if ( isClassIdCompatible ( texmap , Class_ID ( BMTEX_CLASS_ID , 0 ) ) )
{
// texture cube
CTextureCube * pTextureCube = new CTextureCube ( ) ;
// set settings
pTextureCube - > setWrapS ( ITexture : : Clamp ) ;
pTextureCube - > setWrapT ( ITexture : : Clamp ) ;
pTextureCube - > setFilterMode ( ITexture : : Linear , ITexture : : LinearMipMapOff ) ;
// List of channels used by this texture
CMaterialDesc _3dsTexChannel ;
// Ok export the texture in NeL format
ITexture * pTexture = buildATexture ( texmap , _3dsTexChannel , time ) ;
pTextureCube - > setTexture ( CTextureCube : : positive_x , pTexture ) ;
return pTextureCube ;
}
else return NULL ;
}
# pragma optimize("", on)