Free Trial

Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.

  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint
Share this Page URL
Help

4. Let There Be Light > Creating weather controls

Creating weather controls

When building Ogre applications that simulate an outdoor environment, we often need to control weather conditions. In this recipe, we'll build an application with controls that change the parameters of a particle system to simulate different rain-like conditions. We'll also use sound in our application to enhance the rain effect.

Getting ready

Add the sounds folder, which contains nature sounds, such as rain and thunder, in your media folder.

To follow along with this recipe, open the solution located in the Recipes/Chapter04 folder in the code bundle available on the Packt website.

How to do it...

  1. First, create a new Ogre MFC application named WeatherConditions, by following the Creating an MFC Ogre application recipe, in Chapter 1,
  2. Next, create a SAPI voice.
    m_cpVoice.CoCreateInstance(CLSID_SpVoice);
    
  3. Create a submenu named Weather Control in the main menu. Then, add commands: Rain, Snow, Fog, Sky, and Sun to the submenu. For this recipe, we will only be implementing the rain functionality, but it will be easy to complete the other controls, once you see how the rain is implemented.
    How to do it...
  4. Next, add an event handler to the Rain submenu item using the Event Handler Wizard.
    void CWeatherControlView::OnWeatherControlRain() {
      Ogre::SceneNode *RainNode = NULL;
    
      if (!m_SceneManager->hasParticleSystem("Rain")) {
        m_Rain = m_SceneManager->createParticleSystem("Rain", 
          "Examples/Rain");
    
        if (m_Rain != NULL) {
          RainNode = m_SceneManager->
            getRootSceneNode()->createChildSceneNode("RainNode");
           RainNode->attachObject(m_Rain);
          m_Rain->setVisible(false);
        }
      }
    
      if (m_RainControlDlg == NULL) {
        m_RainControlDlg = new CRainControlDlg();
        m_RainControlDlg->Create(IDD_RAIN_CONTROL);
      }
    
      m_RainControlDlg->ShowWindow(SW_SHOW);
    }
    
  5. In the Rain submenu event handler, we create the rain particle system and the Rain Control dialog-box, and then show it.
  6. Create the Rain Control dialog-box using the Dialog Editor.
    How to do it...

    Using this dialog-box, we can start and stop the rain, control particle dimensions, and enable or disable rain sounds.

  7. Now that we've created the dialog-box, we need to add the event handler code for the dialog-box controls. Add a message handler to the Rain Control dialog-box called OnHScroll that handles the WM_HSCROLL message. The WM_HSCROLL message is sent when a click is detected in a horizontal scroll bar. Inside the OnHScroll, we simply check the position of the particle width and height controls, and modify the particle system with the updated values.
    void CRainControlDlg::OnHScroll(UINT nSBCode, UINT nPos, 
      CScrollBar* pScrollBar) {
      CMainFrame *MainFrame = (CMainFrame *)((
        CWeatherControlApp*)AfxGetApp())->GetMainWnd();
    
      CWeatherControlView *View = 
        (CWeatherControlView *)MainFrame->GetActiveView();
    
      int ParticleWidth = m_ParticleWidth.GetPos();
      int ParticleHeight = m_ParticleHeight.GetPos();
    
      View->m_Rain->setDefaultDimensions(ParticleWidth, 
        ParticleHeight);
    
      CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
    }
    
  8. Next, add an event handler named OnClickAction to the Start/Stop button to handle the click event. Inside OnClickAction, we toggle the rain visibility and rain sounds.
    View->m_Rain->setVisible(!View->m_Rain->getVisible());
    
    if (View->m_Rain->getVisible()) {
      m_Action.SetWindowTextA("Stop");
      View->SetTimer(ID_RAIN_TIMER, 1, 0);
    }
    else {
      m_Action.SetWindowTextA("Start");
      View->KillTimer(ID_RAIN_TIMER);
      WeatherControlApp->m_cpVoice->Pause();
    }
    

    We also start or stop the ID_RAIN_TIMER to toggle rain sounds in our OnTimer() function that gets called every time we receive a timer message.

  9. To handle the timer messages, add an ON_WM_TIMER message handler to CWeatherControlView, and name it OnTimer. In the OnTimer member function, we will play rain sounds and render the scene when we receive the ID_RAIN_TIMER timer event.
    SoundPath += L"\\..\\..\\media\\sounds\\rain\\rain storm.wav";
    CWeatherControlApp* WeatherControlApp = (CWeatherControlApp*)AfxGetApp();
    CComPtr<ISpVoice> Voice = WeatherControlApp->m_cpVoice;
    CComPtr<ISpStream> cpWavStream;
    
    switch (nIDEvent) {
      case ID_RAIN_TIMER:
    
        if (m_RainControlDlg != NULL){
          if (m_RainControlDlg->m_PlaySound && m_Rain->getVisible()) {
            SPBindToFile(SoundPath, SPFM_OPEN_READONLY, &cpWavStream);
            Voice->Resume();
            Voice->SpeakStream(cpWavStream, SPF_ASYNC, NULL);
          }
          else {
            Voice->Pause();
          }
        }
        Root->renderOneFrame();
    

    The SPBindToFile function binds the audio stream to the specified file, and SpeakStream plays the contents of the stream. In our case, when we receive an ID_RAIN_TIMER event, we play the rain sound.

How it works...

The settings for our Examples/Rain particle system reside in the media/particle/Examples.particle file. The .particle file is just a text file and the settings are detailed in the Ogre online manual:

particle_system Examples/Rain
{
    material        Examples/Droplet
    particle_width  20
    particle_height 100
    cull_each       true
    quota           10000
    // Make common direction straight down (faster than self oriented)
    billboard_type  oriented_common
    common_direction 0 -1 0
    
    // Area emitter
    emitter Box
    {
        angle           0
        emission_rate   100
        time_to_live    5
        direction       0 -1 0
        velocity    	50
        width           1000
        height          1000
        depth           0
    }

    // Gravity
    affector LinearForce
    {
        force_vector      0 -200 0
        force_application add
    }

}

The rain particle effect uses a box emitter, so all the particles originate from a flat 1000x1000 box. Note that we use the Y-axis as the up and down axis in our example, and our material is the Examples/Droplet material found in the media/materials/scripts/Examples.material file.

material Examples/Droplet{
  technique {
    pass {
      emissive 0.3 0.3 0.3
	      scene_blend colour_blend
	      depth_write off
	      diffuse vertexcolour

	      texture_unit {
        texture basic_droplet.png
	      }
	    }
	  }
}

When you run the program and turn on the rain effect, you can see the rain particles falling on our robot overlord.

How it works...

There's more...

You can add additional elements to the Rain Control dialog-box to control other parameters of the rain particle system, such as the speed or the color. By adding dialog-boxes for each weather control, we can create a full-scale weather editor.

  • Safari Books Online
  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint