From 7a4e795779da67c6bc4ce4eb3e76ec5bbb912aa1 Mon Sep 17 00:00:00 2001 From: poikilos <7557867+poikilos@users.noreply.github.com> Date: Sat, 9 Mar 2019 15:42:40 -0500 Subject: [PATCH] clarify license, improve camera, remove most header creep --- CHANGELOG.md | 6 ++++++ Debug.h | 2 -- Engine.cpp | 14 +++++++++++-- Engine.h | 12 ++++++++---- EventHandler.h | 1 - README.md | 2 ++ UserInterface.cpp | 4 ++++ UserInterface.h | 12 +++--------- Utils.cpp | 4 +++- Utils.h | 4 ++-- View.cpp | 37 +++++++++++++++++++++++++++++++---- View.h | 6 +----- b3view.xcf => etc/b3view.xcf | Bin extlib/CGUITTFont.h | 2 +- main.cpp | 4 ++-- screenshot.jpg | Bin 0 -> 18876 bytes 16 files changed, 77 insertions(+), 33 deletions(-) rename b3view.xcf => etc/b3view.xcf (100%) create mode 100644 screenshot.jpg diff --git a/CHANGELOG.md b/CHANGELOG.md index 02cb93e..2be9813 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ ### Changed * only try to load png or jpg textures--skip others when cycling * cycle backwards correctly +* fix some of the header creep (remove unecessary includes in h files) +* improve initial camera position and angle (see top of characters since + camera is higher; z-forward characters face camera at an angle) +* Clarify relationship between camera start position in m_Engine and + m_View's rotation (m_Pitch and m_Yaw). Now, `setNewCameraPosition` + operates on view correctly (relatively) no matter where camera starts. ## [git] - 2019-03-07 (poikilos) diff --git a/Debug.h b/Debug.h index 4bfb900..2d7c2d8 100644 --- a/Debug.h +++ b/Debug.h @@ -2,8 +2,6 @@ #define DEBUG_H #include -#include - std::ostream & debug(); diff --git a/Engine.cpp b/Engine.cpp index 0db3fe9..3975730 100644 --- a/Engine.cpp +++ b/Engine.cpp @@ -1,5 +1,9 @@ #include "Engine.h" +#include "UserInterface.h" +#include "View.h" +#include "Utils.h" + using std::cout; using std::wcerr; using std::endl; @@ -27,8 +31,11 @@ void Engine::setupScene() m_Scene->setAmbientLight( SColorf( 0.2f, 0.2f, 0.2f )); // Setup Camera - ICameraSceneNode *camera = m_Scene->addCameraSceneNode( nullptr, vector3df( 0, 0, -10 ), vector3df() ); - camera->setAspectRatio(( f32 ) m_Driver->getScreenSize().Width / m_Driver->getScreenSize().Height ); + // (so z-forward characters face camera partially (formerly vector3df( 0, 0, -10 ), vector3df()) + tmpPosVec3f = vector3df( 4.5, 3, 9 ); + tmpTargetVec3f = vector3df(0, 3, 0); + ICameraSceneNode *camera = m_Scene->addCameraSceneNode(nullptr, tmpPosVec3f, tmpTargetVec3f); // this will be overridden by View m_Yaw and m_Pitch--see "calculate m_Yaw" further down + camera->setAspectRatio((f32)m_Driver->getScreenSize().Width / m_Driver->getScreenSize().Height); } IGUIEnvironment * Engine::getGUIEnvironment() const @@ -175,6 +182,9 @@ Engine::Engine() m_WindowSize = new dimension2d(); m_WindowSize->Width = m_Driver->getScreenSize().Width; m_WindowSize->Height = m_Driver->getScreenSize().Height; + + // (do not calculate m_Yaw and m_Pitch, here, but in View constructor) + this->playAnimation(); } diff --git a/Engine.h b/Engine.h index 4844c5c..a317728 100644 --- a/Engine.h +++ b/Engine.h @@ -11,11 +11,7 @@ class View; #include #include - #include "EventHandler.h" -#include "UserInterface.h" -#include "View.h" - #include "extlib/CGUITTFont.h" enum SceneItemID @@ -58,6 +54,14 @@ private: irr::u32 worldFPS; irr::u32 prevFPS; std::vector textureExtensions; + // Making materials in contructor or setupScene causes segfault at + // `m_Driver->setMaterial( *lineX );` in + // `Engine::drawAxisLines` for unknown reason: +// irr::video::SMaterial *lineX; +// irr::video::SMaterial *lineY; +// irr::video::SMaterial *lineZ; + irr::core::vector3df tmpPosVec3f; + irr::core::vector3df tmpTargetVec3f; public: std::wstring m_PreviousPath; diff --git a/EventHandler.h b/EventHandler.h index 86518d1..bc3c6c1 100644 --- a/EventHandler.h +++ b/EventHandler.h @@ -6,7 +6,6 @@ #include #include - #include "Debug.h" using std::cout; diff --git a/README.md b/README.md index 919c6cb..bd8ca28 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,8 @@ only applies to Visual Studio users.) such as from ) **"Feel free to use however you like, commercial etc, credits are Appreciated..."** -Psionic +* icon (b3view.xcf, p3view.png) Creative Commons Attribution Share-Alike + 4.0 [poikilos](https://poikilos.org) * All files not mentioned above, and not described in text files in the same folder as media (such as "build" folder) are licensed under the **GPL v3** as per diff --git a/UserInterface.cpp b/UserInterface.cpp index 51de216..11b3c24 100644 --- a/UserInterface.cpp +++ b/UserInterface.cpp @@ -8,6 +8,10 @@ // #include // requires C++17 #include // requires C++14 such as gcc 8.2.1 +#include "Debug.h" +#include "Engine.h" +#include "Utils.h" + using namespace irr; using namespace irr::core; using namespace irr::gui; diff --git a/UserInterface.h b/UserInterface.h index e52e2f7..1456a22 100644 --- a/UserInterface.h +++ b/UserInterface.h @@ -1,18 +1,12 @@ #ifndef USERINTERFACE_H #define USERINTERFACE_H +#include +#include "extlib/CGUITTFont.h" + // Forward declaration of class Engine class Engine; -#include -#include -#include - -#include "Debug.h" -#include "Engine.h" - -#include "extlib/CGUITTFont.h" - enum UserInterfaceElements { UIE_PLAYBACKWINDOW = 1000, diff --git a/Utils.cpp b/Utils.cpp index 2651c03..a7fd9c3 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1,12 +1,14 @@ +#include "Utils.h" #include #include #include #include #include +#include #include // #include #include -#include "Utils.h" +#include "Debug.h" using namespace irr::core; using namespace irr::scene; diff --git a/Utils.h b/Utils.h index 47a2ed5..696ea3c 100644 --- a/Utils.h +++ b/Utils.h @@ -1,9 +1,9 @@ #ifndef UTILS_H #define UTILS_H -#include +#include + #include -#include "Debug.h" class Utility { diff --git a/View.cpp b/View.cpp index 7111431..abd3ecc 100644 --- a/View.cpp +++ b/View.cpp @@ -1,4 +1,5 @@ #include "View.h" +#include "Engine.h" using namespace irr; using namespace irr::core; @@ -8,7 +9,10 @@ void View::setNewCameraPosition() { vector3d newCameraPosition; ICameraSceneNode *camera = m_Engine->m_Scene->getActiveCamera(); - + vector3df oldCamPos = camera->getPosition(); + // vector3df oldCamRot = camera->getRotation(); + // NOTE: rotationToDirection converts a rotation to a vec3 direction. + // vector3df oldCamRot = m_Engine->tmpPosVec3f.?(m_Engine->tmpTargetVec3f); newCameraPosition.X = 0; newCameraPosition.Y = m_CameraDistance * sin( m_Pitch ); newCameraPosition.Z = m_CameraDistance * cos( m_Pitch ); @@ -17,7 +21,11 @@ void View::setNewCameraPosition() yawMatrix.setRotationRadians( vector3df( 0, m_Yaw, 0 )); yawMatrix.transformVect( newCameraPosition ); - camera->setPosition( newCameraPosition ); + newCameraPosition.Y = oldCamPos.Y; + camera->setPosition( newCameraPosition ); + // vector3df newRotation(); + // camera->setRotation(); + // camera->setTarget(m_Engine->tmpTargetVec3f); // Set Light direction setNewLightDirection( newCameraPosition ); @@ -44,8 +52,29 @@ View::View( Engine *engine ) // Set Camera Distance m_CameraDistance = 10; - debug() << "Yaw: " << m_Yaw << endl; - debug() << "Pitch: " << m_Pitch << endl; + // vectors for angle are opposite, since camera revolves around center + vector3df offsetVec3( + engine->tmpPosVec3f.X-engine->tmpTargetVec3f.X, + engine->tmpPosVec3f.Y-engine->tmpTargetVec3f.Y, + engine->tmpPosVec3f.Z-engine->tmpTargetVec3f.Z + ); + // m_CameraDistance = sqrtf() + m_CameraDistance = offsetVec3.getLength(); + // NOTE: rotationToDirection converts a rotation to a vec3 direction + // vector3df rotationVec3 = engine->tmpPosVec3f.?(engine->tmpTargetVec3f); + // vector3df rotationVec3 = engine->tmpTargetVec3f.?(engine->tmpPosVec3f); + + // see rogerborg on + // const f32 dot = engine->tmpTargetVec3f.dotProduct(engine->tmpPosVec3f); // to...(from) // angle only + + m_Yaw = atan2(offsetVec3.X, offsetVec3.Z); + m_Pitch = asin(-offsetVec3.Y); + + // m_Yaw = rotationVec3.Y; + // m_Pitch = rotationVec3.X; + + debug() << "Yaw: " << radToDeg(m_Yaw) << endl; + debug() << "Pitch: " << radToDeg(m_Pitch) << endl; } View::~View() diff --git a/View.h b/View.h index 7614bca..6666431 100644 --- a/View.h +++ b/View.h @@ -3,11 +3,7 @@ #include -#include "Debug.h" -#include "Engine.h" -#include "Utils.h" - - +class Engine; class View : public irr::IEventReceiver { diff --git a/b3view.xcf b/etc/b3view.xcf similarity index 100% rename from b3view.xcf rename to etc/b3view.xcf diff --git a/extlib/CGUITTFont.h b/extlib/CGUITTFont.h index 51b538b..776589f 100644 --- a/extlib/CGUITTFont.h +++ b/extlib/CGUITTFont.h @@ -1,9 +1,9 @@ #ifndef __C_GUI_TTFONT_H_INCLUDED__ #define __C_GUI_TTFONT_H_INCLUDED__ -#include #include #include FT_FREETYPE_H +#include namespace irr { diff --git a/main.cpp b/main.cpp index 5e79ac9..e39e24b 100644 --- a/main.cpp +++ b/main.cpp @@ -44,8 +44,8 @@ int main( int argc, char **argv ) engine->loadMesh( wstring( initialFileName )); free( initialFileName ); } - else - engine->loadMesh( L"test.b3d" ); +// else +// engine->loadMesh( L"test.b3d" ); engine->run(); diff --git a/screenshot.jpg b/screenshot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9425970e4af82986f54a1a89df7f5edd3e96e754 GIT binary patch literal 18876 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 Sr%EvQk?iHMeBS^M2LA`j%ij?I literal 0 HcmV?d00001