mirror of
https://github.com/minetest/irrlicht.git
synced 2024-12-25 23:47:30 +01:00
21302d038a
git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@6249 dfc29bdd-3216-0410-991c-e03cc46cb475
237 lines
19 KiB
HTML
237 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>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
|
<meta name="generator" content="Doxygen 1.8.13"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
<title>Tutorial 18: Splitscreen</title>
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<!-- Wanted to avoid copying .css to each folder, so copied default .css from doxyen in here, kicked out most stuff we don't need for examples and modified some a little bit.
|
|
Target was having a single html in each example folder which is created from the main.cpp files and needs no files besides some images below media folder.
|
|
Feel free to improve :)
|
|
-->
|
|
<style>
|
|
body, table, div, p, dl {
|
|
font: 400 14px/22px;
|
|
}
|
|
body {
|
|
background-color: #F0F0F0;
|
|
color: black;
|
|
margin-left: 5%;
|
|
margin-right: 5%;
|
|
}
|
|
p.reference, p.definition {
|
|
font: 400 14px/22px;
|
|
}
|
|
.title {
|
|
font: 400 14px/28px;
|
|
font-size: 150%;
|
|
font-weight: bold;
|
|
margin: 10px 2px;
|
|
}
|
|
h1, h2, h3, h4, h5, h6 {
|
|
-webkit-transition: text-shadow 0.5s linear;
|
|
-moz-transition: text-shadow 0.5s linear;
|
|
-ms-transition: text-shadow 0.5s linear;
|
|
-o-transition: text-shadow 0.5s linear;
|
|
transition: text-shadow 0.5s linear;
|
|
margin-right: 15px;
|
|
}
|
|
caption {
|
|
font-weight: bold;
|
|
}
|
|
h3.version {
|
|
font-size: 90%;
|
|
text-align: center;
|
|
}
|
|
a {
|
|
color: #3D578C;
|
|
font-weight: normal;
|
|
text-decoration: none;
|
|
}
|
|
.contents a:visited {
|
|
color: #4665A2;
|
|
}
|
|
a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
a.el {
|
|
font-weight: bold;
|
|
}
|
|
a.code, a.code:visited, a.line, a.line:visited {
|
|
color: #4665A2;
|
|
}
|
|
a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
|
|
color: #4665A2;
|
|
}
|
|
pre.fragment {
|
|
border: 1px solid #C4CFE5;
|
|
background-color: #FBFCFD;
|
|
padding: 4px 6px;
|
|
margin: 4px 8px 4px 2px;
|
|
overflow: auto;
|
|
word-wrap: break-word;
|
|
font-size: 9pt;
|
|
line-height: 125%;
|
|
font-family: monospace, fixed;
|
|
font-size: 105%;
|
|
}
|
|
div.fragment {
|
|
padding: 0px;
|
|
margin: 4px 8px 4px 2px;
|
|
background-color: #FBFCFD;
|
|
border: 1px solid #C4CFE5;
|
|
}
|
|
div.line {
|
|
font-family: monospace, fixed;
|
|
font-size: 13px;
|
|
min-height: 13px;
|
|
line-height: 1.0;
|
|
text-wrap: unrestricted;
|
|
white-space: -moz-pre-wrap; /* Moz */
|
|
white-space: -pre-wrap; /* Opera 4-6 */
|
|
white-space: -o-pre-wrap; /* Opera 7 */
|
|
white-space: pre-wrap; /* CSS3 */
|
|
word-wrap: break-word; /* IE 5.5+ */
|
|
text-indent: -53px;
|
|
padding-left: 53px;
|
|
padding-bottom: 0px;
|
|
margin: 0px;
|
|
-webkit-transition-property: background-color, box-shadow;
|
|
-webkit-transition-duration: 0.5s;
|
|
-moz-transition-property: background-color, box-shadow;
|
|
-moz-transition-duration: 0.5s;
|
|
-ms-transition-property: background-color, box-shadow;
|
|
-ms-transition-duration: 0.5s;
|
|
-o-transition-property: background-color, box-shadow;
|
|
-o-transition-duration: 0.5s;
|
|
transition-property: background-color, box-shadow;
|
|
transition-duration: 0.5s;
|
|
}
|
|
div.contents {
|
|
margin-top: 10px;
|
|
margin-left: 12px;
|
|
margin-right: 8px;
|
|
}
|
|
div.center {
|
|
text-align: center;
|
|
margin-top: 0px;
|
|
margin-bottom: 0px;
|
|
padding: 0px;
|
|
}
|
|
div.center img {
|
|
border: 0px;
|
|
}
|
|
span.keyword {
|
|
color: #008000
|
|
}
|
|
span.keywordtype {
|
|
color: #604020
|
|
}
|
|
span.keywordflow {
|
|
color: #e08000
|
|
}
|
|
span.comment {
|
|
color: #800000
|
|
}
|
|
span.preprocessor {
|
|
color: #806020
|
|
}
|
|
span.stringliteral {
|
|
color: #002080
|
|
}
|
|
span.charliteral {
|
|
color: #008080
|
|
}
|
|
blockquote {
|
|
background-color: #F7F8FB;
|
|
border-left: 2px solid #9CAFD4;
|
|
margin: 0 24px 0 4px;
|
|
padding: 0 12px 0 16px;
|
|
}
|
|
hr {
|
|
height: 0px;
|
|
border: none;
|
|
border-top: 1px solid #4A6AAA;
|
|
}
|
|
address {
|
|
font-style: normal;
|
|
color: #2A3D61;
|
|
}
|
|
div.header {
|
|
background-image:url('nav_h.png');
|
|
background-repeat:repeat-x;
|
|
background-color: #F9FAFC;
|
|
margin: 0px;
|
|
border-bottom: 1px solid #C4CFE5;
|
|
}
|
|
div.headertitle {
|
|
padding: 5px 5px 5px 10px;
|
|
}
|
|
.image {
|
|
text-align: center;
|
|
}
|
|
.caption {
|
|
font-weight: bold;
|
|
}
|
|
div.zoom {
|
|
border: 1px solid #90A5CE;
|
|
}
|
|
tr.heading h2 {
|
|
margin-top: 12px;
|
|
margin-bottom: 4px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
|
<!--END TITLEAREA-->
|
|
<!-- end header part -->
|
|
<!-- Generated by Doxygen 1.8.13 -->
|
|
</div><!-- top -->
|
|
<div class="header">
|
|
<div class="headertitle">
|
|
<div class="title">Tutorial 18: Splitscreen </div> </div>
|
|
</div><!--header-->
|
|
<div class="contents">
|
|
<div class="textblock"><div class="image">
|
|
<img src="../../media/example_screenshots/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"><div class="line"><span class="preprocessor">#include <irrlicht.h></span></div><div class="line"><span class="preprocessor">#include "driverChoice.h"</span></div><div class="line"><span class="preprocessor">#include "exampleHelper.h"</span></div><div class="line"></div><div class="line"><span class="preprocessor">#ifdef _MSC_VER</span></div><div class="line"><span class="preprocessor">#pragma comment(lib, "Irrlicht.lib")</span></div><div class="line"><span class="preprocessor">#endif</span></div><div class="line"></div><div class="line"><span class="comment">//Namespaces for the engine</span></div><div class="line"><span class="keyword">using namespace </span>irr;</div><div class="line"><span class="keyword">using namespace </span>core;</div><div class="line"><span class="keyword">using namespace </span>video;</div><div class="line"><span class="keyword">using namespace </span>scene;</div></div><!-- fragment --><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"><div class="line"><span class="comment">//Resolution</span></div><div class="line"><span class="keyword">const</span> <span class="keywordtype">int</span> ResX=800;</div><div class="line"><span class="keyword">const</span> <span class="keywordtype">int</span> ResY=600;</div><div class="line"><span class="keyword">const</span> <span class="keywordtype">bool</span> fullScreen=<span class="keyword">false</span>;</div><div class="line"></div><div class="line"><span class="comment">//Use SplitScreen?</span></div><div class="line"><span class="keywordtype">bool</span> SplitScreen=<span class="keyword">true</span>;</div></div><!-- fragment --><p> Now we need four pointers to our cameras which are created later: </p><div class="fragment"><div class="line"><span class="comment">//cameras</span></div><div class="line">ICameraSceneNode *camera[4]={0,0,0,0};</div></div><!-- fragment --><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"><div class="line"><span class="keyword">class </span>MyEventReceiver : <span class="keyword">public</span> IEventReceiver</div><div class="line">{</div><div class="line"> <span class="keyword">public</span>:</div><div class="line"> <span class="keyword">virtual</span> <span class="keywordtype">bool</span> OnEvent(<span class="keyword">const</span> SEvent& event)</div><div class="line"> {</div><div class="line"> <span class="comment">//Key S enables/disables SplitScreen</span></div><div class="line"> <span class="keywordflow">if</span> (event.EventType == irr::EET_KEY_INPUT_EVENT &&</div><div class="line"> event.KeyInput.Key == KEY_KEY_S && event.KeyInput.PressedDown)</div><div class="line"> {</div><div class="line"> SplitScreen = !SplitScreen;</div><div class="line"> <span class="keywordflow">return</span> <span class="keyword">true</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">//Send all other events to camera4</span></div><div class="line"> <span class="keywordflow">if</span> (camera[3])</div><div class="line"> <span class="keywordflow">return</span> camera[3]->OnEvent(event);</div><div class="line"> <span class="keywordflow">return</span> <span class="keyword">false</span>;</div><div class="line"> }</div><div class="line">};</div></div><!-- fragment --><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"><div class="line"><span class="keywordtype">int</span> main()</div><div class="line">{</div><div class="line"> <span class="comment">// ask user for driver</span></div><div class="line"> video::E_DRIVER_TYPE driverType=driverChoiceConsole();</div><div class="line"> <span class="keywordflow">if</span> (driverType==video::EDT_COUNT)</div><div class="line"> <span class="keywordflow">return</span> 1;</div><div class="line"></div><div class="line"> <span class="comment">//Instance of the EventReceiver</span></div><div class="line"> MyEventReceiver receiver;</div><div class="line"></div><div class="line"> <span class="comment">//Initialise the engine</span></div><div class="line"> IrrlichtDevice *device = createDevice(driverType,</div><div class="line"> dimension2du(ResX,ResY), 32, fullScreen,</div><div class="line"> <span class="keyword">false</span>, <span class="keyword">false</span>, &receiver);</div><div class="line"> <span class="keywordflow">if</span> (!device)</div><div class="line"> <span class="keywordflow">return</span> 1;</div><div class="line"></div><div class="line"> ISceneManager *smgr = device->getSceneManager();</div><div class="line"> IVideoDriver *driver = device->getVideoDriver();</div><div class="line"></div><div class="line"> <span class="keyword">const</span> io::path mediaPath = getExampleMediaPath();</div><div class="line"></div><div class="line"> <span class="comment">//Load model</span></div><div class="line"> IAnimatedMesh *model = smgr->getMesh(mediaPath + <span class="stringliteral">"sydney.md2"</span>);</div><div class="line"> <span class="keywordflow">if</span> (!model)</div><div class="line"> <span class="keywordflow">return</span> 1;</div><div class="line"> IAnimatedMeshSceneNode *model_node = smgr->addAnimatedMeshSceneNode(model);</div><div class="line"> <span class="comment">//Load texture</span></div><div class="line"> <span class="keywordflow">if</span> (model_node)</div><div class="line"> {</div><div class="line"> ITexture *texture = driver->getTexture(mediaPath + <span class="stringliteral">"sydney.bmp"</span>);</div><div class="line"> model_node->setMaterialTexture(0,texture);</div><div class="line"> model_node->setMD2Animation(scene::EMAT_RUN);</div><div class="line"> <span class="comment">//Disable lighting (we've got no light)</span></div><div class="line"> model_node->setMaterialFlag(EMF_LIGHTING,<span class="keyword">false</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">//Load map</span></div><div class="line"> device->getFileSystem()->addFileArchive(mediaPath + <span class="stringliteral">"map-20kdm2.pk3"</span>);</div><div class="line"> IAnimatedMesh *map = smgr->getMesh(<span class="stringliteral">"20kdm2.bsp"</span>);</div><div class="line"> <span class="keywordflow">if</span> (map)</div><div class="line"> {</div><div class="line"> ISceneNode *map_node = smgr->addOctreeSceneNode(map->getMesh(0));</div><div class="line"> <span class="comment">//Set position</span></div><div class="line"> map_node->setPosition(vector3df(-850,-220,-850));</div><div class="line"> }</div></div><!-- fragment --><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"><div class="line"><span class="comment">// Create 3 fixed and one user-controlled cameras</span></div><div class="line"><span class="comment">//Front</span></div><div class="line">camera[0] = smgr->addCameraSceneNode(0, vector3df(50,0,0), vector3df(0,0,0));</div><div class="line"><span class="comment">//Top</span></div><div class="line">camera[1] = smgr->addCameraSceneNode(0, vector3df(0,50,0), vector3df(0,0,0));</div><div class="line"><span class="comment">//Left</span></div><div class="line">camera[2] = smgr->addCameraSceneNode(0, vector3df(0,0,50), vector3df(0,0,0));</div><div class="line"><span class="comment">//User-controlled</span></div><div class="line">camera[3] = smgr->addCameraSceneNodeFPS();</div><div class="line"><span class="comment">// don't start at sydney's position</span></div><div class="line"><span class="keywordflow">if</span> (camera[3])</div><div class="line"> camera[3]->setPosition(core::vector3df(-50,0,-50));</div></div><!-- fragment --><p> Create a variable for counting the fps and hide the mouse: </p><div class="fragment"><div class="line"><span class="comment">//Hide mouse</span></div><div class="line">device->getCursorControl()->setVisible(<span class="keyword">false</span>);</div><div class="line"><span class="comment">//We want to count the fps</span></div><div class="line"><span class="keywordtype">int</span> lastFPS = -1;</div></div><!-- fragment --><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>
|
|
<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>
|
|
<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"><div class="line"><span class="keywordflow">while</span>(device->run())</div><div class="line">{</div><div class="line"> <span class="comment">//Set the viewpoint to the whole screen and begin scene</span></div><div class="line"> driver->setViewPort(rect<s32>(0,0,ResX,ResY));</div><div class="line"> driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(255,100,100,100));</div><div class="line"> <span class="comment">//If SplitScreen is used</span></div><div class="line"> <span class="keywordflow">if</span> (SplitScreen)</div><div class="line"> {</div><div class="line"> <span class="comment">//Activate camera1</span></div><div class="line"> smgr->setActiveCamera(camera[0]);</div><div class="line"> <span class="comment">//Set viewpoint to the first quarter (left top)</span></div><div class="line"> driver->setViewPort(rect<s32>(0,0,ResX/2,ResY/2));</div><div class="line"> <span class="comment">//Draw scene</span></div><div class="line"> smgr->drawAll();</div><div class="line"> <span class="comment">//Activate camera2</span></div><div class="line"> smgr->setActiveCamera(camera[1]);</div><div class="line"> <span class="comment">//Set viewpoint to the second quarter (right top)</span></div><div class="line"> driver->setViewPort(rect<s32>(ResX/2,0,ResX,ResY/2));</div><div class="line"> <span class="comment">//Draw scene</span></div><div class="line"> smgr->drawAll();</div><div class="line"> <span class="comment">//Activate camera3</span></div><div class="line"> smgr->setActiveCamera(camera[2]);</div><div class="line"> <span class="comment">//Set viewpoint to the third quarter (left bottom)</span></div><div class="line"> driver->setViewPort(rect<s32>(0,ResY/2,ResX/2,ResY));</div><div class="line"> <span class="comment">//Draw scene</span></div><div class="line"> smgr->drawAll();</div><div class="line"> <span class="comment">//Set viewport the last quarter (right bottom)</span></div><div class="line"> driver->setViewPort(rect<s32>(ResX/2,ResY/2,ResX,ResY));</div><div class="line"> }</div><div class="line"> <span class="comment">//Activate camera4</span></div><div class="line"> smgr->setActiveCamera(camera[3]);</div><div class="line"> <span class="comment">//Draw scene</span></div><div class="line"> smgr->drawAll();</div><div class="line"> driver->endScene();</div></div><!-- fragment --><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"><div class="line"> <span class="comment">//Get and show fps</span></div><div class="line"> <span class="keywordflow">if</span> (driver->getFPS() != lastFPS)</div><div class="line"> {</div><div class="line"> lastFPS = driver->getFPS();</div><div class="line"> core::stringw tmp = L<span class="stringliteral">"Irrlicht SplitScreen-Example (FPS: "</span>;</div><div class="line"> tmp += lastFPS;</div><div class="line"> tmp += <span class="stringliteral">")"</span>;</div><div class="line"> device->setWindowCaption(tmp.c_str());</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="comment">//Delete device</span></div><div class="line"> device->drop();</div><div class="line"> <span class="keywordflow">return</span> 0;</div><div class="line">}</div></div><!-- fragment --><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><!-- contents -->
|
|
<!-- HTML footer for doxygen 1.8.13-->
|
|
<!-- start footer part -->
|
|
<p> </p>
|
|
</body>
|
|
</html>
|