1 /* 2 This file is part of Caelum. 3 See http://www.ogre3d.org/wiki/index.php/Caelum 4 5 Copyright (c) 2008 Caelum team. See Contributors.txt for details. 6 7 Caelum is free software: you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published 9 by the Free Software Foundation, either version 3 of the License, or 10 (at your option) any later version. 11 12 Caelum is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU Lesser General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with Caelum. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include "CaelumPrecompiled.h" 22 #include "PointStarfield.h" 23 #include "CaelumExceptions.h" 24 #include "Astronomy.h" 25 #include "InternalUtilities.h" 26 27 using namespace Ogre; 28 29 namespace Caelum 30 { 31 const Ogre::String PointStarfield::STARFIELD_MATERIAL_NAME = "Caelum/StarPoint"; 32 const Ogre::Degree PointStarfield::DEFAULT_OBSERVER_POSITION_REBUILD_DELTA = Ogre::Degree(0.1); 33 PointStarfield(Ogre::SceneManager * sceneMgr,Ogre::SceneNode * caelumRootNode,bool initWithCatalogue)34 PointStarfield::PointStarfield ( 35 Ogre::SceneManager *sceneMgr, 36 Ogre::SceneNode *caelumRootNode, 37 bool initWithCatalogue) 38 { 39 mMag0PixelSize = 16; 40 mMinPixelSize = 4; 41 mMaxPixelSize = 6; 42 mMagnitudeScale = Math::Pow(100, 0.2); 43 mObserverLatitude = 45; 44 mObserverLongitude = 0; 45 mObserverPositionRebuildDelta = DEFAULT_OBSERVER_POSITION_REBUILD_DELTA; 46 47 String uniqueSuffix = "/" + InternalUtilities::pointerToString(this); 48 49 // Load material. 50 mMaterial.reset(InternalUtilities::checkLoadMaterialClone( 51 STARFIELD_MATERIAL_NAME, 52 STARFIELD_MATERIAL_NAME + uniqueSuffix)); 53 54 mParams.setup(mMaterial->getTechnique(0)->getPass(0)->getVertexProgramParameters()); 55 56 // We use a separate data source. 57 Ogre::String objName = "Caelum/PointStarfield" + uniqueSuffix; 58 mManualObj.reset (sceneMgr->createManualObject (objName)); 59 mManualObj->setDynamic(false); 60 mManualObj->setRenderQueueGroup (CAELUM_RENDER_QUEUE_STARFIELD); 61 sceneMgr->getRenderQueue()->getQueueGroup(CAELUM_RENDER_QUEUE_STARFIELD)->setShadowsEnabled (false); 62 mManualObj->setCastShadows(false); 63 64 mNode.reset (caelumRootNode->createChildSceneNode ()); 65 mNode->attachObject (mManualObj.getPointer ()); 66 67 if (initWithCatalogue) { 68 addBrightStarCatalogue (); 69 } 70 } 71 ~PointStarfield()72 PointStarfield::~PointStarfield () 73 { 74 } 75 notifyStarVectorChanged()76 void PointStarfield::notifyStarVectorChanged () { 77 invalidateGeometry (); 78 } 79 clearAllStars()80 void PointStarfield::clearAllStars () { 81 mStars.clear(); 82 notifyStarVectorChanged (); 83 } 84 randReal()85 Real randReal () { 86 return rand() / static_cast<float>(RAND_MAX); 87 } 88 randReal(Real min,Real max)89 Real randReal (Real min, Real max) { 90 Real f = randReal (); 91 return min * (1 - f) + max * f; 92 } 93 addRandomStars(int count)94 void PointStarfield::addRandomStars (int count) 95 { 96 for (int i = 0; i < count; ++i) { 97 // Generate a vector inside a sphere 98 Ogre::Vector3 pos; 99 do { 100 pos.x = randReal(-1, 1); 101 pos.y = randReal(-1, 1); 102 pos.z = randReal(-1, 1); 103 } while (pos.squaredLength () >= 1); 104 105 // Convert to rasc/decl angles. 106 LongReal rasc, decl, dist; 107 Astronomy::convertRectangularToSpherical( 108 pos.x, pos.y, pos.z, 109 rasc, decl, dist); 110 111 Star s; 112 s.RightAscension = Ogre::Degree (rasc); 113 s.Declination = Ogre::Degree (decl); 114 // This distribution is wrong. 115 s.Magnitude = 6 * pos.squaredLength () + 1.5; 116 mStars.push_back(s); 117 } 118 notifyStarVectorChanged (); 119 } 120 addStar(const BrightStarCatalogueEntry & entry)121 void PointStarfield::addStar (const BrightStarCatalogueEntry &entry) { 122 Star s; 123 s.RightAscension = Ogre::Degree(360 / 24.0f * ( 124 Math::Abs(entry.rasc_hour) + 125 entry.rasc_min / 60.0f + 126 entry.rasc_sec / 3600.0f)); 127 s.Declination = Ogre::Degree(Math::Sign(entry.decl_deg) * ( 128 Math::Abs(entry.decl_deg) + 129 entry.decl_min / 60.0f + 130 entry.decl_sec / 3600.0f)); 131 s.Magnitude = entry.magn; 132 mStars.push_back(s); 133 134 notifyStarVectorChanged (); 135 } 136 addBrightStarCatalogue(int count)137 void PointStarfield::addBrightStarCatalogue (int count) { 138 assert(count >= 0); 139 if (count < BrightStarCatalogueSize) { 140 // Only sort if we don't add everything. 141 // It would be lovely if the catalogue was already sorted. 142 std::vector<std::pair<Real, int> > vec; 143 vec.reserve(BrightStarCatalogueSize); 144 for (int i = 0; i < BrightStarCatalogueSize; ++i) { 145 vec.push_back(std::make_pair(BrightStarCatalogue[i].magn, i)); 146 } 147 sort(vec.begin(), vec.end()); 148 for (int i = 0; i < count; ++i) { 149 addStar(BrightStarCatalogue[vec[i].second]); 150 } 151 } else { 152 assert(count == BrightStarCatalogueSize); 153 for (int i = 0; i < BrightStarCatalogueSize; ++i) { 154 addStar(BrightStarCatalogue[i]); 155 } 156 } 157 notifyStarVectorChanged (); 158 } 159 invalidateGeometry()160 void PointStarfield::invalidateGeometry () { 161 mValidGeometry = false; 162 } 163 ensureGeometry()164 void PointStarfield::ensureGeometry () 165 { 166 if (mValidGeometry) { 167 return; 168 } 169 170 //Ogre::LogManager::getSingleton ().logMessage ("Caelum: Recomputing starfield geometry."); 171 172 size_t starCount = mStars.size(); 173 174 mManualObj->clear(); 175 mManualObj->estimateVertexCount(6 * starCount); 176 mManualObj->begin(mMaterial->getName (), Ogre::RenderOperation::OT_TRIANGLE_LIST); 177 for (uint i = 0; i < starCount; ++i) 178 { 179 const Star& star = mStars[i]; 180 181 // Determine position at J2000 182 LongReal azm, alt; 183 Astronomy::convertEquatorialToHorizontal( 184 Astronomy::J2000, 185 mObserverLatitude.valueDegrees(), 186 mObserverLongitude.valueDegrees(), 187 star.RightAscension.valueDegrees(), star.Declination.valueDegrees(), 188 azm, alt); 189 190 Ogre::Vector3 pos; 191 pos.z = -Math::Cos (Ogre::Degree(azm)) * Math::Cos (Ogre::Degree(alt)); 192 pos.x = Math::Sin (Ogre::Degree(azm)) * Math::Cos (Ogre::Degree(alt)); 193 pos.y = -Math::Sin (Ogre::Degree(alt)); 194 195 //mManualObj->colour (Ogre::ColourValue::White); 196 mManualObj->position (pos); 197 mManualObj->textureCoord (+1, -1, star.Magnitude); 198 mManualObj->position (pos); 199 mManualObj->textureCoord (+1, +1, star.Magnitude); 200 mManualObj->position (pos); 201 mManualObj->textureCoord (-1, -1, star.Magnitude); 202 203 mManualObj->position (pos); 204 mManualObj->textureCoord (-1, -1, star.Magnitude); 205 mManualObj->position (pos); 206 mManualObj->textureCoord (+1, +1, star.Magnitude); 207 mManualObj->position (pos); 208 mManualObj->textureCoord (-1, +1, star.Magnitude); 209 } 210 mManualObj->end(); 211 212 // Set finite bounds on the starfield to avoid parent AABB infection 213 AxisAlignedBox box(Ogre::AxisAlignedBox::EXTENT_FINITE); 214 mManualObj->setBoundingBox (box); 215 216 mValidGeometry = true; 217 } 218 setup(Ogre::GpuProgramParametersSharedPtr vpParams)219 void PointStarfield::Params::setup(Ogre::GpuProgramParametersSharedPtr vpParams) 220 { 221 this->vpParams = vpParams; 222 this->mag_scale.bind(vpParams, "mag_scale"); 223 this->mag0_size.bind(vpParams, "mag0_size"); 224 this->min_size.bind(vpParams, "min_size"); 225 this->max_size.bind(vpParams, "max_size"); 226 this->aspect_ratio.bind(vpParams, "aspect_ratio"); 227 } 228 notifyCameraChanged(Ogre::Camera * cam)229 void PointStarfield::notifyCameraChanged (Ogre::Camera *cam) { 230 CameraBoundElement::notifyCameraChanged (cam); 231 232 // Shader params are changed for every camera. 233 Pass* pass = mMaterial->getBestTechnique ()->getPass (0); 234 GpuProgramParametersSharedPtr fpParams = pass->getFragmentProgramParameters (); 235 GpuProgramParametersSharedPtr vpParams = pass->getVertexProgramParameters (); 236 237 int height = cam->getViewport ()-> getActualHeight (); 238 int width = cam->getViewport ()-> getActualWidth (); 239 Real pixFactor = 1.0f / width; 240 Real magScale = -Math::Log (mMagnitudeScale) / 2; 241 Real mag0Size = mMag0PixelSize * pixFactor; 242 Real minSize = mMinPixelSize * pixFactor; 243 Real maxSize = mMaxPixelSize * pixFactor; 244 Real aspectRatio = static_cast<Real>(width) / height; 245 246 // These params are relative to the size of the screen. 247 mParams.mag_scale.set(mParams.vpParams, magScale); 248 mParams.mag0_size.set(mParams.vpParams, mag0Size); 249 mParams.min_size.set(mParams.vpParams, minSize); 250 mParams.max_size.set(mParams.vpParams, maxSize); 251 mParams.aspect_ratio.set(mParams.vpParams, aspectRatio); 252 } 253 setFarRadius(Ogre::Real radius)254 void PointStarfield::setFarRadius (Ogre::Real radius) { 255 CameraBoundElement::setFarRadius(radius); 256 mNode->setScale (Ogre::Vector3::UNIT_SCALE * radius); 257 } 258 _update(const float time)259 void PointStarfield::_update (const float time) { 260 // This is probably wrong. 261 Ogre::Quaternion orientation = Ogre::Quaternion::IDENTITY; 262 orientation = orientation * Ogre::Quaternion (Ogre::Radian (-mObserverLatitude + Ogre::Degree (90)), Ogre::Vector3::UNIT_X); 263 orientation = orientation * Ogre::Quaternion (Ogre::Radian (-time * 2 * Ogre::Math::PI), Ogre::Vector3::UNIT_Y); 264 mNode->setOrientation (orientation); 265 ensureGeometry (); 266 } 267 setObserverLatitude(Ogre::Degree value)268 void PointStarfield::setObserverLatitude (Ogre::Degree value) 269 { 270 if (!Math::RealEqual ( 271 mObserverLatitude.valueDegrees (), 272 value.valueDegrees (), 273 this->getObserverPositionRebuildDelta ().valueDegrees ())) 274 { 275 mObserverLatitude = value; 276 invalidateGeometry (); 277 } 278 } 279 setObserverLongitude(Ogre::Degree value)280 void PointStarfield::setObserverLongitude (Ogre::Degree value) 281 { 282 if (!Math::RealEqual ( 283 mObserverLongitude.valueDegrees (), 284 value.valueDegrees (), 285 this->getObserverPositionRebuildDelta ().valueDegrees ())) 286 { 287 mObserverLongitude = value; 288 invalidateGeometry (); 289 } 290 } 291 } 292