1 /* 2 Copyright (c) 2008-2009 NetAllied Systems GmbH 3 4 This file is part of COLLADAMax. 5 6 Portions of the code are: 7 Copyright (c) 2005-2007 Feeling Software Inc. 8 Copyright (c) 2005-2007 Sony Computer Entertainment America 9 10 Based on the 3dsMax COLLADASW Tools: 11 Copyright (c) 2005-2006 Autodesk Media Entertainment 12 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 16 */ 17 18 19 #include "COLLADAMaxStableHeaders.h" 20 21 #include "COLLADAMaxExportNode.h" 22 #include "COLLADAMaxControllerExporter.h" 23 24 #include "COLLADAMaxXRefFunctions.h" 25 26 #include <max.h> 27 #include <modstack.h> 28 #include <cs/bipexp.h> 29 #include <surf_api.h> 30 #include <plugapi.h> 31 32 namespace COLLADAMax 33 { 34 35 36 //--------------------------------------------------------------- ExportNode(INode * iNode,ExportNode * parent)37 ExportNode::ExportNode ( INode * iNode, ExportNode* parent ) 38 : mINode ( iNode ), 39 mParent(parent), 40 mType ( UNDETERMINED ), 41 mFlags(NONE), 42 mControllerList(0) 43 { 44 determineType(); 45 } 46 47 //--------------------------------------------------------------- ExportNode(INode * iNode,ExportNode * parent,Type type)48 ExportNode::ExportNode ( INode * iNode, ExportNode* parent , Type type ) 49 : mINode ( iNode ), 50 mParent(parent), 51 mType ( type ), 52 mFlags(NONE), 53 mControllerList(0) 54 { 55 determineType(); 56 } 57 58 59 //--------------------------------------------------------------- clean()60 void ExportNode::clean() 61 { 62 while ( !mChildren.empty() ) 63 { 64 delete mChildren.back(); 65 mChildren.pop_back(); 66 } 67 delete mControllerList; 68 } 69 70 //--------------------------------------------------------------- determineType(INode * iNode)71 ExportNode::Type ExportNode::determineType ( INode * iNode ) 72 { 73 Animatable * animatable = iNode->GetObjectRef(); 74 75 if ( !animatable ) 76 return ExportNode::UNKNOWN; 77 78 Animatable* base = animatable; 79 80 //String gg = iNode->GetName(); 81 82 83 // check for an XRef 84 if (XRefFunctions::isXRefItem(base)) 85 { 86 setIsXRefObject(); 87 // replace the current animatable by the x-ref object 88 base = XRefFunctions::getXRefItemSource((Object*)base); 89 if ( !base ) 90 return ExportNode::UNKNOWN; 91 } 92 else if (XRefFunctions::isXRefMaterial(base)) 93 { 94 setIsXRefMaterial(); 95 base = XRefFunctions::getXRefMaterialSource((Mtl*)base); 96 if ( !base ) 97 return ExportNode::UNKNOWN; 98 } 99 100 101 // Modifiers are applied to the object, acquire the base object 102 while ( base->SuperClassID() == GEN_DERIVOB_CLASS_ID ) 103 { 104 IDerivedObject * derivedObject = ( IDerivedObject* ) base; 105 base = derivedObject->GetObjRef(); 106 } 107 108 109 110 SClass_ID superClassId = base->SuperClassID(); 111 112 Class_ID classId = base->ClassID(); 113 114 switch ( superClassId ) 115 { 116 case GEOMOBJECT_CLASS_ID: 117 { 118 // Check for a Max bone mesh 119 if ( classId == BONE_OBJ_CLASSID ) 120 return ExportNode::BONE; 121 122 // Check for biped 123 Control* control = iNode->GetTMController(); 124 125 if ( control ) 126 { 127 Class_ID controllerClassId = control->ClassID(); 128 129 if ( controllerClassId == BIPSLAVE_CONTROL_CLASS_ID 130 || controllerClassId == BIPBODY_CONTROL_CLASS_ID 131 || controllerClassId == FOOTPRINT_CLASS_ID 132 #ifdef MAX_2008_OR_NEWER 133 || controllerClassId == BIPED_CLASS_ID 134 #endif 135 ) 136 return ExportNode::BONE; 137 } 138 return ExportNode::MESH; 139 } 140 case CAMERA_CLASS_ID: 141 return CAMERA; 142 143 case LIGHT_CLASS_ID: 144 return LIGHT; 145 //for surfaces 146 case SHAPE_CLASS_ID: 147 // Modifiers can act on a spline to produce a mesh 148 if (animatable != base) 149 { 150 // We use a mesh here 151 return MESH; 152 // BUG368: For some reason the CanConvertToType function stopped working. 153 // This is the best option anyway, evaluate the object actually created by 154 // the modifier stack. 155 ObjectState os = ((IDerivedObject*)animatable)->Eval(0); 156 // return Get(node, os.obj, detectXRef); 157 } 158 if (classId == EDITABLE_SURF_CLASS_ID || classId == EDITABLE_CVCURVE_CLASS_ID || classId == EDITABLE_FPCURVE_CLASS_ID) 159 { 160 return MESH; 161 // We do not support NURBS here and use mesh instead 162 //return NURBS_CURVE; 163 } 164 if (classId == Class_ID(HELIX_CLASS_ID, 0)) 165 { 166 // TODO export helix as <geometry>/<mesh>/<linestrips> 167 GetCOREInterface()->Log()->LogEntry(SYSLOG_WARN, FALSE, _M("OpenCOLLADA export"), _M("Helix node type is not supported. Node not exported.")); 168 return ExportNode::UNKNOWN; 169 } 170 return SPLINE; 171 case HELPER_CLASS_ID: 172 return (classId.PartA() == BONE_CLASS_ID) ? BONE : HELPER; 173 174 case MATERIAL_CLASS_ID: 175 return MATERIAL; 176 177 } 178 return ExportNode::UNKNOWN; 179 } 180 181 182 //--------------------------------------------------------------- determineType()183 void ExportNode::determineType() 184 { 185 mType = determineType ( mINode ); 186 } 187 188 //--------------------------------------------------------------- addSymbol(Mtl * material,const String & symbol)189 void ExportNode::addSymbol ( Mtl * material, const String & symbol ) 190 { 191 // TODO: should be tested with multiple (composite?) materials 192 bool found = false; 193 194 MeshSymbolMap::const_iterator it = mMeshSymbolMap.find( material ); 195 if ( it!=mMeshSymbolMap.end() ) 196 { 197 if ( it->second.name==symbol ) 198 { 199 found = true; 200 } 201 } 202 203 if (!found) 204 { 205 Symbol newSymbol; 206 newSymbol.used = false; 207 newSymbol.name = mSymbolList.addId ( symbol ); 208 mMeshSymbolMap[ material ] = newSymbol; 209 } 210 } 211 212 213 214 //--------------------------------------------------------------- getSymbolByMaterialAndSetAsUsed(Mtl * material)215 const String& ExportNode::getSymbolByMaterialAndSetAsUsed ( Mtl* material ) 216 { 217 MeshSymbolMap::iterator it = mMeshSymbolMap.find ( material ); 218 219 assert ( it != mMeshSymbolMap.end() ); 220 221 it->second.used = true; 222 223 return it->second.name; 224 } 225 226 //--------------------------------------------------------------- createControllerList()227 void ExportNode::createControllerList() 228 { 229 if ( !mControllerList ) 230 mControllerList = new ControllerList(*this); 231 } 232 233 //--------------------------------------------------------------- getInitialPose() const234 Object* ExportNode::getInitialPose() const 235 { 236 Object* initialPose = 0; 237 238 if ( mControllerList ) 239 initialPose = mControllerList->getInitialPose(); 240 241 if ( !initialPose ) 242 initialPose = mINode->GetObjectRef(); 243 244 if ( getIsXRefObject() ) 245 return XRefFunctions::getXRefItemSource(initialPose); 246 else 247 return initialPose; 248 } 249 250 251 //--------------------------------------------------------------- getFinalPose() const252 Object* ExportNode::getFinalPose() const 253 { 254 if ( !hasControllers() ) 255 return 0; 256 return mControllerList->getController(0)->getPoseAfter(); 257 } 258 259 260 //--------------------------------------------------------------- getLastControllerId() const261 String ExportNode::getLastControllerId() const 262 { 263 if ( !hasControllers() ) 264 return COLLADASW::Utils::EMPTY_STRING; 265 266 size_t controllerCount = mControllerList->getControllerCount(); 267 return ControllerExporter::getControllerId(*this, controllerCount, mControllerList->getController(0)->getType()); 268 } 269 270 //--------------------------------------------------------------- getLastController() const271 Controller* ExportNode::getLastController() const 272 { 273 if ( !hasControllers() ) 274 return 0; 275 return mControllerList->getController(0); 276 } 277 } 278