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