Creating the Client Shell

 

The Client Shell is responsible for handling player input, rendering, and the like. In a single-player game with no networking component, the client shell is also responsible for handling physics, AI, and all other game functions. More detail is available in the LithTech Programming Guide.

 

This page will lead you through the creation of this class.


 

To get started, create a new file in Visual Studio and save it as ltclientshell.h. Next, add the necessary multiple-inclusion protection, and include the engine header for the client shell class.

 

 

#ifndef __LT_CLIENT_SHELL_H__

#define __LT_CLIENT_SHELL_H__

 

#include <iclientshell.h>

 

 

 

The next step is to declare a global pointer to the client shell.

 

 

class CLTClientShell;

extern CLTClientShell *g_pCShell;

 

 

 

We now declare the client shell as CLTClientShell, deriving it from the stub class provided by LithTech. We also include the constructor and destructor, along with a macro which declares the client shell interface to the interface manager.

 

 

class CLTClientShell:public IClientShellStub {

public:

      CLTClientShell();

      ~CLTClientShell();

 

      declare_interface(CLTClientShell);

 

 

 

The next step is to override necessary LithTech engine functions. The purpose of each of these functions is explained later on this page, and fully detailed descriptions are available in the Programming Guide.

 

 

      // LithTech defined functions

      void        Update();

      uint32      OnEngineInitialized(RMode *pMod, LTGUID *pAppGuid);

      void        OnEvent(uint32 dwEventID, uint32 dwParam);

 

 

 

Finally, we add non-LithTech functions and variables that will be used by our game code.

 

 

protected:

      // Non-LithTech defined functions

      LTRESULT    InitRenderer(RMode *pMode);

      LTRESULT    Render();

 

      bool        m_bRender;

};

 

#endif // __LT_CLIENT_SHELL_H__

 

 

 

Save the ltclientshell.h file in the following directory:

 

   <your project directory>\cshell\src

 


 

Now, create another file in Visual Studio and save it as ltclientshell.cpp. Include the class header file along with some engine headers.

 

 

#include "ltclientshell.h"

#include <iltclient.h>

#include <iclientshell.h>

 

 

 

The following code sets up DLL exports and variables, initializes the global client shell pointer, and defines our instantiation of the IClientShell interface.

 

 

SETUP_CLIENTSHELL();

 

CLTClientShell *g_pCShell = NULL;

 

define_interface(CLTClientShell, IClientShell);

 

 

 

The constructor simply initializes the m_bRender variable to true. This variable is set to true or false depending on whether the OS will allow LithTech to render. We also define the destructor for the class.

 

 

CLTClientShell::CLTClientShell() {

      m_bRender = true;

}

 

CLTClientShell::~CLTClientShell() {

}

 

 

 

The OnEngineInitialized function is called, appropriately, after the engine has been initialized. Here is where we will call the InitRenderer function to set up rendering. We also add some text that will be printed to the console using the CPrint function. This function works the same way as C’s printf(), except it prints to the console.

 

 

uint32 CLTClientShell::OnEngineInitialized(RMode *pMode,

      LTGUID *pAppGuid) {

      LTRESULT result = LT_OK;

      result = InitRenderer(pMode);

 

      g_pLTClient->CPrint("Exit by typing \"quit\" at the console (~)");

 

      return result;

}

 

 

 

This is a very simple implementation of an InitRenderer function that simply sets the current render mode to whatever was requested. Later in the course we will use a slightly more sophisticated version that checks whether the requested mode is available and falls back if it’s not. Note the use of g_pLTClient. This is a global pointer to the client interface (as opposed to the client shell interface). The client interface is one of many interfaces provided by the LTDS, and it provides a variety of useful functions.

 

 

LTRESULT CLTClientShell::InitRenderer(RMode *pMode) {

      return g_pLTClient->SetRenderMode(pMode);

}

 

 

 

The client shell’s Update function is called by LithTech as often as possible. This is where much of a game’s logic will exist. This is also where the engine’s renderer should be called, but only if m_bRender is true.

 

 

void CLTClientShell::Update() {

 

      LTRESULT result;

 

      if (m_bRender) {

 

            result = Render();

 

            if (LT_OK != result) {

                  g_pLTClient->DebugOut("Error in Render()\n");

                  g_pLTClient->Shutdown();

            }

      }

}

 

 

 

The Render function is a very simple function that clears the screen, renders the 3D scene, then flips the buffers. Notice that nothing is actually being rendered in our minimal implementation. Anything that needs to be rendered must be placed between the calls to Start3D and End3D.

 

 

LTRESULT CLTClientShell::Render() {

 

      LTRESULT result;

 

      //    Clear the screen to prepare for the next draw

      result = g_pLTClient->ClearScreen(NULL, CLEARSCREEN_SCREEN |

            CLEARSCREEN_RENDER);

      if (LT_OK != result) {

            g_pLTClient->DebugOut("Error in ClearScreen()\n");

            g_pLTClient->Shutdown();

      }

 

      //    Tell LithTech we are going to be starting our 3d render

      result = g_pLTClient->Start3D();

      if (LT_OK != result) {

            g_pLTClient->DebugOut("Error in Start3D()\n");

            g_pLTClient->Shutdown();

      }

 

      //    Tell LithTech to finish rendering for this scene

      result = g_pLTClient->End3D(END3D_CANDRAWCONSOLE);

      if (LT_OK != result) {

            g_pLTClient->DebugOut("Error in End3D()\n");

            g_pLTClient->Shutdown();

      }

 

      //    Tell LithTech to flip the screen surface

      result = g_pLTClient->FlipScreen(NULL);

      if (LT_OK != result) {

            g_pLTClient->DebugOut("Error in FlipScreen()\n");

            g_pLTClient->Shutdown();

      }

 

      return LT_OK;

}

 

 

 

Finally, we have a simple event handler that changes the m_bRender variable to respond to various system conditions..

 

 

void CLTClientShell::OnEvent(uint32 dwEventID, uint32 dwParam) {

 

      if (dwEventID == LTEVENT_LOSTFOCUS ||

            dwEventID == LTEVENT_RENDERTERM)

            m_bRender = false;

 

      if (dwEventID == LTEVENT_GAINEDFOCUS ||

            dwEventID == LTEVENT_RENDERINIT ||

            dwEventID == LTEVENT_RENDERALMOSTINITTED)

            m_bRender = true;

}

 

 

 

Save the ltclientshell.cpp file in the following directory:

 

   <your project directory>\cshell\src

 


Go back to the Project page.