<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"> <title>Irrlicht Engine: Tutorial 18: Splitscreen</title> <link href="doxygen.css" rel="stylesheet" type="text/css"> </head><body> <table class="irrlicht" > <tr valign="middle"> <td><font size="2"><a class="qindex" href="index.html"><font color="#FFFFFF">Home</font></a> | <a class="qindex" href="namespaces.html"><font color="#FFFFFF">Namespaces</font></a> | <a class="qindex" href="hierarchy.html"><font color="#FFFFFF">Hierarchy</font></a> | <a class="qindex" href="classes.html"><font color="#FFFFFF">Alphabetical List</font></a> | <a class="qindex" href="annotated.html"><font color="#FFFFFF"> Class list</font></a> | <a class="qindex" href="files.html"><font color="#FFFFFF">Files</font></a> | <a class="qindex" href="namespacemembers.html"><font color="#FFFFFF"> Namespace Members</font></a> | <a class="qindex" href="functions.html"><font color="#FFFFFF">Class members</font></a> | <a class="qindex" href="globals.html"><font color="#FFFFFF">File members</font></a> | <a class="qindex" href="pages.html"><font color="#FFFFFF">Tutorials</font></a></font> </td> </tr> </table> <!-- Generated by Doxygen 1.6.2 --> <div class="contents"> <h1><a class="anchor" id="example018">Tutorial 18: Splitscreen </a></h1><div align="center"> <img src="018shot.jpg" alt="018shot.jpg"/> </div> <p>A tutorial by Max Winkel.</p> <p>In this tutorial we'll learn how to use splitscreen (e.g. for racing-games) with Irrlicht. We'll create a viewport divided into 4 parts, wtih 3 fixed cameras and one user-controlled.</p> <p>Ok, let's start with the headers (I think there's nothing to say about it) </p> <div class="fragment"><pre class="fragment"><span class="preprocessor">#include <<a class="code" href="irrlicht_8h.html" title="Main header file of the irrlicht, the only file needed to include.">irrlicht.h</a>></span> <span class="preprocessor">#include "<a class="code" href="driver_choice_8h.html">driverChoice.h</a>"</span> <span class="preprocessor">#ifdef _MSC_VER</span> <span class="preprocessor"></span><span class="preprocessor">#pragma comment(lib, "Irrlicht.lib")</span> <span class="preprocessor"></span><span class="preprocessor">#endif</span> <span class="preprocessor"></span> <span class="comment">//Namespaces for the engine</span> <span class="keyword">using namespace </span>irr; <span class="keyword">using namespace </span>core; <span class="keyword">using namespace </span>video; <span class="keyword">using namespace </span>scene; </pre></div><p>Now we'll define the resolution in a constant for use in initializing the device and setting up the viewport. In addition we set up a global variable saying splitscreen is active or not. </p> <div class="fragment"><pre class="fragment"><span class="comment">//Resolution</span> <span class="keyword">const</span> <span class="keywordtype">int</span> ResX=800; <span class="keyword">const</span> <span class="keywordtype">int</span> ResY=600; <span class="keyword">const</span> <span class="keywordtype">bool</span> fullScreen=<span class="keyword">false</span>; <span class="comment">//Use SplitScreen?</span> <span class="keywordtype">bool</span> SplitScreen=<span class="keyword">true</span>; </pre></div><p>Now we need four pointers to our cameras which are created later: </p> <div class="fragment"><pre class="fragment"><span class="comment">//cameras</span> ICameraSceneNode *camera[4]={0,0,0,0}; </pre></div><p>In our event-receiver we switch the SplitScreen-variable, whenever the user press the S-key. All other events are sent to the FPS camera. </p> <div class="fragment"><pre class="fragment"><span class="keyword">class </span>MyEventReceiver : <span class="keyword">public</span> IEventReceiver { <span class="keyword">public</span>: <span class="keyword">virtual</span> <span class="keywordtype">bool</span> OnEvent(<span class="keyword">const</span> SEvent& event) { <span class="comment">//Key S enables/disables SplitScreen</span> <span class="keywordflow">if</span> (event.EventType == <a class="code" href="namespaceirr.html#ac9eed96e06e85ce3c86fcbbbe9e48a0ca6f90390f3147a1693e5e2e3422d6ca09" title="A key input event.">irr::EET_KEY_INPUT_EVENT</a> && event.KeyInput.Key == <a class="code" href="namespaceirr.html#a54da2a0e231901735e3da1b0edf72eb3ae52bafc112fc6c52f6b49cea42fa246e">KEY_KEY_S</a> && event.KeyInput.PressedDown) { SplitScreen = !SplitScreen; <span class="keywordflow">return</span> <span class="keyword">true</span>; } <span class="comment">//Send all other events to camera4</span> <span class="keywordflow">if</span> (camera[3]) <span class="keywordflow">return</span> camera[3]->OnEvent(event); <span class="keywordflow">return</span> <span class="keyword">false</span>; } }; </pre></div><p>Ok, now the main-function: First, we initialize the device, get the SourceManager and VideoDriver, load an animated mesh from .md2 and a map from .pk3. Because that's old stuff, I won't explain every step. Just take care of the maps position. </p> <div class="fragment"><pre class="fragment"><span class="keywordtype">int</span> main(<span class="keywordtype">int</span> argc, <span class="keywordtype">char</span>** argv) { <span class="comment">// ask user for driver</span> <a class="code" href="namespaceirr_1_1video.html#ae35a6de6d436c76107ad157fe42356d0" title="An enum for all types of drivers the Irrlicht Engine supports.">video::E_DRIVER_TYPE</a> driverType=driverChoiceConsole(); <span class="keywordflow">if</span> (driverType==<a class="code" href="namespaceirr_1_1video.html#ae35a6de6d436c76107ad157fe42356d0ae685cada50f8c100403134d932d0414c" title="No driver, just for counting the elements.">video::EDT_COUNT</a>) <span class="keywordflow">return</span> 1; <span class="comment">//Instance of the EventReceiver</span> MyEventReceiver receiver; <span class="comment">//Initialise the engine</span> IrrlichtDevice *device = <a class="code" href="namespaceirr.html#abaf4d8719cc26b0d30813abf85e47c76" title="Creates an Irrlicht device. The Irrlicht device is the root object for using the...">createDevice</a>(driverType, <a class="code" href="namespaceirr_1_1core.html#ad2e562e3219072e2f7fc7c2bba0ef0cb" title="Typedef for an unsigned integer dimension.">dimension2du</a>(ResX,ResY), 32, fullScreen, <span class="keyword">false</span>, <span class="keyword">false</span>, &receiver); <span class="keywordflow">if</span> (!device) <span class="keywordflow">return</span> 1; ISceneManager *smgr = device->getSceneManager(); IVideoDriver *driver = device->getVideoDriver(); <span class="comment">//Load model</span> IAnimatedMesh *model = smgr->getMesh(<span class="stringliteral">"../../media/sydney.md2"</span>); <span class="keywordflow">if</span> (!model) <span class="keywordflow">return</span> 1; IAnimatedMeshSceneNode *model_node = smgr->addAnimatedMeshSceneNode(model); <span class="comment">//Load texture</span> <span class="keywordflow">if</span> (model_node) { ITexture *texture = driver->getTexture(<span class="stringliteral">"../../media/sydney.bmp"</span>); model_node->setMaterialTexture(0,texture); model_node->setMD2Animation(<a class="code" href="namespaceirr_1_1scene.html#a08d4a84966e1d2886d0d57e4acbb4f19af240ef944e6e257ec369f87053c756e8">scene::EMAT_RUN</a>); <span class="comment">//Disable lighting (we've got no light)</span> model_node->setMaterialFlag(<a class="code" href="namespaceirr_1_1video.html#a8a3bc00ae8137535b9fbc5f40add70d3acea597a2692b8415486a464a7f954d34" title="Will this material be lighted? Default: true.">EMF_LIGHTING</a>,<span class="keyword">false</span>); } <span class="comment">//Load map</span> device->getFileSystem()->addZipFileArchive(<span class="stringliteral">"../../media/map-20kdm2.pk3"</span>); IAnimatedMesh *map = smgr->getMesh(<span class="stringliteral">"20kdm2.bsp"</span>); <span class="keywordflow">if</span> (map) { ISceneNode *map_node = smgr->addOctreeSceneNode(map->getMesh(0)); <span class="comment">//Set position</span> map_node->setPosition(<a class="code" href="namespaceirr_1_1core.html#a06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">vector3df</a>(-850,-220,-850)); } </pre></div><p>Now we create our four cameras. One is looking at the model from the front, one from the top and one from the side. In addition there's a FPS-camera which can be controlled by the user. </p> <div class="fragment"><pre class="fragment"> <span class="comment">// Create 3 fixed and one user-controlled cameras</span> <span class="comment">//Front</span> camera[0] = smgr->addCameraSceneNode(0, <a class="code" href="namespaceirr_1_1core.html#a06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">vector3df</a>(50,0,0), <a class="code" href="namespaceirr_1_1core.html#a06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">vector3df</a>(0,0,0)); <span class="comment">//Top</span> camera[1] = smgr->addCameraSceneNode(0, <a class="code" href="namespaceirr_1_1core.html#a06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">vector3df</a>(0,50,0), <a class="code" href="namespaceirr_1_1core.html#a06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">vector3df</a>(0,0,0)); <span class="comment">//Left</span> camera[2] = smgr->addCameraSceneNode(0, <a class="code" href="namespaceirr_1_1core.html#a06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">vector3df</a>(0,0,50), <a class="code" href="namespaceirr_1_1core.html#a06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">vector3df</a>(0,0,0)); <span class="comment">//User-controlled</span> camera[3] = smgr->addCameraSceneNodeFPS(); <span class="comment">// don't start at sydney's position</span> <span class="keywordflow">if</span> (camera[3]) camera[3]->setPosition(<a class="code" href="namespaceirr_1_1core.html#a06f169d08b5c429f5575acb7edbad811" title="Typedef for a f32 3d vector.">core::vector3df</a>(-50,0,-50)); </pre></div><p>Create a variable for counting the fps and hide the mouse: </p> <div class="fragment"><pre class="fragment"> <span class="comment">//Hide mouse</span> device->getCursorControl()->setVisible(<span class="keyword">false</span>); <span class="comment">//We want to count the fps</span> <span class="keywordtype">int</span> lastFPS = -1; </pre></div><p>There wasn't much new stuff - till now! Only by defining four cameras, the game won't be splitscreen. To do this you need several steps:</p> <ul> <li>Set the viewport to the whole screen</li> <li>Begin a new scene (Clear screen)</li> </ul> <ul> <li>The following 3 steps are repeated for every viewport in the splitscreen<ul> <li>Set the viewport to the area you wish</li> <li>Activate the camera which should be "linked" with the viewport</li> <li>Render all objects</li> </ul> </li> </ul> <ul> <li>If you have a GUI:<ul> <li>Set the viewport the whole screen</li> <li>Display the GUI</li> </ul> </li> <li>End scene</li> </ul> <p>Sounds a little complicated, but you'll see it isn't: </p> <div class="fragment"><pre class="fragment"> <span class="keywordflow">while</span>(device->run()) { <span class="comment">//Set the viewpoint to the whole screen and begin scene</span> driver->setViewPort(rect<s32>(0,0,ResX,ResY)); driver->beginScene(<span class="keyword">true</span>,<span class="keyword">true</span>,SColor(255,100,100,100)); <span class="comment">//If SplitScreen is used</span> <span class="keywordflow">if</span> (SplitScreen) { <span class="comment">//Activate camera1</span> smgr->setActiveCamera(camera[0]); <span class="comment">//Set viewpoint to the first quarter (left top)</span> driver->setViewPort(rect<s32>(0,0,ResX/2,ResY/2)); <span class="comment">//Draw scene</span> smgr->drawAll(); <span class="comment">//Activate camera2</span> smgr->setActiveCamera(camera[1]); <span class="comment">//Set viewpoint to the second quarter (right top)</span> driver->setViewPort(rect<s32>(ResX/2,0,ResX,ResY/2)); <span class="comment">//Draw scene</span> smgr->drawAll(); <span class="comment">//Activate camera3</span> smgr->setActiveCamera(camera[2]); <span class="comment">//Set viewpoint to the third quarter (left bottom)</span> driver->setViewPort(rect<s32>(0,ResY/2,ResX/2,ResY)); <span class="comment">//Draw scene</span> smgr->drawAll(); <span class="comment">//Set viewport the last quarter (right bottom)</span> driver->setViewPort(rect<s32>(ResX/2,ResY/2,ResX,ResY)); } <span class="comment">//Activate camera4</span> smgr->setActiveCamera(camera[3]); <span class="comment">//Draw scene</span> smgr->drawAll(); driver->endScene(); </pre></div><p>As you can probably see, the image is rendered for every viewport seperately. That means, that you'll loose much performance. Ok, if you're aksing "How do I have to set the viewport to get this or that screen?", don't panic. It's really easy: In the rect-function you define 4 coordinates:</p> <ul> <li>X-coordinate of the corner left top</li> <li>Y-coordinate of the corner left top</li> <li>X-coordinate of the corner right bottom</li> <li>Y-coordinate of the corner right bottom</li> </ul> <p>That means, if you want to split the screen into 2 viewports you would give the following coordinates:</p> <ul> <li>1st viewport: 0,0,ResX/2,ResY</li> <li>2nd viewport: ResX/2,0,ResX,ResY</li> </ul> <p>If you didn't fully understand, just play arround with the example to check out what happens.</p> <p>Now we just view the current fps and shut down the engine, when the user wants to: </p> <div class="fragment"><pre class="fragment"> <span class="comment">//Get and show fps</span> <span class="keywordflow">if</span> (driver->getFPS() != lastFPS) { lastFPS = driver->getFPS(); <a class="code" href="namespaceirr_1_1core.html#aef83fafbb1b36fcce44c07c9be23a7f2" title="Typedef for wide character strings.">core::stringw</a> tmp = L<span class="stringliteral">"Irrlicht SplitScreen-Example (FPS: "</span>; tmp += lastFPS; tmp += <span class="stringliteral">")"</span>; device->setWindowCaption(tmp.c_str()); } } <span class="comment">//Delete device</span> device->drop(); <span class="keywordflow">return</span> 0; } </pre></div><p>That's it! Just compile and play around with the program. Note: With the S-Key you can switch between using splitscreen and not. </p> </div> <hr size="1"> <address style="align: right;"> <small> </small> </address> <table width="100%" border="0" cellspacing="0" cellpadding="2"> <tr> <td width="0"> <div align="left"><small><a href="http://irrlicht.sourceforge.net" target="_blank"><img src="irrlicht.png" alt="The Irrlicht Engine" align="middle" border=0 width=88 height=31></a></small></div></td> <td> <div align="left"><small><em><font size="2">The <a href="http://irrlicht.sourceforge.net" target="_blank">Irrlicht Engine</a> Documentation © 2003-2010 by Nikolaus Gebhardt. Generated on Sun Oct 24 12:42:00 2010 by <a href="http://www.doxygen.org" target="_blank">Doxygen</a> (1.6.2)</font></em></small></div></td> </tr> </table> <address style="align: right;"> </address> </body> </html>