diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 7d66b2aba..9fa5e38a2 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,10 +22,10 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode - bulletdebugdraw globalmap + bulletdebugdraw globalmap characterpreview # camera # localmap occlusionquery water shadows -# characterpreview ripplesimulation refraction +# ripplesimulation refraction # terrainstorage weaponanimation ) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index fb00d6a98..73b950a6a 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -60,8 +60,10 @@ namespace namespace MWGui { - CharacterCreation::CharacterCreation() - : mNameDialog(0) + CharacterCreation::CharacterCreation(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) + : mViewer(viewer) + , mResourceSystem(resourceSystem) + , mNameDialog(0) , mRaceDialog(0) , mClassChoiceDialog(0) , mGenerateClassQuestionDialog(0) @@ -146,7 +148,7 @@ namespace MWGui case GM_Race: MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; - mRaceDialog = new RaceDialog(); + mRaceDialog = new RaceDialog(mViewer, mResourceSystem); mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); mRaceDialog->setRaceId(mPlayerRaceId); mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); @@ -261,12 +263,6 @@ namespace MWGui } } - void CharacterCreation::doRenderUpdate() - { - if (mRaceDialog) - mRaceDialog->doRenderUpdate(); - } - void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) { MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index a4515569d..f6e7c6c92 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -8,6 +8,16 @@ #include "../mwmechanics/stat.hpp" +namespace osgViewer +{ + class Viewer; +} + +namespace Resource +{ + class ResourceSystem; +} + namespace MWGui { class WindowBase; @@ -29,7 +39,7 @@ namespace MWGui public: typedef std::vector SkillList; - CharacterCreation(); + CharacterCreation(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem); ~CharacterCreation(); //Show a dialog @@ -39,9 +49,11 @@ namespace MWGui void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value); void configureSkills (const SkillList& major, const SkillList& minor); - void doRenderUpdate(); private: + osgViewer::Viewer* mViewer; + Resource::ResourceSystem* mResourceSystem; + //Dialogs TextInputDialog* mNameDialog; RaceDialog* mRaceDialog; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index cbce86650..a225b4e11 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -8,6 +8,10 @@ #include #include +#include + +#include + #include #include "../mwbase/world.hpp" @@ -48,22 +52,23 @@ namespace namespace MWGui { - InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop) + InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop, osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) : WindowPinnableBase("openmw_inventory_window.layout") , mTrading(false) , mLastXSize(0) , mLastYSize(0) - #if 0 - , mPreview(new MWRender::InventoryPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr())) - #endif - , mPreviewDirty(true) - , mPreviewResize(true) + , mViewer(viewer) + , mResourceSystem(resourceSystem) + , mPreview(new MWRender::InventoryPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr())) , mDragAndDrop(dragAndDrop) , mSortModel(NULL) , mTradeModel(NULL) , mSelectedItem(-1) , mGuiMode(GM_Inventory) { + mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture())); + mPreview->rebuild(); + mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); getWidget(mAvatar, "Avatar"); @@ -79,6 +84,8 @@ namespace MWGui getWidget(mArmorRating, "ArmorRating"); mAvatarImage->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked); + mAvatarImage->setRenderItemTexture(mPreviewTexture.get()); + mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); getWidget(mItemView, "ItemView"); mItemView->eventItemClicked += MyGUI::newDelegate(this, &InventoryWindow::onItemSelected); @@ -115,17 +122,13 @@ namespace MWGui mSortModel = new SortFilterItemModel(mTradeModel); mItemView->setModel(mSortModel); - mPreview.reset(NULL); - mAvatarImage->setImageTexture(""); -#if 0 - MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("CharacterPreview"); - if (tex) - MyGUI::RenderManager::getInstance().destroyTexture(tex); - mPreview.reset(new MWRender::InventoryPreview(mPtr)); - mPreview->setup(); -#endif - mPreviewDirty = true; - mPreviewResize = true; + mPreview->updatePtr(mPtr); + mPreview->rebuild(); + mPreview->update(); + + dirtyPreview(); + + updatePreviewSize(); } void InventoryWindow::setGuiMode(GuiMode mode) @@ -158,7 +161,7 @@ namespace MWGui static_cast(Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height)); if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight()) - mPreviewResize = true; + updatePreviewSize(); mMainWidget->setPosition(pos); mMainWidget->setSize(size); @@ -319,7 +322,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->updateSpellWindow(); mItemView->update(); - mPreviewDirty = true; + + dirtyPreview(); } void InventoryWindow::open() @@ -366,10 +370,31 @@ namespace MWGui { mLastXSize = mMainWidget->getSize().width; mLastYSize = mMainWidget->getSize().height; - mPreviewResize = true; + + updatePreviewSize(); + updateArmorRating(); } } + void InventoryWindow::updateArmorRating() + { + mArmorRating->setCaptionWithReplacing ("#{sArmor}: " + + MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); + if (mArmorRating->getTextSize().width > mArmorRating->getSize().width) + mArmorRating->setCaptionWithReplacing (MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); + } + + void InventoryWindow::updatePreviewSize() + { + MyGUI::IntSize size = mAvatarImage->getSize(); + int width = std::min(mPreview->getTextureWidth(), size.width); + int height = std::min(mPreview->getTextureHeight(), size.height); + mPreview->setViewport(width, height); + + mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, height/float(mPreview->getTextureHeight()), + width/float(mPreview->getTextureWidth()), 0.f)); + } + void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender) { if (_sender == mFilterAll) @@ -483,8 +508,6 @@ namespace MWGui MWWorld::Ptr InventoryWindow::getAvatarSelectedItem(int x, int y) { - return MWWorld::Ptr(); -#if 0 int slot = mPreview->getSlotSelected (x, y); if (slot == -1) @@ -503,7 +526,6 @@ namespace MWGui } return MWWorld::Ptr(); -#endif } void InventoryWindow::updateEncumbranceBar() @@ -529,36 +551,11 @@ namespace MWGui mTrading = trading; } - void InventoryWindow::doRenderUpdate () + void InventoryWindow::dirtyPreview() { -#if 0 - mPreview->onFrame(); - - if (mPreviewResize || mPreviewDirty) - { - mArmorRating->setCaptionWithReplacing ("#{sArmor}: " - + MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); - if (mArmorRating->getTextSize().width > mArmorRating->getSize().width) - mArmorRating->setCaptionWithReplacing (MyGUI::utility::toString(static_cast(mPtr.getClass().getArmorRating(mPtr)))); - } - if (mPreviewResize) - { - mPreviewResize = false; - MyGUI::IntSize size = mAvatarImage->getSize(); - mPreview->resize(size.width, size.height); - - mAvatarImage->setImageTexture("CharacterPreview"); - mAvatarImage->setImageCoord(MyGUI::IntCoord(0, 0, std::min(512, size.width), std::min(1024, size.height))); - mAvatarImage->setImageTile(MyGUI::IntSize(std::min(512, size.width), std::min(1024, size.height))); - } - if (mPreviewDirty) - { - mPreviewDirty = false; - mPreview->update (); + mPreview->update(); - mAvatarImage->setImageTexture("CharacterPreview"); - } -#endif + updateArmorRating(); } void InventoryWindow::notifyContentChanged() @@ -569,7 +566,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->updateMagicEffects( MWBase::Environment::get().getWorld()->getPlayerPtr()); - mPreviewDirty = true; + dirtyPreview(); } void InventoryWindow::pickUpObject (MWWorld::Ptr object) @@ -675,8 +672,6 @@ namespace MWGui void InventoryWindow::rebuildAvatar() { -#if 0 mPreview->rebuild(); -#endif } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index ee71d9b04..fc579ae62 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -6,6 +6,16 @@ #include "../mwworld/ptr.hpp" +namespace osgViewer +{ + class Viewer; +} + +namespace Resource +{ + class ResourceSystem; +} + namespace MWRender { class InventoryPreview; @@ -27,12 +37,10 @@ namespace MWGui class InventoryWindow : public WindowPinnableBase { public: - InventoryWindow(DragAndDrop* dragAndDrop); + InventoryWindow(DragAndDrop* dragAndDrop, osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem); virtual void open(); - void doRenderUpdate(); - /// start trading, disables item drag&drop void setTrading(bool trading); @@ -62,8 +70,6 @@ namespace MWGui private: DragAndDrop* mDragAndDrop; - bool mPreviewDirty; - bool mPreviewResize; int mSelectedItem; MWWorld::Ptr mPtr; @@ -93,6 +99,10 @@ namespace MWGui int mLastXSize; int mLastYSize; + Resource::ResourceSystem* mResourceSystem; + osgViewer::Viewer* mViewer; + + std::auto_ptr mPreviewTexture; std::auto_ptr mPreview; bool mTrading; @@ -113,6 +123,9 @@ namespace MWGui void updateEncumbranceBar(); void notifyContentChanged(); + void dirtyPreview(); + void updatePreviewSize(); + void updateArmorRating(); void adjustPanes(); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index af4332c7c..a65379fca 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -5,8 +5,12 @@ #include #include +#include + #include +#include + #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -37,8 +41,10 @@ namespace namespace MWGui { - RaceDialog::RaceDialog() + RaceDialog::RaceDialog(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) : WindowModal("openmw_chargen_race.layout") + , mViewer(viewer) + , mResourceSystem(resourceSystem) , mGenderIndex(0) , mFaceIndex(0) , mHairIndex(0) @@ -125,19 +131,20 @@ namespace MWGui updateSkills(); updateSpellPowers(); - //mPreview.reset(NULL); + mPreviewImage->setRenderItemTexture(NULL); - mPreviewImage->setImageTexture(""); + mPreview.reset(NULL); + mPreviewTexture.reset(NULL); - const std::string textureName = "CharacterHeadPreview"; - MyGUI::RenderManager::getInstance().destroyTexture(MyGUI::RenderManager::getInstance().getTexture(textureName)); + mPreview.reset(new MWRender::RaceSelectionPreview(mViewer, mResourceSystem)); + mPreview->rebuild(); + mPreview->setAngle (mCurrentAngle); - //mPreview.reset(new MWRender::RaceSelectionPreview()); - //mPreview->setup(); - //mPreview->update (mCurrentAngle); + mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture())); + mPreviewImage->setRenderItemTexture(mPreviewTexture.get()); + mPreviewImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f)); - //const ESM::NPC& proto = mPreview->getPrototype(); - ESM::NPC proto; + const ESM::NPC& proto = mPreview->getPrototype(); setRaceId(proto.mRace); recountParts(); @@ -153,8 +160,6 @@ namespace MWGui mHairIndex = i; } - mPreviewImage->setImageTexture (textureName); - mPreviewDirty = true; size_t initialPos = mHeadRotate->getScrollRange()/2+mHeadRotate->getScrollRange()/10; @@ -182,10 +187,10 @@ namespace MWGui void RaceDialog::close() { - mPreviewImage->setImageTexture(""); - const std::string textureName = "CharacterHeadPreview"; - MyGUI::RenderManager::getInstance().destroyTexture(MyGUI::RenderManager::getInstance().getTexture(textureName)); - //mPreview.reset(NULL); + mPreviewImage->setRenderItemTexture(NULL); + + mPreviewTexture.reset(NULL); + mPreview.reset(NULL); } // widget controls @@ -205,8 +210,8 @@ namespace MWGui void RaceDialog::onHeadRotate(MyGUI::ScrollBar* scroll, size_t _position) { float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5f) * 3.14f * 2; - //mPreview->update (angle); - mPreviewDirty = true; + mPreview->setAngle (angle); + mCurrentAngle = angle; } @@ -317,7 +322,7 @@ namespace MWGui void RaceDialog::updatePreview() { - ESM::NPC record;// = mPreview->getPrototype(); + ESM::NPC record = mPreview->getPrototype(); record.mRace = mCurrentRaceId; record.setIsMale(mGenderIndex == 0); @@ -326,27 +331,12 @@ namespace MWGui try { - //mPreview->setPrototype(record); + mPreview->setPrototype(record); } catch (std::exception& e) { std::cerr << "Error creating preview: " << e.what() << std::endl; } - - mPreviewDirty = true; - } - - void RaceDialog::doRenderUpdate() - { - //if (!mPreview.get()) - return; - - //mPreview->onFrame(); - if (mPreviewDirty) - { - //mPreview->render(); - mPreviewDirty = false; - } } void RaceDialog::updateRaces() @@ -451,8 +441,6 @@ namespace MWGui const ESM::NPC& RaceDialog::getResult() const { - static ESM::NPC result; - return result; - //return mPreview->getPrototype(); + return mPreview->getPrototype(); } } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index f188af2b3..b3de9bef0 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -19,12 +19,22 @@ namespace ESM struct NPC; } +namespace osgViewer +{ + class Viewer; +} + +namespace Resource +{ + class ResourceSystem; +} + namespace MWGui { class RaceDialog : public WindowModal { public: - RaceDialog(); + RaceDialog(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem); enum Gender { @@ -35,13 +45,9 @@ namespace MWGui const ESM::NPC &getResult() const; const std::string &getRaceId() const { return mCurrentRaceId; } Gender getGender() const { return mGenderIndex == 0 ? GM_Male : GM_Female; } - // getFace() - // getHair() void setRaceId(const std::string &raceId); void setGender(Gender gender) { mGenderIndex = gender == GM_Male ? 0 : 1; } - // setFace() - // setHair() void setNextButtonShow(bool shown); virtual void open(); @@ -60,8 +66,6 @@ namespace MWGui */ EventHandle_WindowBase eventDone; - void doRenderUpdate(); - protected: void onHeadRotate(MyGUI::ScrollBar* _sender, size_t _position); @@ -89,6 +93,9 @@ namespace MWGui void getBodyParts (int part, std::vector& out); + osgViewer::Viewer* mViewer; + Resource::ResourceSystem* mResourceSystem; + std::vector mAvailableHeads; std::vector mAvailableHairs; @@ -108,7 +115,8 @@ namespace MWGui float mCurrentAngle; - //std::auto_ptr mPreview; + std::auto_ptr mPreview; + std::auto_ptr mPreviewTexture; bool mPreviewDirty; }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 0a9e86750..5649908fc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -275,7 +275,7 @@ namespace MWGui mJournal = JournalWindow::create(JournalViewModel::create ()); mMessageBoxManager = new MessageBoxManager( MWBase::Environment::get().getWorld()->getStore().get().find("fMessageTimePerChar")->getFloat()); - mInventoryWindow = new InventoryWindow(mDragAndDrop); + mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer, mResourceSystem); mTradeWindow = new TradeWindow(); trackWindow(mTradeWindow, "barter"); mSpellBuyingWindow = new SpellBuyingWindow(); @@ -324,7 +324,7 @@ namespace MWGui mHud->setVisible(mHudEnabled); - mCharGen = new CharacterCreation(); + mCharGen = new CharacterCreation(mViewer, mResourceSystem); // Setup player stats for (int i = 0; i < ESM::Attribute::Length; ++i) @@ -358,7 +358,7 @@ namespace MWGui { disallowAll(); delete mCharGen; - mCharGen = new CharacterCreation(); + mCharGen = new CharacterCreation(mViewer, mResourceSystem); mGuiModes.clear(); MWBase::Environment::get().getInputManager()->changeInputMode(false); mHud->unsetSelectedWeapon(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c0cddb4d0..3a0f543d9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1081,12 +1081,21 @@ namespace MWRender return true; } - bool Animation::hasNode(const std::string &name) + bool Animation::hasNode(const std::string &name) const { std::string lowerName = Misc::StringUtils::lowerCase(name); return (mNodeMap.find(lowerName) != mNodeMap.end()); } + const osg::Node* Animation::getNode(const std::string &name) const + { + std::string lowerName = Misc::StringUtils::lowerCase(name); + NodeMap::const_iterator found = mNodeMap.find(lowerName); + if (found == mNodeMap.end()) + throw std::runtime_error("Can't find node " + name); + return found->second; + } + float Animation::AnimationTime::getValue(osg::NodeVisitor*) { if (mTimePtr) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index a12375a9b..0c490b525 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -354,7 +354,11 @@ public: /// Is there a node with the specified name? /// @note The matching is case-insensitive. - bool hasNode(const std::string& name); + bool hasNode(const std::string& name) const; + + /// Return a node with the specified name, throws an exception if the node is not found. + /// @note The matching is case-insensitive. + const osg::Node* getNode(const std::string& name) const; virtual void showWeapons(bool showWeapon) {} virtual void showCarriedLeft(bool show) {} diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 7d61e3b6c..1a7b4ea39 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -1,189 +1,186 @@ #include "characterpreview.hpp" -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include +#include +#include +#include +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "renderconst.hpp" #include "npcanimation.hpp" namespace MWRender { - CharacterPreview::CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, - Ogre::Vector3 position, Ogre::Vector3 lookAt) - : mRecover(false) - , mRenderTarget(NULL) - , mViewport(NULL) - , mCamera(NULL) - , mSceneMgr (0) - , mNode(NULL) + class DrawOnceCallback : public osg::NodeCallback + { + public: + DrawOnceCallback () + : mRendered(false) + { + } + + virtual void operator () (osg::Node* node, osg::NodeVisitor* nv) + { + if (!mRendered) + { + mRendered = true; + } + else + { + node->setNodeMask(0); + } + + traverse(node, nv); + } + + void redrawNextFrame() + { + mRendered = false; + } + + private: + bool mRendered; + }; + + CharacterPreview::CharacterPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, + MWWorld::Ptr character, int sizeX, int sizeY, const osg::Vec3f& position, const osg::Vec3f& lookAt) + : mViewer(viewer) + , mResourceSystem(resourceSystem) , mPosition(position) , mLookAt(lookAt) , mCharacter(character) , mAnimation(NULL) - , mName(name) , mSizeX(sizeX) , mSizeY(sizeY) { + mTexture = new osg::Texture2D; + mTexture->setTextureSize(sizeX, sizeY); + mTexture->setInternalFormat(GL_RGBA); + mTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + mTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); + + mCamera = new osg::Camera; + // hints that the camera is not relative to the master camera + mCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + mCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); + mCamera->setClearColor(osg::Vec4(0.f, 0.f, 0.f, 0.f)); + mCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + const float fovYDegrees = 12.3f; + mCamera->setProjectionMatrixAsPerspective(fovYDegrees, sizeX/static_cast(sizeY), 0.1f, 10000.f); // zNear and zFar are autocomputed + mCamera->setViewport(0, 0, sizeX, sizeY); + mCamera->setRenderOrder(osg::Camera::PRE_RENDER); + mCamera->attach(osg::Camera::COLOR_BUFFER, mTexture); + mCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); + + osg::ref_ptr lightManager = new SceneUtil::LightManager; + lightManager->setStartLight(1); + osg::ref_ptr stateset = new osg::StateSet; + stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON); + stateset->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + + osg::ref_ptr lightmodel = new osg::LightModel; + lightmodel->setAmbientIntensity(osg::Vec4(0.25, 0.25, 0.25, 1.0)); + stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); + + /// \todo Read the fallback values from INIImporter (Inventory:Directional*) ? + osg::ref_ptr light = new osg::Light; + light->setPosition(osg::Vec4(-0.3,0.3,0.7, 0.0)); + light->setDiffuse(osg::Vec4(1,1,1,1)); + light->setAmbient(osg::Vec4(0,0,0,1)); + light->setSpecular(osg::Vec4(0,0,0,0)); + light->setLightNum(0); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + + osg::ref_ptr lightSource = new osg::LightSource; + lightSource->setLight(light); + + lightSource->setStateSetModes(*stateset, osg::StateAttribute::ON); + + lightManager->setStateSet(stateset); + lightManager->addChild(lightSource); + + mCamera->addChild(lightManager); + + mNode = new osg::PositionAttitudeTransform; + lightManager->addChild(mNode); + + mDrawOnceCallback = new DrawOnceCallback; + mCamera->addUpdateCallback(mDrawOnceCallback); + + mViewer->getSceneData()->asGroup()->addChild(mCamera); + mCharacter.mCell = NULL; } - void CharacterPreview::onSetup() + CharacterPreview::~CharacterPreview () { - + mViewer->getSceneData()->asGroup()->removeChild(mCamera); } - void CharacterPreview::onFrame() + int CharacterPreview::getTextureWidth() const { - if (mRecover) - { - setupRenderTarget(); - mRenderTarget->update(); - mRecover = false; - } + return mSizeX; } - void CharacterPreview::setup () + int CharacterPreview::getTextureHeight() const { - mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); - - // This is a dummy light to turn off shadows without having to use a separate set of shaders - Ogre::Light* l = mSceneMgr->createLight(); - l->setType (Ogre::Light::LT_DIRECTIONAL); - l->setDiffuseColour (Ogre::ColourValue(0,0,0)); - - /// \todo Read the fallback values from INIImporter (Inventory:Directional*) - l = mSceneMgr->createLight(); - l->setType (Ogre::Light::LT_DIRECTIONAL); - l->setDirection (Ogre::Vector3(0.3f, -0.7f, 0.3f)); - l->setDiffuseColour (Ogre::ColourValue(1,1,1)); - - mSceneMgr->setAmbientLight (Ogre::ColourValue(0.25, 0.25, 0.25)); - - mCamera = mSceneMgr->createCamera (mName); - mCamera->setFOVy(Ogre::Degree(12.3f)); - mCamera->setAspectRatio (float(mSizeX) / float(mSizeY)); - - Ogre::SceneNode* renderRoot = mSceneMgr->getRootSceneNode()->createChildSceneNode("renderRoot"); - - // leftover of old coordinate system. TODO: remove this and adjust positions/orientations to match - renderRoot->pitch(Ogre::Degree(-90)); - - mNode = renderRoot->createChildSceneNode(); - - mAnimation = new NpcAnimation(mCharacter, mNode, - 0, true, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); - - Ogre::Vector3 scale = mNode->getScale(); - mCamera->setPosition(mPosition * scale); - mCamera->lookAt(mLookAt * scale); - - mCamera->setNearClipDistance (1); - mCamera->setFarClipDistance (1000); - - mTexture = Ogre::TextureManager::getSingleton().createManual(mName, - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mSizeX, mSizeY, 0, Ogre::PF_A8R8G8B8, Ogre::TU_RENDERTARGET, this); - - setupRenderTarget(); + return mSizeY; + } - onSetup (); + void CharacterPreview::onSetup() + { } - CharacterPreview::~CharacterPreview () + osg::ref_ptr CharacterPreview::getTexture() { - if (mSceneMgr) - { - mSceneMgr->destroyAllCameras(); - delete mAnimation; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); - Ogre::TextureManager::getSingleton().remove(mName); - } + return mTexture; } void CharacterPreview::rebuild() { delete mAnimation; mAnimation = NULL; - mAnimation = new NpcAnimation(mCharacter, mNode, - 0, true, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); - - float scale=1.f; - mCharacter.getClass().adjustScale(mCharacter, scale); - mNode->setScale(Ogre::Vector3(scale)); - mCamera->setPosition(mPosition * mNode->getScale()); - mCamera->lookAt(mLookAt * mNode->getScale()); + mAnimation = new NpcAnimation(mCharacter, mNode, mResourceSystem, 0, true, true, + (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); onSetup(); - } - - void CharacterPreview::loadResource(Ogre::Resource *resource) - { - Ogre::Texture* tex = dynamic_cast(resource); - if (!tex) - return; - - tex->createInternalResources(); - mRenderTarget = NULL; - mViewport = NULL; - mRecover = true; + redraw(); } - void CharacterPreview::setupRenderTarget() + void CharacterPreview::redraw() { - mRenderTarget = mTexture->getBuffer()->getRenderTarget(); - mRenderTarget->removeAllViewports (); - mViewport = mRenderTarget->addViewport(mCamera); - mViewport->setOverlaysEnabled(false); - mViewport->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0)); - mViewport->setShadowsEnabled(false); - mRenderTarget->setActive(true); - mRenderTarget->setAutoUpdated (false); + mCamera->setNodeMask(~0); + mDrawOnceCallback->redrawNextFrame(); } // -------------------------------------------------------------------------------------------------- - InventoryPreview::InventoryPreview(MWWorld::Ptr character) - : CharacterPreview(character, 512, 1024, "CharacterPreview", Ogre::Vector3(0, 71, -700), Ogre::Vector3(0,71,0)) - , mSizeX(0) - , mSizeY(0) - , mSelectionBuffer(NULL) + InventoryPreview::InventoryPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, MWWorld::Ptr character) + : CharacterPreview(viewer, resourceSystem, character, 512, 1024, osg::Vec3f(0, 700, 71), osg::Vec3f(0,0,71)) { } - InventoryPreview::~InventoryPreview() + void InventoryPreview::setViewport(int sizeX, int sizeY) { - delete mSelectionBuffer; - } - - void InventoryPreview::resize(int sizeX, int sizeY) - { - mSizeX = sizeX; - mSizeY = sizeY; + sizeX = std::max(sizeX, 0); + sizeY = std::max(sizeY, 0); - mViewport->setDimensions (0, 0, std::min(1.f, float(mSizeX) / float(512)), std::min(1.f, float(mSizeY) / float(1024))); - mTexture->load(); + mCamera->setViewport(0, 0, std::min(mSizeX, sizeX), std::min(mSizeY, sizeY)); - if (!mRenderTarget) - setupRenderTarget(); - - mRenderTarget->update(); + redraw(); } void InventoryPreview::update() @@ -191,6 +188,7 @@ namespace MWRender if (!mAnimation) return; + mAnimation->showWeapons(true); mAnimation->updateParts(); MWWorld::InventoryStore &inv = mCharacter.getClass().getInventoryStore(mCharacter); @@ -250,70 +248,51 @@ namespace MWRender mAnimation->runAnimation(0.0f); - mNode->setOrientation (Ogre::Quaternion::IDENTITY); - - mViewport->setDimensions (0, 0, std::min(1.f, float(mSizeX) / float(512)), std::min(1.f, float(mSizeY) / float(1024))); - mTexture->load(); - - if (!mRenderTarget) - setupRenderTarget(); - - mRenderTarget->update(); - - mSelectionBuffer->update(); + redraw(); } - void InventoryPreview::setupRenderTarget() + int InventoryPreview::getSlotSelected (int posX, int posY) { - CharacterPreview::setupRenderTarget(); - mViewport->setDimensions (0, 0, std::min(1.f, float(mSizeX) / float(512)), std::min(1.f, float(mSizeY) / float(1024))); + // TODO: implement + return 0; } - int InventoryPreview::getSlotSelected (int posX, int posY) + void InventoryPreview::updatePtr(const MWWorld::Ptr &ptr) { - return mSelectionBuffer->getSelected (posX, posY); + mCharacter = MWWorld::Ptr(ptr.getBase(), NULL); } - void InventoryPreview::onSetup () + void InventoryPreview::onSetup() { - delete mSelectionBuffer; - mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); + osg::Vec3f scale (1.f, 1.f, 1.f); + mCharacter.getClass().adjustScale(mCharacter, scale); - mAnimation->showWeapons(true); + mNode->setScale(scale); - mCurrentAnimGroup = "inventoryhandtohand"; - mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + mCamera->setViewMatrixAsLookAt(mPosition * scale.z(), mLookAt * scale.z(), osg::Vec3f(0,0,1)); } // -------------------------------------------------------------------------------------------------- - RaceSelectionPreview::RaceSelectionPreview() - : CharacterPreview(MWBase::Environment::get().getWorld()->getPlayerPtr(), - 512, 512, "CharacterHeadPreview", Ogre::Vector3(0, 8, -125), Ogre::Vector3(0,127,0)) + RaceSelectionPreview::RaceSelectionPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem) + : CharacterPreview(viewer, resourceSystem, MWBase::Environment::get().getWorld()->getPlayerPtr(), + 512, 512, osg::Vec3f(0, 125, 8), osg::Vec3f(0,0,8)) , mBase (*mCharacter.get()->mBase) , mRef(&mBase) - , mPitch(Ogre::Degree(6)) + , mPitchRadians(osg::DegreesToRadians(6.f)) { mCharacter = MWWorld::Ptr(&mRef, NULL); } - void RaceSelectionPreview::update(float angle) + RaceSelectionPreview::~RaceSelectionPreview() { - mAnimation->runAnimation(0.0f); - - mNode->setOrientation(Ogre::Quaternion(Ogre::Radian(angle), Ogre::Vector3::UNIT_Z) - * Ogre::Quaternion(mPitch, Ogre::Vector3::UNIT_X)); - - updateCamera(); } - void RaceSelectionPreview::render() + void RaceSelectionPreview::setAngle(float angleRadians) { - mTexture->load(); - - if (!mRenderTarget) - setupRenderTarget(); - mRenderTarget->update(); + mNode->setAttitude(osg::Quat(mPitchRadians, osg::Vec3(1,0,0)) + * osg::Quat(angleRadians, osg::Vec3(0,0,1))); + redraw(); } void RaceSelectionPreview::setPrototype(const ESM::NPC &proto) @@ -321,27 +300,53 @@ namespace MWRender mBase = proto; mBase.mId = "player"; rebuild(); - mAnimation->runAnimation(0.0f); - updateCamera(); } - void RaceSelectionPreview::onSetup () + class UpdateCameraCallback : public osg::NodeCallback { - mAnimation->play("idle", 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + public: + UpdateCameraCallback(osg::ref_ptr nodeToFollow, const osg::Vec3& posOffset, const osg::Vec3& lookAtOffset) + : mNodeToFollow(nodeToFollow) + , mPosOffset(posOffset) + , mLookAtOffset(lookAtOffset) + { + } - updateCamera(); - } + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::Camera* cam = static_cast(node); - void RaceSelectionPreview::updateCamera() + // Update keyframe controllers in the scene graph first... + traverse(node, nv); + + // Now update camera utilizing the updated head position + osg::MatrixList mats = mNodeToFollow->getWorldMatrices(); + if (!mats.size()) + return; + osg::Matrix worldMat = mats[0]; + osg::Vec3 headOffset = worldMat.getTrans(); + + cam->setViewMatrixAsLookAt(headOffset + mPosOffset, headOffset + mLookAtOffset, osg::Vec3(0,0,1)); + } + + private: + osg::ref_ptr mNodeToFollow; + osg::Vec3 mPosOffset; + osg::Vec3 mLookAtOffset; + }; + + void RaceSelectionPreview::onSetup () { - Ogre::Vector3 scale = mNode->getScale(); - Ogre::Node* headNode = mAnimation->getNode("Bip01 Head"); - if (!headNode) - return; - Ogre::Vector3 headOffset = headNode->_getDerivedPosition(); - headOffset = mNode->convertLocalToWorldPosition(headOffset); + mAnimation->play("idle", 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); + mAnimation->runAnimation(0.f); - mCamera->setPosition(headOffset + mPosition * scale); - mCamera->lookAt(headOffset + mPosition*Ogre::Vector3(0,1,0) * scale); + // attach camera to follow the head node + if (mUpdateCameraCallback) + mCamera->removeUpdateCallback(mUpdateCameraCallback); + + const osg::Node* head = mAnimation->getNode("Bip01 Head"); + mUpdateCameraCallback = new UpdateCameraCallback(head, mPosition, mLookAt); + mCamera->addUpdateCallback(mUpdateCameraCallback); } + } diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 80dbe18b4..b7722d1f3 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -1,45 +1,48 @@ #ifndef MWRENDER_CHARACTERPREVIEW_H #define MWRENDER_CHARACTERPREVIEW_H -#include -#include #include +#include + #include +#include + #include "../mwworld/ptr.hpp" -namespace OEngine +namespace osg { -namespace Render -{ -class SelectionBuffer; + class Texture2D; + class Camera; } + +namespace osgViewer +{ + class Viewer; } namespace MWRender { class NpcAnimation; + class DrawOnceCallback; - class CharacterPreview : public Ogre::ManualResourceLoader + class CharacterPreview { public: - CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, - Ogre::Vector3 position, Ogre::Vector3 lookAt); + CharacterPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, MWWorld::Ptr character, int sizeX, int sizeY, + const osg::Vec3f& position, const osg::Vec3f& lookAt); virtual ~CharacterPreview(); - virtual void setup (); - virtual void onSetup(); - - virtual void rebuild(); + int getTextureWidth() const; + int getTextureHeight() const; - void onFrame(); + void redraw(); - void loadResource(Ogre::Resource *resource); + void rebuild(); - private: - bool mRecover; // Texture content was lost and needs to be re-rendered + osg::ref_ptr getTexture(); private: CharacterPreview(const CharacterPreview&); @@ -47,28 +50,23 @@ namespace MWRender protected: virtual bool renderHeadOnly() { return false; } + virtual void onSetup(); - virtual void setupRenderTarget(); - - Ogre::TexturePtr mTexture; - Ogre::RenderTarget* mRenderTarget; - Ogre::Viewport* mViewport; - - Ogre::Camera* mCamera; - - Ogre::SceneManager* mSceneMgr; - Ogre::SceneNode* mNode; + osg::ref_ptr mViewer; + Resource::ResourceSystem* mResourceSystem; + osg::ref_ptr mTexture; + osg::ref_ptr mCamera; + osg::ref_ptr mDrawOnceCallback; - Ogre::Vector3 mPosition; - Ogre::Vector3 mLookAt; + osg::Vec3f mPosition; + osg::Vec3f mLookAt; MWWorld::Ptr mCharacter; MWRender::NpcAnimation* mAnimation; + osg::ref_ptr mNode; std::string mCurrentAnimGroup; - std::string mName; - int mSizeX; int mSizeY; }; @@ -77,25 +75,21 @@ namespace MWRender { public: - InventoryPreview(MWWorld::Ptr character); - virtual ~InventoryPreview(); - virtual void onSetup(); + InventoryPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem, MWWorld::Ptr character); + + void updatePtr(const MWWorld::Ptr& ptr); void update(); // Render preview again, e.g. after changed equipment - void resize(int sizeX, int sizeY); + void setViewport(int sizeX, int sizeY); int getSlotSelected(int posX, int posY); protected: - virtual void setupRenderTarget(); - - private: - int mSizeX; - int mSizeY; - - OEngine::Render::SelectionBuffer* mSelectionBuffer; + virtual void onSetup(); }; + class UpdateCameraCallback; + class RaceSelectionPreview : public CharacterPreview { ESM::NPC mBase; @@ -104,16 +98,13 @@ namespace MWRender protected: virtual bool renderHeadOnly() { return true; } - - void updateCamera(); + virtual void onSetup(); public: - RaceSelectionPreview(); + RaceSelectionPreview(osgViewer::Viewer* viewer, Resource::ResourceSystem* resourceSystem); + virtual ~RaceSelectionPreview(); - virtual void onSetup(); - void render(); - - void update(float angle); + void setAngle(float angleRadians); const ESM::NPC &getPrototype() const { return mBase; @@ -123,7 +114,9 @@ namespace MWRender private: - Ogre::Radian mPitch; + osg::ref_ptr mUpdateCameraCallback; + + float mPitchRadians; }; }