Panda3D

daeToEggConverter.cxx

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 &copy) :
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 }
 All Classes Functions Variables Enumerations