2011-11-01 03:59:16 +00:00
|
|
|
#include "objects.hpp"
|
2012-02-06 09:41:13 +00:00
|
|
|
|
2011-11-02 04:13:33 +00:00
|
|
|
#include <OgreSceneNode.h>
|
2012-02-06 09:41:13 +00:00
|
|
|
|
2011-11-03 23:40:37 +00:00
|
|
|
#include <components/nifogre/ogre_nif_loader.hpp>
|
2012-04-02 12:24:16 +00:00
|
|
|
#include <components/settings/settings.hpp>
|
2012-04-03 13:13:47 +00:00
|
|
|
#include "renderconst.hpp"
|
2011-11-01 03:59:16 +00:00
|
|
|
|
2011-11-08 04:35:39 +00:00
|
|
|
using namespace MWRender;
|
|
|
|
|
2011-11-03 23:40:37 +00:00
|
|
|
bool Objects::lightConst = false;
|
|
|
|
float Objects::lightConstValue = 0.0f;
|
|
|
|
|
|
|
|
bool Objects::lightLinear = true;
|
|
|
|
int Objects::lightLinearMethod = 1;
|
|
|
|
float Objects::lightLinearValue = 3;
|
|
|
|
float Objects::lightLinearRadiusMult = 1;
|
|
|
|
|
|
|
|
bool Objects::lightQuadratic = false;
|
|
|
|
int Objects::lightQuadraticMethod = 2;
|
|
|
|
float Objects::lightQuadraticValue = 16;
|
|
|
|
float Objects::lightQuadraticRadiusMult = 1;
|
|
|
|
|
|
|
|
bool Objects::lightOutQuadInLin = false;
|
|
|
|
|
|
|
|
int Objects::uniqueID = 0;
|
2011-11-01 03:59:16 +00:00
|
|
|
|
2012-02-06 09:29:18 +00:00
|
|
|
void Objects::clearSceneNode (Ogre::SceneNode *node)
|
|
|
|
{
|
|
|
|
/// \todo This should probably be moved into OpenEngine at some point.
|
|
|
|
for (int i=node->numAttachedObjects()-1; i>=0; --i)
|
|
|
|
{
|
|
|
|
Ogre::MovableObject *object = node->getAttachedObject (i);
|
|
|
|
node->detachObject (object);
|
2012-02-06 09:41:13 +00:00
|
|
|
mRenderer.getScene()->destroyMovableObject (object);
|
2012-02-06 09:29:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-06 09:41:13 +00:00
|
|
|
void Objects::setMwRoot(Ogre::SceneNode* root)
|
|
|
|
{
|
2011-11-22 07:39:28 +00:00
|
|
|
mMwRoot = root;
|
2011-11-17 22:10:27 +00:00
|
|
|
}
|
2012-02-06 09:41:13 +00:00
|
|
|
|
|
|
|
void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_)
|
|
|
|
{
|
2011-11-22 07:39:28 +00:00
|
|
|
Ogre::SceneNode* root = mMwRoot;
|
2011-11-05 01:57:39 +00:00
|
|
|
Ogre::SceneNode* cellnode;
|
|
|
|
if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end())
|
|
|
|
{
|
2011-11-21 11:52:28 +00:00
|
|
|
//Create the scenenode and put it in the map
|
|
|
|
cellnode = root->createChildSceneNode();
|
2011-11-05 01:57:39 +00:00
|
|
|
mCellSceneNodes[ptr.getCell()] = cellnode;
|
2011-11-21 11:52:28 +00:00
|
|
|
}
|
|
|
|
else
|
2011-11-05 01:57:39 +00:00
|
|
|
{
|
|
|
|
cellnode = mCellSceneNodes[ptr.getCell()];
|
|
|
|
}
|
2011-11-05 01:48:52 +00:00
|
|
|
|
2011-11-05 01:57:39 +00:00
|
|
|
Ogre::SceneNode* insert = cellnode->createChildSceneNode();
|
2011-11-09 18:53:29 +00:00
|
|
|
const float *f = ptr.getRefData().getPosition().pos;
|
2011-11-05 01:57:39 +00:00
|
|
|
insert->setPosition(f[0], f[1], f[2]);
|
|
|
|
insert->setScale(ptr.getCellRef().scale, ptr.getCellRef().scale, ptr.getCellRef().scale);
|
2011-11-03 23:40:37 +00:00
|
|
|
|
2011-11-05 01:57:39 +00:00
|
|
|
// Convert MW rotation to a quaternion:
|
|
|
|
f = ptr.getCellRef().pos.rot;
|
2011-11-03 23:40:37 +00:00
|
|
|
|
2011-11-05 01:57:39 +00:00
|
|
|
// Rotate around X axis
|
2012-02-06 09:41:13 +00:00
|
|
|
Ogre::Quaternion xr(Ogre::Radian(-f[0]), Ogre::Vector3::UNIT_X);
|
2011-11-03 23:40:37 +00:00
|
|
|
|
2011-11-05 01:57:39 +00:00
|
|
|
// Rotate around Y axis
|
2012-02-06 09:41:13 +00:00
|
|
|
Ogre::Quaternion yr(Ogre::Radian(-f[1]), Ogre::Vector3::UNIT_Y);
|
2011-11-03 23:40:37 +00:00
|
|
|
|
2011-11-05 01:57:39 +00:00
|
|
|
// Rotate around Z axis
|
2012-02-06 09:41:13 +00:00
|
|
|
Ogre::Quaternion zr(Ogre::Radian(-f[2]), Ogre::Vector3::UNIT_Z);
|
2011-11-03 23:40:37 +00:00
|
|
|
|
2012-02-06 09:41:13 +00:00
|
|
|
// Rotates first around z, then y, then x
|
2011-11-05 01:57:39 +00:00
|
|
|
insert->setOrientation(xr*yr*zr);
|
2012-02-06 09:29:18 +00:00
|
|
|
|
2011-11-05 01:57:39 +00:00
|
|
|
if (!enabled)
|
|
|
|
insert->setVisible (false);
|
2011-11-03 02:41:48 +00:00
|
|
|
ptr.getRefData().setBaseNode(insert);
|
2012-02-06 09:41:13 +00:00
|
|
|
mIsStatic = static_;
|
2011-11-01 03:59:16 +00:00
|
|
|
}
|
2012-02-06 09:41:13 +00:00
|
|
|
|
|
|
|
void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
|
|
|
|
{
|
2011-11-11 19:37:42 +00:00
|
|
|
Ogre::SceneNode* insert = ptr.getRefData().getBaseNode();
|
2011-11-05 01:57:39 +00:00
|
|
|
assert(insert);
|
2011-11-03 23:40:37 +00:00
|
|
|
|
2011-11-05 01:57:39 +00:00
|
|
|
NifOgre::NIFLoader::load(mesh);
|
2012-02-06 09:41:13 +00:00
|
|
|
Ogre::Entity *ent = mRenderer.getScene()->createEntity(mesh);
|
2011-11-03 23:40:37 +00:00
|
|
|
|
2012-04-02 13:30:29 +00:00
|
|
|
|
2012-03-26 22:45:25 +00:00
|
|
|
Ogre::Vector3 extents = ent->getBoundingBox().getSize();
|
|
|
|
extents *= insert->getScale();
|
2012-04-02 13:30:29 +00:00
|
|
|
float size = std::max(std::max(extents.x, extents.y), extents.z);
|
2012-03-26 22:45:25 +00:00
|
|
|
|
2012-04-02 14:14:39 +00:00
|
|
|
bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && Settings::Manager::getBool("limit small object distance", "Objects");
|
2012-03-26 22:45:25 +00:00
|
|
|
|
|
|
|
// do not fade out doors. that will cause holes and look stupid
|
|
|
|
if (ptr.getTypeName().find("Door") != std::string::npos)
|
|
|
|
small = false;
|
|
|
|
|
2012-03-29 14:47:59 +00:00
|
|
|
if (mBounds.find(ptr.getCell()) == mBounds.end())
|
|
|
|
mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL;
|
|
|
|
|
|
|
|
Ogre::AxisAlignedBox bounds = ent->getBoundingBox();
|
2012-03-29 15:30:13 +00:00
|
|
|
bounds = Ogre::AxisAlignedBox(
|
|
|
|
insert->_getDerivedPosition() + bounds.getMinimum(),
|
|
|
|
insert->_getDerivedPosition() + bounds.getMaximum()
|
|
|
|
);
|
|
|
|
|
2012-03-29 14:47:59 +00:00
|
|
|
bounds.scale(insert->getScale());
|
|
|
|
mBounds[ptr.getCell()].merge(bounds);
|
|
|
|
|
2012-04-04 16:53:40 +00:00
|
|
|
bool transparent = false;
|
|
|
|
for (unsigned int i=0; i<ent->getNumSubEntities(); ++i)
|
|
|
|
{
|
|
|
|
Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial();
|
|
|
|
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
|
|
|
|
while (techIt.hasMoreElements())
|
|
|
|
{
|
|
|
|
Ogre::Technique* tech = techIt.getNext();
|
|
|
|
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
|
|
|
|
while (passIt.hasMoreElements())
|
|
|
|
{
|
|
|
|
Ogre::Pass* pass = passIt.getNext();
|
|
|
|
|
|
|
|
if (pass->getDepthWriteEnabled() == false)
|
|
|
|
transparent = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-02 12:24:16 +00:00
|
|
|
if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects"))
|
2011-11-05 01:57:39 +00:00
|
|
|
{
|
|
|
|
insert->attachObject(ent);
|
2012-03-26 22:45:25 +00:00
|
|
|
|
2012-04-03 13:13:47 +00:00
|
|
|
ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0);
|
|
|
|
ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc);
|
2012-04-05 17:07:21 +00:00
|
|
|
ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
|
2011-11-05 01:57:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-11-21 11:52:28 +00:00
|
|
|
Ogre::StaticGeometry* sg = 0;
|
2012-03-26 22:45:25 +00:00
|
|
|
|
2012-04-05 17:07:21 +00:00
|
|
|
if (transparent)
|
|
|
|
{
|
|
|
|
if( mStaticGeometryAlpha.find(ptr.getCell()) == mStaticGeometryAlpha.end())
|
|
|
|
{
|
|
|
|
uniqueID = uniqueID +1;
|
|
|
|
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
|
|
|
mStaticGeometryAlpha[ptr.getCell()] = sg;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sg = mStaticGeometryAlpha[ptr.getCell()];
|
|
|
|
}
|
|
|
|
else if (small)
|
2011-11-05 01:57:39 +00:00
|
|
|
{
|
2012-03-26 22:45:25 +00:00
|
|
|
if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end())
|
|
|
|
{
|
|
|
|
uniqueID = uniqueID +1;
|
|
|
|
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
|
|
|
mStaticGeometrySmall[ptr.getCell()] = sg;
|
|
|
|
|
2012-04-05 17:07:21 +00:00
|
|
|
sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance"));
|
2012-03-26 22:45:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
sg = mStaticGeometrySmall[ptr.getCell()];
|
2011-11-05 01:57:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-03-26 22:45:25 +00:00
|
|
|
if( mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
|
|
|
|
{
|
|
|
|
|
|
|
|
uniqueID = uniqueID +1;
|
|
|
|
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
|
|
|
mStaticGeometry[ptr.getCell()] = sg;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sg = mStaticGeometry[ptr.getCell()];
|
2011-11-05 01:57:39 +00:00
|
|
|
}
|
2012-03-29 16:04:52 +00:00
|
|
|
|
2012-03-26 22:45:25 +00:00
|
|
|
// This specifies the size of a single batch region.
|
|
|
|
// If it is set too high:
|
|
|
|
// - there will be problems choosing the correct lights
|
|
|
|
// - the culling will be more inefficient
|
|
|
|
// If it is set too low:
|
|
|
|
// - there will be too many batches.
|
|
|
|
sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500));
|
|
|
|
|
2011-11-05 01:57:39 +00:00
|
|
|
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
|
|
|
|
|
2012-04-03 13:13:47 +00:00
|
|
|
sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics);
|
|
|
|
|
2012-04-05 17:07:21 +00:00
|
|
|
sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
|
|
|
|
|
2012-02-06 09:41:13 +00:00
|
|
|
mRenderer.getScene()->destroyEntity(ent);
|
2011-11-05 01:57:39 +00:00
|
|
|
}
|
2011-11-01 03:59:16 +00:00
|
|
|
}
|
2012-02-06 09:41:13 +00:00
|
|
|
|
|
|
|
void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius)
|
|
|
|
{
|
|
|
|
Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle());
|
2011-11-05 01:57:39 +00:00
|
|
|
assert(insert);
|
2012-02-06 09:41:13 +00:00
|
|
|
Ogre::Light *light = mRenderer.getScene()->createLight();
|
2011-11-05 01:57:39 +00:00
|
|
|
light->setDiffuseColour (r, g, b);
|
2012-04-02 17:37:24 +00:00
|
|
|
mLights.push_back(light->getName());
|
2011-11-03 23:40:37 +00:00
|
|
|
|
2011-11-05 01:57:39 +00:00
|
|
|
float cval=0.0f, lval=0.0f, qval=0.0f;
|
2011-11-03 23:40:37 +00:00
|
|
|
|
2011-11-05 01:57:39 +00:00
|
|
|
if(lightConst)
|
|
|
|
cval = lightConstValue;
|
2012-02-06 09:41:13 +00:00
|
|
|
|
|
|
|
if(!lightOutQuadInLin)
|
|
|
|
{
|
|
|
|
if(lightLinear)
|
|
|
|
radius *= lightLinearRadiusMult;
|
|
|
|
if(lightQuadratic)
|
|
|
|
radius *= lightQuadraticRadiusMult;
|
|
|
|
|
|
|
|
if(lightLinear)
|
|
|
|
lval = lightLinearValue / pow(radius, lightLinearMethod);
|
|
|
|
if(lightQuadratic)
|
|
|
|
qval = lightQuadraticValue / pow(radius, lightQuadraticMethod);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// FIXME:
|
|
|
|
// Do quadratic or linear, depending if we're in an exterior or interior
|
|
|
|
// cell, respectively. Ignore lightLinear and lightQuadratic.
|
|
|
|
}
|
|
|
|
|
|
|
|
light->setAttenuation(10*radius, cval, lval, qval);
|
|
|
|
|
|
|
|
insert->attachObject(light);
|
2011-11-01 03:59:16 +00:00
|
|
|
}
|
2011-11-02 04:13:33 +00:00
|
|
|
|
2011-11-21 11:52:28 +00:00
|
|
|
bool Objects::deleteObject (const MWWorld::Ptr& ptr)
|
2011-11-05 01:48:52 +00:00
|
|
|
{
|
2011-11-21 11:52:28 +00:00
|
|
|
if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode())
|
2011-11-05 01:48:52 +00:00
|
|
|
{
|
2011-11-21 11:52:28 +00:00
|
|
|
Ogre::SceneNode *parent = base->getParentSceneNode();
|
|
|
|
|
|
|
|
for (std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *>::const_iterator iter (
|
|
|
|
mCellSceneNodes.begin()); iter!=mCellSceneNodes.end(); ++iter)
|
|
|
|
if (iter->second==parent)
|
|
|
|
{
|
2012-02-06 09:29:18 +00:00
|
|
|
clearSceneNode (base);
|
2011-11-21 11:52:28 +00:00
|
|
|
base->removeAndDestroyAllChildren();
|
2012-02-06 09:41:13 +00:00
|
|
|
mRenderer.getScene()->destroySceneNode (base);
|
2011-11-21 11:52:28 +00:00
|
|
|
ptr.getRefData().setBaseNode (0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2011-11-05 01:48:52 +00:00
|
|
|
}
|
2011-11-21 11:52:28 +00:00
|
|
|
|
|
|
|
return true;
|
2011-11-05 01:48:52 +00:00
|
|
|
}
|
|
|
|
|
2012-02-06 09:41:13 +00:00
|
|
|
void Objects::removeCell(MWWorld::Ptr::CellStore* store)
|
|
|
|
{
|
2011-11-21 11:52:28 +00:00
|
|
|
if(mCellSceneNodes.find(store) != mCellSceneNodes.end())
|
2011-11-05 01:48:52 +00:00
|
|
|
{
|
2011-11-19 06:01:19 +00:00
|
|
|
Ogre::SceneNode* base = mCellSceneNodes[store];
|
2012-02-06 09:29:18 +00:00
|
|
|
|
|
|
|
for (int i=0; i<base->numChildren(); ++i)
|
|
|
|
clearSceneNode (static_cast<Ogre::SceneNode *> (base->getChild (i)));
|
|
|
|
|
2011-11-05 01:57:39 +00:00
|
|
|
base->removeAndDestroyAllChildren();
|
2011-11-20 01:22:56 +00:00
|
|
|
mCellSceneNodes.erase(store);
|
2012-02-06 09:41:13 +00:00
|
|
|
mRenderer.getScene()->destroySceneNode(base);
|
2011-11-21 11:52:28 +00:00
|
|
|
base = 0;
|
2011-11-05 01:48:52 +00:00
|
|
|
}
|
|
|
|
|
2012-02-06 09:41:13 +00:00
|
|
|
if(mStaticGeometry.find(store) != mStaticGeometry.end())
|
2011-11-05 01:48:52 +00:00
|
|
|
{
|
2012-02-06 09:41:13 +00:00
|
|
|
Ogre::StaticGeometry* sg = mStaticGeometry[store];
|
|
|
|
mStaticGeometry.erase(store);
|
|
|
|
mRenderer.getScene()->destroyStaticGeometry (sg);
|
2011-11-05 01:48:52 +00:00
|
|
|
sg = 0;
|
|
|
|
}
|
2012-03-26 22:45:25 +00:00
|
|
|
if(mStaticGeometrySmall.find(store) != mStaticGeometrySmall.end())
|
|
|
|
{
|
|
|
|
Ogre::StaticGeometry* sg = mStaticGeometrySmall[store];
|
|
|
|
mStaticGeometrySmall.erase(store);
|
|
|
|
mRenderer.getScene()->destroyStaticGeometry (sg);
|
|
|
|
sg = 0;
|
|
|
|
}
|
2012-04-05 17:07:21 +00:00
|
|
|
if(mStaticGeometryAlpha.find(store) != mStaticGeometryAlpha.end())
|
|
|
|
{
|
|
|
|
Ogre::StaticGeometry* sg = mStaticGeometryAlpha[store];
|
|
|
|
mStaticGeometryAlpha.erase(store);
|
|
|
|
mRenderer.getScene()->destroyStaticGeometry (sg);
|
|
|
|
sg = 0;
|
|
|
|
}
|
2012-03-29 16:04:52 +00:00
|
|
|
|
2012-03-10 14:28:18 +00:00
|
|
|
if(mBounds.find(store) != mBounds.end())
|
|
|
|
mBounds.erase(store);
|
2011-11-05 01:48:52 +00:00
|
|
|
}
|
2012-02-06 09:29:18 +00:00
|
|
|
|
2012-02-06 09:41:13 +00:00
|
|
|
void Objects::buildStaticGeometry(ESMS::CellStore<MWWorld::RefData>& cell)
|
|
|
|
{
|
|
|
|
if(mStaticGeometry.find(&cell) != mStaticGeometry.end())
|
2011-11-05 18:57:33 +00:00
|
|
|
{
|
2012-02-06 09:41:13 +00:00
|
|
|
Ogre::StaticGeometry* sg = mStaticGeometry[&cell];
|
2011-11-21 11:52:28 +00:00
|
|
|
sg->build();
|
2011-11-05 18:57:33 +00:00
|
|
|
}
|
2012-03-26 22:45:25 +00:00
|
|
|
if(mStaticGeometrySmall.find(&cell) != mStaticGeometrySmall.end())
|
|
|
|
{
|
|
|
|
Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell];
|
|
|
|
sg->build();
|
|
|
|
}
|
2012-04-05 17:07:21 +00:00
|
|
|
if(mStaticGeometryAlpha.find(&cell) != mStaticGeometryAlpha.end())
|
|
|
|
{
|
|
|
|
Ogre::StaticGeometry* sg = mStaticGeometryAlpha[&cell];
|
|
|
|
sg->build();
|
|
|
|
}
|
2011-11-05 18:57:33 +00:00
|
|
|
}
|
2012-03-10 14:28:18 +00:00
|
|
|
|
|
|
|
Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
|
|
|
|
{
|
|
|
|
return mBounds[cell];
|
|
|
|
}
|
2012-04-02 17:37:24 +00:00
|
|
|
|
|
|
|
void Objects::enableLights()
|
|
|
|
{
|
|
|
|
std::vector<std::string>::iterator it = mLights.begin();
|
|
|
|
while (it != mLights.end())
|
|
|
|
{
|
|
|
|
if (mMwRoot->getCreator()->hasLight(*it))
|
|
|
|
{
|
|
|
|
mMwRoot->getCreator()->getLight(*it)->setVisible(true);
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
it = mLights.erase(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Objects::disableLights()
|
|
|
|
{
|
|
|
|
std::vector<std::string>::iterator it = mLights.begin();
|
|
|
|
while (it != mLights.end())
|
|
|
|
{
|
|
|
|
if (mMwRoot->getCreator()->hasLight(*it))
|
|
|
|
{
|
|
|
|
mMwRoot->getCreator()->getLight(*it)->setVisible(false);
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
it = mLights.erase(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|