Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding color as a proper option type #1967

Merged
merged 18 commits into from
Feb 16, 2025
5 changes: 1 addition & 4 deletions application/testing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1034,10 +1034,7 @@ endif ()
f3d_test(NAME TestInvalidTexture DATA cow.vtp ARGS --texture-material=${F3D_SOURCE_DIR}/testing/data/invalid.png REGEXP "Cannot open texture file" NO_BASELINE)

# Test invalid color
f3d_test(NAME TestInvalidColor DATA cow.vtp ARGS --color=0,0,0,1 REGEXP "Invalid surface color provided, not applying" NO_BASELINE)

# Test invalid emmisive factor
f3d_test(NAME TestInvalidEmissiveFactor DATA cow.vtp ARGS --emissive-factor=0,0,0,1 REGEXP "Invalid emissive factor provided, not applying" NO_BASELINE)
f3d_test(NAME TestInvalidColor DATA cow.vtp ARGS --color=0,0,0,1 REGEXP "Provided vector does not have the right size" NO_BASELINE)

# Test non existent interaction file, do not add a TestNonExistentInteraction
f3d_test(NAME TestNonExistentInteraction DATA cow.vtp INTERACTION REGEXP "Interaction record file to play does not exist" NO_BASELINE)
5 changes: 5 additions & 0 deletions cmake/f3dOptions.cmake
Original file line number Diff line number Diff line change
@@ -129,6 +129,11 @@ function(_parse_json_option _top_json)
elseif(_option_type STREQUAL "ratio")
set(_option_actual_type "f3d::ratio_t")
set(_option_variant_type "double")
elseif(_option_type STREQUAL "color")
set(_option_actual_type "f3d::color_t")
set(_option_variant_type "std::vector<double>")
set(_option_default_value_start "{")
set(_option_default_value_end "}")
endif()

# Add option to struct and methods
58 changes: 29 additions & 29 deletions doc/libf3d/OPTIONS.md

Large diffs are not rendered by default.

108 changes: 54 additions & 54 deletions doc/user/OPTIONS.md

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion doc/user/PARSING.md
Original file line number Diff line number Diff line change
@@ -9,8 +9,9 @@ The following types are supported:
- double: A floating point number.
- ratio: A double dividend over a double divisor, stored in a double.
- string: A string of characters.
- color: A RGB color

As well as a list for each of these types, noted as
As well as a list for bool, int, double, ratio, string, noted as

- vector\<type\>

@@ -62,3 +63,7 @@ String are parsed and formatted as is.
Vector tokens are separated by `,`, tokens are then parsed using their respective types.

When formatting a vector into a string, individual token are formatted according to their type and separated using `,`.

## Color

Color are parsed and formatted as a vector of double.
8 changes: 4 additions & 4 deletions library/options.json
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@
"default_value": "10"
},
"color": {
"type": "double_vector",
"type": "color",
"default_value": "0.0, 0.0, 0.0"
}
},
@@ -107,7 +107,7 @@
},
"background": {
"color": {
"type": "double_vector",
"type": "color",
"default_value": "0.2, 0.2, 0.2"
},
"skybox": {
@@ -206,15 +206,15 @@
"type": "double"
},
"rgb": {
"type": "double_vector"
"type": "color"
},
"texture": {
"type": "string"
}
},
"emissive": {
"factor": {
"type": "double_vector"
"type": "color"
},
"texture": {
"type": "string"
36 changes: 36 additions & 0 deletions library/private/options_tools.h.in
Original file line number Diff line number Diff line change
@@ -181,6 +181,26 @@ ratio_t parse(const std::string& str)
}
}

//----------------------------------------------------------------------------
/**
* Parse provided string into a color_t.
* Supported formats: "R,G,B"
* rely on parse<std::vector<double>>(str)
* Can throw options::parsing_exception in case of failure to parse
*/
template<>
color_t parse(const std::string& str)
{
try
{
return color_t(options_tools::parse<std::vector<double>>(str));
}
catch (const f3d::type_construction_exception& ex)
{
throw options::parsing_exception("Cannot parse " + str + " into a color_t: " + ex.what());
}
}

//----------------------------------------------------------------------------
/**
* Return provided string stripped of leading and trailing spaces.
@@ -263,6 +283,17 @@ std::string format(const std::vector<T>& var)
return stream.str();
}

//----------------------------------------------------------------------------
/**
* Format provided var into a string from provided color_t
* rely on format(std::vector<double>&)
*/
std::string format(color_t var)
{
// TODO generate a proper color string
return options_tools::format(static_cast<std::vector<double>>(var));
}

//----------------------------------------------------------------------------
/**
* Generated method, see `options::set`
@@ -281,6 +312,11 @@ void set(options& opt, std::string_view name, const option_variant_t& value)
throw options::incompatible_exception(
"Trying to set " + std::string(name) + " with incompatible type");
}
catch (const f3d::type_construction_exception& ex)
{
throw options::incompatible_exception(
"Could not create type for " + std::string(name) + " : " + ex.what());
}
}

//----------------------------------------------------------------------------
9 changes: 9 additions & 0 deletions library/public/options.h.in
Original file line number Diff line number Diff line change
@@ -194,6 +194,15 @@ public:
${_options_struct}
// clang-format on
};

}

// Certain options types are not trivially streamable
//----------------------------------------------------------------------------
inline std::ostream& operator<<(std::ostream& os, const f3d::color_t& color)
{
os << f3d::options::format(color);
return os;
}

#endif
101 changes: 101 additions & 0 deletions library/public/types.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
#ifndef f3d_types_h
#define f3d_types_h

#include "exception.h"
#include "export.h"

#include <algorithm>
#include <array>
#include <iostream>
#include <string>
#include <vector>

namespace f3d
{
/**
* An exception that can be thrown by any type if
* it fails in the constructor for some reason.
*/
struct type_construction_exception : public exception
{
explicit type_construction_exception(const std::string& what = "")
: exception(what) {};
};

/**
* An exception that can be thrown by any type if
* it fails when accessing data for some reason.
*/
struct type_access_exception : public exception
{
explicit type_access_exception(const std::string& what = "")
: exception(what) {};
};

/**
* Describe a 3D point.
*/
@@ -58,6 +81,84 @@ class F3D_EXPORT ratio_t
double Value;
};

/**
* Describe a RGB color.
*/
class F3D_EXPORT color_t
{
public:
color_t() = default;
color_t(const std::vector<double>& vec)
{
if (vec.size() != 3)
{
throw f3d::type_construction_exception("Provided vector does not have the right size");
}
std::copy_n(vec.begin(), 3, this->RGB.begin());
}
color_t(double red, double green, double blue)
{
this->RGB[0] = red;
this->RGB[1] = green;
this->RGB[2] = blue;
}
color_t(const std::initializer_list<double>& list)
{
if (list.size() != 3)
{
throw f3d::type_construction_exception("Provided list does not have the right size");
}
std::copy_n(list.begin(), 3, this->RGB.begin());
}
operator std::vector<double>() const
{
return std::vector<double>(this->RGB.begin(), this->RGB.end());
}
bool operator==(const color_t& other) const
{
return this->RGB == other.RGB;
}
bool operator!=(const color_t& other) const
{
return this->RGB != other.RGB;
}
double operator[](size_t i) const
{
if (i >= 3)
{
throw f3d::type_access_exception("Incorrect index");
}
return this->RGB[i];
}
double& operator[](size_t i)
{
if (i >= 3)
{
throw f3d::type_access_exception("Incorrect index");
}
return this->RGB[i];
}
const double* data() const
{
return this->RGB.data();
}
double r() const
{
return this->RGB[0];
}
double g() const
{
return this->RGB[1];
}
double b() const
{
return this->RGB[2];
}

private:
std::array<double, 3> RGB;
};

/**
* Describe a 3D surfacic mesh.
* A valid mesh fulfills these requirements:
19 changes: 10 additions & 9 deletions library/src/options.cxx
Original file line number Diff line number Diff line change
@@ -181,17 +181,18 @@ std::string options::format(const T& var)
}

//----------------------------------------------------------------------------
#define F3D_DECL_TYPE_INTERNAL(TYPE) \
#define F3D_DECL_TYPE(TYPE) \
template F3D_EXPORT TYPE options::parse<TYPE>(const std::string& str); \
template F3D_EXPORT std::string options::format<TYPE>(const TYPE& val)
#define F3D_DECL_TYPE(TYPE) \
F3D_DECL_TYPE_INTERNAL(TYPE); \
F3D_DECL_TYPE_INTERNAL(std::vector<TYPE>)
F3D_DECL_TYPE(bool);
F3D_DECL_TYPE(int);
F3D_DECL_TYPE(double);
F3D_DECL_TYPE(f3d::ratio_t);
F3D_DECL_TYPE(std::string);
#define F3D_DECL_TYPE_WITH_VEC(TYPE) \
F3D_DECL_TYPE(TYPE); \
F3D_DECL_TYPE(std::vector<TYPE>)
F3D_DECL_TYPE_WITH_VEC(bool);
F3D_DECL_TYPE_WITH_VEC(int);
F3D_DECL_TYPE_WITH_VEC(double);
F3D_DECL_TYPE_WITH_VEC(f3d::ratio_t);
F3D_DECL_TYPE_WITH_VEC(std::string);
F3D_DECL_TYPE(color_t);

//----------------------------------------------------------------------------
options::parsing_exception::parsing_exception(const std::string& what)
2 changes: 1 addition & 1 deletion library/testing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -141,9 +141,9 @@ endif ()
# List tests that do not require rendering
list(APPEND libf3dSDKTestsNoRender_list
TestSDKEngineExceptions
TestSDKLog
TestSDKOptions
TestSDKOptionsIO
TestSDKLog
TestSDKScene)

# Add all the ADD_TEST for each test
2 changes: 2 additions & 0 deletions library/testing/PseudoUnitTest.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef PseudoUnitTest_h
#define PseudoUnitTest_h

#include "options.h"

#include <functional>
#include <iostream>
#include <sstream>
Loading