diff --git a/CMakeLists.txt b/CMakeLists.txt index b5b0884e4..e01b3d26b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,7 @@ set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/fader.cpp ${LIBDIR}/openengine/ogre/imagerotate.cpp ${LIBDIR}/openengine/ogre/atlas.cpp + ${LIBDIR}/openengine/ogre/selectionbuffer.cpp ) set(OENGINE_GUI ${LIBDIR}/openengine/gui/manager.cpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 1870a93f8..2542ef350 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -16,7 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows - compositors + compositors characterpreview externalrendering ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 19405fb7a..a83d6906f 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -35,6 +35,11 @@ namespace ESMS struct ESMStore; } +namespace MWRender +{ + class ExternalRendering; +} + namespace MWWorld { class CellStore; @@ -271,6 +276,8 @@ namespace MWBase virtual void togglePlayerLooking(bool enable) = 0; virtual void renderPlayer() = 0; + + virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; }; } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 6dc19944f..a8c0e2ac9 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -44,10 +44,14 @@ namespace MWGui : ContainerBase(dragAndDrop) , WindowPinnableBase("openmw_inventory_window.layout", parWindowManager) , mTrading(false) + , mLastXSize(0) + , mLastYSize(0) + , mPreview(MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()) { static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); getWidget(mAvatar, "Avatar"); + getWidget(mAvatarImage, "AvatarImage"); getWidget(mEncumbranceBar, "EncumbranceBar"); getWidget(mEncumbranceText, "EncumbranceBarT"); getWidget(mFilterAll, "AllButton"); @@ -76,6 +80,8 @@ namespace MWGui setCoord(0, 342, 498, 258); + MWBase::Environment::get().getWorld ()->setupExternalRendering (mPreview); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); openContainer(player); } @@ -89,6 +95,7 @@ namespace MWGui mBoughtItems.clear(); onWindowResize(static_cast(mMainWidget)); + drawItems(); } void InventoryWindow::onWindowResize(MyGUI::Window* _sender) @@ -99,7 +106,13 @@ namespace MWGui mRightPane->getPosition().top, _sender->getSize().width - 12 - (_sender->getSize().height-44) * aspect - 15, _sender->getSize().height-44 ); - drawItems(); + + if (mMainWidget->getSize().width != mLastXSize || mMainWidget->getSize().height != mLastYSize) + { + drawItems(); + mLastXSize = mMainWidget->getSize().width; + mLastYSize = mMainWidget->getSize().height; + } } void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender) @@ -171,15 +184,45 @@ namespace MWGui drawItems(); - // update selected weapon icon - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); - MWWorld::ContainerStoreIterator weaponSlot = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - if (weaponSlot == invStore.end()) - mWindowManager.unsetSelectedWeapon(); - else - mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability - + notifyContentChanged(); } + else + { + MyGUI::IntPoint mousePos = MyGUI::InputManager::getInstance ().getLastPressedPosition (MyGUI::MouseButton::Left); + MyGUI::IntPoint relPos = mousePos - mAvatar->getAbsolutePosition (); + int realX = int(float(relPos.left) / float(mAvatar->getSize().width) * 512.f ); + int realY = int(float(relPos.top) / float(mAvatar->getSize().height) * 1024.f ); + + MWWorld::Ptr itemSelected = getAvatarSelectedItem (realX, realY); + if (itemSelected.isEmpty ()) + return; + + for (unsigned int i=0; i < mContainerWidget->getChildCount (); ++i) + { + MyGUI::Widget* w = mContainerWidget->getChildAt (i); + + if (*w->getUserData() == itemSelected) + { + onSelectedItem(w); + return; + } + } + } + } + + MWWorld::Ptr InventoryWindow::getAvatarSelectedItem(int x, int y) + { + int slot = mPreview.getSlotSelected (x, y); + + if (slot == -1) + return MWWorld::Ptr(); + + MWWorld::Ptr player = mPtr; + MWWorld::InventoryStore& invStore = MWWorld::Class::get(player).getInventoryStore(player); + if (invStore.getSlot(slot) != invStore.end()) + return *invStore.getSlot (slot); + else + return MWWorld::Ptr(); } std::vector InventoryWindow::getEquippedItems() @@ -265,6 +308,12 @@ namespace MWGui mWindowManager.unsetSelectedWeapon(); else mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability + + MyGUI::IntSize size = mAvatar->getSize(); + + mPreview.update (size.width, size.height); + mAvatarImage->setSize(MyGUI::IntSize(std::max(mAvatar->getSize().width, 512), std::max(mAvatar->getSize().height, 1024))); + mAvatarImage->setImageTexture("CharacterPreview"); } void InventoryWindow::pickUpObject (MWWorld::Ptr object) @@ -329,4 +378,9 @@ namespace MWGui text->setCaption(getCountString(count)); mDragAndDrop->mDraggedFrom = this; } + + MyGUI::IntCoord InventoryWindow::getAvatarScreenCoord () + { + return mAvatar->getAbsoluteCoord (); + } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index fbdb79977..84b576a58 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -1,6 +1,8 @@ #ifndef MGUI_Inventory_H #define MGUI_Inventory_H +#include "../mwrender/characterpreview.hpp" + #include "container.hpp" #include "window_pinnable_base.hpp" @@ -22,8 +24,13 @@ namespace MWGui int getPlayerGold(); + MyGUI::IntCoord getAvatarScreenCoord(); + + MWWorld::Ptr getAvatarSelectedItem(int x, int y); + protected: MyGUI::Widget* mAvatar; + MyGUI::ImageBox* mAvatarImage; MyGUI::TextBox* mArmorRating; MyGUI::ProgressBar* mEncumbranceBar; MyGUI::TextBox* mEncumbranceText; @@ -37,6 +44,11 @@ namespace MWGui MyGUI::Button* mFilterMagic; MyGUI::Button* mFilterMisc; + int mLastXSize; + int mLastYSize; + + MWRender::InventoryPreview mPreview; + bool mTrading; void onWindowResize(MyGUI::Window* _sender); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 370b30733..3fe70d959 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -25,15 +25,18 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) , mHairIndex(0) , mFaceCount(10) , mHairCount(14) + , mCurrentAngle(0) { // Centre dialog center(); - // These are just demo values, you should replace these with - // real calls from outside the class later. - setText("AppearanceT", mWindowManager.getGameSettingString("sRaceMenu1", "Appearance")); - getWidget(mAppearanceBox, "AppearanceBox"); + getWidget(mPreviewImage, "PreviewImage"); + + MWBase::Environment::get().getWorld ()->setupExternalRendering (mPreview); + mPreview.update (0); + + mPreviewImage->setImageTexture ("CharacterHeadPreview"); getWidget(mHeadRotate, "HeadRotate"); mHeadRotate->setScrollRange(50); @@ -149,7 +152,10 @@ void RaceDialog::onBackClicked(MyGUI::Widget* _sender) void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position) { - // TODO: Rotate head + float angle = (float(_position) / 49.f - 0.5) * 3.14 * 2; + float diff = angle - mCurrentAngle; + mPreview.update (diff); + mCurrentAngle += diff; } void RaceDialog::onSelectPreviousGender(MyGUI::Widget*) diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 4aded28c3..0505e58e1 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -1,11 +1,15 @@ #ifndef MWGUI_RACE_H #define MWGUI_RACE_H + +#include + #include +#include "../mwrender/characterpreview.hpp" + #include "window_base.hpp" -#include namespace MWGui { @@ -73,7 +77,7 @@ namespace MWGui void updateSkills(); void updateSpellPowers(); - MyGUI::CanvasPtr mAppearanceBox; + MyGUI::ImageBox* mPreviewImage; MyGUI::ListBox* mRaceList; MyGUI::ScrollBar* mHeadRotate; @@ -87,6 +91,10 @@ namespace MWGui int mFaceCount, mHairCount; std::string mCurrentRaceId; + + float mCurrentAngle; + + MWRender::RaceSelectionPreview mPreview; }; } #endif diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7aee26bcc..8186279d1 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -14,6 +14,7 @@ #include "map_window.hpp" #include "widgets.hpp" +#include "inventorywindow.hpp" using namespace MWGui; using namespace MyGUI; @@ -162,12 +163,23 @@ void ToolTips::onFrame(float frameDuration) return; } - if (type == "ItemPtr") { mFocusObject = *focus->getUserData(); tooltipSize = getToolTipViaPtr(false); } + else if (type == "AvatarItemSelection") + { + MyGUI::IntCoord avatarPos = mWindowManager->getInventoryWindow ()->getAvatarScreenCoord (); + MyGUI::IntPoint relMousePos = MyGUI::InputManager::getInstance ().getMousePosition () - MyGUI::IntPoint(avatarPos.left, avatarPos.top); + int realX = int(float(relMousePos.left) / float(avatarPos.width) * 512.f ); + int realY = int(float(relMousePos.top) / float(avatarPos.height) * 1024.f ); + MWWorld::Ptr item = mWindowManager->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); + + mFocusObject = item; + if (!mFocusObject.isEmpty ()) + tooltipSize = getToolTipViaPtr(false); + } else if (type == "Spell") { ToolTipInfo info; diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 415d17241..41d02332e 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -3,6 +3,8 @@ #include #include +#include "renderconst.hpp" + using namespace Ogre; using namespace MWRender; @@ -23,7 +25,7 @@ void Actors::setMwRoot(Ogre::SceneNode* root){ void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv){ insertBegin(ptr, true, true); - NpcAnimation* anim = new MWRender::NpcAnimation(ptr, mRend, inv); + NpcAnimation* anim = new MWRender::NpcAnimation(ptr, ptr.getRefData ().getBaseNode (), inv, RV_Actors); mAllActors[ptr] = anim; } @@ -68,7 +70,7 @@ void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ void Actors::insertCreature (const MWWorld::Ptr& ptr){ insertBegin(ptr, true, true); - CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr, mRend); + CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr); //mAllActors.insert(std::pair(ptr,anim)); delete mAllActors[ptr]; mAllActors[ptr] = anim; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 46f3bdc0d..3d7629e5b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -11,9 +11,8 @@ namespace MWRender { -Animation::Animation(OEngine::Render::OgreRenderer& _rend) +Animation::Animation() : mInsert(NULL) - , mRend(_rend) , mTime(0.0f) , mSkipFrame(false) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3611d35c0..07583db78 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,7 +31,6 @@ class Animation { protected: Ogre::SceneNode* mInsert; - OEngine::Render::OgreRenderer &mRend; float mTime; GroupTimes mCurGroup; @@ -45,7 +44,7 @@ protected: bool findGroupTimes(const std::string &groupname, GroupTimes *times); public: - Animation(OEngine::Render::OgreRenderer& _rend); + Animation(); virtual ~Animation(); void playGroup(std::string groupname, int mode, int loops); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp new file mode 100644 index 000000000..01c5d594a --- /dev/null +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -0,0 +1,135 @@ +#include "characterpreview.hpp" + + +#include +#include + +#include + + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwworld/player.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) + : mSizeX(sizeX) + , mSizeY(sizeY) + , mName(name) + , mPosition(position) + , mLookAt(lookAt) + , mCharacter(character) + { + + } + + void CharacterPreview::onSetup() + { + + } + + void CharacterPreview::setup (Ogre::SceneManager *sceneManager) + { + mSceneMgr = sceneManager; + mCamera = mSceneMgr->createCamera (mName); + mCamera->setAspectRatio (float(mSizeX) / float(mSizeY)); + + mNode = static_cast(mSceneMgr->getRootSceneNode()->getChild("mwRoot"))->createChildSceneNode (); + + mAnimation = new NpcAnimation(mCharacter, mNode, + MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), RV_PlayerPreview); + + mNode->setVisible (false); + + mCamera->setPosition(mPosition); + mCamera->lookAt(mLookAt); + + mCamera->setNearClipDistance (0.01); + 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); + + mRenderTarget = mTexture->getBuffer()->getRenderTarget(); + mViewport = mRenderTarget->addViewport(mCamera); + mViewport->setOverlaysEnabled(false); + mViewport->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0)); + mViewport->setShadowsEnabled(false); + mViewport->setMaterialScheme("local_map"); + mViewport->setVisibilityMask (RV_PlayerPreview); + mRenderTarget->setActive(true); + mRenderTarget->setAutoUpdated (false); + + onSetup (); + } + + CharacterPreview::~CharacterPreview () + { + Ogre::TextureManager::getSingleton().remove(mName); + } + + + // -------------------------------------------------------------------------------------------------- + + + InventoryPreview::InventoryPreview(MWWorld::Ptr character) + : CharacterPreview(character, 512, 1024, "CharacterPreview", Ogre::Vector3(0, 65, -180), Ogre::Vector3(0,65,0)) + { + } + + InventoryPreview::~InventoryPreview() + { + delete mSelectionBuffer; + } + + void InventoryPreview::update(int sizeX, int sizeY) + { + mAnimation->forceUpdate (); + + mViewport->setDimensions (0, 0, std::min(1.f, float(sizeX) / float(512)), std::min(1.f, float(sizeY) / float(1024))); + + mNode->setOrientation (Ogre::Quaternion::IDENTITY); + + mNode->setVisible (true); + + mRenderTarget->update(); + mSelectionBuffer->update(); + + mNode->setVisible (false); + } + + int InventoryPreview::getSlotSelected (int posX, int posY) + { + return mSelectionBuffer->getSelected (posX, posY); + } + + void InventoryPreview::onSetup () + { + mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); + } + + // -------------------------------------------------------------------------------------------------- + + RaceSelectionPreview::RaceSelectionPreview() + : CharacterPreview(MWBase::Environment::get().getWorld()->getPlayer().getPlayer(), + 512, 512, "CharacterHeadPreview", Ogre::Vector3(0, 120, -35), Ogre::Vector3(0,125,0)) + { + + } + + void RaceSelectionPreview::update(float angle) + { + mNode->roll(Ogre::Radian(angle), Ogre::SceneNode::TS_LOCAL); + + mNode->setVisible (true); + mRenderTarget->update(); + mNode->setVisible (false); + } + +} diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp new file mode 100644 index 000000000..2a6b12b9e --- /dev/null +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -0,0 +1,88 @@ +#ifndef MWRENDER_CHARACTERPREVIEW_H +#define MWRENDER_CHARACTERPREVIEW_H + +#include +#include + + +#include "externalrendering.hpp" + +#include "../mwworld/ptr.hpp" + +namespace OEngine +{ +namespace Render +{ +class SelectionBuffer; +} +} + +namespace MWRender +{ + + class NpcAnimation; + + class CharacterPreview : public ExternalRendering + { + public: + CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, + Ogre::Vector3 position, Ogre::Vector3 lookAt); + virtual ~CharacterPreview(); + + virtual void setup (Ogre::SceneManager *sceneManager); + virtual void onSetup(); + + + protected: + Ogre::TexturePtr mTexture; + Ogre::RenderTarget* mRenderTarget; + Ogre::Viewport* mViewport; + + Ogre::Camera* mCamera; + + Ogre::SceneManager* mSceneMgr; + Ogre::SceneNode* mNode; + + Ogre::Vector3 mPosition; + Ogre::Vector3 mLookAt; + + MWWorld::Ptr mCharacter; + + MWRender::NpcAnimation* mAnimation; + + std::string mName; + + int mSizeX; + int mSizeY; + }; + + class InventoryPreview : public CharacterPreview + { + public: + + InventoryPreview(MWWorld::Ptr character); + virtual ~InventoryPreview(); + virtual void onSetup(); + + void update(int sizeX, int sizeY); + + int getSlotSelected(int posX, int posY); + + void setNpcAnimation (NpcAnimation* anim); + + private: + + OEngine::Render::SelectionBuffer* mSelectionBuffer; + }; + + class RaceSelectionPreview : public CharacterPreview + { + public: + RaceSelectionPreview(); + + void update(float angle); + }; + +} + +#endif diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 7fb153bd1..5e3ec9a77 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -16,7 +16,7 @@ CreatureAnimation::~CreatureAnimation() { } -CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend): Animation(_rend) +CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() { mInsert = ptr.getRefData().getBaseNode(); MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index b3c9d3ddd..e1a7bbb8f 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -8,13 +8,13 @@ namespace MWRender{ -class CreatureAnimation: public Animation{ - + class CreatureAnimation: public Animation + { public: - virtual ~CreatureAnimation(); - CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend); - virtual void runAnimation(float timepassed); + virtual ~CreatureAnimation(); + CreatureAnimation(const MWWorld::Ptr& ptr); + virtual void runAnimation(float timepassed); -}; + }; } #endif diff --git a/apps/openmw/mwrender/externalrendering.hpp b/apps/openmw/mwrender/externalrendering.hpp new file mode 100644 index 000000000..33c9afd87 --- /dev/null +++ b/apps/openmw/mwrender/externalrendering.hpp @@ -0,0 +1,23 @@ +#ifndef GAME_RENDERING_EXTERNALRENDERING_H +#define GAME_RENDERING_EXTERNALRENDERING_H + +namespace Ogre +{ + class SceneManager; +} + +namespace MWRender +{ + /// \brief Base class for out of world rendering + class ExternalRendering + { + public: + + virtual void setup (Ogre::SceneManager *sceneManager) = 0; + + virtual ~ExternalRendering() {} + }; +} + +#endif + diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 4f98aebc4..fdf4910f8 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -45,8 +45,8 @@ NpcAnimation::~NpcAnimation() } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv) - : Animation(_rend), mStateID(-1), mInv(_inv), timeToChange(0), +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& _inv, int visibilityFlags) + : Animation(), mStateID(-1), mInv(_inv), timeToChange(0), mVisibilityFlags(visibilityFlags), robe(mInv.end()), helmet(mInv.end()), shirt(mInv.end()), cuirass(mInv.end()), greaves(mInv.end()), leftpauldron(mInv.end()), rightpauldron(mInv.end()), @@ -84,7 +84,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere std::cout << " Sex: Male" << " Height: " << race->data.height.male << "\n"; */ - mInsert = ptr.getRefData().getBaseNode(); + mInsert = node; assert(mInsert); std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); @@ -94,7 +94,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRendere { Ogre::Entity *base = mEntityList.mEntities[i]; - base->setVisibilityFlags(RV_Actors); + base->getUserObjectBindings ().setUserAny (Ogre::Any(-1)); + + base->setVisibilityFlags(mVisibilityFlags); bool transparent = false; for(unsigned int j=0;j < base->getNumSubEntities();++j) { @@ -351,13 +353,16 @@ void NpcAnimation::updateParts() } } -NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, const std::string &bonename) +NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int group, const std::string &bonename) { NifOgre::EntityList entities = NIFLoader::createEntities(mEntityList.mSkelBase, bonename, mInsert, mesh); std::vector &parts = entities.mEntities; for(size_t i = 0;i < parts.size();i++) - parts[i]->setVisibilityFlags(RV_Actors); + { + parts[i]->setVisibilityFlags(mVisibilityFlags); + parts[i]->getUserObjectBindings ().setUserAny (Ogre::Any(group)); + } return entities; } @@ -480,83 +485,83 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, switch(type) { case ESM::PRT_Head: //0 - head = insertBoundedPart(mesh, "Head"); + head = insertBoundedPart(mesh, group, "Head"); break; case ESM::PRT_Hair: //1 - hair = insertBoundedPart(mesh, "Head"); + hair = insertBoundedPart(mesh, group, "Head"); break; case ESM::PRT_Neck: //2 - neck = insertBoundedPart(mesh, "Neck"); + neck = insertBoundedPart(mesh, group, "Neck"); break; case ESM::PRT_Cuirass: //3 - chest = insertBoundedPart(mesh, "Chest"); + chest = insertBoundedPart(mesh, group, "Chest"); break; case ESM::PRT_Groin: //4 - groin = insertBoundedPart(mesh, "Groin"); + groin = insertBoundedPart(mesh, group, "Groin"); break; case ESM::PRT_Skirt: //5 - skirt = insertBoundedPart(mesh, "Groin"); + skirt = insertBoundedPart(mesh, group, "Groin"); break; case ESM::PRT_RHand: //6 - rHand = insertBoundedPart(mesh, "Right Hand"); + rHand = insertBoundedPart(mesh, group, "Right Hand"); break; case ESM::PRT_LHand: //7 - lHand = insertBoundedPart(mesh, "Left Hand"); + lHand = insertBoundedPart(mesh, group, "Left Hand"); break; case ESM::PRT_RWrist: //8 - rWrist = insertBoundedPart(mesh, "Right Wrist"); + rWrist = insertBoundedPart(mesh, group, "Right Wrist"); break; case ESM::PRT_LWrist: //9 - lWrist = insertBoundedPart(mesh, "Left Wrist"); + lWrist = insertBoundedPart(mesh, group, "Left Wrist"); break; case ESM::PRT_Shield: //10 break; case ESM::PRT_RForearm: //11 - rForearm = insertBoundedPart(mesh, "Right Forearm"); + rForearm = insertBoundedPart(mesh, group, "Right Forearm"); break; case ESM::PRT_LForearm: //12 - lForearm = insertBoundedPart(mesh, "Left Forearm"); + lForearm = insertBoundedPart(mesh, group, "Left Forearm"); break; case ESM::PRT_RUpperarm: //13 - rupperArm = insertBoundedPart(mesh, "Right Upper Arm"); + rupperArm = insertBoundedPart(mesh, group, "Right Upper Arm"); break; case ESM::PRT_LUpperarm: //14 - lupperArm = insertBoundedPart(mesh, "Left Upper Arm"); + lupperArm = insertBoundedPart(mesh, group, "Left Upper Arm"); break; case ESM::PRT_RFoot: //15 - rfoot = insertBoundedPart(mesh, "Right Foot"); + rfoot = insertBoundedPart(mesh, group, "Right Foot"); break; case ESM::PRT_LFoot: //16 - lfoot = insertBoundedPart(mesh, "Left Foot"); + lfoot = insertBoundedPart(mesh, group, "Left Foot"); break; case ESM::PRT_RAnkle: //17 - rAnkle = insertBoundedPart(mesh, "Right Ankle"); + rAnkle = insertBoundedPart(mesh, group, "Right Ankle"); break; case ESM::PRT_LAnkle: //18 - lAnkle = insertBoundedPart(mesh, "Left Ankle"); + lAnkle = insertBoundedPart(mesh, group, "Left Ankle"); break; case ESM::PRT_RKnee: //19 - rKnee = insertBoundedPart(mesh, "Right Knee"); + rKnee = insertBoundedPart(mesh, group, "Right Knee"); break; case ESM::PRT_LKnee: //20 - lKnee = insertBoundedPart(mesh, "Left Knee"); + lKnee = insertBoundedPart(mesh, group, "Left Knee"); break; case ESM::PRT_RLeg: //21 - rUpperLeg = insertBoundedPart(mesh, "Right Upper Leg"); + rUpperLeg = insertBoundedPart(mesh, group, "Right Upper Leg"); break; case ESM::PRT_LLeg: //22 - lUpperLeg = insertBoundedPart(mesh, "Left Upper Leg"); + lUpperLeg = insertBoundedPart(mesh, group, "Left Upper Leg"); break; case ESM::PRT_RPauldron: //23 - rclavicle = insertBoundedPart(mesh , "Right Clavicle"); + rclavicle = insertBoundedPart(mesh , group, "Right Clavicle"); break; case ESM::PRT_LPauldron: //24 - lclavicle = insertBoundedPart(mesh, "Left Clavicle"); + lclavicle = insertBoundedPart(mesh, group, "Left Clavicle"); break; case ESM::PRT_Weapon: //25 break; case ESM::PRT_Tail: //26 - tail = insertBoundedPart(mesh, "Tail"); + tail = insertBoundedPart(mesh, group, "Tail"); break; } return true; @@ -575,10 +580,15 @@ void NpcAnimation::addPartGroup(int group, int priority, std::vectorgetStore().bodyParts.search(part.male); if(bodypart) - addOrReplaceIndividualPart(part.part, group,priority,"meshes\\" + bodypart->model); + addOrReplaceIndividualPart(part.part, group, priority,"meshes\\" + bodypart->model); else reserveIndividualPart(part.part, group, priority); } } +void NpcAnimation::forceUpdate () +{ + updateParts(); +} + } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index d4b2a5b9e..21edb3be4 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -65,10 +65,13 @@ private: MWWorld::ContainerStoreIterator rightglove; MWWorld::ContainerStoreIterator skirtiter; + int mVisibilityFlags; + public: - NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); + NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, + MWWorld::InventoryStore& _inv, int visibilityFlags); virtual ~NpcAnimation(); - NifOgre::EntityList insertBoundedPart(const std::string &mesh, const std::string &bonename); + NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename); virtual void runAnimation(float timepassed); void updateParts(); void removeEntities(NifOgre::EntityList &entities); @@ -78,6 +81,8 @@ public: bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh); void removePartGroup(int group); void addPartGroup(int group, int priority, std::vector& parts); + + void forceUpdate(); }; } diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 3ccc08022..297cb8d7a 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -35,6 +35,11 @@ namespace MWRender mPreviewCam.yaw = 0.f; mPreviewCam.offset = 400.f; } + + Player::~Player() + { + delete mAnimation; + } bool Player::rotate(const Ogre::Vector3 &rot, bool adjust) { diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index 8dd313b7f..b4d8983e4 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -63,6 +63,7 @@ namespace MWRender public: Player (Ogre::Camera *camera, Ogre::SceneNode* mNode); + ~Player(); /// Set where the player is looking at. Uses Morrowind (euler) angles /// \param rot Rotation angles in radians diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 9f57833bb..e6ecb5150 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -41,7 +41,7 @@ enum VisibilityFlags // Water RV_Water = 8, - // Actors (player, npcs, creatures) + // Actors (npcs, creatures) RV_Actors = 16, // Misc objects (containers, dynamic objects) @@ -54,6 +54,8 @@ enum VisibilityFlags RV_OcclusionQuery = 256, + RV_PlayerPreview = 512, + RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water /// \todo markers (normally hidden) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 70d7de552..308a01688 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -34,6 +34,7 @@ #include "water.hpp" #include "compositors.hpp" #include "npcanimation.hpp" +#include "externalrendering.hpp" using namespace MWRender; using namespace Ogre; @@ -94,7 +95,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; else if (filter == "trilinear") tfo = TFO_TRILINEAR; else if (filter == "bilinear") tfo = TFO_BILINEAR; - else if (filter == "none") tfo = TFO_NONE; + else /*if (filter == "none")*/ tfo = TFO_NONE; MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); @@ -137,7 +138,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // Morrowind uses, and it automagically makes everything work as it // should. SceneNode *rt = mRendering.getScene()->getRootSceneNode(); - mMwRoot = rt->createChildSceneNode(); + mMwRoot = rt->createChildSceneNode("mwRoot"); mMwRoot->pitch(Degree(-90)); mObjects.setMwRoot(mMwRoot); @@ -723,7 +724,7 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; else if (filter == "trilinear") tfo = TFO_TRILINEAR; else if (filter == "bilinear") tfo = TFO_BILINEAR; - else if (filter == "none") tfo = TFO_NONE; + else /*if (filter == "none")*/ tfo = TFO_NONE; MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); @@ -858,9 +859,8 @@ void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) { MWRender::NpcAnimation *anim = new MWRender::NpcAnimation( - ptr, - mRendering, - MWWorld::Class::get(ptr).getInventoryStore(ptr) + ptr, ptr.getRefData ().getBaseNode (), + MWWorld::Class::get(ptr).getInventoryStore(ptr), RV_Actors ); mPlayer->setAnimation(anim); } @@ -882,4 +882,9 @@ bool RenderingManager::isPositionExplored (float nX, float nY, int x, int y, boo return mLocalMap->isPositionExplored(nX, nY, x, y, interior); } +void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rendering) +{ + rendering.setup (mRendering.getScene()); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index e5be238bd..e994e4909 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -43,6 +43,7 @@ namespace MWRender class LocalMap; class Water; class Compositors; + class ExternalRendering; class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener { @@ -185,12 +186,14 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList static bool waterShaderSupported(); - virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y); + void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y); ///< see MWRender::LocalMap::getInteriorMapPosition - virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior); + bool isPositionExplored (float nX, float nY, int x, int y, bool interior); ///< see MWRender::LocalMap::isPositionExplored + void setupExternalRendering (MWRender::ExternalRendering& rendering); + protected: virtual void windowResized(Ogre::RenderWindow* rw); virtual void windowClosed(Ogre::RenderWindow* rw); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 869ce94d1..6c9267836 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1222,4 +1222,9 @@ namespace MWWorld { mRendering->renderPlayer(mPlayer->getPlayer()); } + + void World::setupExternalRendering (MWRender::ExternalRendering& rendering) + { + mRendering->setupExternalRendering (rendering); + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 6279343d4..96e6ae3f8 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -307,6 +307,8 @@ namespace MWWorld } virtual void renderPlayer(); + + virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); }; } diff --git a/extern/shiny b/extern/shiny index 716841523..4750676ac 160000 --- a/extern/shiny +++ b/extern/shiny @@ -1 +1 @@ -Subproject commit 7168415233905de2864eec71ed4312cb8f83059b +Subproject commit 4750676ac46a7aaa86bca53dc68c5a1ba11f3bc1 diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 3e99f5745..e8426afb7 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -40,7 +40,9 @@ set(MATERIAL_FILES water.mat water.shader water.shaderset - + selection.mat + selection.shader + selection.shaderset ) copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") diff --git a/files/materials/selection.mat b/files/materials/selection.mat new file mode 100644 index 000000000..a76dd7179 --- /dev/null +++ b/files/materials/selection.mat @@ -0,0 +1,8 @@ +material SelectionColour +{ + pass + { + vertex_program selection_vertex + fragment_program selection_fragment + } +} diff --git a/files/materials/selection.shader b/files/materials/selection.shader new file mode 100644 index 000000000..095a31259 --- /dev/null +++ b/files/materials/selection.shader @@ -0,0 +1,24 @@ +#include "core.h" + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + + SH_START_PROGRAM + { + shOutputPosition = shMatrixMult(wvp, shInputPosition); + } + +#else + + SH_BEGIN_PROGRAM + shUniform(float4, colour) @shAutoConstant(colour, custom, 1) + + SH_START_PROGRAM + { + shOutputColour(0) = colour; + //shOutputColour(0) = float4(1,0,0,1); + } + +#endif diff --git a/files/materials/selection.shaderset b/files/materials/selection.shaderset new file mode 100644 index 000000000..c90826282 --- /dev/null +++ b/files/materials/selection.shaderset @@ -0,0 +1,15 @@ +shader_set selection_vertex +{ + source selection.shader + type vertex + profiles_cg vs_2_0 arbvp1 + profiles_hlsl vs_2_0 +} + +shader_set selection_fragment +{ + source selection.shader + type fragment + profiles_cg ps_2_x ps_2_0 ps arbfp1 + profiles_hlsl ps_2_0 +} diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index 3d32ffd9a..b69073899 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -8,11 +8,13 @@ - + + + - + diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index 1ffabe3b6..3a60916f7 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -12,8 +12,13 @@ + + + + + diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index daf82b9da..831b04930 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -188,7 +188,7 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& mWindow = mRoot->createRenderWindow(title, settings.window_x, settings.window_y, settings.fullscreen, ¶ms); // create the semi-transparent black background texture used by the GUI. - // has to be created in code with TU_DYNAMIC_WRITE_ONLY_DISCARDABLE param + // has to be created in code with TU_DYNAMIC_WRITE_ONLY param // so that it can be modified at runtime. Ogre::TextureManager::getSingleton().createManual( "transparent.png", @@ -197,7 +197,7 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& 1, 1, 0, Ogre::PF_A8R8G8B8, - Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); + Ogre::TU_DYNAMIC_WRITE_ONLY); } void OgreRenderer::createScene(const std::string& camName, float fov, float nearClip) diff --git a/libs/openengine/ogre/selectionbuffer.cpp b/libs/openengine/ogre/selectionbuffer.cpp new file mode 100644 index 000000000..3ecb99f3b --- /dev/null +++ b/libs/openengine/ogre/selectionbuffer.cpp @@ -0,0 +1,122 @@ +#include "selectionbuffer.hpp" + +#include +#include +#include +#include + +#include + +namespace OEngine +{ +namespace Render +{ + + SelectionBuffer::SelectionBuffer(Ogre::Camera *camera, int sizeX, int sizeY, int visibilityFlags) + { + mTexture = Ogre::TextureManager::getSingleton().createManual("SelectionBuffer", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, sizeX, sizeY, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); + + mRenderTarget = mTexture->getBuffer()->getRenderTarget(); + Ogre::Viewport* vp = mRenderTarget->addViewport(camera); + vp->setOverlaysEnabled(false); + vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0)); + vp->setShadowsEnabled(false); + vp->setMaterialScheme("selectionbuffer"); + vp->setVisibilityMask (visibilityFlags); + mRenderTarget->setActive(true); + mRenderTarget->setAutoUpdated (false); + + mCurrentColour = Ogre::ColourValue(0.3, 0.3, 0.3); + } + + SelectionBuffer::~SelectionBuffer() + { + Ogre::TextureManager::getSingleton ().remove("SelectionBuffer"); + } + + void SelectionBuffer::update () + { + Ogre::MaterialManager::getSingleton ().addListener (this); + + mRenderTarget->update(); + + Ogre::MaterialManager::getSingleton ().removeListener (this); + + mTexture->convertToImage(mBuffer); + } + + int SelectionBuffer::getSelected(int xPos, int yPos) + { + Ogre::ColourValue clr = mBuffer.getColourAt (xPos, yPos, 0); + clr.a = 1; + if (mColourMap.find(clr) != mColourMap.end()) + return mColourMap[clr]; + else + return -1; // nothing selected + } + + Ogre::Technique* SelectionBuffer::handleSchemeNotFound ( + unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, + unsigned short lodIndex, const Ogre::Renderable *rend) + { + if (schemeName == "selectionbuffer") + { + sh::Factory::getInstance ()._ensureMaterial ("SelectionColour", "Default"); + + Ogre::MaterialPtr m = Ogre::MaterialManager::getSingleton ().getByName("SelectionColour"); + + + if(typeid(*rend) == typeid(Ogre::SubEntity)) + { + const Ogre::SubEntity *subEntity = static_cast(rend); + int id = Ogre::any_cast(subEntity->getParent ()->getUserObjectBindings().getUserAny()); + bool found = false; + Ogre::ColourValue colour; + for (std::map::iterator it = mColourMap.begin(); it != mColourMap.end(); ++it) + { + if (it->second == id) + { + found = true; + colour = it->first; + } + } + + + if (!found) + { + getNextColour(); + const_cast(subEntity)->setCustomParameter(1, Ogre::Vector4(mCurrentColour.r, mCurrentColour.g, mCurrentColour.b, 1.0)); + mColourMap[mCurrentColour] = id; + } + else + { + const_cast(subEntity)->setCustomParameter(1, Ogre::Vector4(colour.r, colour.g, colour.b, 1.0)); + } + + assert(m->getTechnique(1)); + return m->getTechnique(1); + } + else + throw std::runtime_error("selectionbuffer only works with entities"); + } + return NULL; + } + + void SelectionBuffer::getNextColour () + { + Ogre::ARGB color = (float(rand()) / float(RAND_MAX)) * std::numeric_limits::max(); + + if (mCurrentColour.getAsARGB () == color) + { + getNextColour(); + return; + } + + mCurrentColour.setAsARGB(color); + mCurrentColour.a = 1; + } + + +} +} diff --git a/libs/openengine/ogre/selectionbuffer.hpp b/libs/openengine/ogre/selectionbuffer.hpp new file mode 100644 index 000000000..c487b24b0 --- /dev/null +++ b/libs/openengine/ogre/selectionbuffer.hpp @@ -0,0 +1,54 @@ +#ifndef OENGINE_SELECTIONBUFFER_H +#define OENGINE_SELECTIONBUFFER_H + + +#include +#include +#include + +namespace OEngine +{ +namespace Render +{ + + struct cmp_ColourValue + { + bool operator()(const Ogre::ColourValue &a, const Ogre::ColourValue &b) const + { + return a.getAsBGRA() < b.getAsBGRA(); + } + }; + + class SelectionBuffer : public Ogre::MaterialManager::Listener + { + public: + SelectionBuffer(Ogre::Camera* camera, int sizeX, int sizeY, int visibilityFlags); + virtual ~SelectionBuffer(); + + int getSelected(int xPos, int yPos); + ///< @return ID of the selected object + + void update(); + + virtual Ogre::Technique* handleSchemeNotFound ( + unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, + unsigned short lodIndex, const Ogre::Renderable *rend); + + + private: + Ogre::TexturePtr mTexture; + Ogre::RenderTexture* mRenderTarget; + + Ogre::Image mBuffer; + + std::map mColourMap; + + Ogre::ColourValue mCurrentColour; + + void getNextColour(); + }; + +} +} + +#endif