08b08990830adebd0f05edbed4550517778b01e9
[oweals/minetest.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         if (*texture != NULL)
135         {
136                 driver->removeTexture(*texture);
137         }
138         *texture = driver->addRenderTargetTexture(
139                         core::dimension2d<u32>(screensize.X, screensize.Y));
140 }
141
142 video::ITexture* draw_image(const v2u32& screensize,
143                 paralax_sign psign, const irr::core::matrix4& startMatrix,
144                 const irr::core::vector3df& focusPoint, bool show_hud,
145                 video::IVideoDriver* driver, Camera& camera, scene::ISceneManager* smgr,
146                 Hud& hud, std::vector<aabb3f>& hilightboxes,
147                 bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv,
148                 video::SColor skycolor )
149 {
150         static video::ITexture* images[2] = { NULL, NULL };
151         static v2u32 last_screensize = v2u32(0,0);
152
153         video::ITexture* image = NULL;
154
155         if (screensize != last_screensize) {
156                 init_texture(driver, screensize, &images[1]);
157                 image = images[1];
158                 init_texture(driver, screensize, &images[0]);
159                 image = images[0];
160                 last_screensize = screensize;
161         }
162
163         driver->setRenderTarget(image, true, true,
164                         irr::video::SColor(255,
165                                         skycolor.getRed(), skycolor.getGreen(), skycolor.getBlue()));
166
167         irr::core::vector3df eye_pos;
168         irr::core::matrix4 movement;
169         movement.setTranslation(
170                         irr::core::vector3df((int) psign *
171                                         g_settings->getFloat("3d_paralax_strength"), 0.0f, 0.0f));
172         eye_pos = (startMatrix * movement).getTranslation();
173
174         //clear the depth buffer
175         driver->clearZBuffer();
176         camera.getCameraNode()->setPosition(eye_pos);
177         camera.getCameraNode()->setTarget(focusPoint);
178         smgr->drawAll();
179
180         driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
181
182         if (show_hud)
183         {
184                 draw_selectionbox(driver, hud, hilightboxes, show_hud);
185
186                 if (draw_wield_tool)
187                         camera.drawWieldedTool(&movement);
188         }
189
190         guienv->drawAll();
191
192         /* switch back to real renderer */
193         driver->setRenderTarget(0, true, true,
194                         irr::video::SColor(0,
195                                         skycolor.getRed(), skycolor.getGreen(), skycolor.getBlue()));
196
197         return image;
198 }
199
200 video::ITexture*  draw_hud(video::IVideoDriver* driver, const v2u32& screensize,
201                 bool show_hud, Hud& hud, Client& client, bool draw_crosshair,
202                 video::SColor skycolor, gui::IGUIEnvironment* guienv, Camera& camera )
203 {
204         static video::ITexture* image = NULL;
205         init_texture(driver, screensize, &image);
206         driver->setRenderTarget(image, true, true,
207                         irr::video::SColor(255,0,0,0));
208
209         if (show_hud)
210         {
211                 if (draw_crosshair)
212                         hud.drawCrosshair();
213                 hud.drawHotbar(client.getPlayerItem());
214                 hud.drawLuaElements(camera.getOffset());
215
216                 guienv->drawAll();
217         }
218
219         driver->setRenderTarget(0, true, true,
220                         irr::video::SColor(0,
221                                         skycolor.getRed(), skycolor.getGreen(), skycolor.getBlue()));
222
223         return image;
224 }
225
226 void draw_interlaced_3d_mode(Camera& camera, bool show_hud,
227                 Hud& hud, std::vector<aabb3f> hilightboxes, video::IVideoDriver* driver,
228                 scene::ISceneManager* smgr, const v2u32& screensize,
229                 bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv,
230                 video::SColor skycolor )
231 {
232         /* save current info */
233         irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
234         irr::core::vector3df oldTarget = camera.getCameraNode()->getTarget();
235         irr::core::matrix4 startMatrix =
236                         camera.getCameraNode()->getAbsoluteTransformation();
237         irr::core::vector3df focusPoint = (camera.getCameraNode()->getTarget()
238                         - camera.getCameraNode()->getAbsolutePosition()).setLength(1)
239                         + camera.getCameraNode()->getAbsolutePosition();
240
241         /* create left view */
242         video::ITexture* left_image = draw_image(screensize, LEFT, startMatrix,
243                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
244                         draw_wield_tool, client, guienv, skycolor);
245
246         //Right eye...
247         irr::core::vector3df rightEye;
248         irr::core::matrix4 rightMove;
249         rightMove.setTranslation(
250                         irr::core::vector3df(g_settings->getFloat("3d_paralax_strength"),
251                                         0.0f, 0.0f));
252         rightEye = (startMatrix * rightMove).getTranslation();
253
254         //clear the depth buffer
255         driver->clearZBuffer();
256         camera.getCameraNode()->setPosition(rightEye);
257         camera.getCameraNode()->setTarget(focusPoint);
258         smgr->drawAll();
259
260         driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
261
262         if (show_hud)
263         {
264                 draw_selectionbox(driver, hud, hilightboxes, show_hud);
265
266                 if(draw_wield_tool)
267                         camera.drawWieldedTool(&rightMove);
268         }
269         guienv->drawAll();
270
271         for (unsigned int i = 0; i < screensize.Y; i+=2 ) {
272 #if (IRRLICHT_VERSION_MAJOR >= 1) && (IRRLICHT_VERSION_MINOR >= 8)
273                 driver->draw2DImage(left_image, irr::core::position2d<s32>(0, i),
274 #else
275                 driver->draw2DImage(left_image, irr::core::position2d<s32>(0, screensize.Y-i),
276 #endif
277                                 irr::core::rect<s32>(0, i,screensize.X, i+1), 0,
278                                 irr::video::SColor(255, 255, 255, 255),
279                                 false);
280         }
281
282         /* cleanup */
283         camera.getCameraNode()->setPosition(oldPosition);
284         camera.getCameraNode()->setTarget(oldTarget);
285 }
286
287 void draw_sidebyside_3d_mode(Camera& camera, bool show_hud,
288                 Hud& hud, std::vector<aabb3f> hilightboxes, video::IVideoDriver* driver,
289                 scene::ISceneManager* smgr, const v2u32& screensize,
290                 bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv,
291                 video::SColor skycolor )
292 {
293         /* save current info */
294         irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
295         irr::core::vector3df oldTarget = camera.getCameraNode()->getTarget();
296         irr::core::matrix4 startMatrix =
297                         camera.getCameraNode()->getAbsoluteTransformation();
298         irr::core::vector3df focusPoint = (camera.getCameraNode()->getTarget()
299                         - camera.getCameraNode()->getAbsolutePosition()).setLength(1)
300                         + camera.getCameraNode()->getAbsolutePosition();
301
302         /* create left view */
303         video::ITexture* left_image = draw_image(screensize, LEFT, startMatrix,
304                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
305                         draw_wield_tool, client, guienv, skycolor);
306
307         /* create right view */
308         video::ITexture* right_image = draw_image(screensize, RIGHT, startMatrix,
309                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
310                         draw_wield_tool, client, guienv, skycolor);
311
312         /* create hud overlay */
313         video::ITexture* hudtexture = draw_hud(driver, screensize, show_hud, hud, client,
314                         false, skycolor, guienv, camera );
315         driver->makeColorKeyTexture(hudtexture, irr::video::SColor(255, 0, 0, 0));
316         //makeColorKeyTexture mirrors texture so we do it twice to get it right again
317         driver->makeColorKeyTexture(hudtexture, irr::video::SColor(255, 0, 0, 0));
318
319         driver->draw2DImage(left_image,
320                         irr::core::rect<s32>(0, 0, screensize.X/2, screensize.Y),
321                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
322
323         driver->draw2DImage(hudtexture,
324                         irr::core::rect<s32>(0, 0, screensize.X/2, screensize.Y),
325                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, true);
326
327         driver->draw2DImage(right_image,
328                         irr::core::rect<s32>(screensize.X/2, 0, screensize.X, screensize.Y),
329                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
330
331         driver->draw2DImage(hudtexture,
332                         irr::core::rect<s32>(screensize.X/2, 0, screensize.X, screensize.Y),
333                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, true);
334
335         left_image = NULL;
336         right_image = NULL;
337
338         /* cleanup */
339         camera.getCameraNode()->setPosition(oldPosition);
340         camera.getCameraNode()->setTarget(oldTarget);
341 }
342
343 void draw_top_bottom_3d_mode(Camera& camera, bool show_hud,
344                 Hud& hud, std::vector<aabb3f> hilightboxes, video::IVideoDriver* driver,
345                 scene::ISceneManager* smgr, const v2u32& screensize,
346                 bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv,
347                 video::SColor skycolor )
348 {
349         /* save current info */
350         irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
351         irr::core::vector3df oldTarget = camera.getCameraNode()->getTarget();
352         irr::core::matrix4 startMatrix =
353                         camera.getCameraNode()->getAbsoluteTransformation();
354         irr::core::vector3df focusPoint = (camera.getCameraNode()->getTarget()
355                         - camera.getCameraNode()->getAbsolutePosition()).setLength(1)
356                         + camera.getCameraNode()->getAbsolutePosition();
357
358         /* create left view */
359         video::ITexture* left_image = draw_image(screensize, LEFT, startMatrix,
360                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
361                         draw_wield_tool, client, guienv, skycolor);
362
363         /* create right view */
364         video::ITexture* right_image = draw_image(screensize, RIGHT, startMatrix,
365                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
366                         draw_wield_tool, client, guienv, skycolor);
367
368         /* create hud overlay */
369         video::ITexture* hudtexture = draw_hud(driver, screensize, show_hud, hud, client,
370                         false, skycolor, guienv, camera );
371         driver->makeColorKeyTexture(hudtexture, irr::video::SColor(255, 0, 0, 0));
372         //makeColorKeyTexture mirrors texture so we do it twice to get it right again
373         driver->makeColorKeyTexture(hudtexture, irr::video::SColor(255, 0, 0, 0));
374
375         driver->draw2DImage(left_image,
376                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y/2),
377                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
378
379         driver->draw2DImage(hudtexture,
380                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y/2),
381                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, true);
382
383         driver->draw2DImage(right_image,
384                         irr::core::rect<s32>(0, screensize.Y/2, screensize.X, screensize.Y),
385                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
386
387         driver->draw2DImage(hudtexture,
388                         irr::core::rect<s32>(0, screensize.Y/2, screensize.X, screensize.Y),
389                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, true);
390
391         left_image = NULL;
392         right_image = NULL;
393
394         /* cleanup */
395         camera.getCameraNode()->setPosition(oldPosition);
396         camera.getCameraNode()->setTarget(oldTarget);
397 }
398
399 void draw_plain(Camera& camera, bool show_hud, Hud& hud,
400                 std::vector<aabb3f> hilightboxes, video::IVideoDriver* driver,
401                 bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv)
402 {
403         driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
404
405         draw_selectionbox(driver, hud, hilightboxes, show_hud);
406
407         if(draw_wield_tool)
408                 camera.drawWieldedTool();
409 }
410
411 void draw_scene(video::IVideoDriver* driver, scene::ISceneManager* smgr,
412                 Camera& camera, Client& client, LocalPlayer* player, Hud& hud,
413                 gui::IGUIEnvironment* guienv, std::vector<aabb3f> hilightboxes,
414                 const v2u32& screensize, video::SColor skycolor, bool show_hud)
415 {
416         //TODO check if usefull
417         u32 scenetime = 0;
418         {
419                 TimeTaker timer("smgr");
420
421                 bool draw_wield_tool = (show_hud &&
422                                 (player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE) &&
423                                 camera.getCameraMode() < CAMERA_MODE_THIRD );
424
425                 bool draw_crosshair = ((player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) &&
426                                 (camera.getCameraMode() != CAMERA_MODE_THIRD_FRONT));
427
428 #ifdef HAVE_TOUCHSCREENGUI
429                 try {
430                         draw_crosshair = !g_settings->getBool("touchtarget");
431                 }
432                 catch(SettingNotFoundException) {}
433 #endif
434
435                 std::string draw_mode = g_settings->get("3d_mode");
436
437                 smgr->drawAll();
438
439                 if (draw_mode == "anaglyph")
440                 {
441                         draw_anaglyph_3d_mode(camera, show_hud, hud, hilightboxes, driver,
442                                         smgr, draw_wield_tool, client, guienv);
443                         draw_crosshair = false;
444                 }
445                 else if (draw_mode == "interlaced")
446                 {
447                         draw_interlaced_3d_mode(camera, show_hud, hud, hilightboxes, driver,
448                                         smgr, screensize, draw_wield_tool, client, guienv, skycolor);
449                         draw_crosshair = false;
450                 }
451                 else if (draw_mode == "sidebyside")
452                 {
453                         draw_sidebyside_3d_mode(camera, show_hud, hud, hilightboxes, driver,
454                                         smgr, screensize, draw_wield_tool, client, guienv, skycolor);
455                         show_hud = false;
456                 }
457                 else if (draw_mode == "topbottom")
458                 {
459                         draw_top_bottom_3d_mode(camera, show_hud, hud, hilightboxes, driver,
460                                         smgr, screensize, draw_wield_tool, client, guienv, skycolor);
461                         show_hud = false;
462                 }
463                 else {
464                         draw_plain(camera, show_hud, hud, hilightboxes, driver,
465                                         draw_wield_tool, client, guienv);
466                 }
467
468                 /*
469                         Post effects
470                 */
471                 {
472                         client.getEnv().getClientMap().renderPostFx(camera.getCameraMode());
473                 }
474
475                 //TODO how to make those 3d too
476                 if (show_hud)
477                 {
478                         if (draw_crosshair)
479                                 hud.drawCrosshair();
480                         hud.drawHotbar(client.getPlayerItem());
481                         hud.drawLuaElements(camera.getOffset());
482                 }
483
484                 guienv->drawAll();
485
486                 scenetime = timer.stop(true);
487         }
488
489 }
490
491 /*
492         Draws a screen with a single text on it.
493         Text will be removed when the screen is drawn the next time.
494         Additionally, a progressbar can be drawn when percent is set between 0 and 100.
495 */
496 /*gui::IGUIStaticText **/
497 void draw_load_screen(const std::wstring &text, IrrlichtDevice* device,
498                 gui::IGUIEnvironment* guienv, gui::IGUIFont* font, float dtime,
499                 int percent, bool clouds )
500 {
501         video::IVideoDriver* driver = device->getVideoDriver();
502         v2u32 screensize = driver->getScreenSize();
503         const wchar_t *loadingtext = text.c_str();
504         core::vector2d<u32> textsize_u = font->getDimension(loadingtext);
505         core::vector2d<s32> textsize(textsize_u.X,textsize_u.Y);
506         core::vector2d<s32> center(screensize.X/2, screensize.Y/2);
507         core::rect<s32> textrect(center - textsize/2, center + textsize/2);
508
509         gui::IGUIStaticText *guitext = guienv->addStaticText(
510                         loadingtext, textrect, false, false);
511         guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
512
513         bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds");
514         if (cloud_menu_background)
515         {
516                 g_menuclouds->step(dtime*3);
517                 g_menuclouds->render();
518                 driver->beginScene(true, true, video::SColor(255,140,186,250));
519                 g_menucloudsmgr->drawAll();
520         }
521         else
522                 driver->beginScene(true, true, video::SColor(255,0,0,0));
523
524         if (percent >= 0 && percent <= 100) // draw progress bar
525         {
526                 core::vector2d<s32> barsize(256,32);
527                 core::rect<s32> barrect(center-barsize/2, center+barsize/2);
528                 driver->draw2DRectangle(video::SColor(255,255,255,255),barrect, NULL); // border
529                 driver->draw2DRectangle(video::SColor(255,64,64,64), core::rect<s32> (
530                                 barrect.UpperLeftCorner+1,
531                                 barrect.LowerRightCorner-1), NULL); // black inside the bar
532                 driver->draw2DRectangle(video::SColor(255,128,128,128), core::rect<s32> (
533                                 barrect.UpperLeftCorner+1,
534                                 core::vector2d<s32>(
535                                         barrect.LowerRightCorner.X-(barsize.X-1)+percent*(barsize.X-2)/100,
536                                         barrect.LowerRightCorner.Y-1)), NULL); // the actual progress
537         }
538         guienv->drawAll();
539         driver->endScene();
540
541         guitext->remove();
542
543         //return guitext;
544 }