]> git.lizzy.rs Git - minetest.git/blob - src/drawscene.cpp
Add formspec api versioning
[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         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                 driver->draw2DImage(left_image, irr::core::position2d<s32>(0, screensize.Y-i),
279                                 irr::core::rect<s32>(0, i,screensize.X, i+1), 0,
280                                 irr::video::SColor(255, 255, 255, 255),
281                                 false);
282         }
283
284         /* cleanup */
285         camera.getCameraNode()->setPosition(oldPosition);
286         camera.getCameraNode()->setTarget(oldTarget);
287 }
288
289 void draw_sidebyside_3d_mode(Camera& camera, bool show_hud,
290                 Hud& hud, std::vector<aabb3f> hilightboxes, video::IVideoDriver* driver,
291                 scene::ISceneManager* smgr, const v2u32& screensize,
292                 bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv,
293                 video::SColor skycolor )
294 {
295         /* save current info */
296         irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
297         irr::core::vector3df oldTarget = camera.getCameraNode()->getTarget();
298         irr::core::matrix4 startMatrix =
299                         camera.getCameraNode()->getAbsoluteTransformation();
300         irr::core::vector3df focusPoint = (camera.getCameraNode()->getTarget()
301                         - camera.getCameraNode()->getAbsolutePosition()).setLength(1)
302                         + camera.getCameraNode()->getAbsolutePosition();
303
304         /* create left view */
305         video::ITexture* left_image = draw_image(screensize, LEFT, startMatrix,
306                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
307                         draw_wield_tool, client, guienv, skycolor);
308
309         /* create right view */
310         video::ITexture* right_image = draw_image(screensize, RIGHT, startMatrix,
311                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
312                         draw_wield_tool, client, guienv, skycolor);
313
314         /* create hud overlay */
315         video::ITexture* hudtexture = draw_hud(driver, screensize, show_hud, hud, client,
316                         false, skycolor, guienv, camera );
317         driver->makeColorKeyTexture(hudtexture, irr::video::SColor(255, 0, 0, 0));
318         //makeColorKeyTexture mirrors texture so we do it twice to get it right again
319         driver->makeColorKeyTexture(hudtexture, irr::video::SColor(255, 0, 0, 0));
320
321         driver->draw2DImage(left_image,
322                         irr::core::rect<s32>(0, 0, screensize.X/2, screensize.Y),
323                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
324
325         driver->draw2DImage(hudtexture,
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, true);
328
329         driver->draw2DImage(right_image,
330                         irr::core::rect<s32>(screensize.X/2, 0, screensize.X, screensize.Y),
331                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
332
333         driver->draw2DImage(hudtexture,
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, true);
336
337         left_image = NULL;
338         right_image = NULL;
339
340         /* cleanup */
341         camera.getCameraNode()->setPosition(oldPosition);
342         camera.getCameraNode()->setTarget(oldTarget);
343 }
344
345 void draw_top_bottom_3d_mode(Camera& camera, bool show_hud,
346                 Hud& hud, std::vector<aabb3f> hilightboxes, video::IVideoDriver* driver,
347                 scene::ISceneManager* smgr, const v2u32& screensize,
348                 bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv,
349                 video::SColor skycolor )
350 {
351         /* save current info */
352         irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
353         irr::core::vector3df oldTarget = camera.getCameraNode()->getTarget();
354         irr::core::matrix4 startMatrix =
355                         camera.getCameraNode()->getAbsoluteTransformation();
356         irr::core::vector3df focusPoint = (camera.getCameraNode()->getTarget()
357                         - camera.getCameraNode()->getAbsolutePosition()).setLength(1)
358                         + camera.getCameraNode()->getAbsolutePosition();
359
360         /* create left view */
361         video::ITexture* left_image = draw_image(screensize, LEFT, startMatrix,
362                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
363                         draw_wield_tool, client, guienv, skycolor);
364
365         /* create right view */
366         video::ITexture* right_image = draw_image(screensize, RIGHT, startMatrix,
367                         focusPoint, show_hud, driver, camera, smgr, hud, hilightboxes,
368                         draw_wield_tool, client, guienv, skycolor);
369
370         /* create hud overlay */
371         video::ITexture* hudtexture = draw_hud(driver, screensize, show_hud, hud, client,
372                         false, skycolor, guienv, camera );
373         driver->makeColorKeyTexture(hudtexture, irr::video::SColor(255, 0, 0, 0));
374         //makeColorKeyTexture mirrors texture so we do it twice to get it right again
375         driver->makeColorKeyTexture(hudtexture, irr::video::SColor(255, 0, 0, 0));
376
377         driver->draw2DImage(left_image,
378                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y/2),
379                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
380
381         driver->draw2DImage(hudtexture,
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, true);
384
385         driver->draw2DImage(right_image,
386                         irr::core::rect<s32>(0, screensize.Y/2, screensize.X, screensize.Y),
387                         irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
388
389         driver->draw2DImage(hudtexture,
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, true);
392
393         left_image = NULL;
394         right_image = NULL;
395
396         /* cleanup */
397         camera.getCameraNode()->setPosition(oldPosition);
398         camera.getCameraNode()->setTarget(oldTarget);
399 }
400
401 void draw_plain(Camera& camera, bool show_hud, Hud& hud,
402                 std::vector<aabb3f> hilightboxes, video::IVideoDriver* driver,
403                 bool draw_wield_tool, Client& client, gui::IGUIEnvironment* guienv)
404 {
405         driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
406
407         draw_selectionbox(driver, hud, hilightboxes, show_hud);
408
409         if(draw_wield_tool)
410                 camera.drawWieldedTool();
411 }
412
413 void draw_scene(video::IVideoDriver* driver, scene::ISceneManager* smgr,
414                 Camera& camera, Client& client, LocalPlayer* player, Hud& hud,
415                 gui::IGUIEnvironment* guienv, std::vector<aabb3f> hilightboxes,
416                 const v2u32& screensize, video::SColor skycolor, bool show_hud)
417 {
418         //TODO check if usefull
419         u32 scenetime = 0;
420         {
421                 TimeTaker timer("smgr");
422
423                 bool draw_wield_tool = (show_hud &&
424                                 (player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE) &&
425                                 camera.getCameraMode() < CAMERA_MODE_THIRD );
426
427                 bool draw_crosshair = ((player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) &&
428                                 (camera.getCameraMode() != CAMERA_MODE_THIRD_FRONT));
429
430                 std::string draw_mode = g_settings->get("3d_mode");
431
432                 smgr->drawAll();
433
434                 if (draw_mode == "anaglyph")
435                 {
436                         draw_anaglyph_3d_mode(camera, show_hud, hud, hilightboxes, driver,
437                                         smgr, draw_wield_tool, client, guienv);
438                         draw_crosshair = false;
439                 }
440                 else if (draw_mode == "interlaced")
441                 {
442                         draw_interlaced_3d_mode(camera, show_hud, hud, hilightboxes, driver,
443                                         smgr, screensize, draw_wield_tool, client, guienv, skycolor);
444                         draw_crosshair = false;
445                 }
446                 else if (draw_mode == "sidebyside")
447                 {
448                         draw_sidebyside_3d_mode(camera, show_hud, hud, hilightboxes, driver,
449                                         smgr, screensize, draw_wield_tool, client, guienv, skycolor);
450                         show_hud = false;
451                 }
452                 else if (draw_mode == "topbottom")
453                 {
454                         draw_top_bottom_3d_mode(camera, show_hud, hud, hilightboxes, driver,
455                                         smgr, screensize, draw_wield_tool, client, guienv, skycolor);
456                         show_hud = false;
457                 }
458                 else {
459                         draw_plain(camera, show_hud, hud, hilightboxes, driver,
460                                         draw_wield_tool, client, guienv);
461                 }
462
463                 /*
464                         Post effects
465                 */
466                 {
467                         client.getEnv().getClientMap().renderPostFx(camera.getCameraMode());
468                 }
469
470                 //TODO how to make those 3d too
471                 if (show_hud)
472                 {
473                         if (draw_crosshair)
474                                 hud.drawCrosshair();
475                         hud.drawHotbar(client.getPlayerItem());
476                         hud.drawLuaElements(camera.getOffset());
477                 }
478
479                 guienv->drawAll();
480
481                 scenetime = timer.stop(true);
482         }
483
484 }
485
486 /*
487         Draws a screen with a single text on it.
488         Text will be removed when the screen is drawn the next time.
489         Additionally, a progressbar can be drawn when percent is set between 0 and 100.
490 */
491 /*gui::IGUIStaticText **/
492 void draw_load_screen(const std::wstring &text, IrrlichtDevice* device,
493                 gui::IGUIEnvironment* guienv, gui::IGUIFont* font, float dtime,
494                 int percent, bool clouds )
495 {
496         video::IVideoDriver* driver = device->getVideoDriver();
497         v2u32 screensize = driver->getScreenSize();
498         const wchar_t *loadingtext = text.c_str();
499         core::vector2d<u32> textsize_u = font->getDimension(loadingtext);
500         core::vector2d<s32> textsize(textsize_u.X,textsize_u.Y);
501         core::vector2d<s32> center(screensize.X/2, screensize.Y/2);
502         core::rect<s32> textrect(center - textsize/2, center + textsize/2);
503
504         gui::IGUIStaticText *guitext = guienv->addStaticText(
505                         loadingtext, textrect, false, false);
506         guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
507
508         bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds");
509         if (cloud_menu_background)
510         {
511                 g_menuclouds->step(dtime*3);
512                 g_menuclouds->render();
513                 driver->beginScene(true, true, video::SColor(255,140,186,250));
514                 g_menucloudsmgr->drawAll();
515         }
516         else
517                 driver->beginScene(true, true, video::SColor(255,0,0,0));
518
519         if (percent >= 0 && percent <= 100) // draw progress bar
520         {
521                 core::vector2d<s32> barsize(256,32);
522                 core::rect<s32> barrect(center-barsize/2, center+barsize/2);
523                 driver->draw2DRectangle(video::SColor(255,255,255,255),barrect, NULL); // border
524                 driver->draw2DRectangle(video::SColor(255,64,64,64), core::rect<s32> (
525                                 barrect.UpperLeftCorner+1,
526                                 barrect.LowerRightCorner-1), NULL); // black inside the bar
527                 driver->draw2DRectangle(video::SColor(255,128,128,128), core::rect<s32> (
528                                 barrect.UpperLeftCorner+1,
529                                 core::vector2d<s32>(
530                                         barrect.LowerRightCorner.X-(barsize.X-1)+percent*(barsize.X-2)/100,
531                                         barrect.LowerRightCorner.Y-1)), NULL); // the actual progress
532         }
533         guienv->drawAll();
534         driver->endScene();
535
536         guitext->remove();
537
538         //return guitext;
539 }