3 Copyright (C) 2020 Jean-Patrick Guerrero <jeanpatrick.guerrero@gmail.com>
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.
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.
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.
22 #include <SViewFrustum.h>
23 #include <IAnimatedMeshSceneNode.h>
24 #include <ILightSceneNode.h>
27 GUIScene::GUIScene(gui::IGUIEnvironment *env, scene::ISceneManager *smgr,
28 gui::IGUIElement *parent, core::recti rect, s32 id)
29 : IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rect)
31 m_driver = env->getVideoDriver();
32 m_smgr = smgr->createNewSceneManager(false);
34 m_cam = m_smgr->addCameraSceneNode(0, v3f(0.f, 0.f, -100.f), v3f(0.f));
35 m_cam->setFOV(30.f * core::DEGTORAD);
37 m_smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
47 scene::IAnimatedMeshSceneNode *GUIScene::setMesh(scene::IAnimatedMesh *mesh)
57 m_mesh = m_smgr->addAnimatedMeshSceneNode(mesh);
58 m_mesh->setPosition(-m_mesh->getBoundingBox().getCenter());
59 m_mesh->animateJoints();
64 void GUIScene::setTexture(u32 idx, video::ITexture *texture)
66 video::SMaterial &material = m_mesh->getMaterial(idx);
67 material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
68 material.MaterialTypeParam = 0.5f;
69 material.TextureLayer[0].Texture = texture;
70 material.setFlag(video::EMF_LIGHTING, false);
71 material.setFlag(video::EMF_FOG_ENABLE, true);
72 material.setFlag(video::EMF_BILINEAR_FILTER, false);
73 material.setFlag(video::EMF_BACK_FACE_CULLING, false);
74 material.setFlag(video::EMF_ZWRITE_ENABLE, true);
79 m_driver->clearBuffers(video::ECBF_DEPTH);
81 // Control rotation speed based on time
82 u64 new_time = porting::getTimeMs();
85 dtime_ms = porting::getDeltaMs(m_last_time, new_time);
86 m_last_time = new_time;
88 core::rect<s32> oldViewPort = m_driver->getViewPort();
89 m_driver->setViewPort(getAbsoluteClippingRect());
90 core::recti borderRect = Environment->getRootGUIElement()->getAbsoluteClippingRect();
93 Environment->getSkin()->draw3DSunkenPane(
94 this, m_bgcolor, false, true, borderRect, 0);
97 core::dimension2d<s32> size = getAbsoluteClippingRect().getSize();
98 m_smgr->getActiveCamera()->setAspectRatio((f32)size.Width / (f32)size.Height);
101 updateCamera(m_smgr->addEmptySceneNode());
102 rotateCamera(v3f(0.f));
103 m_cam->bindTargetAndRotation(true);
108 // Continuous rotation
110 rotateCamera(v3f(0.f, -0.03f * (float)dtime_ms, 0.f));
114 if (m_initial_rotation && m_mesh) {
115 rotateCamera(v3f(m_custom_rot.X, m_custom_rot.Y, 0.f));
116 calcOptimalDistance();
118 m_initial_rotation = false;
121 m_driver->setViewPort(oldViewPort);
124 bool GUIScene::OnEvent(const SEvent &event)
126 if (m_mouse_ctrl && event.EventType == EET_MOUSE_INPUT_EVENT) {
127 if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
128 m_last_pos = v2f((f32)event.MouseInput.X, (f32)event.MouseInput.Y);
130 } else if (event.MouseInput.Event == EMIE_MOUSE_MOVED) {
131 if (event.MouseInput.isLeftPressed()) {
132 m_curr_pos = v2f((f32)event.MouseInput.X, (f32)event.MouseInput.Y);
135 m_last_pos.Y - m_curr_pos.Y,
136 m_curr_pos.X - m_last_pos.X, 0.f));
138 m_last_pos = m_curr_pos;
144 return gui::IGUIElement::OnEvent(event);
147 void GUIScene::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES> &styles)
149 StyleSpec::State state = StyleSpec::STATE_DEFAULT;
150 StyleSpec style = StyleSpec::getStyleFromStatePropagation(styles, state);
152 setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
153 setBackgroundColor(style.getColor(StyleSpec::BGCOLOR, m_bgcolor));
157 * Sets the frame loop range for the mesh
159 void GUIScene::setFrameLoop(s32 begin, s32 end)
161 if (m_mesh->getStartFrame() != begin || m_mesh->getEndFrame() != end)
162 m_mesh->setFrameLoop(begin, end);
166 * Sets the animation speed (FPS) for the mesh
168 void GUIScene::setAnimationSpeed(f32 speed)
170 m_mesh->setAnimationSpeed(speed);
173 /* Camera control functions */
175 inline void GUIScene::calcOptimalDistance()
177 core::aabbox3df box = m_mesh->getBoundingBox();
178 f32 width = box.MaxEdge.X - box.MinEdge.X;
179 f32 height = box.MaxEdge.Y - box.MinEdge.Y;
180 f32 depth = box.MaxEdge.Z - box.MinEdge.Z;
181 f32 max_width = width > depth ? width : depth;
183 const scene::SViewFrustum *f = m_cam->getViewFrustum();
184 f32 cam_far = m_cam->getFarValue();
185 f32 far_width = core::line3df(f->getFarLeftUp(), f->getFarRightUp()).getLength();
186 f32 far_height = core::line3df(f->getFarLeftUp(), f->getFarLeftDown()).getLength();
188 core::recti rect = getAbsolutePosition();
189 f32 zoomX = rect.getWidth() / max_width;
190 f32 zoomY = rect.getHeight() / height;
194 dist = (max_width / (far_width / cam_far)) + (0.5f * max_width);
196 dist = (height / (far_height / cam_far)) + (0.5f * max_width);
198 m_cam_distance = dist;
202 void GUIScene::updateCamera(scene::ISceneNode *target)
207 m_last_target_pos = m_target_pos;
213 void GUIScene::updateTargetPos()
215 m_last_target_pos = m_target_pos;
216 m_target->updateAbsolutePosition();
217 m_target_pos = m_target->getAbsolutePosition();
220 void GUIScene::setCameraRotation(v3f rot)
225 mat.setRotationDegrees(rot);
227 m_cam_pos = v3f(0.f, 0.f, m_cam_distance);
228 mat.rotateVect(m_cam_pos);
230 m_cam_pos += m_target_pos;
231 m_cam->setPosition(m_cam_pos);
232 m_update_cam = false;
235 bool GUIScene::correctBounds(v3f &rot)
237 const float ROTATION_MAX_1 = 60.0f;
238 const float ROTATION_MAX_2 = 300.0f;
240 // Limit and correct the rotation when needed
242 if (rot.X > ROTATION_MAX_1) {
243 rot.X = ROTATION_MAX_1;
246 } else if (rot.X < ROTATION_MAX_2) {
247 rot.X = ROTATION_MAX_2;
255 void GUIScene::cameraLoop()
260 if (m_target_pos != m_last_target_pos)
264 m_cam_pos = m_target_pos + (m_cam_pos - m_target_pos).normalize() * m_cam_distance;
266 v3f rot = getCameraRotation();
267 if (correctBounds(rot))
268 setCameraRotation(rot);
270 m_cam->setPosition(m_cam_pos);
271 m_cam->setTarget(m_target_pos);
273 m_update_cam = false;