dsodb.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:13k
源码类别:

OpenGL

开发平台:

Visual C++

  1. //
  2. // C++ Implementation: dsodb
  3. //
  4. // Description:
  5. //
  6. //
  7. // Author: Toti <root@totibox>, (C) 2005
  8. //
  9. // Copyright: See COPYING file that comes with this distribution
  10. //
  11. //
  12. #include <cmath>
  13. #include <cstdlib>
  14. #include <cstdio>
  15. #include <cassert>
  16. #include <algorithm>
  17. #include <celmath/mathlib.h>
  18. #include <celmath/plane.h>
  19. #include <celutil/util.h>
  20. #include <celutil/bytes.h>
  21. #include <celutil/utf8.h>
  22. #include <celengine/dsodb.h>
  23. #include "celestia.h"
  24. #include "astro.h"
  25. #include "parser.h"
  26. #include "parseobject.h"
  27. #include "multitexture.h"
  28. #include "meshmanager.h"
  29. #include <celutil/debug.h>
  30. #include <celengine/galaxy.h>
  31. #include <celengine/globular.h>
  32. #include <celengine/opencluster.h>
  33. #include <celengine/nebula.h>
  34. using namespace std;
  35. // 100 Gly - on the order of the current size of the universe
  36. const float DSO_OCTREE_ROOT_SIZE   = 1.0e11f;
  37. static const float DSO_OCTREE_MAGNITUDE   = 8.0f;
  38. static const float DSO_EXTRA_ROOM         = 0.01f; // Reserve 1% capacity for extra DSOs
  39.                                                    // (useful as a complement of binary loaded DSOs)
  40. const char* DSODatabase::FILE_HEADER      = "CEL_DSOs";
  41. // Used to sort DSO pointers by catalog number
  42. struct PtrCatalogNumberOrderingPredicate
  43. {
  44.     int unused;
  45.     PtrCatalogNumberOrderingPredicate() {};
  46.     bool operator()(const DeepSkyObject* const & dso0, const DeepSkyObject* const & dso1) const
  47.     {
  48.         return (dso0->getCatalogNumber() < dso1->getCatalogNumber());
  49.     }
  50. };
  51. DSODatabase::DSODatabase():
  52.     nDSOs                (0),
  53.     capacity             (0),
  54.     DSOs                 (NULL),
  55.     namesDB              (NULL),
  56.     catalogNumberIndex   (NULL),
  57.     octreeRoot           (NULL),
  58.     nextAutoCatalogNumber(0xfffffffe),
  59.     avgAbsMag            (0)
  60. {
  61. }
  62. DSODatabase::~DSODatabase()
  63. {
  64.     if (DSOs != NULL)
  65.         delete [] DSOs;
  66.     if (catalogNumberIndex != NULL)
  67.         delete [] catalogNumberIndex;
  68. }
  69. DeepSkyObject* DSODatabase::find(const uint32 catalogNumber) const
  70. {
  71.     Galaxy refDSO;  //terrible hack !!
  72.     refDSO.setCatalogNumber(catalogNumber);
  73.     DeepSkyObject** dso   = lower_bound(catalogNumberIndex,
  74.                                         catalogNumberIndex + nDSOs,
  75.                                         &refDSO,
  76.                                         PtrCatalogNumberOrderingPredicate());
  77.     if (dso != catalogNumberIndex + nDSOs && (*dso)->getCatalogNumber() == catalogNumber)
  78.         return *dso;
  79.     else
  80.         return NULL;
  81. }
  82. DeepSkyObject* DSODatabase::find(const string& name) const
  83. {
  84.     if (name.empty())
  85.         return NULL;
  86.     if (namesDB != NULL)
  87.     {
  88.         uint32 catalogNumber   = namesDB->findCatalogNumberByName(name);
  89.         if (catalogNumber != DeepSkyObject::InvalidCatalogNumber)
  90.             return find(catalogNumber);
  91.     }
  92.     return NULL;
  93. }
  94. vector<string> DSODatabase::getCompletion(const string& name) const
  95. {
  96.     vector<string> completion;
  97.     // only named DSOs are supported by completion.
  98.     if (!name.empty() && namesDB != NULL)
  99.         return namesDB->getCompletion(name);
  100.     else
  101.         return completion;
  102. }
  103. string DSODatabase::getDSOName(const DeepSkyObject* const & dso, bool i18n) const
  104. {
  105.     uint32 catalogNumber    = dso->getCatalogNumber();
  106.     if (namesDB != NULL)
  107.     {
  108.         DSONameDatabase::NumberIndex::const_iterator iter   = namesDB->getFirstNameIter(catalogNumber);
  109.         if (iter != namesDB->getFinalNameIter() && iter->first == catalogNumber)
  110.         {
  111.             if (i18n && iter->second != _(iter->second.c_str()))
  112.                 return _(iter->second.c_str());
  113.             else
  114.                 return iter->second;
  115.         }
  116.     }
  117.     return "";
  118. }
  119. string DSODatabase::getDSONameList(const DeepSkyObject* const & dso, const unsigned int maxNames) const
  120. {
  121.     string dsoNames;
  122.     unsigned int catalogNumber   = dso->getCatalogNumber();
  123.     DSONameDatabase::NumberIndex::const_iterator iter  = namesDB->getFirstNameIter(catalogNumber);
  124.     unsigned int count = 0;
  125.     while (iter != namesDB->getFinalNameIter() && iter->first == catalogNumber && count < maxNames)
  126.     {
  127.         if (count != 0)
  128.             dsoNames   += " / ";
  129.         dsoNames   += iter->second;
  130.         ++iter;
  131.         ++count;
  132.     }
  133.     return dsoNames;
  134. }
  135. void DSODatabase::findVisibleDSOs(DSOHandler&    dsoHandler,
  136.                                   const Point3d& obsPos,
  137.                                   const Quatf&   obsOrient,
  138.                                   float fovY,
  139.                                   float aspectRatio,
  140.                                   float limitingMag) const
  141. {
  142.     // Compute the bounding planes of an infinite view frustum
  143.     Planed frustumPlanes[5];
  144.     Vec3d  planeNormals[5];
  145.     Quatd obsOrientd(obsOrient.w, obsOrient.x, obsOrient.y, obsOrient.z);
  146.     Mat3d   rot    = obsOrientd.toMatrix3();
  147.     double  h      = tan(fovY / 2);
  148.     double  w      = h * aspectRatio;
  149.     planeNormals[0] = Vec3d( 0,  1, -h);
  150.     planeNormals[1] = Vec3d( 0, -1, -h);
  151.     planeNormals[2] = Vec3d( 1,  0, -w);
  152.     planeNormals[3] = Vec3d(-1,  0, -w);
  153.     planeNormals[4] = Vec3d( 0,  0, -1);
  154.     for (int i = 0; i < 5; ++i)
  155.     {
  156.         planeNormals[i].normalize();                        //TODO: prenormalize ?
  157.         planeNormals[i]    = planeNormals[i] * rot;
  158.         frustumPlanes[i]   = Planed(planeNormals[i], obsPos);
  159.     }
  160.     octreeRoot->processVisibleObjects(dsoHandler,
  161.                                       obsPos,
  162.                                       frustumPlanes,
  163.                                       limitingMag,
  164.                                       DSO_OCTREE_ROOT_SIZE);
  165. }
  166. void DSODatabase::findCloseDSOs(DSOHandler&    dsoHandler,
  167.                                 const Point3d& obsPos,
  168.                                 float radius) const
  169. {
  170.     octreeRoot->processCloseObjects(dsoHandler,
  171.                                     obsPos,
  172.                                     radius,
  173.                                     DSO_OCTREE_ROOT_SIZE);
  174. }
  175. DSONameDatabase* DSODatabase::getNameDatabase() const
  176. {
  177.     return namesDB;
  178. }
  179. void DSODatabase::setNameDatabase(DSONameDatabase* _namesDB)
  180. {
  181.     namesDB    = _namesDB;
  182. }
  183. bool DSODatabase::load(istream& in, const string& resourcePath)
  184. {
  185.     Tokenizer tokenizer(&in);
  186.     Parser    parser(&tokenizer);
  187.     while (tokenizer.nextToken() != Tokenizer::TokenEnd)
  188.     {
  189.         string objType;
  190.         string objName;
  191.         if (tokenizer.getTokenType() != Tokenizer::TokenName)
  192.         {
  193.             DPRINTF(0, "Error parsing deep sky catalog file.n");
  194.             return false;
  195.         }
  196.         objType = tokenizer.getNameValue();
  197.         bool   autoGenCatalogNumber   = true;
  198.         uint32 objCatalogNumber       = DeepSkyObject::InvalidCatalogNumber;
  199.         if (tokenizer.getTokenType() == Tokenizer::TokenNumber)
  200.         {
  201.             autoGenCatalogNumber   = false;
  202.             objCatalogNumber       = (uint32) tokenizer.getNumberValue();
  203.             tokenizer.nextToken();
  204.         }
  205.         if (autoGenCatalogNumber)
  206.         {
  207.             objCatalogNumber   = nextAutoCatalogNumber--;
  208.         }
  209.         if (tokenizer.nextToken() != Tokenizer::TokenString)
  210.         {
  211.             DPRINTF(0, "Error parsing deep sky catalog file: bad name.n");
  212.             return false;
  213.         }
  214.         objName = tokenizer.getStringValue();
  215.         Value* objParamsValue    = parser.readValue();
  216.         if (objParamsValue == NULL ||
  217.             objParamsValue->getType() != Value::HashType)
  218.         {
  219.             DPRINTF(0, "Error parsing deep sky catalog entry %sn", objName.c_str());
  220.             return false;
  221.         }
  222.         Hash* objParams    = objParamsValue->getHash();
  223.         assert(objParams != NULL);
  224.         DeepSkyObject* obj = NULL;
  225.         if (compareIgnoringCase(objType, "Galaxy") == 0)
  226.             obj = new Galaxy();
  227. else if (compareIgnoringCase(objType, "Globular") == 0)
  228. obj = new Globular();
  229. else if (compareIgnoringCase(objType, "Nebula") == 0)        
  230.             obj = new Nebula();
  231.         else if (compareIgnoringCase(objType, "OpenCluster") == 0)
  232.             obj = new OpenCluster();
  233.         if (obj != NULL && obj->load(objParams, resourcePath))
  234.         {
  235.             delete objParamsValue;
  236.             // Ensure that the DSO array is large enough
  237.             if (nDSOs == capacity)
  238.             {
  239.                 // Grow the array by 5%--this may be too little, but the
  240.                 // assumption here is that there will be small numbers of
  241.                 // DSOs in text files added to a big collection loaded from
  242.                 // a binary file.
  243.                 capacity    = (int) (capacity * 1.05);
  244.                 // 100 DSOs seems like a reasonable minimum
  245.                 if (capacity < 100)
  246.                     capacity   = 100;
  247.                 DeepSkyObject** newDSOs   = new DeepSkyObject*[capacity];
  248.                 if (newDSOs == NULL)
  249.                 {
  250.                     DPRINTF(0, "Out of memory!");
  251.                     return false;
  252.                 }
  253.                 if (DSOs != NULL)
  254.                 {
  255.                     copy(DSOs, DSOs + nDSOs, newDSOs);
  256.                     delete[] DSOs;
  257.                 }
  258.                 DSOs   = newDSOs;
  259.             }
  260.             DSOs[nDSOs++]    = obj;
  261.             obj->setCatalogNumber(objCatalogNumber);
  262.             if (namesDB != NULL && !objName.empty())
  263.             {
  264.                 // List of names will replace any that already exist for
  265.                 // this DSO.
  266.                 namesDB->erase(objCatalogNumber);
  267.                 // Iterate through the string for names delimited
  268.                 // by ':', and insert them into the DSO database.
  269.                 // Note that db->add() will skip empty names.
  270.                 string::size_type startPos   = 0;
  271.                 while (startPos != string::npos)
  272.                 {
  273.                     string::size_type next    = objName.find(':', startPos);
  274.                     string::size_type length  = string::npos;
  275.                     if (next != string::npos)
  276.                     {
  277.                         length   = next - startPos;
  278.                         ++next;
  279.                     }
  280.                     string DSOName = objName.substr(startPos, length);
  281.                     namesDB->add(objCatalogNumber, DSOName);
  282.                     if (DSOName != _(DSOName.c_str()))
  283.                         namesDB->add(objCatalogNumber, _(DSOName.c_str()));
  284.                     startPos   = next;
  285.                 }
  286.             }
  287.         }
  288.         else
  289.         {
  290.             DPRINTF(1, "Bad Deep Sky Object definition--will continue parsing file.n");
  291.             delete objParamsValue;
  292.             return false;
  293.         }
  294.     }
  295.     return true;
  296. }
  297. bool DSODatabase::loadBinary(istream&)
  298. {
  299.     // TODO: define a binary dso file format
  300.     return true;
  301. }
  302. void DSODatabase::finish()
  303. {
  304.     buildOctree();
  305.     buildIndexes();
  306.     calcAvgAbsMag();
  307.     /*
  308.     // Put AbsMag = avgAbsMag for Add-ons without AbsMag entry
  309.     for (int i = 0; i < nDSOs; ++i)
  310.     {
  311.         if(DSOs[i]->getAbsoluteMagnitude() == DSO_DEFAULT_ABS_MAGNITUDE)
  312.             DSOs[i]->setAbsoluteMagnitude((float)avgAbsMag);
  313.     }
  314.     */
  315.     clog << _("Loaded ") << nDSOs << _(" deep space objects") << 'n';
  316. }
  317. void DSODatabase::buildOctree()
  318. {
  319.     DPRINTF(1, "Sorting DSOs into octree . . .n");
  320.     float absMag             = astro::appToAbsMag(DSO_OCTREE_MAGNITUDE, DSO_OCTREE_ROOT_SIZE * (float) sqrt(3.0));
  321.     // TODO: investigate using a different center--it's possible that more
  322.     // objects end up straddling the base level nodes when the center of the
  323.     // octree is at the origin.
  324.     DynamicDSOOctree* root   = new DynamicDSOOctree(Point3d(0, 0, 0), absMag);
  325.     for (int i = 0; i < nDSOs; ++i)
  326.     {
  327.         root->insertObject(DSOs[i], DSO_OCTREE_ROOT_SIZE);
  328.     }
  329.     DPRINTF(1, "Spatially sorting DSOs for improved locality of reference . . .n");
  330.     DeepSkyObject** sortedDSOs    = new DeepSkyObject*[nDSOs];
  331.     DeepSkyObject** firstDSO      = sortedDSOs;
  332.     // The spatial sorting part is useless for DSOs since we
  333.     // are storing pointers to objects and not the objects themselves:
  334.     root->rebuildAndSort(octreeRoot, firstDSO);
  335.     DPRINTF(1, "%d DSOs totaln", (int) (firstDSO - sortedDSOs));
  336.     DPRINTF(1, "Octree has %d nodes and %d DSOs.n",
  337.             1 + octreeRoot->countChildren(), octreeRoot->countObjects());
  338.     //cout<<"DSOs:  "<< octreeRoot->countObjects()<<"   Nodes:"
  339.     //    <<octreeRoot->countChildren() <<endl;
  340.     // Clean up . . .
  341.     delete[] DSOs;
  342.     delete   root;
  343.     DSOs = sortedDSOs;
  344. }
  345. void DSODatabase::calcAvgAbsMag()
  346. {
  347.     uint32 nDSOeff = size();
  348.     for (int i = 0; i < nDSOs; ++i)
  349.     {
  350.         double DSOmag = DSOs[i]->getAbsoluteMagnitude();
  351.         // take only DSO's with realistic AbsMag entry
  352.         // (> DSO_DEFAULT_ABS_MAGNITUDE) into account
  353.         if (DSOmag > DSO_DEFAULT_ABS_MAGNITUDE)
  354.             avgAbsMag += DSOmag;
  355.         else if (nDSOeff > 1)
  356.             nDSOeff--;
  357.         //cout << nDSOs<<"  "<<DSOmag<<"  "<<nDSOeff<<endl;
  358.     }
  359.     avgAbsMag /= (double) nDSOeff;
  360.     //cout<<avgAbsMag<<endl;
  361. }
  362. void DSODatabase::buildIndexes()
  363. {
  364.     // This should only be called once for the database
  365.     // assert(catalogNumberIndexes[0] == NULL);
  366.     DPRINTF(1, "Building catalog number indexes . . .n");
  367.     catalogNumberIndex = new DeepSkyObject*[nDSOs];
  368.     for (int i = 0; i < nDSOs; ++i)
  369.         catalogNumberIndex[i] = DSOs[i];
  370.     sort(catalogNumberIndex, catalogNumberIndex + nDSOs, PtrCatalogNumberOrderingPredicate());
  371. }
  372. double DSODatabase::getAverageAbsoluteMagnitude() const
  373. {
  374.     return avgAbsMag;
  375. }