00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "colladaLoader.h"
00016 #include "virtualFileSystem.h"
00017 #include "luse.h"
00018 #include "string_utils.h"
00019 #include "geomNode.h"
00020 #include "geomVertexWriter.h"
00021 #include "geomTriangles.h"
00022 #include "lightNode.h"
00023 #include "lightAttrib.h"
00024 #include "ambientLight.h"
00025 #include "directionalLight.h"
00026 #include "pointLight.h"
00027 #include "spotlight.h"
00028
00029 #include "colladaBindMaterial.h"
00030 #include "colladaPrimitive.h"
00031
00032
00033 #include "pre_collada_include.h"
00034 #include <dom/domCOLLADA.h>
00035 #include <dom/domNode.h>
00036 #include <dom/domVisual_scene.h>
00037 #include <dom/domTranslate.h>
00038 #include <dom/domRotate.h>
00039 #include <dom/domMatrix.h>
00040
00041 #if PANDA_COLLADA_VERSION >= 15
00042 #include <dom/domInstance_with_extra.h>
00043 #else
00044 #include <dom/domInstanceWithExtra.h>
00045 #define domInstance_with_extra domInstanceWithExtra
00046 #define domTargetable_floatRef domTargetableFloatRef
00047 #endif
00048
00049 #define TOSTRING(x) (x == NULL ? "" : x)
00050
00051
00052
00053
00054
00055 ColladaLoader::
00056 ColladaLoader() :
00057 _record (NULL),
00058 _cs (CS_default),
00059 _error (false),
00060 _root (NULL),
00061 _collada (NULL) {
00062
00063 _dae = new DAE;
00064 }
00065
00066
00067
00068
00069
00070 ColladaLoader::
00071 ~ColladaLoader() {
00072 delete _dae;
00073 }
00074
00075
00076
00077
00078
00079 bool ColladaLoader::
00080 read(const Filename &filename) {
00081 _filename = filename;
00082
00083 string data;
00084 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00085
00086 if (!vfs->read_file(_filename, data, true)) {
00087 collada_cat.error()
00088 << "Error reading " << _filename << "\n";
00089 _error = true;
00090 return false;
00091 }
00092
00093 _collada = _dae->openFromMemory(_filename.to_os_specific(), data.c_str());
00094 _error = (_collada == NULL);
00095 return !_error;
00096 }
00097
00098
00099
00100
00101
00102
00103 void ColladaLoader::
00104 build_graph() {
00105 nassertv(_collada);
00106 nassertv(!_error);
00107
00108 _root = new ModelRoot(_filename.get_basename());
00109
00110 domCOLLADA::domScene* scene = _collada->getScene();
00111 domInstance_with_extra* inst = scene->getInstance_visual_scene();
00112 domVisual_scene* vscene = daeSafeCast<domVisual_scene> (inst->getUrl().getElement());
00113 if (vscene) {
00114 load_visual_scene(*vscene, _root);
00115 }
00116 }
00117
00118
00119
00120
00121
00122 void ColladaLoader::
00123 load_visual_scene(domVisual_scene& scene, PandaNode *parent) {
00124
00125 if (scene.getUserData() != NULL) {
00126 parent->add_child((PandaNode *) scene.getUserData());
00127 return;
00128 }
00129
00130 PT(PandaNode) pnode = new PandaNode(TOSTRING(scene.getName()));
00131 scene.setUserData((void *) pnode);
00132 parent->add_child(pnode);
00133
00134
00135 domExtra_Array &extras = scene.getExtra_array();
00136 for (size_t i = 0; i < extras.getCount(); ++i) {
00137 load_tags(*extras[i], pnode);
00138 }
00139
00140
00141 domNode_Array &nodes = scene.getNode_array();
00142 for (size_t i = 0; i < nodes.getCount(); ++i) {
00143 load_node(*nodes[i], pnode);
00144 }
00145
00146
00147 if (_lights.size() > 0) {
00148 CPT(LightAttrib) lattr = DCAST(LightAttrib, LightAttrib::make());
00149 pvector<LightNode*>::iterator it;
00150 for (it = _lights.begin(); it != _lights.end(); ++it) {
00151 lattr = DCAST(LightAttrib, lattr->add_on_light(*it));
00152 }
00153 pnode->set_state(RenderState::make(lattr));
00154
00155 _lights.clear();
00156 }
00157 }
00158
00159
00160
00161
00162
00163 void ColladaLoader::
00164 load_node(domNode& node, PandaNode *parent) {
00165
00166 if (node.getUserData() != NULL) {
00167 parent->add_child((PandaNode *) node.getUserData());
00168 return;
00169 }
00170
00171
00172 PT(PandaNode) pnode;
00173 pnode = new PandaNode(TOSTRING(node.getName()));
00174 node.setUserData((void *) pnode);
00175 parent->add_child(pnode);
00176
00177
00178 LMatrix4f transform (LMatrix4f::ident_mat());
00179
00180 daeElementRefArray &elements = node.getContents();
00181 for (size_t i = elements.getCount(); i > 0; --i) {
00182 daeElementRef &elem = elements[i - 1];
00183
00184 switch (elem->getElementType()) {
00185 case COLLADA_TYPE::LOOKAT: {
00186
00187 domFloat3x3 &l = (daeSafeCast<domLookat>(elem))->getValue();
00188 LPoint3f eye (l[0], l[1], l[2]);
00189 LVector3f up (l[6], l[7], l[8]);
00190 LVector3f forward = LPoint3f(l[3], l[4], l[5]) - eye;
00191 forward.normalize();
00192 LVector3f side = forward.cross(up);
00193 side.normalize();
00194 up = side.cross(forward);
00195 LMatrix4f mat (LMatrix4f::ident_mat());
00196 mat.set_col(0, side);
00197 mat.set_col(1, up);
00198 mat.set_col(2, -forward);
00199 transform *= mat;
00200 transform *= LMatrix4f::translate_mat(-eye);
00201 break;
00202 }
00203 case COLLADA_TYPE::MATRIX: {
00204 domFloat4x4 &m = (daeSafeCast<domMatrix>(elem))->getValue();
00205 transform *= LMatrix4f(
00206 m[0], m[4], m[ 8], m[12],
00207 m[1], m[5], m[ 9], m[13],
00208 m[2], m[6], m[10], m[14],
00209 m[3], m[7], m[11], m[15]);
00210 break;
00211 }
00212 case COLLADA_TYPE::ROTATE: {
00213 domFloat4 &r = (daeSafeCast<domRotate>(elem))->getValue();
00214 transform *= LMatrix4f::rotate_mat(r[3], LVecBase3f(r[0], r[1], r[2]));
00215 break;
00216 }
00217 case COLLADA_TYPE::SCALE: {
00218 domFloat3 &s = (daeSafeCast<domScale>(elem))->getValue();
00219 transform *= LMatrix4f::scale_mat(s[0], s[1], s[2]);
00220 break;
00221 }
00222 case COLLADA_TYPE::SKEW:
00223
00224 collada_cat.error() << "<skew> not supported yet\n";
00225 break;
00226 case COLLADA_TYPE::TRANSLATE: {
00227 domFloat3 &t = (daeSafeCast<domTranslate>(elem))->getValue();
00228 transform *= LMatrix4f::translate_mat(t[0], t[1], t[2]);
00229 break;
00230 }
00231 }
00232 }
00233
00234
00235
00236
00237 if (transform != LMatrix4f::ident_mat()) {
00238 pnode->set_transform(TransformState::make_mat(transform));
00239 }
00240
00241
00242 domInstance_camera_Array &caminst = node.getInstance_camera_array();
00243 for (size_t i = 0; i < caminst.getCount(); ++i) {
00244 domCamera* target = daeSafeCast<domCamera> (caminst[i]->getUrl().getElement());
00245 load_camera(*target, pnode);
00246 }
00247
00248
00249 domInstance_controller_Array &ctrlinst = node.getInstance_controller_array();
00250 for (size_t i = 0; i < ctrlinst.getCount(); ++i) {
00251 domController* target = daeSafeCast<domController> (ctrlinst[i]->getUrl().getElement());
00252
00253 if (target->getSkin() != NULL) {
00254 domGeometry* geom = daeSafeCast<domGeometry> (target->getSkin()->getSource().getElement());
00255
00256
00257 }
00258 }
00259
00260
00261 domInstance_geometry_Array &ginst = node.getInstance_geometry_array();
00262 for (size_t i = 0; i < ginst.getCount(); ++i) {
00263 load_instance_geometry(*ginst[i], pnode);
00264 }
00265
00266
00267 domInstance_light_Array &linst = node.getInstance_light_array();
00268 for (size_t i = 0; i < linst.getCount(); ++i) {
00269 domLight* target = daeSafeCast<domLight> (linst[i]->getUrl().getElement());
00270 load_light(*target, pnode);
00271 }
00272
00273
00274 domInstance_node_Array &ninst = node.getInstance_node_array();
00275 for (size_t i = 0; i < ninst.getCount(); ++i) {
00276 domNode* target = daeSafeCast<domNode> (ninst[i]->getUrl().getElement());
00277 load_node(*target, pnode);
00278 }
00279
00280
00281 domNode_Array &nodes = node.getNode_array();
00282 for (size_t i = 0; i < nodes.getCount(); ++i) {
00283 load_node(*nodes[i], pnode);
00284 }
00285
00286
00287 domExtra_Array &extras = node.getExtra_array();
00288 for (size_t i = 0; i < extras.getCount(); ++i) {
00289 load_tags(*extras[i], pnode);
00290
00291
00292 }
00293 }
00294
00295
00296
00297
00298
00299 void ColladaLoader::
00300 load_tags(domExtra &extra, PandaNode *node) {
00301 domTechnique_Array &techniques = extra.getTechnique_array();
00302
00303 for (size_t t = 0; t < techniques.getCount(); ++t) {
00304 if (cmp_nocase(techniques[t]->getProfile(), "PANDA3D") == 0) {
00305 const daeElementRefArray &children = techniques[t]->getChildren();
00306
00307 for (size_t c = 0; c < children.getCount(); ++c) {
00308 daeElement &child = *children[c];
00309
00310 if (cmp_nocase(child.getElementName(), "tag") == 0) {
00311 const string &name = child.getAttribute("name");
00312 if (name.size() > 0) {
00313 node->set_tag(name, child.getCharData());
00314 } else {
00315 collada_cat.warning() << "Ignoring <tag> without name attribute\n";
00316 }
00317 } else if (cmp_nocase(child.getElementName(), "param") == 0) {
00318 collada_cat.error() <<
00319 "Unknown <param> attribute in PANDA3D technique. "
00320 "Did you mean to use <tag> instead?\n";
00321 }
00322 }
00323 }
00324 }
00325 }
00326
00327
00328
00329
00330
00331 void ColladaLoader::
00332 load_camera(domCamera &cam, PandaNode *parent) {
00333
00334 if (cam.getUserData() != NULL) {
00335 parent->add_child((PandaNode *) cam.getUserData());
00336 return;
00337 }
00338
00339
00340 }
00341
00342
00343
00344
00345
00346
00347 void ColladaLoader::
00348 load_instance_geometry(domInstance_geometry &inst, PandaNode *parent) {
00349
00350 if (inst.getUserData() != NULL) {
00351 parent->add_child((PandaNode *) inst.getUserData());
00352 return;
00353 }
00354
00355 domGeometry* geom = daeSafeCast<domGeometry> (inst.getUrl().getElement());
00356 nassertv(geom != NULL);
00357
00358
00359 PT(GeomNode) gnode = new GeomNode(TOSTRING(geom->getName()));
00360 inst.setUserData((void *) gnode);
00361 parent->add_child(gnode);
00362
00363 domBind_materialRef bind_mat = inst.getBind_material();
00364 ColladaBindMaterial cbm;
00365 if (bind_mat != NULL) {
00366 cbm.load_bind_material(*bind_mat);
00367 }
00368
00369 load_geometry(*geom, gnode, cbm);
00370
00371
00372 domExtra_Array &extras = geom->getExtra_array();
00373 for (size_t i = 0; i < extras.getCount(); ++i) {
00374 load_tags(*extras[i], gnode);
00375 }
00376 }
00377
00378
00379
00380
00381
00382
00383 void ColladaLoader::
00384 load_geometry(domGeometry &geom, GeomNode *gnode, ColladaBindMaterial &bind_mat) {
00385 domMesh* mesh = geom.getMesh();
00386 if (mesh == NULL) {
00387
00388 return;
00389 }
00390
00391
00392 domLines_Array &lines_array = mesh->getLines_array();
00393 for (size_t i = 0; i < lines_array.getCount(); ++i) {
00394 PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*lines_array[i]);
00395 if (prim != NULL) {
00396 gnode->add_geom(prim->get_geom());
00397 }
00398 }
00399
00400 domLinestrips_Array &linestrips_array = mesh->getLinestrips_array();
00401 for (size_t i = 0; i < linestrips_array.getCount(); ++i) {
00402 PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*linestrips_array[i]);
00403 if (prim != NULL) {
00404 gnode->add_geom(prim->get_geom());
00405 }
00406 }
00407
00408 domPolygons_Array &polygons_array = mesh->getPolygons_array();
00409 for (size_t i = 0; i < polygons_array.getCount(); ++i) {
00410 PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*polygons_array[i]);
00411 if (prim != NULL) {
00412 gnode->add_geom(prim->get_geom());
00413 }
00414 }
00415
00416 domPolylist_Array &polylist_array = mesh->getPolylist_array();
00417 for (size_t i = 0; i < polylist_array.getCount(); ++i) {
00418 PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*polylist_array[i]);
00419 if (prim != NULL) {
00420 gnode->add_geom(prim->get_geom());
00421 }
00422 }
00423
00424 domTriangles_Array &triangles_array = mesh->getTriangles_array();
00425 for (size_t i = 0; i < triangles_array.getCount(); ++i) {
00426 PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*triangles_array[i]);
00427 if (prim != NULL) {
00428 gnode->add_geom(prim->get_geom());
00429 }
00430 }
00431
00432 domTrifans_Array &trifans_array = mesh->getTrifans_array();
00433 for (size_t i = 0; i < trifans_array.getCount(); ++i) {
00434 PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*trifans_array[i]);
00435 if (prim != NULL) {
00436 gnode->add_geom(prim->get_geom());
00437 }
00438 }
00439
00440 domTristrips_Array &tristrips_array = mesh->getTristrips_array();
00441 for (size_t i = 0; i < tristrips_array.getCount(); ++i) {
00442 PT(ColladaPrimitive) prim = ColladaPrimitive::from_dom(*tristrips_array[i]);
00443 if (prim != NULL) {
00444 gnode->add_geom(prim->get_geom());
00445 }
00446 }
00447 }
00448
00449
00450
00451
00452
00453 void ColladaLoader::
00454 load_light(domLight &light, PandaNode *parent) {
00455
00456 if (light.getUserData() != NULL) {
00457 parent->add_child((PandaNode *) light.getUserData());
00458 return;
00459 }
00460
00461 PT(LightNode) lnode;
00462 domLight::domTechnique_common &tc = *light.getTechnique_common();
00463
00464
00465 domLight::domTechnique_common::domAmbientRef ambient = tc.getAmbient();
00466 if (ambient != NULL) {
00467 PT(AmbientLight) alight = new AmbientLight(TOSTRING(light.getName()));
00468 lnode = DCAST(LightNode, alight);
00469
00470 domFloat3 &color = ambient->getColor()->getValue();
00471 alight->set_color(LColor(color[0], color[1], color[2], 1.0));
00472 }
00473
00474
00475 domLight::domTechnique_common::domDirectionalRef directional = tc.getDirectional();
00476 if (directional != NULL) {
00477 PT(DirectionalLight) dlight = new DirectionalLight(TOSTRING(light.getName()));
00478 lnode = DCAST(LightNode, dlight);
00479
00480 domFloat3 &color = directional->getColor()->getValue();
00481 dlight->set_color(LColor(color[0], color[1], color[2], 1.0));
00482 dlight->set_direction(LVector3f(0, 0, -1));
00483 }
00484
00485
00486 domLight::domTechnique_common::domPointRef point = tc.getPoint();
00487 if (point != NULL) {
00488 PT(PointLight) plight = new PointLight(TOSTRING(light.getName()));
00489 lnode = DCAST(LightNode, plight);
00490
00491 domFloat3 &color = point->getColor()->getValue();
00492 plight->set_color(LColor(color[0], color[1], color[2], 1.0));
00493
00494 LVecBase3f atten (1.0f, 0.0f, 0.0f);
00495 domTargetable_floatRef fval = point->getConstant_attenuation();
00496 if (fval != NULL) {
00497 atten[0] = fval->getValue();
00498 }
00499 fval = point->getLinear_attenuation();
00500 if (fval != NULL) {
00501 atten[1] = fval->getValue();
00502 }
00503 fval = point->getQuadratic_attenuation();
00504 if (fval != NULL) {
00505 atten[2] = fval->getValue();
00506 }
00507
00508 plight->set_attenuation(atten);
00509 }
00510
00511
00512 domLight::domTechnique_common::domSpotRef spot = tc.getSpot();
00513 if (spot != NULL) {
00514 PT(Spotlight) slight = new Spotlight(TOSTRING(light.getName()));
00515 lnode = DCAST(LightNode, slight);
00516
00517 domFloat3 &color = spot->getColor()->getValue();
00518 slight->set_color(LColor(color[0], color[1], color[2], 1.0));
00519
00520 LVecBase3f atten (1.0f, 0.0f, 0.0f);
00521 domTargetable_floatRef fval = spot->getConstant_attenuation();
00522 if (fval != NULL) {
00523 atten[0] = fval->getValue();
00524 }
00525 fval = spot->getLinear_attenuation();
00526 if (fval != NULL) {
00527 atten[1] = fval->getValue();
00528 }
00529 fval = spot->getQuadratic_attenuation();
00530 if (fval != NULL) {
00531 atten[2] = fval->getValue();
00532 }
00533
00534 slight->set_attenuation(atten);
00535
00536 fval = spot->getFalloff_angle();
00537 if (fval != NULL) {
00538 slight->get_lens()->set_fov(fval->getValue());
00539 } else {
00540 slight->get_lens()->set_fov(180.0f);
00541 }
00542
00543 fval = spot->getFalloff_exponent();
00544 if (fval != NULL) {
00545 slight->set_exponent(fval->getValue());
00546 } else {
00547 slight->set_exponent(0.0f);
00548 }
00549 }
00550
00551 if (lnode == NULL) {
00552 return;
00553 }
00554 parent->add_child(lnode);
00555 _lights.push_back(lnode);
00556 light.setUserData((void*) lnode);
00557
00558
00559 domExtra_Array &extras = light.getExtra_array();
00560 for (size_t i = 0; i < extras.getCount(); ++i) {
00561 load_tags(*extras[i], lnode);
00562 }
00563 }