2
Copyright (c) 2008-2009 NetAllied Systems GmbH
4
This file is part of COLLADAMax.
6
Portions of the code are:
7
Copyright (c) 2005-2007 Feeling Software Inc.
8
Copyright (c) 2005-2007 Sony Computer Entertainment America
10
Based on the 3dsMax COLLADASW Tools:
11
Copyright (c) 2005-2006 Autodesk Media Entertainment
13
Licensed under the MIT Open Source License,
14
for details please see LICENSE file or the website
15
http://www.opensource.org/licenses/mit-license.php
19
#include "COLLADAMaxStableHeaders.h"
21
#include "COLLADAMaxEffectExporter.h"
23
#include "COLLADAMaxExportSceneGraph.h"
24
#include "COLLADAMaxMultiMtl.h"
25
#include "COLLADAMaxAnimationExporter.h"
26
#include "COLLADAMaxConversionFunctor.h"
27
#include "COLLADAMaxHwShaderExporter.h"
29
#include "COLLADAMaxXRefFunctions.h"
31
#include "COLLADASWNode.h"
32
//#include "COLLADASWTextureModifier.h"
36
#include <IDxMaterial.h>
47
const String EffectExporter::COLOR_EFFECT_ID_PREFIX = "ColorEffect";
48
const String EffectExporter::TEXCOORD_BASE = "CHANNEL";
50
const String EffectExporter::DAE_AMBIENT_TEXTURE_CHANNEL = "AMBIENT";
51
const String EffectExporter::DAE_BUMP_TEXTURE_CHANNEL = "BUMP";
52
const String EffectExporter::DAE_DIFFUSE_TEXTURE_CHANNEL = "DIFFUSE";
53
const String EffectExporter::DAE_DISPLACEMENT_TEXTURE_CHANNEL = "DISPLACEMENT";
54
const String EffectExporter::DAE_EMISSION_TEXTURE_CHANNEL = "GLOW";
55
const String EffectExporter::DAE_FILTER_TEXTURE_CHANNEL = "FILTER";
56
//#defineDAE_OPACITY_TEXTURE_CHANNEL = "OPACITY";
57
const String EffectExporter::DAE_REFLECTION_TEXTURE_CHANNEL = "REFLECTION";
58
const String EffectExporter::DAE_REFRACTION_TEXTURE_CHANNEL = "REFRACTION";
59
const String EffectExporter::DAE_SHININESS_TEXTURE_CHANNEL = "SHININESS";
60
const String EffectExporter::DAE_SPECULAR_TEXTURE_CHANNEL = "SPECULAR";
61
const String EffectExporter::DAE_SPECULARLEVEL_TEXTURE_CHANNEL = "SPECULAR-LEVEL";
62
const String EffectExporter::DAE_TRANSPARENT_TEXTURE_CHANNEL = "TRANSPARENT";
64
const String EffectExporter::DAE_BUMP_TYPE_ATTRIBUTE = "bumptype";
65
const String EffectExporter::DAE_BUMP_TYPE_NORMALMAP = "NORMALMAP";
66
const String EffectExporter::DAE_BUMP_TYPE_HEIGHTFIELD = "HEIGHTFIELD";
68
const String EffectExporter::EMPTY_STRING = "";
70
const String EffectExporter::SELF_ILLUMINATION_PARAMETER = "self_illumination";
72
const String EffectExporter::COLOR_PARAMETERS[ 4 ] =
76
const String EffectExporter::SHADER_ELEMENT = "shader";
77
const int EffectExporter::SHADER_PARAMETER_COUNT = 7;
78
const Extra::ExtraParameter EffectExporter::SHADER_PARAMETERS[] =
80
{TYPE_BOOL, 3, "ambient_diffuse_texture_lock"},
81
{TYPE_BOOL, 4, "ambient_diffuse_lock"},
82
{TYPE_BOOL, 5, "diffuse_specular_lock"},
83
{TYPE_BOOL, 6, "use_self_illum_color"},
84
{TYPE_PCNT_FRAC, 7, "self_illumination"},
85
{TYPE_PCNT_FRAC, 9, "specular_level"},
86
{TYPE_FLOAT, 11, "soften"}
90
const String EffectExporter::EXTENDED_SHADER_ELEMENT = "extended_shader";
91
const int EffectExporter::EXTENDED_SHADER_PARAMETER_COUNT = 11;
92
const Extra::ExtraParameter EffectExporter::EXTENDED_SHADER_PARAMETERS[] =
94
{TYPE_INT, 0, "opacity_type"},
95
{TYPE_RGBA, 2, "filter_color"},
96
{TYPE_TEXMAP, 3, "filtert_map"},
97
{TYPE_INT, 4, "falloff_type"},
98
{TYPE_PCNT_FRAC, 5, "falloff"},
99
{TYPE_FLOAT, 6, "index_of_refraction"},
100
{TYPE_FLOAT, 7, "wire_size"},
101
{TYPE_INT, 8, "wire_units"},
102
{TYPE_BOOL, 9, "apply_reflection_dimming"},
103
{TYPE_FLOAT, 10, "dim_level"},
104
{TYPE_FLOAT, 11, "reflection_level"}
109
//---------------------------------------------------------------
110
String EffectExporter::createTexcoordSementicFromMapchannel( int mapChannel )
112
return TEXCOORD_BASE + COLLADASW::Utils::toString ( mapChannel );
115
//---------------------------------------------------------------
116
EffectExporter::EffectExporter ( COLLADASW::StreamWriter * streamWriter, ExportSceneGraph * exportSceneGraph, DocumentExporter * documentExporter )
117
: COLLADASW::LibraryEffects ( streamWriter )
118
, Extra(streamWriter, documentExporter)
119
, mExportSceneGraph ( exportSceneGraph )
120
, mDocumentExporter ( documentExporter )
121
, mTextureExporter ( documentExporter )
122
, mAnimationExporter( documentExporter->getAnimationExporter() )
124
, mCopyImageCounter( 0 )
127
//---------------------------------------------------------------
128
void EffectExporter::doExport()
130
mExportedEffectIdList = & ( mDocumentExporter->getMaterialExporter() ->getEffectIdList() );
132
exportEffect ( mExportSceneGraph->getRootExportNode() );
136
//---------------------------------------------------------------
137
void EffectExporter::exportEffect ( ExportNode* exportNode )
139
if ( !exportNode->getIsInVisualScene() && !exportNode->getIsReferenced() )
142
INode * iNode = exportNode->getINode();
143
Mtl * material = iNode->GetMtl();
145
// If the node has material export it. If not, export the wire color.
149
exportEffect ( exportNode, material );
154
// export wire frame material only for meshes
155
if ( exportNode->getType() == ExportNode::MESH )
157
exportColorEffect ( exportNode, iNode->GetWireColor() );
161
//export the child nodes materials
162
size_t numberOfChildren = exportNode->getNumberOfChildren();
164
for ( size_t i = 0; i < numberOfChildren; ++i )
165
exportEffect ( exportNode->getChild ( i ) );
168
//---------------------------------------------------------------
169
void EffectExporter::exportEffect ( ExportNode* exportNode, Mtl* material )
173
if (XRefFunctions::isXRefMaterial(material))
175
if ( mDocumentExporter->getOptions().getIncludeXRefs() )
177
// we don't export XRef materials, but remember them for later use
178
material = XRefFunctions::getXRefMaterialSource(material);
183
// xRefedMaterialList.push_back(mat);
189
if ( material->IsMultiMtl() )
191
// This material type is used for meshes with multiple materials:
192
// only export the individual materials.
194
for ( int j = 0; j < material->NumSubMtls(); j++ )
196
Mtl* submat = material->GetSubMtl ( j );
199
exportEffect ( exportNode, submat );
205
// add <material> node for this material to the library
206
exportSimpleEffect ( exportNode, material );
210
//---------------------------------------------------------------
211
void EffectExporter::exportSimpleEffect ( ExportNode* exportNode, Mtl* baseMaterial )
213
// check if this is not an XRef
215
if ( XRefFunctions::isXRefMaterial ( baseMaterial ) )
217
if ( mDocumentExporter->getOptions().getIncludeXRefs() )
219
// don't generate the FCDMaterial
220
baseMaterial = XRefFunctions::getXRefMaterialSource( baseMaterial );
230
EffectMap::iterator it = mEffectMap.find ( baseMaterial );
232
if ( it != mEffectMap.end() )
234
exportNode->addSymbol ( baseMaterial, it->second );
239
String materialName = NativeString(baseMaterial->GetName().data());
240
// Add it to the exported materials list
241
String effectId = mEffectIdList.addId ( materialName );
243
exportNode->addSymbol ( baseMaterial, effectId );
245
mEffectMap[ baseMaterial ] = effectId;
247
mExportedEffectIdList->push_back ( EffectIdAndName(effectId, materialName) );
249
openEffect ( effectId );
251
setExtraTechnique(this);
253
//COLLADASW::EffectProfile effectCommonProfile ( LibraryEffects::mSW );
256
// Write out the custom attributes
257
// ExportCustomAttributes(baseMaterial, material);
259
/// @TODO Handle other types of material properly
260
// does the material have an HLSL profile?
261
//bool itHasHardwareShader = false;
262
IDxMaterial* dxm = static_cast<IDxMaterial*> ( baseMaterial->GetInterface( IDXMATERIAL_INTERFACE ) );
264
#ifdef MAX_2010_OR_NEWER
266
std::string effectFileNameString;
267
const char* effectFileName = NULL;
271
COLLADABU::StringUtils::wideString2utf8String(dxm->GetEffectFile().GetFileName().data());
272
effectFileName = effectFileNameString.c_str();
275
const char* effectFileName = dxm ? dxm->GetEffectFile().GetFileName().data() : 0;
278
const char* effectFileName = dxm ? dxm->GetEffectFilename() : 0;
281
if ( effectFileName && *effectFileName )
284
if ( baseMaterial->NumSubMtls() > 0 && baseMaterial->GetSubMtl( 0 ) )
286
// Create common profile
287
Mtl * workingMaterial = baseMaterial->GetSubMtl ( 0 );
288
// ExportCustomAttributes(workingMaterial, material);
289
// exportCommonEffect((FCDEffectStandard*)matEffect->AddProfile(FUDaeProfileType::COMMON), workingMaterial);
290
exportCommonEffect ( effectCommonProfile, exportNode, workingMaterial, effectId );
294
// Create HLSL profile and add the effect instantiation elements
295
COLLADASW::EffectProfile effectHLSLProfile ( LibraryEffects::mSW );
297
COLLADASW::URI shaderFxFileUri ( COLLADASW::URI::nativePathToUri ( effectFileName ) );
298
effectHLSLProfile.setInclude ( shaderFxFileUri, shaderFxFileUri.getPathFileBase() );
299
exportHLSLEffect ( effectHLSLProfile, exportNode, baseMaterial, effectId );
300
//itHasHardwareShader = true;
303
// else if (baseMaterial->ClassID() == COLLADASW_EFFECT_ID)
305
// exportColladaEffect(material, (ColladaEffect*)baseMaterial);
310
// Create common profile
311
COLLADASW::EffectProfile effectCommonProfile ( LibraryEffects::mSW );
312
exportCommonEffect ( effectCommonProfile, exportNode, baseMaterial, effectId );
313
addEffectProfile ( effectCommonProfile );
317
//addEffectProfile ( effectCommonProfile );
319
//if ( itHasHardwareShader )
321
// effectHLSLProfile.openProfile ();
322
// effectHLSLProfile.addProfileElements ();
324
// exportEffectParameters ( shaderNode, cgEffect );
326
// // Find if effect parameter is used by any program of the selected technique
327
// CGtechnique cgTechnique = cgGetFirstTechnique ( cgEffect );
328
// while ( cgTechnique )
330
// exportTechnique ( cgTechnique );
331
// cgTechnique = cgGetNextTechnique ( cgTechnique );
334
// effectHLSLProfile.closeProfile ();
337
addExtraTechniques(ElementWriter::mSW);
343
//---------------------------------------------------------------
344
void EffectExporter::exportCommonEffect ( COLLADASW::EffectProfile & effectProfile, ExportNode* exportNode, Mtl* material, const String & effectId, float weight, bool inited )
346
// Export all submaterials first.
347
int subMaterialCount = material->NumSubMtls();
349
for ( int i = 0; i < subMaterialCount; ++i )
351
Mtl* subMaterial = material->GetSubMtl ( i );
352
float subMtlWeight = weight;
354
if ( material->ClassID() == CompositeMtl::classID )
356
IParamBlock2 * pblock = material->GetParamBlock ( 0 );
358
if ( pblock != NULL )
360
if ( !pblock->GetInt ( CompositeMtl::compmat_map_on ) )
363
subMtlWeight *= pblock->GetFloat ( CompositeMtl::compmat_amount ) / 100.0f;
367
if ( subMaterial != NULL )
369
exportCommonEffect ( effectProfile, exportNode, subMaterial, effectId, subMtlWeight, inited );
374
Class_ID materialId = material->ClassID();
376
if ( materialId.PartA() == DMTL2_CLASS_ID || materialId.PartA() == DMTL_CLASS_ID )
378
exportStandardEffect ( effectProfile, exportNode, ( StdMat2* ) material, effectId, weight, inited );
383
// This must be some strange 'RayTrace' or render-only material
384
// Export whatever information we can from the Max material interface
385
exportUnknownEffect ( effectProfile, exportNode, material, effectId );
389
//---------------------------------------------------------------
390
void logEffectParameters (
394
int numParamBlocks = material->NumParamBlocks();
396
for ( int i = 0; i < numParamBlocks; i++ )
398
IParamBlock2 * pblock = material->GetParamBlock ( i );
399
int parameterCount = pblock->NumParams();
401
fprintf( stdout, "Param block = %i;\n", i );
403
for ( int j = 0; j < parameterCount; j++ )
405
ParamID parameterID = pblock->IndextoID( j );
406
ParamType2 parameterType = pblock->GetParameterType( parameterID );
407
ParamDef parameterDef = pblock->GetParamDef( parameterID );
410
std::string paramNameString = COLLADABU::StringUtils::wideString2utf8String(parameterDef.int_name);
411
const char* paramName = paramNameString.c_str();
413
const char* paramName = parameterDef.int_name;
415
fprintf( stdout, "\tParam name = %s; Type = %i;\n", paramName, (int)parameterType );
420
void EffectExporter::exportHLSLEffect ( COLLADASW::EffectProfile & effectProfile, ExportNode* exportNode, Mtl* material, const String & effectId, float weight, bool inited )
422
// Export all submaterials first.
423
int subMaterialCount = material->NumSubMtls();
424
logEffectParameters( material );
427
for ( int i = 0; i < subMaterialCount; ++i )
429
Mtl* subMaterial = material->GetSubMtl ( i );
430
float subMtlWeight = weight;
432
if ( material->ClassID() == CompositeMtl::classID )
434
IParamBlock2 * pblock = material->GetParamBlock ( 0 );
436
if ( pblock != NULL )
438
if ( !pblock->GetInt ( CompositeMtl::compmat_map_on ) )
441
subMtlWeight *= pblock->GetFloat ( CompositeMtl::compmat_amount ) / 100.0f;
445
if ( subMaterial != NULL )
447
exportHLSLEffect ( effectProfile, exportNode, subMaterial, effectId, subMtlWeight, inited );
452
Class_ID materialId = material->ClassID();
454
if ( materialId.PartA() == DMTL2_CLASS_ID || materialId.PartA() == DMTL_CLASS_ID )
457
HwShaderExporter hwShaderExporter ( mDocumentExporter );
458
hwShaderExporter.exportPluginHwShaderNode ( effectId, &effectProfile, exportNode, ( StdMat2* ) material, weight );
462
//---------------------------------------------------------------
463
void EffectExporter::exportStandardEffect ( COLLADASW::EffectProfile & effectProfile, ExportNode* exportNode, StdMat2* material, const String & effectId, float weight, bool inited )
465
assert ( material != 0 );
467
// TODO ensure that effect id unique
468
// String effectId = mEffectIdList.addId(material->GetName().data());
472
EffectMap::iterator effectIterator = mEffectMap.find ( ( Mtl* ) material );
475
if ( effectIterator != mEffectMap.end() )
477
exportNode->addSymbol ( ( Mtl* ) material, effectId );
482
exportNode->addSymbol ( material, NativeString(material->GetName().data()) );
484
mEffectMap[ material ] = effectId;
486
Shader* shader = material->GetShader();
488
TimeValue animationStart = mDocumentExporter->getOptions().getAnimationStart();
492
effectProfile.setShaderType ( maxShaderToShaderType ( shader->ClassID() ) );
495
// Retrieve the interesting parameter blocks
496
IParamBlock2* shaderParameters = ( IParamBlock2* ) shader->GetReference ( 0 );
498
IParamBlock2* extendedParameters = ( IParamBlock2* ) material->GetReference ( StandardMaterial::EXTENDED_PB_REF );
500
TimeValue initTime = mDocumentExporter->getOptions().getAnimationStart();
504
ScaleConversionFunctor scaleConversion(weight);
506
// effectProfile.setShaderType(COLLADASW::EffectProfile::PHONG);
507
bool isAmbientAnimated = mAnimationExporter->addAnimatedParameter(shaderParameters, ShaderParameterIndices::AMBIENT_COLOR, effectId, effectProfile.getAmbientDefaultSid(), COLOR_PARAMETERS, true, &scaleConversion);
508
effectProfile.setAmbient ( maxColor2ColorOrTexture ( shader->GetAmbientClr ( animationStart ), weight ), isAmbientAnimated );
510
bool isDiffuseAnimated = mAnimationExporter->addAnimatedParameter(shaderParameters, ShaderParameterIndices::DIFFUSE_COLOR, effectId, effectProfile.getDiffuseDefaultSid(), COLOR_PARAMETERS, true, &scaleConversion);
511
effectProfile.setDiffuse ( maxColor2ColorOrTexture ( shader->GetDiffuseClr ( animationStart ), weight ), isDiffuseAnimated );
513
effectProfile.setTransparent ( COLLADASW::ColorOrTexture ( COLLADASW::Color::WHITE ) );
515
bool isOpacityAnimated = mAnimationExporter->addAnimatedParameter(extendedParameters, ExtendedParameterIndices::OPACITY, effectId, effectProfile.getSpecularDefaultSid(), COLOR_PARAMETERS);
516
effectProfile.setTransparency ( material->GetOpacity ( animationStart ) * weight );
518
effectProfile.setReflective ( COLLADASW::ColorOrTexture ( COLLADASW::Color::BLACK ) );
520
bool isSpecularAnimated = mAnimationExporter->addAnimatedParameter(shaderParameters, ShaderParameterIndices::SPECULAR_COLOR, effectId, effectProfile.getSpecularDefaultSid(), COLOR_PARAMETERS, true, &scaleConversion);
521
effectProfile.setSpecular ( maxColor2ColorOrTexture ( shader->GetSpecularClr ( animationStart ), weight ), isSpecularAnimated );
523
//bool isGlossinessAnimated = mAnimationExporter->addAnimatedParameter(shaderParameters, ShaderParameterIndices::GLOSSINESS, effectId, effectProfile.getShininessDefaultSid(), 0, true, &ConversionFunctors::toPercent);
524
//effectProfile.setShininess ( ConversionFunctors::toPercent(shader->GetGlossiness ( animationStart )) * weight, isGlossinessAnimated );
526
bool isSpecularLevelAnimated = mAnimationExporter->addAnimatedParameter(shaderParameters, ShaderParameterIndices::SPECULAR_LEVEL, effectId, effectProfile.getShininessDefaultSid(), 0, true, &ConversionFunctors::toPercent);
527
float specularLevel = shader->GetSpecularLevel ( animationStart );
528
effectProfile.setShininess ( specularLevel * weight, isSpecularLevelAnimated );
530
bool useEmissionColor = shader->IsSelfIllumClrOn() != false;
531
if (useEmissionColor)
533
bool isEmissionAnimated = mAnimationExporter->addAnimatedParameter(shaderParameters, ShaderParameterIndices::SELF_ILLUMINATION_COLOR, effectId, effectProfile.getEmissionDefaultSid(), COLOR_PARAMETERS, true, &scaleConversion);
534
effectProfile.setEmission( maxColor2ColorOrTexture ( shader->GetSelfIllumClr ( animationStart ), weight ), isEmissionAnimated );
538
bool isEmissionAnimated = mAnimationExporter->addAnimatedParameter(shaderParameters, ShaderParameterIndices::SELF_ILLUMINATION_COLOR, effectId, effectProfile.getEmissionDefaultSid(), COLOR_PARAMETERS);
539
effectProfile.setEmission( maxColor2ColorOrTexture ( shader->GetSelfIllumClr ( animationStart ) ), isEmissionAnimated );
542
addParamBlockAnimatedExtraParameters(SHADER_ELEMENT, SHADER_PARAMETERS, SHADER_PARAMETER_COUNT, shaderParameters, effectId);
544
addParamBlockAnimatedExtraParameters(EXTENDED_SHADER_ELEMENT, EXTENDED_SHADER_PARAMETERS, EXTENDED_SHADER_PARAMETER_COUNT, extendedParameters, effectId);
548
int numSubTexMaps = material->NumSubTexmaps();
550
for ( int i = 0; i < numSubTexMaps; i++ )
552
Channel channel = maxIdToEffectChannel ( material, i );
554
if ( channel == EffectExporter::UNKNOWN )
557
Texmap* map = material->GetSubTexmap ( i );
565
/* if ( !material->GetSelfIllumColorOn() ) // Emission
568
// ANIM->ExportProperty(_T("self_illum_level"), shaderParameters, FSStandardMaterial::shdr_self_illum_amnt, 0, stdProfile->GetEmissionFactorParam()->GetValue(), NULL);
569
//TODO: check what this is good for
570
//stdProfile->SetIsEmissionFactor(true);
577
effectProfile.setOpaque ( getOpacity ( map ) );
581
// Calculate weight here. Let execution continue
582
// even if map is disabled, in order to manage colour blending
583
float colorAmount, mapAmount = 0;
585
bool exportThisMap = material->GetMapState ( i ) == 2;
589
mapAmount = material->GetTexmapAmt ( i, 0 );
590
colorAmount = weight * ( 1.0f - mapAmount );
595
colorAmount = weight;
597
// If our id maps to a colour value, modulate that by our colourAmount.
598
// TODO: add this later
603
blendColor ( effectProfile.getAmbient(), material->GetAmbient ( initTime ), colorAmount );
607
blendColor ( effectProfile.getDiffuse(), material->GetDiffuse ( initTime ), colorAmount );
611
blendColor ( effectProfile.getSpecular(), material->GetSpecular ( initTime ), colorAmount );
618
exportMap (material, channel, map, effectProfile, weight * mapAmount );
622
//---------------------------------------------------------------
623
void EffectExporter::exportMap ( Mtl * material, unsigned int index, Texmap* texMap, COLLADASW::EffectProfile & profile, float weight )
628
//if (weight <= 0) return;
630
// Get any weight control directly on this texmap
631
float amount = weight;
633
Control* weightControl = 0;
635
if ( texMap && GetIBitmapTextInterface ( texMap ) != 0 )
639
BitmapTex * bmTex = ( BitmapTex* ) texMap;
640
TextureOutput* texOut = bmTex->GetTexout();
641
IParamBlock* params = ( IParamBlock* ) texOut->GetReference ( TextureOutputIDs::param_block_ref_id );
643
if ( index == ID_BU )
645
weightControl = params->GetController ( TextureOutputIDs::bump_amount );
646
amount *= params->GetFloat ( TextureOutputIDs::bump_amount );
651
weightControl = params->GetController ( TextureOutputIDs::output_amount );
652
amount *= params->GetFloat ( TextureOutputIDs::output_amount );
658
/// @TODO error handling
664
String imageId = exportImage ( texMap, fullFileName );
666
if ( !imageId.empty() )
668
COLLADASW::Texture texture ( imageId );
670
// Create the sampler
671
String samplerSid = imageId + COLLADASW::Sampler::SAMPLER_SID_SUFFIX;
672
String surfaceSid = imageId + COLLADASW::Sampler::SURFACE_SID_SUFFIX;
673
COLLADASW::Sampler sampler( COLLADASW::Sampler::SAMPLER_TYPE_2D, samplerSid, surfaceSid );
674
sampler.setImageId( imageId );
675
//sampler.setFormat( FORMAT );
676
//texture.setSampler( sampler );
682
mapChannel = texMap->GetMapChannel();
684
UVGen* uvCoordinatesGenerator = texMap->GetTheUVGen();
685
if (uvCoordinatesGenerator && uvCoordinatesGenerator->ClassID().PartA() == STDUV_CLASS_ID)
687
StdUVGen* uvGenParameters = (StdUVGen*)uvCoordinatesGenerator;
688
int uvFlags = uvGenParameters->GetTextureTiling();
690
sampler.setWrapS(COLLADASW::Sampler::WRAP_MODE_CLAMP);
691
sampler.setWrapT(COLLADASW::Sampler::WRAP_MODE_CLAMP);
693
if ( uvFlags & U_WRAP )
695
//Indicates the texture map is tiled in the U direction.
696
sampler.setWrapS(COLLADASW::Sampler::WRAP_MODE_WRAP);
698
if ( uvFlags & V_WRAP )
700
//Indicates the texture map is tiled in the V direction.
701
sampler.setWrapT(COLLADASW::Sampler::WRAP_MODE_WRAP);
703
if ( uvFlags & U_MIRROR )
705
//Indicates the texture map is mirrored in the U direction.
706
sampler.setWrapS(COLLADASW::Sampler::WRAP_MODE_MIRROR);
708
if ( uvFlags & V_MIRROR )
710
//Indicates the texture map is mirrored in the V direction.
711
sampler.setWrapT(COLLADASW::Sampler::WRAP_MODE_MIRROR);
714
IParamBlock* uvParams = (IParamBlock*)uvGenParameters->GetReference(StdUVGenEnums::pblock);
719
float rotationAngle = uvParams->GetFloat(StdUVGenEnums::w_angle);
721
String textureFileName;
723
DocumentExporter::splitFilePath(fullFileName, textureDir, textureFileName);
724
COLLADASW::TextureModifier textureModifier(fullFileName, mDocumentExporter->getOutputDir() + textureFileName);
726
textureModifier.setRotationAngle(rotationAngle);
728
textureModifier.performModifications();
730
mMaterialChannelPairParamBlockMap[MaterialChannelPair(material, index)] = uvParams;
735
// TODO: add extra tag
738
texture.setSampler( sampler );
740
String semantic = createTexcoordSementicFromMapchannel( mapChannel );
742
texture.setTexcoord ( semantic );
750
profile.setAmbient ( COLLADASW::ColorOrTexture ( texture ) );
753
profile.setDiffuse ( COLLADASW::ColorOrTexture ( texture ) );
756
profile.setSpecular ( COLLADASW::ColorOrTexture ( texture ) );
759
texture.setProfileName(Extra::TECHNIQUE_PROFILE_3DSMAX);
760
texture.setChildElementName("specularLevel");
761
profile.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
763
case SHININESS: // Glossiness
764
texture.setProfileName(Extra::TECHNIQUE_PROFILE_3DSMAX);
765
texture.setChildElementName("gloss");
766
profile.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
768
case EMISSION: // Self-illumination
769
profile.setEmission ( COLLADASW::ColorOrTexture ( texture ) );
771
case TRANSPARENt: // Opacity
772
profile.setTransparent ( COLLADASW::ColorOrTexture ( texture ) );
775
texture.setProfileName(Extra::TECHNIQUE_PROFILE_3DSMAX);
776
texture.setChildElementName("filter");
777
profile.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
781
texture.setProfileName(Extra::TECHNIQUE_PROFILE_3DSMAX);
782
texture.setChildElementName("bump");
783
COLLADASW::EffectProfile::StringPairList attributes;
784
attributes.push_back(std::make_pair(DAE_BUMP_TYPE_ATTRIBUTE, DAE_BUMP_TYPE_HEIGHTFIELD));
785
profile.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture), attributes);
789
profile.setReflective( COLLADASW::ColorOrTexture ( texture ) );
792
texture.setProfileName(Extra::TECHNIQUE_PROFILE_3DSMAX);
793
texture.setChildElementName("refraction");
794
profile.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
797
texture.setProfileName(Extra::TECHNIQUE_PROFILE_3DSMAX);
798
texture.setChildElementName("displacement");
799
profile.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
803
//@TODO error handling
808
// Export any and all submaps
809
float subAmount = amount;
811
int numSubTex = texMap->NumSubTexmaps();
813
for ( int subIdx = 0; subIdx < numSubTex; subIdx++ )
815
Texmap* subMap = texMap->GetSubTexmap ( subIdx );
817
// Handle special cases.
818
Class_ID mapClassId = texMap->ClassID();
820
if ( mapClassId.PartB() == 0 )
822
switch ( mapClassId.PartA() )
827
IParamBlock2 * mixParams = texMap->GetParamBlock ( 0 );
839
color = mixParams->GetColor ( MixMap::mix_color1 );
843
subAmount = amount * mixParams->GetFloat ( MixMap::mix_mix );
844
color = mixParams->GetColor ( MixMap::mix_color2 );
848
// Scale to 0, as this isn't an actual texture, but a mix modifier
849
// In that case, we want to keep a texture reference for the user
850
// to figure out if they want
855
// Handle the simple case, which is blending colors.
857
if ( subMap == NULL && subAmount > 0 )
863
blendColor ( profile.getAmbient(), color, subAmount );
867
blendColor ( profile.getDiffuse(), color, subAmount );
871
blendColor ( profile.getSpecular(), color, subAmount );
884
if ( subMap != NULL )
886
if ( texMap->SubTexmapOn ( subIdx ) == 0 )
889
exportMap (material, index, subMap, profile, subAmount );
894
//---------------------------------------------------------------
895
void EffectExporter::exportUnknownEffect ( COLLADASW::EffectProfile & effectProfile, ExportNode* exportNode, Mtl* material, const String & effectId )
897
assert ( material != 0 );
899
/* TODO: think about this*/
901
if ( effectProfile.getShaderType() == COLLADASW::EffectProfile::UNSPECIFIED )
903
float specularLevel = material->GetShinStr();
904
bool isPhong = specularLevel > 0.2f;
905
effectProfile.setShaderType ( isPhong ? COLLADASW::EffectProfile::PHONG : COLLADASW::EffectProfile::BLINN );
908
if ( material->GetSelfIllumColorOn() && !effectProfile.getEmission().isValid() )
909
effectProfile.setEmission ( maxColor2ColorOrTexture ( material->GetSelfIllumColor() ) );
911
if ( !effectProfile.getAmbient().isValid() )
912
effectProfile.setAmbient ( maxColor2ColorOrTexture ( material->GetAmbient() ) );
914
if ( !effectProfile.getDiffuse().isValid() )
915
effectProfile.setDiffuse ( maxColor2ColorOrTexture ( material->GetDiffuse() ) );
918
if ( effectProfile.getShaderType() == COLLADASW::EffectProfile::PHONG )
920
if ( !effectProfile.getSpecular().isValid() )
921
effectProfile.setSpecular ( maxColor2ColorOrTexture ( material->GetSpecular() ) );
923
/// TODO: think about this
924
if ( effectProfile.getShininess() < 0 )
925
effectProfile.setShininess ( material->GetShininess() * 100.0f );
927
/* if (!material->GetSelfIllumColorOn())
929
stdProfile->SetIsEmissionFactor(true);
930
float emissionFactor = material->GetSelfIllum();
931
stdProfile->SetEmissionFactor(emissionFactor);
934
// stdProfile->SetSpecularFactor(specularLevel);
937
exportNode->addSymbol ( material, NativeString(material->GetName().data()) );
939
mEffectMap[ material ] = effectId;
942
//---------------------------------------------------------------
943
void EffectExporter::exportColorEffect ( ExportNode* exportNode, DWORD color )
945
String effectId = getEffectId ( color );
947
if ( find ( mWireFrameColorEffectList.begin(), mWireFrameColorEffectList.end(), color ) == mWireFrameColorEffectList.end() )
949
String effectId = getEffectId ( color );
951
openEffect ( effectId );
952
setExtraTechnique(this);
954
COLLADASW::EffectProfile effectProfile ( LibraryEffects::mSW );
955
effectProfile.setShaderType ( COLLADASW::EffectProfile::PHONG );
956
COLLADASW::Color commonColor ( GetRValue ( color ) / 255.0f, GetGValue ( color ) / 255.0f, GetBValue ( color ) / 255.0f );
957
effectProfile.setAmbient ( COLLADASW::ColorOrTexture ( commonColor ) );
958
effectProfile.setDiffuse ( COLLADASW::ColorOrTexture ( commonColor ) );
959
effectProfile.setTransparent ( COLLADASW::ColorOrTexture ( COLLADASW::Color::WHITE ) );
960
effectProfile.setTransparency ( 1.0 );
961
effectProfile.setReflective ( COLLADASW::ColorOrTexture ( COLLADASW::Color::BLACK ) );
962
effectProfile.setSpecular ( COLLADASW::ColorOrTexture ( COLLADASW::Color::WHITE ) );
963
effectProfile.setShininess ( 10.0 );
965
addEffectProfile ( effectProfile );
967
addExtraTechniques(ElementWriter::mSW);
971
mWireFrameColorEffectList.push_back ( color );
974
exportNode->setWireFrameColor ( color );
977
//---------------------------------------------------------------
978
String EffectExporter::getEffectId ( DWORD color )
980
std::ostringstream name;
981
name << COLOR_EFFECT_ID_PREFIX << "R" << ( int ) GetRValue ( color ) << "G" << ( int ) GetGValue ( color )
982
<< "B" << ( int ) GetBValue ( color );
986
//---------------------------------------------------------------
987
COLLADASW::Color EffectExporter::maxColor2Color ( const Color & color, double scale )
989
return COLLADASW::Color ( color.r * scale, color.g * scale, color.b * scale, scale );
993
//---------------------------------------------------------------
994
COLLADASW::ColorOrTexture EffectExporter::maxColor2ColorOrTexture ( const Color & color, double scale )
996
return COLLADASW::ColorOrTexture ( maxColor2Color( color, scale ) );
999
//---------------------------------------------------------------
1000
EffectExporter::Channel EffectExporter::maxIdToEffectChannel ( StdMat2* material, int id )
1002
assert ( material );
1004
// Order of channels depends on shader.
1005
bool stdShader = true;
1006
Shader* shader = material->GetShader();
1010
Class_ID shaderClassId = shader->ClassID();
1011
unsigned long partA = shaderClassId.PartA();
1013
if ( shaderClassId.PartB() != 0 ||
1015
partA == EffectExporter::STD2_PHONG_CLASS_ID ||
1016
partA == EffectExporter::STD2_BLINN_SHADER_CLASS_ID ||
1017
partA == EffectExporter::STD2_METAL_SHADER_CLASS_ID ||
1018
partA == EffectExporter::STD2_ANISOTROPIC_SHADER_CLASS_ID ||
1019
partA == EffectExporter::STD2_MULTI_LAYER_SHADER_CLASS_ID ||
1020
partA == EffectExporter::STD2_OREN_NAYER_BLINN_CLASS_ID
1030
// First attempt for a non-max shader is name-matching.
1031
// this is because StdIDToChannel may need some extra help
1032
// if for some weird reason there are several different texture
1033
// slots for the same effect. Quite why that happens is
1034
// completely beyond me, but it does happen... Also, as it
1035
// turns out, it is better not to trust the 3rd party implementations
1036
TSTR subName = material->GetSubTexmapSlotName ( id );
1038
if ( subName.Length() > 0 )
1040
String upperName = NativeString(subName.data());
1041
std::transform ( upperName.begin(), upperName.end(), upperName.begin(), toupper );
1042
size_t firstSpace = upperName.find ( ' ' );
1044
if ( firstSpace != String::npos )
1045
upperName.resize ( firstSpace );
1047
if ( upperName == "BASE" )
1048
return EffectExporter::DIFFUSE;
1049
else if ( upperName == "GLOSS" )
1050
return EffectExporter::SPECULAR;
1053
EffectExporter::Channel channel = EffectExporter::channelFromString ( upperName );
1055
if ( channel != EffectExporter::UNKNOWN )
1064
// What do we have here, ay?
1065
TSTR subName = material->GetSubTexmapSlotName ( id );
1071
// If we are here, we are either a std max mtl, or a
1072
// non-std mtl we couldnt match a name to.
1075
for ( int i = 0; i < NTEXMAPS; i++ )
1077
//int x = material->StdIDToChannel(i);
1079
if ( material->StdIDToChannel ( i ) == id )
1090
return EffectExporter::AMBIENT;
1093
return EffectExporter::DIFFUSE;
1096
return EffectExporter::SPECULAR;
1099
return EffectExporter::SHININESS;
1102
return EffectExporter::SPECULAR_LEVEL;
1105
return EffectExporter::EMISSION;
1108
return EffectExporter::TRANSPARENt;
1111
return EffectExporter::FILTER;
1114
return EffectExporter::BUMP;
1117
return EffectExporter::REFLECTION;
1120
return EffectExporter::REFRACTION;
1123
return EffectExporter::DISPLACEMENT;
1126
return EffectExporter::UNKNOWN;
1131
//---------------------------------------------------------------
1132
EffectExporter::Channel EffectExporter::channelFromString ( const String & value )
1134
if ( value == DAE_AMBIENT_TEXTURE_CHANNEL )
1135
return EffectExporter::AMBIENT;
1136
else if ( value == DAE_BUMP_TEXTURE_CHANNEL )
1137
return EffectExporter::BUMP;
1138
else if ( value == DAE_DIFFUSE_TEXTURE_CHANNEL )
1139
return EffectExporter::DIFFUSE;
1140
else if ( value == DAE_DISPLACEMENT_TEXTURE_CHANNEL )
1141
return EffectExporter::DISPLACEMENT;
1142
else if ( value == DAE_EMISSION_TEXTURE_CHANNEL )
1143
return EffectExporter::EMISSION;
1144
else if ( value == DAE_FILTER_TEXTURE_CHANNEL )
1145
return EffectExporter::FILTER;
1147
// else if (value == DAE_OPACITY_TEXTURE_CHANNEL) return OPACITY;
1148
else if ( value == DAE_REFLECTION_TEXTURE_CHANNEL )
1149
return EffectExporter::REFLECTION;
1150
else if ( value == DAE_REFRACTION_TEXTURE_CHANNEL )
1151
return EffectExporter::REFRACTION;
1152
else if ( value == DAE_SHININESS_TEXTURE_CHANNEL )
1153
return EffectExporter::SHININESS;
1154
else if ( value == DAE_SPECULAR_TEXTURE_CHANNEL )
1155
return EffectExporter::SPECULAR;
1156
else if ( value == DAE_SPECULARLEVEL_TEXTURE_CHANNEL )
1157
return EffectExporter::SPECULAR_LEVEL;
1158
else if ( value == DAE_TRANSPARENT_TEXTURE_CHANNEL )
1159
return EffectExporter::TRANSPARENt;
1164
//---------------------------------------------------------------
1165
COLLADASW::EffectProfile::Opaque EffectExporter::getOpacity ( Texmap *texMap )
1167
// Only one transparency factor is supported, so retrieve only the first texture from this bucket.
1169
if ( texMap == NULL )
1170
return COLLADASW::EffectProfile::A_ONE;
1172
BitmapTex* bmap = GetIBitmapTextInterface ( texMap );
1174
BOOL isAlphaTransparency = true;
1177
isAlphaTransparency = bmap->GetAlphaAsMono ( TRUE );
1179
// As far as my tests are concerned, the only real way to get alpha-transparency is through
1180
// the mono-channel output as Alpha.
1181
return isAlphaTransparency ? COLLADASW::EffectProfile::A_ONE : COLLADASW::EffectProfile::RGB_ZERO;
1184
//---------------------------------------------------------------
1185
COLLADASW::EffectProfile::ShaderType EffectExporter::maxShaderToShaderType ( Class_ID id )
1187
switch ( id.PartA() )
1190
case StandardMaterial::STD2_BLINN_SHADER_CLASS_ID:
1192
case StandardMaterial::STD2_OREN_NAYER_BLINN_CLASS_ID:
1194
case StandardMaterial::STD2_METAL_SHADER_CLASS_ID:
1195
return COLLADASW::EffectProfile::BLINN;
1197
case StandardMaterial::STD2_PHONG_CLASS_ID:
1198
return COLLADASW::EffectProfile::PHONG;
1201
return COLLADASW::EffectProfile::PHONG;
1205
//---------------------------------------------------------------
1206
String EffectExporter::exportImage ( Texmap* map, String& fullFileName )
1209
return EMPTY_STRING;
1211
if ( map->ClassID() == Class_ID ( BMTEX_CLASS_ID, 0x00 ) )
1213
BitmapTex * baseBitmap = ( BitmapTex* ) map;
1216
return EMPTY_STRING;
1218
// get a valid filename
1219
BitmapInfo bitmapInfo;
1221
bitmapInfo.SetName ( baseBitmap->GetMapName() );
1223
return exportImage ( bitmapInfo, fullFileName );
1226
else if ( map->ClassID() == Class_ID ( MIX_CLASS_ID, 0x00 ) )
1228
return EMPTY_STRING;
1232
return EMPTY_STRING;
1235
//---------------------------------------------------------------
1236
String EffectExporter::exportImage ( BitmapInfo& bitmapInfo, String& fullFileName )
1238
const TCHAR * fileNamePtr = bitmapInfo.Name();
1242
fileName = NativeString(fileNamePtr);
1244
static const String noneString("none");
1245
if ( !fileName.empty() && !StringUtils::equals(fileName, noneString) )
1248
BMMGetFullFilename ( &bitmapInfo );
1249
NativeString fullNativeFileName = NativeString(bitmapInfo.Name());
1250
fullFileName = fullNativeFileName;
1251
COLLADABU::URI fullFileNameURI = URI::nativePathToUri( fullNativeFileName.toUtf8String() );
1252
if ( fullFileNameURI.getScheme().empty() )
1253
fullFileNameURI.setScheme(COLLADASW::URI::SCHEME_FILE);
1255
// Export the equivalent <image> node in the image library and add
1256
// the <init_from> element to the sampler's surface definition.
1257
// "None" is a special Max token, to indicate no texture assigned
1258
ExportedImageMap::iterator it = mExportedImageMap.find ( fullFileNameURI );
1260
if ( it == mExportedImageMap.end() )
1262
// generate an interesting name: strip the filename away from the filepath.
1263
size_t slashIndex = fullFileName.rfind ( '/' );
1264
size_t backSlashIndex = fullFileName.rfind ( '\\' );
1266
ImageInfo imageInfo;
1268
if ( slashIndex == String::npos )
1269
slashIndex = backSlashIndex;
1270
else if ( backSlashIndex != String::npos && backSlashIndex > slashIndex )
1271
slashIndex = backSlashIndex;
1273
imageInfo.imageId = ( slashIndex != String::npos ) ? fullFileName.substr ( slashIndex + 1 ) : fullFileName;
1274
imageInfo.imageId = COLLADASW::Utils::replaceDot ( COLLADASW::Utils::checkID(imageInfo.imageId) );
1275
imageInfo.imageId = mImageIdList.addId( imageInfo.imageId );
1277
if ( mDocumentExporter->getOptions().getCopyImages() )
1279
// we need to copy the image in output directory/images
1280
COLLADASW::URI imageTargetPath = createTargetURI(fullFileNameURI);
1281
// Copy the texture, if it isn't already there...
1282
bool exists = COLLADABU::Utils::fileExistsAndIsReadable( imageTargetPath.toNativePath() );
1287
// Create the target directory, if necessary.
1288
// Note: some systems (window$) requires the string to be
1289
// enclosed in quotes when a space is present.
1290
COLLADASW::URI imageTargetPathDir ( imageTargetPath.getPathDir() );
1291
exists = COLLADABU::Utils::createDirectoryIfNeeded( imageTargetPathDir.toNativePath() );
1295
// Throws: basic_filesystem_error<Path> if
1296
// from_fp.empty() || to_fp.empty() ||!exists(from_fp) || !is_regular(from_fp) || exists(to_fp)
1297
exists = COLLADABU::Utils::copyFile( fullFileNameURI.toNativePath(), imageTargetPath.toNativePath() );
1307
// todo handle error
1311
if ( mDocumentExporter->getOptions().getExportRelativePaths() )
1313
bool success = true;
1314
imageInfo.fileLocation = imageTargetPath.getRelativeTo(mDocumentExporter->getOutputFileUri(),success, true);
1318
imageInfo.fileLocation = imageTargetPath;
1323
if ( mDocumentExporter->getOptions().getExportRelativePaths() )
1325
bool success = true;
1326
imageInfo.fileLocation = fullFileNameURI.getRelativeTo(mDocumentExporter->getOutputFileUri(),success, true);
1330
imageInfo.fileLocation = fullFileNameURI;
1334
// image not exported
1335
mExportedImageMap[ fullFileNameURI ] = imageInfo;
1336
return imageInfo.imageId;
1340
return it->second.imageId;
1345
return EMPTY_STRING;
1348
// ------------------------------------------------------------
1349
COLLADASW::URI EffectExporter::createTargetURI ( const COLLADASW::URI& sourceUri )
1352
const COLLADABU::URI& outputFile = mDocumentExporter->getOutputFileUri();
1354
String relativePath = mDocumentExporter->getOptions().getImageDirectory();
1355
relativePath.append("/");
1356
relativePath.append( COLLADABU::Utils::toString( mCopyImageCounter++ ) );
1357
relativePath.append("_");
1358
relativePath.append( sourceUri.getPathFile() );
1360
COLLADASW::URI targetUri ( outputFile, relativePath);
1362
// Get the pure file name of the source file and set
1363
// the source file name to the target path
1364
// targetUri.setPathFile ( sourceUri.getPathFile () );
1365
targetUri.setScheme ( COLLADASW::URI::SCHEME_FILE );
1367
// Generate the target file name
1372
//---------------------------------------------------------------
1373
void EffectExporter::blendColor ( COLLADASW::ColorOrTexture & colorOrTexture, Color blendColor, double ammount )
1375
if ( colorOrTexture.isColor() )
1377
COLLADASW::Color & color = colorOrTexture.getColor();
1379
color.set ( color.getRed() + ( blendColor[ 0 ] - color.getRed() ) * ammount,
1380
color.getGreen() + ( blendColor[ 1 ] - color.getGreen() ) * ammount,
1381
color.getBlue() + ( blendColor[ 2 ] - color.getBlue() ) * ammount,
1389
bool EffectExporter::MaterialChannelPair::operator<( const EffectExporter::MaterialChannelPair & rhs ) const
1391
if ( mMaterial < rhs.mMaterial )
1393
if ( mMaterial > rhs.mMaterial )
1396
if ( mChannel < rhs.mChannel )
1398
if ( mChannel > rhs.mChannel )