Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

galaxy.cpp

Go to the documentation of this file.
00001 // galaxy.cpp
00002 //
00003 // Copyright (C) 2001-2005, Chris Laurel <claurel@shatters.net>
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 
00010 #include <fstream>
00011 #include <algorithm>
00012 #include <cstdio>
00013 #include <cassert>
00014 #include "celestia.h"
00015 #include <celmath/mathlib.h>
00016 #include <celmath/perlin.h>
00017 #include "astro.h"
00018 #include "galaxy.h"
00019 #include <celutil/util.h>
00020 #include <celutil/debug.h>
00021 #include "gl.h"
00022 #include "vecgl.h"
00023 #include "render.h"
00024 #include "texture.h"
00025 
00026 using namespace std;
00027 
00028 static Color colorTable[256];
00029 
00030 static const unsigned int GALAXY_POINTS  = 7000;
00031 
00032 static bool formsInitialized = false;
00033 
00034 static GalacticForm** spiralForms     = NULL;
00035 static GalacticForm** ellipticalForms = NULL;
00036 static GalacticForm*  irregularForm   = NULL;
00037 
00038 static Texture* galaxyTex = NULL;
00039 
00040 static void InitializeForms();
00041 
00042 float Galaxy::lightGain  = 0.0f;
00043 
00044 
00045 struct GalaxyTypeName
00046 {
00047     const char* name;
00048     Galaxy::GalaxyType type;
00049 };
00050 
00051 static GalaxyTypeName GalaxyTypeNames[] = 
00052 {
00053     { "S0",  Galaxy::S0 },
00054     { "Sa",  Galaxy::Sa },
00055     { "Sb",  Galaxy::Sb },
00056     { "Sc",  Galaxy::Sc },
00057     { "SBa", Galaxy::SBa },
00058     { "SBb", Galaxy::SBb },
00059     { "SBc", Galaxy::SBc },
00060     { "E0",  Galaxy::E0 },
00061     { "E1",  Galaxy::E1 },
00062     { "E2",  Galaxy::E2 },
00063     { "E3",  Galaxy::E3 },
00064     { "E4",  Galaxy::E4 },
00065     { "E5",  Galaxy::E5 },
00066     { "E6",  Galaxy::E6 },
00067     { "E7",  Galaxy::E7 },
00068     { "Irr", Galaxy::Irr },
00069 };
00070 
00071 
00072 static void GalaxyTextureEval(float u, float v, float w,
00073                               unsigned char *pixel)
00074 {
00075     float r = 0.9f - (float) sqrt(u * u + v * v);
00076     if (r < 0)
00077         r = 0;
00078 
00079     int pixVal = (int) (r * 255.99f);
00080     pixel[0] = 255;//65;
00081     pixel[1] = 255;//64;
00082     pixel[2] = 255;//65;
00083     pixel[3] = pixVal;
00084 }
00085 
00086 
00087 Galaxy::Galaxy() :
00088     detail(1.0f),
00089     form(NULL)
00090 {
00091 }
00092 
00093 
00094 float Galaxy::getDetail() const
00095 {
00096     return detail;
00097 }
00098 
00099 
00100 void Galaxy::setDetail(float d)
00101 {
00102     detail = d;
00103 }
00104 
00105 
00106 const char* Galaxy::getType() const
00107 {
00108     return GalaxyTypeNames[(int) type].name;
00109 }
00110 
00111 void Galaxy::setType(const string& typeStr)
00112 {
00113     type = Galaxy::Irr;
00114     for (int i = 0; i < (int) (sizeof(GalaxyTypeNames) / sizeof(GalaxyTypeNames[0])); ++i)
00115     {
00116         if (GalaxyTypeNames[i].name == typeStr)
00117         {
00118             type = GalaxyTypeNames[i].type;
00119             break;
00120         }
00121     }
00122 
00123     if (!formsInitialized)
00124         InitializeForms();
00125     switch (type)
00126     {
00127     case S0:
00128     case Sa:
00129     case Sb:
00130     case Sc:
00131     case SBa:
00132     case SBb:
00133     case SBc:
00134         form = spiralForms[type - S0];
00135         break;
00136     case E0:
00137     case E1:
00138     case E2:
00139     case E3:
00140     case E4:
00141     case E5:
00142     case E6:
00143     case E7:
00144         form = ellipticalForms[type - E0];
00145         //form = NULL;
00146         break;
00147     case Irr:
00148         form = irregularForm;
00149         break;    
00150     }
00151 } 
00152 
00153 
00154 size_t Galaxy::getDescription(char* buf, size_t bufLength) const
00155 {
00156     // Should use snprintf, but it's not available on Windows; the
00157     // buffer *must* be large enough.
00158     return sprintf(buf, _("Galaxy (Hubble type: %s)"), getType());
00159 }
00160 
00161 
00162 GalacticForm* Galaxy::getForm() const
00163 {
00164     return form;
00165 }
00166 
00167 
00168 bool Galaxy::load(AssociativeArray* params, const string& resPath)
00169 {
00170     double detail = 1.0;
00171     params->getNumber("Detail", detail);
00172     setDetail((float) detail);
00173 
00174     string typeName;
00175     params->getString("Type", typeName);
00176     setType(typeName);
00177     
00178     return DeepSkyObject::load(params, resPath);
00179 }
00180 
00181 
00182 void Galaxy::render(const GLContext& context,
00183                     const Vec3f& offset,
00184                     const Quatf& viewerOrientation,
00185                     float brightness,
00186                     float pixelSize)
00187 {
00188     if (form == NULL)
00189         renderGalaxyEllipsoid(context, offset, viewerOrientation, brightness, pixelSize);
00190     else
00191         renderGalaxyPointSprites(context, offset, viewerOrientation, brightness, pixelSize);
00192 }
00193 
00194 
00195 void Galaxy::renderGalaxyPointSprites(const GLContext& context,
00196                                       const Vec3f& offset,
00197                                       const Quatf& viewerOrientation,
00198                                       float brightness,
00199                                       float pixelSize)
00200 {
00201     if (form == NULL)
00202         return;
00203 
00204     if (galaxyTex == NULL)
00205     {
00206         galaxyTex = CreateProceduralTexture(128, 128, GL_RGBA,
00207                                             GalaxyTextureEval);
00208     }
00209     assert(galaxyTex != NULL);
00210 
00211     glEnable(GL_TEXTURE_2D);
00212     galaxyTex->bind();
00213 
00214     Mat3f viewMat = viewerOrientation.toMatrix3();
00215     Vec3f v0 = Vec3f(-1, -1, 0) * viewMat;
00216     Vec3f v1 = Vec3f( 1, -1, 0) * viewMat;
00217     Vec3f v2 = Vec3f( 1,  1, 0) * viewMat;
00218     Vec3f v3 = Vec3f(-1,  1, 0) * viewMat;
00219 
00220     float distanceToDSO = offset.length() - getRadius();
00221     if (distanceToDSO < 0)
00222         distanceToDSO = 0;
00223 
00224     float minimumFeatureSize = pixelSize * distanceToDSO;
00225 
00226     //Mat4f m = (getOrientation().toMatrix4() *
00227     //           Mat4f::scaling(form->scale) *
00228     //           Mat4f::scaling(getRadius()));
00229 
00230     float  size  = 2 * getRadius();
00231     Mat3f m =
00232         Mat3f::scaling(form->scale)*getOrientation().toMatrix3()*Mat3f::scaling(size);
00233 
00234     // Note: fixed missing factor of 2 in getRadius() scaling of galaxy diameter!
00235     // Note: fixed correct ordering of (non-commuting) operations!
00236 
00237     int   pow2  = 1;
00238 
00239     vector<Blob>* points = form->blobs;
00240     unsigned int nPoints = (unsigned int) (points->size() * clamp(getDetail()));
00241 
00242     // corrections to avoid excessive brightening if viewed e.g. edge-on
00243 
00244     float brightness_corr = 1.0f;
00245     float cosi;
00246 
00247     if (type < E0 || type > E3) //all galaxies, except ~round elliptics
00248     {
00249         cosi = Vec3f(0,1,0) * getOrientation().toMatrix3()
00250                             * offset/offset.length();
00251         brightness_corr = (float) sqrt(abs(cosi));
00252         if (brightness_corr < 0.2f)
00253             brightness_corr = 0.2f;
00254     }
00255 
00256     if (type > E3) // only elliptics with higher ellipticities
00257     {
00258         cosi = Vec3f(1,0,0) * getOrientation().toMatrix3()
00259                             * offset/offset.length();
00260         brightness_corr = brightness_corr * (float) sqrt(abs((cosi)));
00261         if (brightness_corr < 0.65f)
00262             brightness_corr = 0.65f;
00263     }
00264 
00265     glBegin(GL_QUADS);
00266     for (unsigned int i = 0; i < nPoints; ++i)
00267     {
00268         Blob    b    = (*points)[i];
00269         Point3f p    = b.position * m;            
00270         float   br   = b.brightness;
00271 
00272         // Reddening for elliptical galaxies
00273 
00274         b.colorIndex = type < E0 ? b.colorIndex : (unsigned int) ceil(0.3f*b.colorIndex);
00275         Color   c    = colorTable[b.colorIndex];     // lookup static color table
00276           
00277         Point3f relPos = p + offset;
00278   
00279         if ((i & pow2) != 0)
00280         {
00281             pow2 <<= 1;
00282             size /= 1.57f;
00283             if (size < minimumFeatureSize)
00284                 break;
00285         }          
00286             
00287         float screenFrac = size / relPos.distanceFromOrigin();
00288           
00289         if (screenFrac < 0.1f)
00290         {
00291             float a  = 3.5f * (0.1f - screenFrac) * brightness_corr * brightness * br;
00292             
00293             glColor4f(c.red(), c.green(), c.blue(), (4.0f*lightGain + 1.0f)*a);
00294               
00295             glTexCoord2f(0, 0);          glVertex(p + (v0 * size));
00296             glTexCoord2f(1, 0);          glVertex(p + (v1 * size));
00297             glTexCoord2f(1, 1);          glVertex(p + (v2 * size));
00298             glTexCoord2f(0, 1);          glVertex(p + (v3 * size));
00299         }
00300     }
00301     glEnd();
00302 }
00303 
00304 
00305 void Galaxy::renderGalaxyEllipsoid(const GLContext& context,
00306                                    const Vec3f& offset,
00307                                    const Quatf& viewerOrientation,
00308                                    float brightness,
00309                                    float pixelSize)
00310 {
00311     float discSizeInPixels = pixelSize * getRadius() / offset.length();
00312     unsigned int nRings = (unsigned int) (discSizeInPixels / 4.0f);
00313     unsigned int nSlices = (unsigned int) (discSizeInPixels / 4.0f);
00314     nRings = max(nRings, 100);
00315     nSlices = max(nSlices, 100);
00316 
00317     VertexProcessor* vproc = context.getVertexProcessor();
00318     if (vproc == NULL)
00319         return;
00320 
00321     int e = min(max((int) type - (int) E0, 0), 7);
00322     Vec3f scale = Vec3f(1.0f, 0.9f, 1.0f) * getRadius();
00323     Vec3f eyePos_obj = -offset * (~getOrientation()).toMatrix3();
00324 
00325     vproc->enable();
00326     vproc->use(vp::ellipticalGalaxy);
00327 
00328     vproc->parameter(vp::EyePosition, eyePos_obj);
00329     vproc->parameter(vp::Scale, scale);
00330     vproc->parameter(vp::InverseScale,
00331                      Vec3f(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z));
00332     vproc->parameter((vp::Parameter) 23, eyePos_obj.length() / scale.x, 0.0f, 0.0f, 0.0f);
00333 
00334     glRotate(getOrientation());
00335 
00336     glDisable(GL_TEXTURE_2D);
00337     glColor4f(1.0f, 1.0f, 1.0f, 0.3f);
00338     for (unsigned int i = 0; i < nRings; i++)
00339     {
00340         float phi0 = (float) PI * ((float) i / (float) nRings - 0.5f);
00341         float phi1 = (float) PI * ((float) (i + 1) / (float) nRings - 0.5f);
00342 
00343         glBegin(GL_QUAD_STRIP);
00344         for (unsigned int j = 0; j <= nSlices; j++)
00345         {
00346             float theta = (float) (PI * 2) * (float) j / (float) nSlices;
00347             float sinTheta = (float) sin(theta);
00348             float cosTheta = (float) cos(theta);
00349             
00350             glVertex3f((float) cos(phi0) * cosTheta * scale.x,
00351                        (float) sin(phi0)            * scale.y,
00352                        (float) cos(phi0) * sinTheta * scale.z);
00353             glVertex3f((float) cos(phi1) * cosTheta * scale.x,
00354                        (float) sin(phi1)            * scale.y,
00355                        (float) cos(phi1) * sinTheta * scale.z);
00356         }
00357         glEnd();
00358     }
00359     glEnable(GL_TEXTURE_2D);
00360 
00361     vproc->disable();
00362 }
00363 
00364 
00365 unsigned int Galaxy::getRenderMask() const
00366 {
00367     return Renderer::ShowGalaxies;
00368 }
00369 
00370 
00371 unsigned int Galaxy::getLabelMask() const
00372 {
00373     return Renderer::GalaxyLabels;
00374 }
00375 
00376 
00377 void Galaxy::increaseLightGain()
00378 {
00379     lightGain  += 0.05f;
00380     if (lightGain > 1.0f)
00381         lightGain  = 1.0f;
00382 } 
00383 
00384 
00385 void Galaxy::decreaseLightGain()
00386 {
00387     lightGain  -= 0.05f;
00388     if (lightGain < 0.0f)
00389         lightGain  = 0.0f;  
00390 } 
00391 
00392 
00393 float Galaxy::getLightGain()
00394 {
00395     return lightGain;
00396 } 
00397 
00398 
00399 void Galaxy::setLightGain(float lg)
00400 {
00401     if (lg < 0.0f)
00402         lightGain = 0.0f;
00403     else if (lg > 1.0f)
00404         lightGain = 1.0f;
00405     else
00406         lightGain = lg;
00407 }
00408 
00409 
00410 void Galaxy::hsv2rgb( float *r, float *g, float *b, float h, float s, float v )
00411 {
00412 // r,g,b values are from 0 to 1
00413 // h = [0,360], s = [0,1], v = [0,1]
00414 
00415    int i;
00416    float f, p, q, t;
00417 
00418    if( s == 0 ) {
00419        // achromatic (grey)
00420        *r = *g = *b = v;
00421    return;
00422    }
00423 
00424    h /= 60;            // sector 0 to 5
00425    i = (int) floorf( h );
00426    f = h - (float) i;            // factorial part of h
00427    p = v * ( 1 - s );
00428    q = v * ( 1 - s * f );
00429    t = v * ( 1 - s * ( 1 - f ) );
00430 
00431    switch( i ) {
00432    case 0:
00433      *r = v;
00434      *g = t;
00435      *b = p;
00436      break;
00437    case 1:
00438      *r = q;
00439      *g = v;
00440      *b = p;
00441      break;
00442    case 2:
00443      *r = p;
00444      *g = v;
00445      *b = t;
00446      break;
00447    case 3:
00448      *r = p;
00449      *g = q;
00450      *b = v;
00451      break;
00452    case 4:
00453      *r = t;
00454      *g = p;
00455      *b = v;
00456      break;
00457    default:              *r = v;
00458      *g = p;
00459      *b = q;
00460      break;
00461    }
00462 }
00463 
00464 
00465 GalacticForm* buildGalacticForms(const std::string& filename)
00466 {
00467     unsigned int galaxySize = GALAXY_POINTS;
00468     Blob b;    
00469     vector<Blob>* galacticPoints = new vector<Blob>;
00470     galacticPoints->reserve(galaxySize);
00471 
00472     ifstream inFile(filename.c_str());    
00473     while (inFile.good())
00474     {
00475         float x, y, z, br;
00476         inFile >> x;
00477         inFile >> y;
00478         inFile >> z;
00479         inFile >> br;
00480       
00481         b.position    = Point3f(x, y, z);
00482         b.brightness  = br;
00483         b.colorIndex  = (unsigned int) (b.position.distanceFromOrigin() * 255);
00484       
00485         galacticPoints->push_back(b);
00486     }          
00487     
00488     GalacticForm* galacticForm  = new GalacticForm();
00489     galacticForm->blobs         = galacticPoints;
00490     galacticForm->scale         = Vec3f(1.0f, 1.0f, 1.0f);
00491     
00492     return galacticForm;
00493 };
00494 
00495 
00496 void InitializeForms()
00497 {
00498     unsigned int i = 0;
00499 
00500     // build color table:
00501     for (i = 0; i < 256; ++i)
00502     {
00503         float rr,gg,bb;
00504         float rho  = (float) i / 255.0f;
00505         // generic Hue profile as deduced from true-color imaging for spirals
00506         float h = 30.0f * (float) tanh(15.68 * (0.1086 - rho));
00507         if (rho > 0.1086f)
00508             h += 260.0f;
00509         //convert Hue to RGB
00510         Galaxy::hsv2rgb( &rr, &gg, &bb, h , 0.15f, 1.0f);
00511         colorTable[i]  = Color( rr,gg,bb);
00512     }
00513     // Spiral Galaxies, 7 classical Hubble types
00514     
00515     spiralForms   = new GalacticForm*[7];
00516         
00517     spiralForms[Galaxy::S0]   = buildGalacticForms("models/S0.pts");
00518     spiralForms[Galaxy::Sa]   = buildGalacticForms("models/Sa.pts");
00519     spiralForms[Galaxy::Sb]   = buildGalacticForms("models/Sb.pts");
00520     spiralForms[Galaxy::Sc]   = buildGalacticForms("models/Sc.pts");
00521     spiralForms[Galaxy::SBa]  = buildGalacticForms("models/SBa.pts");
00522 
00523     spiralForms[Galaxy::SBb]  = buildGalacticForms("models/SBb.pts");
00524     spiralForms[Galaxy::SBc]  = buildGalacticForms("models/SBc.pts");
00525 
00526     // Elliptical Galaxies , 8 classical Hubble types, E0..E7,
00527     //
00528     // To save space: generate spherical E0 template from S0 disk
00529     // via rescaling by (1.0f, 3.8f, 1.0f).
00530 
00531     ellipticalForms = new GalacticForm*[8];
00532 
00533     for (unsigned int eform  = 0; eform <= 7; ++eform)
00534     {
00535         float ell = 1.0f - (float) eform / 8.0f;
00536         ellipticalForms[eform] = new GalacticForm();
00537         ellipticalForms[eform]->blobs = spiralForms[Galaxy::S0]->blobs;
00538         // note the correct x,y-alignment of 'ell' scaling!!
00539         ellipticalForms[eform]->scale = Vec3f(ell, 3.8*ell, 1.0f);
00540     }
00541 
00542     //Irregular Galaxies
00543     unsigned int galaxySize = GALAXY_POINTS;
00544     Blob b;    
00545     Point3f p;    
00546     
00547     
00548     vector<Blob>* irregularPoints = new vector<Blob>;
00549     irregularPoints->reserve(galaxySize);
00550     
00551     i = 0;
00552     while (i < galaxySize)
00553     {
00554         p        = Point3f(Mathf::sfrand(), Mathf::sfrand(), Mathf::sfrand());
00555         float r  = p.distanceFromOrigin();
00556         if (r < 1)
00557         {
00558             float prob = (1 - r) * (fractalsum(Point3f(p.x + 5, p.y + 5, p.z + 5), 8) + 1) * 0.5f;
00559             if (Mathf::frand() < prob)
00560             {
00561                 b.position   = p;
00562                 b.brightness = 1.0f;  
00563                 b.colorIndex = (unsigned int) (r*255);
00564                 irregularPoints->push_back(b);
00565                 ++i;
00566             }
00567         }
00568     }
00569     irregularForm        = new GalacticForm();
00570     irregularForm->blobs = irregularPoints;
00571     irregularForm->scale = Vec3f(1.0f, 0.1f, 1.0f);
00572 
00573     formsInitialized = true;
00574 }
00575 
00576 
00577 ostream& operator<<(ostream& s, const Galaxy::GalaxyType& sc)
00578 {
00579     return s << GalaxyTypeNames[static_cast<int>(sc)].name;
00580 }

Generated on Sat Jan 14 22:30:27 2006 for Celestia by  doxygen 1.4.1