1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 08:49:55 +00:00
openmw-tes3mp/apps/openmw/mwrender/water.cpp

222 lines
6.5 KiB
C++
Raw Normal View History

2012-01-14 23:34:14 +00:00
#include "water.hpp"
2012-05-29 04:45:44 +00:00
2015-06-02 14:35:35 +00:00
#include <iomanip>
2012-01-14 23:34:14 +00:00
2015-06-02 14:35:35 +00:00
#include <osg/Group>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/PositionAttitudeTransform>
#include <osg/Depth>
2015-06-02 23:18:36 +00:00
#include <osgUtil/IncrementalCompileOperation>
2015-06-02 14:35:35 +00:00
#include <components/resource/resourcesystem.hpp>
#include <components/resource/texturemanager.hpp>
2015-06-02 14:35:35 +00:00
#include <components/nifosg/controller.hpp>
#include <components/sceneutil/controller.hpp>
2015-06-02 14:35:35 +00:00
#include "vismask.hpp"
2015-06-16 18:36:48 +00:00
#include "ripplesimulation.hpp"
2015-06-02 14:35:35 +00:00
namespace
{
2015-06-02 14:35:35 +00:00
osg::ref_ptr<osg::Geometry> createWaterGeometry(float size, int segments, float textureRepeats)
{
2015-06-02 14:35:35 +00:00
osg::ref_ptr<osg::Vec3Array> verts (new osg::Vec3Array);
osg::ref_ptr<osg::Vec2Array> texcoords (new osg::Vec2Array);
// some drivers don't like huge triangles, so we do some subdivisons
// a paged solution would be even better
const float step = size/segments;
const float texCoordStep = textureRepeats / segments;
for (int x=0; x<segments; ++x)
{
for (int y=0; y<segments; ++y)
{
float x1 = -size/2.f + x*step;
float y1 = -size/2.f + y*step;
float x2 = x1 + step;
float y2 = y1 + step;
verts->push_back(osg::Vec3f(x1, y2, 0.f));
verts->push_back(osg::Vec3f(x1, y1, 0.f));
verts->push_back(osg::Vec3f(x2, y1, 0.f));
verts->push_back(osg::Vec3f(x2, y2, 0.f));
float u1 = x*texCoordStep;
float v1 = y*texCoordStep;
float u2 = u1 + texCoordStep;
float v2 = v1 + texCoordStep;
texcoords->push_back(osg::Vec2f(u1, v2));
texcoords->push_back(osg::Vec2f(u1, v1));
texcoords->push_back(osg::Vec2f(u2, v1));
texcoords->push_back(osg::Vec2f(u2, v2));
}
}
2015-06-02 14:35:35 +00:00
osg::ref_ptr<osg::Geometry> waterGeom (new osg::Geometry);
waterGeom->setVertexArray(verts);
waterGeom->setTexCoordArray(0, texcoords);
2015-06-02 14:35:35 +00:00
waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size()));
return waterGeom;
}
2012-07-20 12:45:42 +00:00
2015-06-02 14:35:35 +00:00
void createWaterStateSet(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Node> node)
2012-04-11 16:53:13 +00:00
{
2015-06-02 14:35:35 +00:00
osg::ref_ptr<osg::StateSet> stateset (new osg::StateSet);
2012-04-12 14:46:56 +00:00
2015-06-02 14:35:35 +00:00
osg::ref_ptr<osg::Material> material (new osg::Material);
material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f));
material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f));
material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f));
material->setColorMode(osg::Material::OFF);
stateset->setAttributeAndModes(material, osg::StateAttribute::ON);
2012-04-12 14:46:56 +00:00
2015-06-02 14:35:35 +00:00
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
2012-04-12 14:46:56 +00:00
2015-06-02 14:35:35 +00:00
osg::ref_ptr<osg::Depth> depth (new osg::Depth);
depth->setWriteMask(false);
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
2012-04-11 16:53:13 +00:00
2015-06-02 14:35:35 +00:00
stateset->setRenderBinDetails(9, "RenderBin");
2012-04-12 14:46:56 +00:00
2015-06-02 14:35:35 +00:00
std::vector<osg::ref_ptr<osg::Texture2D> > textures;
for (int i=0; i<32; ++i)
2012-04-11 16:53:13 +00:00
{
2015-06-02 14:35:35 +00:00
std::ostringstream texname;
texname << "textures/water/water" << std::setw(2) << std::setfill('0') << i << ".dds";
textures.push_back(resourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT));
2012-04-11 16:53:13 +00:00
}
2012-03-29 13:49:24 +00:00
2015-06-02 14:35:35 +00:00
osg::ref_ptr<NifOsg::FlipController> controller (new NifOsg::FlipController(0, 2/32.f, textures));
controller->setSource(boost::shared_ptr<SceneUtil::ControllerSource>(new SceneUtil::FrameTimeSource));
node->addUpdateCallback(controller);
node->setStateSet(stateset);
stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON);
}
2012-04-03 13:13:47 +00:00
}
2012-01-22 21:38:10 +00:00
2015-06-02 14:35:35 +00:00
namespace MWRender
{
2015-06-02 14:35:35 +00:00
// --------------------------------------------------------------------------------------------------------------------------------
2012-01-20 22:59:56 +00:00
2015-06-16 18:36:48 +00:00
Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback)
2015-06-02 14:35:35 +00:00
: mParent(parent)
, mResourceSystem(resourceSystem)
, mEnabled(true)
, mToggled(true)
, mTop(0)
{
2015-06-16 18:36:48 +00:00
mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback));
2015-06-02 14:35:35 +00:00
osg::ref_ptr<osg::Geometry> waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900);
2012-03-29 13:49:24 +00:00
2015-06-02 14:35:35 +00:00
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(waterGeom);
geode->setNodeMask(Mask_Water);
2012-07-19 20:23:07 +00:00
2015-06-02 23:18:36 +00:00
if (ico)
ico->add(geode);
2015-06-02 14:35:35 +00:00
createWaterStateSet(mResourceSystem, geode);
2015-06-02 14:35:35 +00:00
mWaterNode = new osg::PositionAttitudeTransform;
mWaterNode->addChild(geode);
2012-07-19 20:23:07 +00:00
2015-06-02 14:35:35 +00:00
mParent->addChild(mWaterNode);
2012-07-19 20:23:07 +00:00
2015-06-02 14:35:35 +00:00
setHeight(mTop);
}
2012-01-14 23:34:14 +00:00
2015-06-02 14:35:35 +00:00
Water::~Water()
{
2015-06-02 14:35:35 +00:00
mParent->removeChild(mWaterNode);
}
2012-01-14 23:34:14 +00:00
2015-06-02 14:35:35 +00:00
void Water::setEnabled(bool enabled)
{
2015-06-02 14:35:35 +00:00
mEnabled = enabled;
2012-04-12 14:46:56 +00:00
updateVisible();
2012-01-14 23:34:14 +00:00
}
2015-06-02 14:35:35 +00:00
void Water::changeCell(const MWWorld::CellStore* store)
{
2015-06-02 14:35:35 +00:00
if (store->getCell()->isExterior())
mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY));
else
mWaterNode->setPosition(osg::Vec3f(0,0,mTop));
}
2015-06-02 14:35:35 +00:00
void Water::setHeight(const float height)
2012-04-05 13:30:55 +00:00
{
2015-06-02 14:35:35 +00:00
mTop = height;
2012-04-05 13:30:55 +00:00
2015-06-17 20:49:20 +00:00
mSimulation->setWaterHeight(height);
2015-06-02 14:35:35 +00:00
osg::Vec3f pos = mWaterNode->getPosition();
pos.z() = height;
mWaterNode->setPosition(pos);
2012-04-18 23:08:26 +00:00
}
2015-06-16 18:36:48 +00:00
void Water::update(float dt)
{
mSimulation->update(dt);
}
2015-06-02 14:35:35 +00:00
void Water::updateVisible()
2012-04-18 23:08:26 +00:00
{
2015-06-02 14:35:35 +00:00
mWaterNode->setNodeMask(mEnabled && mToggled ? ~0 : 0);
}
2015-06-02 14:35:35 +00:00
bool Water::toggle()
2012-05-29 04:45:44 +00:00
{
2015-06-02 14:35:35 +00:00
mToggled = !mToggled;
updateVisible();
2015-06-02 14:35:35 +00:00
return mToggled;
2012-05-29 04:45:44 +00:00
}
2015-06-02 14:35:35 +00:00
bool Water::isUnderwater(const osg::Vec3f &pos) const
2012-07-20 12:45:42 +00:00
{
2015-06-02 14:35:35 +00:00
return pos.z() < mTop && mToggled && mEnabled;
2012-07-20 12:45:42 +00:00
}
2015-06-02 14:35:35 +00:00
osg::Vec3f Water::getSceneNodeCoordinates(int gridX, int gridY)
2012-07-20 12:45:42 +00:00
{
2015-06-02 14:35:35 +00:00
return osg::Vec3f(static_cast<float>(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast<float>(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop);
2012-07-20 12:45:42 +00:00
}
2013-02-27 08:20:42 +00:00
void Water::addEmitter (const MWWorld::Ptr& ptr, float scale, float force)
{
mSimulation->addEmitter (ptr, scale, force);
}
void Water::removeEmitter (const MWWorld::Ptr& ptr)
{
mSimulation->removeEmitter (ptr);
}
void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr)
{
2013-02-27 08:20:42 +00:00
mSimulation->updateEmitterPtr(old, ptr);
}
2015-06-16 18:36:48 +00:00
void Water::removeCell(const MWWorld::CellStore *store)
{
mSimulation->removeCell(store);
}
void Water::clearRipples()
{
mSimulation->clear();
}
}