7 // Revision 1.1 2005/01/18 19:11:00 waker
10 // Revision 1.1.1.1 2005/01/03 15:21:07 waker
13 // Revision 1.15 2004/11/10 01:22:10 waker
14 // added lightmap support
16 // Revision 1.14 2003/12/19 20:09:18 waker
17 // added progress bar (really useless on hi-poly models not split up into separate objects)
19 // Revision 1.13 2003/06/09 13:10:43 waker
20 // exports to right fmt (additional parenthesis w/ mtl name)
22 // Revision 1.12 2002/12/02 11:05:26 waker
23 // added parent check in animation controller export
25 // Revision 1.11 2002/12/02 10:57:47 waker
26 // INode::GetObjTMAfterWSM is used instead of INode::GetNodeTM
28 // Revision 1.10 2002/11/23 16:07:54 waker
29 // going home, saving changes
32 #define FEXPORT_CLASS_ID Class_ID(0x770130b9, 0x5a8d06cc)
34 class FExport
: public SceneExport
{
37 static BOOL CALLBACK
ParmsDlgProc( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
39 //Constructor/Destructor
42 BOOL
SupportsOptions( int ext
, DWORD options
) { return ( options
& SCENE_EXPORT_SELECTED
) ? TRUE
: FALSE
; }
43 int ExtCount( void ) { return 1; }
44 const TCHAR
*Ext( int i
) { return _T( "mdl" ); }
45 const TCHAR
*LongDesc( void ) { return _T( "fe model and animation exporter" ); }
46 const TCHAR
*ShortDesc( void ) { return _T( "fe model" ); }
47 const TCHAR
*AuthorName( void ) { return _T( "[_WaKeR_]" ); }
48 const TCHAR
*CopyrightMessage( void ) { return _T( "" ); }
49 const TCHAR
*OtherMessage1( void ) { return _T( "" ); }
50 const TCHAR
*OtherMessage2( void ) { return _T( "" ); }
51 unsigned int Version( void ) { return 1; }
52 void ShowAbout( HWND hWnd
) {}
61 typedef std::map
< Mtl
*, int > MtlMap
;
63 std::vector
< ExpMtl
> mtlList
;
65 typedef std::vector
< INode
* > boneList
;
69 enum nodeType
{ none
, tri
, light
, dummy
};
82 for ( size_t i
= 0; i
< children
.size(); i
++ )
88 std::map
< std::string
, std::string
> props
;
101 std::vector
< Point3
> verts
; // indexed by faces
102 std::vector
< Point3
> colors
; // indexed by colorFaces
103 std::vector
< boneList
> boneAssignments
; // indexed by faces if present
104 std::vector
< Point3
> normals
; // indexed by normalFaces
105 std::vector
< Point2
> uvVerts
; // indexed by uvFaces
106 std::vector
< Point2
> uvLightmap
; // indexed by uvLightmapFaces if present
108 std::vector
< Face
> faces
;
109 std::vector
< Face
> colorFaces
;
110 std::vector
< Face
> normalFaces
;
111 std::vector
< Face
> uvFaces
;
112 std::vector
< Face
> uvLightmapFaces
;
114 std::vector
< int > mtlIndex
;
116 std::vector
< ExpNode
* > children
;
118 float animSpeed
; // frames per second (or matrices per second, or whatever..)
119 std::vector
< Matrix3
> animFrames
;
122 ExpNode
* rootExpNode
;
123 Interface
* pInterface
;
125 int DoExport( const TCHAR
*name
, ExpInterface
*ei
, Interface
*i
, BOOL suppressPrompts
, DWORD options
)
132 // BOOL res = DialogBox( hInstance, MAKEINTRESOURCE( IDD_PARMS ), i->GetMAXHWnd(), ParmsDlgProc );
134 ExportScene( i
, fname
, options
);
138 // dummy progress func
139 static DWORD WINAPI
fn(LPVOID arg
)
{
return 0;
}
140 void ExportScene( Interface
*ip
, const TSTR
&fname
, DWORD options
)
143 TCHAR df
[_MAX_FNAME
];
145 BMMSplitFilename( fname
.data(), dp
, df
, de
);
148 ExportMaterials( ip
->GetRootNode(), df
, options
, numberOfNodes
);
151 // Startup the progress bar.
152 ip
->ProgressStart( _T( "Exporting FE model file..." ), TRUE
, fn
, NULL
);
154 if ( ExportGeometry( rootExpNode
, ip
->GetRootNode(), df
, options
, 0 ) )
167 void Save( const TSTR
&fname
)
170 fp
= _tfopen( fname
.data(), _T( "w+t" ) );
176 SaveNode( fp
, rootExpNode
);
181 void SaveMaterials( FILE *fp
)
183 if ( mtlList
.size() )
185 for ( int i
= 0; i
< (int)mtlList
.size(); i
++ )
187 FILE *fp
= _tfopen( ( mtlList
[i
].name
+ _T( ".fmtl" ) ).data(), _T( "w+t" ) );
192 _ftprintf( fp
, _T( "\"%s\" {\n" ), mtlList
[i
].name
);
193 _ftprintf( fp
, _T( "\teffectfile effects/simple.fx\n" ) );
194 if ( mtlList
[i
].textureName
.Length() )
195 _ftprintf( fp
, _T( "\ttexinput basetexture \"%s\"\n" ), mtlList
[i
].textureName
.data() );
196 _ftprintf( fp
, _T( "}\n" ) );
201 // write materials to textfile
202 _ftprintf( fp
, _T( "materials {\n" ) );
203 for ( int i
= 0; i
< (int)mtlList
.size(); i
++ )
205 _ftprintf( fp
, _T( "\t\"materials/%s\"\n" ), mtlList
[i
].name
);
207 _ftprintf( fp
, _T( "}\n\n" ) );
211 void SaveNode( FILE *fp
, ExpNode
*node
, const TSTR
&indent
= _T( "" ) )
215 assert( node
->children
.empty() );
216 return; // shouldn't have children
219 TSTR ind
= indent
+ _T( "\t" );
222 if ( node
->type
== tri
)
223 _ftprintf( fp
, _T( "%striobject \"%s\" {\n" ), indent
.data(), node
->node
->GetName() );
224 else if ( node
->type
== light
)
225 _ftprintf( fp
, _T( "%sentity \"%s\" {\n" ), indent
.data(), node
->node
->GetName() );
226 else if ( node
->type
== dummy
)
227 _ftprintf( fp
, _T( "%sdummy \"%s\" {\n" ), indent
.data(), node
->node
->GetName() );
231 _stprintf( str
, _T( "node '%s' has no correct type assignment. will be written as dummy." ), node
->node
->GetName() );
233 _ftprintf( fp
, _T( "%sdummy \"%s\" {\n" ), indent
.data(), node
->node
->GetName() );
238 Matrix3 nodeTM
= node
->node
->GetObjTMAfterWSM( 0 );
239 if ( node
->node
->GetParentNode() )
240 nodeTM
= nodeTM
* Inverse( node
->node
->GetParentNode()->GetObjTMAfterWSM( 0 ) );
241 Point3 x
= nodeTM
.GetRow( 0 );
242 Point3 y
= nodeTM
.GetRow( 1 );
243 Point3 z
= nodeTM
.GetRow( 2 );
244 m
[0][0] = x
.x
; m
[0][1] = x
.z
; m
[0][2] = x
.y
; m
[0][3] = 0;
245 m
[1][0] = z
.x
; m
[1][1] = z
.z
; m
[1][2] = z
.y
; m
[1][3] = 0;
246 m
[2][0] = y
.x
; m
[2][1] = y
.z
; m
[2][2] = y
.y
; m
[2][3] = 0;
247 m
[3][0] = nodeTM
.GetTrans().x
; m
[3][1] = nodeTM
.GetTrans().z
; m
[3][2] = nodeTM
.GetTrans().y
; m
[3][3] = 1;
249 _ftprintf( fp
, _T( "%snodeTransform {\n" ), ind
.data() );
250 _ftprintf( fp
, _T( "%s\t%f %f %f\n" ), ind
.data(), m
[0][0], m
[0][1], m
[0][2] );
251 _ftprintf( fp
, _T( "%s\t%f %f %f\n" ), ind
.data(), m
[1][0], m
[1][1], m
[1][2] );
252 _ftprintf( fp
, _T( "%s\t%f %f %f\n" ), ind
.data(), m
[2][0], m
[2][1], m
[2][2] );
253 _ftprintf( fp
, _T( "%s\t%f %f %f\n" ), ind
.data(), m
[3][0], m
[3][1], m
[3][2] );
254 _ftprintf( fp
, _T( "%s}\n" ), ind
.data() );
256 if ( node
->type
== tri
&& node
->verts
.size() )
259 _ftprintf( fp
, _T( "%sverts {\n" ), ind
.data() );
260 _ftprintf( fp
, _T( "%s\tcount %d\n" ), ind
.data(), (int)node
->verts
.size() );
261 for ( i
= 0; i
< (int)node
->verts
.size(); i
++ )
263 _ftprintf( fp
, _T( "%s\tv %f %f %f\n" ), ind
.data(), node
->verts
[i
].x
, node
->verts
[i
].y
, node
->verts
[i
].z
);
265 _ftprintf( fp
, _T( "%s}\n" ), ind
.data() );
268 _ftprintf( fp
, _T( "%sfaces {\n" ), ind
.data() );
269 _ftprintf( fp
, _T( "%s\tcount %d\n" ), ind
.data(), (int)node
->faces
.size() );
270 for ( i
= 0; i
< (int)node
->faces
.size(); i
++ )
272 _ftprintf( fp
, _T( "%s\tf %d %d %d\n" ), ind
.data(), node
->faces
[i
].v
[0], node
->faces
[i
].v
[1], node
->faces
[i
].v
[2] );
274 _ftprintf( fp
, _T( "%s}\n" ), ind
.data() );
277 _ftprintf( fp
, _T( "%scolors {\n" ), ind
.data() );
278 _ftprintf( fp
, _T( "%s\tcount %d\n" ), ind
.data(), (int)node
->colors
.size() );
279 for ( i
= 0; i
< (int)node
->colors
.size(); i
++ )
281 _ftprintf( fp
, _T( "%s\tv %f %f %f\n" ), ind
.data(), node
->colors
[i
].x
, node
->colors
[i
].y
, node
->colors
[i
].z
);
283 _ftprintf( fp
, _T( "%s}\n" ), ind
.data() );
286 _ftprintf( fp
, _T( "%scolorFaces {\n" ), ind
.data() );
287 _ftprintf( fp
, _T( "%s\tcount %d\n" ), ind
.data(), (int)node
->colorFaces
.size() );
288 for ( i
= 0; i
< (int)node
->colorFaces
.size(); i
++ )
290 _ftprintf( fp
, _T( "%s\tf %d %d %d\n" ), ind
.data(), node
->colorFaces
[i
].v
[0], node
->colorFaces
[i
].v
[1], node
->colorFaces
[i
].v
[2] );
292 _ftprintf( fp
, _T( "%s}\n" ), ind
.data() );
295 _ftprintf( fp
, _T( "%snormals {\n" ), ind
.data() );
296 _ftprintf( fp
, _T( "%s\tcount %d\n" ), ind
.data(), (int)node
->normals
.size() );
297 for ( i
= 0; i
< (int)node
->normals
.size(); i
++ )
299 _ftprintf( fp
, _T( "%s\tv %f %f %f\n" ), ind
.data(), node
->normals
[i
].x
, node
->normals
[i
].y
, node
->normals
[i
].z
);
301 _ftprintf( fp
, _T( "%s}\n" ), ind
.data() );
304 _ftprintf( fp
, _T( "%snormalFaces {\n" ), ind
.data() );
305 _ftprintf( fp
, _T( "%s\tcount %d\n" ), ind
.data(), (int)node
->normalFaces
.size() );
306 for ( i
= 0; i
< (int)node
->normalFaces
.size(); i
++ )
308 _ftprintf( fp
, _T( "%s\tf %d %d %d\n" ), ind
.data(), node
->normalFaces
[i
].v
[0], node
->normalFaces
[i
].v
[1], node
->normalFaces
[i
].v
[2] );
310 _ftprintf( fp
, _T( "%s}\n" ), ind
.data() );
312 if ( node
->uvVerts
.size() )
315 _ftprintf( fp
, _T( "%suvVerts {\n" ), ind
.data() );
316 _ftprintf( fp
, _T( "%s\tcount %d\n" ), ind
.data(), (int)node
->uvVerts
.size() );
317 for ( i
= 0; i
< (int)node
->uvVerts
.size(); i
++ )
319 _ftprintf( fp
, _T( "%s\tv %f %f\n" ), ind
.data(), node
->uvVerts
[i
].x
, node
->uvVerts
[i
].y
);
321 _ftprintf( fp
, _T( "%s}\n" ), ind
.data() );
324 _ftprintf( fp
, _T( "%suvFaces {\n" ), ind
.data() );
325 _ftprintf( fp
, _T( "%s\tcount %d\n" ), ind
.data(), (int)node
->uvFaces
.size() );
326 for ( i
= 0; i
< (int)node
->uvFaces
.size(); i
++ )
328 _ftprintf( fp
, _T( "%s\tf %d %d %d\n" ), ind
.data(), node
->uvFaces
[i
].v
[0], node
->uvFaces
[i
].v
[1], node
->uvFaces
[i
].v
[2] );
330 _ftprintf( fp
, _T( "%s}\n" ), ind
.data() );
333 if ( node
->uvLightmap
.size() )
336 _ftprintf( fp
, _T( "%suvLightmap {\n" ), ind
.data() );
337 _ftprintf( fp
, _T( "%s\tcount %d\n" ), ind
.data(), (int)node
->uvLightmap
.size() );
338 for ( i
= 0; i
< (int)node
->uvLightmap
.size(); i
++ )
340 _ftprintf( fp
, _T( "%s\tv %f %f\n" ), ind
.data(), node
->uvLightmap
[i
].x
, node
->uvLightmap
[i
].y
);
342 _ftprintf( fp
, _T( "%s}\n" ), ind
.data() );
345 _ftprintf( fp
, _T( "%suvLightmapFaces {\n" ), ind
.data() );
346 _ftprintf( fp
, _T( "%s\tcount %d\n" ), ind
.data(), (int)node
->uvLightmapFaces
.size() );
347 for ( i
= 0; i
< (int)node
->uvLightmapFaces
.size(); i
++ )
349 _ftprintf( fp
, _T( "%s\tf %d %d %d\n" ), ind
.data(), node
->uvLightmapFaces
[i
].v
[0], node
->uvLightmapFaces
[i
].v
[1], node
->uvLightmapFaces
[i
].v
[2] );
351 _ftprintf( fp
, _T( "%s}\n" ), ind
.data() );
354 if ( node
->mtlIndex
.size() )
357 _ftprintf( fp
, _T( "%smtlIndex {\n" ), ind
.data() );
358 _ftprintf( fp
, _T( "%s\tcount %d\n" ), ind
.data(), (int)node
->mtlIndex
.size() );
359 for ( i
= 0; i
< (int)node
->mtlIndex
.size(); i
++ )
361 _ftprintf( fp
, _T( "%s\tf %d\n" ), ind
.data(), node
->mtlIndex
[i
] );
363 _ftprintf( fp
, _T( "%s}\n" ), ind
.data() );
366 if ( false == node
->animFrames
.empty() )
369 _ftprintf( fp
, _T( "%sanimation {\n" ), ind
.data() );
370 _ftprintf( fp
, _T( "%s\tframeRate %f\n" ), ind
.data(), node
->animSpeed
);
371 _ftprintf( fp
, _T( "%s\tnumFrames %d\n" ), ind
.data(), (int)node
->animFrames
.size() );
372 for ( i
= 0; i
< (int)node
->animFrames
.size(); i
++ )
375 _ftprintf( fp
, _T( "%s\ttime %f transform " ), ind
.data(), i
* TicksToSec( GetTicksPerFrame() ) );
377 Matrix3
&nodeTM
= node
->animFrames
[i
];
378 Point3 x
= nodeTM
.GetRow( 0 );
379 Point3 y
= nodeTM
.GetRow( 1 );
380 Point3 z
= nodeTM
.GetRow( 2 );
381 m
[0][0] = x
.x
; m
[0][1] = x
.z
; m
[0][2] = x
.y
; m
[0][3] = 0;
382 m
[1][0] = z
.x
; m
[1][1] = z
.z
; m
[1][2] = z
.y
; m
[1][3] = 0;
383 m
[2][0] = y
.x
; m
[2][1] = y
.z
; m
[2][2] = y
.y
; m
[2][3] = 0;
384 m
[3][0] = nodeTM
.GetTrans().x
; m
[3][1] = nodeTM
.GetTrans().z
; m
[3][2] = nodeTM
.GetTrans().y
; m
[3][3] = 1;
385 _ftprintf( fp
, _T( "%f %f %f " ), m
[0][0], m
[0][1], m
[0][2] );
386 _ftprintf( fp
, _T( "%f %f %f " ), m
[1][0], m
[1][1], m
[1][2] );
387 _ftprintf( fp
, _T( "%f %f %f " ), m
[2][0], m
[2][1], m
[2][2] );
388 _ftprintf( fp
, _T( "%f %f %f\n" ), m
[3][0], m
[3][1], m
[3][2] );
390 _ftprintf( fp
, _T( "%s}\n" ), ind
.data() );
393 else if ( node
->type
== light
)
395 std::map
< std::string
, std::string
>::iterator it
;
396 for ( it
= node
->lightentity
.props
.begin(); it
!= node
->lightentity
.props
.end(); it
++ )
398 _ftprintf( fp
, _T( "%sprop \"%s\" \"%s\"\n" ), ind
.data(), (*it
).first
.c_str(), (*it
).second
.c_str() );
403 for ( i
= 0; i
< (int)node
->children
.size(); i
++ )
405 SaveNode( fp
, node
->children
[i
], ind
);
408 _ftprintf( fp
, _T( "%s}\n" ), indent
.data() );
411 void ExportMaterials( INode
*node
, const TSTR
&parentName
, DWORD options
, int &numNodes
)
414 if ( !( options
& SCENE_EXPORT_SELECTED
) || ( node
->Selected() ) )
416 if ( node
->GetMtl() )
417 ExportMaterial( node
->GetMtl(), parentName
);
419 for ( int i
= 0; i
< node
->NumberOfChildren(); i
++ )
420 ExportMaterials( node
->GetChildNode( i
), parentName
, options
, numNodes
);
423 void ExportMaterial( Mtl
*mtl
, const TSTR
&parentName
)
425 if ( mtl
->ClassID() == Class_ID( MULTI_CLASS_ID
, 0 ) )
427 TSTR name
= parentName
+ _T( "_" ) + mtl
->GetName();
428 for ( int i
= 0; i
< mtl
->NumSubMtls(); i
++ )
429 ExportMaterial( mtl
->GetSubMtl( i
), name
);
431 else if ( mtl
->ClassID() == Class_ID( DMTL_CLASS_ID
, 0 ) )
433 ExportStdMat( mtl
, parentName
);
437 void ExportStdMat( Mtl
*mtl
, const TSTR
&parentName
)
439 MtlMap::iterator it
= mtlIndex
.find( mtl
);
440 if ( it
!= mtlIndex
.end() )
443 StdMat
*stdMtl
= ( StdMat
* )mtl
;
446 m
.name
= parentName
+ _T( "_" ) + mtl
->GetName();
448 Texmap
*tmap
= stdMtl
->GetSubTexmap( ID_DI
);
451 // return; // do not export texture-less materials
453 if ( !tmap
|| tmap
->ClassID() != Class_ID( BMTEX_CLASS_ID
, 0 ) )
455 // return; // unsupported texmap class
460 BitmapTex
*bmt
= ( BitmapTex
* ) tmap
;
461 TextureOutput
*tout
= bmt
->GetTexout();
462 texname
= bmt
->GetMapName();
464 TCHAR df
[_MAX_FNAME
];
466 BMMSplitFilename( texname
, dp
, df
, de
);
467 m
.textureName
= TSTR( df
) + TSTR( de
);
470 mtlIndex
[mtl
] = (int)mtlList
.size();
471 mtlList
.push_back( m
);
474 bool ExportGeometry( ExpNode
*parentNode
, INode
*node
, const TSTR
&parentName
, DWORD options
, int numNodes
, bool parentDiscard
= false )
476 if ( GetCOREInterface()->GetCancel() )
482 ExpNode
*n
= new ExpNode
;
488 rootExpNode
->children
.push_back( n
);
490 parentNode
->children
.push_back( n
);
494 TriObject
*o
= GetTriObjectFromNode( node
, 0, del
);
498 if ( ( options
& SCENE_EXPORT_SELECTED
) && ( !node
->Selected() ) )
501 parentDiscard
= true; // all selected children will be attached to the root node
506 Matrix3 nodeTM
= node
->GetObjTMAfterWSM(0);
508 if (!nodeTM
.Parity())
509 { order
[0]=0; order
[1]=1; order
[2]=2; }
511 { order
[0]=2; order
[1]=1; order
[2]=0; }
513 // export geometry info (verts, normals, etc)
514 Mesh
&mesh
= o
->GetMesh();
519 n
->verts
.resize( mesh
.getNumVerts() );
520 for ( i
= 0; i
< ( int )n
->verts
.size(); i
++ )
522 n
->verts
[i
].x
= mesh
.verts
[i
].x
;
523 n
->verts
[i
].y
= mesh
.verts
[i
].z
;
524 n
->verts
[i
].z
= mesh
.verts
[i
].y
;
526 n
->faces
.resize( mesh
.getNumFaces() );
527 // memcpy( &n->faces.front(), mesh.faces, n->faces.size() * sizeof( Face ) );
528 for ( i
= 0; i
< n
->faces
.size(); i
++ )
530 n
->faces
[i
].v
[0] = mesh
.faces
[i
].v
[order
[2]];
531 n
->faces
[i
].v
[1] = mesh
.faces
[i
].v
[order
[1]];
532 n
->faces
[i
].v
[2] = mesh
.faces
[i
].v
[order
[0]];
538 n
->colors
.resize( mesh
.getNumVertCol() );
539 for ( i
= 0; i
< (size_t)mesh
.getNumVertCol(); i
++ )
541 n
->colors
[i
] = mesh
.vertCol
[i
];
543 n
->colorFaces
.resize( mesh
.getNumFaces() );
544 for ( i
= 0; i
< (size_t)mesh
.getNumFaces(); i
++ )
546 n
->colorFaces
[i
].v
[0] = mesh
.vcFace
[i
].t
[order
[2]];
547 n
->colorFaces
[i
].v
[1] = mesh
.vcFace
[i
].t
[order
[1]];
548 n
->colorFaces
[i
].v
[2] = mesh
.vcFace
[i
].t
[order
[0]];
553 if ( 0 != mesh
.getNumTVerts() )
555 n
->uvVerts
.resize( mesh
.getNumTVerts() );
556 for ( i
= 0; i
< ( int )n
->uvVerts
.size(); i
++ )
558 n
->uvVerts
[i
].x
= mesh
.tVerts
[i
].x
;
559 n
->uvVerts
[i
].y
= 1 - mesh
.tVerts
[i
].y
;
561 n
->uvFaces
.resize( mesh
.getNumFaces() );
562 // memcpy( &n->uvFaces.front(), mesh.tvFace, n->faces.size() * sizeof( TVFace ) );
563 for ( i
= 0; i
< n
->uvFaces
.size(); i
++ )
565 n
->uvFaces
[i
].v
[0] = mesh
.tvFace
[i
].t
[order
[2]];
566 n
->uvFaces
[i
].v
[1] = mesh
.tvFace
[i
].t
[order
[1]];
567 n
->uvFaces
[i
].v
[2] = mesh
.tvFace
[i
].t
[order
[0]];
572 for (i
= 2; i
< MAX_MESHMAPS
; i
++)
574 if (mesh
.mapSupport (i
))
577 size_t nverts
= mesh
.getNumMapVerts (i
);
578 n
->uvLightmap
.resize (nverts
);
579 for (size_t vx
= 0; vx
< nverts
; vx
++)
581 n
->uvLightmap
[vx
].x
= mesh
.mapVerts (i
)[vx
].x
;
582 n
->uvLightmap
[vx
].y
= 1 - mesh
.mapVerts (i
)[vx
].y
;
585 n
->uvLightmapFaces
.resize( mesh
.getNumFaces() );
586 // memcpy( &n->uvFaces.front(), mesh.tvFace, n->faces.size() * sizeof( TVFace ) );
587 for (size_t f
= 0; f
< n
->uvLightmapFaces
.size(); f
++)
589 n
->uvLightmapFaces
[f
].v
[0] = mesh
.mapFaces (i
)[f
].t
[order
[2]];
590 n
->uvLightmapFaces
[f
].v
[1] = mesh
.mapFaces (i
)[f
].t
[order
[1]];
591 n
->uvLightmapFaces
[f
].v
[2] = mesh
.mapFaces (i
)[f
].t
[order
[0]];
598 std::vector
< Point3
> faceNormals
;
599 faceNormals
.resize( mesh
.getNumFaces() );
600 ExpNode::Face
*face
= &n
->faces
.front();
601 for ( i
= 0; i
< ( int )faceNormals
.size(); i
++, face
++ )
603 Point3 v0
= n
->verts
[face
->v
[order
[0]]];
604 Point3 v1
= n
->verts
[face
->v
[order
[1]]];
605 Point3 v2
= n
->verts
[face
->v
[order
[2]]];
606 Point3 norm
= ( v1
- v0
) ^ ( v2
- v1
);
607 faceNormals
[i
] = norm
;
611 std::vector
< std::vector
<int> > indexing
;
612 indexing
.resize( n
->verts
.size() );
613 face
= &n
->faces
.front();
614 for ( i
= 0; i
< n
->faces
.size(); i
++, face
++ )
616 indexing
[face
->v
[order
[0]]].push_back( (int)i
);
617 indexing
[face
->v
[order
[1]]].push_back( (int)i
);
618 indexing
[face
->v
[order
[2]]].push_back( (int)i
);
622 face
= &n
->faces
.front();
623 n
->normalFaces
.resize( n
->faces
.size() );
624 for ( i
= 0; i
< n
->faces
.size(); i
++, face
++ )
626 for ( int k
= 0; k
< 3; k
++ )
628 // calc normal for face's vertex
629 Point3 norm
= faceNormals
[i
];
630 std::vector
<int> &ind
= indexing
[face
->v
[order
[k
]]];
631 for ( int j
= 0; j
< (int)ind
.size(); j
++ )
633 if ( ind
[j
] != i
&& ( mesh
.faces
[i
].getSmGroup() & mesh
.faces
[ind
[j
]].getSmGroup() ) != 0 )
634 norm
+= faceNormals
[ind
[j
]];
636 norm
= norm
.Normalize();
638 // check for duplicate
639 std::vector
< Point3
>::iterator it
;
640 it
= std::find( n
->normals
.begin(), n
->normals
.end(), norm
);
641 int index
= (int)n
->normals
.size();
642 if ( it
!= n
->normals
.end() )
643 index
= it
- n
->normals
.begin();
645 n
->normals
.push_back( norm
);
646 n
->normalFaces
[i
].v
[order
[k
]] = index
;
650 // material assignments
651 Mtl
*mtl
= node
->GetMtl();
654 n
->mtlIndex
.resize( mesh
.getNumFaces() );
655 for ( i
= 0; i
< (size_t)mesh
.getNumFaces(); i
++ )
658 if ( mtl
->IsMultiMtl() )
659 it
= mtlIndex
.find( mtl
->GetSubMtl( mesh
.faces
[i
].getMatID() % mtl
->NumSubMtls() ) );
661 it
= mtlIndex
.find( mtl
);
663 if ( it
== mtlIndex
.end() )
666 n
->mtlIndex
[i
] = ( *it
).second
;
676 // can be light or dummy
677 ObjectState state
= node
->EvalWorldState(0);
678 if ( state
.obj
&& state
.obj
->SuperClassID() == LIGHT_CLASS_ID
)
680 n
->lightentity
.props
[_T( "classname" )] = _T( "light" );
682 TCHAR str
[256]; // required to do some formatting. unsafe!
684 GenLight
*lightObj
=(GenLight
*)state
.obj
;
685 if ( lightObj
->GetUseLight() == FALSE
)
686 n
->lightentity
.props
[_T( "disabled" )] = _T( "1" );
687 ObjLightDesc
*ld
= lightObj
->CreateLightDesc( node
);
689 // export diffuse color
690 // TODO: export color animation controller
691 Color rgb
=lightObj
->GetRGBColor(0);
692 _stprintf( str
, _T( "%.2f %.2f %.2f" ), rgb
.r
, rgb
.g
, rgb
.b
);
693 n
->lightentity
.props
[ _T( "diffusecolor" ) ] = str
;
696 // multiplier = lightObj->GetIntensity( 0 );
699 int type
=lightObj
->Type();
703 n
->lightentity
.props
[ _T( "type" ) ] = _T( "omni" );
707 n
->lightentity
.props
[ _T( "type" ) ] = _T( "spot" );
711 n
->lightentity
.props
[ _T( "type" ) ] = _T( "dir" );
714 _stprintf( str
, _T( "light '%s' has unknown type and will be treated as dummy object." ), node
->GetName() );
719 // export atten and range
720 float atten
[3] = { 1, 0, 0 };
721 float range
= 1.0e+5f
;
722 if ( lightObj
->GetUseAtten() )
724 range
= lightObj
->GetAtten(0, ATTEN_END
);
726 atten
[1] = 1.f
/ ( lightObj
->GetAtten( 0, ATTEN_END
) - lightObj
->GetAtten( 0, ATTEN_START
) );
727 atten
[2] = atten
[1] * atten
[1];
729 _stprintf( str
, _T( "%.2f" ), range
);
730 n
->lightentity
.props
[ _T( "range" ) ] = str
;
731 _stprintf( str
, _T( "%.2f %.2f %.2f" ), atten
[0], atten
[1], atten
[2] );
732 n
->lightentity
.props
[ _T( "atten" ) ] = str
;
734 // get shadowcasting parms
735 n
->lightentity
.props
[ _T( "castshadows" ) ] = lightObj
->GetShadow() ? _T( "1" ) : _T( "0" );
737 #if 0 // FIXME: uncomment this if matrix stuff doesn't apply
738 // get direction (from matrix or directly from light)
739 if ( type
!= OMNI_LIGHT
)
741 Point3 pos
=node
->GetObjTMAfterWSM(0).GetTrans();
742 position
= Point3( pos
.x
, pos
.z
, pos
.y
);
743 INode
*target
=node
->GetTarget();
747 Point3 t
=target
->GetObjTMAfterWSM(0).GetTrans();
748 direction
= Point3( t
.x
, t
.z
, t
.y
);
749 direction
-= position
;
750 direction
= Normalize( direction
);
754 Point4 at
= node
->GetObjTMAfterWSM(0).GetColumn( 1 );
755 direction
= Point3( at
.x
, at
.z
, at
.y
);
756 direction
= Normalize( direction
);
758 _stprintf( str
, _T( "%.2f %.2f %.2f" ), direction
[0], direction
[1], direction
[2] );
759 n
->lightentity
.props
[ _T( "direction" ) ] = str
;
762 if ( type
== TSPOT_LIGHT
|| type
== FSPOT_LIGHT
)
764 float theta
= lightObj
->GetHotspot(0) * 3.14159f
/ 360.f
;
765 float phi
= lightObj
->GetFallsize(0) * 3.14159f
/ 360.f
;
766 float falloff
= 1.f
; // FIXME: does 3dsmax has an analogue?
767 _stprintf( str
, _T( "%.2f" ), theta
);
768 n
->lightentity
.props
[ _T( "theta" ) ] = str
;
769 _stprintf( str
, _T( "%.2f" ), theta
);
770 n
->lightentity
.props
[ _T( "phi" ) ] = str
;
771 _stprintf( str
, _T( "%.2f" ), falloff
);
772 n
->lightentity
.props
[ _T( "falloff" ) ] = str
;
778 // dummy has no additional attributes
783 if ( !ExportAnim( node
, n
->animFrames
) )
784 n
->animFrames
.clear();
787 n
->animSpeed
= GetFrameRate();
790 GetCOREInterface()->ProgressUpdate((int)((float)numNodes
/numberOfNodes
*100.0f
));
792 for ( int i
= 0; i
< node
->NumberOfChildren(); i
++ )
794 if ( !ExportGeometry( n
, node
->GetChildNode( i
), parentName
, options
, numNodes
, parentDiscard
) )
801 #define ALMOST_ZERO 1.0e-3f
802 // Not truly the correct way to compare floats of arbitary magnitude...
803 bool EqualPoint3( const Point3
&p1
, const Point3
&p2
)
805 if (fabs(p1
.x
- p2
.x
) > ALMOST_ZERO
)
807 if (fabs(p1
.y
- p2
.y
) > ALMOST_ZERO
)
809 if (fabs(p1
.z
- p2
.z
) > ALMOST_ZERO
)
815 bool ExportAnim( INode
*node
, std::vector
<Matrix3
> &frames
)
817 TimeValue start
= pInterface
->GetAnimRange().Start();
818 TimeValue end
= pInterface
->GetAnimRange().End();
820 int delta
= GetTicksPerFrame();
823 bool animated
= false;
825 for ( t
= start
; t
<= end
; t
+= delta
)
827 tm
= node
->GetParentNode() ? node
->GetObjTMAfterWSM( t
) * Inverse( node
->GetParentNode()->GetObjTMAfterWSM( t
) ) : node
->GetObjTMAfterWSM( t
);
830 if ( !EqualPoint3( tm
.GetRow( 0 ), startTM
.GetRow( 0 ) ) )
832 if ( !EqualPoint3( tm
.GetRow( 1 ), startTM
.GetRow( 1 ) ) )
834 if ( !EqualPoint3( tm
.GetRow( 2 ), startTM
.GetRow( 2 ) ) )
836 if ( !EqualPoint3( tm
.GetTrans(), startTM
.GetTrans() ) )
841 frames
.push_back( tm
);
846 TriObject
* GetTriObjectFromNode( INode
*pNode
, TimeValue t
, bool &bDeleteIt
)
849 Object
*obj
= pNode
->EvalWorldState( t
).obj
;
850 if ( obj
&& obj
->CanConvertToType( Class_ID( TRIOBJ_CLASS_ID
, 0 ) ) ) {
851 TriObject
*tri
= ( TriObject
* )obj
->ConvertToType( t
, Class_ID( TRIOBJ_CLASS_ID
, 0 ) );
852 if ( obj
!= tri
) bDeleteIt
= true;
858 void warning( TCHAR
*str
)
860 ::MessageBox( pInterface
->GetMAXHWnd(), str
, "fexport warning", MB_OK
| MB_ICONINFORMATION
);
864 BOOL CALLBACK
FExport::ParmsDlgProc( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
871 switch ( LOWORD( wParam
) )
874 EndDialog( hwnd
, TRUE
);
877 EndDialog( hwnd
, FALSE
);
887 class FExportClassDesc
:public ClassDesc2
{
889 int IsPublic() {return 1;}
890 void * Create(BOOL loading
= FALSE
) {return new FExport();}
891 const TCHAR
* ClassName() {return GetString(IDS_CLASS_NAME
);}
892 SClass_ID
SuperClassID() {return SCENE_EXPORT_CLASS_ID
;}
893 Class_ID
ClassID() {return FEXPORT_CLASS_ID
;}
894 const TCHAR
* Category() {return GetString(IDS_CATEGORY
);}
895 const TCHAR
* InternalName() { return _T("FExport"); } // returns fixed parsable name (scripter-visible name)
896 HINSTANCE
HInstance() { return hInstance
; } // returns owning module handle
899 static FExportClassDesc FExportDesc
;
900 ClassDesc2
* GetFExportDesc() {return &FExportDesc
;}