Header
Code: Select all
#include <OgreTexture.h>
class RenderableMaterialSwitcher;
class RenderableSelectionRenderListener;
/**
* \brief Buffer for \c Ogre::Renderable selection.
**/
class _TouchscapeExport RenderableSelectionBuffer
{
public:
/**
* \brief Constructor.
* \param [in,out] scene_manager Manager for scene.
* \param [in,out] camera The camera.
* \param [in,out] render_target The render target.
**/
RenderableSelectionBuffer(SceneManager& scene_manager, Camera& camera, RenderTarget& render_target);
~RenderableSelectionBuffer();
/**
* \brief Executes the selection click action.
* \param x The x coordinate of the click in pixel screen coordinates.
* \param y The y coordinate of the click in pixel screen coordinates.
*
* \return null if it fails, else the renderable that was picked.
**/
Ogre::Renderable* onSelectionClick(int x, int y);
private:
void update();
void createRTTOverlays();
void updateBufferSize();
void createTexture(uint width, uint height);
void clearTexture();
SceneManager& m_sceneManager;
Camera& m_camera;
RenderTarget& m_renderTarget;
RenderableMaterialSwitcher* m_materialSwitcher;
RenderableSelectionRenderListener* m_selectionTargetListener;
const String m_TextureName;
const String m_SelectionDebugMaterialName;
TexturePtr m_texture;
RenderTexture* m_renderTexture;
uint8* m_buffer;
Ogre::PixelBox* m_pixelBox;
Overlay* m_selectionDebugOverlay;
time_t m_updateTimestamp;
};
Code: Select all
#include <OgreMaterialManager.h>
#include <OgreRenderTarget.h>
#include <OgreRenderTargetListener.h>
#include <OgreRenderTexture.h>
#include <OgreSceneManager.h>
#include <OgreTextureManager.h>
#include <OgreMaterialManager.h>
#include <OgreSubEntity.h>
#include <OgreEntity.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreOverlayManager.h>
#include <OgreOverlayContainer.h>
#define SHOW_OVERLAY 0
// Use random colours only if the debug overlay is being shown.
#if SHOW_OVERLAY
# define USE_RANDOM_COLOURS 1
#else
# define USE_RANDOM_COLOURS 0
#endif // SHOW_OVERLAY
struct ColourCompare
{
bool operator()(const Ogre::ColourValue& a, const Ogre::ColourValue& b) const
{
return a.getAsBGRA() < b.getAsBGRA();
}
};
class RenderableMaterialSwitcher : public Ogre::MaterialManager::Listener
{
public:
RenderableMaterialSwitcher();
virtual ~RenderableMaterialSwitcher();
Ogre::Technique* handleSchemeNotFound(unsigned short schemeIndex, const Ogre::String& schemeName, Ogre::Material* originalMaterial, unsigned short lodIndex, const Ogre::Renderable* rend);
Ogre::Renderable* getRenderable(const Ogre::ColourValue& colour);
void reset();
private:
friend class RenderableSelectionBuffer;
void getNextColour();
typedef std::map<ColourValue, Ogre::Renderable*, ColourCompare> ColourMap;
typedef ColourMap::const_iterator ColourMapConstItr;
static const ColourValue RESET_COLOUR;
ColourValue m_currentColour;
Ogre::Renderable* m_lastRenderable;
Ogre::Technique* m_lastTechnique;
ColourMap m_colourMap;
};
const ColourValue RenderableMaterialSwitcher::RESET_COLOUR(0.0f, 0.0f, 0.0f);
RenderableMaterialSwitcher::RenderableMaterialSwitcher()
:m_lastTechnique(NULL)
,m_currentColour(RESET_COLOUR)
{
}
RenderableMaterialSwitcher::~RenderableMaterialSwitcher()
{
}
Ogre::Technique* RenderableMaterialSwitcher::handleSchemeNotFound( unsigned short schemeIndex, const Ogre::String& schemeName, Ogre::Material* originalMaterial, unsigned short lodIndex, const Ogre::Renderable* rend )
{
if (rend)
{
if (m_lastRenderable != rend)
{
Ogre::ResourcePtr res = Ogre::MaterialManager::getSingleton().load("SelectionBuffer/PlainColour", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
m_lastTechnique = static_cast<Ogre::MaterialPtr>(res)->getTechnique(0);
getNextColour();
m_lastRenderable = const_cast<Ogre::Renderable*>(rend);
m_colourMap[m_currentColour] = m_lastRenderable;
}
m_lastRenderable->setCustomParameter(1, Vector4(m_currentColour.r, m_currentColour.g, m_currentColour.b, 1.0f));
return m_lastTechnique;
}
return NULL;
}
Ogre::Renderable* RenderableMaterialSwitcher::getRenderable( const Ogre::ColourValue& colour )
{
if (m_colourMap.count(colour))
{
return m_colourMap[colour];
}
return NULL;
}
void RenderableMaterialSwitcher::getNextColour()
{
#if USE_RANDOM_COLOURS
m_currentColour.setAsARGB(Ogre::Math::UnitRandom()*0x00FFFFFF + 0xFF000000);
#else
Ogre::ARGB colour = m_currentColour.getAsARGB();
colour++;
m_currentColour.setAsARGB(colour);
#endif // USE_RANDOM_COLOURS
}
void RenderableMaterialSwitcher::reset()
{
m_currentColour = RESET_COLOUR;
m_lastRenderable = NULL;
m_colourMap.clear();
}
class RenderableSelectionRenderListener : public Ogre::RenderTargetListener
{
public:
RenderableSelectionRenderListener(RenderableMaterialSwitcher& switcher);
~RenderableSelectionRenderListener();
void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
private:
RenderableMaterialSwitcher& m_materialListener;
};
RenderableSelectionRenderListener::RenderableSelectionRenderListener( RenderableMaterialSwitcher& switcher )
:m_materialListener(switcher)
{
}
RenderableSelectionRenderListener::~RenderableSelectionRenderListener()
{
}
void RenderableSelectionRenderListener::preRenderTargetUpdate( const Ogre::RenderTargetEvent& evt )
{
Ogre::MaterialManager::getSingleton().addListener(&m_materialListener);
}
void RenderableSelectionRenderListener::postRenderTargetUpdate( const Ogre::RenderTargetEvent& evt )
{
Ogre::MaterialManager::getSingleton().removeListener(&m_materialListener);
}
RenderableSelectionBuffer::RenderableSelectionBuffer( SceneManager& scene_manager, Camera& camera, RenderTarget& render_target )
:m_sceneManager(scene_manager)
,m_camera(camera)
,m_renderTarget(render_target)
,m_TextureName(NameGenerator::Next("RenderableSelectionPassTex"))
,m_SelectionDebugMaterialName(NameGenerator::Next("RenderableSelectionDebugMaterial"))
,m_buffer(NULL)
,m_pixelBox(NULL)
,m_selectionDebugOverlay(NULL)
,m_materialSwitcher(new RenderableMaterialSwitcher())
,m_selectionTargetListener(new RenderableSelectionRenderListener(*m_materialSwitcher))
{
uint width = m_renderTarget.getWidth();
uint height = m_renderTarget.getHeight();
createTexture(width, height);
#if SHOW_OVERLAY
createRTTOverlays();
#endif // SHOW_OVERLAY
}
RenderableSelectionBuffer::~RenderableSelectionBuffer()
{
clearTexture();
SafeDelete(m_selectionTargetListener);
SafeDelete(m_materialSwitcher);
#if SHOW_OVERLAY
Ogre::MaterialManager::getSingleton().unload(m_SelectionDebugMaterialName);
#endif // SHOW_OVERLAY
}
__forceinline void RenderableSelectionBuffer::createTexture( uint width, uint height )
{
m_texture = Ogre::TextureManager::getSingleton().createManual(
m_TextureName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::TEX_TYPE_2D, width, height, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
Ogre::HardwarePixelBufferSharedPtr pixel_buffer = m_texture->getBuffer();
m_renderTexture = pixel_buffer->getRenderTarget();
m_renderTexture->setAutoUpdated(false);
m_renderTexture->setPriority(0);
Ogre::Viewport* viewport = m_renderTexture->addViewport(&m_camera);
viewport->setOverlaysEnabled(false);
viewport->setClearEveryFrame(true);
m_renderTexture->addListener(m_selectionTargetListener);
viewport->setMaterialScheme("{45B9A135-0D74-443f-9806-2129FD7A2A96}");
size_t buffer_size = pixel_buffer->getSizeInBytes();
m_buffer = new uint8[buffer_size];
m_pixelBox = new Ogre::PixelBox(pixel_buffer->getWidth(), pixel_buffer->getHeight(),
pixel_buffer->getDepth(), pixel_buffer->getFormat(), m_buffer);
}
__forceinline void RenderableSelectionBuffer::clearTexture()
{
m_renderTexture->removeAllViewports();
m_renderTexture->removeAllListeners();
Ogre::TextureManager::getSingleton().unload(m_TextureName);
m_renderTexture = NULL;
SafeDelete(m_pixelBox);
delete[] m_buffer;
m_buffer = NULL;
}
void RenderableSelectionBuffer::createRTTOverlays()
{
Ogre::MaterialPtr base_white = Ogre::MaterialManager::getSingleton().getDefaultSettings();
Ogre::MaterialPtr selection_buffer_material = base_white->clone(m_SelectionDebugMaterialName);
Ogre::TextureUnitState* texture_unit = selection_buffer_material->getTechnique(0)->getPass(0)->createTextureUnitState(m_TextureName);
Ogre::OverlayManager& overlay_manager = Ogre::OverlayManager::getSingleton();
m_selectionDebugOverlay = overlay_manager.create(NameGenerator::Next("SelectionDebugOverlay"));
Ogre::OverlayContainer* panel = static_cast<Ogre::OverlayContainer*>(overlay_manager.createOverlayElement("Panel", NameGenerator::Next("SelectionDebugPanel")));
//panel->setMetricsMode(Ogre::GMM_PIXELS);
panel->setPosition(0.0125, 0.0166667);
panel->setDimensions(0.5f, 0.5f);
panel->setMaterialName(m_SelectionDebugMaterialName);
m_selectionDebugOverlay->add2D(panel);
m_selectionDebugOverlay->show();
}
__forceinline void RenderableSelectionBuffer::update()
{
if (m_updateTimestamp != System::FrameTimeStamp)
{
updateBufferSize();
m_materialSwitcher->reset();
m_renderTexture->update();
m_renderTexture->copyContentsToMemory(*m_pixelBox, Ogre::RenderTarget::FB_FRONT);
m_updateTimestamp = System::FrameTimeStamp;
}
}
void RenderableSelectionBuffer::updateBufferSize()
{
uint width = m_renderTarget.getWidth();
uint height = m_renderTarget.getHeight();
if (width != m_renderTexture->getWidth() || height != m_renderTexture->getHeight())
{
clearTexture();
createTexture(width, height);
}
}
Ogre::Renderable* RenderableSelectionBuffer::onSelectionClick( int x, int y )
{
update();
size_t position_in_stream = m_pixelBox->getWidth() * y * 4;
position_in_stream += x * 4;
Ogre::ARGB argb(0);
memcpy_s((void*)&argb, 4, m_buffer+position_in_stream, 4);
Ogre::ColourValue colour;
colour.setAsARGB(argb);
colour.a = 1.0f;
Ogre::Renderable* renderable = m_materialSwitcher->getRenderable(colour);
return renderable;
}