00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "CaelumPrecompiled.h"
00022 #include "PointStarfield.h"
00023 #include "GeometryFactory.h"
00024 #include "CaelumExceptions.h"
00025 #include "Astronomy.h"
00026
00027 using namespace Ogre;
00028
00029 namespace Caelum
00030 {
00031 const Ogre::String PointStarfield::BILLBOARD_MATERIAL_NAME = "Caelum/StarPoint";
00032 const Ogre::Degree PointStarfield::DEFAULT_OBSERVER_POSITION_REBUILD_DELTA = Ogre::Degree(0.1);
00033
00034 PointStarfield::PointStarfield (
00035 Ogre::SceneManager *sceneMgr,
00036 Ogre::SceneNode *caelumRootNode,
00037 bool initWithCatalogue)
00038 {
00039 mMag0PixelSize = 16;
00040 mMinPixelSize = 4;
00041 mMaxPixelSize = 6;
00042 mMagnitudeScale = Math::Pow(100, 0.2);
00043 mObserverLatitude = 45;
00044 mObserverLongitude = 0;
00045 mObserverPositionRebuildDelta = DEFAULT_OBSERVER_POSITION_REBUILD_DELTA;
00046
00047 String uniqueId = StringConverter::toString ((size_t)this);
00048
00049 MaterialPtr scriptMaterial = MaterialManager::getSingleton ().getByName (BILLBOARD_MATERIAL_NAME);
00050 if (scriptMaterial.isNull ()) {
00051 CAELUM_THROW_UNSUPPORTED_EXCEPTION ("Can't find point starfield material", "PointStarfield");
00052 }
00053 mMaterial.reset (scriptMaterial->clone (BILLBOARD_MATERIAL_NAME + uniqueId));
00054 mMaterial->load ();
00055 if (mMaterial->getBestTechnique () == 0) {
00056 CAELUM_THROW_UNSUPPORTED_EXCEPTION ("Can't load point starfield material: " + mMaterial->getUnsupportedTechniquesExplanation(), "PointStarfield");
00057 }
00058
00059 sceneMgr->getRenderQueue()->getQueueGroup(CAELUM_RENDER_QUEUE_STARFIELD)->setShadowsEnabled (false);
00060
00061
00062 Ogre::String objName = "Caelum/PointStarfield/" + uniqueId;
00063 mManualObj.reset (sceneMgr->createManualObject (objName));
00064 mManualObj->setDynamic(false);
00065 mManualObj->setRenderQueueGroup (CAELUM_RENDER_QUEUE_STARFIELD);
00066 mManualObj->setCastShadows(false);
00067
00068 mNode.reset (caelumRootNode->createChildSceneNode ());
00069 mNode->attachObject (mManualObj.getPointer ());
00070
00071 if (initWithCatalogue) {
00072 addBrightStarCatalogue ();
00073 }
00074 }
00075
00076 PointStarfield::~PointStarfield ()
00077 {
00078 }
00079
00080 void PointStarfield::notifyStarVectorChanged () {
00081 invalidateGeometry ();
00082 }
00083
00084 void PointStarfield::clearAllStars () {
00085 mStars.clear();
00086 notifyStarVectorChanged ();
00087 }
00088
00089 Real randReal () {
00090 return rand() / static_cast<float>(RAND_MAX);
00091 }
00092
00093 Real randReal (Real min, Real max) {
00094 Real f = randReal ();
00095 return min * (1 - f) + max * f;
00096 }
00097
00098 void PointStarfield::addRandomStars (int count)
00099 {
00100 for (int i = 0; i < count; ++i) {
00101
00102 Ogre::Vector3 pos;
00103 do {
00104 pos.x = randReal(-1, 1);
00105 pos.y = randReal(-1, 1);
00106 pos.z = randReal(-1, 1);
00107 } while (pos.squaredLength () >= 1);
00108
00109
00110 LongReal rasc, decl, dist;
00111 Astronomy::convertRectangularToSpherical(
00112 pos.x, pos.y, pos.z,
00113 rasc, decl, dist);
00114
00115 Star s;
00116 s.RightAscension = Ogre::Degree (rasc);
00117 s.Declination = Ogre::Degree (decl);
00118
00119 s.Magnitude = 6 * pos.squaredLength () + 1.5;
00120 mStars.push_back(s);
00121 }
00122 notifyStarVectorChanged ();
00123 }
00124
00125 void PointStarfield::addStar (const BrightStarCatalogueEntry &entry) {
00126 Star s;
00127 s.RightAscension = Ogre::Degree(360 / 24.0f * (
00128 Math::Abs(entry.rasc_hour) +
00129 entry.rasc_min / 60.0f +
00130 entry.rasc_sec / 3600.0f));
00131 s.Declination = Ogre::Degree(Math::Sign(entry.decl_deg) * (
00132 Math::Abs(entry.decl_deg) +
00133 entry.decl_min / 60.0f +
00134 entry.decl_sec / 3600.0f));
00135 s.Magnitude = entry.magn;
00136 mStars.push_back(s);
00137
00138 notifyStarVectorChanged ();
00139 }
00140
00141 void PointStarfield::addBrightStarCatalogue (int count) {
00142 assert(count >= 0);
00143 if (count < BrightStarCatalogueSize) {
00144
00145
00146 std::vector<std::pair<Real, int> > vec;
00147 vec.reserve(BrightStarCatalogueSize);
00148 for (int i = 0; i < BrightStarCatalogueSize; ++i) {
00149 vec.push_back(std::make_pair(BrightStarCatalogue[i].magn, i));
00150 }
00151 sort(vec.begin(), vec.end());
00152 for (int i = 0; i < count; ++i) {
00153 addStar(BrightStarCatalogue[vec[i].second]);
00154 }
00155 } else {
00156 assert(count == BrightStarCatalogueSize);
00157 for (int i = 0; i < BrightStarCatalogueSize; ++i) {
00158 addStar(BrightStarCatalogue[i]);
00159 }
00160 }
00161 notifyStarVectorChanged ();
00162 }
00163
00164 void PointStarfield::invalidateGeometry () {
00165 mValidGeometry = false;
00166 }
00167
00168 void PointStarfield::ensureGeometry ()
00169 {
00170 if (mValidGeometry) {
00171 return;
00172 }
00173
00174
00175
00176 size_t starCount = mStars.size();
00177
00178 mManualObj->clear();
00179 mManualObj->estimateVertexCount(6 * starCount);
00180 mManualObj->begin(mMaterial->getName (), Ogre::RenderOperation::OT_TRIANGLE_LIST);
00181 for (uint i = 0; i < starCount; ++i)
00182 {
00183 const Star& star = mStars[i];
00184
00185
00186 LongReal azm, alt;
00187 Astronomy::convertEquatorialToHorizontal(
00188 Astronomy::J2000,
00189 mObserverLatitude.valueDegrees(),
00190 mObserverLongitude.valueDegrees(),
00191 star.RightAscension.valueDegrees(), star.Declination.valueDegrees(),
00192 azm, alt);
00193
00194 Ogre::Vector3 pos;
00195 pos.z = -Math::Cos (Ogre::Degree(azm)) * Math::Cos (Ogre::Degree(alt));
00196 pos.x = Math::Sin (Ogre::Degree(azm)) * Math::Cos (Ogre::Degree(alt));
00197 pos.y = -Math::Sin (Ogre::Degree(alt));
00198
00199
00200 mManualObj->position (pos);
00201 mManualObj->textureCoord (+1, -1, star.Magnitude);
00202 mManualObj->position (pos);
00203 mManualObj->textureCoord (+1, +1, star.Magnitude);
00204 mManualObj->position (pos);
00205 mManualObj->textureCoord (-1, -1, star.Magnitude);
00206
00207 mManualObj->position (pos);
00208 mManualObj->textureCoord (-1, -1, star.Magnitude);
00209 mManualObj->position (pos);
00210 mManualObj->textureCoord (+1, +1, star.Magnitude);
00211 mManualObj->position (pos);
00212 mManualObj->textureCoord (-1, +1, star.Magnitude);
00213 }
00214 mManualObj->end();
00215
00216
00217 AxisAlignedBox box;
00218 box.setInfinite ();
00219 mManualObj->setBoundingBox (box);
00220
00221 mValidGeometry = true;
00222 }
00223
00224 void PointStarfield::notifyCameraChanged (Ogre::Camera *cam) {
00225 CameraBoundElement::notifyCameraChanged (cam);
00226
00227
00228 Pass* pass = mMaterial->getBestTechnique ()->getPass (0);
00229 GpuProgramParametersSharedPtr fpParams = pass->getFragmentProgramParameters ();
00230 GpuProgramParametersSharedPtr vpParams = pass->getVertexProgramParameters ();
00231
00232 int height = cam->getViewport ()-> getActualHeight ();
00233 int width = cam->getViewport ()-> getActualWidth ();
00234 Real pixFactor = 1.0f / width;
00235 Real magScale = -Math::Log (mMagnitudeScale) / 2;
00236 Real mag0Size = mMag0PixelSize * pixFactor;
00237 Real minSize = mMinPixelSize * pixFactor;
00238 Real maxSize = mMaxPixelSize * pixFactor;
00239 Real aspectRatio = static_cast<Real>(width) / height;
00240
00241
00242 vpParams->setIgnoreMissingParams (true);
00243 vpParams->setNamedConstant ("mag_scale", magScale);
00244 vpParams->setNamedConstant ("mag0_size", mag0Size);
00245 vpParams->setNamedConstant ("min_size", minSize);
00246 vpParams->setNamedConstant ("max_size", maxSize);
00247 vpParams->setNamedConstant ("aspect_ratio", aspectRatio);
00248 }
00249
00250 void PointStarfield::setFarRadius (Ogre::Real radius) {
00251 CameraBoundElement::setFarRadius(radius);
00252 mNode->setScale (Ogre::Vector3::UNIT_SCALE * radius);
00253 }
00254
00255 void PointStarfield::_update (const float time) {
00256
00257 Ogre::Quaternion orientation = Ogre::Quaternion::IDENTITY;
00258 orientation = orientation * Ogre::Quaternion (Ogre::Radian (-mObserverLatitude + Ogre::Degree (90)), Ogre::Vector3::UNIT_X);
00259 orientation = orientation * Ogre::Quaternion (Ogre::Radian (-time * 2 * Ogre::Math::PI), Ogre::Vector3::UNIT_Y);
00260 mNode->setOrientation (orientation);
00261 ensureGeometry ();
00262 }
00263
00264 void PointStarfield::setObserverLatitude (Ogre::Degree value)
00265 {
00266 if (!Math::RealEqual (
00267 mObserverLatitude.valueDegrees (),
00268 value.valueDegrees (),
00269 this->getObserverPositionRebuildDelta ().valueDegrees ()))
00270 {
00271 mObserverLatitude = value;
00272 invalidateGeometry ();
00273 }
00274 }
00275
00276 void PointStarfield::setObserverLongitude (Ogre::Degree value)
00277 {
00278 if (!Math::RealEqual (
00279 mObserverLongitude.valueDegrees (),
00280 value.valueDegrees (),
00281 this->getObserverPositionRebuildDelta ().valueDegrees ()))
00282 {
00283 mObserverLongitude = value;
00284 invalidateGeometry ();
00285 }
00286 }
00287 }