Panda3D
|
00001 // Filename: daeToEggConverter.cxx 00002 // Created by: pro-rsoft (08May08) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "daeToEggConverter.h" 00016 #include "fcollada_utils.h" 00017 #include "config_daeegg.h" 00018 #include "daeCharacter.h" 00019 #include "dcast.h" 00020 #include "string_utils.h" 00021 #include "eggData.h" 00022 #include "eggPrimitive.h" 00023 #include "eggLine.h" 00024 #include "eggPolygon.h" 00025 #include "eggTriangleFan.h" 00026 #include "eggTriangleStrip.h" 00027 #include "eggPoint.h" 00028 #include "eggXfmSAnim.h" 00029 #include "eggSAnimData.h" 00030 #include "pt_EggVertex.h" 00031 00032 #include "FCDocument/FCDAsset.h" 00033 #include "FCDocument/FCDocumentTools.h" 00034 #include "FCDocument/FCDSceneNode.h" 00035 #include "FCDocument/FCDSceneNodeTools.h" 00036 #include "FCDocument/FCDGeometry.h" 00037 #include "FCDocument/FCDGeometryInstance.h" 00038 #include "FCDocument/FCDGeometryPolygons.h" 00039 #include "FCDocument/FCDGeometrySource.h" 00040 #include "FCDocument/FCDSkinController.h" 00041 #include "FCDocument/FCDController.h" 00042 #include "FCDocument/FCDControllerInstance.h" 00043 #include "FCDocument/FCDMorphController.h" 00044 #include "FCDocument/FCDMaterialInstance.h" 00045 #include "FCDocument/FCDExtra.h" 00046 #include "FCDocument/FCDEffect.h" 00047 #include "FCDocument/FCDEffectStandard.h" 00048 #if FCOLLADA_VERSION >= 0x00030005 00049 #include "FCDocument/FCDGeometryPolygonsInput.h" 00050 #endif 00051 00052 //////////////////////////////////////////////////////////////////// 00053 // Function: DAEToEggConverter::Constructor 00054 // Access: Public 00055 // Description: 00056 //////////////////////////////////////////////////////////////////// 00057 DAEToEggConverter:: 00058 DAEToEggConverter() { 00059 _document = NULL; 00060 _table = NULL; 00061 _frame_rate = -1; 00062 _error_handler = NULL; 00063 } 00064 00065 //////////////////////////////////////////////////////////////////// 00066 // Function: DAEToEggConverter::Copy Constructor 00067 // Access: Public 00068 // Description: 00069 //////////////////////////////////////////////////////////////////// 00070 DAEToEggConverter:: 00071 DAEToEggConverter(const DAEToEggConverter ©) : 00072 SomethingToEggConverter(copy) 00073 { 00074 } 00075 00076 //////////////////////////////////////////////////////////////////// 00077 // Function: DAEToEggConverter::Destructor 00078 // Access: Public 00079 // Description: 00080 //////////////////////////////////////////////////////////////////// 00081 DAEToEggConverter:: 00082 ~DAEToEggConverter() { 00083 if (_error_handler != NULL) { 00084 delete _error_handler; 00085 } 00086 } 00087 00088 //////////////////////////////////////////////////////////////////// 00089 // Function: DAEToEggConverter::make_copy 00090 // Access: Public, Virtual 00091 // Description: Allocates and returns a new copy of the converter. 00092 //////////////////////////////////////////////////////////////////// 00093 SomethingToEggConverter *DAEToEggConverter:: 00094 make_copy() { 00095 return new DAEToEggConverter(*this); 00096 } 00097 00098 00099 //////////////////////////////////////////////////////////////////// 00100 // Function: DAEToEggConverter::get_name 00101 // Access: Public, Virtual 00102 // Description: Returns the English name of the file type this 00103 // converter supports. 00104 //////////////////////////////////////////////////////////////////// 00105 string DAEToEggConverter:: 00106 get_name() const { 00107 return "COLLADA"; 00108 } 00109 00110 //////////////////////////////////////////////////////////////////// 00111 // Function: DAEToEggConverter::get_extension 00112 // Access: Public, Virtual 00113 // Description: Returns the common extension of the file type this 00114 // converter supports. 00115 //////////////////////////////////////////////////////////////////// 00116 string DAEToEggConverter:: 00117 get_extension() const { 00118 return "dae"; 00119 } 00120 00121 //////////////////////////////////////////////////////////////////// 00122 // Function: DAEToEggConverter::convert_file 00123 // Access: Public, Virtual 00124 // Description: Handles the reading of the input file and converting 00125 // it to egg. Returns true if successful, false 00126 // otherwise. 00127 //////////////////////////////////////////////////////////////////// 00128 bool DAEToEggConverter:: 00129 convert_file(const Filename &filename) { 00130 // Reset stuff 00131 clear_error(); 00132 _joints.clear(); 00133 _vertex_pools.clear(); 00134 _skeletons.clear(); 00135 _frame_rate = -1; 00136 if (_error_handler == NULL) { 00137 _error_handler = new FUErrorSimpleHandler; 00138 } 00139 00140 // The default coordinate system is Y-up 00141 if (_egg_data->get_coordinate_system() == CS_default) { 00142 _egg_data->set_coordinate_system(CS_yup_right); 00143 } 00144 00145 // Read the file 00146 FCollada::Initialize(); 00147 _document = FCollada::LoadDocument(filename.to_os_specific().c_str()); 00148 if (_document == NULL) { 00149 daeegg_cat.error() << "Failed to load document: " << _error_handler->GetErrorString() << endl; 00150 FCollada::Release(); 00151 return false; 00152 } 00153 // Make sure the file uses consistent coordinate system and length 00154 if (_document->GetAsset() != NULL) { 00155 FCDocumentTools::StandardizeUpAxisAndLength(_document); 00156 } 00157 00158 _table = new EggTable(); 00159 _table->set_table_type(EggTable::TT_table); 00160 // Process the stuff 00161 process_asset(); 00162 preprocess(); 00163 FCDSceneNode* visual_scene = _document->GetVisualSceneInstance(); 00164 if (visual_scene != NULL) { 00165 // First check for an <extra> tag 00166 const FCDExtra* extra = visual_scene->GetExtra(); 00167 //FIXME: eek this looks horrid 00168 if (extra != NULL) { 00169 const FCDEType* etype = extra->GetDefaultType(); 00170 if (etype != NULL) { 00171 const FCDENode* enode = (const FCDENode*) etype->FindTechnique("MAX3D"); 00172 if (enode != NULL) { 00173 enode = enode->FindChildNode("frame_rate"); 00174 if (enode != NULL && !string_to_int(enode->GetContent(), _frame_rate)) { 00175 daeegg_cat.warning() << "Invalid integer in <frame_rate> tag: '" << enode->GetContent() << "'" << endl; 00176 } } } } 00177 // Now loop through the children 00178 for (size_t ch = 0; ch < visual_scene->GetChildrenCount(); ++ch) { 00179 process_node(DCAST(EggGroupNode, _egg_data), visual_scene->GetChild(ch)); 00180 } 00181 } 00182 SAFE_DELETE(visual_scene); 00183 00184 _egg_data->add_child(_table); 00185 00186 // Clean up and return 00187 SAFE_DELETE(_document); 00188 FCollada::Release(); 00189 return true; 00190 } 00191 00192 void DAEToEggConverter::process_asset() { 00193 if (_document->GetAsset() == NULL) return; 00194 // Read out the coordinate system 00195 FMVector3 up_axis (_document->GetAsset()->GetUpAxis()); 00196 if (up_axis == FMVector3(0, 1, 0)) { 00197 _egg_data->set_coordinate_system(CS_yup_right); 00198 } else if (up_axis == FMVector3(0, 0, 1)) { 00199 _egg_data->set_coordinate_system(CS_zup_right); 00200 } else { 00201 _egg_data->set_coordinate_system(CS_invalid); 00202 daeegg_cat.warning() << "Unrecognized coordinate system!\n"; 00203 } 00204 } 00205 00206 // This function lists all the joints and referenced skeletons 00207 void DAEToEggConverter::preprocess(const FCDSceneNode* node) { 00208 // If the node is NULL, take the visual scene instance. 00209 if (node == NULL) { 00210 assert(_document != NULL); 00211 _skeletons.clear(); 00212 _joints.clear(); 00213 node = _document->GetVisualSceneInstance(); 00214 } 00215 if (node == NULL) return; 00216 if (node->IsJoint()) { 00217 _joints[FROM_FSTRING(node->GetDaeId())] = NULL; 00218 } 00219 // Loop through the instances first. 00220 for (size_t in = 0; in < node->GetInstanceCount(); ++in) { 00221 if (node->GetInstance(in)->GetType() == FCDEntityInstance::CONTROLLER) { 00222 // Loop through the skeleton roots now. 00223 #if FCOLLADA_VERSION < 0x00030005 00224 FCDSceneNodeList roots = ((FCDControllerInstance*) node->GetInstance(in))->FindSkeletonNodes(); 00225 #else 00226 FCDSceneNodeList roots; 00227 ((FCDControllerInstance*) node->GetInstance(in))->FindSkeletonNodes(roots); 00228 #endif 00229 for (FCDSceneNodeList::iterator it = roots.begin(); it != roots.end(); ++it) { 00230 daeegg_cat.spam() << "Found referenced skeleton root " << FROM_FSTRING((*it)->GetDaeId()) << endl; 00231 _skeletons.push_back(FROM_FSTRING((*it)->GetDaeId())); 00232 } 00233 } 00234 } 00235 // Now loop through the children and recurse. 00236 for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) { 00237 preprocess(node->GetChild(ch)); 00238 } 00239 } 00240 00241 // Process the node. If forced is true, it will even process it if its known to be a skeleton root. 00242 void DAEToEggConverter::process_node(PT(EggGroupNode) parent, const FCDSceneNode* node, bool forced) { 00243 nassertv(node != NULL); 00244 string node_id = FROM_FSTRING(node->GetDaeId()); 00245 daeegg_cat.spam() << "Processing node with ID '" << node_id << "'" << endl; 00246 // Important! If it's known to be a skeleton root, ignore it for now, unless we're processing forced. 00247 if (!forced && count(_skeletons.begin(), _skeletons.end(), node_id) > 0) { 00248 daeegg_cat.spam() << "Ignoring skeleton root node with ID '" << node_id << "', we'll process it later" << endl; 00249 return; 00250 } 00251 // Create an egg group for this node 00252 PT(EggGroup) node_group = new EggGroup(FROM_FSTRING(node->GetName())); 00253 process_extra(node_group, node->GetExtra()); 00254 parent->add_child(node_group); 00255 // Check if its a joint 00256 if (node->IsJoint()) { 00257 node_group->set_group_type(EggGroup::GT_joint); 00258 _joints[node_id] = node_group; 00259 } 00260 // Loop through the transforms and apply them 00261 for (size_t tr = 0; tr < node->GetTransformCount(); ++tr) { 00262 apply_transform(node_group, node->GetTransform(tr)); 00263 } 00264 // Loop through the instances and process them 00265 for (size_t in = 0; in < node->GetInstanceCount(); ++in) { 00266 process_instance(node_group, node->GetInstance(in)); 00267 } 00268 // Loop through the children and recursively process them 00269 for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) { 00270 process_node(DCAST(EggGroupNode, node_group), node->GetChild(ch)); 00271 } 00272 // Loop through any possible scene node instances and process those, too. 00273 for (size_t in = 0; in < node->GetInstanceCount(); ++in) { 00274 if (node->GetInstance(in)->GetEntity() && node->GetInstance(in)->GetEntity()->GetType() == FCDEntity::SCENE_NODE) { 00275 process_node(DCAST(EggGroupNode, node_group), (const FCDSceneNode*) node->GetInstance(in)->GetEntity()); 00276 } 00277 } 00278 } 00279 00280 void DAEToEggConverter::process_instance(PT(EggGroup) parent, const FCDEntityInstance* instance) { 00281 nassertv(instance != NULL); 00282 nassertv(instance->GetEntity() != NULL); 00283 // Check what kind of instance this is 00284 switch (instance->GetType()) { 00285 case FCDEntityInstance::GEOMETRY: { 00286 const FCDGeometry* geometry = (const FCDGeometry*) instance->GetEntity(); 00287 assert(geometry != NULL); 00288 if (geometry->IsMesh()) { 00289 // Now, handle the mesh. 00290 process_mesh(parent, geometry->GetMesh(), new DaeMaterials((const FCDGeometryInstance*) instance)); 00291 } 00292 if (geometry->IsSpline()) { 00293 process_spline(parent, FROM_FSTRING(geometry->GetName()), const_cast<FCDGeometrySpline*> (geometry->GetSpline())); 00294 } 00295 break; } 00296 case FCDEntityInstance::CONTROLLER: { 00297 // Add the dart tag and process the controller instance 00298 parent->set_dart_type(EggGroup::DT_default); 00299 process_controller(parent, (const FCDControllerInstance*) instance); 00300 break; } 00301 case FCDEntityInstance::MATERIAL: 00302 // We don't process this directly, handled per-geometry instead. 00303 break; 00304 case FCDEntityInstance::SIMPLE: { 00305 // Grab the entity and check it's type. 00306 const FCDEntity* entity = instance->GetEntity(); 00307 if (entity->GetType() != FCDEntity::SCENE_NODE) { 00308 daeegg_cat.warning() << "Unsupported entity type found" << endl; 00309 } 00310 break; } 00311 default: 00312 daeegg_cat.warning() << "Unsupported instance type found" << endl; 00313 } 00314 } 00315 00316 // Processes the given mesh. 00317 void DAEToEggConverter::process_mesh(PT(EggGroup) parent, const FCDGeometryMesh* mesh, PT(DaeMaterials) materials) { 00318 nassertv(mesh != NULL); 00319 daeegg_cat.debug() << "Processing mesh with id " << FROM_FSTRING(mesh->GetDaeId()) << endl; 00320 00321 // Create the egg stuff to hold this mesh 00322 PT(EggGroup) mesh_group = new EggGroup(FROM_FSTRING(mesh->GetDaeId())); 00323 parent->add_child(mesh_group); 00324 PT(EggVertexPool) mesh_pool = new EggVertexPool(FROM_FSTRING(mesh->GetDaeId())); 00325 mesh_group->add_child(mesh_pool); 00326 _vertex_pools[FROM_FSTRING(mesh->GetDaeId())] = mesh_pool; 00327 00328 // First retrieve the vertex source 00329 if (mesh->GetSourceCount() == 0) { 00330 daeegg_cat.debug() << "Mesh with id " << FROM_FSTRING(mesh->GetDaeId()) << " has no sources" << endl; 00331 return; 00332 } 00333 const FCDGeometrySource* vsource = mesh->FindSourceByType(FUDaeGeometryInput::POSITION); 00334 if (vsource == NULL) { 00335 daeegg_cat.debug() << "Mesh with id " << FROM_FSTRING(mesh->GetDaeId()) << " has no source for POSITION data" << endl; 00336 return; 00337 } 00338 00339 // Loop through the polygon groups and add them 00340 daeegg_cat.spam() << "Mesh with id " << FROM_FSTRING(mesh->GetDaeId()) << " has " << mesh->GetPolygonsCount() << " polygon groups" << endl; 00341 if (mesh->GetPolygonsCount() == 0) return; 00342 00343 // This is an array of pointers, I know. But since they are refcounted, I don't have a better idea. 00344 PT(EggGroup) *primitive_holders = new PT(EggGroup) [mesh->GetPolygonsCount()]; 00345 for (size_t gr = 0; gr < mesh->GetPolygonsCount(); ++gr) { 00346 const FCDGeometryPolygons* polygons = mesh->GetPolygons(gr); 00347 // Stores which group holds the primitives. 00348 PT(EggGroup) primitiveholder; 00349 // If we have materials, make a group for each material. Then, apply the material's per-group stuff. 00350 if (materials != NULL && (!polygons->GetMaterialSemantic().empty()) && mesh->GetPolygonsCount() > 1) { 00351 primitiveholder = new EggGroup(FROM_FSTRING(mesh->GetDaeId()) + "." + FROM_FSTRING(polygons->GetMaterialSemantic())); 00352 mesh_group->add_child(primitiveholder); 00353 } else { 00354 primitiveholder = mesh_group; 00355 } 00356 primitive_holders[gr] = primitiveholder; 00357 // Apply the per-group data of the materials, if we have it. 00358 if (materials != NULL) { 00359 materials->apply_to(FROM_FSTRING(polygons->GetMaterialSemantic()), primitiveholder); 00360 } 00361 // Find the position sources 00362 const FCDGeometryPolygonsInput* pinput = polygons->FindInput(FUDaeGeometryInput::POSITION); 00363 assert(pinput != NULL); 00364 const uint32* indices = pinput->GetIndices(); 00365 // Find the normal sources 00366 const FCDGeometrySource* nsource = mesh->FindSourceByType(FUDaeGeometryInput::NORMAL); 00367 const FCDGeometryPolygonsInput* ninput = polygons->FindInput(FUDaeGeometryInput::NORMAL); 00368 const uint32* nindices; 00369 if (ninput != NULL) nindices = ninput->GetIndices(); 00370 // Find texcoord sources 00371 const FCDGeometrySource* tcsource = mesh->FindSourceByType(FUDaeGeometryInput::TEXCOORD); 00372 const FCDGeometryPolygonsInput* tcinput = polygons->FindInput(FUDaeGeometryInput::TEXCOORD); 00373 const uint32* tcindices; 00374 if (tcinput != NULL) tcindices = tcinput->GetIndices(); 00375 // Find vcolor sources 00376 const FCDGeometrySource* csource = mesh->FindSourceByType(FUDaeGeometryInput::COLOR); 00377 const FCDGeometryPolygonsInput* cinput = polygons->FindInput(FUDaeGeometryInput::COLOR); 00378 const uint32* cindices; 00379 if (cinput != NULL) cindices = cinput->GetIndices(); 00380 // Find binormal sources 00381 const FCDGeometrySource* bsource = mesh->FindSourceByType(FUDaeGeometryInput::TEXBINORMAL); 00382 const FCDGeometryPolygonsInput* binput = polygons->FindInput(FUDaeGeometryInput::TEXBINORMAL); 00383 const uint32* bindices; 00384 if (binput != NULL) bindices = binput->GetIndices(); 00385 // Find tangent sources 00386 const FCDGeometrySource* tsource = mesh->FindSourceByType(FUDaeGeometryInput::TEXTANGENT); 00387 const FCDGeometryPolygonsInput* tinput = polygons->FindInput(FUDaeGeometryInput::TEXTANGENT); 00388 const uint32* tindices; 00389 if (tinput != NULL) tindices = tinput->GetIndices(); 00390 // Get a name for potential coordinate sets 00391 string tcsetname (""); 00392 if (materials != NULL && tcinput != NULL) { 00393 daeegg_cat.debug() << "Assigning texcoord set " << tcinput->GetSet() << " to semantic '" << FROM_FSTRING(polygons->GetMaterialSemantic()) << "'\n"; 00394 tcsetname = materials->get_uvset_name(FROM_FSTRING(polygons->GetMaterialSemantic()), FUDaeGeometryInput::TEXCOORD, tcinput->GetSet()); 00395 } 00396 string tbsetname (""); 00397 if (materials != NULL && binput != NULL) { 00398 daeegg_cat.debug() << "Assigning texbinormal set " << binput->GetSet() << " to semantic '" << FROM_FSTRING(polygons->GetMaterialSemantic()) << "'\n"; 00399 tbsetname = materials->get_uvset_name(FROM_FSTRING(polygons->GetMaterialSemantic()), FUDaeGeometryInput::TEXBINORMAL, binput->GetSet()); 00400 } 00401 string ttsetname (""); 00402 if (materials != NULL && tinput != NULL) { 00403 daeegg_cat.debug() << "Assigning textangent set " << tinput->GetSet() << " to semantic '" << FROM_FSTRING(polygons->GetMaterialSemantic()) << "'\n"; 00404 ttsetname = materials->get_uvset_name(FROM_FSTRING(polygons->GetMaterialSemantic()), FUDaeGeometryInput::TEXTANGENT, tinput->GetSet()); 00405 } 00406 // Loop through the indices and add the vertices. 00407 for (size_t ix = 0; ix < pinput->GetIndexCount(); ++ix) { 00408 PT_EggVertex vertex = mesh_pool->make_new_vertex(); 00409 const float* data = &vsource->GetData()[indices[ix]*3]; 00410 vertex->set_pos(LPoint3d(data[0], data[1], data[2])); 00411 // Process the normal 00412 if (nsource != NULL && ninput != NULL) { 00413 assert(nsource->GetStride() == 3); 00414 data = &nsource->GetData()[nindices[ix]*3]; 00415 vertex->set_normal(LVecBase3d(data[0], data[1], data[2])); 00416 } 00417 // Process the texcoords 00418 if (tcsource != NULL && tcinput != NULL) { 00419 assert(tcsource->GetStride() == 2 || tcsource->GetStride() == 3); 00420 data = &tcsource->GetData()[tcindices[ix]*tcsource->GetStride()]; 00421 if (tcsource->GetStride() == 2) { 00422 vertex->set_uv(tcsetname, LPoint2d(data[0], data[1])); 00423 } else { 00424 vertex->set_uvw(tcsetname, LPoint3d(data[0], data[1], data[2])); 00425 } 00426 } 00427 // Process the color 00428 if (csource != NULL && cinput != NULL) { 00429 assert(csource->GetStride() == 3 || csource->GetStride() == 4); 00430 if (csource->GetStride() == 3) { 00431 data = &csource->GetData()[cindices[ix]*3]; 00432 vertex->set_color(LColor(data[0], data[1], data[2], 1.0f)); 00433 } else { 00434 data = &csource->GetData()[cindices[ix]*4]; 00435 vertex->set_color(LColor(data[0], data[1], data[2], data[3])); 00436 } 00437 } 00438 // Possibly add a UV object 00439 if ((bsource != NULL && binput != NULL) || (tsource != NULL && tinput != NULL)) { 00440 if (bsource != NULL && binput != NULL) { 00441 assert(bsource->GetStride() == 3); 00442 data = &bsource->GetData()[bindices[ix]*3]; 00443 PT(EggVertexUV) uv_obj = vertex->modify_uv_obj(tbsetname); 00444 if (uv_obj == NULL) { 00445 uv_obj = new EggVertexUV(tbsetname, LTexCoordd()); 00446 } 00447 uv_obj->set_binormal(LVecBase3d(data[0], data[1], data[2])); 00448 } 00449 if (tsource != NULL && tinput != NULL) { 00450 assert(tsource->GetStride() == 3); 00451 data = &tsource->GetData()[tindices[ix]*3]; 00452 PT(EggVertexUV) uv_obj = vertex->modify_uv_obj(ttsetname); 00453 if (uv_obj == NULL) { 00454 uv_obj = new EggVertexUV(ttsetname, LTexCoordd()); 00455 } 00456 uv_obj->set_tangent(LVecBase3d(data[0], data[1], data[2])); 00457 } 00458 } 00459 vertex->transform(parent->get_node_to_vertex()); 00460 } 00461 } 00462 // Loop again for the polygons 00463 for (size_t gr = 0; gr < mesh->GetPolygonsCount(); ++gr) { 00464 const FCDGeometryPolygons* polygons = mesh->GetPolygons(gr); 00465 // Now loop through the faces 00466 uint32 offset = 0; 00467 for (size_t fa = 0; fa < polygons->GetFaceVertexCountCount(); ++fa) { 00468 PT(EggPrimitive) primitive = NULL; 00469 // Create a primitive that matches the fcollada type 00470 switch (polygons->GetPrimitiveType()) { 00471 case FCDGeometryPolygons::LINES: 00472 primitive = new EggLine(); 00473 break; 00474 case FCDGeometryPolygons::POLYGONS: 00475 primitive = new EggPolygon(); 00476 break; 00477 case FCDGeometryPolygons::TRIANGLE_FANS: 00478 primitive = new EggTriangleFan(); 00479 break; 00480 case FCDGeometryPolygons::TRIANGLE_STRIPS: 00481 primitive = new EggTriangleStrip(); 00482 break; 00483 case FCDGeometryPolygons::POINTS: 00484 primitive = new EggPoint(); 00485 break; 00486 case FCDGeometryPolygons::LINE_STRIPS: 00487 daeegg_cat.warning() << "Linestrips not yet supported!" << endl; 00488 break; 00489 default: 00490 daeegg_cat.warning() << "Unsupported primitive type found!" << endl; 00491 } 00492 if (primitive != NULL) { 00493 primitive_holders[gr]->add_child(primitive); 00494 if (materials != NULL) { 00495 materials->apply_to(FROM_FSTRING(polygons->GetMaterialSemantic()), primitive); 00496 } 00497 for (size_t ve = 0; ve < polygons->GetFaceVertexCount(fa); ++ve) { 00498 assert(mesh_pool->has_vertex(ve + polygons->GetFaceVertexOffset() + offset)); 00499 primitive->add_vertex(mesh_pool->get_vertex(ve + polygons->GetFaceVertexOffset() + offset)); 00500 } 00501 } 00502 offset += polygons->GetFaceVertexCount(fa); 00503 } 00504 } 00505 delete[] primitive_holders; 00506 } 00507 00508 void DAEToEggConverter::process_spline(PT(EggGroup) parent, const string group_name, FCDGeometrySpline* geometry_spline) { 00509 assert(geometry_spline != NULL); 00510 PT(EggGroup) result = new EggGroup(group_name); 00511 parent->add_child(result); 00512 //TODO: if its not a nurbs, make it convert between the types 00513 if (geometry_spline->GetType() != FUDaeSplineType::NURBS) { 00514 daeegg_cat.warning() << "Only NURBS curves are supported (yet)!" << endl; 00515 } else { 00516 // Loop through the splines 00517 for (size_t sp = 0; sp < geometry_spline->GetSplineCount(); ++sp) { 00518 process_spline(result, geometry_spline->GetSpline(sp)); 00519 } 00520 } 00521 } 00522 00523 void DAEToEggConverter::process_spline(PT(EggGroup) parent, const FCDSpline* spline) { 00524 assert(spline != NULL); 00525 nassertv(spline->GetSplineType() == FUDaeSplineType::NURBS); 00526 // Now load in the nurbs curve to the egg library 00527 PT(EggNurbsCurve) nurbs_curve = new EggNurbsCurve(FROM_FSTRING(spline->GetName())); 00528 parent->add_child(nurbs_curve); 00529 //TODO: what value is this? 00530 nurbs_curve->setup(0, ((const FCDNURBSSpline*) spline)->GetKnotCount()); 00531 for (size_t kn = 0; kn < ((const FCDNURBSSpline*) spline)->GetKnotCount(); ++kn) { 00532 const float* knot = ((const FCDNURBSSpline*) spline)->GetKnot(kn); 00533 assert(knot != NULL); 00534 nurbs_curve->set_knot(kn, *knot); 00535 } 00536 for (size_t cv = 0; cv < spline->GetCVCount(); ++cv) { 00537 PT_EggVertex c_vtx = new EggVertex(); 00538 c_vtx->set_pos(TO_VEC3(*spline->GetCV(cv))); 00539 c_vtx->transform(parent->get_node_to_vertex()); 00540 nurbs_curve->add_vertex(c_vtx); 00541 } 00542 } 00543 00544 void DAEToEggConverter::process_controller(PT(EggGroup) parent, const FCDControllerInstance* instance) { 00545 assert(instance != NULL); 00546 const FCDController* controller = (const FCDController*) instance->GetEntity(); 00547 assert(controller != NULL); 00548 PT(EggVertexPool) vertex_pool = NULL; 00549 // Add the skin geometry 00550 const FCDGeometry* geometry = controller->GetBaseGeometry(); 00551 if (geometry != NULL) { 00552 if (geometry->IsMesh()) { 00553 process_mesh(parent, geometry->GetMesh(), new DaeMaterials((const FCDGeometryInstance*) instance)); 00554 daeegg_cat.spam() << "Processing mesh for controller\n"; 00555 if (_vertex_pools.count(FROM_FSTRING(geometry->GetMesh()->GetDaeId()))) { 00556 daeegg_cat.debug() << "Using vertex pool " << FROM_FSTRING(geometry->GetMesh()->GetDaeId()) << "\n"; 00557 vertex_pool = _vertex_pools[FROM_FSTRING(geometry->GetMesh()->GetDaeId())]; 00558 } 00559 } 00560 if (geometry->IsSpline()) { 00561 process_spline(parent, FROM_FSTRING(geometry->GetName()), const_cast<FCDGeometrySpline*> (geometry->GetSpline())); 00562 } 00563 } 00564 // Add the joint hierarchy 00565 #if FCOLLADA_VERSION < 0x00030005 00566 FCDSceneNodeList roots = (const_cast<FCDControllerInstance*> (instance))->FindSkeletonNodes(); 00567 #else 00568 FCDSceneNodeList roots; 00569 (const_cast<FCDControllerInstance*> (instance))->FindSkeletonNodes(roots); 00570 #endif 00571 for (FCDSceneNodeList::iterator it = roots.begin(); it != roots.end(); ++it) { 00572 process_node(DCAST(EggGroupNode, parent), *it, true); 00573 } 00574 if (controller->IsSkin()) { 00575 // Load in the vertex influences first 00576 pmap<int32, pvector<pair<PT_EggVertex, PN_stdfloat> > > influences; 00577 if (vertex_pool) { 00578 for (size_t in = 0; in < controller->GetSkinController()->GetInfluenceCount(); ++in) { 00579 assert(vertex_pool->has_vertex(in)); 00580 for (size_t pa = 0; pa < controller->GetSkinController()->GetVertexInfluence(in)->GetPairCount(); ++pa) { 00581 const FCDJointWeightPair* jwpair = controller->GetSkinController()->GetVertexInfluence(in)->GetPair(pa); 00582 influences[jwpair->jointIndex].push_back(pair<PT_EggVertex, PN_stdfloat> (vertex_pool->get_vertex(in), jwpair->weight)); 00583 } 00584 } 00585 } 00586 // Loop through the joints in the vertex influences 00587 for (pmap<int32, pvector<pair<PT_EggVertex, PN_stdfloat> > >::iterator it = influences.begin(); it != influences.end(); ++it) { 00588 if (it->first == -1) { 00589 daeegg_cat.warning() << "Ignoring vertex influence with negative joint index\n"; 00590 //FIXME: Why are there joints with index -1 00591 } else { 00592 const string joint_id = FROM_FSTRING(controller->GetSkinController()->GetJoint(it->first)->GetId()); 00593 //TODO: what if the joints have just not been defined yet? 00594 if (_joints.count(joint_id) > 0) { 00595 if (_joints[joint_id]) { 00596 for (pvector<pair<PT_EggVertex, PN_stdfloat> >::iterator vi = it->second.begin(); vi != it->second.end(); ++vi) { 00597 _joints[joint_id]->ref_vertex(vi->first, vi->second); 00598 } 00599 } else { 00600 daeegg_cat.warning() << "Unprocessed joint being referenced: '" << joint_id << "'" << endl; 00601 } 00602 } else { 00603 daeegg_cat.warning() << "Unknown joint being referenced: '" << joint_id << "'" << endl; 00604 } 00605 } 00606 } 00607 } 00608 if (controller->IsMorph()) { 00609 assert(controller != NULL); 00610 const FCDMorphController* morph_controller = controller->GetMorphController(); 00611 assert(morph_controller != NULL); 00612 PT(EggTable) bundle = new EggTable(parent->get_name()); 00613 bundle->set_table_type(EggTable::TT_bundle); 00614 PT(EggTable) morph = new EggTable("morph"); 00615 morph->set_table_type(EggTable::TT_table); 00616 bundle->add_child(morph); 00617 // Loop through the morph targets. 00618 for (size_t mt = 0; mt < morph_controller->GetTargetCount(); ++mt) { 00619 const FCDMorphTarget* morph_target = morph_controller->GetTarget(mt); 00620 assert(morph_target != NULL); 00621 PT(EggSAnimData) target = new EggSAnimData(FROM_FSTRING(morph_target->GetGeometry()->GetName())); 00622 if (morph_target->IsAnimated()) { 00623 //TODO 00624 } else { 00625 target->add_data(morph_target->GetWeight()); 00626 } 00627 morph->add_child(target); 00628 } 00629 } 00630 00631 // Get a <Bundle> for the character and add it to the table 00632 PT(DaeCharacter) character = new DaeCharacter(parent->get_name(), instance); 00633 _table->add_child(character->as_egg_bundle()); 00634 } 00635 00636 void DAEToEggConverter::process_extra(PT(EggGroup) group, const FCDExtra* extra) { 00637 if (extra == NULL) { 00638 return; 00639 } 00640 nassertv(group != NULL); 00641 00642 const FCDEType* etype = extra->GetDefaultType(); 00643 if (etype == NULL) { 00644 return; 00645 } 00646 00647 const FCDENode* enode = (const FCDENode*) etype->FindTechnique("PANDA3D"); 00648 if (enode == NULL) { 00649 return; 00650 } 00651 00652 FCDENodeList tags; 00653 enode->FindChildrenNodes("param", tags); 00654 for (FCDENodeList::iterator it = tags.begin(); it != tags.end(); ++it) { 00655 const FCDEAttribute* attr = (*it)->FindAttribute("sid"); 00656 if (attr) { 00657 group->set_tag(FROM_FSTRING(attr->GetValue()), (*it)->GetContent()); 00658 } 00659 } 00660 } 00661 00662 LMatrix4d DAEToEggConverter::convert_matrix(const FMMatrix44& matrix) { 00663 LMatrix4d result = LMatrix4d::zeros_mat(); 00664 for (char x = 0; x < 4; ++x) { 00665 for (char y = 0; y < 4; ++y) { 00666 result(x, y) = matrix[x][y]; 00667 } 00668 } 00669 return result; 00670 } 00671 00672 void DAEToEggConverter::apply_transform(const PT(EggGroup) to, const FCDTransform* from) { 00673 assert(from != NULL); 00674 assert(to != NULL); 00675 to->set_transform3d(convert_matrix(from->ToMatrix()) * to->get_transform3d()); 00676 }