From 5674e0da24de98cc4d781d6e74bfd17f6603dd72 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Thu, 4 Aug 2016 22:58:55 -0400 Subject: [PATCH 1/6] Render water in editor. --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/view/render/cell.cpp | 2 + apps/opencs/view/render/cell.hpp | 2 + apps/opencs/view/render/cellmarker.cpp | 1 + apps/opencs/view/render/cellwater.cpp | 191 +++++++++++++++++++++++++ apps/opencs/view/render/cellwater.hpp | 69 +++++++++ 6 files changed, 266 insertions(+) create mode 100644 apps/opencs/view/render/cellwater.cpp create mode 100644 apps/opencs/view/render/cellwater.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6e19c03b2..8a830f2cb 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -87,6 +87,7 @@ opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget previewwidget editmode instancemode instanceselectionmode instancemovemode orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller + cellwater ) opencs_units_noqt (view/render diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index dc22fd511..395fbf95f 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -16,6 +16,7 @@ #include "../../model/world/refcollection.hpp" #include "../../model/world/cellcoordinates.hpp" +#include "cellwater.hpp" #include "mask.hpp" #include "pathgrid.hpp" #include "terrainstorage.hpp" @@ -111,6 +112,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st } mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates)); + mCellWater.reset(new CellWater(mData, mCellNode, mId, mCoordinates)); } } diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index a5b581d24..8f68e9f53 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -35,6 +35,7 @@ namespace CSMWorld namespace CSVRender { + class CellWater; class Pathgrid; class TagBase; @@ -49,6 +50,7 @@ namespace CSVRender std::auto_ptr mCellArrows[4]; std::auto_ptr mCellMarker; std::auto_ptr mCellBorder; + std::auto_ptr mCellWater; std::auto_ptr mPathgrid; bool mDeleted; int mSubMode; diff --git a/apps/opencs/view/render/cellmarker.cpp b/apps/opencs/view/render/cellmarker.cpp index e0d270f85..09690190d 100644 --- a/apps/opencs/view/render/cellmarker.cpp +++ b/apps/opencs/view/render/cellmarker.cpp @@ -75,6 +75,7 @@ CSVRender::CellMarker::CellMarker( mMarkerNode->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN); mMarkerNode->setAutoScaleToScreen(true); mMarkerNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); + mMarkerNode->getOrCreateStateSet()->setRenderBinDetails(2000, "RenderBin"); mMarkerNode->setUserData(new CellMarkerTag(this)); mMarkerNode->setNodeMask(Mask_CellMarker); diff --git a/apps/opencs/view/render/cellwater.cpp b/apps/opencs/view/render/cellwater.cpp new file mode 100644 index 000000000..956864d7b --- /dev/null +++ b/apps/opencs/view/render/cellwater.cpp @@ -0,0 +1,191 @@ +#include "cellwater.hpp" + +#include +#include +#include +#include +#include + +#include +#include + +#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(0) + , mWaterNode(0) + , mWaterGeometry(0) + , mExterior(false) + , mHasWater(false) + , mWaterHeight(0) + { + mWaterTransform = new osg::PositionAttitudeTransform(); + mWaterTransform->setPosition(osg::Vec3f(cellCoords.getX() * CellSize, cellCoords.getY() * CellSize, 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).get()); + } + + // Keep water existance/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::Cell& cell) + { + int cellIndex = mData.getCells().searchId(mId); + if (cellIndex > -1) + { + const CSMWorld::Record& cellRecord = mData.getCells().getRecord(cellIndex); + + mDeleted = cellRecord.isDeleted(); + if (!mDeleted) + { + mExterior = cellRecord.get().isExterior(); + + mHasWater = cellRecord.get().hasWater(); + mWaterHeight = cellRecord.get().mWater; + } + } + else + { + mDeleted = true; + } + + update(); + } + + void CellWater::cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) + { + const CSMWorld::Collection& 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::Cell& cell = cells.getRecord(row).get(); + + if (Misc::StringUtils::lowerCase(cell.mId) == mId) + updateCellData(cell); + } + } + + void CellWater::update() + { + const int InteriorSize = CellSize * 10; + + const size_t NumPoints = 4; + const size_t NumIndices = 6; + + const osg::Vec3f ExteriorPoints[] = + { + osg::Vec3f(0, 0, mWaterHeight), + osg::Vec3f(0, CellSize, mWaterHeight), + osg::Vec3f(CellSize, CellSize, mWaterHeight), + osg::Vec3f(CellSize, 0, mWaterHeight) + }; + + const osg::Vec3f InteriorPoints[] = + { + osg::Vec3f(-InteriorSize, -InteriorSize, mWaterHeight), + osg::Vec3f(-InteriorSize, InteriorSize, mWaterHeight), + osg::Vec3f( InteriorSize, InteriorSize, mWaterHeight), + osg::Vec3f( InteriorSize, -InteriorSize, mWaterHeight) + }; + + const unsigned short TriangleStrip[] = + { + 0, 1, 2, 3, 0, 1 + }; + + const osg::Vec4f Color = osg::Vec4f(0.6f, 0.7f, 1.f, 0.5f); + + if (mWaterGeometry) + { + mWaterNode->removeDrawable(mWaterGeometry); + mWaterGeometry = 0; + } + + if (mDeleted || !mHasWater) + return; + + mWaterGeometry = new osg::Geometry(); + + osg::ref_ptr vertices = new osg::Vec3Array(); + osg::ref_ptr colors = new osg::Vec4Array(); + osg::ref_ptr indices = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, + NumIndices); + + for (size_t i = 0; i < NumPoints; ++i) + { + if (mExterior) + vertices->push_back(ExteriorPoints[i]); + else + vertices->push_back(InteriorPoints[i]); + } + + colors->push_back(Color); + + for (size_t i = 0; i < NumIndices; ++i) + { + indices->setElement(i, TriangleStrip[i]); + } + + mWaterGeometry->setVertexArray(vertices); + mWaterGeometry->setColorArray(colors, osg::Array::BIND_OVERALL); + mWaterGeometry->addPrimitiveSet(indices); + + // Transparency + mWaterGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + mWaterGeometry->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON ); + mWaterGeometry->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + mWaterGeometry->getOrCreateStateSet()->setRenderBinDetails(1000, "RenderBin"); + + // Reduce some z-fighting + osg::ref_ptr polygonOffset = new osg::PolygonOffset(); + polygonOffset->setFactor(0.2f); + polygonOffset->setUnits(0.2f); + + mWaterGeometry->getOrCreateStateSet()->setAttributeAndModes(polygonOffset, + osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); + + mWaterNode->addDrawable(mWaterGeometry); + } +} diff --git a/apps/opencs/view/render/cellwater.hpp b/apps/opencs/view/render/cellwater.hpp new file mode 100644 index 000000000..6d533e291 --- /dev/null +++ b/apps/opencs/view/render/cellwater.hpp @@ -0,0 +1,69 @@ +#ifndef CSV_RENDER_CELLWATER_H +#define CSV_RENDER_CELLWATER_H + +#include + +#include + +#include + +namespace osg +{ + class Geode; + class Geometry; + class Group; + class PositionAttitudeTransform; +} + +namespace CSMWorld +{ + class Cell; + class CellCoordinates; + class Data; +} + +namespace CSVRender +{ + /// For exterior cells, this adds a patch of water to fit the size of the cell. For interior cells with water, this + /// adds a large patch of water much larger than the typical size of a cell. + class CellWater : public QObject + { + Q_OBJECT + + public: + + CellWater(CSMWorld::Data& data, osg::Group* cellNode, const std::string& id, + const CSMWorld::CellCoordinates& cellCoords); + + ~CellWater(); + + void updateCellData(const CSMWorld::Cell& cell); + + private slots: + + void cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); + + private: + + void update(); + + static const int CellSize; + + CSMWorld::Data& mData; + std::string mId; + + osg::Group* mParentNode; + + osg::ref_ptr mWaterTransform; + osg::ref_ptr mWaterNode; + osg::ref_ptr mWaterGeometry; + + bool mDeleted; + bool mExterior; + + bool mHasWater; + float mWaterHeight; + }; +} + +#endif From 3904a24e6cb6e4d9f61271d6648916b0f58562a5 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 5 Aug 2016 00:30:28 -0400 Subject: [PATCH 2/6] Add missing include. --- apps/opencs/view/render/cellwater.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/cellwater.hpp b/apps/opencs/view/render/cellwater.hpp index 6d533e291..a7154e9cb 100644 --- a/apps/opencs/view/render/cellwater.hpp +++ b/apps/opencs/view/render/cellwater.hpp @@ -6,6 +6,7 @@ #include #include +#include namespace osg { From 5753f52b473bc5ee246f8e9fc67845983f9711cc Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 5 Aug 2016 13:25:05 -0400 Subject: [PATCH 3/6] Move water mesh + simple state generation to components library. --- apps/openmw/mwrender/water.cpp | 75 ++-------------------------- components/CMakeLists.txt | 2 +- components/sceneutil/waterutil.cpp | 79 ++++++++++++++++++++++++++++++ components/sceneutil/waterutil.hpp | 19 +++++++ 4 files changed, 104 insertions(+), 71 deletions(-) create mode 100644 components/sceneutil/waterutil.cpp create mode 100644 components/sceneutil/waterutil.hpp diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index ab828a3ad..532e5cedc 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -24,6 +24,8 @@ #include #include +#include + #include #include @@ -40,58 +42,6 @@ #include "renderbin.hpp" #include "util.hpp" -namespace -{ - - osg::ref_ptr createWaterGeometry(float size, int segments, float textureRepeats) - { - osg::ref_ptr verts (new osg::Vec3Array); - osg::ref_ptr 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; xpush_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)); - } - } - - osg::ref_ptr waterGeom (new osg::Geometry); - waterGeom->setVertexArray(verts); - waterGeom->setTexCoordArray(0, texcoords); - - osg::ref_ptr normal (new osg::Vec3Array); - normal->push_back(osg::Vec3f(0,0,1)); - waterGeom->setNormalArray(normal, osg::Array::BIND_OVERALL); - - waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size())); - return waterGeom; - } - -} - namespace MWRender { @@ -465,7 +415,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem { mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback)); - mWaterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); + mWaterGeom = SceneUtil::createWaterGeometry(CELL_SIZE*150, 40, 900); mWaterGeom->setDrawCallback(new DepthClampCallback); mWaterGeom->setNodeMask(Mask_Water); @@ -527,26 +477,11 @@ void Water::updateWaterMaterial() void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) { - osg::ref_ptr stateset (new osg::StateSet); - - osg::ref_ptr material (new osg::Material); - material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, alpha)); - material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - material->setColorMode(osg::Material::OFF); - stateset->setAttributeAndModes(material, osg::StateAttribute::ON); - - stateset->setMode(GL_BLEND, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - - osg::ref_ptr depth (new osg::Depth); - depth->setWriteMask(false); - stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - - stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); + osg::ref_ptr stateset = SceneUtil::createSimpleWaterStateSet(alpha, MWRender::RenderBin_Water); node->setStateSet(stateset); + // Add animated textures std::vector > textures; int frameCount = mFallback->getFallbackInt("Water_SurfaceFrameCount"); std::string texture = mFallback->getFallbackString("Water_SurfaceTexture"); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f50f30fa6..663616873 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -50,7 +50,7 @@ add_component_dir (shader add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry lightcontroller - lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil + lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil ) add_component_dir (nif diff --git a/components/sceneutil/waterutil.cpp b/components/sceneutil/waterutil.cpp new file mode 100644 index 000000000..562b0ee73 --- /dev/null +++ b/components/sceneutil/waterutil.cpp @@ -0,0 +1,79 @@ +#include "waterutil.hpp" + +#include +#include +#include +#include + +namespace SceneUtil +{ + osg::ref_ptr createWaterGeometry(float size, int segments, float textureRepeats) + { + osg::ref_ptr verts (new osg::Vec3Array); + osg::ref_ptr 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; xpush_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)); + } + } + + osg::ref_ptr waterGeom (new osg::Geometry); + waterGeom->setVertexArray(verts); + waterGeom->setTexCoordArray(0, texcoords); + + osg::ref_ptr normal (new osg::Vec3Array); + normal->push_back(osg::Vec3f(0,0,1)); + waterGeom->setNormalArray(normal, osg::Array::BIND_OVERALL); + + waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size())); + return waterGeom; + } + + osg::ref_ptr createSimpleWaterStateSet(float alpha, int renderBin) + { + osg::ref_ptr stateset (new osg::StateSet); + + osg::ref_ptr material (new osg::Material); + material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, alpha)); + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + material->setColorMode(osg::Material::OFF); + stateset->setAttributeAndModes(material, osg::StateAttribute::ON); + + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + + stateset->setRenderBinDetails(renderBin, "RenderBin"); + + return stateset; + } +} diff --git a/components/sceneutil/waterutil.hpp b/components/sceneutil/waterutil.hpp new file mode 100644 index 000000000..7b8c38010 --- /dev/null +++ b/components/sceneutil/waterutil.hpp @@ -0,0 +1,19 @@ +#ifndef OPENMW_COMPONENTS_WATERUTIL_H +#define OPENMW_COMPONENTS_WATERUTIL_H + +#include + +namespace osg +{ + class Geometry; + class StateSet; +} + +namespace SceneUtil +{ + osg::ref_ptr createWaterGeometry(float size, int segments, float textureRepeats); + + osg::ref_ptr createSimpleWaterStateSet(float alpha, int renderBin); +} + +#endif From 9454f4f2e734cf8ee589a9fe483cfa3fae1c3519 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 5 Aug 2016 13:49:44 -0400 Subject: [PATCH 4/6] Use shared water geometry + state generation, Fix water position and render bin, Fix passed cell parameter being ignored --- apps/opencs/view/render/cellmarker.cpp | 2 +- apps/opencs/view/render/cellwater.cpp | 123 +++++++++---------------- apps/opencs/view/render/cellwater.hpp | 8 +- 3 files changed, 51 insertions(+), 82 deletions(-) diff --git a/apps/opencs/view/render/cellmarker.cpp b/apps/opencs/view/render/cellmarker.cpp index 09690190d..abc337ce2 100644 --- a/apps/opencs/view/render/cellmarker.cpp +++ b/apps/opencs/view/render/cellmarker.cpp @@ -75,7 +75,7 @@ CSVRender::CellMarker::CellMarker( mMarkerNode->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN); mMarkerNode->setAutoScaleToScreen(true); mMarkerNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); - mMarkerNode->getOrCreateStateSet()->setRenderBinDetails(2000, "RenderBin"); + mMarkerNode->getOrCreateStateSet()->setRenderBinDetails(osg::StateSet::TRANSPARENT_BIN + 1, "RenderBin"); mMarkerNode->setUserData(new CellMarkerTag(this)); mMarkerNode->setNodeMask(Mask_CellMarker); diff --git a/apps/opencs/view/render/cellwater.cpp b/apps/opencs/view/render/cellwater.cpp index 956864d7b..5e93d589b 100644 --- a/apps/opencs/view/render/cellwater.cpp +++ b/apps/opencs/view/render/cellwater.cpp @@ -3,11 +3,11 @@ #include #include #include -#include #include #include #include +#include #include "../../model/world/cell.hpp" #include "../../model/world/cellcoordinates.hpp" @@ -27,12 +27,14 @@ namespace CSVRender , mWaterTransform(0) , mWaterNode(0) , mWaterGeometry(0) + , mDeleted(false) , mExterior(false) , mHasWater(false) - , mWaterHeight(0) { mWaterTransform = new osg::PositionAttitudeTransform(); - mWaterTransform->setPosition(osg::Vec3f(cellCoords.getX() * CellSize, cellCoords.getY() * CellSize, 0)); + mWaterTransform->setPosition(osg::Vec3f(cellCoords.getX() * CellSize + CellSize / 2.f, + cellCoords.getY() * CellSize + CellSize / 2.f, 0)); + mWaterTransform->setNodeMask(Mask_Water); mParentNode->addChild(mWaterTransform); @@ -42,7 +44,7 @@ namespace CSVRender int cellIndex = mData.getCells().searchId(mId); if (cellIndex > -1) { - updateCellData(mData.getCells().getRecord(cellIndex).get()); + updateCellData(mData.getCells().getRecord(cellIndex)); } // Keep water existance/height up to date @@ -56,28 +58,35 @@ namespace CSVRender mParentNode->removeChild(mWaterTransform); } - void CellWater::updateCellData(const CSMWorld::Cell& cell) + void CellWater::updateCellData(const CSMWorld::Record& cellRecord) { - int cellIndex = mData.getCells().searchId(mId); - if (cellIndex > -1) + mDeleted = cellRecord.isDeleted(); + if (!mDeleted) { - const CSMWorld::Record& cellRecord = mData.getCells().getRecord(cellIndex); + const CSMWorld::Cell& cell = cellRecord.get(); - mDeleted = cellRecord.isDeleted(); - if (!mDeleted) + if (mExterior != cell.isExterior() || mHasWater != cell.hasWater()) { mExterior = cellRecord.get().isExterior(); - mHasWater = cellRecord.get().hasWater(); - mWaterHeight = cellRecord.get().mWater; + + recreate(); + } + + float waterHeight = -1; + if (!mExterior) + { + waterHeight = cellRecord.get().mWater; } + + osg::Vec3d pos = mWaterTransform->getPosition(); + pos.z() = waterHeight; + mWaterTransform->setPosition(pos); } else { - mDeleted = true; + recreate(); } - - update(); } void CellWater::cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) @@ -100,42 +109,22 @@ namespace CSVRender for (int row = rowStart; row <= rowEnd; ++row) { - const CSMWorld::Cell& cell = cells.getRecord(row).get(); + const CSMWorld::Record& cellRecord = cells.getRecord(row); - if (Misc::StringUtils::lowerCase(cell.mId) == mId) - updateCellData(cell); + if (Misc::StringUtils::lowerCase(cellRecord.get().mId) == mId) + updateCellData(cellRecord); } } - void CellWater::update() + void CellWater::recreate() { - const int InteriorSize = CellSize * 10; + const int InteriorScalar = 20; + const int SegmentsPerCell = 1; + const int TextureRepeatsPerCell = 6; - const size_t NumPoints = 4; - const size_t NumIndices = 6; + const float Alpha = 0.5f; - const osg::Vec3f ExteriorPoints[] = - { - osg::Vec3f(0, 0, mWaterHeight), - osg::Vec3f(0, CellSize, mWaterHeight), - osg::Vec3f(CellSize, CellSize, mWaterHeight), - osg::Vec3f(CellSize, 0, mWaterHeight) - }; - - const osg::Vec3f InteriorPoints[] = - { - osg::Vec3f(-InteriorSize, -InteriorSize, mWaterHeight), - osg::Vec3f(-InteriorSize, InteriorSize, mWaterHeight), - osg::Vec3f( InteriorSize, InteriorSize, mWaterHeight), - osg::Vec3f( InteriorSize, -InteriorSize, mWaterHeight) - }; - - const unsigned short TriangleStrip[] = - { - 0, 1, 2, 3, 0, 1 - }; - - const osg::Vec4f Color = osg::Vec4f(0.6f, 0.7f, 1.f, 0.5f); + const int RenderBin = osg::StateSet::TRANSPARENT_BIN - 1; if (mWaterGeometry) { @@ -146,45 +135,25 @@ namespace CSVRender if (mDeleted || !mHasWater) return; - mWaterGeometry = new osg::Geometry(); - - osg::ref_ptr vertices = new osg::Vec3Array(); - osg::ref_ptr colors = new osg::Vec4Array(); - osg::ref_ptr indices = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, - NumIndices); + float size; + int segments; + float textureRepeats; - for (size_t i = 0; i < NumPoints; ++i) + if (mExterior) { - if (mExterior) - vertices->push_back(ExteriorPoints[i]); - else - vertices->push_back(InteriorPoints[i]); + size = CellSize; + segments = SegmentsPerCell; + textureRepeats = TextureRepeatsPerCell; } - - colors->push_back(Color); - - for (size_t i = 0; i < NumIndices; ++i) + else { - indices->setElement(i, TriangleStrip[i]); + size = CellSize * InteriorScalar; + segments = SegmentsPerCell * InteriorScalar; + textureRepeats = TextureRepeatsPerCell * InteriorScalar; } - mWaterGeometry->setVertexArray(vertices); - mWaterGeometry->setColorArray(colors, osg::Array::BIND_OVERALL); - mWaterGeometry->addPrimitiveSet(indices); - - // Transparency - mWaterGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - mWaterGeometry->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON ); - mWaterGeometry->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - mWaterGeometry->getOrCreateStateSet()->setRenderBinDetails(1000, "RenderBin"); - - // Reduce some z-fighting - osg::ref_ptr polygonOffset = new osg::PolygonOffset(); - polygonOffset->setFactor(0.2f); - polygonOffset->setUnits(0.2f); - - mWaterGeometry->getOrCreateStateSet()->setAttributeAndModes(polygonOffset, - osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); + mWaterGeometry = SceneUtil::createWaterGeometry(size, segments, textureRepeats); + mWaterGeometry->setStateSet(SceneUtil::createSimpleWaterStateSet(Alpha, RenderBin)); mWaterNode->addDrawable(mWaterGeometry); } diff --git a/apps/opencs/view/render/cellwater.hpp b/apps/opencs/view/render/cellwater.hpp index a7154e9cb..09830d95a 100644 --- a/apps/opencs/view/render/cellwater.hpp +++ b/apps/opencs/view/render/cellwater.hpp @@ -8,6 +8,8 @@ #include #include +#include "../../model/world/record.hpp" + namespace osg { class Geode; @@ -38,7 +40,7 @@ namespace CSVRender ~CellWater(); - void updateCellData(const CSMWorld::Cell& cell); + void updateCellData(const CSMWorld::Record& cellRecord); private slots: @@ -46,7 +48,7 @@ namespace CSVRender private: - void update(); + void recreate(); static const int CellSize; @@ -61,9 +63,7 @@ namespace CSVRender bool mDeleted; bool mExterior; - bool mHasWater; - float mWaterHeight; }; } From 1f32f1eef513a541b2bff954a33b052511bfb647 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 5 Aug 2016 14:55:40 -0400 Subject: [PATCH 5/6] Add water texture. --- apps/opencs/view/render/cellwater.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/apps/opencs/view/render/cellwater.cpp b/apps/opencs/view/render/cellwater.cpp index 5e93d589b..b8975da49 100644 --- a/apps/opencs/view/render/cellwater.cpp +++ b/apps/opencs/view/render/cellwater.cpp @@ -6,7 +6,10 @@ #include #include +#include #include +#include +#include #include #include "../../model/world/cell.hpp" @@ -155,6 +158,20 @@ namespace CSVRender mWaterGeometry = SceneUtil::createWaterGeometry(size, segments, textureRepeats); mWaterGeometry->setStateSet(SceneUtil::createSimpleWaterStateSet(Alpha, RenderBin)); + // Add water texture + std::string textureName = mData.getFallbackMap()->getFallbackString("Water_SurfaceTexture"); + textureName = "textures/water/" + textureName + "00.dds"; + + Resource::ImageManager* imageManager = mData.getResourceSystem()->getImageManager(); + + osg::ref_ptr 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); } } From 16d0580ce891f7acbc830b7657754d4fff6c2066 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Fri, 5 Aug 2016 15:39:08 -0400 Subject: [PATCH 6/6] Fix struct/class mismatch. --- apps/opencs/view/render/cellwater.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/cellwater.hpp b/apps/opencs/view/render/cellwater.hpp index 09830d95a..d2ed9b458 100644 --- a/apps/opencs/view/render/cellwater.hpp +++ b/apps/opencs/view/render/cellwater.hpp @@ -20,7 +20,7 @@ namespace osg namespace CSMWorld { - class Cell; + struct Cell; class CellCoordinates; class Data; }