diff --git a/.travis.yml b/.travis.yml index 22f6164c2..0910ac546 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,8 +40,8 @@ script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi - - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi - - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi notifications: recipients: - corrmage+travis-ci@gmail.com diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 479f8cba2..251889e28 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -20,7 +20,6 @@ MwIniImporter::MwIniImporter() { const char *map[][2] = { - { "fps", "General:Show FPS" }, { "no-sound", "General:Disable Audio" }, { 0, 0 } }; diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 089880fb2..5d2d588ed 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -168,9 +168,6 @@ void OMW::Engine::frame(float frametime) if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { -#if 0 - mEnvironment.getWindowManager()->wmUpdateFps(fps); -#endif mEnvironment.getWindowManager()->update(); } diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index fb7eca4a3..f364ada7a 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -155,8 +155,6 @@ namespace MWBase virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; - virtual void wmUpdateFps(float fps) = 0; - /// Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0; diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index cfb49ebff..b728b748f 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -153,6 +153,34 @@ struct TypesetBookImpl : TypesetBook visitRuns (top, bottom, NULL, visitor); } + /// hit test with a margin for error. only hits on interactive text fragments are reported. + StyleImpl * hitTestWithMargin (int left, int top) + { + StyleImpl * hit = hitTest(left, top); + if (hit && hit->mInteractiveId > 0) + return hit; + + const int maxMargin = 10; + for (int margin=1; margin < maxMargin; ++margin) + { + for (int i=0; i<4; ++i) + { + if (i==0) + hit = hitTest(left, top-margin); + else if (i==1) + hit = hitTest(left, top+margin); + else if (i==2) + hit = hitTest(left-margin, top); + else + hit = hitTest(left+margin, top); + + if (hit && hit->mInteractiveId > 0) + return hit; + } + } + return NULL; + } + StyleImpl * hitTest (int left, int top) const { for (Sections::const_iterator i = mSections.begin (); i != mSections.end (); ++i) @@ -916,15 +944,15 @@ public: left -= mCroppedParent->getAbsoluteLeft (); top -= mCroppedParent->getAbsoluteTop (); - Style * Hit = mBook->hitTest (left, mViewTop + top); + Style * hit = mBook->hitTestWithMargin (left, mViewTop + top); if (mLastDown == MyGUI::MouseButton::None) { - if (Hit != mFocusItem) + if (hit != mFocusItem) { dirtyFocusItem (); - mFocusItem = Hit; + mFocusItem = hit; mItemActive = false; dirtyFocusItem (); @@ -933,7 +961,7 @@ public: else if (mFocusItem != 0) { - bool newItemActive = Hit == mFocusItem; + bool newItemActive = hit == mFocusItem; if (newItemActive != mItemActive) { @@ -949,12 +977,18 @@ public: if (!mBook) return; - left -= mCroppedParent->getAbsoluteLeft (); - top -= mCroppedParent->getAbsoluteTop (); + // work around inconsistency in MyGUI where the mouse press coordinates aren't + // transformed by the current Layer (even though mouse *move* events are). + MyGUI::IntPoint pos (left, top); +#if MYGUI_VERSION < MYGUI_DEFINE_VERSION(3,2,3) + pos = mNode->getLayer()->getPosition(left, top); +#endif + pos.left -= mCroppedParent->getAbsoluteLeft (); + pos.top -= mCroppedParent->getAbsoluteTop (); if (mLastDown == MyGUI::MouseButton::None) { - mFocusItem = mBook->hitTest (left, mViewTop + top); + mFocusItem = mBook->hitTestWithMargin (pos.left, mViewTop + pos.top); mItemActive = true; dirtyFocusItem (); @@ -968,14 +1002,21 @@ public: if (!mBook) return; - left -= mCroppedParent->getAbsoluteLeft (); - top -= mCroppedParent->getAbsoluteTop (); + // work around inconsistency in MyGUI where the mouse release coordinates aren't + // transformed by the current Layer (even though mouse *move* events are). + MyGUI::IntPoint pos (left, top); +#if MYGUI_VERSION < MYGUI_DEFINE_VERSION(3,2,3) + pos = mNode->getLayer()->getPosition(left, top); +#endif + + pos.left -= mCroppedParent->getAbsoluteLeft (); + pos.top -= mCroppedParent->getAbsoluteTop (); if (mLastDown == id) { - Style * mItem = mBook->hitTest (left, mViewTop + top); + Style * item = mBook->hitTestWithMargin (pos.left, mViewTop + pos.top); - bool clicked = mFocusItem == mItem; + bool clicked = mFocusItem == item; mItemActive = false; @@ -983,8 +1024,8 @@ public: mLastDown = MyGUI::MouseButton::None; - if (clicked && mLinkClicked && mItem && mItem->mInteractiveId != 0) - mLinkClicked (mItem->mInteractiveId); + if (clicked && mLinkClicked && item && item->mInteractiveId != 0) + mLinkClicked (item->mInteractiveId); } } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a93bb47e9..3922b1997 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -67,7 +67,7 @@ namespace MWGui }; - HUD::HUD(CustomMarkerCollection &customMarkers, bool showFps, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) + HUD::HUD(CustomMarkerCollection &customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) : Layout("openmw_hud.layout") , LocalMapBase(customMarkers, localMapRender) , mHealth(NULL) @@ -85,8 +85,6 @@ namespace MWGui , mCellNameBox(NULL) , mDrowningFrame(NULL) , mDrowningFlash(NULL) - , mFpsBox(NULL) - , mFpsCounter(NULL) , mHealthManaStaminaBaseLeft(0) , mWeapBoxBaseLeft(0) , mSpellBoxBaseLeft(0) @@ -161,8 +159,6 @@ namespace MWGui getWidget(mCrosshair, "Crosshair"); - setFpsVisible(showFps); - LocalMapBase::init(mMinimap, mCompass, Settings::Manager::getInt("local map hud widget size", "Map")); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); @@ -181,28 +177,6 @@ namespace MWGui delete mSpellIcons; } - void HUD::setFpsVisible(const bool visible) - { - mFpsCounter = 0; - - MyGUI::Widget* fps; - getWidget(fps, "FPSBox"); - fps->setVisible(false); - - if (visible) - { - getWidget(mFpsBox, "FPSBox"); - //mFpsBox->setVisible(true); - getWidget(mFpsCounter, "FPSCounter"); - } - } - - void HUD::setFPS(float fps) - { - if (mFpsCounter) - mFpsCounter->setCaption(MyGUI::utility::toString((int)fps)); - } - void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) { int current = std::max(0, static_cast(value.getCurrent())); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 629613c98..c5ae45789 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -19,10 +19,9 @@ namespace MWGui class HUD : public Layout, public LocalMapBase { public: - HUD(CustomMarkerCollection& customMarkers, bool fpsVisible, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender); + HUD(CustomMarkerCollection& customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender); virtual ~HUD(); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); - void setFPS(float fps); /// Set time left for the player to start drowning /// @param time time left to start drowning @@ -38,8 +37,6 @@ namespace MWGui void setEffectVisible(bool visible); void setMinimapVisible(bool visible); - void setFpsVisible(const bool visible); - void setSelectedSpell(const std::string& spellId, int successChancePercent); void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent); void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent); @@ -77,9 +74,6 @@ namespace MWGui MyGUI::TextBox* mWeaponSpellBox; MyGUI::Widget *mDrowningFrame, *mDrowningFlash; - MyGUI::Widget* mFpsBox; - MyGUI::TextBox* mFpsCounter; - // bottom left elements int mHealthManaStaminaBaseLeft, mWeapBoxBaseLeft, mSpellBoxBaseLeft, mSneakBoxBaseLeft; // bottom right elements diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 9afce6873..321d5e664 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -282,7 +282,13 @@ namespace MWGui MWBase::Environment::get().getInputManager()->update(0, true, true); //osg::Timer timer; - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + // at the time this function is called we are in the middle of a frame, + // so out of order calls are necessary to get a correct frameNumber for the next frame. + // refer to the advance() and frame() order in Engine::go() + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); //std::cout << "frame took " << timer.time_m() << std::endl; //if (mViewer->getIncrementalCompileOperation()) diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index 473776a82..c44bcc3f1 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -66,8 +66,8 @@ namespace MWGui mFader->notifyOperationFinished(); } - ScreenFader::ScreenFader(const std::string & texturePath) - : WindowBase("openmw_screen_fader.layout") + ScreenFader::ScreenFader(const std::string & texturePath, const std::string& layout) + : WindowBase(layout) , mCurrentAlpha(0.f) , mFactor(1.f) , mRepeat(false) diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index 402554555..d25f5fdc4 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -36,7 +36,7 @@ namespace MWGui class ScreenFader : public WindowBase { public: - ScreenFader(const std::string & texturePath); + ScreenFader(const std::string & texturePath, const std::string& layout = "openmw_screen_fader.layout"); void setTexture(const std::string & texturePath); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 667dc0c28..eb2f23529 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -166,7 +166,6 @@ namespace MWGui getWidget(mFullscreenButton, "FullscreenButton"); getWidget(mVSyncButton, "VSyncButton"); getWidget(mWindowBorderButton, "WindowBorderButton"); - getWidget(mFPSButton, "FPSButton"); getWidget(mFOVSlider, "FOVSlider"); getWidget(mAnisotropySlider, "AnisotropySlider"); getWidget(mTextureFilteringButton, "TextureFilteringButton"); @@ -201,7 +200,6 @@ namespace MWGui mSettingsTab->eventTabChangeSelect += MyGUI::newDelegate(this, &SettingsWindow::onTabChanged); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mTextureFilteringButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringChanged); - mFPSButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onFpsToggled); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged); @@ -256,8 +254,6 @@ namespace MWGui mShadowsEnabledButton->setEnabled(false); } - mFPSButton->setCaptionWithReplacing(fpsLevelToStr(Settings::Manager::getInt("fps", "HUD"))); - MyGUI::TextBox* fovText; getWidget(fovText, "FovText"); fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(Settings::Manager::getInt("field of view", "General"))) + ")"); @@ -427,14 +423,6 @@ namespace MWGui } } - void SettingsWindow::onFpsToggled(MyGUI::Widget* _sender) - { - int newLevel = (Settings::Manager::getInt("fps", "HUD") + 1) % 2; - Settings::Manager::setInt("fps", "HUD", newLevel); - mFPSButton->setCaptionWithReplacing(fpsLevelToStr(newLevel)); - apply(); - } - void SettingsWindow::onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos) { Settings::Manager::setString("texture filtering", "General", Misc::StringUtils::lowerCase(_sender->getItemNameAt(pos))); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 0369eb40e..99553808b 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -30,7 +30,6 @@ namespace MWGui MyGUI::Button* mFullscreenButton; MyGUI::Button* mVSyncButton; MyGUI::Button* mWindowBorderButton; - MyGUI::Button* mFPSButton; MyGUI::ScrollBar* mFOVSlider; MyGUI::ScrollBar* mDifficultySlider; MyGUI::ScrollBar* mAnisotropySlider; @@ -53,7 +52,6 @@ namespace MWGui void onTabChanged(MyGUI::TabControl* _sender, size_t index); void onOkButtonClicked(MyGUI::Widget* _sender); - void onFpsToggled(MyGUI::Widget* _sender); void onTextureFilteringChanged(MyGUI::ComboBox* _sender, size_t pos); void onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onButtonToggled(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 191e8223d..c9d1b0617 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -49,11 +49,13 @@ void WindowBase::center() { // Centre dialog - MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntSize layerSize = MyGUI::RenderManager::getInstance().getViewSize(); + if (mMainWidget->getLayer()) + layerSize = mMainWidget->getLayer()->getSize(); MyGUI::IntCoord coord = mMainWidget->getCoord(); - coord.left = (gameWindowSize.width - coord.width)/2; - coord.top = (gameWindowSize.height - coord.height)/2; + coord.left = (layerSize.width - coord.width)/2; + coord.top = (layerSize.height - coord.height)/2; mMainWidget->setCoord(coord); } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 90a5f7481..a7c3a1957 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -33,6 +33,9 @@ #include #include +#include +#include +#include #include @@ -185,7 +188,6 @@ namespace MWGui , mForceHidden(GW_None) , mAllowed(GW_ALL) , mRestAllowed(true) - , mFPS(0.0f) , mFallbackMap(fallbackMap) , mShowOwned(0) , mVersionDescription(versionDescription) @@ -216,6 +218,8 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Layer"); + MyGUI::FactoryManager::getInstance().registerFactory("Layer"); BookPage::registerMyGUIComponents (); ItemView::registerComponents(); ItemWidget::registerComponents(); @@ -246,7 +250,7 @@ namespace MWGui MyGUI::PointerManager::getInstance().setVisible(false); mVideoBackground = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, - MyGUI::Align::Default, "Overlay"); + MyGUI::Align::Default, "InputBlocker"); mVideoBackground->setImageTexture("black"); mVideoBackground->setVisible(false); mVideoBackground->setNeedMouseFocus(true); @@ -296,7 +300,7 @@ namespace MWGui trackWindow(mDialogueWindow, "dialogue"); mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); - mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop, mLocalMapRender); + mHud = new HUD(mCustomMarkers, mDragAndDrop, mLocalMapRender); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mBookWindow = new BookWindow(); @@ -327,12 +331,12 @@ namespace MWGui // TODO: check if non-BM versions actually use player_hit_01.dds if(!mResourceSystem->getVFS()->exists(hitFaderTexture)) hitFaderTexture = "textures\\player_hit_01.dds"; - mHitFader = new ScreenFader(hitFaderTexture); + mHitFader = new ScreenFader(hitFaderTexture, "openmw_screen_fader_hit.layout"); mScreenFader = new ScreenFader("black"); mDebugWindow = new DebugWindow(); - mInputBlocker = MyGUI::Gui::getInstance().createWidget("",0,0,w,h,MyGUI::Align::Stretch,"Overlay"); + mInputBlocker = MyGUI::Gui::getInstance().createWidget("",0,0,w,h,MyGUI::Align::Stretch,"InputBlocker"); mHud->setVisible(mHudEnabled); @@ -464,8 +468,6 @@ namespace MWGui { cleanupGarbage(); - mHud->setFPS(mFPS); - mHud->update(); } @@ -859,7 +861,13 @@ namespace MWGui mMessageBoxManager->onFrame(0.f); MWBase::Environment::get().getInputManager()->update(0, true, false); - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + // at the time this function is called we are in the middle of a frame, + // so out of order calls are necessary to get a correct frameNumber for the next frame. + // refer to the advance() and frame() order in Engine::go() + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); } } } @@ -1132,7 +1140,6 @@ namespace MWGui void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) { - mHud->setFpsVisible(static_cast(Settings::Manager::getInt("fps", "HUD"))); mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); for (Settings::CategorySettingVector::const_iterator it = changed.begin(); @@ -1316,11 +1323,6 @@ namespace MWGui mConsole->executeFile (path); } - void WindowManager::wmUpdateFps(float fps) - { - mFPS = fps; - } - MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } @@ -1756,7 +1758,13 @@ namespace MWGui { MWBase::Environment::get().getInputManager()->update(0, true, false); - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + // at the time this function is called we are in the middle of a frame, + // so out of order calls are necessary to get a correct frameNumber for the next frame. + // refer to the advance() and frame() order in Engine::go() + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); } mVideoWidget->stop(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a1f76683e..7df5508a1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -180,8 +180,6 @@ namespace MWGui virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); - virtual void wmUpdateFps(float fps); - ///< Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); virtual void setValue (int parSkill, const MWMechanics::SkillValue& value); @@ -486,8 +484,6 @@ namespace MWGui void updateMap(); - float mFPS; - std::map mFallbackMap; int mShowOwned; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 92994d557..55144afe7 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -240,8 +240,6 @@ namespace MWPhysics const ESM::Position& refpos = ptr.getRefData().getPosition(); osg::Vec3f position(refpos.asVec3()); - float collisionShapeOffset = physicActor->getPosition().z() - position.z(); - // Early-out for totally static creatures // (Not sure if gravity should still apply?) if (!ptr.getClass().isMobile(ptr)) @@ -258,11 +256,17 @@ namespace MWPhysics } btCollisionObject *colobj = physicActor->getCollisionObject(); - position.z() += collisionShapeOffset; + osg::Vec3f halfExtents = physicActor->getHalfExtents(); + + // NOTE: here we don't account for the collision box translation (i.e. physicActor->getPosition() - refpos.pos). + // That means the collision shape used for moving this actor is in a different spot than the collision shape + // other actors are using to collide against this actor. + // While this is strictly speaking wrong, it's needed for MW compatibility. + position.z() += halfExtents.z(); static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() .find("fSwimHeightScale")->getFloat(); - float swimlevel = waterlevel + collisionShapeOffset - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); + float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); ActorTracer tracer; osg::Vec3f inertia = physicActor->getInertialForce(); @@ -284,6 +288,11 @@ namespace MWPhysics velocity = velocity + physicActor->getInertialForce(); } } + + // dead actors underwater will float to the surface + if (ptr.getClass().getCreatureStats(ptr).isDead() && position.z() < swimlevel) + velocity = osg::Vec3f(0,0,1) * 25; + ptr.getClass().getMovementSettings(ptr).mPosition[2] = 0; // Now that we have the effective movement vector, apply wind forces to it @@ -370,7 +379,7 @@ namespace MWPhysics { // don't let pure water creatures move out of water after stepMove if (ptr.getClass().isPureWaterCreature(ptr) - && newPosition.z() + physicActor->getHalfExtents().z() > waterlevel) + && newPosition.z() + halfExtents.z() > waterlevel) newPosition = oldPosition; } else @@ -451,7 +460,7 @@ namespace MWPhysics } physicActor->setOnGround(isOnGround); - newPosition.z() -= collisionShapeOffset; // remove what was added at the beginning + newPosition.z() -= halfExtents.z(); // remove what was added at the beginning return newPosition; } }; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7b11c9d85..45c04ceec 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -489,6 +489,15 @@ namespace MWRender mutable bool mDone; }; + + class NoTraverseCallback : public osg::NodeCallback + { + public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + } + }; + void RenderingManager::screenshot(osg::Image *image, int w, int h) { osg::ref_ptr rttCamera (new osg::Camera); @@ -512,6 +521,7 @@ namespace MWRender image->setDataType(GL_UNSIGNED_BYTE); image->setPixelFormat(texture->getInternalFormat()); + rttCamera->setUpdateCallback(new NoTraverseCallback); rttCamera->addChild(mLightRoot); rttCamera->setCullMask(mViewer->getCamera()->getCullMask() & (~Mask_GUI)); @@ -521,10 +531,18 @@ namespace MWRender osg::ref_ptr callback (new NotifyDrawCompletedCallback); rttCamera->setFinalDrawCallback(callback); - mViewer->frame(mViewer->getFrameStamp()->getSimulationTime()); + // at the time this function is called we are in the middle of a frame, + // so out of order calls are necessary to get a correct frameNumber for the next frame. + // refer to the advance() and frame() order in Engine::go() + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); callback->waitTillDone(); + // now that we've "used up" the current frame, get a fresh framenumber for the next frame() following after the screenshot is completed + mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); + rttCamera->removeChildren(0, rttCamera->getNumChildren()); rttCamera->setGraphicsContext(NULL); mRootNode->removeChild(rttCamera); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 12708ba48..5c38d79d4 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1563,17 +1563,15 @@ void SkyManager::setWeather(const WeatherResult& weather) mCloudMesh2->setNodeMask(mCloudBlendFactor > 0.f ? ~0 : 0); } - if (mCloudColour != weather.mSunColor) + if (mCloudColour != weather.mFogColor) { - // FIXME: this doesn't look correct - osg::Vec4f clr( weather.mSunColor.r()*0.7f + weather.mAmbientColor.r()*0.7f, - weather.mSunColor.g()*0.7f + weather.mAmbientColor.g()*0.7f, - weather.mSunColor.b()*0.7f + weather.mAmbientColor.b()*0.7f, 1.f); + osg::Vec4f clr (weather.mFogColor); + clr += osg::Vec4f(0.13f, 0.13f, 0.13f, 0.f); mCloudUpdater->setEmissionColor(clr); mCloudUpdater2->setEmissionColor(clr); - mCloudColour = weather.mSunColor; + mCloudColour = weather.mFogColor; } if (mSkyColour != weather.mSkyColor) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 00eac6ca5..f8f4c64ab 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -115,7 +115,7 @@ add_component_dir (loadinglistener ) add_component_dir (myguiplatform - myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener + myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener additivelayer scalinglayer ) add_component_dir (widgets diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index ccfe6d9ee..c36e3efe0 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -34,19 +34,22 @@ namespace ESMTerrain osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); - assert(origin.x() == (int) origin.x()); - assert(origin.y() == (int) origin.y()); + int cellX = static_cast(std::floor(origin.x())); + int cellY = static_cast(std::floor(origin.y())); - int cellX = static_cast(origin.x()); - int cellY = static_cast(origin.y()); + int startRow = (origin.x() - cellX) * ESM::Land::LAND_SIZE; + int startColumn = (origin.y() - cellY) * ESM::Land::LAND_SIZE; + + int endRow = startRow + size * (ESM::Land::LAND_SIZE-1) + 1; + int endColumn = startColumn + size * (ESM::Land::LAND_SIZE-1) + 1; if (const ESM::Land::LandData *data = getLandData (cellX, cellY, ESM::Land::DATA_VHGT)) { min = std::numeric_limits::max(); max = -std::numeric_limits::max(); - for (int row=0; rowmHeights[col*ESM::Land::LAND_SIZE+row]; if (h > max) @@ -143,11 +146,9 @@ namespace ESMTerrain size_t increment = 1 << lodLevel; osg::Vec2f origin = center - osg::Vec2f(size/2.f, size/2.f); - assert(origin.x() == (int) origin.x()); - assert(origin.y() == (int) origin.y()); - int startX = static_cast(origin.x()); - int startY = static_cast(origin.y()); + int startCellX = static_cast(std::floor(origin.x())); + int startCellY = static_cast(std::floor(origin.y())); size_t numVerts = static_cast(size*(ESM::Land::LAND_SIZE - 1) / increment + 1); @@ -162,10 +163,10 @@ namespace ESMTerrain float vertX = 0; float vertY_ = 0; // of current cell corner - for (int cellY = startY; cellY < startY + std::ceil(size); ++cellY) + for (int cellY = startCellY; cellY < startCellY + std::ceil(size); ++cellY) { float vertX_ = 0; // of current cell corner - for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) + for (int cellX = startCellX; cellX < startCellX + std::ceil(size); ++cellX) { const ESM::Land::LandData *heightData = getLandData (cellX, cellY, ESM::Land::DATA_VHGT); const ESM::Land::LandData *normalData = getLandData (cellX, cellY, ESM::Land::DATA_VNML); @@ -175,18 +176,31 @@ namespace ESMTerrain int colStart = 0; // Skip the first row / column unless we're at a chunk edge, // since this row / column is already contained in a previous cell + // This is only relevant if we're creating a chunk spanning multiple cells if (colStart == 0 && vertY_ != 0) colStart += increment; if (rowStart == 0 && vertX_ != 0) rowStart += increment; + // Only relevant for chunks smaller than (contained in) one cell + rowStart += (origin.x() - startCellX) * ESM::Land::LAND_SIZE; + colStart += (origin.y() - startCellY) * ESM::Land::LAND_SIZE; + int rowEnd = rowStart + std::min(1.f, size) * (ESM::Land::LAND_SIZE-1) + 1; + int colEnd = colStart + std::min(1.f, size) * (ESM::Land::LAND_SIZE-1) + 1; + vertY = vertY_; - for (int col=colStart; col= 0 && row < ESM::Land::LAND_SIZE); + assert(col >= 0 && col < ESM::Land::LAND_SIZE); + + assert (vertX < numVerts); + assert (vertY < numVerts); float height = -2048; if (heightData) @@ -200,7 +214,7 @@ namespace ESMTerrain if (normalData) { for (int i=0; i<3; ++i) - normal[i] = normalData->mNormals[arrayIndex+i]; + normal[i] = normalData->mNormals[srcArrayIndex+i]; normal.normalize(); } @@ -222,7 +236,7 @@ namespace ESMTerrain if (colourData) { for (int i=0; i<3; ++i) - color[i] = colourData->mColours[arrayIndex+i] / 255.f; + color[i] = colourData->mColours[srcArrayIndex+i] / 255.f; } else { @@ -305,8 +319,19 @@ namespace ESMTerrain // and interpolate the rest of the cell by hand? :/ osg::Vec2f origin = chunkCenter - osg::Vec2f(chunkSize/2.f, chunkSize/2.f); - int cellX = static_cast(origin.x()); - int cellY = static_cast(origin.y()); + int cellX = static_cast(std::floor(origin.x())); + int cellY = static_cast(std::floor(origin.y())); + + int realTextureSize = ESM::Land::LAND_TEXTURE_SIZE+1; // add 1 to wrap around next cell + + int rowStart = (origin.x() - cellX) * realTextureSize; + int colStart = (origin.y() - cellY) * realTextureSize; + int rowEnd = rowStart + chunkSize * (realTextureSize-1) + 1; + int colEnd = colStart + chunkSize * (realTextureSize-1) + 1; + + assert (rowStart >= 0 && colStart >= 0); + assert (rowEnd <= realTextureSize); + assert (colEnd <= realTextureSize); // Save the used texture indices so we know the total number of textures // and number of required blend maps @@ -317,8 +342,8 @@ namespace ESMTerrain // So we're always adding _land_default.dds as the base layer here, even if it's not referenced in this cell. textureIndices.insert(std::make_pair(0,0)); - for (int y=0; ysecond; int blendIndex = (pack ? static_cast(std::floor((layerIndex - 1) / 4.f)) : layerIndex - 1); int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0; diff --git a/components/myguiplatform/additivelayer.cpp b/components/myguiplatform/additivelayer.cpp new file mode 100644 index 000000000..aa2ef08b3 --- /dev/null +++ b/components/myguiplatform/additivelayer.cpp @@ -0,0 +1,33 @@ +#include "additivelayer.hpp" + +#include +#include + +#include "myguirendermanager.hpp" + +namespace osgMyGUI +{ + + AdditiveLayer::AdditiveLayer() + { + mStateSet = new osg::StateSet; + mStateSet->setAttributeAndModes(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE)); + } + + AdditiveLayer::~AdditiveLayer() + { + // defined in .cpp file since we can't delete incomplete types + } + + void AdditiveLayer::renderToTarget(MyGUI::IRenderTarget *_target, bool _update) + { + RenderManager& renderManager = static_cast(MyGUI::RenderManager::getInstance()); + + renderManager.setInjectState(mStateSet.get()); + + MyGUI::OverlappedLayer::renderToTarget(_target, _update); + + renderManager.setInjectState(NULL); + } + +} diff --git a/components/myguiplatform/additivelayer.hpp b/components/myguiplatform/additivelayer.hpp new file mode 100644 index 000000000..f3d47bc82 --- /dev/null +++ b/components/myguiplatform/additivelayer.hpp @@ -0,0 +1,33 @@ +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_ADDITIVELAYER +#define OPENMW_COMPONENTS_MYGUIPLATFORM_ADDITIVELAYER + +#include + +#include + +namespace osg +{ + class StateSet; +} + +namespace osgMyGUI +{ + + /// @brief A Layer rendering with additive blend mode. + class AdditiveLayer : public MyGUI::OverlappedLayer + { + public: + MYGUI_RTTI_DERIVED( AdditiveLayer ) + + AdditiveLayer(); + ~AdditiveLayer(); + + virtual void renderToTarget(MyGUI::IRenderTarget* _target, bool _update); + + private: + osg::ref_ptr mStateSet; + }; + +} + +#endif diff --git a/components/myguiplatform/myguiplatform.cpp b/components/myguiplatform/myguiplatform.cpp index 01d6ca567..22b88438f 100644 --- a/components/myguiplatform/myguiplatform.cpp +++ b/components/myguiplatform/myguiplatform.cpp @@ -1,2 +1,64 @@ #include "myguiplatform.hpp" +#include "myguirendermanager.hpp" +#include "myguidatamanager.hpp" +#include "myguiloglistener.hpp" + +namespace osgMyGUI +{ + +Platform::Platform(osgViewer::Viewer *viewer, osg::Group *guiRoot, Resource::TextureManager *textureManager, float uiScalingFactor) + : mRenderManager(nullptr) + , mDataManager(nullptr) + , mLogManager(nullptr) + , mLogFacility(nullptr) +{ + mLogManager = new MyGUI::LogManager(); + mRenderManager = new RenderManager(viewer, guiRoot, textureManager, uiScalingFactor); + mDataManager = new DataManager(); +} + +Platform::~Platform() +{ + delete mRenderManager; + mRenderManager = nullptr; + delete mDataManager; + mDataManager = nullptr; + delete mLogManager; + mLogManager = nullptr; + delete mLogFacility; + mLogFacility = nullptr; +} + +void Platform::initialise(const std::string &resourcePath, const std::string &_logName) +{ + if (!_logName.empty() && !mLogFacility) + { + mLogFacility = new LogFacility(_logName, false); + mLogManager->addLogSource(mLogFacility->getSource()); + } + + mDataManager->setResourcePath(resourcePath); + + mRenderManager->initialise(); + mDataManager->initialise(); +} + +void Platform::shutdown() +{ + mRenderManager->shutdown(); + mDataManager->shutdown(); +} + +RenderManager *Platform::getRenderManagerPtr() +{ + return mRenderManager; +} + +DataManager *Platform::getDataManagerPtr() +{ + return mDataManager; +} + + +} diff --git a/components/myguiplatform/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp index 513267c99..56562e12a 100644 --- a/components/myguiplatform/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -1,71 +1,46 @@ #ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIPLATFORM_H #define OPENMW_COMPONENTS_MYGUIPLATFORM_MYGUIPLATFORM_H -#include "MyGUI_Prerequest.h" -#include "MyGUI_LogManager.h" +#include -#include "myguirendermanager.hpp" -#include "myguidatamanager.hpp" -#include "myguiloglistener.hpp" +namespace osgViewer +{ + class Viewer; +} +namespace osg +{ + class Group; +} +namespace Resource +{ + class TextureManager; +} +namespace MyGUI +{ + class LogManager; +} namespace osgMyGUI { + class RenderManager; + class DataManager; + class LogFacility; + class Platform { public: - Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager, float uiScalingFactor) - : mRenderManager(nullptr) - , mDataManager(nullptr) - , mLogManager(nullptr) - , mLogFacility(nullptr) - { - mLogManager = new MyGUI::LogManager(); - mRenderManager = new RenderManager(viewer, guiRoot, textureManager, uiScalingFactor); - mDataManager = new DataManager(); - } + Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::TextureManager* textureManager, float uiScalingFactor); - ~Platform() - { - delete mRenderManager; - mRenderManager = nullptr; - delete mDataManager; - mDataManager = nullptr; - delete mLogManager; - mLogManager = nullptr; - delete mLogFacility; - mLogFacility = nullptr; - } + ~Platform(); - void initialise(const std::string& resourcePath, const std::string& _logName = "MyGUI.log") - { - if (!_logName.empty() && !mLogFacility) - { - mLogFacility = new LogFacility(_logName, false); - mLogManager->addLogSource(mLogFacility->getSource()); - } + void initialise(const std::string& resourcePath, const std::string& _logName = "MyGUI.log"); - mDataManager->setResourcePath(resourcePath); + void shutdown(); - mRenderManager->initialise(); - mDataManager->initialise(); - } + RenderManager* getRenderManagerPtr(); - void shutdown() - { - mRenderManager->shutdown(); - mDataManager->shutdown(); - } - - RenderManager* getRenderManagerPtr() - { - return mRenderManager; - } - - DataManager* getDataManagerPtr() - { - return mDataManager; - } + DataManager* getDataManagerPtr(); private: RenderManager* mRenderManager; diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 160d659bd..5bd56dc8f 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -45,6 +45,9 @@ namespace osgMyGUI class Drawable : public osg::Drawable { osgMyGUI::RenderManager *mParent; + osg::ref_ptr mStateSet; + +public: // Stage 0: update widget animations and controllers. Run during the Update traversal. class FrameUpdate : public osg::Drawable::UpdateCallback @@ -101,6 +104,10 @@ class Drawable : public osg::Drawable { virtual void drawImplementation(osg::RenderInfo &renderInfo) const { osg::State *state = renderInfo.getState(); + + state->pushStateSet(mStateSet); + state->apply(); + state->disableAllVertexArrays(); state->setClientActiveTextureUnit(0); glEnableClientState(GL_VERTEX_ARRAY); @@ -113,6 +120,13 @@ class Drawable : public osg::Drawable { { const Batch& batch = *it; osg::VertexBufferObject *vbo = batch.mVertexBuffer; + + if (batch.mStateSet) + { + state->pushStateSet(batch.mStateSet); + state->apply(); + } + osg::Texture2D* texture = batch.mTexture; if(texture) state->applyTextureAttribute(0, texture); @@ -135,12 +149,20 @@ class Drawable : public osg::Drawable { } glDrawArrays(GL_TRIANGLES, 0, batch.mVertexCount); + + if (batch.mStateSet) + { + state->popStateSet(); + state->apply(); + } } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); + state->popStateSet(); + state->unbindVertexBufferObject(); state->dirtyAllVertexArrays(); state->disableAllVertexArrays(); @@ -161,10 +183,17 @@ public: osg::ref_ptr frameUpdate = new FrameUpdate; frameUpdate->setRenderManager(mParent); setUpdateCallback(frameUpdate); + + mStateSet = new osg::StateSet; + mStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + mStateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); + mStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + mStateSet->setMode(GL_BLEND, osg::StateAttribute::ON); } Drawable(const Drawable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) : osg::Drawable(copy, copyop) , mParent(copy.mParent) + , mStateSet(copy.mStateSet) , mWriteTo(0) , mReadFrom(0) { @@ -180,6 +209,9 @@ public: // need to hold on to this too as the mVertexBuffer does not hold a ref to its own array osg::ref_ptr mArray; + // optional + osg::ref_ptr mStateSet; + size_t mVertexCount; }; @@ -321,6 +353,7 @@ RenderManager::RenderManager(osgViewer::Viewer *viewer, osg::Group *sceneroot, R , mUpdate(false) , mIsInitialise(false) , mInvScalingFactor(1.f) + , mInjectState(NULL) { if (scalingFactor != 0.f) mInvScalingFactor = 1.f / scalingFactor; @@ -364,12 +397,6 @@ void RenderManager::initialise() camera->setViewMatrix(osg::Matrix::identity()); camera->setRenderOrder(osg::Camera::POST_RENDER); camera->setClearMask(GL_NONE); - osg::StateSet *state = new osg::StateSet; - state->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); - state->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - state->setMode(GL_BLEND, osg::StateAttribute::ON); - state->setAttribute(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - geode->setStateSet(state); geode->setCullingActive(false); camera->addChild(geode.get()); @@ -418,10 +445,17 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text if (batch.mTexture->getDataVariance() == osg::Object::DYNAMIC) mDrawable->setDataVariance(osg::Object::DYNAMIC); // only for this frame, reset in begin() } + if (mInjectState) + batch.mStateSet = mInjectState; mDrawable->addBatch(batch); } +void RenderManager::setInjectState(osg::StateSet* stateSet) +{ + mInjectState = stateSet; +} + void RenderManager::end() { } diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index d9fdc1834..f2251cdb0 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -20,6 +20,7 @@ namespace osg class Group; class Camera; class RenderInfo; + class StateSet; } namespace osgMyGUI @@ -48,6 +49,8 @@ class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget float mInvScalingFactor; + osg::StateSet* mInjectState; + void destroyAllResources(); public: @@ -95,6 +98,9 @@ public: /** @see IRenderTarget::doRender */ virtual void doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count); + /** specify a StateSet to inject for rendering. The StateSet will be used by future doRender calls until you reset it to NULL again. */ + void setInjectState(osg::StateSet* stateSet); + /** @see IRenderTarget::getInfo */ virtual const MyGUI::RenderTargetInfo& getInfo() { return mInfo; } diff --git a/components/myguiplatform/scalinglayer.cpp b/components/myguiplatform/scalinglayer.cpp new file mode 100644 index 000000000..19ae10841 --- /dev/null +++ b/components/myguiplatform/scalinglayer.cpp @@ -0,0 +1,139 @@ +#include "scalinglayer.hpp" + +#include + +namespace osgMyGUI +{ + + /// @brief the ProxyRenderTarget allows to adjust the pixel scale and offset for a "source" render target. + class ProxyRenderTarget : public MyGUI::IRenderTarget + { + public: + /// @param target The target to render to. + /// @param viewSize The size of the underlying layer node to render. + /// @param hoffset The horizontal rendering offset, specified as an offset from the left screen edge in range 0-1. + /// @param voffset The vertical rendering offset, specified as an offset from the top screen edge in range 0-1. + ProxyRenderTarget(MyGUI::IRenderTarget* target, MyGUI::IntSize viewSize, float hoffset, float voffset) + : mTarget(target) + , mViewSize(viewSize) + , mHOffset(hoffset) + , mVOffset(voffset) + { + } + + virtual void begin() + { + mTarget->begin(); + } + + virtual void end() + { + mTarget->end(); + } + + virtual void doRender(MyGUI::IVertexBuffer* _buffer, MyGUI::ITexture* _texture, size_t _count) + { + mTarget->doRender(_buffer, _texture, _count); + } + + virtual const MyGUI::RenderTargetInfo& getInfo() + { + mInfo = mTarget->getInfo(); + mInfo.hOffset = mHOffset; + mInfo.vOffset = mVOffset; + mInfo.pixScaleX = 1.f / mViewSize.width; + mInfo.pixScaleY = 1.f / mViewSize.height; + return mInfo; + } + + private: + MyGUI::IRenderTarget* mTarget; + MyGUI::IntSize mViewSize; + float mHOffset, mVOffset; + MyGUI::RenderTargetInfo mInfo; + }; + + MyGUI::ILayerItem *ScalingLayer::getLayerItemByPoint(int _left, int _top) const + { + screenToLayerCoords(_left, _top); + + return OverlappedLayer::getLayerItemByPoint(_left, _top); + } + + void ScalingLayer::screenToLayerCoords(int& _left, int& _top) const + { + float scale = getScaleFactor(); + if (scale <= 0.f) + return; + + MyGUI::IntSize globalViewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + _left -= globalViewSize.width/2; + _top -= globalViewSize.height/2; + + _left /= scale; + _top /= scale; + + _left += mViewSize.width/2; + _top += mViewSize.height/2; + } + + float ScalingLayer::getScaleFactor() const + { + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + float w = viewSize.width; + float h = viewSize.height; + + float heightScale = (h / mViewSize.height); + float widthScale = (w / mViewSize.width); + return std::min(widthScale, heightScale); + } + + MyGUI::IntPoint ScalingLayer::getPosition(int _left, int _top) const + { + screenToLayerCoords(_left, _top); + return MyGUI::IntPoint(_left, _top); + } + + void ScalingLayer::renderToTarget(MyGUI::IRenderTarget *_target, bool _update) + { + MyGUI::IntSize globalViewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntSize viewSize = globalViewSize; + float scale = getScaleFactor(); + viewSize.width /= scale; + viewSize.height /= scale; + + float hoffset = (globalViewSize.width - mViewSize.width*getScaleFactor())/2.f / static_cast(globalViewSize.width); + float voffset = (globalViewSize.height - mViewSize.height*getScaleFactor())/2.f / static_cast(globalViewSize.height); + + ProxyRenderTarget proxy(_target, viewSize, hoffset, voffset); + + MyGUI::OverlappedLayer::renderToTarget(&proxy, _update); + } + + void ScalingLayer::resizeView(const MyGUI::IntSize &_viewSize) + { + // do nothing + } + + void ScalingLayer::deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version) + { + MyGUI::OverlappedLayer::deserialization(_node, _version); + + MyGUI::xml::ElementEnumerator info = _node->getElementEnumerator(); + while (info.next()) + { + if (info->getName() == "Property") + { + const std::string& key = info->findAttribute("key"); + const std::string& value = info->findAttribute("value"); + + if (key == "Size") + { + mViewSize = MyGUI::IntSize::parse(value); + } + } + } + } + +} diff --git a/components/myguiplatform/scalinglayer.hpp b/components/myguiplatform/scalinglayer.hpp new file mode 100644 index 000000000..3ee1489f1 --- /dev/null +++ b/components/myguiplatform/scalinglayer.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_COMPONENTS_MYGUIPLATFORM_SCALINGLAYER +#define OPENMW_COMPONENTS_MYGUIPLATFORM_SCALINGLAYER + +#include + +namespace osgMyGUI +{ + + ///@brief A Layer that lays out and renders widgets in screen-relative coordinates. The "Size" property determines the size of the virtual screen, + /// which is then upscaled to the real screen size during rendering. The aspect ratio is kept intact, adding blanks to the sides when necessary. + class ScalingLayer : public MyGUI::OverlappedLayer + { + public: + MYGUI_RTTI_DERIVED(ScalingLayer) + + virtual void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version); + + virtual MyGUI::ILayerItem* getLayerItemByPoint(int _left, int _top) const; + virtual MyGUI::IntPoint getPosition(int _left, int _top) const; + virtual void renderToTarget(MyGUI::IRenderTarget* _target, bool _update); + + virtual void resizeView(const MyGUI::IntSize& _viewSize); + + private: + void screenToLayerCoords(int& _left, int& _top) const; + float getScaleFactor() const; + }; + +} + +#endif diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index b652562aa..e62dc00e5 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -76,7 +76,7 @@ namespace SceneUtil struct LightSourceTransform { - osg::ref_ptr mLightSource; + LightSource* mLightSource; osg::Matrix mWorldMatrix; }; @@ -84,7 +84,7 @@ namespace SceneUtil struct LightSourceViewBound { - osg::ref_ptr mLightSource; + LightSource* mLightSource; osg::BoundingSphere mViewBound; }; diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index df45b6ec2..59d06f254 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -11,7 +11,7 @@ namespace Terrain { FixedFunctionTechnique::FixedFunctionTechnique(const std::vector >& layers, - const std::vector >& blendmaps) + const std::vector >& blendmaps, int blendmapScale, float layerTileSize) { bool firstLayer = true; int i=0; @@ -36,7 +36,7 @@ namespace Terrain // This is to map corner vertices directly to the center of a blendmap texel. osg::Matrixf texMat; - float scale = (16/(16.f+1.f)); + float scale = (blendmapScale/(static_cast(blendmapScale)+1.f)); texMat.preMultTranslate(osg::Vec3f(0.5f, 0.5f, 0.f)); texMat.preMultScale(osg::Vec3f(scale, scale, 1.f)); texMat.preMultTranslate(osg::Vec3f(-0.5f, -0.5f, 0.f)); @@ -57,8 +57,7 @@ namespace Terrain stateset->setTextureAttributeAndModes(texunit, tex.get()); osg::ref_ptr texMat (new osg::TexMat); - float scale = 16.f; - texMat->setMatrix(osg::Matrix::scale(osg::Vec3f(scale,scale,1.f))); + texMat->setMatrix(osg::Matrix::scale(osg::Vec3f(layerTileSize,layerTileSize,1.f))); stateset->setTextureAttributeAndModes(texunit, texMat, osg::StateAttribute::ON); firstLayer = false; @@ -67,9 +66,12 @@ namespace Terrain } } - Effect::Effect(const std::vector > &layers, const std::vector > &blendmaps) + Effect::Effect(const std::vector > &layers, const std::vector > &blendmaps, + int blendmapScale, float layerTileSize) : mLayers(layers) , mBlendmaps(blendmaps) + , mBlendmapScale(blendmapScale) + , mLayerTileSize(layerTileSize) { osg::ref_ptr material (new osg::Material); material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); @@ -80,7 +82,7 @@ namespace Terrain bool Effect::define_techniques() { - addTechnique(new FixedFunctionTechnique(mLayers, mBlendmaps)); + addTechnique(new FixedFunctionTechnique(mLayers, mBlendmaps, mBlendmapScale, mLayerTileSize)); return true; } diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index b423aa8b0..dd00e41ed 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -19,7 +19,7 @@ namespace Terrain public: FixedFunctionTechnique( const std::vector >& layers, - const std::vector >& blendmaps); + const std::vector >& blendmaps, int blendmapScale, float layerTileSize); protected: virtual void define_passes() {} @@ -30,7 +30,7 @@ namespace Terrain public: Effect( const std::vector >& layers, - const std::vector >& blendmaps); + const std::vector >& blendmaps, int blendmapScale, float layerTileSize); virtual bool define_techniques(); @@ -50,6 +50,8 @@ namespace Terrain private: std::vector > mLayers; std::vector > mBlendmaps; + int mBlendmapScale; + float mLayerTileSize; }; } diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 5afb99176..732936aa9 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -7,6 +7,8 @@ #include +#include + #include #include #include @@ -45,8 +47,10 @@ namespace Terrain TerrainGrid::TerrainGrid(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, Storage* storage, int nodeMask) : Terrain::World(parent, resourceSystem, ico, storage, nodeMask) + , mNumSplits(4) , mKdTreeBuilder(new osg::KdTreeBuilder) { + mCache = BufferCache((storage->getCellVertices()-1)/static_cast(mNumSplits) + 1); } TerrainGrid::~TerrainGrid() @@ -60,108 +64,144 @@ TerrainGrid::~TerrainGrid() class GridElement { public: - osg::ref_ptr mNode; + osg::ref_ptr mNode; }; +osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter) +{ + if (chunkSize * mNumSplits > 1.f) + { + // keep splitting + osg::ref_ptr group (new osg::Group); + if (parent) + parent->addChild(group); + + float newChunkSize = chunkSize/2.f; + buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, newChunkSize/2.f)); + buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(newChunkSize/2.f, -newChunkSize/2.f)); + buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(-newChunkSize/2.f, newChunkSize/2.f)); + buildTerrain(group, newChunkSize, chunkCenter + osg::Vec2f(-newChunkSize/2.f, -newChunkSize/2.f)); + return group; + } + else + { + float minH, maxH; + if (!mStorage->getMinMaxHeights(chunkSize, chunkCenter, minH, maxH)) + return NULL; // no terrain defined + + osg::Vec2f worldCenter = chunkCenter*mStorage->getCellWorldSize(); + osg::ref_ptr transform (new osg::PositionAttitudeTransform); + transform->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f)); + + if (parent) + parent->addChild(transform); + + osg::ref_ptr positions (new osg::Vec3Array); + osg::ref_ptr normals (new osg::Vec3Array); + osg::ref_ptr colors (new osg::Vec4Array); + + osg::ref_ptr vbo (new osg::VertexBufferObject); + positions->setVertexBufferObject(vbo); + normals->setVertexBufferObject(vbo); + colors->setVertexBufferObject(vbo); + + mStorage->fillVertexBuffers(0, chunkSize, chunkCenter, positions, normals, colors); + + osg::ref_ptr geometry (new osg::Geometry); + geometry->setVertexArray(positions); + geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX); + geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + geometry->setUseDisplayList(false); + geometry->setUseVertexBufferObjects(true); + + geometry->addPrimitiveSet(mCache.getIndexBuffer(0)); + + // we already know the bounding box, so no need to let OSG compute it. + osg::Vec3f min(-0.5f*mStorage->getCellWorldSize()*chunkSize, + -0.5f*mStorage->getCellWorldSize()*chunkSize, + minH); + osg::Vec3f max (0.5f*mStorage->getCellWorldSize()*chunkSize, + 0.5f*mStorage->getCellWorldSize()*chunkSize, + maxH); + osg::BoundingBox bounds(min, max); + geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds)); + + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(geometry); + + + std::vector layerList; + std::vector > blendmaps; + mStorage->getBlendmaps(chunkSize, chunkCenter, false, blendmaps, layerList); + + // For compiling textures, I don't think the osgFX::Effect does it correctly + osg::ref_ptr textureCompileDummy (new osg::Node); + + std::vector > layerTextures; + for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) + { + layerTextures.push_back(mResourceSystem->getTextureManager()->getTexture2D(it->mDiffuseMap, osg::Texture::REPEAT, osg::Texture::REPEAT)); + textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); + } + + std::vector > blendmapTextures; + for (std::vector >::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it) + { + osg::ref_ptr texture (new osg::Texture2D); + texture->setImage(*it); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); + texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + texture->setResizeNonPowerOfTwoHint(false); + blendmapTextures.push_back(texture); + + textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); + } + + // use texture coordinates for both texture units, the layer texture and blend texture + for (unsigned int i=0; i<2; ++i) + geometry->setTexCoordArray(i, mCache.getUVBuffer()); + + float blendmapScale = ESM::Land::LAND_TEXTURE_SIZE*chunkSize; + osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures, blendmapScale, blendmapScale)); + + effect->addCullCallback(new SceneUtil::LightListCallback); + + transform->addChild(effect); + effect->addChild(geode); + + if (mIncrementalCompileOperation) + { + mIncrementalCompileOperation->add(geode); + mIncrementalCompileOperation->add(textureCompileDummy); + } + + return transform; + } +} + void TerrainGrid::loadCell(int x, int y) { if (mGrid.find(std::make_pair(x, y)) != mGrid.end()) return; // already loaded osg::Vec2f center(x+0.5f, y+0.5f); - float minH, maxH; - if (!mStorage->getMinMaxHeights(1, center, minH, maxH)) + + osg::ref_ptr terrainNode = buildTerrain(NULL, 1.f, center); + if (!terrainNode) return; // no terrain defined std::auto_ptr element (new GridElement); - - osg::Vec2f worldCenter = center*mStorage->getCellWorldSize(); - element->mNode = new osg::PositionAttitudeTransform; - element->mNode->setPosition(osg::Vec3f(worldCenter.x(), worldCenter.y(), 0.f)); + element->mNode = terrainNode; mTerrainRoot->addChild(element->mNode); - osg::ref_ptr positions (new osg::Vec3Array); - osg::ref_ptr normals (new osg::Vec3Array); - osg::ref_ptr colors (new osg::Vec4Array); - - osg::ref_ptr vbo (new osg::VertexBufferObject); - positions->setVertexBufferObject(vbo); - normals->setVertexBufferObject(vbo); - colors->setVertexBufferObject(vbo); - - mStorage->fillVertexBuffers(0, 1, center, positions, normals, colors); - - osg::ref_ptr geometry (new osg::Geometry); - geometry->setVertexArray(positions); - geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX); - geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX); - geometry->setUseDisplayList(false); - geometry->setUseVertexBufferObjects(true); - - geometry->addPrimitiveSet(mCache.getIndexBuffer(0)); - - // we already know the bounding box, so no need to let OSG compute it. - osg::Vec3f min(-0.5f*mStorage->getCellWorldSize(), - -0.5f*mStorage->getCellWorldSize(), - minH); - osg::Vec3f max (0.5f*mStorage->getCellWorldSize(), - 0.5f*mStorage->getCellWorldSize(), - maxH); - osg::BoundingBox bounds(min, max); - geometry->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(bounds)); - - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(geometry); - + // kdtree probably not needed with mNumSplits=4 + /* // build a kdtree to speed up intersection tests with the terrain // Note, the build could be optimized using a custom kdtree builder, since we know that the terrain can be represented by a quadtree geode->accept(*mKdTreeBuilder); - - std::vector layerList; - std::vector > blendmaps; - mStorage->getBlendmaps(1.f, center, false, blendmaps, layerList); - - // For compiling textures, I don't think the osgFX::Effect does it correctly - osg::ref_ptr textureCompileDummy (new osg::Node); - - std::vector > layerTextures; - for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) - { - layerTextures.push_back(mResourceSystem->getTextureManager()->getTexture2D(it->mDiffuseMap, osg::Texture::REPEAT, osg::Texture::REPEAT)); - textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); - } - - std::vector > blendmapTextures; - for (std::vector >::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it) - { - osg::ref_ptr texture (new osg::Texture2D); - texture->setImage(*it); - texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); - texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); - texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); - texture->setResizeNonPowerOfTwoHint(false); - blendmapTextures.push_back(texture); - - textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(0, layerTextures.back()); - } - - // use texture coordinates for both texture units, the layer texture and blend texture - for (unsigned int i=0; i<2; ++i) - geometry->setTexCoordArray(i, mCache.getUVBuffer()); - - osg::ref_ptr effect (new Terrain::Effect(layerTextures, blendmapTextures)); - - effect->addCullCallback(new SceneUtil::LightListCallback); - - effect->addChild(geode); - element->mNode->addChild(effect); - - if (mIncrementalCompileOperation) - { - mIncrementalCompileOperation->add(geode); - mIncrementalCompileOperation->add(textureCompileDummy); - } + */ mGrid[std::make_pair(x,y)] = element.release(); } diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 832b952e8..169a9a622 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -1,6 +1,8 @@ #ifndef COMPONENTS_TERRAIN_TERRAINGRID_H #define COMPONENTS_TERRAIN_TERRAINGRID_H +#include + #include "world.hpp" #include "material.hpp" @@ -26,6 +28,11 @@ namespace Terrain virtual void unloadCell(int x, int y); private: + osg::ref_ptr buildTerrain (osg::Group* parent, float chunkSize, const osg::Vec2f& chunkCenter); + + // split each ESM::Cell into mNumSplits*mNumSplits terrain chunks + unsigned int mNumSplits; + typedef std::map, GridElement*> Grid; Grid mGrid; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index dc9e8ea84..7494d3ba2 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -80,6 +80,7 @@ set(MYGUI_FILES openmw_savegame_dialog.layout openmw_recharge_dialog.layout openmw_screen_fader.layout + openmw_screen_fader_hit.layout openmw_edit_note.layout openmw_debug_window.layout openmw_debug_window.skin.xml diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index 2336d5b2c..7c158af8d 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 97b018469..03c05260f 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -125,11 +125,5 @@ - - - - - - diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index 5524f5520..9c40bd562 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index cf577aec5..c6d3df521 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -1,10 +1,14 @@ - + + + + + @@ -12,6 +16,6 @@ - + diff --git a/files/mygui/openmw_screen_fader.layout b/files/mygui/openmw_screen_fader.layout index 13234792f..e9009d32a 100644 --- a/files/mygui/openmw_screen_fader.layout +++ b/files/mygui/openmw_screen_fader.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_screen_fader_hit.layout b/files/mygui/openmw_screen_fader_hit.layout new file mode 100644 index 000000000..7e60f0ff5 --- /dev/null +++ b/files/mygui/openmw_screen_fader_hit.layout @@ -0,0 +1,7 @@ + + + + + + + diff --git a/files/mygui/openmw_scroll.layout b/files/mygui/openmw_scroll.layout index 194700f36..b2e62f28d 100644 --- a/files/mygui/openmw_scroll.layout +++ b/files/mygui/openmw_scroll.layout @@ -2,24 +2,24 @@ - + - + - + - + diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index e76c3a7db..22d36de2b 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -255,13 +255,9 @@ - - - - - - + + @@ -271,6 +267,12 @@ + + + + + + @@ -392,7 +394,11 @@ + + + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index e459f22fa..b7a893580 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -18,15 +18,6 @@ color_misc=0,205,205 # ???? - - - - - - - - - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7c809b926..d68bc2fef 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -84,11 +84,6 @@ fade start = 0.8 debug = false [HUD] -# FPS counter -# 0: not visible -# 1: FPS display -fps = 0 - crosshair = true [Objects]