Added DefinitionWatcher system

Also switched to the new definition system for /terrain/water_height
This commit is contained in:
Michaël Lemaire 2015-08-17 22:55:30 +02:00
parent 67bd80fba5
commit 8fa0d8af29
23 changed files with 201 additions and 36 deletions

View file

@ -2,6 +2,7 @@
#include "Logs.h"
#include "PackStream.h"
#include "DefinitionWatcher.h"
#include "DefinitionDiff.h"
#include "DiffManager.h"
@ -157,10 +158,25 @@ bool DefinitionNode::applyDiff(const DefinitionDiff *diff, bool)
}
}
void DefinitionNode::addWatcher(DefinitionWatcher *watcher)
void DefinitionNode::generateInitDiffs(std::vector<const DefinitionDiff *> *) const
{
}
void DefinitionNode::addWatcher(DefinitionWatcher *watcher, bool init_diff)
{
if (root && root->diffs)
{
if (init_diff)
{
std::vector<const DefinitionDiff *> diffs;
generateInitDiffs(&diffs);
for (auto diff: diffs)
{
watcher->nodeChanged(this, diff);
delete diff;
}
}
root->diffs->addWatcher(this, watcher);
}
}

View file

@ -61,12 +61,21 @@ public:
*/
virtual bool applyDiff(const DefinitionDiff *diff, bool backward=false);
/**
* Fill a diff array to be applied to initialize a proper state for a watcher.
*
* This method should be overridden by subclasses.
*/
virtual void generateInitDiffs(std::vector<const DefinitionDiff *> *diffs) const;
/**
* Add a watcher over this node.
*
* The watcher will receive DefinitionDiff objects when this node changes.
*
* If *init_diff* is set to true, a first diff (or several) will be be pushed immediately to initialize the state.
*/
void addWatcher(DefinitionWatcher *watcher);
void addWatcher(DefinitionWatcher *watcher, bool init_diff=false);
protected:
void addChild(DefinitionNode* child);

View file

@ -15,6 +15,11 @@ class DEFINITIONSHARED_EXPORT DefinitionWatcher
{
public:
DefinitionWatcher();
/**
* Abstract method called when a node changed.
*/
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) = 0;
};
}

View file

@ -2,6 +2,7 @@
#include "DefinitionNode.h"
#include "DefinitionDiff.h"
#include "DefinitionWatcher.h"
DiffManager::DiffManager(DefinitionNode *tree):
tree(tree)
@ -9,6 +10,15 @@ DiffManager::DiffManager(DefinitionNode *tree):
undone = 0;
}
DiffManager::~DiffManager()
{
for (auto diff: diffs)
{
delete diff;
}
diffs.clear();
}
void DiffManager::addWatcher(const DefinitionNode *node, DefinitionWatcher *watcher)
{
watchers[node].push_back(watcher);
@ -19,6 +29,7 @@ void DiffManager::addDiff(DefinitionNode *node, const DefinitionDiff *diff)
while (undone > 0)
{
// truncate diffs ahead
delete diffs.back();
diffs.pop_back();
undone--;
}
@ -28,9 +39,9 @@ void DiffManager::addDiff(DefinitionNode *node, const DefinitionDiff *diff)
// TODO Delayed commit (with merge of consecutive diffs)
node->applyDiff(diff);
for (auto &watcher: watchers[node])
for (auto watcher: watchers[node])
{
// TODO
watcher->nodeChanged(node, diff);
}
}

View file

@ -18,6 +18,7 @@ class DEFINITIONSHARED_EXPORT DiffManager
{
public:
DiffManager(DefinitionNode *tree);
~DiffManager();
/**
* Add a watcher for a specific node.

View file

@ -52,6 +52,11 @@ const FloatDiff *FloatNode::produceDiff(double new_value) const
return new FloatDiff(this, value, new_value);
}
void FloatNode::generateInitDiffs(std::vector<const DefinitionDiff *> *diffs) const
{
diffs->push_back(produceDiff(value));
}
bool FloatNode::applyDiff(const DefinitionDiff *diff, bool backward)
{
if (!DefinitionNode::applyDiff(diff, backward))

View file

@ -30,6 +30,7 @@ public:
*/
void setValue(double new_value);
const FloatDiff *produceDiff(double new_value) const;
void generateInitDiffs(std::vector<const DefinitionDiff *> *diffs) const;
virtual bool applyDiff(const DefinitionDiff *diff, bool backward=false) override;
private:
double value;

View file

@ -15,8 +15,7 @@ TerrainDefinition::TerrainDefinition(DefinitionNode* parent):
height_map = new TerrainHeightMap(this);
addChild(height_map);
water_height = -0.3;
_water_height = new FloatNode(this, "water_height", -0.3);
water_height = new FloatNode(this, "water_height", -0.3);
_height_noise = new NoiseGenerator;
}
@ -67,7 +66,6 @@ void TerrainDefinition::save(PackStream* stream) const
stream->write(&height);
stream->write(&scaling);
stream->write(&shadow_smoothing);
stream->write(&water_height);
_height_noise->save(stream);
}
@ -78,7 +76,6 @@ void TerrainDefinition::load(PackStream* stream)
stream->read(&height);
stream->read(&scaling);
stream->read(&shadow_smoothing);
stream->read(&water_height);
_height_noise->load(stream);
validate();
@ -96,7 +93,7 @@ double TerrainDefinition::getGridHeight(int x, int z, bool with_painting)
return h;
}
double TerrainDefinition::getInterpolatedHeight(double x, double z, bool scaled, bool with_painting)
double TerrainDefinition::getInterpolatedHeight(double x, double z, bool scaled, bool with_painting, bool water_offset)
{
double h;
x /= scaling;
@ -109,7 +106,7 @@ double TerrainDefinition::getInterpolatedHeight(double x, double z, bool scaled,
if (scaled)
{
return (h - water_height) * height * scaling;
return (water_offset ? (h - water_height->getValue()) : h) * height * scaling;
}
else
{
@ -117,6 +114,11 @@ double TerrainDefinition::getInterpolatedHeight(double x, double z, bool scaled,
}
}
double TerrainDefinition::getWaterOffset() const
{
return -water_height->getValue() * height * scaling;
}
HeightInfo TerrainDefinition::getHeightInfo()
{
HeightInfo result;
@ -124,7 +126,7 @@ HeightInfo TerrainDefinition::getHeightInfo()
result.min_height = _min_height;
result.max_height = _max_height;
/* TODO This is duplicated in ter_render.c (_realGetWaterHeight) */
result.base_height = water_height * height * scaling;
result.base_height = water_height->getValue() * height * scaling;
return result;
}

View file

@ -27,8 +27,11 @@ public:
virtual void copy(DefinitionNode* destination) const override;
virtual void validate() override;
inline FloatNode *propWaterHeight() const {return water_height;}
double getGridHeight(int x, int z, bool with_painting);
double getInterpolatedHeight(double x, double z, bool scaled, bool with_painting);
double getInterpolatedHeight(double x, double z, bool scaled, bool with_painting, bool water_offset=true);
double getWaterOffset() const;
unsigned long getMemoryStats();
HeightInfo getHeightInfo();
@ -46,15 +49,13 @@ public:
TerrainHeightMap* height_map;
double water_height;
double _detail;
NoiseGenerator* _height_noise;
double _min_height;
double _max_height;
private:
FloatNode *_water_height;
FloatNode *water_height;
};
}

View file

@ -10,6 +10,7 @@
#include "RenderPreviewProvider.h"
#include "RenderProcess.h"
#include "RenderConfig.h"
#include "DiffManager.h"
#include <QQmlEngine>
#include <QGuiApplication>
@ -103,4 +104,25 @@ void MainModelerWindow::keyReleaseEvent(QKeyEvent *event)
QGuiApplication::instance()->exit();
}
}
else if (event->key() == Qt::Key_Z)
{
if (event->modifiers() & Qt::ControlModifier)
{
if (event->modifiers() & Qt::ShiftModifier)
{
scenery->getDiffManager()->redo();
}
else
{
scenery->getDiffManager()->undo();
}
}
}
else if (event->key() == Qt::Key_Y)
{
if (event->modifiers() & Qt::ControlModifier)
{
scenery->getDiffManager()->undo();
}
}
}

View file

@ -1,6 +1,10 @@
#include "WaterModeler.h"
#include "MainModelerWindow.h"
#include "Scenery.h"
#include "TerrainDefinition.h"
#include "FloatNode.h"
#include "Logs.h"
WaterModeler::WaterModeler(MainModelerWindow *main):
main(main)
@ -8,12 +12,17 @@ WaterModeler::WaterModeler(MainModelerWindow *main):
QObject *item = main->findQmlObject("water_level");
if (item)
{
item->setProperty("value", propWaterHeight()->getValue() * 0.5 + 0.5);
connect(item, SIGNAL(changed(double)), this, SLOT(waterLevelChanged(double)));
}
}
void WaterModeler::waterLevelChanged(double)
void WaterModeler::waterLevelChanged(double value)
{
// TODO
//qDebug() << "water level : " << value;
propWaterHeight()->setValue(value * 2.0 - 1.0);
}
FloatNode *WaterModeler::propWaterHeight() const
{
return main->getScenery()->getTerrain()->propWaterHeight();
}

View file

@ -18,6 +18,7 @@ public slots:
void waterLevelChanged(double value);
private:
FloatNode *propWaterHeight() const;
MainModelerWindow *main;
};

View file

@ -9,7 +9,7 @@
#include "TerrainRenderer.h"
#include "VertexArray.h"
ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height):
ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks):
_renderer(renderer)
{
priority = 0.0;
@ -32,7 +32,6 @@ ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, d
distance_to_camera = 0.0;
_water_height = water_height;
overwater = false;
tessellation_count = 33;
@ -90,8 +89,8 @@ bool ExplorerChunkTerrain::maintain()
double x = _startx + _tessellation_step * (float)i;
double z = _startz + _tessellation_step * (float)j;
double height = _renderer->getTerrainRenderer()->getHeight(x, z, true);
if (height >= _water_height)
double height = _renderer->getTerrainRenderer()->getHeight(x, z, true, false);
if (height >= 0.0)
{
overwater = true;
}
@ -270,7 +269,7 @@ void ExplorerChunkTerrain::render(QOpenGLShaderProgram* program, OpenGLFunctions
int tessellation_size = _tessellation_current_size;
_lock_data.unlock();
if (tessellation_size <= 1 or not overwater)
if (tessellation_size <= 1)
{
return;
}

View file

@ -20,7 +20,7 @@ public:
} TerrainVertex;
public:
ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height);
ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks);
~ExplorerChunkTerrain();
bool maintain();
@ -42,8 +42,6 @@ private:
double _size;
double _overall_step;
double _water_height;
int tessellation_count;
VertexArray<TerrainVertex> *tessellated;
int _tessellation_max_size;

View file

@ -9,6 +9,8 @@
#include "WaterRenderer.h"
#include "CameraDefinition.h"
#include "Scenery.h"
#include "FloatNode.h"
#include "FloatDiff.h"
class ChunkMaintenanceThreads:public ParallelPool
{
@ -62,12 +64,11 @@ void OpenGLTerrain::initialize()
double size = 800.0;
double chunksize = size / (double) chunks;
double start = -size / 2.0;
double water_height = renderer->getWaterRenderer()->getHeightInfo().base_height;
for (int i = 0; i < chunks; i++)
{
for (int j = 0; j < chunks; j++)
{
ExplorerChunkTerrain* chunk = new ExplorerChunkTerrain(renderer, start + chunksize * (double) i, start + chunksize * (double) j, chunksize, chunks, water_height);
ExplorerChunkTerrain* chunk = new ExplorerChunkTerrain(renderer, start + chunksize * (double) i, start + chunksize * (double) j, chunksize, chunks);
_chunks.append(chunk);
_updateQueue.append(chunk);
}
@ -75,6 +76,9 @@ void OpenGLTerrain::initialize()
// Start chunks maintenance
work->start();
// Watch for definition changes
renderer->getScenery()->getTerrain()->propWaterHeight()->addWatcher(this);
}
void OpenGLTerrain::update()
@ -142,3 +146,12 @@ void OpenGLTerrain::performChunksMaintenance()
qSort(_updateQueue.begin(), _updateQueue.end(), _cmpChunks);
_lock_chunks.unlock();
}
void OpenGLTerrain::nodeChanged(const DefinitionNode *node, const DefinitionDiff *)
{
if (node->getPath() == "/terrain/water_height")
{
resetTextures();
}
}

View file

@ -4,6 +4,7 @@
#include "opengl_global.h"
#include "OpenGLPart.h"
#include "DefinitionWatcher.h"
#include <QVector>
#include <QList>
@ -12,7 +13,7 @@
namespace paysages {
namespace opengl {
class OPENGLSHARED_EXPORT OpenGLTerrain:public OpenGLPart
class OPENGLSHARED_EXPORT OpenGLTerrain: public OpenGLPart, public DefinitionWatcher
{
public:
OpenGLTerrain(OpenGLRenderer* renderer);
@ -30,6 +31,7 @@ public:
void performChunksMaintenance();
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
private:
OpenGLShaderProgram* program;
@ -38,6 +40,7 @@ private:
QVector<ExplorerChunkTerrain*> _chunks;
QList<ExplorerChunkTerrain*> _updateQueue;
QMutex _lock_chunks;
};
}

View file

@ -8,6 +8,8 @@
#include "WaterDefinition.h"
#include "SurfaceMaterial.h"
#include "NoiseFunctionSimplex.h"
#include "FloatNode.h"
#include "FloatDiff.h"
OpenGLWater::OpenGLWater(OpenGLRenderer *renderer):
OpenGLPart(renderer)
@ -34,6 +36,9 @@ void OpenGLWater::initialize()
setVertex(1, -1.0f, 0.0f, 1.0f);
setVertex(2, 1.0f, 0.0f, -1.0f);
setVertex(3, 1.0f, 0.0f, 1.0f);
// Watch for definition changes
renderer->getScenery()->getTerrain()->propWaterHeight()->addWatcher(this, true);
}
void OpenGLWater::update()
@ -58,3 +63,11 @@ void OpenGLWater::setVertex(int i, float x, float y, float z)
vertices[i * 3 + 1] = y;
vertices[i * 3 + 2] = z;
}
void OpenGLWater::nodeChanged(const DefinitionNode *node, const DefinitionDiff *)
{
if (node->getPath() == "/terrain/water_height")
{
renderer->getSharedState()->set("waterOffset", renderer->getScenery()->getTerrain()->getWaterOffset());
}
}

View file

@ -4,11 +4,12 @@
#include "opengl_global.h"
#include "OpenGLPart.h"
#include "DefinitionWatcher.h"
namespace paysages {
namespace opengl {
class OPENGLSHARED_EXPORT OpenGLWater: public OpenGLPart
class OPENGLSHARED_EXPORT OpenGLWater: public OpenGLPart, public DefinitionWatcher
{
public:
OpenGLWater(OpenGLRenderer* renderer);
@ -18,6 +19,7 @@ public:
virtual void update() override;
virtual void render() override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
private:
void setVertex(int i, float x, float y, float z);

View file

@ -3,10 +3,12 @@ attribute highp vec2 uv;
uniform highp mat4 viewMatrix;
varying vec3 unprojected;
varying vec2 texcoord;
uniform float waterOffset;
void main(void)
{
unprojected = vertex.xyz;
vec4 final = vertex + vec4(0, waterOffset, 0, 0);
unprojected = final.xyz;
texcoord = uv;
gl_Position = viewMatrix * vertex;
gl_Position = viewMatrix * final;
}

View file

@ -23,9 +23,9 @@ void TerrainRenderer::update()
walker->update();
}
double TerrainRenderer::getHeight(double x, double z, bool with_painting)
double TerrainRenderer::getHeight(double x, double z, bool with_painting, bool water_offset)
{
return parent->getScenery()->getTerrain()->getInterpolatedHeight(x, z, true, with_painting);
return parent->getScenery()->getTerrain()->getInterpolatedHeight(x, z, true, with_painting, water_offset);
}
static inline Vector3 _getNormal4(Vector3 center, Vector3 north, Vector3 east, Vector3 south, Vector3 west)

View file

@ -27,7 +27,7 @@ public:
virtual void update();
virtual RayCastingResult castRay(const Vector3 &start, const Vector3 &direction);
virtual double getHeight(double x, double z, bool with_painting);
virtual double getHeight(double x, double z, bool with_painting, bool water_offset=true);
virtual TerrainResult getResult(double x, double z, bool with_painting, bool with_textures);
virtual Color getFinalColor(const Vector3 &location, double precision);
virtual bool applyLightFilter(LightComponent &light, const Vector3 &at) override;

View file

@ -2,6 +2,8 @@
#include "DiffManager.h"
#include "DefinitionNode.h"
#include "DefinitionWatcher.h"
#include "FloatDiff.h"
#include "FloatNode.h"
TEST(DiffManager, undoRedo)
@ -111,3 +113,52 @@ TEST(DiffManager, undoBranch)
diffs->redo();
EXPECT_DOUBLE_EQ(4.4, leaf.getValue());
}
class TestWatcher: public DefinitionWatcher
{
public:
TestWatcher(DefinitionNode* expected_node, double expected_old_value, double expected_new_value):
DefinitionWatcher(), expected_node(expected_node), expected_old_value(expected_old_value), expected_new_value(expected_new_value)
{
calls = 0;
}
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override
{
EXPECT_EQ(expected_node, node);
ASSERT_EQ("float", diff->getTypeName());
const FloatDiff *float_diff = (const FloatDiff *)diff;
EXPECT_EQ(expected_old_value, float_diff->getOldValue());
EXPECT_EQ(expected_new_value, float_diff->getNewValue());
calls++;
}
int calls;
DefinitionNode* expected_node;
double expected_old_value;
double expected_new_value;
};
TEST(DiffManager, addWatcher)
{
FloatNode node(NULL, "node");
TestWatcher watcher(&node, 1.3, -4.0);
node.setValue(1.3);
EXPECT_EQ(0, watcher.calls);
node.addWatcher(&watcher);
EXPECT_EQ(0, watcher.calls);
node.setValue(-4.0);
EXPECT_EQ(1, watcher.calls);
}
TEST(DiffManager, addWatcherWithInitDiffs)
{
FloatNode node(NULL, "node", 1.3);
TestWatcher watcher(&node, 1.3, 1.3);
node.addWatcher(&watcher, true);
EXPECT_EQ(1, watcher.calls);
}

View file

@ -5,6 +5,7 @@
#include "TerrainDefinition.h"
#include "TerrainHeightMap.h"
#include "PaintedGridBrush.h"
#include "FloatNode.h"
/* Noise sin period is defined at 20.0 */
#define X_FACTOR (M_PI / 10.0)
@ -31,7 +32,7 @@ protected:
terrain->height = 3.0;
terrain->scaling = 1.0;
terrain->_height_noise->clearLevels();
terrain->water_height = 0.0;
terrain->propWaterHeight()->setValue(0.0);
NoiseGenerator::NoiseLevel level = {1.0, 2.0, -1.0};
terrain->_height_noise->addLevel(level);
noise_state.resetOffsets();