00001
00002
00003
00004
00005
00006
00007
00008
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;
00081 pixel[1] = 255;
00082 pixel[2] = 255;
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
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
00157
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
00227
00228
00229
00230 float size = 2 * getRadius();
00231 Mat3f m =
00232 Mat3f::scaling(form->scale)*getOrientation().toMatrix3()*Mat3f::scaling(size);
00233
00234
00235
00236
00237 int pow2 = 1;
00238
00239 vector<Blob>* points = form->blobs;
00240 unsigned int nPoints = (unsigned int) (points->size() * clamp(getDetail()));
00241
00242
00243
00244 float brightness_corr = 1.0f;
00245 float cosi;
00246
00247 if (type < E0 || type > E3)
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)
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
00273
00274 b.colorIndex = type < E0 ? b.colorIndex : (unsigned int) ceil(0.3f*b.colorIndex);
00275 Color c = colorTable[b.colorIndex];
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
00413
00414
00415 int i;
00416 float f, p, q, t;
00417
00418 if( s == 0 ) {
00419
00420 *r = *g = *b = v;
00421 return;
00422 }
00423
00424 h /= 60;
00425 i = (int) floorf( h );
00426 f = h - (float) i;
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
00501 for (i = 0; i < 256; ++i)
00502 {
00503 float rr,gg,bb;
00504 float rho = (float) i / 255.0f;
00505
00506 float h = 30.0f * (float) tanh(15.68 * (0.1086 - rho));
00507 if (rho > 0.1086f)
00508 h += 260.0f;
00509
00510 Galaxy::hsv2rgb( &rr, &gg, &bb, h , 0.15f, 1.0f);
00511 colorTable[i] = Color( rr,gg,bb);
00512 }
00513
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
00527
00528
00529
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
00539 ellipticalForms[eform]->scale = Vec3f(ell, 3.8*ell, 1.0f);
00540 }
00541
00542
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 }