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