mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-03 01:49:41 +00:00
Working version. White lines still present. Marker toggle hard-coded to 'm' key. Mouse events not implemented.
This commit is contained in:
parent
c9e054cdd7
commit
85d93807c5
9 changed files with 458 additions and 88 deletions
|
@ -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
|
||||
|
|
|
@ -4,17 +4,13 @@
|
|||
#include <sstream>
|
||||
|
||||
#include <OgreCamera.h>
|
||||
#include <OgreTextureManager.h>
|
||||
#include <OgreTechnique.h>
|
||||
#include <OgreMaterialManager.h>
|
||||
#include <OgreBillboardSet.h>
|
||||
#include <OgreBillboard.h>
|
||||
#include <OgreHardwarePixelBuffer.h>
|
||||
#include <OgreSceneManager.h>
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
#include <QEvent>
|
||||
#include <QPainter>
|
||||
#include <OgreManualObject.h>
|
||||
#include <OgreEntity.h>
|
||||
|
||||
#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<CSMWorld::CellCoordinates, Cell *>::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<std::string, Ogre::Entity *>::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<CSVRender::TextOverlay *>::iterator it = mTextOverlays.begin();
|
||||
for(; it != mTextOverlays.end(); ++it)
|
||||
{
|
||||
(*it)->update(toggleOverlay);
|
||||
}
|
||||
std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
|
||||
|
||||
#if 0
|
||||
if(toggleOverlay)
|
||||
{
|
||||
while (iter!=mCells.end())
|
||||
{
|
||||
std::map<std::string, Ogre::Entity *>::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<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
|
||||
iter!=mCells.end(); ++iter)
|
||||
{
|
||||
delete iter->second;
|
||||
|
||||
std::map<std::string, Ogre::Entity *>::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)
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
|
||||
namespace CSVRender
|
||||
{
|
||||
|
||||
class TextOverlay;
|
||||
|
||||
class PagedWorldspaceWidget : public WorldspaceWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -19,7 +22,8 @@ namespace CSVRender
|
|||
std::map<CSMWorld::CellCoordinates, Cell *> mCells;
|
||||
std::string mWorldspace;
|
||||
CSVWidget::SceneToolToggle *mControlElements;
|
||||
bool mDisplayCellCoord;
|
||||
std::list<TextOverlay *> mTextOverlays;
|
||||
std::map<std::string, Ogre::Entity*> 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<CSMWorld::UniversalId>& 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);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <OgreCamera.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreViewport.h>
|
||||
#include <Overlay/OgreOverlaySystem.h>
|
||||
|
||||
#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)
|
||||
|
|
|
@ -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);
|
||||
|
|
301
apps/opencs/view/render/textoverlay.cpp
Normal file
301
apps/opencs/view/render/textoverlay.cpp
Normal file
|
@ -0,0 +1,301 @@
|
|||
#include "textoverlay.hpp"
|
||||
|
||||
#include <OgreCamera.h>
|
||||
#include <OgreMaterialManager.h>
|
||||
#include <OgreTechnique.h>
|
||||
|
||||
#include <Overlay/OgreOverlayManager.h>
|
||||
#include <Overlay/OgreOverlayContainer.h>
|
||||
#include <Overlay/OgreFontManager.h>
|
||||
#include <Overlay/OgreTextAreaOverlayElement.h>
|
||||
#include <OgreEntity.h>
|
||||
#include <OgreViewport.h>
|
||||
#include <OgreRoot.h>
|
||||
#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<uint8_t*>(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<Ogre::OverlayContainer*>(overlayMgr.createOverlayElement("Panel", "container"+mId));
|
||||
mContainer->setMaterialName("TransOverlayMaterial");
|
||||
mOverlay->add2D(mContainer);
|
||||
|
||||
// setup text area overlay element
|
||||
mElement = static_cast<Ogre::TextAreaOverlayElement*>(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();
|
||||
}
|
||||
|
||||
}
|
54
apps/opencs/view/render/textoverlay.hpp
Normal file
54
apps/opencs/view/render/textoverlay.hpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef OPENCS_VIEW_TEXTOVERLAY_H
|
||||
#define OPENCS_VIEW_TEXTOVERLAY_H
|
||||
|
||||
#include <OgreString.h>
|
||||
#include <Overlay/OgreFont.h>
|
||||
|
||||
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
|
|
@ -314,3 +314,6 @@ void CSVRender::WorldspaceWidget::elementSelectionChanged()
|
|||
setVisibilityMask (getElementMask());
|
||||
flagAsModified();
|
||||
}
|
||||
|
||||
void CSVRender::WorldspaceWidget::updateOverlay(bool toggleOverlay)
|
||||
{ }
|
||||
|
|
|
@ -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
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue