Add GUIScene files
parent
37278ff7f9
commit
42d1394ea4
|
@ -15,6 +15,7 @@ set(gui_SRCS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/guiKeyChangeMenu.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiPasswordChange.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiPathSelectMenu.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiScene.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiScrollBar.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiScrollContainer.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiSkin.cpp
|
||||
|
|
|
@ -69,6 +69,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "guiTable.h"
|
||||
#include "intlGUIEditBox.h"
|
||||
#include "guiHyperText.h"
|
||||
#include "guiScene.h"
|
||||
|
||||
#define MY_CHECKPOS(a,b) \
|
||||
if (v_pos.size() != 2) { \
|
||||
|
@ -2693,6 +2694,99 @@ bool GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element, b
|
|||
return true;
|
||||
}
|
||||
|
||||
void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element)
|
||||
{
|
||||
std::vector<std::string> parts = split(element, ';');
|
||||
|
||||
if (parts.size() < 5 || (parts.size() > 10 &&
|
||||
m_formspec_version <= FORMSPEC_API_VERSION)) {
|
||||
errorstream << "Invalid model element (" << parts.size() << "): '" << element
|
||||
<< "'" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid length checks by resizing
|
||||
if (parts.size() < 10)
|
||||
parts.resize(10);
|
||||
|
||||
std::vector<std::string> v_pos = split(parts[0], ',');
|
||||
std::vector<std::string> v_geom = split(parts[1], ',');
|
||||
std::string name = unescape_string(parts[2]);
|
||||
std::string meshstr = unescape_string(parts[3]);
|
||||
std::vector<std::string> textures = split(parts[4], ',');
|
||||
std::vector<std::string> vec_rot = split(parts[5], ',');
|
||||
bool inf_rotation = is_yes(parts[6]);
|
||||
bool mousectrl = is_yes(parts[7]) || parts[7].empty(); // default true
|
||||
std::vector<std::string> frame_loop = split(parts[8], ',');
|
||||
std::string speed = unescape_string(parts[9]);
|
||||
|
||||
MY_CHECKPOS("model", 0);
|
||||
MY_CHECKGEOM("model", 1);
|
||||
|
||||
v2s32 pos;
|
||||
v2s32 geom;
|
||||
|
||||
if (data->real_coordinates) {
|
||||
pos = getRealCoordinateBasePos(v_pos);
|
||||
geom = getRealCoordinateGeometry(v_geom);
|
||||
} else {
|
||||
pos = getElementBasePos(&v_pos);
|
||||
geom.X = stof(v_geom[0]) * (float)imgsize.X;
|
||||
geom.Y = stof(v_geom[1]) * (float)imgsize.Y;
|
||||
}
|
||||
|
||||
if (!data->explicit_size)
|
||||
warningstream << "invalid use of model without a size[] element" << std::endl;
|
||||
|
||||
scene::IAnimatedMesh *mesh = m_client->getMesh(meshstr);
|
||||
|
||||
if (!mesh) {
|
||||
errorstream << "Invalid model element: Unable to load mesh:"
|
||||
<< std::endl << "\t" << meshstr << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
FieldSpec spec(
|
||||
name,
|
||||
L"",
|
||||
L"",
|
||||
258 + m_fields.size()
|
||||
);
|
||||
|
||||
core::rect<s32> rect(pos, pos + geom);
|
||||
|
||||
GUIScene *e = new GUIScene(Environment, RenderingEngine::get_scene_manager(),
|
||||
data->current_parent, rect, spec.fid);
|
||||
|
||||
auto meshnode = e->setMesh(mesh);
|
||||
|
||||
for (u32 i = 0; i < textures.size() && i < meshnode->getMaterialCount(); ++i)
|
||||
e->setTexture(i, m_tsrc->getTexture(unescape_string(textures[i])));
|
||||
|
||||
if (vec_rot.size() >= 2)
|
||||
e->setRotation(v2f(stof(vec_rot[0]), stof(vec_rot[1])));
|
||||
|
||||
e->enableContinuousRotation(inf_rotation);
|
||||
e->enableMouseControl(mousectrl);
|
||||
|
||||
s32 frame_loop_begin = 0;
|
||||
s32 frame_loop_end = 0x7FFFFFFF;
|
||||
|
||||
if (frame_loop.size() == 2) {
|
||||
frame_loop_begin = stoi(frame_loop[0]);
|
||||
frame_loop_end = stoi(frame_loop[1]);
|
||||
}
|
||||
|
||||
e->setFrameLoop(frame_loop_begin, frame_loop_end);
|
||||
e->setAnimationSpeed(stof(speed));
|
||||
|
||||
auto style = getStyleForElement("model", spec.fname);
|
||||
e->setStyles(style);
|
||||
e->drop();
|
||||
|
||||
m_fields.push_back(spec);
|
||||
}
|
||||
|
||||
void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
|
||||
{
|
||||
//some prechecks
|
||||
|
@ -2884,6 +2978,11 @@ void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
|
|||
return;
|
||||
}
|
||||
|
||||
if (type == "model") {
|
||||
parseModel(data, description);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore others
|
||||
infostream << "Unknown DrawSpec: type=" << type << ", data=\"" << description << "\""
|
||||
<< std::endl;
|
||||
|
|
|
@ -440,6 +440,7 @@ private:
|
|||
bool parseAnchorDirect(parserData *data, const std::string &element);
|
||||
void parseAnchor(parserData *data, const std::string &element);
|
||||
bool parseStyle(parserData *data, const std::string &element, bool style_type);
|
||||
void parseModel(parserData *data, const std::string &element);
|
||||
|
||||
void tryClose();
|
||||
|
||||
|
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2020 Jean-Patrick Guerrero <jeanpatrick.guerrero@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "guiScene.h"
|
||||
|
||||
#include <SViewFrustum.h>
|
||||
#include <IAnimatedMeshSceneNode.h>
|
||||
#include <ILightSceneNode.h>
|
||||
#include "porting.h"
|
||||
|
||||
GUIScene::GUIScene(gui::IGUIEnvironment *env, scene::ISceneManager *smgr,
|
||||
gui::IGUIElement *parent, core::recti rect, s32 id)
|
||||
: IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rect)
|
||||
{
|
||||
m_driver = env->getVideoDriver();
|
||||
m_smgr = smgr->createNewSceneManager(false);
|
||||
|
||||
m_cam = m_smgr->addCameraSceneNode(0, v3f(0.f, 0.f, -100.f), v3f(0.f));
|
||||
m_cam->setFOV(30.f * core::DEGTORAD);
|
||||
|
||||
m_smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
|
||||
}
|
||||
|
||||
GUIScene::~GUIScene()
|
||||
{
|
||||
setMesh(nullptr);
|
||||
|
||||
m_smgr->drop();
|
||||
}
|
||||
|
||||
scene::IAnimatedMeshSceneNode *GUIScene::setMesh(scene::IAnimatedMesh *mesh)
|
||||
{
|
||||
if (m_mesh) {
|
||||
m_mesh->remove();
|
||||
m_mesh = nullptr;
|
||||
}
|
||||
|
||||
if (!mesh)
|
||||
return nullptr;
|
||||
|
||||
m_mesh = m_smgr->addAnimatedMeshSceneNode(mesh);
|
||||
m_mesh->setPosition(-m_mesh->getBoundingBox().getCenter());
|
||||
m_mesh->animateJoints();
|
||||
|
||||
return m_mesh;
|
||||
}
|
||||
|
||||
void GUIScene::setTexture(u32 idx, video::ITexture *texture)
|
||||
{
|
||||
video::SMaterial &material = m_mesh->getMaterial(idx);
|
||||
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
material.MaterialTypeParam = 0.5f;
|
||||
material.TextureLayer[0].Texture = texture;
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
material.setFlag(video::EMF_ZWRITE_ENABLE, true);
|
||||
}
|
||||
|
||||
void GUIScene::draw()
|
||||
{
|
||||
m_driver->clearZBuffer();
|
||||
|
||||
// Control rotation speed based on time
|
||||
u64 new_time = porting::getTimeMs();
|
||||
u64 dtime_ms = 0;
|
||||
if (m_last_time != 0)
|
||||
dtime_ms = porting::getDeltaMs(m_last_time, new_time);
|
||||
m_last_time = new_time;
|
||||
|
||||
core::rect<s32> oldViewPort = m_driver->getViewPort();
|
||||
m_driver->setViewPort(getAbsoluteClippingRect());
|
||||
core::recti borderRect = Environment->getRootGUIElement()->getAbsoluteClippingRect();
|
||||
|
||||
if (m_bgcolor != 0) {
|
||||
Environment->getSkin()->draw3DSunkenPane(
|
||||
this, m_bgcolor, false, true, borderRect, 0);
|
||||
}
|
||||
|
||||
core::dimension2d<s32> size = getAbsoluteClippingRect().getSize();
|
||||
m_smgr->getActiveCamera()->setAspectRatio((f32)size.Width / (f32)size.Height);
|
||||
|
||||
if (!m_target) {
|
||||
updateCamera(m_smgr->addEmptySceneNode());
|
||||
rotateCamera(v3f(0.f));
|
||||
m_cam->bindTargetAndRotation(true);
|
||||
}
|
||||
|
||||
cameraLoop();
|
||||
|
||||
// Continuous rotation
|
||||
if (m_inf_rot)
|
||||
rotateCamera(v3f(0.f, -0.03f * (float)dtime_ms, 0.f));
|
||||
|
||||
m_smgr->drawAll();
|
||||
|
||||
if (m_initial_rotation && m_mesh) {
|
||||
rotateCamera(v3f(m_custom_rot.X, m_custom_rot.Y, 0.f));
|
||||
calcOptimalDistance();
|
||||
|
||||
m_initial_rotation = false;
|
||||
}
|
||||
|
||||
m_driver->setViewPort(oldViewPort);
|
||||
}
|
||||
|
||||
bool GUIScene::OnEvent(const SEvent &event)
|
||||
{
|
||||
if (m_mouse_ctrl && event.EventType == EET_MOUSE_INPUT_EVENT) {
|
||||
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
|
||||
m_last_pos = v2f((f32)event.MouseInput.X, (f32)event.MouseInput.Y);
|
||||
return true;
|
||||
} else if (event.MouseInput.Event == EMIE_MOUSE_MOVED) {
|
||||
if (event.MouseInput.isLeftPressed()) {
|
||||
m_curr_pos = v2f((f32)event.MouseInput.X, (f32)event.MouseInput.Y);
|
||||
|
||||
rotateCamera(v3f(
|
||||
m_last_pos.Y - m_curr_pos.Y,
|
||||
m_curr_pos.X - m_last_pos.X, 0.f));
|
||||
|
||||
m_last_pos = m_curr_pos;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gui::IGUIElement::OnEvent(event);
|
||||
}
|
||||
|
||||
void GUIScene::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES> &styles)
|
||||
{
|
||||
StyleSpec::State state = StyleSpec::STATE_DEFAULT;
|
||||
StyleSpec style = StyleSpec::getStyleFromStatePropagation(styles, state);
|
||||
|
||||
setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
|
||||
setBackgroundColor(style.getColor(StyleSpec::BGCOLOR, m_bgcolor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frame loop range for the mesh
|
||||
*/
|
||||
void GUIScene::setFrameLoop(s32 begin, s32 end)
|
||||
{
|
||||
if (m_mesh->getStartFrame() != begin || m_mesh->getEndFrame() != end)
|
||||
m_mesh->setFrameLoop(begin, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the animation speed (FPS) for the mesh
|
||||
*/
|
||||
void GUIScene::setAnimationSpeed(f32 speed)
|
||||
{
|
||||
m_mesh->setAnimationSpeed(speed);
|
||||
}
|
||||
|
||||
/* Camera control functions */
|
||||
|
||||
inline void GUIScene::calcOptimalDistance()
|
||||
{
|
||||
core::aabbox3df box = m_mesh->getBoundingBox();
|
||||
f32 width = box.MaxEdge.X - box.MinEdge.X;
|
||||
f32 height = box.MaxEdge.Y - box.MinEdge.Y;
|
||||
f32 depth = box.MaxEdge.Z - box.MinEdge.Z;
|
||||
f32 max_width = width > depth ? width : depth;
|
||||
|
||||
const scene::SViewFrustum *f = m_cam->getViewFrustum();
|
||||
f32 cam_far = m_cam->getFarValue();
|
||||
f32 far_width = core::line3df(f->getFarLeftUp(), f->getFarRightUp()).getLength();
|
||||
f32 far_height = core::line3df(f->getFarLeftUp(), f->getFarLeftDown()).getLength();
|
||||
|
||||
core::recti rect = getAbsolutePosition();
|
||||
f32 zoomX = rect.getWidth() / max_width;
|
||||
f32 zoomY = rect.getHeight() / height;
|
||||
f32 dist;
|
||||
|
||||
if (zoomX < zoomY)
|
||||
dist = (max_width / (far_width / cam_far)) + (0.5f * max_width);
|
||||
else
|
||||
dist = (height / (far_height / cam_far)) + (0.5f * max_width);
|
||||
|
||||
m_cam_distance = dist;
|
||||
m_update_cam = true;
|
||||
}
|
||||
|
||||
void GUIScene::updateCamera(scene::ISceneNode *target)
|
||||
{
|
||||
m_target = target;
|
||||
updateTargetPos();
|
||||
|
||||
m_last_target_pos = m_target_pos;
|
||||
updateCameraPos();
|
||||
|
||||
m_update_cam = true;
|
||||
}
|
||||
|
||||
void GUIScene::updateTargetPos()
|
||||
{
|
||||
m_last_target_pos = m_target_pos;
|
||||
m_target->updateAbsolutePosition();
|
||||
m_target_pos = m_target->getAbsolutePosition();
|
||||
}
|
||||
|
||||
void GUIScene::setCameraRotation(v3f rot)
|
||||
{
|
||||
correctBounds(rot);
|
||||
|
||||
core::matrix4 mat;
|
||||
mat.setRotationDegrees(rot);
|
||||
|
||||
m_cam_pos = v3f(0.f, 0.f, m_cam_distance);
|
||||
mat.rotateVect(m_cam_pos);
|
||||
|
||||
m_cam_pos += m_target_pos;
|
||||
m_cam->setPosition(m_cam_pos);
|
||||
m_update_cam = false;
|
||||
}
|
||||
|
||||
bool GUIScene::correctBounds(v3f &rot)
|
||||
{
|
||||
const float ROTATION_MAX_1 = 60.0f;
|
||||
const float ROTATION_MAX_2 = 300.0f;
|
||||
|
||||
// Limit and correct the rotation when needed
|
||||
if (rot.X < 90.f) {
|
||||
if (rot.X > ROTATION_MAX_1) {
|
||||
rot.X = ROTATION_MAX_1;
|
||||
return true;
|
||||
}
|
||||
} else if (rot.X < ROTATION_MAX_2) {
|
||||
rot.X = ROTATION_MAX_2;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not modified
|
||||
return false;
|
||||
}
|
||||
|
||||
void GUIScene::cameraLoop()
|
||||
{
|
||||
updateCameraPos();
|
||||
updateTargetPos();
|
||||
|
||||
if (m_target_pos != m_last_target_pos)
|
||||
m_update_cam = true;
|
||||
|
||||
if (m_update_cam) {
|
||||
m_cam_pos = m_target_pos + (m_cam_pos - m_target_pos).normalize() * m_cam_distance;
|
||||
|
||||
v3f rot = getCameraRotation();
|
||||
if (correctBounds(rot))
|
||||
setCameraRotation(rot);
|
||||
|
||||
m_cam->setPosition(m_cam_pos);
|
||||
m_cam->setTarget(m_target_pos);
|
||||
|
||||
m_update_cam = false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2020 Jean-Patrick Guerrero <jeanpatrick.guerrero@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "ICameraSceneNode.h"
|
||||
#include "StyleSpec.h"
|
||||
|
||||
using namespace irr;
|
||||
|
||||
class GUIScene : public gui::IGUIElement
|
||||
{
|
||||
public:
|
||||
GUIScene(gui::IGUIEnvironment *env, scene::ISceneManager *smgr,
|
||||
gui::IGUIElement *parent, core::recti rect, s32 id = -1);
|
||||
|
||||
~GUIScene();
|
||||
|
||||
scene::IAnimatedMeshSceneNode *setMesh(scene::IAnimatedMesh *mesh = nullptr);
|
||||
void setTexture(u32 idx, video::ITexture *texture);
|
||||
void setBackgroundColor(const video::SColor &color) noexcept { m_bgcolor = color; };
|
||||
void setFrameLoop(s32 begin, s32 end);
|
||||
void setAnimationSpeed(f32 speed);
|
||||
void enableMouseControl(bool enable) noexcept { m_mouse_ctrl = enable; };
|
||||
void setRotation(v2f rot) noexcept { m_custom_rot = rot; };
|
||||
void enableContinuousRotation(bool enable) noexcept { m_inf_rot = enable; };
|
||||
void setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES> &styles);
|
||||
|
||||
virtual void draw();
|
||||
virtual bool OnEvent(const SEvent &event);
|
||||
|
||||
private:
|
||||
void calcOptimalDistance();
|
||||
void updateTargetPos();
|
||||
void updateCamera(scene::ISceneNode *target);
|
||||
void setCameraRotation(v3f rot);
|
||||
/// @return true indicates that the rotation was corrected
|
||||
bool correctBounds(v3f &rot);
|
||||
void cameraLoop();
|
||||
|
||||
void updateCameraPos() { m_cam_pos = m_cam->getPosition(); };
|
||||
v3f getCameraRotation() const { return (m_cam_pos - m_target_pos).getHorizontalAngle(); };
|
||||
void rotateCamera(const v3f &delta) { setCameraRotation(getCameraRotation() + delta); };
|
||||
|
||||
scene::ISceneManager *m_smgr;
|
||||
video::IVideoDriver *m_driver;
|
||||
scene::ICameraSceneNode *m_cam;
|
||||
scene::ISceneNode *m_target = nullptr;
|
||||
scene::IAnimatedMeshSceneNode *m_mesh = nullptr;
|
||||
|
||||
f32 m_cam_distance = 50.f;
|
||||
|
||||
u64 m_last_time = 0;
|
||||
|
||||
v3f m_cam_pos;
|
||||
v3f m_target_pos;
|
||||
v3f m_last_target_pos;
|
||||
// Cursor positions
|
||||
v2f m_curr_pos;
|
||||
v2f m_last_pos;
|
||||
// Initial rotation
|
||||
v2f m_custom_rot;
|
||||
|
||||
bool m_mouse_ctrl = true;
|
||||
bool m_update_cam = false;
|
||||
bool m_inf_rot = false;
|
||||
bool m_initial_rotation = true;
|
||||
|
||||
video::SColor m_bgcolor = 0;
|
||||
};
|
Loading…
Reference in New Issue