tutorial.html 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
  5. <meta http-equiv="X-UA-Compatible" content="IE=9"/>
  6. <meta name="generator" content="Doxygen 1.8.13"/>
  7. <meta name="viewport" content="width=device-width, initial-scale=1"/>
  8. <title>Tutorial 18: Splitscreen</title>
  9. <html xmlns="http://www.w3.org/1999/xhtml">
  10. <!-- 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.
  11. 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.
  12. Feel free to improve :)
  13. -->
  14. <style>
  15. body, table, div, p, dl {
  16. font: 400 14px/22px;
  17. }
  18. body {
  19. background-color: #F0F0F0;
  20. color: black;
  21. margin-left: 5%;
  22. margin-right: 5%;
  23. }
  24. p.reference, p.definition {
  25. font: 400 14px/22px;
  26. }
  27. .title {
  28. font: 400 14px/28px;
  29. font-size: 150%;
  30. font-weight: bold;
  31. margin: 10px 2px;
  32. }
  33. h1, h2, h3, h4, h5, h6 {
  34. -webkit-transition: text-shadow 0.5s linear;
  35. -moz-transition: text-shadow 0.5s linear;
  36. -ms-transition: text-shadow 0.5s linear;
  37. -o-transition: text-shadow 0.5s linear;
  38. transition: text-shadow 0.5s linear;
  39. margin-right: 15px;
  40. }
  41. caption {
  42. font-weight: bold;
  43. }
  44. h3.version {
  45. font-size: 90%;
  46. text-align: center;
  47. }
  48. a {
  49. color: #3D578C;
  50. font-weight: normal;
  51. text-decoration: none;
  52. }
  53. .contents a:visited {
  54. color: #4665A2;
  55. }
  56. a:hover {
  57. text-decoration: underline;
  58. }
  59. a.el {
  60. font-weight: bold;
  61. }
  62. a.code, a.code:visited, a.line, a.line:visited {
  63. color: #4665A2;
  64. }
  65. a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
  66. color: #4665A2;
  67. }
  68. pre.fragment {
  69. border: 1px solid #C4CFE5;
  70. background-color: #FBFCFD;
  71. padding: 4px 6px;
  72. margin: 4px 8px 4px 2px;
  73. overflow: auto;
  74. word-wrap: break-word;
  75. font-size: 9pt;
  76. line-height: 125%;
  77. font-family: monospace, fixed;
  78. font-size: 105%;
  79. }
  80. div.fragment {
  81. padding: 0px;
  82. margin: 4px 8px 4px 2px;
  83. background-color: #FBFCFD;
  84. border: 1px solid #C4CFE5;
  85. }
  86. div.line {
  87. font-family: monospace, fixed;
  88. font-size: 13px;
  89. min-height: 13px;
  90. line-height: 1.0;
  91. text-wrap: unrestricted;
  92. white-space: -moz-pre-wrap; /* Moz */
  93. white-space: -pre-wrap; /* Opera 4-6 */
  94. white-space: -o-pre-wrap; /* Opera 7 */
  95. white-space: pre-wrap; /* CSS3 */
  96. word-wrap: break-word; /* IE 5.5+ */
  97. text-indent: -53px;
  98. padding-left: 53px;
  99. padding-bottom: 0px;
  100. margin: 0px;
  101. -webkit-transition-property: background-color, box-shadow;
  102. -webkit-transition-duration: 0.5s;
  103. -moz-transition-property: background-color, box-shadow;
  104. -moz-transition-duration: 0.5s;
  105. -ms-transition-property: background-color, box-shadow;
  106. -ms-transition-duration: 0.5s;
  107. -o-transition-property: background-color, box-shadow;
  108. -o-transition-duration: 0.5s;
  109. transition-property: background-color, box-shadow;
  110. transition-duration: 0.5s;
  111. }
  112. div.contents {
  113. margin-top: 10px;
  114. margin-left: 12px;
  115. margin-right: 8px;
  116. }
  117. div.center {
  118. text-align: center;
  119. margin-top: 0px;
  120. margin-bottom: 0px;
  121. padding: 0px;
  122. }
  123. div.center img {
  124. border: 0px;
  125. }
  126. span.keyword {
  127. color: #008000
  128. }
  129. span.keywordtype {
  130. color: #604020
  131. }
  132. span.keywordflow {
  133. color: #e08000
  134. }
  135. span.comment {
  136. color: #800000
  137. }
  138. span.preprocessor {
  139. color: #806020
  140. }
  141. span.stringliteral {
  142. color: #002080
  143. }
  144. span.charliteral {
  145. color: #008080
  146. }
  147. blockquote {
  148. background-color: #F7F8FB;
  149. border-left: 2px solid #9CAFD4;
  150. margin: 0 24px 0 4px;
  151. padding: 0 12px 0 16px;
  152. }
  153. hr {
  154. height: 0px;
  155. border: none;
  156. border-top: 1px solid #4A6AAA;
  157. }
  158. address {
  159. font-style: normal;
  160. color: #2A3D61;
  161. }
  162. div.header {
  163. background-image:url('nav_h.png');
  164. background-repeat:repeat-x;
  165. background-color: #F9FAFC;
  166. margin: 0px;
  167. border-bottom: 1px solid #C4CFE5;
  168. }
  169. div.headertitle {
  170. padding: 5px 5px 5px 10px;
  171. }
  172. .image {
  173. text-align: center;
  174. }
  175. .caption {
  176. font-weight: bold;
  177. }
  178. div.zoom {
  179. border: 1px solid #90A5CE;
  180. }
  181. tr.heading h2 {
  182. margin-top: 12px;
  183. margin-bottom: 4px;
  184. }
  185. </style>
  186. </head>
  187. <div id="top"><!-- do not remove this div, it is closed by doxygen! -->
  188. <!--END TITLEAREA-->
  189. <!-- end header part -->
  190. <!-- Generated by Doxygen 1.8.13 -->
  191. </div><!-- top -->
  192. <div class="header">
  193. <div class="headertitle">
  194. <div class="title">Tutorial 18: Splitscreen </div> </div>
  195. </div><!--header-->
  196. <div class="contents">
  197. <div class="textblock"><div class="image">
  198. <img src="../../media/example_screenshots/018shot.jpg" alt="018shot.jpg"/>
  199. </div>
  200. <p>A tutorial by Max Winkel.</p>
  201. <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>
  202. <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 &lt;irrlicht.h&gt;</span></div><div class="line"><span class="preprocessor">#include &quot;driverChoice.h&quot;</span></div><div class="line"><span class="preprocessor">#include &quot;exampleHelper.h&quot;</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, &quot;Irrlicht.lib&quot;)</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&amp; 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 &amp;&amp;</div><div class="line"> event.KeyInput.Key == KEY_KEY_S &amp;&amp; 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]-&gt;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>, &amp;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-&gt;getSceneManager();</div><div class="line"> IVideoDriver *driver = device-&gt;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-&gt;getMesh(mediaPath + <span class="stringliteral">&quot;sydney.md2&quot;</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-&gt;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-&gt;getTexture(mediaPath + <span class="stringliteral">&quot;sydney.bmp&quot;</span>);</div><div class="line"> model_node-&gt;setMaterialTexture(0,texture);</div><div class="line"> model_node-&gt;setMD2Animation(scene::EMAT_RUN);</div><div class="line"> <span class="comment">//Disable lighting (we&#39;ve got no light)</span></div><div class="line"> model_node-&gt;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-&gt;getFileSystem()-&gt;addFileArchive(mediaPath + <span class="stringliteral">&quot;map-20kdm2.pk3&quot;</span>);</div><div class="line"> IAnimatedMesh *map = smgr-&gt;getMesh(<span class="stringliteral">&quot;20kdm2.bsp&quot;</span>);</div><div class="line"> <span class="keywordflow">if</span> (map)</div><div class="line"> {</div><div class="line"> ISceneNode *map_node = smgr-&gt;addOctreeSceneNode(map-&gt;getMesh(0));</div><div class="line"> <span class="comment">//Set position</span></div><div class="line"> map_node-&gt;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-&gt;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-&gt;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-&gt;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-&gt;addCameraSceneNodeFPS();</div><div class="line"><span class="comment">// don&#39;t start at sydney&#39;s position</span></div><div class="line"><span class="keywordflow">if</span> (camera[3])</div><div class="line"> camera[3]-&gt;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-&gt;getCursorControl()-&gt;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>
  203. <li>Set the viewport to the whole screen</li>
  204. <li>Begin a new scene (Clear screen)</li>
  205. <li>The following 3 steps are repeated for every viewport in the splitscreen<ul>
  206. <li>Set the viewport to the area you wish</li>
  207. <li>Activate the camera which should be "linked" with the viewport</li>
  208. <li>Render all objects</li>
  209. </ul>
  210. </li>
  211. <li>If you have a GUI:<ul>
  212. <li>Set the viewport the whole screen</li>
  213. <li>Display the GUI</li>
  214. </ul>
  215. </li>
  216. <li>End scene</li>
  217. </ul>
  218. <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-&gt;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-&gt;setViewPort(rect&lt;s32&gt;(0,0,ResX,ResY));</div><div class="line"> driver-&gt;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-&gt;setActiveCamera(camera[0]);</div><div class="line"> <span class="comment">//Set viewpoint to the first quarter (left top)</span></div><div class="line"> driver-&gt;setViewPort(rect&lt;s32&gt;(0,0,ResX/2,ResY/2));</div><div class="line"> <span class="comment">//Draw scene</span></div><div class="line"> smgr-&gt;drawAll();</div><div class="line"> <span class="comment">//Activate camera2</span></div><div class="line"> smgr-&gt;setActiveCamera(camera[1]);</div><div class="line"> <span class="comment">//Set viewpoint to the second quarter (right top)</span></div><div class="line"> driver-&gt;setViewPort(rect&lt;s32&gt;(ResX/2,0,ResX,ResY/2));</div><div class="line"> <span class="comment">//Draw scene</span></div><div class="line"> smgr-&gt;drawAll();</div><div class="line"> <span class="comment">//Activate camera3</span></div><div class="line"> smgr-&gt;setActiveCamera(camera[2]);</div><div class="line"> <span class="comment">//Set viewpoint to the third quarter (left bottom)</span></div><div class="line"> driver-&gt;setViewPort(rect&lt;s32&gt;(0,ResY/2,ResX/2,ResY));</div><div class="line"> <span class="comment">//Draw scene</span></div><div class="line"> smgr-&gt;drawAll();</div><div class="line"> <span class="comment">//Set viewport the last quarter (right bottom)</span></div><div class="line"> driver-&gt;setViewPort(rect&lt;s32&gt;(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-&gt;setActiveCamera(camera[3]);</div><div class="line"> <span class="comment">//Draw scene</span></div><div class="line"> smgr-&gt;drawAll();</div><div class="line"> driver-&gt;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
  219. to get this or that screen?", don't panic. It's really easy: In the rect-function you define 4 coordinates:</p><ul>
  220. <li>X-coordinate of the corner left top</li>
  221. <li>Y-coordinate of the corner left top</li>
  222. <li>X-coordinate of the corner right bottom</li>
  223. <li>Y-coordinate of the corner right bottom</li>
  224. </ul>
  225. <p>That means, if you want to split the screen into 2 viewports you would give the following coordinates:</p><ul>
  226. <li>1st viewport: 0,0,ResX/2,ResY</li>
  227. <li>2nd viewport: ResX/2,0,ResX,ResY</li>
  228. </ul>
  229. <p>If you didn't fully understand, just play around with the example to check out what happens.</p>
  230. <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-&gt;getFPS() != lastFPS)</div><div class="line"> {</div><div class="line"> lastFPS = driver-&gt;getFPS();</div><div class="line"> core::stringw tmp = L<span class="stringliteral">&quot;Irrlicht SplitScreen-Example (FPS: &quot;</span>;</div><div class="line"> tmp += lastFPS;</div><div class="line"> tmp += <span class="stringliteral">&quot;)&quot;</span>;</div><div class="line"> device-&gt;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-&gt;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>
  231. </div></div><!-- contents -->
  232. <!-- HTML footer for doxygen 1.8.13-->
  233. <!-- start footer part -->
  234. <p>&nbsp;</p>
  235. </body>
  236. </html>