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

OpenGL

开发平台:

Visual C++

  1. // galaxy.cpp
  2. //
  3. // Copyright (C) 2001-2005, Chris Laurel <claurel@shatters.net>
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. #include <cstring>
  10. #include <fstream>
  11. #include <algorithm>
  12. #include <cstdio>
  13. #include <cassert>
  14. #include "celestia.h"
  15. #include <celmath/mathlib.h>
  16. #include <celmath/perlin.h>
  17. #include <celmath/intersect.h>
  18. #include "astro.h"
  19. #include "galaxy.h"
  20. #include <celutil/util.h>
  21. #include <celutil/debug.h>
  22. #include "gl.h"
  23. #include "vecgl.h"
  24. #include "render.h"
  25. #include "texture.h"
  26. using namespace std;
  27. static int width = 128, height = 128;
  28. static Color colorTable[256];
  29. static const unsigned int GALAXY_POINTS  = 3500;
  30. static bool formsInitialized = false;
  31. static GalacticForm** spiralForms     = NULL;
  32. static GalacticForm** ellipticalForms = NULL;
  33. static GalacticForm*  irregularForm   = NULL;
  34. static Texture* galaxyTex = NULL;
  35. static void InitializeForms();
  36. static GalacticForm* buildGalacticForms(const std::string& filename);
  37. float Galaxy::lightGain  = 0.0f;
  38. bool operator < (const Blob& b1, const Blob& b2)
  39. {
  40.   return (b1.position.distanceFromOrigin() < b2.position.distanceFromOrigin());
  41. }
  42. struct GalaxyTypeName
  43. {
  44.     const char* name;
  45.     Galaxy::GalaxyType type;
  46. };
  47. static GalaxyTypeName GalaxyTypeNames[] =
  48. {
  49.     { "S0",  Galaxy::S0 },
  50.     { "Sa",  Galaxy::Sa },
  51.     { "Sb",  Galaxy::Sb },
  52.     { "Sc",  Galaxy::Sc },
  53.     { "SBa", Galaxy::SBa },
  54.     { "SBb", Galaxy::SBb },
  55.     { "SBc", Galaxy::SBc },
  56.     { "E0",  Galaxy::E0 },
  57.     { "E1",  Galaxy::E1 },
  58.     { "E2",  Galaxy::E2 },
  59.     { "E3",  Galaxy::E3 },
  60.     { "E4",  Galaxy::E4 },
  61.     { "E5",  Galaxy::E5 },
  62.     { "E6",  Galaxy::E6 },
  63.     { "E7",  Galaxy::E7 },
  64.     { "Irr", Galaxy::Irr },
  65. };
  66. static void GalaxyTextureEval(float u, float v, float /*w*/, unsigned char *pixel)
  67. {
  68.     float r = 0.9f - (float) sqrt(u * u + v * v );
  69.     if (r < 0)
  70.         r = 0;
  71.     int pixVal = (int) (r * 255.99f);
  72. #ifdef HDR_COMPRESS
  73.     pixel[0] = 127;
  74.     pixel[1] = 127;
  75.     pixel[2] = 127;
  76. #else
  77.     pixel[0] = 255;//65;
  78.     pixel[1] = 255;//64;
  79.     pixel[2] = 255;//65;
  80. #endif
  81.     pixel[3] = pixVal;
  82. }
  83. Galaxy::Galaxy() :
  84.     detail(1.0f),
  85.     customTmpName(NULL),
  86.     form(NULL)
  87. {
  88. }
  89. float Galaxy::getDetail() const
  90. {
  91.     return detail;
  92. }
  93. void Galaxy::setDetail(float d)
  94. {
  95.     detail = d;
  96. }
  97. void Galaxy::setCustomTmpName(const string& tmpNameStr)
  98. {
  99.     if (customTmpName == NULL)
  100.         customTmpName = new string(tmpNameStr);
  101.     else
  102.         *customTmpName = tmpNameStr;
  103. }
  104. string Galaxy::getCustomTmpName() const
  105. {
  106.     if (customTmpName == NULL)
  107.         return "";
  108.     else
  109.         return *customTmpName;
  110. }
  111. const char* Galaxy::getType() const
  112. {
  113.     return GalaxyTypeNames[(int) type].name;
  114. }
  115. void Galaxy::setType(const string& typeStr)
  116. {
  117.     type = Galaxy::Irr;
  118.     for (int i = 0; i < (int) (sizeof(GalaxyTypeNames) / sizeof(GalaxyTypeNames[0])); ++i)
  119.     {
  120.         if (GalaxyTypeNames[i].name == typeStr)
  121.         {
  122.             type = GalaxyTypeNames[i].type;
  123.             break;
  124.         }
  125.     }
  126.     if (!formsInitialized)
  127.         InitializeForms();
  128. if (customTmpName != NULL)
  129. {
  130. form = buildGalacticForms("models/" + *customTmpName);
  131. }
  132. else
  133. {
  134. switch (type)
  135. {
  136. case S0:
  137. case Sa:
  138. case Sb:
  139. case Sc:
  140. case SBa:
  141. case SBb:
  142. case SBc:
  143. form = spiralForms[type - S0];
  144. break;
  145. case E0:
  146. case E1:
  147. case E2:
  148. case E3:
  149. case E4:
  150. case E5:
  151. case E6:
  152. case E7:
  153. form = ellipticalForms[type - E0];
  154. //form = NULL;
  155. break;
  156. case Irr:
  157. form = irregularForm;
  158. break;
  159. }
  160. }
  161. }
  162. size_t Galaxy::getDescription(char* buf, size_t bufLength) const
  163. {
  164.     return snprintf(buf, bufLength, _("Galaxy (Hubble type: %s)"), getType());
  165. }
  166. GalacticForm* Galaxy::getForm() const
  167. {
  168.     return form;
  169. }
  170. const char* Galaxy::getObjTypeName() const
  171. {
  172.     return "galaxy";
  173. }
  174. // TODO: This value is just a guess.
  175. // To be optimal, it should actually be computed:
  176. static const float RADIUS_CORRECTION     = 0.025f;
  177. static const float MAX_SPIRAL_THICKNESS  = 0.06f;
  178. bool Galaxy::pick(const Ray3d& ray,
  179.                   double& distanceToPicker,
  180.                   double& cosAngleToBoundCenter) const
  181. {
  182.     if (!isVisible())
  183.         return false;
  184.     
  185.     // The ellipsoid should be slightly larger to compensate for the fact
  186.     // that blobs are considered points when galaxies are built, but have size
  187.     // when they are drawn.
  188.     float yscale = (type < E0 )? MAX_SPIRAL_THICKNESS: form->scale.y + RADIUS_CORRECTION;
  189.     Vec3d ellipsoidAxes(getRadius()*(form->scale.x + RADIUS_CORRECTION),
  190.                         getRadius()* yscale,
  191.                         getRadius()*(form->scale.z + RADIUS_CORRECTION));
  192.     Quatf qf= getOrientation();
  193.     Quatd qd(qf.w, qf.x, qf.y, qf.z);
  194.     return testIntersection(Ray3d(Point3d() + (ray.origin - getPosition()), ray.direction) * conjugate(qd).toMatrix3(),
  195.                             Ellipsoidd(ellipsoidAxes),
  196.                             distanceToPicker,
  197.                             cosAngleToBoundCenter);
  198. }
  199. bool Galaxy::load(AssociativeArray* params, const string& resPath)
  200. {
  201.     double detail = 1.0;
  202.     params->getNumber("Detail", detail);
  203.     setDetail((float) detail);
  204. string customTmpName;
  205. if(params->getString("CustomTemplate",customTmpName))
  206. setCustomTmpName(customTmpName);
  207.     string typeName;
  208.     params->getString("Type", typeName);
  209.     setType(typeName);
  210.     return DeepSkyObject::load(params, resPath);
  211. }
  212. void Galaxy::render(const GLContext& context,
  213.                     const Vec3f& offset,
  214.                     const Quatf& viewerOrientation,
  215.                     float brightness,
  216.                     float pixelSize)
  217. {
  218.     if (form == NULL)
  219.         renderGalaxyEllipsoid(context, offset, viewerOrientation, brightness, pixelSize);
  220.     else
  221.         renderGalaxyPointSprites(context, offset, viewerOrientation, brightness, pixelSize);
  222. }
  223. void Galaxy::renderGalaxyPointSprites(const GLContext&,
  224.                                       const Vec3f& offset,
  225.                                       const Quatf& viewerOrientation,
  226.                                       float brightness,
  227.                                       float pixelSize)
  228. {
  229.     if (form == NULL)
  230.         return;
  231.     /* We'll first see if the galaxy's apparent size is big enough to
  232.        be noticeable on screen; if it's not we'll break right here,
  233.        avoiding all the overhead of the matrix transformations and
  234.        GL state changes: */
  235.         float distanceToDSO = offset.length() - getRadius();
  236.         if (distanceToDSO < 0)
  237.             distanceToDSO = 0;
  238.         float minimumFeatureSize = pixelSize * distanceToDSO;
  239.         float size  = 2 * getRadius();
  240.         if (size < minimumFeatureSize)
  241.             return;
  242.     if (galaxyTex == NULL)
  243.     {
  244.         galaxyTex = CreateProceduralTexture(width, height, GL_RGBA,
  245.                                             GalaxyTextureEval);
  246.     }
  247.     assert(galaxyTex != NULL);
  248.     glEnable(GL_TEXTURE_2D);
  249.     galaxyTex->bind();
  250.     Mat3f viewMat = viewerOrientation.toMatrix3();
  251.     Vec3f v0 = Vec3f(-1, -1, 0) * viewMat;
  252.     Vec3f v1 = Vec3f( 1, -1, 0) * viewMat;
  253.     Vec3f v2 = Vec3f( 1,  1, 0) * viewMat;
  254.     Vec3f v3 = Vec3f(-1,  1, 0) * viewMat;
  255.     //Mat4f m = (getOrientation().toMatrix4() *
  256.     //           Mat4f::scaling(form->scale) *
  257.     //           Mat4f::scaling(getRadius()));
  258.     Mat3f m =
  259.         Mat3f::scaling(form->scale)*getOrientation().toMatrix3()*Mat3f::scaling(size);
  260.     // Note: fixed missing factor of 2 in getRadius() scaling of galaxy diameter!
  261.     // Note: fixed correct ordering of (non-commuting) operations!
  262.     int   pow2  = 1;
  263.     vector<Blob>* points = form->blobs;
  264.     unsigned int nPoints = (unsigned int) (points->size() * clamp(getDetail()));
  265.     // corrections to avoid excessive brightening if viewed e.g. edge-on
  266.     float brightness_corr = 1.0f;
  267.     float cosi;
  268.     if (type < E0 || type > E3) //all galaxies, except ~round elliptics
  269.     {
  270.         cosi = Vec3f(0,1,0) * getOrientation().toMatrix3()
  271.                             * offset/offset.length();
  272.         brightness_corr = (float) sqrt(abs(cosi));
  273.         if (brightness_corr < 0.2f)
  274.             brightness_corr = 0.2f;
  275.     }
  276.     if (type > E3) // only elliptics with higher ellipticities
  277.     {
  278.         cosi = Vec3f(1,0,0) * getOrientation().toMatrix3()
  279.                             * offset/offset.length();
  280.         brightness_corr = brightness_corr * (float) abs((cosi));
  281.         if (brightness_corr < 0.45f)
  282.             brightness_corr = 0.45f;
  283.     }
  284.     glBegin(GL_QUADS);
  285.     for (unsigned int i = 0; i < nPoints; ++i)
  286.     {
  287.         if ((i & pow2) != 0)
  288.         {
  289.             pow2 <<= 1;
  290.             size /= 1.55f;
  291.             if (size < minimumFeatureSize)
  292.                 break;
  293.         }
  294.         Blob    b  = (*points)[i];
  295.         Point3f p  = b.position * m;
  296.         float   br = b.brightness / 255.0f;
  297.         Color   c      = colorTable[b.colorIndex];     // lookup static color table
  298.         Point3f relPos = p + offset;
  299.         float screenFrac = size / relPos.distanceFromOrigin();
  300.         if (screenFrac < 0.1f)
  301.         {
  302.             float btot = ((type > SBc) && (type < Irr))? 2.5f: 5.0f;
  303.             float a  = btot * (0.1f - screenFrac) * brightness_corr * brightness * br;
  304.             glColor4f(c.red(), c.green(), c.blue(), (4.0f*lightGain + 1.0f)*a);
  305.             glTexCoord2f(0, 0);          glVertex(p + (v0 * size));
  306.             glTexCoord2f(1, 0);          glVertex(p + (v1 * size));
  307.             glTexCoord2f(1, 1);          glVertex(p + (v2 * size));
  308.             glTexCoord2f(0, 1);          glVertex(p + (v3 * size));
  309.         }
  310.     }
  311.     glEnd();
  312. }
  313. void Galaxy::renderGalaxyEllipsoid(const GLContext& context,
  314.                                    const Vec3f& offset,
  315.                                    const Quatf&,
  316.                                    float,
  317.                                    float pixelSize)
  318. {
  319.     float discSizeInPixels = pixelSize * getRadius() / offset.length();
  320.     unsigned int nRings = (unsigned int) (discSizeInPixels / 4.0f);
  321.     unsigned int nSlices = (unsigned int) (discSizeInPixels / 4.0f);
  322.     nRings = max(nRings, 100u);
  323.     nSlices = max(nSlices, 100u);
  324.     VertexProcessor* vproc = context.getVertexProcessor();
  325.     if (vproc == NULL)
  326.         return;
  327.     //int e = min(max((int) type - (int) E0, 0), 7);
  328.     Vec3f scale = Vec3f(1.0f, 0.9f, 1.0f) * getRadius();
  329.     Vec3f eyePos_obj = -offset * (~getOrientation()).toMatrix3();
  330.     vproc->enable();
  331.     vproc->use(vp::ellipticalGalaxy);
  332.     vproc->parameter(vp::EyePosition, eyePos_obj);
  333.     vproc->parameter(vp::Scale, scale);
  334.     vproc->parameter(vp::InverseScale,
  335.                      Vec3f(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z));
  336.     vproc->parameter((vp::Parameter) 23, eyePos_obj.length() / scale.x, 0.0f, 0.0f, 0.0f);
  337.     glRotate(getOrientation());
  338.     glDisable(GL_TEXTURE_2D);
  339.     glColor4f(1.0f, 1.0f, 1.0f, 0.3f);
  340.     for (unsigned int i = 0; i < nRings; i++)
  341.     {
  342.         float phi0 = (float) PI * ((float) i / (float) nRings - 0.5f);
  343.         float phi1 = (float) PI * ((float) (i + 1) / (float) nRings - 0.5f);
  344.         glBegin(GL_QUAD_STRIP);
  345.         for (unsigned int j = 0; j <= nSlices; j++)
  346.         {
  347.             float theta = (float) (PI * 2) * (float) j / (float) nSlices;
  348.             float sinTheta = (float) sin(theta);
  349.             float cosTheta = (float) cos(theta);
  350.             glVertex3f((float) cos(phi0) * cosTheta * scale.x,
  351.                        (float) sin(phi0)            * scale.y,
  352.                        (float) cos(phi0) * sinTheta * scale.z);
  353.             glVertex3f((float) cos(phi1) * cosTheta * scale.x,
  354.                        (float) sin(phi1)            * scale.y,
  355.                        (float) cos(phi1) * sinTheta * scale.z);
  356.         }
  357.         glEnd();
  358.     }
  359.     glEnable(GL_TEXTURE_2D);
  360.     vproc->disable();
  361. }
  362. unsigned int Galaxy::getRenderMask() const
  363. {
  364.     return Renderer::ShowGalaxies;
  365. }
  366. unsigned int Galaxy::getLabelMask() const
  367. {
  368.     return Renderer::GalaxyLabels;
  369. }
  370. void Galaxy::increaseLightGain()
  371. {
  372.     lightGain  += 0.05f;
  373.     if (lightGain > 1.0f)
  374.         lightGain  = 1.0f;
  375. }
  376. void Galaxy::decreaseLightGain()
  377. {
  378.     lightGain  -= 0.05f;
  379.     if (lightGain < 0.0f)
  380.         lightGain  = 0.0f;
  381. }
  382. float Galaxy::getLightGain()
  383. {
  384.     return lightGain;
  385. }
  386. void Galaxy::setLightGain(float lg)
  387. {
  388.     if (lg < 0.0f)
  389.         lightGain = 0.0f;
  390.     else if (lg > 1.0f)
  391.         lightGain = 1.0f;
  392.     else
  393.         lightGain = lg;
  394. }
  395. GalacticForm* buildGalacticForms(const std::string& filename)
  396. {
  397. Blob b;
  398. vector<Blob>* galacticPoints = new vector<Blob>;
  399. // Load templates in standard .png format
  400. int width, height, rgb, j = 0, kmin = 9;
  401. unsigned char value;
  402. float h = 0.75f;
  403. Image* img;
  404. img = LoadPNGImage(filename);
  405. if (img == NULL)
  406. {
  407. cout<<"nThe galaxy template *** "<<filename<<" *** could not be loaded!nn";
  408. return NULL;
  409. }
  410. width  = img->getWidth();
  411. height = img->getHeight();
  412. rgb    = img->getComponents();
  413. for (int i = 0; i < width * height; i++)
  414. {
  415. value = img->getPixels()[rgb * i];
  416. if (value > 10)
  417. {
  418. float x, y, z, r2, yy, prob;
  419. z  = floor(i /(float) width);
  420. x  = (i - width * z - 0.5f * (width - 1)) / (float) width;
  421. z  = (0.5f * (height - 1) - z) / (float) height;
  422. x  += Mathf::sfrand() * 0.008f;
  423. z  += Mathf::sfrand() * 0.008f;
  424. r2 = x * x + z * z;
  425. if ( strcmp ( filename.c_str(), "models/E0.png") != 0 )
  426. {
  427. float y0 = 0.5f * MAX_SPIRAL_THICKNESS * sqrt((float)value/256.0f) * exp(- 5.0f * r2);
  428. float B, yr;
  429. B = (r2 > 0.35f)? 1.0f: 0.75f; // the darkness of the "dust lane", 0 < B < 1
  430. float p0 = 1.0f - B * exp(-h * h); // the uniform reference probability, envelopping prob*p0.
  431. do
  432. {
  433. // generate "thickness" y of spirals with emulation of a dust lane
  434. // in galctic plane (y=0)
  435. yr =  Mathf::sfrand() * h;
  436. prob = (1.0f - B * exp(-yr * yr))/p0;
  437. } while (Mathf::frand() > prob);
  438. b.brightness  = value * prob;
  439. y = y0 * yr / h;
  440. }
  441. else
  442. {
  443. // generate spherically symmetric distribution from E0.png
  444. do
  445. {
  446. yy = Mathf::sfrand();
  447. float ry2 = 1.0f - yy * yy;
  448. prob = ry2 > 0? sqrt(ry2): 0.0f;
  449. } while (Mathf::frand() > prob);
  450. y = yy * sqrt(0.25f - r2) ;
  451. b.brightness  = value;
  452. kmin = 12;
  453. }
  454. b.position    = Point3f(x, y, z);
  455. unsigned int rr =  (unsigned int) (b.position.distanceFromOrigin() * 511);
  456. b.colorIndex  = rr < 256? rr: 255;
  457. galacticPoints->push_back(b);
  458. j++;
  459.  }
  460. }
  461.     delete img;
  462. galacticPoints->reserve(j);
  463. // sort to start with the galaxy center region (x^2 + y^2 + z^2 ~ 0), such that
  464. // the biggest (brightest) sprites will be localized there!
  465. sort(galacticPoints->begin(), galacticPoints->end());
  466. // reshuffle the galaxy points randomly...except the first kmin+1 in the center!
  467. // the higher that number the stronger the central "glow"
  468. random_shuffle( galacticPoints->begin() + kmin, galacticPoints->end());
  469. GalacticForm* galacticForm  = new GalacticForm();
  470. galacticForm->blobs         = galacticPoints;
  471. galacticForm->scale         = Vec3f(1.0f, 1.0f, 1.0f);
  472. return galacticForm;
  473. }
  474. void InitializeForms()
  475. {
  476.     // build color table:
  477.     for (unsigned int i = 0; i < 256; i++)
  478.     {
  479.         float rr, gg, bb;
  480.         //
  481.         // generic Hue profile as deduced from true-color imaging for spirals
  482.         // Hue in degrees
  483.         float hue = (i < 28)? 25 * tanh(0.0615f * (27 - i)): 25 * tanh(0.0615f * (27 - i)) + 220;
  484.         //convert Hue to RGB
  485. DeepSkyObject::hsv2rgb(&rr, &gg, &bb, hue, 0.20f, 1.0f);
  486.         colorTable[i]  = Color(rr, gg, bb);
  487.     }
  488.     // Spiral Galaxies, 7 classical Hubble types
  489.     spiralForms   = new GalacticForm*[7];
  490.     spiralForms[Galaxy::S0]   = buildGalacticForms("models/S0.png");
  491.     spiralForms[Galaxy::Sa]   = buildGalacticForms("models/Sa.png");
  492.     spiralForms[Galaxy::Sb]   = buildGalacticForms("models/Sb.png");
  493.     spiralForms[Galaxy::Sc]   = buildGalacticForms("models/Sc.png");
  494.     spiralForms[Galaxy::SBa]  = buildGalacticForms("models/SBa.png");
  495.     spiralForms[Galaxy::SBb]  = buildGalacticForms("models/SBb.png");
  496.     spiralForms[Galaxy::SBc]  = buildGalacticForms("models/SBc.png");
  497.     // Elliptical Galaxies , 8 classical Hubble types, E0..E7,
  498.     //
  499.     // To save space: generate spherical E0 template from S0 disk
  500.     // via rescaling by (1.0f, 3.8f, 1.0f).
  501.     ellipticalForms = new GalacticForm*[8];
  502.     for (unsigned int eform  = 0; eform <= 7; ++eform)
  503.     {
  504.         float ell = 1.0f - (float) eform / 8.0f;
  505.         // note the correct x,y-alignment of 'ell' scaling!!
  506.     // build all elliptical templates from rescaling E0
  507.     ellipticalForms[eform] = buildGalacticForms("models/E0.png");
  508.     if (*ellipticalForms)
  509.     ellipticalForms[eform]->scale = Vec3f(ell, ell, 1.0f);
  510.         // account for reddening of ellipticals rel.to spirals
  511.         if (*ellipticalForms)
  512.         {
  513.          unsigned int nPoints = (unsigned int) (ellipticalForms[eform]->blobs->size());
  514. for (unsigned int i = 0; i < nPoints; ++i)
  515.      {
  516.              (*ellipticalForms[eform]->blobs)[i].colorIndex = (unsigned int) ceil(0.76f * (*ellipticalForms[eform]->blobs)[i].colorIndex);
  517.          }
  518.         }
  519.     }
  520.     //Irregular Galaxies
  521.     unsigned int galaxySize = GALAXY_POINTS, ip = 0;
  522.     Blob b;
  523.     Point3f p;
  524.     vector<Blob>* irregularPoints = new vector<Blob>;
  525.     irregularPoints->reserve(galaxySize);
  526.     while (ip < galaxySize)
  527.     {
  528.         p        = Point3f(Mathf::sfrand(), Mathf::sfrand(), Mathf::sfrand());
  529.         float r  = p.distanceFromOrigin();
  530.         if (r < 1)
  531.         {
  532.             float prob = (1 - r) * (fractalsum(Point3f(p.x + 5, p.y + 5, p.z + 5), 8) + 1) * 0.5f;
  533.             if (Mathf::frand() < prob)
  534.             {
  535.                 b.position   = p;
  536.                 b.brightness = 64u;
  537.                 unsigned int rr =  (unsigned int) (r * 511);
  538.              b.colorIndex  = rr < 256? rr: 255;
  539.                 irregularPoints->push_back(b);
  540.                 ++ip;
  541.             }
  542.         }
  543.     }
  544.     irregularForm        = new GalacticForm();
  545.     irregularForm->blobs = irregularPoints;
  546.     irregularForm->scale = Vec3f(0.5f, 0.5f, 0.5f);
  547.     formsInitialized = true;
  548. }
  549. ostream& operator<<(ostream& s, const Galaxy::GalaxyType& sc)
  550. {
  551.     return s << GalaxyTypeNames[static_cast<int>(sc)].name;
  552. }