mirror of
https://github.com/minetest/irrlicht.git
synced 2024-11-11 21:00:35 +01:00
317 lines
19 KiB
HTML
317 lines
19 KiB
HTML
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
|
<head>
|
||
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||
|
<title>Irrlicht 3D Engine: Tutorial 18: Splitscreen</title>
|
||
|
|
||
|
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||
|
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||
|
<link href="navtree.css" rel="stylesheet" type="text/css"/>
|
||
|
<script type="text/javascript" src="jquery.js"></script>
|
||
|
<script type="text/javascript" src="resize.js"></script>
|
||
|
<script type="text/javascript" src="navtree.js"></script>
|
||
|
<script type="text/javascript">
|
||
|
$(document).ready(initResizable);
|
||
|
</script>
|
||
|
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
||
|
<script type="text/javascript" src="search/search.js"></script>
|
||
|
<script type="text/javascript">
|
||
|
$(document).ready(function() { searchBox.OnSelectItem(0); });
|
||
|
</script>
|
||
|
|
||
|
</head>
|
||
|
<body>
|
||
|
<div id="top"><!-- do not remove this div! -->
|
||
|
|
||
|
|
||
|
<div id="titlearea">
|
||
|
<table cellspacing="0" cellpadding="0">
|
||
|
<tbody>
|
||
|
<tr style="height: 56px;">
|
||
|
|
||
|
<td id="projectlogo"><img alt="Logo" src="irrlichtlogo.png"/></td>
|
||
|
|
||
|
|
||
|
<td style="padding-left: 0.5em;">
|
||
|
<div id="projectname">Irrlicht 3D Engine
|
||
|
|
||
|
</div>
|
||
|
|
||
|
</td>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<td> <div id="MSearchBox" class="MSearchBoxInactive">
|
||
|
<span class="left">
|
||
|
<img id="MSearchSelect" src="search/mag_sel.png"
|
||
|
onmouseover="return searchBox.OnSearchSelectShow()"
|
||
|
onmouseout="return searchBox.OnSearchSelectHide()"
|
||
|
alt=""/>
|
||
|
<input type="text" id="MSearchField" value="Search" accesskey="S"
|
||
|
onfocus="searchBox.OnSearchFieldFocus(true)"
|
||
|
onblur="searchBox.OnSearchFieldFocus(false)"
|
||
|
onkeyup="searchBox.OnSearchFieldChange(event)"/>
|
||
|
</span><span class="right">
|
||
|
<a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
|
||
|
</span>
|
||
|
</div>
|
||
|
</td>
|
||
|
|
||
|
|
||
|
</tr>
|
||
|
</tbody>
|
||
|
</table>
|
||
|
</div>
|
||
|
|
||
|
<!-- Generated by Doxygen 1.7.5.1 -->
|
||
|
<script type="text/javascript">
|
||
|
var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
||
|
</script>
|
||
|
<script type="text/javascript" src="dynsections.js"></script>
|
||
|
</div>
|
||
|
<div id="side-nav" class="ui-resizable side-nav-resizable">
|
||
|
<div id="nav-tree">
|
||
|
<div id="nav-tree-contents">
|
||
|
</div>
|
||
|
</div>
|
||
|
<div id="splitbar" style="-moz-user-select:none;"
|
||
|
class="ui-resizable-handle">
|
||
|
</div>
|
||
|
</div>
|
||
|
<script type="text/javascript">
|
||
|
initNavTree('example018.html','');
|
||
|
</script>
|
||
|
<div id="doc-content">
|
||
|
<div class="header">
|
||
|
<div class="headertitle">
|
||
|
<div class="title">Tutorial 18: Splitscreen </div> </div>
|
||
|
</div>
|
||
|
<div class="contents">
|
||
|
<div class="textblock"><div class="image">
|
||
|
<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, with 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="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 engine.">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()->addFileArchive(<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 separately. That means, that you'll loose much performance. Ok, if you're asking "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 around 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></div>
|
||
|
</div>
|
||
|
<div id="nav-path" class="navpath">
|
||
|
<ul>
|
||
|
<!-- window showing the filter options -->
|
||
|
<div id="MSearchSelectWindow"
|
||
|
onmouseover="return searchBox.OnSearchSelectShow()"
|
||
|
onmouseout="return searchBox.OnSearchSelectHide()"
|
||
|
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
||
|
<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark"> </span>All</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark"> </span>Classes</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark"> </span>Namespaces</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(3)"><span class="SelectionMark"> </span>Files</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(4)"><span class="SelectionMark"> </span>Functions</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(5)"><span class="SelectionMark"> </span>Variables</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(6)"><span class="SelectionMark"> </span>Typedefs</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(7)"><span class="SelectionMark"> </span>Enumerations</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(8)"><span class="SelectionMark"> </span>Enumerator</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(9)"><span class="SelectionMark"> </span>Friends</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(10)"><span class="SelectionMark"> </span>Defines</a></div>
|
||
|
|
||
|
<!-- iframe showing the search results (closed by default) -->
|
||
|
<div id="MSearchResultsWindow">
|
||
|
<iframe src="javascript:void(0)" frameborder="0"
|
||
|
name="MSearchResults" id="MSearchResults">
|
||
|
</iframe>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
<li class="footer">
|
||
|
<a href="http://irrlicht.sourceforge.net" target="_blank">Irrlicht
|
||
|
Engine</a> Documentation © 2003-2012 by Nikolaus Gebhardt. Generated on Sat Jul 9 2016 18:18:26 for Irrlicht 3D Engine by
|
||
|
<a href="http://www.doxygen.org/index.html" target="_blank">Doxygen</a> 1.7.5.1 </li>
|
||
|
</ul>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
</body>
|
||
|
</html>
|