celestia/src/galaxy.cpp

331 lines
7.9 KiB
C++

// galaxy.cpp
//
// Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include <algorithm>
#include "celestia.h"
#include "mathlib.h"
#include "util.h"
#include "astro.h"
#include "galaxy.h"
#include "perlin.h"
#include "parser.h"
using namespace std;
static bool formsInitialized = false;
static vector<Point3f>* spiralPoints = NULL;
static vector<Point3f>* ellipticalPoints = NULL;
static vector<Point3f>* irregularPoints = NULL;
static GalacticForm* spiralForm = NULL;
static GalacticForm* irregularForm = NULL;
static GalacticForm** ellipticalForms = NULL;
static void InitializeForms();
struct GalaxyTypeName
{
char* name;
Galaxy::GalaxyType type;
};
static GalaxyTypeName GalaxyTypeNames[] =
{
{ "S0", Galaxy::S0 },
{ "Sa", Galaxy::Sa },
{ "Sb", Galaxy::Sb },
{ "Sc", Galaxy::Sc },
{ "SBa", Galaxy::SBa },
{ "SBb", Galaxy::SBb },
{ "SBc", Galaxy::SBc },
{ "E0", Galaxy::E0 },
{ "E1", Galaxy::E1 },
{ "E2", Galaxy::E2 },
{ "E3", Galaxy::E3 },
{ "E4", Galaxy::E4 },
{ "E5", Galaxy::E5 },
{ "E6", Galaxy::E6 },
{ "E7", Galaxy::E7 },
{ "Irr", Galaxy::Irr },
};
Galaxy::Galaxy() :
name(""),
position(0, 0, 0), orientation(1), radius(1),
detail(1.0f),
form(NULL)
{
}
string Galaxy::getName() const
{
return name;
}
void Galaxy::setName(const string& s)
{
name = s;
}
Point3d Galaxy::getPosition() const
{
return position;
}
void Galaxy::setPosition(Point3d p)
{
position = p;
}
Quatf Galaxy::getOrientation() const
{
return orientation;
}
void Galaxy::setOrientation(Quatf q)
{
orientation = q;
}
float Galaxy::getRadius() const
{
return radius;
}
void Galaxy::setRadius(float r)
{
radius = r;
}
float Galaxy::getDetail() const
{
return detail;
}
void Galaxy::setDetail(float d)
{
detail = d;
}
Galaxy::GalaxyType Galaxy::getType() const
{
return type;
}
void Galaxy::setType(Galaxy::GalaxyType _type)
{
type = _type;
if (!formsInitialized)
InitializeForms();
switch (type)
{
case Sa:
case Sb:
case Sc:
case SBa:
case SBb:
case SBc:
form = spiralForm;
break;
case Irr:
form = irregularForm;
break;
case E0:
case E1:
case E2:
case E3:
case E4:
case E5:
case E6:
case E7:
form = ellipticalForms[type - E0];
break;
}
}
GalacticForm* Galaxy::getForm() const
{
return form;
}
void InitializeForms()
{
int galaxySize = 5000;
int i;
// Initialize the spiral form--this is a big hack
spiralPoints = new vector<Point3f>();
spiralPoints->reserve(galaxySize);
for (i = 0; i < galaxySize; i++)
{
float r = Mathf::frand();
float theta = Mathf::sfrand() * PI;
if (r > 0.2f)
{
theta = (Mathf::sfrand() + Mathf::sfrand() + Mathf::sfrand()) * (float) PI / 2.0f / 3.0f;
if (Mathf::sfrand() < 0)
theta += (float) PI;
}
theta += (float) log(r + 1) * 3 * PI;
float x = r * (float) cos(theta);
float z = r * (float) sin(theta);
float y = Mathf::sfrand() * 0.1f * 1.0f / (1 + 2 * r);
spiralPoints->insert(spiralPoints->end(), Point3f(x, y, z));
}
spiralForm = new GalacticForm();
spiralForm->points = spiralPoints;
spiralForm->scale = Vec3f(1, 1, 1);
irregularPoints = new vector<Point3f>;
irregularPoints->reserve(galaxySize);
i = 0;
while (i < galaxySize)
{
Point3f p(Mathf::sfrand(), Mathf::sfrand(), Mathf::sfrand());
float r = p.distanceFromOrigin();
if (r < 1)
{
float prob = (1 - r) * (fractalsum(Point3f(p.x + 5, p.y + 5, p.z + 5), 8) + 1) * 0.5f;
if (Mathf::frand() < prob)
{
irregularPoints->insert(irregularPoints->end(), p);
i++;
}
}
}
irregularForm = new GalacticForm();
irregularForm->points = irregularPoints;
irregularForm->scale = Vec3f(1, 1, 1);
ellipticalPoints = new vector<Point3f>();
ellipticalPoints->reserve(galaxySize);
i = 0;
while (i < galaxySize)
{
Point3f p(Mathf::sfrand(), Mathf::sfrand(), Mathf::sfrand());
float r = p.distanceFromOrigin();
if (r < 1)
{
if (Mathf::frand() < cube(1 - r))
{
ellipticalPoints->insert(ellipticalPoints->end(), p);
i++;
}
}
}
ellipticalForms = new GalacticForm*[8];
for (int eform = 0; eform <= 7; eform++)
{
ellipticalForms[eform] = new GalacticForm();
ellipticalForms[eform]->points = ellipticalPoints;
ellipticalForms[eform]->scale = Vec3f(1.0f, 1.0f - (float) eform / 8.0f, 1.0f);
}
formsInitialized = true;
}
GalaxyList* ReadGalaxyList(istream& in)
{
GalaxyList* galaxies = new GalaxyList();
Tokenizer tokenizer(&in);
Parser parser(&tokenizer);
while (tokenizer.nextToken() != Tokenizer::TokenEnd)
{
if (tokenizer.getTokenType() != Tokenizer::TokenString)
{
DPRINTF("Error parsing galaxies file.\n");
for_each(galaxies->begin(), galaxies->end(), deleteFunc<Galaxy*>());
delete galaxies;
return NULL;
}
Galaxy* galaxy = new Galaxy();
galaxy->setName(tokenizer.getStringValue());
Value* galaxyParamsValue = parser.readValue();
if (galaxyParamsValue == NULL || galaxyParamsValue->getType() != Value::HashType)
{
DPRINTF("Error parsing galaxy entry %s\n", galaxy->getName().c_str());
for_each(galaxies->begin(), galaxies->end(), deleteFunc<Galaxy*>());
delete galaxy;
return NULL;
}
Hash* galaxyParams = galaxyParamsValue->getHash();
// Get position
Vec3d position(0.0, 0.0, 0.0);
if (galaxyParams->getVector("Position", position))
{
galaxy->setPosition(Point3d(position.x, position.y, position.z));
}
else
{
double distance = 1.0;
double RA = 0.0;
double dec = 0.0;
galaxyParams->getNumber("Distance", distance);
galaxyParams->getNumber("RA", RA);
galaxyParams->getNumber("Dec", dec);
Point3f p = astro::equatorialToCelestialCart(RA, dec, distance);
galaxy->setPosition(Point3d(p.x, p.y, p.z));
cout << galaxy->getName() << ": " << p.x << ", " << p.y << ", " << p.z << '\n';
}
// Get orientation
Vec3d axis(1.0, 0.0, 0.0);
double angle = 0.0;
galaxyParams->getVector("Axis", axis);
galaxyParams->getNumber("Angle", angle);
Quatf q(1);
q.setAxisAngle(Vec3f((float) axis.x, (float) axis.y, (float) axis.z),
(float) angle);
galaxy->setOrientation(q);
double radius = 0.0;
galaxyParams->getNumber("Radius", radius);
galaxy->setRadius((float) radius);
double detail = 1.0;
galaxyParams->getNumber("Detail", detail);
galaxy->setDetail((float) detail);
string typeName;
galaxyParams->getString("Type", typeName);
Galaxy::GalaxyType type = Galaxy::Irr;
for (int i = 0; i < sizeof(GalaxyTypeNames) / sizeof(GalaxyTypeNames[0]); i++)
{
if (GalaxyTypeNames[i].name == typeName)
{
type = GalaxyTypeNames[i].type;
break;
}
}
galaxy->setType(type);
galaxies->insert(galaxies->end(), galaxy);
}
return galaxies;
}
ostream& operator<<(ostream& s, const Galaxy::GalaxyType& sc)
{
return s << GalaxyTypeNames[static_cast<int>(sc)].name;
}