]> git.lizzy.rs Git - dragonfireclient.git/blob - src/drawscene.cpp
Fix interlaced 3d mode second image being flipped on compiling against irrlicht ...
[dragonfireclient.git] / src / drawscene.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2014 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "drawscene.h"
21 #include "main.h" // for g_settings
22 #include "settings.h"
23 #include "clouds.h"
24 #include "clientmap.h"
25 #include "util/timetaker.h"
26
27 typedef enum {
28         LEFT = -1,
29         RIGHT = 1,
30         EYECOUNT = 2
31 } paralax_sign;
32
33 void draw_selectionbox(video::IVideoDriver* driver, Hud& hud,
34                 std::vector<aabb3f>& hilightboxes, bool show_hud)
35 {
36         if (!show_hud)
37                 return;
38
39         video::SMaterial oldmaterial = driver->getMaterial2D();
40         video::SMaterial m;
41         m.Thickness = 3;
42         m.Lighting = false;
43         driver->setMaterial(m);
44         hud.drawSelectionBoxes(hilightboxes);
45         driver->setMaterial(oldmaterial);
46 }
47
48 void draw_anaglyph_3d_mode(Camera& camera, bool show_hud, Hud& hud,
49                 std::vector<aabb3f> hilightboxes, video::IVideoDriver* driver,
50                 scene::ISceneManager* smgr, bool draw_wield_tool, Client& client,
51                 gui::IGUIEnvironment* guienv )
52 {
53
54         /* preserve old setup*/
55         irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
56         irr::core::vector3df oldTarget   = camera.getCameraNode()->getTarget();
57
58         irr::core::matrix4 startMatrix =
59                         camera.getCameraNode()->getAbsoluteTransformation();
60         irr::core::vector3df focusPoint = (camera.getCameraNode()->getTarget()
61                         - camera.getCameraNode()->getAbsolutePosition()).setLength(1)
62                         + camera.getCameraNode()->getAbsolutePosition();
63
64
65         //Left eye...
66         irr::core::vector3df leftEye;
67         irr::core::matrix4 leftMove;
68         leftMove.setTranslation(
69                         irr::core::vector3df(-g_settings->getFloat("3d_paralax_strength"),
70                                         0.0f, 0.0f));
71         leftEye = (startMatrix * leftMove).getTranslation();
72
73         //clear the depth buffer, and color
74         driver->beginScene( true, true, irr::video::SColor(0, 200, 200, 255));
75         driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_RED;
76         driver->getOverrideMaterial().EnableFlags = irr::video::EMF_COLOR_MASK;
77         driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX
78                         + irr::scene::ESNRP_SOLID + irr::scene::ESNRP_TRANSPARENT
79                         + irr::scene::ESNRP_TRANSPARENT_EFFECT + irr::scene::ESNRP_SHADOW;
80         camera.getCameraNode()->setPosition(leftEye);
81         camera.getCameraNode()->setTarget(focusPoint);
82         smgr->drawAll();
83         driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
84         if (show_hud)
85         {
86                 draw_selectionbox(driver, hud, hilightboxes, show_hud);
87
88                 if (draw_wield_tool)
89                         camera.drawWieldedTool(&leftMove);
90         }
91
92         guienv->drawAll();
93
94         //Right eye...
95         irr::core::vector3df rightEye;
96         irr::core::matrix4 rightMove;
97         rightMove.setTranslation(
98                         irr::core::vector3df(g_settings->getFloat("3d_paralax_strength"),
99                                         0.0f, 0.0f));
100         rightEye = (startMatrix * rightMove).getTranslation();
101
102         //clear the depth buffer
103         driver->clearZBuffer();
104         driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_GREEN
105                         + irr::video::ECP_BLUE;
106         driver->getOverrideMaterial().EnableFlags = irr::video::EMF_COLOR_MASK;
107         driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX
108                         + irr::scene::ESNRP_SOLID + irr::scene::ESNRP_TRANSPARENT
109                         + irr::scene::ESNRP_TRANSPARENT_EFFECT + irr::scene::ESNRP_SHADOW;
110         camera.getCameraNode()->setPosition(rightEye);
111         camera.getCameraNode()->setTarget(focusPoint);
112         smgr->drawAll();
113         driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
114         if (show_hud)
115         {
116                 draw_selectionbox(driver, hud, hilightboxes, show_hud);
117
118                 if (draw_wield_tool)
119                         camera.drawWieldedTool(&rightMove);
120         }
121
122         guienv->drawAll();
123
124         driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_ALL;
125         driver->getOverrideMaterial().EnableFlags = 0;
126         driver->getOverrideMaterial().EnablePasses = 0;
127         camera.getCameraNode()->setPosition(oldPosition);
128         camera.getCameraNode()->setTarget(oldTarget);
129 }
130
131 void init_texture(video::IVideoDriver* driver, const v2u32& screensize,
132                 video::ITexture** texture)
133 {
134         static v2u32 last_screensize = v2u32(0,0);
135
136         if (( *texture == NULL ) || (screensize != last_screensize))
137         {
138                 if (*texture != NULL)
139                 {
140                         driver->removeTexture(*texture);
141                 }
142                 *texture = driver->addRenderTargetTexture(
143                                 core::dimension2d<u32>(screensize.X, screensize.Y));
144                 last_screensize = screensize;
145         }
146 }
147
148 video::ITexture* draw_image(const v2u32& screensize,
149                 paralax_sign psign, const irr::core::matrix4& startMatrix,
150                 const irr::core::vector3df& focusPoint, bool show_hud,
151                 video::IVideoDriver* driver, Camera& camera, scene::ISceneManager* smgr,
152                 Hud& hud, std::vector<aabb3f>& hilightboxes,
153                 bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv,
154                 video::SColor skycolor )
155 {
156         static video::ITexture* images[2] = { NULL, NULL };
157
158         video::ITexture* image = NULL;
159
160         if (psign == RIGHT)
161         {
162                 init_texture(driver, screensize, &images[1]);
163                 image = images[1];
164         } else {
165                 init_texture(driver, screensize, &images[0]);
166                 image = images[0];
167         }
168
169         driver->setRenderTarget(image, true, true,
170                         irr::video::SColor(255,
171                                         skycolor.getRed(), skycolor.getGreen(), skycolor.getBlue()));
172
173         irr::core::vector3df eye_pos;
174         irr::core::matrix4 movement;
175         movement.setTranslation(
176                         irr::core::vector3df((int) psign *
177                                         g_settings->getFloat("3d_paralax_strength"), 0.0f, 0.0f));
178         eye_pos = (startMatrix * movement).getTranslation();
179
180         //clear the depth buffer
181         driver->clearZBuffer();
182         camera.getCameraNode()->setPosition(eye_pos);
183         camera.getCameraNode()->setTarget(focusPoint);
184         smgr->drawAll();
185
186         driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
187
188         if (show_hud)
189         {
190                 draw_selectionbox(driver, hud, hilightboxes, show_hud);
191
192                 if (draw_wield_tool)
193                         camera.drawWieldedTool(&movement);
194         }
195
196         guienv->drawAll();
197
198         /* switch back to real renderer */
199         driver->setRenderTarget(0, true, true,
200                         irr::video::SColor(0,
201                                         skycolor.getRed(), skycolor.getGreen(), skycolor.getBlue()));
202
203         return image;
204 }
205
206 video::ITexture*  draw_hud(video::IVideoDriver* driver, const v2u32& screensize,
207                 bool show_hud, Hud& hud, Client& client, bool draw_crosshair,
208                 video::SColor skycolor, gui::IGUIEnvironment* guienv, Camera& camera )
209 {
210         static video::ITexture* image = NULL;
211         init_texture(driver, screensize, &image);
212         driver->setRenderTarget(image, true, true,
213                         irr::video::SColor(255,0,0,0));
214
215         if (show_hud)
216         {
217                 if (draw_crosshair)
218                         hud.drawCrosshair();
219                 hud.drawHotbar(client.getPlayerItem());
220                 hud.drawLuaElements(camera.getOffset());
221
222                 guienv->drawAll();
223         }
224
225         driver->setRenderTarget(0, true, true,
226                         irr::video::SColor(0,
227                                         skycolor.getRed(), skycolor.getGreen(), skycolor.getBlue()));
228
229         return image;
230 }
231
232 void draw_interlaced_3d_mode(Camera& camera, bool show_hud,
233                 Hud& hud, std::vector<aabb3f> hilightboxes, video::IVideoDriver* driver,
234                 scene::ISceneManager* smgr, const v2u32& screensize,
235                 bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv,
236                 video::SColor skycolor )
237 {
238         /* save current info */
239         irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
240         irr::core::vector3df oldTarget = camera.getCameraNode()->getTarget();
241         irr::core::matrix4 startMatrix =
242                         camera.getCameraNode()->getAbsoluteTransformation();
243         irr::core::vector3df focusPoint = (camera.getCameraNode()->getTarget()
244                         - camera.getCameraNode()->getAbsolutePosition()).setLength(1)
245                         + camera.getCameraNode()->getAbsolutePosition();
246
247         /* create left view */
248         video::ITexture* left_image = draw_image(screensize, LEFT, startMatrix,
249                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
250                         draw_wield_tool, client, guienv, skycolor);
251
252         //Right eye...
253         irr::core::vector3df rightEye;
254         irr::core::matrix4 rightMove;
255         rightMove.setTranslation(
256                         irr::core::vector3df(g_settings->getFloat("3d_paralax_strength"),
257                                         0.0f, 0.0f));
258         rightEye = (startMatrix * rightMove).getTranslation();
259
260         //clear the depth buffer
261         driver->clearZBuffer();
262         camera.getCameraNode()->setPosition(rightEye);
263         camera.getCameraNode()->setTarget(focusPoint);
264         smgr->drawAll();
265
266         driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
267
268         if (show_hud)
269         {
270                 draw_selectionbox(driver, hud, hilightboxes, show_hud);
271
272                 if(draw_wield_tool)
273                         camera.drawWieldedTool(&rightMove);
274         }
275         guienv->drawAll();
276
277         for (unsigned int i = 0; i < screensize.Y; i+=2 ) {
278 #if (IRRLICHT_VERSION_MAJOR >= 1) && (IRRLICHT_VERSION_MINOR >= 8)
279                 driver->draw2DImage(left_image, irr::core::position2d<s32>(0, i),
280 #else
281                 driver->draw2DImage(left_image, irr::core::position2d<s32>(0, screensize.Y-i),
282 #endif
283                                 irr::core::rect<s32>(0, i,screensize.X, i+1), 0,
284                                 irr::video::SColor(255, 255, 255, 255),
285                                 false);
286         }
287
288         /* cleanup */
289         camera.getCameraNode()->setPosition(oldPosition);
290         camera.getCameraNode()->setTarget(oldTarget);
291 }
292
293 void draw_sidebyside_3d_mode(Camera& camera, bool show_hud,
294                 Hud& hud, std::vector<aabb3f> hilightboxes, video::IVideoDriver* driver,
295                 scene::ISceneManager* smgr, const v2u32& screensize,
296                 bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv,
297                 video::SColor skycolor )
298 {
299         /* save current info */
300         irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
301         irr::core::vector3df oldTarget = camera.getCameraNode()->getTarget();
302         irr::core::matrix4 startMatrix =
303                         camera.getCameraNode()->getAbsoluteTransformation();
304         irr::core::vector3df focusPoint = (camera.getCameraNode()->getTarget()
305                         - camera.getCameraNode()->getAbsolutePosition()).setLength(1)
306                         + camera.getCameraNode()->getAbsolutePosition();
307
308         /* create left view */
309         video::ITexture* left_image = draw_image(screensize, LEFT, startMatrix,
310                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
311                         draw_wield_tool, client, guienv, skycolor);
312
313         /* create right view */
314         video::ITexture* right_image = draw_image(screensize, RIGHT, startMatrix,
315                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
316                         draw_wield_tool, client, guienv, skycolor);
317
318         /* create hud overlay */
319         video::ITexture* hudtexture = draw_hud(driver, screensize, show_hud, hud, client,
320                         false, skycolor, guienv, camera );
321         driver->makeColorKeyTexture(hudtexture, irr::video::SColor(255, 0, 0, 0));
322         //makeColorKeyTexture mirrors texture so we do it twice to get it right again
323         driver->makeColorKeyTexture(hudtexture, irr::video::SColor(255, 0, 0, 0));
324
325         driver->draw2DImage(left_image,
326                         irr::core::rect<s32>(0, 0, screensize.X/2, screensize.Y),
327                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
328
329         driver->draw2DImage(hudtexture,
330                         irr::core::rect<s32>(0, 0, screensize.X/2, screensize.Y),
331                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, true);
332
333         driver->draw2DImage(right_image,
334                         irr::core::rect<s32>(screensize.X/2, 0, screensize.X, screensize.Y),
335                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
336
337         driver->draw2DImage(hudtexture,
338                         irr::core::rect<s32>(screensize.X/2, 0, screensize.X, screensize.Y),
339                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, true);
340
341         left_image = NULL;
342         right_image = NULL;
343
344         /* cleanup */
345         camera.getCameraNode()->setPosition(oldPosition);
346         camera.getCameraNode()->setTarget(oldTarget);
347 }
348
349 void draw_top_bottom_3d_mode(Camera& camera, bool show_hud,
350                 Hud& hud, std::vector<aabb3f> hilightboxes, video::IVideoDriver* driver,
351                 scene::ISceneManager* smgr, const v2u32& screensize,
352                 bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv,
353                 video::SColor skycolor )
354 {
355         /* save current info */
356         irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
357         irr::core::vector3df oldTarget = camera.getCameraNode()->getTarget();
358         irr::core::matrix4 startMatrix =
359                         camera.getCameraNode()->getAbsoluteTransformation();
360         irr::core::vector3df focusPoint = (camera.getCameraNode()->getTarget()
361                         - camera.getCameraNode()->getAbsolutePosition()).setLength(1)
362                         + camera.getCameraNode()->getAbsolutePosition();
363
364         /* create left view */
365         video::ITexture* left_image = draw_image(screensize, LEFT, startMatrix,
366                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
367                         draw_wield_tool, client, guienv, skycolor);
368
369         /* create right view */
370         video::ITexture* right_image = draw_image(screensize, RIGHT, startMatrix,
371                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
372                         draw_wield_tool, client, guienv, skycolor);
373
374         /* create hud overlay */
375         video::ITexture* hudtexture = draw_hud(driver, screensize, show_hud, hud, client,
376                         false, skycolor, guienv, camera );
377         driver->makeColorKeyTexture(hudtexture, irr::video::SColor(255, 0, 0, 0));
378         //makeColorKeyTexture mirrors texture so we do it twice to get it right again
379         driver->makeColorKeyTexture(hudtexture, irr::video::SColor(255, 0, 0, 0));
380
381         driver->draw2DImage(left_image,
382                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y/2),
383                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
384
385         driver->draw2DImage(hudtexture,
386                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y/2),
387                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, true);
388
389         driver->draw2DImage(right_image,
390                         irr::core::rect<s32>(0, screensize.Y/2, screensize.X, screensize.Y),
391                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
392
393         driver->draw2DImage(hudtexture,
394                         irr::core::rect<s32>(0, screensize.Y/2, screensize.X, screensize.Y),
395                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, true);
396
397         left_image = NULL;
398         right_image = NULL;
399
400         /* cleanup */
401         camera.getCameraNode()->setPosition(oldPosition);
402         camera.getCameraNode()->setTarget(oldTarget);
403 }
404
405 void draw_plain(Camera& camera, bool show_hud, Hud& hud,
406                 std::vector<aabb3f> hilightboxes, video::IVideoDriver* driver,
407                 bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv)
408 {
409         driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
410
411         draw_selectionbox(driver, hud, hilightboxes, show_hud);
412
413         if(draw_wield_tool)
414                 camera.drawWieldedTool();
415 }
416
417 void draw_scene(video::IVideoDriver* driver, scene::ISceneManager* smgr,
418                 Camera& camera, Client& client, LocalPlayer* player, Hud& hud,
419                 gui::IGUIEnvironment* guienv, std::vector<aabb3f> hilightboxes,
420                 const v2u32& screensize, video::SColor skycolor, bool show_hud)
421 {
422         //TODO check if usefull
423         u32 scenetime = 0;
424         {
425                 TimeTaker timer("smgr");
426
427                 bool draw_wield_tool = (show_hud &&
428                                 (player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE) &&
429                                 camera.getCameraMode() < CAMERA_MODE_THIRD );
430
431                 bool draw_crosshair = ((player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) &&
432                                 (camera.getCameraMode() != CAMERA_MODE_THIRD_FRONT));
433
434 #ifdef HAVE_TOUCHSCREENGUI
435                 try {
436                         draw_crosshair = !g_settings->getBool("touchtarget");
437                 }
438                 catch(SettingNotFoundException) {}
439 #endif
440
441                 std::string draw_mode = g_settings->get("3d_mode");
442
443                 smgr->drawAll();
444
445                 if (draw_mode == "anaglyph")
446                 {
447                         draw_anaglyph_3d_mode(camera, show_hud, hud, hilightboxes, driver,
448                                         smgr, draw_wield_tool, client, guienv);
449                         draw_crosshair = false;
450                 }
451                 else if (draw_mode == "interlaced")
452                 {
453                         draw_interlaced_3d_mode(camera, show_hud, hud, hilightboxes, driver,
454                                         smgr, screensize, draw_wield_tool, client, guienv, skycolor);
455                         draw_crosshair = false;
456                 }
457                 else if (draw_mode == "sidebyside")
458                 {
459                         draw_sidebyside_3d_mode(camera, show_hud, hud, hilightboxes, driver,
460                                         smgr, screensize, draw_wield_tool, client, guienv, skycolor);
461                         show_hud = false;
462                 }
463                 else if (draw_mode == "topbottom")
464                 {
465                         draw_top_bottom_3d_mode(camera, show_hud, hud, hilightboxes, driver,
466                                         smgr, screensize, draw_wield_tool, client, guienv, skycolor);
467                         show_hud = false;
468                 }
469                 else {
470                         draw_plain(camera, show_hud, hud, hilightboxes, driver,
471                                         draw_wield_tool, client, guienv);
472                 }
473
474                 /*
475                         Post effects
476                 */
477                 {
478                         client.getEnv().getClientMap().renderPostFx(camera.getCameraMode());
479                 }
480
481                 //TODO how to make those 3d too
482                 if (show_hud)
483                 {
484                         if (draw_crosshair)
485                                 hud.drawCrosshair();
486                         hud.drawHotbar(client.getPlayerItem());
487                         hud.drawLuaElements(camera.getOffset());
488                 }
489
490                 guienv->drawAll();
491
492                 scenetime = timer.stop(true);
493         }
494
495 }
496
497 /*
498         Draws a screen with a single text on it.
499         Text will be removed when the screen is drawn the next time.
500         Additionally, a progressbar can be drawn when percent is set between 0 and 100.
501 */
502 /*gui::IGUIStaticText **/
503 void draw_load_screen(const std::wstring &text, IrrlichtDevice* device,
504                 gui::IGUIEnvironment* guienv, gui::IGUIFont* font, float dtime,
505                 int percent, bool clouds )
506 {
507         video::IVideoDriver* driver = device->getVideoDriver();
508         v2u32 screensize = driver->getScreenSize();
509         const wchar_t *loadingtext = text.c_str();
510         core::vector2d<u32> textsize_u = font->getDimension(loadingtext);
511         core::vector2d<s32> textsize(textsize_u.X,textsize_u.Y);
512         core::vector2d<s32> center(screensize.X/2, screensize.Y/2);
513         core::rect<s32> textrect(center - textsize/2, center + textsize/2);
514
515         gui::IGUIStaticText *guitext = guienv->addStaticText(
516                         loadingtext, textrect, false, false);
517         guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
518
519         bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds");
520         if (cloud_menu_background)
521         {
522                 g_menuclouds->step(dtime*3);
523                 g_menuclouds->render();
524                 driver->beginScene(true, true, video::SColor(255,140,186,250));
525                 g_menucloudsmgr->drawAll();
526         }
527         else
528                 driver->beginScene(true, true, video::SColor(255,0,0,0));
529
530         if (percent >= 0 && percent <= 100) // draw progress bar
531         {
532                 core::vector2d<s32> barsize(256,32);
533                 core::rect<s32> barrect(center-barsize/2, center+barsize/2);
534                 driver->draw2DRectangle(video::SColor(255,255,255,255),barrect, NULL); // border
535                 driver->draw2DRectangle(video::SColor(255,64,64,64), core::rect<s32> (
536                                 barrect.UpperLeftCorner+1,
537                                 barrect.LowerRightCorner-1), NULL); // black inside the bar
538                 driver->draw2DRectangle(video::SColor(255,128,128,128), core::rect<s32> (
539                                 barrect.UpperLeftCorner+1,
540                                 core::vector2d<s32>(
541                                         barrect.LowerRightCorner.X-(barsize.X-1)+percent*(barsize.X-2)/100,
542                                         barrect.LowerRightCorner.Y-1)), NULL); // the actual progress
543         }
544         guienv->drawAll();
545         driver->endScene();
546
547         guitext->remove();
548
549         //return guitext;
550 }