diff --git a/src/basics/Color.h b/src/basics/Color.h index 9af2225..f305d60 100644 --- a/src/basics/Color.h +++ b/src/basics/Color.h @@ -35,7 +35,12 @@ class BASICSSHARED_EXPORT Color { Color add(const Color &other) const; Color lerp(const Color &other, double f) const; + inline bool operator==(const Color &other) const { + return r == other.r and g == other.g and b == other.b and a == other.a; + } + public: + // TODO Make private double r; double g; double b; @@ -52,11 +57,4 @@ BASICSSHARED_EXPORT extern const Color COLOR_GREY; } } -// Inlining -#if PAYSAGES_USE_INLINING -#ifndef COLOR_INLINE_CPP -#include "Color.inline.cpp" -#endif -#endif - #endif // COLOR_H diff --git a/src/definition/ColorDiff.cpp b/src/definition/ColorDiff.cpp new file mode 100644 index 0000000..0f7ed8f --- /dev/null +++ b/src/definition/ColorDiff.cpp @@ -0,0 +1,13 @@ +#include "ColorDiff.h" + +ColorDiff::ColorDiff(const DefinitionNode *node, const Color &oldvalue, const Color &newvalue) + : DefinitionDiff(node), oldvalue(oldvalue), newvalue(newvalue) { +} + +ColorDiff::ColorDiff(const ColorDiff *other, const Color &oldvalue, const Color &newvalue) + : DefinitionDiff(other), oldvalue(oldvalue), newvalue(newvalue) { +} + +DefinitionDiff *ColorDiff::newReversed() const { + return new ColorDiff(this, newvalue, oldvalue); +} diff --git a/src/definition/ColorDiff.h b/src/definition/ColorDiff.h new file mode 100644 index 0000000..65ff39b --- /dev/null +++ b/src/definition/ColorDiff.h @@ -0,0 +1,36 @@ +#ifndef COLORDIFF_H +#define COLORDIFF_H + +#include "definition_global.h" + +#include "DefinitionDiff.h" +#include "Color.h" + +namespace paysages { +namespace definition { + +/** + * Diff for a ColorNode. + */ +class DEFINITIONSHARED_EXPORT ColorDiff : public DefinitionDiff { + public: + ColorDiff(const DefinitionNode *node, const Color &oldvalue, const Color &newvalue); + ColorDiff(const ColorDiff *other, const Color &oldvalue, const Color &newvalue); + + inline const Color &getOldValue() const { + return oldvalue; + } + inline const Color &getNewValue() const { + return newvalue; + } + + virtual DefinitionDiff *newReversed() const override; + + private: + Color oldvalue; + Color newvalue; +}; +} +} + +#endif // COLORDIFF_H diff --git a/src/definition/ColorNode.cpp b/src/definition/ColorNode.cpp new file mode 100644 index 0000000..68f9014 --- /dev/null +++ b/src/definition/ColorNode.cpp @@ -0,0 +1,74 @@ +#include "ColorNode.h" + +#include +#include +#include "ColorDiff.h" +#include "Logs.h" + +// TODO Could be made into a template + +ColorNode::ColorNode(DefinitionNode *parent, const string &name, const Color &value) + : DefinitionNode(parent, name, "color"), value(value) { +} + +string ColorNode::toString(int indent) const { + ostringstream stream; + + stream << DefinitionNode::toString(indent) << " " << value.r << "," << value.g << "," << value.b << "," << value.a; + + return stream.str(); +} + +void ColorNode::save(PackStream *stream) const { + value.save(stream); +} + +void ColorNode::load(PackStream *stream) { + value.load(stream); +} + +void ColorNode::copy(DefinitionNode *destination) const { + if (auto tdest = dynamic_cast(destination)) { + tdest->value = value; + } else { + Logs::error("Definition") << "Can't copy from " << getTypeName() << " to " << destination->getTypeName() + << endl; + } +} + +void ColorNode::setValue(const Color &value) { + addDiff(produceDiff(value)); +} + +const ColorDiff *ColorNode::produceDiff(const Color &value) const { + return new ColorDiff(this, this->value, value); +} + +void ColorNode::generateInitDiffs(vector *diffs) const { + diffs->push_back(produceDiff(value)); +} + +bool ColorNode::applyDiff(const DefinitionDiff *diff, bool backward) { + if (!DefinitionNode::applyDiff(diff, backward)) { + return false; + } + + assert(diff->getTypeName() == "color"); + auto color_diff = dynamic_cast(diff); + + if (color_diff) { + Color previous = backward ? color_diff->getNewValue() : color_diff->getOldValue(); + Color next = backward ? color_diff->getOldValue() : color_diff->getNewValue(); + + if (value == previous) { + value = next; + return true; + } else { + Logs::error("Definition") << "Can't apply color diff" << endl; + return false; + } + } else { + Logs::error("Could not cast DefinitionDiff to ColorDiff"); + return false; + } +} diff --git a/src/definition/ColorNode.h b/src/definition/ColorNode.h new file mode 100644 index 0000000..544d4a2 --- /dev/null +++ b/src/definition/ColorNode.h @@ -0,0 +1,44 @@ +#ifndef COLORNODE_H +#define COLORNODE_H + +#include "definition_global.h" + +#include "DefinitionNode.h" +#include "Color.h" + +namespace paysages { +namespace definition { + +/** + * Node with a single color value, for the definition tree. + */ +class DEFINITIONSHARED_EXPORT ColorNode : public DefinitionNode { + public: + ColorNode(DefinitionNode *parent, const string &name, const Color &value = COLOR_TRANSPARENT); + + inline const Color &getValue() const { + return value; + } + + virtual string toString(int indent) const override; + virtual void save(PackStream *stream) const override; + virtual void load(PackStream *stream) override; + virtual void copy(DefinitionNode *destination) const override; + + /** + * Change the color value stored. + * + * The DiffManager is used as intermediary, so that the change may not happen immediately. + */ + void setValue(const Color &value); + const ColorDiff *produceDiff(const Color &value) const; + virtual void generateInitDiffs(vector *diffs) const override; + virtual bool applyDiff(const DefinitionDiff *diff, bool backward = false) override; + + private: + Color value; +}; +} +} + +#endif // COLORNODE_H diff --git a/src/definition/DefinitionNode.cpp b/src/definition/DefinitionNode.cpp index d5c3483..bfffed7 100644 --- a/src/definition/DefinitionNode.cpp +++ b/src/definition/DefinitionNode.cpp @@ -249,6 +249,7 @@ void DefinitionNode::addDiff(const DefinitionDiff *diff) { if (root && root->diffs) { root->diffs->addDiff(this, diff); } else { + // TODO Apply diff ? delete diff; } } diff --git a/src/definition/FloatNode.cpp b/src/definition/FloatNode.cpp index f52a495..70f7a28 100644 --- a/src/definition/FloatNode.cpp +++ b/src/definition/FloatNode.cpp @@ -27,8 +27,8 @@ void FloatNode::load(PackStream *stream) { } void FloatNode::copy(DefinitionNode *destination) const { - if (destination->getTypeName() == getTypeName()) { - ((FloatNode *)destination)->value = value; + if (auto tdest = dynamic_cast(destination)) { + tdest->value = value; } else { Logs::error("Definition") << "Can't copy from " << getTypeName() << " to " << destination->getTypeName() << endl; @@ -53,17 +53,22 @@ bool FloatNode::applyDiff(const DefinitionDiff *diff, bool backward) { } assert(diff->getTypeName() == "float"); - const FloatDiff *float_diff = (const FloatDiff *)diff; + auto float_diff = dynamic_cast(diff); - double previous = backward ? float_diff->getNewValue() : float_diff->getOldValue(); - double next = backward ? float_diff->getOldValue() : float_diff->getNewValue(); + if (float_diff) { + double previous = backward ? float_diff->getNewValue() : float_diff->getOldValue(); + double next = backward ? float_diff->getOldValue() : float_diff->getNewValue(); - if (value == previous) { - value = next; - return true; + if (value == previous) { + value = next; + return true; + } else { + Logs::error("Definition") << "Can't apply float diff " << previous << " => " << next << " to " << getName() + << endl; + return false; + } } else { - Logs::error("Definition") << "Can't apply float diff " << previous << " => " << next << " to " << getName() - << endl; + Logs::error("Could not cast DefinitionDiff to IntDiff"); return false; } } diff --git a/src/definition/FloatNode.h b/src/definition/FloatNode.h index 50f7170..c424018 100644 --- a/src/definition/FloatNode.h +++ b/src/definition/FloatNode.h @@ -31,7 +31,7 @@ class DEFINITIONSHARED_EXPORT FloatNode : public DefinitionNode { */ void setValue(double new_value); const FloatDiff *produceDiff(double new_value) const; - void generateInitDiffs(vector *diffs) const; + virtual void generateInitDiffs(vector *diffs) const override; virtual bool applyDiff(const DefinitionDiff *diff, bool backward = false) override; void addValue(double added); diff --git a/src/definition/IntNode.cpp b/src/definition/IntNode.cpp index a552314..e676ced 100644 --- a/src/definition/IntNode.cpp +++ b/src/definition/IntNode.cpp @@ -27,8 +27,8 @@ void IntNode::load(PackStream *stream) { } void IntNode::copy(DefinitionNode *destination) const { - if (destination->getTypeName() == getTypeName()) { - ((IntNode *)destination)->value = value; + if (auto tdest = dynamic_cast(destination)) { + tdest->value = value; } else { Logs::error("Definition") << "Can't copy from " << getTypeName() << " to " << destination->getTypeName() << endl; @@ -53,17 +53,22 @@ bool IntNode::applyDiff(const DefinitionDiff *diff, bool backward) { } assert(diff->getTypeName() == "int"); - const IntDiff *int_diff = (const IntDiff *)diff; + auto int_diff = dynamic_cast(diff); - double previous = backward ? int_diff->getNewValue() : int_diff->getOldValue(); - double next = backward ? int_diff->getOldValue() : int_diff->getNewValue(); + if (int_diff) { + int previous = backward ? int_diff->getNewValue() : int_diff->getOldValue(); + int next = backward ? int_diff->getOldValue() : int_diff->getNewValue(); - if (value == previous) { - value = next; - return true; + if (value == previous) { + value = next; + return true; + } else { + Logs::error("Definition") << "Can't apply int diff " << previous << " => " << next << " to " << getName() + << endl; + return false; + } } else { - Logs::error("Definition") << "Can't apply int diff " << previous << " => " << next << " to " << getName() - << endl; + Logs::error("Could not cast DefinitionDiff to IntDiff"); return false; } } diff --git a/src/definition/IntNode.h b/src/definition/IntNode.h index 4f23ce8..5c84a0d 100644 --- a/src/definition/IntNode.h +++ b/src/definition/IntNode.h @@ -31,7 +31,7 @@ class DEFINITIONSHARED_EXPORT IntNode : public DefinitionNode { */ void setValue(int new_value); const IntDiff *produceDiff(int new_value) const; - void generateInitDiffs(vector *diffs) const; + virtual void generateInitDiffs(vector *diffs) const override; virtual bool applyDiff(const DefinitionDiff *diff, bool backward = false) override; private: diff --git a/src/definition/WaterDefinition.cpp b/src/definition/WaterDefinition.cpp index 4753571..5ba9723 100644 --- a/src/definition/WaterDefinition.cpp +++ b/src/definition/WaterDefinition.cpp @@ -2,19 +2,19 @@ #include "PackStream.h" #include "NoiseState.h" -#include "Color.h" #include "SurfaceMaterial.h" #include "IntNode.h" #include "FloatNode.h" +#include "ColorNode.h" WaterDefinition::WaterDefinition(DefinitionNode *parent) : DefinitionNode(parent, "water", "water") { model = new IntNode(this, "model", -1); reflection = new FloatNode(this, "reflection"); xoffset = new FloatNode(this, "xoffset"); zoffset = new FloatNode(this, "zoffset"); + depth_color = new ColorNode(this, "depth_color"); material = new SurfaceMaterial; - depth_color = new Color; foam_material = new SurfaceMaterial; noise_state = new NoiseState(); @@ -32,7 +32,6 @@ WaterDefinition::WaterDefinition(DefinitionNode *parent) : DefinitionNode(parent WaterDefinition::~WaterDefinition() { delete material; - delete depth_color; delete foam_material; delete noise_state; } @@ -41,7 +40,6 @@ void WaterDefinition::save(PackStream *stream) const { DefinitionNode::save(stream); material->save(stream); - depth_color->save(stream); stream->write(&transparency_depth); stream->write(&transparency); stream->write(&lighting_depth); @@ -61,7 +59,6 @@ void WaterDefinition::load(PackStream *stream) { DefinitionNode::load(stream); material->load(stream); - depth_color->load(stream); stream->read(&transparency_depth); stream->read(&transparency); stream->read(&lighting_depth); @@ -84,7 +81,6 @@ void WaterDefinition::copy(DefinitionNode *_destination) const { WaterDefinition *destination = (WaterDefinition *)_destination; *destination->material = *material; - *destination->depth_color = *depth_color; destination->transparency_depth = transparency_depth; destination->transparency = transparency; destination->lighting_depth = lighting_depth; @@ -100,7 +96,6 @@ void WaterDefinition::copy(DefinitionNode *_destination) const { void WaterDefinition::validate() { DefinitionNode::validate(); - depth_color->a = 1.0; material->base->a = 1.0; material->reflection = 1.0; material->shininess = 16.0; @@ -116,17 +111,13 @@ void WaterDefinition::validate() { void WaterDefinition::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) { if (node == model) { - noise_state->randomizeOffsets(); - switch (model->getValue()) { case 1: transparency = 0.3; reflection->setValue(0.07); transparency_depth = 3.0; material->setColor(0.05, 0.18, 0.2, 1.0); - depth_color->r = 0.0; - depth_color->g = 0.18; - depth_color->b = 0.15; + depth_color->setValue(Color(0.0, 0.18, 0.15)); lighting_depth = 4.0; scaling = 1.5; waves_height = 1.0; @@ -140,9 +131,7 @@ void WaterDefinition::nodeChanged(const DefinitionNode *node, const DefinitionDi reflection->setValue(0.2); transparency_depth = 4.0; material->setColor(0.08, 0.15, 0.2, 1.0); - depth_color->r = 0.0; - depth_color->g = 0.1; - depth_color->b = 0.1; + depth_color->setValue(Color(0.0, 0.1, 0.1)); lighting_depth = 6.0; scaling = 1.0; waves_height = 0.8; @@ -155,6 +144,8 @@ void WaterDefinition::nodeChanged(const DefinitionNode *node, const DefinitionDi } void WaterDefinition::applyPreset(WaterPreset preset, RandomGenerator &random) { + noise_state->randomizeOffsets(random); + if (preset == WATER_PRESET_LAKE) { model->setValue(0); } else if (preset == WATER_PRESET_SEA) { diff --git a/src/definition/WaterDefinition.h b/src/definition/WaterDefinition.h index 4b4b4da..edfec38 100644 --- a/src/definition/WaterDefinition.h +++ b/src/definition/WaterDefinition.h @@ -32,6 +32,9 @@ class DEFINITIONSHARED_EXPORT WaterDefinition : public DefinitionNode, public De inline FloatNode *propZOffset() const { return zoffset; } + inline ColorNode *propDepthColor() const { + return depth_color; + } virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff); @@ -41,7 +44,6 @@ class DEFINITIONSHARED_EXPORT WaterDefinition : public DefinitionNode, public De public: double transparency; SurfaceMaterial *material; - Color *depth_color; double transparency_depth; double lighting_depth; @@ -60,6 +62,7 @@ class DEFINITIONSHARED_EXPORT WaterDefinition : public DefinitionNode, public De FloatNode *reflection; FloatNode *xoffset; FloatNode *zoffset; + ColorNode *depth_color; }; } } diff --git a/src/definition/definition_global.h b/src/definition/definition_global.h index ebf2a73..efc710e 100644 --- a/src/definition/definition_global.h +++ b/src/definition/definition_global.h @@ -18,6 +18,8 @@ class FloatDiff; class IntNode; class IntDiff; class NoiseNode; +class ColorNode; +class ColorDiff; class DiffManager; class DefinitionWatcher; class Scenery; diff --git a/src/render/software/WaterRenderer.cpp b/src/render/software/WaterRenderer.cpp index 4f058f6..8ffd701 100644 --- a/src/render/software/WaterRenderer.cpp +++ b/src/render/software/WaterRenderer.cpp @@ -10,6 +10,7 @@ #include "SurfaceMaterial.h" #include "NoiseFunctionSimplex.h" #include "FloatNode.h" +#include "ColorNode.h" #include "RayCastingResult.h" WaterRenderer::WaterRenderer(SoftwareRenderer *parent) : parent(parent) { @@ -178,7 +179,7 @@ WaterRenderer::WaterResult WaterRenderer::getResult(double x, double z) { if (definition->transparency == 0.0) { result.refracted = COLOR_BLACK; } else { - Color depth_color = *definition->depth_color; + Color depth_color = definition->propDepthColor()->getValue(); refracted = parent->rayWalking(location, _refractRay(look_direction, normal), 1, 0, 1, 1); depth = location.sub(refracted.hit_location).getNorm(); depth_color.limitPower(refracted.hit_color.getPower()); diff --git a/src/tests/ColorNode_Test.cpp b/src/tests/ColorNode_Test.cpp new file mode 100644 index 0000000..5a6f71b --- /dev/null +++ b/src/tests/ColorNode_Test.cpp @@ -0,0 +1,108 @@ +#include "BaseTestCase.h" + +#include "ColorNode.h" +#include "ColorDiff.h" +#include "IntDiff.h" +#include "PackStream.h" + +TEST(ColorNode, toString) { + ColorNode test(NULL, "test", Color(0.1, 0.2, 0.3, 0.4)); + + EXPECT_EQ("test 0.1,0.2,0.3,0.4", test.toString(0)); + EXPECT_EQ(" test 0.1,0.2,0.3,0.4", test.toString(2)); +} + +TEST(ColorNode, saveLoadAndSkip) { + DefinitionNode root1(NULL, "root"); + ColorNode testa1(&root1, "testa", COLOR_RED); + ColorNode testb1(&root1, "testb", COLOR_GREEN); + + PackStream stream1; + root1.save(&stream1); + + DefinitionNode root2(NULL, "root"); + ColorNode testb2(&root2, "testb"); + + PackStream stream2(&stream1); + root2.load(&stream2); + + EXPECT_EQ(COLOR_GREEN, testb2.getValue()); +} + +TEST(ColorNode, copy) { + ColorNode base(NULL, "test", COLOR_BLUE); + ColorNode other(NULL, "test", COLOR_RED); + DefinitionNode badother(NULL, "test"); + + base.copy(&other); + EXPECT_EQ(COLOR_BLUE, base.getValue()); + EXPECT_EQ(COLOR_BLUE, other.getValue()); + + badother.copy(&base); + EXPECT_EQ(COLOR_BLUE, base.getValue()); + + base.copy(&badother); + // can't check anything, just useful in valgrind +} + +TEST(ColorNode, produceDiff) { + ColorNode node(NULL, "test", COLOR_BLUE); + const ColorDiff *diff = node.produceDiff(COLOR_RED); + + EXPECT_EQ("color", diff->getTypeName()); + EXPECT_EQ(COLOR_BLUE, diff->getOldValue()); + EXPECT_EQ(COLOR_RED, diff->getNewValue()); + + bool result = node.applyDiff(diff); + + EXPECT_TRUE(result); + EXPECT_EQ(COLOR_RED, node.getValue()); + + delete diff; +} + +TEST(ColorNode, applyDiff) { + ColorNode node(NULL, "test", COLOR_BLUE); + ColorDiff diff(&node, COLOR_BLUE, COLOR_RED); + DefinitionNode onode(NULL, "test", "badtype"); + IntDiff odiff(&onode, 1, 2); + bool result; + + EXPECT_EQ(COLOR_BLUE, node.getValue()); + + // apply + result = node.applyDiff(&diff); + + EXPECT_TRUE(result); + EXPECT_EQ(COLOR_RED, node.getValue()); + + // can't apply twice + result = node.applyDiff(&diff); + + EXPECT_FALSE(result); + EXPECT_EQ(COLOR_RED, node.getValue()); + + // reverse + result = node.applyDiff(&diff, true); + + EXPECT_TRUE(result); + EXPECT_EQ(COLOR_BLUE, node.getValue()); + + // can't reverse twice + result = node.applyDiff(&diff, true); + + EXPECT_FALSE(result); + EXPECT_EQ(COLOR_BLUE, node.getValue()); + + // bad type + result = node.applyDiff(&odiff); + + EXPECT_FALSE(result); + EXPECT_EQ(COLOR_BLUE, node.getValue()); + + // apply again + result = node.applyDiff(&diff); + + EXPECT_TRUE(result); + EXPECT_EQ(COLOR_RED, node.getValue()); +}