You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
5.4 KiB
C++
183 lines
5.4 KiB
C++
#include "cellwater.hpp"
|
|
|
|
#include <osg/Geode>
|
|
#include <osg/Geometry>
|
|
#include <osg/Group>
|
|
#include <osg/PositionAttitudeTransform>
|
|
|
|
#include <components/esm/loadland.hpp>
|
|
#include <components/fallback/fallback.hpp>
|
|
#include <components/misc/stringops.hpp>
|
|
#include <components/resource/imagemanager.hpp>
|
|
#include <components/resource/resourcesystem.hpp>
|
|
#include <components/sceneutil/waterutil.hpp>
|
|
|
|
#include "../../model/world/cell.hpp"
|
|
#include "../../model/world/cellcoordinates.hpp"
|
|
#include "../../model/world/data.hpp"
|
|
|
|
#include "mask.hpp"
|
|
|
|
namespace CSVRender
|
|
{
|
|
const int CellWater::CellSize = ESM::Land::REAL_SIZE;
|
|
|
|
CellWater::CellWater(CSMWorld::Data& data, osg::Group* cellNode, const std::string& id,
|
|
const CSMWorld::CellCoordinates& cellCoords)
|
|
: mData(data)
|
|
, mId(id)
|
|
, mParentNode(cellNode)
|
|
, mWaterTransform(nullptr)
|
|
, mWaterNode(nullptr)
|
|
, mWaterGeometry(nullptr)
|
|
, mDeleted(false)
|
|
, mExterior(false)
|
|
, mHasWater(false)
|
|
{
|
|
mWaterTransform = new osg::PositionAttitudeTransform();
|
|
mWaterTransform->setPosition(osg::Vec3f(cellCoords.getX() * CellSize + CellSize / 2.f,
|
|
cellCoords.getY() * CellSize + CellSize / 2.f, 0));
|
|
|
|
mWaterTransform->setNodeMask(Mask_Water);
|
|
mParentNode->addChild(mWaterTransform);
|
|
|
|
mWaterNode = new osg::Geode();
|
|
mWaterTransform->addChild(mWaterNode);
|
|
|
|
int cellIndex = mData.getCells().searchId(mId);
|
|
if (cellIndex > -1)
|
|
{
|
|
updateCellData(mData.getCells().getRecord(cellIndex));
|
|
}
|
|
|
|
// Keep water existence/height up to date
|
|
QAbstractItemModel* cells = mData.getTableModel(CSMWorld::UniversalId::Type_Cells);
|
|
connect(cells, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
|
this, SLOT(cellDataChanged(const QModelIndex&, const QModelIndex&)));
|
|
}
|
|
|
|
CellWater::~CellWater()
|
|
{
|
|
mParentNode->removeChild(mWaterTransform);
|
|
}
|
|
|
|
void CellWater::updateCellData(const CSMWorld::Record<CSMWorld::Cell>& cellRecord)
|
|
{
|
|
mDeleted = cellRecord.isDeleted();
|
|
if (!mDeleted)
|
|
{
|
|
const CSMWorld::Cell& cell = cellRecord.get();
|
|
|
|
if (mExterior != cell.isExterior() || mHasWater != cell.hasWater())
|
|
{
|
|
mExterior = cellRecord.get().isExterior();
|
|
mHasWater = cellRecord.get().hasWater();
|
|
|
|
recreate();
|
|
}
|
|
|
|
float waterHeight = -1;
|
|
if (!mExterior)
|
|
{
|
|
waterHeight = cellRecord.get().mWater;
|
|
}
|
|
|
|
osg::Vec3d pos = mWaterTransform->getPosition();
|
|
pos.z() = waterHeight;
|
|
mWaterTransform->setPosition(pos);
|
|
}
|
|
else
|
|
{
|
|
recreate();
|
|
}
|
|
}
|
|
|
|
void CellWater::reloadAssets()
|
|
{
|
|
recreate();
|
|
}
|
|
|
|
void CellWater::cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
|
{
|
|
const CSMWorld::Collection<CSMWorld::Cell>& cells = mData.getCells();
|
|
|
|
int rowStart = -1;
|
|
int rowEnd = -1;
|
|
|
|
if (topLeft.parent().isValid())
|
|
{
|
|
rowStart = topLeft.parent().row();
|
|
rowEnd = bottomRight.parent().row();
|
|
}
|
|
else
|
|
{
|
|
rowStart = topLeft.row();
|
|
rowEnd = bottomRight.row();
|
|
}
|
|
|
|
for (int row = rowStart; row <= rowEnd; ++row)
|
|
{
|
|
const CSMWorld::Record<CSMWorld::Cell>& cellRecord = cells.getRecord(row);
|
|
|
|
if (Misc::StringUtils::lowerCase(cellRecord.get().mId) == mId)
|
|
updateCellData(cellRecord);
|
|
}
|
|
}
|
|
|
|
void CellWater::recreate()
|
|
{
|
|
const int InteriorScalar = 20;
|
|
const int SegmentsPerCell = 1;
|
|
const int TextureRepeatsPerCell = 6;
|
|
|
|
const float Alpha = 0.5f;
|
|
|
|
const int RenderBin = osg::StateSet::TRANSPARENT_BIN - 1;
|
|
|
|
if (mWaterGeometry)
|
|
{
|
|
mWaterNode->removeDrawable(mWaterGeometry);
|
|
mWaterGeometry = nullptr;
|
|
}
|
|
|
|
if (mDeleted || !mHasWater)
|
|
return;
|
|
|
|
float size;
|
|
int segments;
|
|
float textureRepeats;
|
|
|
|
if (mExterior)
|
|
{
|
|
size = CellSize;
|
|
segments = SegmentsPerCell;
|
|
textureRepeats = TextureRepeatsPerCell;
|
|
}
|
|
else
|
|
{
|
|
size = CellSize * InteriorScalar;
|
|
segments = SegmentsPerCell * InteriorScalar;
|
|
textureRepeats = TextureRepeatsPerCell * InteriorScalar;
|
|
}
|
|
|
|
mWaterGeometry = SceneUtil::createWaterGeometry(size, segments, textureRepeats);
|
|
mWaterGeometry->setStateSet(SceneUtil::createSimpleWaterStateSet(Alpha, RenderBin));
|
|
|
|
// Add water texture
|
|
std::string textureName = Fallback::Map::getString("Water_SurfaceTexture");
|
|
textureName = "textures/water/" + textureName + "00.dds";
|
|
|
|
Resource::ImageManager* imageManager = mData.getResourceSystem()->getImageManager();
|
|
|
|
osg::ref_ptr<osg::Texture2D> waterTexture = new osg::Texture2D();
|
|
waterTexture->setImage(imageManager->getImage(textureName));
|
|
waterTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
|
|
waterTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
|
|
|
|
mWaterGeometry->getStateSet()->setTextureAttributeAndModes(0, waterTexture, osg::StateAttribute::ON);
|
|
|
|
|
|
mWaterNode->addDrawable(mWaterGeometry);
|
|
}
|
|
}
|