[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.4 The Camera

In Crystal Space there is an interface called iView which encapsulates both `iCamera' and iClipper2D instances. In principle you can use those classes directly but using iView is easier. Now edit `simple.h' to make use of iView:

 
...
struct iView;
...

class Simple
{
private:
  ...
  csRef<iView> view;
  ...
  void SetupFrame ();
  void FinishFrame ();
  ...

Then edit `simple.cpp' and make the following changes at the end of our Initialize() function:

 
bool Simple::Initialize ()
{
  ...
  view = csPtr<iView> (new csView (engine, g3d));
  view->GetCamera ()->SetSector (room);
  view->GetCamera ()->GetTransform ().SetOrigin (csVector3 (0, 5, -3));
  iGraphics2D* g2d = g3d->GetDriver2D ();
  view->SetRectangle (0, 0, g2d->GetWidth (), g2d->GetHeight ());

  return true;
}

So first we create a view for our world and 3D graphics renderer. The view has a current sector which is passed to the camera and is set by SetSector(). The camera also has a position in that sector which you can set by first getting the camera with GetCamera() and then setting the position (which is a `csVector3') with SetPosition(). The view also holds a clipping region which corresponds to the area on the window that is going to be used for drawing the world. Crystal Space supports convex polygons to be used as viewing areas, but in case we use a simple rectangle which has almost the size of the window. We set this viewing rectangle with SetRectangle().

The call to create a new view is a bit special. See the discussion on smart pointers for a full info (see section 5.9.1 Correctly Using Smart Pointers).

Now, this still isn't enough. We have a camera but the camera is not used. We still have to write code that actually draws the screen. We will do this in the functions SetupFrame() and FinishFrame(). Note that Crystal Space is event driver so the actual drawing needs to be triggered by the event handler. Add the following code somewhere in the source file:

 
void Simple::SetupFrame ()
{
  // Tell 3D driver we're going to display 3D things.
  if (!g3d->BeginDraw(
    engine->GetBeginDrawFlags() | CSDRAW_3DGRAPHICS))
    return;

  // Tell the camera to render into the frame buffer.
  view->Draw ();
}

void Simple::FinishFrame ()
{
  g3d->FinishDraw ();
  g3d->Print (NULL);
}

Modify the event handler like this:

 
bool Simple::HandleEvent (iEvent& ev)
{
  if (ev.Type == csevBroadcast && ev.Command.Code == cscmdProcess)
  {
    simple->SetupFrame ();
    return true;
  }
  else if (ev.Type == csevBroadcast &&
    ev.Command.Code == cscmdFinalProcess)
  {
    simple->FinishFrame ();
    return true;
  }
  else if (ev.Type == csevKeyDown && ev.Key.Code == CSKEY_ESC)
  ...

Drawing the screen is split in two parts. First there is the part that is done in SetupFrame(). Here we will actually fill the display. In this case we let the engine do most of that work by calling view->Draw(). But in principle you can do any kind of drawing here.

In SetupFrame() we first have to indicate to the 3D rasterizer that we want to start drawing 3D graphics. This call makes sure that the needed buffers are set up and performs all necessary initialization. The engine often needs extra settings for this as well so you must call engine->GetBeginDrawFlags() to get these flags and or them with the ones that you want.

The second part is in FinishFrame() where we actually dump the frame to the screen. The reason this is split is that other components (plugins) in Crystal Space may choose to listen to events to draw additional things on top of the 3D view rendered in SetupFrame(). When a frame needs to be rendered the Crystal Space framework will send four messages:

Compile and run this example. For the first time you should see something. A solid wall. Congratulations, you have created your first almost useful Crystal Space application.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated using texi2html