Caelum
PrecipitationController.cpp
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 "PrecipitationController.h"
23 #include "InternalUtilities.h"
24 
25 using namespace Ogre;
26 
27 namespace Caelum
28 {
29  const String PrecipitationController::COMPOSITOR_NAME = "Caelum/PrecipitationCompositor";
30  const String PrecipitationController::MATERIAL_NAME = "Caelum/PrecipitationMaterial";
31 
32  const PrecipitationPresetParams PrecipitationPresets[] = {
33  { Ogre::ColourValue(0.8, 0.8, 0.8, 1), 0.95, "precipitation_drizzle.png" },
34  { Ogre::ColourValue(0.8, 0.8, 0.8, 1), 0.85, "precipitation_rain.png" },
35  { Ogre::ColourValue(0.8, 0.8, 0.8, 1), 0.12, "precipitation_snow.png" },
36  { Ogre::ColourValue(0.8, 0.8, 0.8, 1), 0.33, "precipitation_snowgrains.png" },
37  { Ogre::ColourValue(0.8, 0.8, 0.8, 1), 0.70, "precipitation_icecrystals.png" },
38  { Ogre::ColourValue(0.8, 0.8, 0.8, 1), 0.78, "precipitation_icepellets.png" },
39  { Ogre::ColourValue(0.8, 0.8, 0.8, 1), 0.74, "precipitation_hail.png" },
40  { Ogre::ColourValue(0.8, 0.8, 0.8, 1), 0.70, "precipitation_smallhail.png" }
41  };
42 
43  PrecipitationController::PrecipitationController(
44  Ogre::SceneManager *sceneMgr)
45  {
46  Ogre::String uniqueId = Ogre::StringConverter::toString((size_t)this);
47  mSceneMgr = sceneMgr;
48 
49  setAutoDisableThreshold (0.001);
50  mCameraSpeedScale = Ogre::Vector3::UNIT_SCALE;
51 
52  setIntensity (0);
53  setWindSpeed (Ogre::Vector3(0, 0, 0));
54  mInternalTime = 0;
55  mSecondsSinceLastFrame = 0;
56  mFallingDirection = Ogre::Vector3::NEGATIVE_UNIT_Y;
57 
58  setPresetType (PRECTYPE_RAIN);
59 
60  update (0, Ogre::ColourValue(0, 0, 0, 0));
61  InternalUtilities::checkCompositorSupported(COMPOSITOR_NAME);
62  }
63 
64  PrecipitationController::~PrecipitationController () {
65  destroyAllViewportInstances ();
66  }
67 
68  void PrecipitationController::setTextureName (const Ogre::String& textureName) {
69  mPresetType = PRECTYPE_CUSTOM;
70  mTextureName = textureName;
71  }
72 
73  const Ogre::String PrecipitationController::getTextureName () const {
74  return mTextureName;
75  }
76 
77  void PrecipitationController::setSpeed (Real speed) {
78  mPresetType = PRECTYPE_CUSTOM;
79  mSpeed = speed;
80  }
81 
82  Real PrecipitationController::getSpeed () const {
83  return mSpeed;
84  }
85 
86  void PrecipitationController::setColour (const Ogre::ColourValue& color) {
87  mPresetType = PRECTYPE_CUSTOM;
88  mColour = color;
89  }
90 
91  const Ogre::ColourValue PrecipitationController::getColour () const {
92  return mColour;
93  }
94 
95  bool PrecipitationController::isPresetType (PrecipitationType type) {
96  return PRECTYPE_DRIZZLE <= type && type <= PRECTYPE_SMALLHAIL;
97  }
98 
99  const PrecipitationPresetParams& PrecipitationController::getPresetParams (PrecipitationType type) {
100  assert(isPresetType(type));
101  return PrecipitationPresets[type];
102  }
103 
104  void PrecipitationController::setParams (const PrecipitationPresetParams& params) {
105  setColour (params.Colour);
106  setSpeed (params.Speed);
107  setTextureName (params.Name);
108  }
109 
110  void PrecipitationController::setPresetType (PrecipitationType type) {
111  setParams (getPresetParams (type));
112  mPresetType = type;
113  }
114 
115  PrecipitationType PrecipitationController::getPresetType () const {
116  return mPresetType;
117  }
118 
119  void PrecipitationController::setWindSpeed (const Ogre::Vector3& value) {
120  mWindSpeed = value;
121  }
122 
123  const Ogre::Vector3 PrecipitationController::getWindSpeed () const {
124  return mWindSpeed;
125  }
126 
127  void PrecipitationController::setIntensity (Real intensity) {
128  mIntensity = intensity;
129  }
130 
131  Real PrecipitationController::getIntensity () const {
132  return mIntensity;
133  }
134 
135  void PrecipitationController::update (Real secondsSinceLastFrame, Ogre::ColourValue colour) {
136  mSecondsSinceLastFrame = secondsSinceLastFrame;
137  mInternalTime += mSecondsSinceLastFrame;
138  mSceneColour = colour;
139 
140  ViewportInstanceMap::const_iterator it;
141  ViewportInstanceMap::const_iterator begin = mViewportInstanceMap.begin ();
142  ViewportInstanceMap::const_iterator end = mViewportInstanceMap.end ();
143  for (it = begin; it != end; ++it) {
144  it->second->_update ();
145  }
146  }
147 
148  void PrecipitationController::setManualCameraSpeed (const Ogre::Vector3& value) {
149  ViewportInstanceMap::const_iterator it;
150  ViewportInstanceMap::const_iterator begin = mViewportInstanceMap.begin();
151  ViewportInstanceMap::const_iterator end = mViewportInstanceMap.end();
152  for (it = begin; it != end; ++it) {
153  it->second->setManualCameraSpeed(value);
154  }
155  }
156 
157  void PrecipitationController::setAutoCameraSpeed() {
158  ViewportInstanceMap::const_iterator it;
159  ViewportInstanceMap::const_iterator begin = mViewportInstanceMap.begin();
160  ViewportInstanceMap::const_iterator end = mViewportInstanceMap.end();
161  for (it = begin; it != end; ++it) {
162  it->second->setAutoCameraSpeed();
163  }
164  }
165 
166  PrecipitationInstance::PrecipitationInstance
167  (
168  PrecipitationController* parent,
169  Ogre::Viewport* viewport
170  ):
171  mParent(parent),
172  mViewport(viewport),
173  mCompInst(0),
174  mLastCamera(0),
175  mLastCameraPosition(Vector3::ZERO),
176  mCameraSpeed(Vector3::ZERO),
177  mAutoCameraSpeed(true)
178  {
179  createCompositor ();
180  }
181 
182  PrecipitationInstance::~PrecipitationInstance ()
183  {
184  destroyCompositor();
185  }
186 
187  void PrecipitationInstance::createCompositor ()
188  {
189  // Check if nothing to do.
190  if (mCompInst) {
191  return;
192  }
193 
194  Ogre::CompositorManager* compMgr = Ogre::CompositorManager::getSingletonPtr();
195 
196  // Create the precipitation compositor.
197  mCompInst = compMgr->addCompositor(mViewport, PrecipitationController::COMPOSITOR_NAME);
198  assert(mCompInst);
199  mCompInst->setEnabled (false);
200  mCompInst->addListener (this);
201  }
202 
203  void PrecipitationInstance::destroyCompositor ()
204  {
205  // Check if nothing to do.
206  if (mCompInst == 0) {
207  return;
208  }
209 
210  Ogre::CompositorManager* compMgr = Ogre::CompositorManager::getSingletonPtr();
211 
212  // Remove the precipitation compositor.
213  mCompInst->removeListener (this);
214  compMgr->removeCompositor(mViewport, PrecipitationController::COMPOSITOR_NAME);
215  mCompInst = 0;
216  }
217 
218  void PrecipitationInstance::notifyMaterialSetup(uint pass_id, Ogre::MaterialPtr &mat)
219  {
220  mParams.setup(mat->getTechnique (0)->getPass (0)->getFragmentProgramParameters ());
221  }
222 
223  void PrecipitationInstance::Params::setup(Ogre::GpuProgramParametersSharedPtr fpParams)
224  {
225  this->fpParams = fpParams;
226  this->precColor.bind(fpParams, "precColor");
227  this->intensity.bind(fpParams, "intensity");
228  this->dropSpeed.bind(fpParams, "dropSpeed");
229  this->corner1.bind(fpParams, "corner1");
230  this->corner2.bind(fpParams, "corner2");
231  this->corner3.bind(fpParams, "corner3");
232  this->corner4.bind(fpParams, "corner4");
233  this->deltaX.bind(fpParams, "deltaX");
234  this->deltaY.bind(fpParams, "deltaY");
235  }
236 
237  void PrecipitationInstance::notifyMaterialRender(uint pass_id, Ogre::MaterialPtr &mat)
238  {
239  if (mAutoCameraSpeed) {
240  Ogre::Camera* cam = mViewport->getCamera();
241  Ogre::Vector3 camPos = cam->getDerivedPosition();
242  if (cam != mLastCamera) {
243  mCameraSpeed = Ogre::Vector3::ZERO;
244  } else {
245  Real timeDiff = mParent->getSecondsSinceLastFrame ();
246  Ogre::Vector3 posDiff = camPos - mLastCameraPosition;
247 
248  // Avoid division by 0 and keep old camera speed.
249  if (timeDiff > 1e-10) {
250  mCameraSpeed = posDiff / timeDiff;
251  } else {
252  // Keep old camera speed.
253  }
254 
255  /*
256  LogManager::getSingletonPtr ()->logMessage (
257  "Caelum::PrecipitationInstance:"
258  " posDiff = " + StringConverter::toString(posDiff) +
259  " timeDiff = " + StringConverter::toString(mParent->getSecondsSinceLastFrame (), 10) +
260  " speed = " + StringConverter::toString(mCameraSpeed));
261  */
262  }
263  mLastCamera = cam;
264  mLastCameraPosition = camPos;
265  }
266 
267  this->_updateMaterialParams(mat, mViewport->getCamera(), mCameraSpeed);
268  }
269 
270  void PrecipitationInstance::_updateMaterialParams(
271  const Ogre::MaterialPtr& mat,
272  const Ogre::Camera* cam,
273  const Ogre::Vector3& camSpeed)
274  {
275  // 4523.893416f is divisible with all the sine periods in the shader
276  Real appTime = static_cast<Real>(fmod(mParent->mInternalTime, static_cast<Real>(4523.893416f)));
277 
278  ColourValue sceneColour = mParent->mSceneColour;
279  Real sceneLum = (sceneColour.r + sceneColour.g + sceneColour.b) / 3;
280  mParams.precColor.set(mParams.fpParams, ColourValue::White * sceneLum * mParent->mColour);
281  mParams.intensity.set(mParams.fpParams, mParent->mIntensity);
282  mParams.dropSpeed.set(mParams.fpParams, 0);
283 
284  Ogre::Vector3 corner1, corner2, corner3, corner4;
285 
286  corner1 = cam->getCameraToViewportRay(0, 0).getDirection();
287  corner2 = cam->getCameraToViewportRay(1, 0).getDirection();
288  corner3 = cam->getCameraToViewportRay(0, 1).getDirection();
289  corner4 = cam->getCameraToViewportRay(1, 1).getDirection();
290 
291  Ogre::Vector3 precDir =
292  mParent->mSpeed * mParent->mFallingDirection +
293  mParent->mWindSpeed -
294  camSpeed * mParent->mCameraSpeedScale;
295  Ogre::Quaternion quat = precDir.getRotationTo(Ogre::Vector3(0, -1, 0));
296 
297  corner1 = quat * corner1;
298  corner2 = quat * corner2;
299  corner3 = quat * corner3;
300  corner4 = quat * corner4;
301 
302  mParams.corner1.set(mParams.fpParams, corner1);
303  mParams.corner2.set(mParams.fpParams, corner2);
304  mParams.corner3.set(mParams.fpParams, corner3);
305  mParams.corner4.set(mParams.fpParams, corner4);
306 
307  float fallSpeed = precDir.length();
308 
309  mParams.deltaX.set(mParams.fpParams,
310  Ogre::Vector3(sin(appTime) + 4.33,
311  cos(appTime * 1.5) + 5.26,
312  cos(appTime * 2.5)) * fallSpeed / 10 + 88.001);
313  mParams.deltaY.set(mParams.fpParams,
314  Ogre::Vector3(0.6, 1.0, 1.4) * fallSpeed * appTime);
315 
316  if (mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->getTextureName() != mParent->mTextureName) {
317  mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName(mParent->mTextureName);
318  }
319  }
320 
321  bool PrecipitationInstance::getAutoCameraSpeed () {
322  return mAutoCameraSpeed;
323  }
324 
325  void PrecipitationInstance::setAutoCameraSpeed () {
326  mAutoCameraSpeed = true;
327  mCameraSpeed = Ogre::Vector3::ZERO;
328  mLastCamera = 0;
329  }
330 
331  void PrecipitationInstance::setManualCameraSpeed (const Ogre::Vector3& value) {
332  mAutoCameraSpeed = false;
333  mCameraSpeed = value;
334  }
335 
336  const Ogre::Vector3 PrecipitationInstance::getCameraSpeed () {
337  return mCameraSpeed;
338  }
339 
340  bool PrecipitationInstance::shouldBeEnabled () const {
341  return mParent->getAutoDisableThreshold () < 0 ||
342  mParent->getIntensity () > mParent->getAutoDisableThreshold ();
343  }
344 
345  void PrecipitationInstance::_update ()
346  {
347  mCompInst->setEnabled (shouldBeEnabled ());
348  }
349 
350  PrecipitationInstance* PrecipitationController::createViewportInstance (Ogre::Viewport* vp)
351  {
352  ViewportInstanceMap::const_iterator it = mViewportInstanceMap.find (vp);
353  if (it == mViewportInstanceMap.end()) {
354  std::auto_ptr<PrecipitationInstance> inst (new PrecipitationInstance(this, vp));
355  mViewportInstanceMap.insert (std::make_pair (vp, inst.get()));
356  // hold instance until successfully added to map.
357  return inst.release();
358  } else {
359  return it->second;
360  }
361  }
362 
363  PrecipitationInstance* PrecipitationController::getViewportInstance(Ogre::Viewport* vp) {
364  ViewportInstanceMap::iterator it = mViewportInstanceMap.find (vp);
365  if (it != mViewportInstanceMap.end ()) {
366  return it->second;
367  } else {
368  return 0;
369  }
370  }
371 
372  void PrecipitationController::destroyViewportInstance (Viewport* vp)
373  {
374  ViewportInstanceMap::iterator it = mViewportInstanceMap.find (vp);
375  if (it != mViewportInstanceMap.end ()) {
376  PrecipitationInstance* inst = it->second;
377  delete inst;
378  mViewportInstanceMap.erase (it);
379  }
380  }
381 
382  void PrecipitationController::destroyAllViewportInstances () {
383  ViewportInstanceMap::const_iterator it;
384  ViewportInstanceMap::const_iterator begin = mViewportInstanceMap.begin();
385  ViewportInstanceMap::const_iterator end = mViewportInstanceMap.end();
386  for (it = begin; it != end; ++it) {
387  assert(it->first == it->second->getViewport ());
388  delete it->second;
389  }
390  mViewportInstanceMap.clear ();
391  }
392 }
Compositor-based precipitation controller.
PrecipitationType
An enumeration of the available precipitation presets.
Per-viewport instance of precipitation.
Preset parameters for a certain type of precipitation.
Caelum namespace.
Definition: Astronomy.cpp:24