From 85d93807c5bd909389c52483b9f1d70eefd7bc17 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 5 Oct 2014 19:25:37 +1100 Subject: [PATCH] Working version. White lines still present. Marker toggle hard-coded to 'm' key. Mouse events not implemented. --- apps/opencs/CMakeLists.txt | 2 +- .../view/render/pagedworldspacewidget.cpp | 158 +++++---- .../view/render/pagedworldspacewidget.hpp | 12 +- apps/opencs/view/render/scenewidget.cpp | 10 + apps/opencs/view/render/scenewidget.hpp | 2 + apps/opencs/view/render/textoverlay.cpp | 301 ++++++++++++++++++ apps/opencs/view/render/textoverlay.hpp | 54 ++++ apps/opencs/view/render/worldspacewidget.cpp | 3 + apps/opencs/view/render/worldspacewidget.hpp | 4 +- 9 files changed, 458 insertions(+), 88 deletions(-) create mode 100644 apps/opencs/view/render/textoverlay.cpp create mode 100644 apps/opencs/view/render/textoverlay.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 2869904cc2..ff29a7da20 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -81,7 +81,7 @@ opencs_units (view/render opencs_units_noqt (view/render navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight - lightingbright object cell + lightingbright object cell textoverlay ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 903a478867..200c1a9d77 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -4,17 +4,13 @@ #include #include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include +#include +#include + +#include "../../../../components/esm/loadland.hpp" +#include "textoverlay.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/idtable.hpp" @@ -23,18 +19,6 @@ #include "elements.hpp" -void CSVRender::PagedWorldspaceWidget::displayCellCoord(bool display) -{ - mDisplayCellCoord = display; - std::map::iterator iter(mCells.begin()); - - while (iter != mCells.end()) - { - getSceneManager()->getBillboardSet("CellBillboardSet" + iter->first.getId(mWorldspace))->setVisible(display); - iter++; - } -} - bool CSVRender::PagedWorldspaceWidget::adjustCells() { bool modified = false; @@ -56,9 +40,14 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() delete iter->second; mCells.erase (iter++); - getSceneManager()->getSceneNode("CellBillboardNode" + iter->first.getId(mWorldspace))->detachAllObjects(); - getSceneManager()->destroySceneNode("CellBillboardNode" + iter->first.getId(mWorldspace)); - getSceneManager()->destroyBillboardSet("CellBillboardSet" + iter->first.getId(mWorldspace)); + // destroy manual objects and entities + std::map::iterator it = mEntities.find(iter->first.getId(mWorldspace)); + if(it != mEntities.end()) + { + getSceneManager()->destroyEntity(it->second); + mEntities.erase(it); + } + getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); modified = true; } @@ -82,72 +71,37 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() if (setCamera) { setCamera = false; - getCamera()->setPosition (8192*iter->getX()+4096, 8192*iter->getY()+4096, 0); + getCamera()->setPosition (ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, + ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, 0); } mCells.insert (std::make_pair (*iter, - new Cell (mDocument.getData(), getSceneManager(), - iter->getId (mWorldspace)))); + new Cell (mDocument.getData(), getSceneManager(), iter->getId (mWorldspace)))); - //billboard which indicate the Cell coord - Ogre::SceneNode* billboardNode = getSceneManager()->getRootSceneNode()->createChildSceneNode("CellBillboardNode" + iter->getId(mWorldspace)); - billboardNode->setPosition(8192 * iter->getX() + 4096, 8192 * iter->getY() + 4096, 0); + // FIXME: delete this later + Ogre::ManualObject* manual = getSceneManager()->createManualObject("manual" + iter->getId(mWorldspace)); - QImage image(QSize(1024, 1024), QImage::Format_RGB888); - QPainter painter(&image); - std::stringstream ss; - ss << iter->getX() << ";" << iter->getY(); - std::string text = ss.str(); - QFont font = painter.font(); - font.setPointSize(256); - painter.setFont(font); - painter.setPen(Qt::SolidLine); - painter.setPen(Qt::white); - painter.drawText(QRect(0, 0, 1024, 1024), Qt::AlignCenter, QString(text.c_str())); + manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); + // define start and end point (x, y, z) + // FIXME: need terrain height to get the correct starting point + manual-> position(ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, + ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, 0); + manual-> position(ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2, + ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, 2000); + manual->end(); + Ogre::MeshPtr meshPtr = manual->convertToMesh("vLine" + iter->getId(mWorldspace)); + Ogre::Entity* entity = getSceneManager()->createEntity(meshPtr); + getSceneManager()->getRootSceneNode()->createChildSceneNode()->attachObject(entity); + //entity->setVisible(false); - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("CellBillboardTexture" + iter->getId(mWorldspace)); - if (texture.isNull()) - { - texture = Ogre::TextureManager::getSingleton().createManual("CellBillboardTexture" + iter->getId(mWorldspace), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, 1024, 1024, 5, Ogre::PF_X8R8G8B8, Ogre::TU_DEFAULT); + mEntities.insert(std::make_pair(iter->getId(mWorldspace), entity)); - int w = 1024; - int h = 1024; - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream((void*)image.constBits(), w*h*Ogre::PixelUtil::getNumElemBytes(Ogre::PF_R8G8B8), false)); - texture->loadRawData(stream, w, h, Ogre::PF_R8G8B8); - texture->load(); - } - - Ogre::MaterialPtr material; - if (Ogre::MaterialManager::getSingleton().resourceExists("CellBillboardMaterial" + iter->getId(mWorldspace))) - { - material = Ogre::MaterialManager::getSingleton().getByName("CellBillboardMaterial" + iter->getId(mWorldspace)); - } - else - { - material = Ogre::MaterialManager::getSingleton().create( - "CellBillboardMaterial" + iter->getId(mWorldspace), // name - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - - material->getTechnique(0)->getPass(0)->createTextureUnitState("CellBillboardTexture" + iter->getId(mWorldspace)); - material->getTechnique(0)->getPass(0)->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); - material->setDepthCheckEnabled(false); - material->setDepthWriteEnabled(false); - } - - Ogre::BillboardSet* mySet = getSceneManager()->createBillboardSet("CellBillboardSet" + iter->getId(mWorldspace)); - // FIXME: myBillboard is currently not used but will be required later - // for manipulating the billboard (e.g. mouse events). Ignore compiler - // warnings for now. - Ogre::Billboard* myBillboard = mySet->createBillboard(Ogre::Vector3(0, 0, 0)); - mySet->setDefaultDimensions(4000, 2000); - mySet->setMaterial(material); - mySet->setRenderQueueGroup(mySet->getRenderQueueGroup() + 1); // render the bilboard on top - billboardNode->attachObject(mySet); - - mySet->setVisible(mDisplayCellCoord); + CSVRender::TextOverlay *textDisp = new CSVRender::TextOverlay(entity, getCamera(), iter->getId(mWorldspace)); + textDisp->enable(true); + textDisp->setCaption(iter->getId(mWorldspace)); + textDisp->update(); + mTextOverlays.push_back(textDisp); modified = true; } @@ -156,6 +110,34 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() return modified; } +void CSVRender::PagedWorldspaceWidget::updateOverlay(bool toggleOverlay) +{ + if(!mTextOverlays.empty()) + { + std::list::iterator it = mTextOverlays.begin(); + for(; it != mTextOverlays.end(); ++it) + { + (*it)->update(toggleOverlay); + } + std::map::iterator iter (mCells.begin()); + +#if 0 + if(toggleOverlay) + { + while (iter!=mCells.end()) + { + std::map::iterator it = mEntities.find(iter->first.getId(mWorldspace)); + if(it != mEntities.end()) + { + it->second->setVisible(!it->second->isVisible()); + } + ++iter; + } + } +#endif + } +} + void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { @@ -234,7 +216,7 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() } CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) -: WorldspaceWidget(document, parent), mDocument(document), mWorldspace("std::default"), mDisplayCellCoord(true) +: WorldspaceWidget(document, parent), mDocument(document), mWorldspace("std::default"), mTextOverlays(0) { QAbstractItemModel *cells = document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells); @@ -251,7 +233,17 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() { for (std::map::iterator iter (mCells.begin()); iter!=mCells.end(); ++iter) + { delete iter->second; + + std::map::iterator it = mEntities.find(iter->first.getId(mWorldspace)); + if(it != mEntities.end()) + { + getSceneManager()->destroyEntity(it->second); + mEntities.erase(it); + } + getSceneManager()->destroyManualObject("manual"+iter->first.getId(mWorldspace)); + } } void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 304424453b..1013319d11 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -10,6 +10,9 @@ namespace CSVRender { + + class TextOverlay; + class PagedWorldspaceWidget : public WorldspaceWidget { Q_OBJECT @@ -19,7 +22,8 @@ namespace CSVRender std::map mCells; std::string mWorldspace; CSVWidget::SceneToolToggle *mControlElements; - bool mDisplayCellCoord; + std::list mTextOverlays; + std::map mEntities; private: @@ -58,8 +62,6 @@ namespace CSVRender void setCellSelection(const CSMWorld::CellSelection& selection); - void displayCellCoord(bool display); - /// \return Drop handled? virtual bool handleDrop (const std::vector& data, DropType type); @@ -73,6 +75,10 @@ namespace CSVRender virtual unsigned int getElementMask() const; + protected: + + virtual void updateOverlay(bool toggleOverlay = false); + signals: void cellSelectionChanged (const CSMWorld::CellSelection& selection); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 5ddb5e084b..089f4a4f37 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" @@ -57,6 +58,9 @@ namespace CSVRender setLighting (&mLightingDay); + Ogre::OverlaySystem *mOverlaySystem = new Ogre::OverlaySystem(); // FIXME: delete + mSceneMgr->addRenderQueueListener(mOverlaySystem); + QTimer *timer = new QTimer (this); connect (timer, SIGNAL (timeout()), this, SLOT (update())); @@ -283,6 +287,8 @@ namespace CSVRender break; + case Qt::Key_M: updateOverlay(true); + default: QWidget::keyReleaseEvent (event); } } @@ -377,9 +383,13 @@ namespace CSVRender { mUpdate = false; mWindow->update(); + updateOverlay(); } } + void SceneWidget::updateOverlay(bool toggleOverlay) + { } + void SceneWidget::setLighting (Lighting *lighting) { if (mLighting) diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 8301cd4466..650b4d1b5d 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -59,6 +59,8 @@ namespace CSVRender void setDefaultAmbient (const Ogre::ColourValue& colour); ///< \note The actual ambient colour may differ based on lighting settings. + virtual void updateOverlay(bool toggleOverlay = false); + private: void paintEvent(QPaintEvent* e); void resizeEvent(QResizeEvent* e); diff --git a/apps/opencs/view/render/textoverlay.cpp b/apps/opencs/view/render/textoverlay.cpp new file mode 100644 index 0000000000..31c9e50ac3 --- /dev/null +++ b/apps/opencs/view/render/textoverlay.cpp @@ -0,0 +1,301 @@ +#include "textoverlay.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "OgreHardwarePixelBuffer.h" + +namespace CSVRender +{ + +static const int sMargin = 5; // margin around overlay text in pixels + +// Things to do: +// - configurable font size in pixels (automatically calulate everything else from it) +// - configurable texture to use +// - configurable toggle key to enable/disable the text overlays (currntly fixed 'm') +// - try material script +// - setup common resources such as font in a central place, so that they are not +// repeated for each text overlay (also destroy once) +// - decide whether to use QPaint + +// http://www.ogre3d.org/tikiwiki/tiki-index.php?page=ObjectTextDisplay +// http://www.ogre3d.org/tikiwiki/tiki-index.php?page=MovableTextOverlay +// http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Creating+dynamic+textures +// http://www.ogre3d.org/tikiwiki/ManualObject +TextOverlay::TextOverlay(const Ogre::MovableObject* obj, const Ogre::Camera* camera, const Ogre::String& id) + : mOverlay(0), mCaption(""), mEnabled(false), mCamera(camera), mObj(obj), mId(id), mOnScreen(false) + , mFontHeight(16) // FIXME: make this configurable +{ + if(id == "" || !camera || !obj) + throw std::runtime_error("TextOverlay could not be created."); + + // setup font + if (Ogre::FontManager::getSingleton().resourceExists("DejaVuLGC")) + mFont = Ogre::FontManager::getSingleton().getByName("DejaVuLGC","General"); + else + { + Ogre::ResourceGroupManager::getSingleton().addResourceLocation("resources\\mygui", "FileSystem"); + mFont = Ogre::FontManager::getSingleton().create("DejaVuLGC","General"); + mFont->setType(Ogre::FT_TRUETYPE); + mFont->setSource("DejaVuLGCSansMono.ttf"); + mFont->setTrueTypeSize(mFontHeight); + mFont->setTrueTypeResolution(96); + } + if(!mFont.isNull()) + mFont->load(); + else + throw std::runtime_error("TextOverlay font not loaded."); + + // setup overlay + Ogre::OverlayManager &overlayMgr = Ogre::OverlayManager::getSingleton(); + mOverlay = overlayMgr.getByName("CellIDPanel"); + if(!mOverlay) + mOverlay = overlayMgr.create("CellIDPanel"); + + // create texture + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTransBlue"); + if(texture.isNull()) + { + texture = Ogre::TextureManager::getSingleton().createManual( + "DynamicTransBlue", // name + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, // type + 8, 8, // width & height + 0, // number of mipmaps + Ogre::PF_BYTE_BGRA, // pixel format + Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for + // textures updated very often (e.g. each frame) + + Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); + pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); + const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); + + uint8_t* pDest = static_cast(pixelBox.data); + + // Fill in some pixel data. This will give a semi-transparent blue, + // but this is of course dependent on the chosen pixel format. + for (size_t j = 0; j < 8; j++) + { + for(size_t i = 0; i < 8; i++) + { + *pDest++ = 255; // B + *pDest++ = 0; // G + *pDest++ = 0; // R + *pDest++ = 63; // A + } + + pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); + } + pixelBuffer->unlock(); + } + + // setup material for containers + Ogre::MaterialPtr mQuadMaterial = Ogre::MaterialManager::getSingleton().create("TransOverlayMaterial", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); + Ogre::Pass *pass = mQuadMaterial->getTechnique( 0 )->getPass( 0 ); + pass->setLightingEnabled( false ); + pass->setDepthWriteEnabled( false ); + pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); + + Ogre::TextureUnitState *tex = pass->createTextureUnitState("MyCustomState", 0); + tex->setTextureName("DynamicTransBlue"); + tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); + mQuadMaterial->load(); + + mContainer = static_cast(overlayMgr.createOverlayElement("Panel", "container"+mId)); + mContainer->setMaterialName("TransOverlayMaterial"); + mOverlay->add2D(mContainer); + + // setup text area overlay element + mElement = static_cast(overlayMgr.createOverlayElement("TextArea", "text"+mId)); + mElement->setMetricsMode(Ogre::GMM_RELATIVE); + mElement->setDimensions(1.0, 1.0); + mElement->setMetricsMode(Ogre::GMM_PIXELS); + mElement->setPosition(sMargin*2, sMargin*1.3); // 1.3 & 2 = fudge factor + + mElement->setFontName("DejaVuLGC"); + mElement->setCharHeight(fontHeight()); // NOTE: seems that this is required as well as font->setTrueTypeSize() + mElement->setHorizontalAlignment(Ogre::GHA_LEFT); + //mElement->setColour(Ogre::ColourValue(1.0, 1.0, 1.0)); // R, G, B + mElement->setColour(Ogre::ColourValue(1.0, 1.0, 0)); // yellow + + mContainer->addChild(mElement); + mOverlay->show(); +} + +void TextOverlay::getScreenCoordinates(const Ogre::Vector3& position, Ogre::Real& x, Ogre::Real& y) +{ + Ogre::Vector3 hcsPosition = mCamera->getProjectionMatrix() * (mCamera->getViewMatrix() * position); + + x = 1.0f - ((hcsPosition.x * 0.5f) + 0.5f); // 0 <= x <= 1 // left := 0,right := 1 + y = ((hcsPosition.y * 0.5f) + 0.5f); // 0 <= y <= 1 // bottom := 0,top := 1 +} + +void TextOverlay::getMinMaxEdgesOfTopAABBIn2D(float& MinX, float& MinY, float& MaxX, float& MaxY) +{ + MinX = 0, MinY = 0, MaxX = 0, MaxY = 0; + float X[4]; // the 2D dots of the AABB in screencoordinates + float Y[4]; + + if (!mObj->isInScene()) + return; + + const Ogre::AxisAlignedBox &AABB = mObj->getWorldBoundingBox(true); // the AABB of the target + const Ogre::Vector3 CornersOfTopAABB[4] = { AABB.getCorner(Ogre::AxisAlignedBox::FAR_LEFT_TOP), + AABB.getCorner(Ogre::AxisAlignedBox::FAR_RIGHT_TOP), + AABB.getCorner(Ogre::AxisAlignedBox::NEAR_LEFT_TOP), + AABB.getCorner(Ogre::AxisAlignedBox::NEAR_RIGHT_TOP)}; + + //The normal vector of the plaine.this points directly infront of the cam + Ogre::Vector3 CameraPlainNormal = mCamera->getDerivedOrientation().zAxis(); + + //the plaine that devides the space bevor and behin the cam + Ogre::Plane CameraPlain = Ogre::Plane(CameraPlainNormal, mCamera->getDerivedPosition()); + + for (int i = 0; i < 4; i++) + { + X[i] = 0; + Y[i] = 0; + + getScreenCoordinates(CornersOfTopAABB[i],X[i],Y[i]); // transfor into 2d dots + + if (CameraPlain.getSide(CornersOfTopAABB[i]) == Ogre::Plane::NEGATIVE_SIDE) + { + if (i == 0) // accept the first set of values, no matter how bad it might be. + { + MinX = X[i]; + MinY = Y[i]; + MaxX = X[i]; + MaxY = Y[i]; + } + else // now compare if you get "better" values + { + if (MinX > X[i]) MinX = X[i]; + if (MinY > Y[i]) MinY = Y[i]; + if (MaxX < X[i]) MaxX = X[i]; + if (MaxY < Y[i]) MaxY = Y[i]; + } + } + else + { + MinX = 0; + MinY = 0; + MaxX = 0; + MaxY = 0; + break; + } + } +} + +TextOverlay::~TextOverlay() +{ + Ogre::OverlayManager::OverlayMapIterator iter = Ogre::OverlayManager::getSingleton().getOverlayIterator(); + if(!iter.hasMoreElements()) + mOverlay->hide(); + + Ogre::OverlayManager *overlayMgr = Ogre::OverlayManager::getSingletonPtr(); + mContainer->removeChild("text"+mId); + mOverlay->remove2D(mContainer); + overlayMgr->destroyOverlayElement(mElement); + overlayMgr->destroyOverlayElement(mContainer); + + if(!iter.hasMoreElements()) + overlayMgr->destroy(mOverlay); +} + +void TextOverlay::enable(bool enable) +{ + mEnabled = enable; + if (enable) + mOverlay->show(); + else + mOverlay->hide(); +} + +void TextOverlay::setCaption(const Ogre::String& text) +{ + if(mCaption == text) + return; + + mCaption = text; + mElement->setCaption(text); +} + +Ogre::FontPtr TextOverlay::getFont() +{ + return mFont; +} + +int TextOverlay::textWidth() +{ + float textWidth = 0; + + // NOTE: assumed fixed width font, i.e. no compensation for narrow glyphs + for(Ogre::String::const_iterator i = mCaption.begin(); i < mCaption.end(); ++i) + textWidth += getFont()->getGlyphAspectRatio(*i); + + textWidth *= fontHeight(); + + return (int) textWidth; +} + +int TextOverlay::fontHeight() +{ + return mFontHeight; +} + +void TextOverlay::update(bool toggleOverlay) +{ + if(toggleOverlay) + mEnabled = !mEnabled; + + if (!mEnabled) + { + mOverlay->hide(); + Ogre::Root::getSingleton().renderOneFrame(); + return; + } + else + mOverlay->show(); + + float min_x, max_x, min_y, max_y; + getMinMaxEdgesOfTopAABBIn2D(min_x, min_y, max_x, max_y); + + if ((min_x>0.0) && (max_x<1.0) && (min_y>0.0) && (max_y<1.0)) + { + mOnScreen = true; + mContainer->show(); + } + else + { + mOnScreen = false; + mContainer->hide(); + Ogre::Root::getSingleton().renderOneFrame(); + return; + } + + Ogre::OverlayManager &overlayMgr = Ogre::OverlayManager::getSingleton(); + float viewportWidth = std::max(overlayMgr.getViewportWidth(), 1); // zero at the start + float viewportHeight = std::max(overlayMgr.getViewportHeight(), 1); // zero at the start + + float relTextWidth = (2*sMargin + textWidth() + sMargin) / viewportWidth; // 2 = fudge factor + float relTextHeight = (sMargin + fontHeight() + sMargin) / viewportHeight; + + mContainer->setMetricsMode(Ogre::GMM_RELATIVE); + mContainer->setPosition(1-(min_x + max_x + relTextWidth)/2, 1-max_y-(relTextHeight-sMargin/viewportHeight)); + + mContainer->setDimensions(relTextWidth, relTextHeight); + + Ogre::Root::getSingleton().renderOneFrame(); +} + +} diff --git a/apps/opencs/view/render/textoverlay.hpp b/apps/opencs/view/render/textoverlay.hpp new file mode 100644 index 0000000000..a90b301946 --- /dev/null +++ b/apps/opencs/view/render/textoverlay.hpp @@ -0,0 +1,54 @@ +#ifndef OPENCS_VIEW_TEXTOVERLAY_H +#define OPENCS_VIEW_TEXTOVERLAY_H + +#include +#include + +namespace Ogre +{ + class MovableObject; + class Camera; + class Font; + class Overlay; + class OverlayContainer; + class TextAreaOverlayElement; +} + +namespace CSVRender +{ + + class TextOverlay + { + Ogre::Overlay* mOverlay; + Ogre::OverlayContainer* mContainer; + Ogre::TextAreaOverlayElement* mElement; + Ogre::String mCaption; + + const Ogre::MovableObject* mObj; + const Ogre::Camera* mCamera; + Ogre::FontPtr mFont; + int mFontHeight; // in pixels + Ogre::String mId; + + bool mEnabled; + bool mOnScreen; // not used + + Ogre::FontPtr getFont(); + int textWidth(); + int fontHeight(); + void getScreenCoordinates(const Ogre::Vector3& position, Ogre::Real& x, Ogre::Real& y); + void getMinMaxEdgesOfTopAABBIn2D(float& MinX, float& MinY, float& MaxX, float& MaxY); + + public: + + TextOverlay(const Ogre::MovableObject* obj, const Ogre::Camera* camera, const Ogre::String &id); + virtual ~TextOverlay(); + + void enable(bool enable); + void setCaption(const Ogre::String& text); + void update(bool toggleOverlay = false); + }; + +} + +#endif // OPENCS_VIEW_TEXTOVERLAY_H diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index fa304dd829..eca00fcbae 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -314,3 +314,6 @@ void CSVRender::WorldspaceWidget::elementSelectionChanged() setVisibilityMask (getElementMask()); flagAsModified(); } + +void CSVRender::WorldspaceWidget::updateOverlay(bool toggleOverlay) +{ } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 0754e9ecff..a7d3a78826 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -88,6 +88,8 @@ namespace CSVRender CSMDoc::Document& getDocument(); + virtual void updateOverlay(bool toggleOverlay = false); + private: void dragEnterEvent(QDragEnterEvent *event); @@ -134,4 +136,4 @@ namespace CSVRender }; } -#endif \ No newline at end of file +#endif