home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 5164 / miletos.7z / document.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2011-04-02  |  12.5 KB  |  556 lines

  1. #define __MILETOS_DOCUMENT_CPP__
  2.  
  3. //
  4. // Libmiletos
  5. //
  6. // Copyright (C) Lauris Kaplinski 2007
  7. //
  8.  
  9. static const int debug = 1;
  10.  
  11. #ifndef _CRT_SECURE_NO_DEPRECATE
  12. #define _CRT_SECURE_NO_DEPRECATE 1
  13. #endif
  14.  
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include <assert.h>
  19.  
  20. #include <libarikkei/dict.h>
  21.  
  22. #include "collada/collada.h"
  23. #include "scene.h"
  24.  
  25. #ifdef WIN32
  26. #define strdup _strdup
  27. #endif
  28.  
  29. namespace Miletos {
  30.  
  31. struct IdentityChangeListener {
  32.     char *id;
  33.     IdentityChangeListener *prev;
  34.     IdentityChangeListener *next;
  35.     std::vector<Object *> objects;
  36. };
  37.  
  38. struct Document::Dict {
  39. public:
  40.     Arikkei::Dict<const char *, Object *> objectdict;
  41.     // Identity tracking
  42.     IdentityChangeListener *listeners;
  43.     Arikkei::Dict<const char *, IdentityChangeListener *> listenerdict;
  44.  
  45.     // Constructor
  46.     Dict(unsigned int hashsize) : objectdict(hashsize), listeners(NULL), listenerdict(109) {}
  47.     // Access
  48.     Object *lookup (const char *id) { return objectdict.lookup (id); }
  49.     void insert (const char *id, Object *object) { objectdict.insert (id, object); }
  50.     void remove (const char *id) { objectdict.remove (id); }
  51.     // Identity change signals
  52.     void invokeIdentityAdded (Document *pdocument, const char *pidentity, Object *pobject);
  53.     void invokeIdentityRemoved (Document *pdocument, const char *pidentity);
  54.     // Management
  55.     void addIdentityChangeListener (const char *pidentity, Object *pobject);
  56.     void removeIdentityChangeListener (const char *pidentity, Object *pobject);
  57.     void removeIdentityChangeListeners (Object *pobject);
  58.     unsigned int isIdentityTracked (const char *id);
  59. };
  60.  
  61. void
  62. Document::Dict::addIdentityChangeListener (const char *pidentity, Object *pobject)
  63. {
  64.     IdentityChangeListener *listener = listenerdict.lookup (pidentity);
  65.     if (!listener) {
  66.         listener = new IdentityChangeListener ();
  67.         listener->id = strdup (pidentity);
  68.         listener->prev = NULL;
  69.         if (listeners) listeners->prev = listener;
  70.         listener->next = listeners;
  71.         listeners = listener;
  72.         listenerdict.insert (listener->id, listener);
  73.     }
  74.     listener->objects.push_back (pobject);
  75. }
  76.  
  77. void
  78. Document::Dict::removeIdentityChangeListener (const char *pidentity, Object *pobject)
  79. {
  80.     IdentityChangeListener *listener = listenerdict.lookup (pidentity);
  81.     if (!listener) return;
  82.     size_t i = 0;
  83.     while (i < listener->objects.size ()) {
  84.         if (listener->objects[i] == pobject) {
  85.             listener->objects.erase (listener->objects.begin () + i);
  86.         } else {
  87.             i += 1;
  88.         }
  89.     }
  90.     if (!listener->objects.empty ()) return;
  91.     listenerdict.remove (listener->id);
  92.     if (listener->prev) {
  93.         listener->prev->next = listener->next;
  94.     } else {
  95.         listeners = listener->next;
  96.     }
  97.     if (listener->next) {
  98.         listener->next->prev = listener->prev;
  99.     }
  100.     free (listener->id);
  101.     delete listener;
  102. }
  103.  
  104. void
  105. Document::Dict::removeIdentityChangeListeners (Object *pobject)
  106. {
  107.     IdentityChangeListener *listener = listeners;
  108.     while (listener) {
  109.         size_t i = 0;
  110.         while (i < listener->objects.size ()) {
  111.             if (listener->objects[i] == pobject) {
  112.                 listener->objects.erase (listener->objects.begin () + i);
  113.             } else {
  114.                 i += 1;
  115.             }
  116.         }
  117.         if (listener->objects.empty ()) {
  118.             IdentityChangeListener *next = listener->next;
  119.             if (listener->prev) {
  120.                 listener->prev->next = listener->next;
  121.             } else {
  122.                 listeners = listener->next;
  123.             }
  124.             if (listener->next) {
  125.                 listener->next->prev = listener->prev;
  126.             }
  127.             listenerdict.remove (listener->id);
  128.             free (listener->id);
  129.             delete listener;
  130.             listener = next;
  131.         } else {
  132.             listener = listener->next;
  133.         }
  134.     }
  135. }
  136.  
  137. void
  138. Document::Dict::invokeIdentityAdded (Document *pdocument, const char *pidentity, Object *pobject)
  139. {
  140.     IdentityChangeListener *listener = listenerdict.lookup (pidentity);
  141.     if (listener) {
  142.         for (size_t i = 0; i < listener->objects.size (); i++) {
  143.             listener->objects[i]->invokeIdentityAdded (pdocument, pidentity, pobject);
  144.         }
  145.     }
  146. }
  147.  
  148. void
  149. Document::Dict::invokeIdentityRemoved (Document *pdocument, const char *pidentity)
  150. {
  151.     IdentityChangeListener *listener = listenerdict.lookup (pidentity);
  152.     if (listener) {
  153.         for (size_t i = 0; i < listener->objects.size (); i++) {
  154.             listener->objects[i]->invokeIdentityRemoved (pdocument, pidentity);
  155.         }
  156.     }
  157. }
  158.  
  159. unsigned int
  160. Document::Dict::isIdentityTracked (const char *id)
  161. {
  162.     return listenerdict.lookup (id) != NULL;
  163. }
  164.  
  165. Document::Document (Scene *scene, const char *purl)
  166. : _numid(0), _dict(new Dict(109)), _updatereq(true), _modifiedreq(false), sizetimers(0), sizelights(0), url(NULL), root(scene),
  167. numtimers(0), timers(NULL), numlights(0), lights(NULL)
  168. {
  169.     if (purl) url = strdup (purl);
  170. #ifdef WITH_JAVA
  171.     javaenv = NULL;
  172.     javaobject = NULL;
  173. #endif
  174. }
  175.  
  176. Document::~Document (void)
  177. {
  178. #ifdef WITH_JAVA
  179.     if (javaenv) {
  180.         if (javaobject) {
  181.             releaseJavaDocument (javaenv);
  182.             javaobject = NULL;
  183.         }
  184.         javaenv = NULL;
  185.     }
  186. #endif
  187.     sig_destroy.invoke (this);
  188.     root->invokeRelease ();
  189.     if (lights) free (lights);
  190.     delete _dict;
  191.     if (url) free (url);
  192. }
  193.  
  194. Document *
  195. Document::newDocument (Thera::Node *node, const char *url)
  196. {
  197.     if (!node) return NULL;
  198.  
  199.     if (strcmp (node->name, "scene")) return NULL;
  200.     const char *defaultns = node->getAttribute ("xmlns");
  201.     if (!defaultns || strcmp (defaultns, getDefaultNamespace ())) return NULL;
  202.  
  203.     Scene *root = new Scene();
  204.     Document *doc = new Document(root, url);
  205.  
  206.     Object::BuildCtx ctx;
  207.     ctx.defaultns = getDefaultNamespace ();
  208.     root->invokeBuild (node, doc, &ctx);
  209.  
  210.     return doc;
  211. }
  212.  
  213. void
  214. Document::requestUpdate (void)
  215. {
  216.     _updatereq = true;
  217. }
  218.  
  219. void
  220. Document::invokeUpdate (void)
  221. {
  222.     if (_updatereq) {
  223.         _updatereq = false;
  224.         Object::UpdateCtx ctx;
  225.         if (root->needUpdate ()) {
  226.             root->invokeUpdate (&ctx, 0);
  227.             _modifiedreq = true;
  228.         }
  229.     }
  230.     if (_modifiedreq) {
  231.         _modifiedreq = false;
  232.         if (root->needModified ()) root->invokeModified (0);
  233.         sig_modified.invoke (this);
  234.     }
  235. }
  236.  
  237. void
  238. Document::requestModified (void)
  239. {
  240.     _modifiedreq = true;
  241. }
  242.  
  243. void
  244. Document::show (Sehle::Graph *graph)
  245. {
  246.     root->show (graph);
  247. }
  248.  
  249. void
  250. Document::hide (void)
  251. {
  252.     root->hide ();
  253. }
  254.  
  255. void
  256. Document::defineObject (Object *object)
  257. {
  258.     _dict->insert (object->id, object);
  259. }
  260.  
  261. Object *
  262. Document::lookupObject (const char *id)
  263. {
  264.     return _dict->lookup (id);
  265. }
  266.  
  267. void
  268. Document::undefObject (const Object *object)
  269. {
  270.     _dict->remove (object->id);
  271. }
  272.  
  273. const char *
  274. Document::getUniqueId (Object *object)
  275. {
  276.     const char *name = object->node->getName ();
  277.     if (!name) name = "NULL";
  278. #if 1
  279.     static int l = 0;
  280.     static char *c = NULL;
  281.     int nlen = (int) strlen (name);
  282.     if ((nlen + 16) > l) {
  283.         l = l << 1;
  284.         if (l < 64) l = 64;
  285.         c = (char *) realloc (c, l);
  286.     }
  287. #else
  288.     static char c[1024];
  289. #endif
  290.     do {
  291.         sprintf (c, "%s_%d", name, ++_numid);
  292.     } while (_dict->lookup (c));
  293.     return c;
  294. }
  295.  
  296. void
  297. Document::addIdentityChangeListener (const char *pidentity, Object *pobject)
  298. {
  299.     _dict->addIdentityChangeListener (pidentity, pobject);
  300. }
  301.  
  302. void
  303. Document::removeIdentityChangeListener (const char *pidentity, Object *pobject)
  304. {
  305.     _dict->removeIdentityChangeListener (pidentity, pobject);
  306. }
  307.  
  308. void
  309. Document::removeIdentityChangeListeners (Object *pobject)
  310. {
  311.     _dict->removeIdentityChangeListeners (pobject);
  312. }
  313.  
  314. void
  315. Document::identityAdded (const char *pidentity, Object *pobject)
  316. {
  317.     _dict->invokeIdentityAdded (this, pidentity, pobject);
  318. }
  319.  
  320. void
  321. Document::identityRemoved (const char *pidentity)
  322. {
  323.     _dict->invokeIdentityRemoved (this, pidentity);
  324. }
  325.  
  326. unsigned int
  327. Document::isIdentityTracked (const char *id)
  328. {
  329.     return _dict->isIdentityTracked (id);
  330. }
  331.  
  332. Thera::Document *
  333. Document::getTheraDocument (void)
  334. {
  335.     if (!root) return NULL;
  336.     return root->node->document;
  337. }
  338.  
  339. Thera::Node *
  340. Document::getTheraRootNode (void)
  341. {
  342.     if (!root) return NULL;
  343.     return root->node;
  344. }
  345.  
  346. void
  347. Document::setURL (const char *purl)
  348. {
  349.     if (!url && !purl) return;
  350.     if (url && purl && !strcmp (url, purl)) return;
  351.     char *old = url;
  352.     url = (purl) ? strdup (purl) : NULL;
  353.     sig_url_changed.invoke (this, old, url);
  354.     if (old) free (old);
  355. }
  356.  
  357. void
  358. Document::addLight (Light *plight)
  359. {
  360.     if (numlights >= sizelights) {
  361.         if (!sizelights) {
  362.             sizelights = 32;
  363.         } else {
  364.             sizelights = sizelights << 1;
  365.         }
  366.         lights = (Light **) realloc (lights, sizelights * sizeof (Light *));
  367.     }
  368.     lights[numlights] = plight;
  369.     numlights += 1;
  370. }
  371.  
  372. void
  373. Document::removeLight (Light *plight)
  374. {
  375.     for (int i = 0; i < numlights; i++) {
  376.         if (lights[i] == plight) {
  377.             numlights -= 1;
  378.             if (numlights) lights[i] = lights[numlights];
  379.             break;
  380.         }
  381.     }
  382. }
  383.  
  384. void
  385. Document::addTimer (Object *ptimer)
  386. {
  387.     if (numtimers >= sizetimers) {
  388.         if (!sizetimers) {
  389.             sizetimers = 32;
  390.         } else {
  391.             sizetimers = sizetimers << 1;
  392.         }
  393.         timers = (Object **) realloc (timers, sizetimers * sizeof (Object *));
  394.     }
  395.     timers[numtimers] = ptimer;
  396.     numtimers += 1;
  397. }
  398.  
  399. void
  400. Document::removeTimer (Object *ptimer)
  401. {
  402.     for (int i = 0; i < numtimers; i++) {
  403.         if (timers[i] == ptimer) {
  404.             numtimers -= 1;
  405.             if (numtimers) timers[i] = timers[numtimers];
  406.             break;
  407.         }
  408.     }
  409. }
  410.  
  411. void
  412. Document::ensureUpdated (int maxretries)
  413. {
  414.     while ((maxretries > 0) && (_updatereq || _modifiedreq)) {
  415.         invokeUpdate ();
  416.         maxretries -= 1;
  417.     }
  418. }
  419.  
  420. void
  421. Document::timeStep (double time)
  422. {
  423.     for (int i = 0; i < numtimers; i++) {
  424.         timers[i]->invokeTimeStep (time);
  425.     }
  426. }
  427.  
  428. const char *
  429. Document::getDefaultNamespace (void)
  430. {
  431.     return "urn:Miletos";
  432. }
  433.  
  434. } // Namespace Miletos
  435.  
  436. #include "animationdata.h"
  437. #include "animationgraph.h"
  438. #include "blockworld.h"
  439. #include "bone.h"
  440. #include "camera.h"
  441. #include "figure.h"
  442. #include "ikchain.h"
  443. #include "light.h"
  444. #include "material.h"
  445. #include "mesh3ds.h"
  446. #include "meshbsp.h"
  447. #include "meshcollada.h"
  448. #include "meshmd5.h"
  449. #include "meshobj.h"
  450. #include "meshobjm.h"
  451. #include "meshxx.h"
  452. #include "particleemitter.h"
  453. #include "poseableitem.h"
  454. #include "primitives.h"
  455. #include "skeleton.h"
  456. #include "sphere.h"
  457. #include "staticmesh.h"
  458. #include "walkcycle.h"
  459. #include "bvh.h"
  460. // Poser
  461. #include "poser/pose.h"
  462. #include "poser/poseablefigure.h"
  463. #include "poser/prop.h"
  464.  
  465. static Arikkei::Dict<const char *, const Miletos::Object::Type *> *types = NULL;
  466.  
  467. static void
  468. add_type (const Miletos::Object::Type *type)
  469. {
  470.     if (!type->tag) {
  471.         fprintf (stderr, "add_type: Type %s has no tag\n", type->name);
  472.         return;
  473.     }
  474.     types->insert (type->tag, type);
  475. }
  476.  
  477. Miletos::Object *
  478. Miletos::Document::newObject (Thera::Node::Type type, const char *defaultns, const char *name)
  479. {
  480.     if (name) {
  481.         if (!strcmp (defaultns, Document::getDefaultNamespace ())) {
  482.             if (!types) {
  483.                 types = new Arikkei::Dict<const char *, const Object::Type *>(101);
  484.                 add_type (AreaLight::type ());
  485.                 add_type (BlockWorld::type ());
  486.                 add_type (Bone::type ());
  487.                 add_type (BoneAnimationBVH::type ());
  488.                 add_type (BoneAnimationOBJM::type ());
  489.                 add_type (BoneAnimationXA::type ());
  490.                 add_type (Box::type ());
  491.                 add_type (Camera::type ());
  492.                 add_type (DayLight::type ());
  493.                 add_type (Defs::type ());
  494.                 add_type (DirectionalLight::type ());
  495.                 add_type (Figure::type ());
  496.                 add_type (Geometry3DS::type ());
  497.                 add_type (GeometryMD5::type ());
  498.                 add_type (GeometryOBJ::type ());
  499.                 add_type (GeometryOBJM::type ());
  500.                 add_type (GeometryXX::type ());
  501.                 add_type (Group::type ());
  502.                 add_type (IKChain::type ());
  503.                 add_type (KeyFrameAnimationOBJM::type ());
  504.                 add_type (MaterialDNS::type ());
  505.                 add_type (MaterialNoise::type ());
  506.                 add_type (MeshBSP::type ());
  507.                 add_type (Morph::type ());
  508.                 add_type (MorphTargetOBJM::type ());
  509.                 add_type (MorphTargetXA::type ());
  510.                 add_type (ParticleEmitter::type ());
  511.                 add_type (PointLight::type ());
  512.                 add_type (PoseableItem::type ());
  513.                 add_type (Scene::type ());
  514.                 add_type (Skeleton::type ());
  515.                 add_type (SkinnedGeometryCollada::type ());
  516.                 add_type (StaticGeometryCollada::type ());
  517.                 add_type (Sphere::type ());
  518.                 add_type (SMesh::type ());
  519.                 add_type (SpotLight::type ());
  520.  
  521.                 add_type (Animation::Biped::type ());
  522.                 add_type (Animation::BoneKeys::type ());
  523.                 add_type (Animation::Controller::type ());
  524.                 add_type (Animation::Graph::type ());
  525.                 add_type (Animation::Pose::type ());
  526.                 add_type (Animation::Sequence::type ());
  527.                 add_type (Animation::SkinAnimation::type ());
  528.                 add_type (Animation::Transition::type ());
  529.                 add_type (Animation::WalkCycle::type ());
  530.                 add_type (Poser::Geometry::type ());
  531.                 add_type (Poser::Pose::type ());
  532.                 add_type (Poser::Prop::type ());
  533.             }
  534.             const Object::Type *type = types->lookup (name);
  535.             if (type) {
  536.                 return type->factory ();
  537.             }
  538. #if 0
  539.             } else if (!strcmp (name, "geometryOBJ")) {
  540.                 return new GeometryOBJ();
  541.             } else if (!strcmp (name, "meshOBJ")) {
  542.                 return new MeshOBJ();
  543. #endif
  544.         } else if (!strcmp (defaultns, Collada::getDefaultNamespace ())) {
  545.             // Collada
  546.             Object *object = Collada::newObject (type, defaultns, name);
  547.             if (object) return object;
  548.         }
  549.     } else if (type == Thera::Node::TEXT) {
  550.         return new Text();
  551.     }
  552.     if (debug) fprintf (stderr, "Factory::newObject: Unknown object: type %d name %s\n", type, name);
  553.     return new Unknown();
  554. }
  555.  
  556.