gfx-shader-param: Vastly improve parameter functionality

Allow for overriding type and size of an element, opening the path for `int#[]`, `float#[]`, `int#x#`, `float#x#`, `bool#x#`, `vector<type, #>` and `matrix<type, #, #>`. Also allows for specifying the exact type of texture instead of hoping the user gets it right, as well as samplers.

Parameters are also now created if they are invisible, which means that the properties() function must not be called, but they must still be used like any other. This is due to a problem with default values not being applied all the time, and sometimes just vanishing.

The code also now throws exceptions with reasonable text, which should be caught by the gfx::shader implementation and refuse a load of the effect. No other state should be modified at that point, so care must be taken that up until the moment the complete initialization is done no other state is modified.
This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2019-12-24 22:02:37 +01:00
parent eab3ae4fbc
commit 777556f4f6
2 changed files with 210 additions and 35 deletions

View file

@ -16,9 +16,98 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include "gfx-shader-param.hpp" #include "gfx-shader-param.hpp"
#include <algorithm>
#include <sstream> #include <sstream>
#include "gfx-shader-param-basic.hpp" #include "gfx-shader-param-basic.hpp"
#define ANNO_ORDER "order"
#define ANNO_VISIBILITY "visible"
#define ANNO_NAME "name"
#define ANNO_DESCRIPTION "description"
#define ANNO_TYPE "type"
#define ANNO_SIZE "size"
typedef gs::effect_parameter::type eptype;
gfx::shader::parameter_type gfx::shader::get_type_from_effect_type(gs::effect_parameter::type type)
{
switch (type) {
case eptype::Boolean:
return parameter_type::Boolean;
case eptype::Integer:
case eptype::Integer2:
case eptype::Integer3:
case eptype::Integer4:
return parameter_type::Integer;
case eptype::Float:
case eptype::Float2:
case eptype::Float3:
case eptype::Float4:
case eptype::Matrix:
return parameter_type::Float;
case eptype::String:
return parameter_type::String;
case eptype::Texture:
return parameter_type::Texture;
default:
return parameter_type::Unknown;
}
}
size_t gfx::shader::get_length_from_effect_type(gs::effect_parameter::type type)
{
switch (type) {
case eptype::Unknown:
case eptype::Invalid:
case eptype::String:
return 0;
case eptype::Boolean:
case eptype::Float:
case eptype::Integer:
case eptype::Texture:
return 1;
case eptype::Float2:
case eptype::Integer2:
return 2;
case eptype::Float3:
case eptype::Integer3:
return 3;
case eptype::Float4:
case eptype::Integer4:
return 4;
case eptype::Matrix:
return 16;
}
}
gfx::shader::parameter_type gfx::shader::get_type_from_string(std::string v)
{
if ((v == "bool") || (v == "boolean")) {
return parameter_type::Boolean;
}
if ((v == "float") || (v == "single")) {
return parameter_type::Float;
}
if ((v == "int") || (v == "integer")) {
return parameter_type::Integer;
}
if ((v == "text") || (v == "string")) {
return parameter_type::String;
}
if ((v == "tex") || (v == "texture")) {
return parameter_type::Texture;
}
if ((v == "sampler")) {
return parameter_type::Sampler;
}
/* To decide on in the future:
* - Double support?
* - Half Support?
* - Texture Arrays? (Likely not supported in libobs)
*/
throw std::invalid_argument("Invalid parameter type string.");
}
gfx::shader::parameter::parameter(gs::effect_parameter param, std::string key_prefix) gfx::shader::parameter::parameter(gs::effect_parameter param, std::string key_prefix)
: _param(param), _order(0), _key(_param.get_name()), _name(_key), _description() : _param(param), _order(0), _key(_param.get_name()), _name(_key), _description()
{ {
@ -28,17 +117,44 @@ gfx::shader::parameter::parameter(gs::effect_parameter param, std::string key_pr
_name = (_key); _name = (_key);
} }
if (auto anno = _param.get_annotation("order"); anno) { // Read Order
if (auto anno = _param.get_annotation(ANNO_ORDER); anno) {
_order = anno.get_default_int(); _order = anno.get_default_int();
} }
if (auto anno = _param.get_annotation("name"); anno) {
if (std::string v = anno.get_default_string(); v.length() > 0) // Read Name
if (auto anno = _param.get_annotation(ANNO_NAME); anno) {
if (std::string v = anno.get_default_string(); v.length() > 0) {
_name = v; _name = v;
} else {
throw std::out_of_range("'" ANNO_NAME "' annotation has zero length.");
} }
if (auto anno = _param.get_annotation("description"); anno) { }
if (std::string v = anno.get_default_string(); v.length() > 0)
// Read Description
if (auto anno = _param.get_annotation(ANNO_DESCRIPTION); anno) {
if (std::string v = anno.get_default_string(); v.length() > 0) {
_description = v; _description = v;
} else {
throw std::out_of_range("'" ANNO_DESCRIPTION "' annotation has zero length.");
} }
}
// Read Type override.
_type = get_type_from_effect_type(_param.get_type());
if (auto anno = _param.get_annotation(ANNO_TYPE); anno) {
// We have a type override.
_type = get_type_from_string(anno.get_default_string());
}
// Read Size override.
_size = get_length_from_effect_type(_param.get_type());
if (auto anno = _param.get_annotation(ANNO_SIZE); anno) {
size_t ov = anno.get_default_int();
if (ov > 0)
_size = ov;
}
_size = std::clamp(_size, 1ull, 32ull);
} }
void gfx::shader::parameter::defaults(obs_data_t* settings) {} void gfx::shader::parameter::defaults(obs_data_t* settings) {}
@ -49,11 +165,36 @@ void gfx::shader::parameter::update(obs_data_t* settings) {}
void gfx::shader::parameter::assign() {} void gfx::shader::parameter::assign() {}
gs::effect_parameter gfx::shader::parameter::get_parameter()
{
return gs::effect_parameter();
}
gfx::shader::parameter_type gfx::shader::parameter::get_type()
{
return _type;
}
size_t gfx::shader::parameter::get_size()
{
return _size;
}
int32_t gfx::shader::parameter::get_order() int32_t gfx::shader::parameter::get_order()
{ {
return _order; return _order;
} }
const std::string& gfx::shader::parameter::get_key()
{
return _key;
}
bool gfx::shader::parameter::has_name()
{
return _name.length() > 0;
}
const std::string& gfx::shader::parameter::get_name() const std::string& gfx::shader::parameter::get_name()
{ {
return _name; return _name;
@ -72,36 +213,23 @@ const std::string& gfx::shader::parameter::get_description()
std::shared_ptr<gfx::shader::parameter> gfx::shader::parameter::make_parameter(gs::effect_parameter param, std::shared_ptr<gfx::shader::parameter> gfx::shader::parameter::make_parameter(gs::effect_parameter param,
std::string prefix) std::string prefix)
{ {
if (!param) if (!param) {
return nullptr; throw std::runtime_error("Bad call to make_parameter. This is a bug in the plugin.");
// ToDo: Allow other parameters to specify hidden properties, as well as the shader itself, and the source/filter/transition.
if (auto anno = param.get_annotation("visible"); anno != nullptr) {
if (!anno.get_default_bool()) {
return nullptr;
}
} }
typedef gs::effect_parameter::type eptype; parameter_type real_type = get_type_from_effect_type(param.get_type());
switch (param.get_type()) { if (auto anno = param.get_annotation(ANNO_TYPE); anno) {
case eptype::Boolean: { // We have a type override.
auto el = std::make_shared<gfx::shader::bool_parameter>(param, prefix); parameter_type real_type = get_type_from_string(param.get_default_string());
return el;
}
case eptype::Integer:
case eptype::Integer2:
case eptype::Integer3:
case eptype::Integer4: {
auto el = std::make_shared<gfx::shader::int_parameter>(param, prefix);
return el;
}
case eptype::Float:
case eptype::Float2:
case eptype::Float3:
case eptype::Float4: {
auto el = std::make_shared<gfx::shader::float_parameter>(param, prefix);
return el;
} }
switch (real_type) {
case parameter_type::Boolean:
return std::make_shared<gfx::shader::bool_parameter>(param, prefix);
case parameter_type::Integer:
return std::make_shared<gfx::shader::int_parameter>(param, prefix);
case parameter_type::Float:
return std::make_shared<gfx::shader::float_parameter>(param, prefix);
default: default:
return nullptr; return nullptr;
} }

View file

@ -34,19 +34,54 @@ extern "C" {
namespace gfx { namespace gfx {
namespace shader { namespace shader {
enum class parameter_type {
// Unknown type, could be anything.
Unknown,
// Boolean, either false or true.
Boolean,
// Single Floating Point
Float,
// 32-Bit Integer
Integer,
// UTF-8 Character based String.
String,
// Texture with dimensions stored in size (1 = Texture1D, 2 = Texture2D, 3 = Texture3D, 6 = TextureCube).
Texture,
// Sampler for Textures.
Sampler
};
parameter_type get_type_from_effect_type(gs::effect_parameter::type type);
size_t get_length_from_effect_type(gs::effect_parameter::type type);
parameter_type get_type_from_string(std::string v);
class parameter { class parameter {
protected: // Parameter used for all functionality.
gs::effect_parameter _param; gs::effect_parameter _param;
// Real type of the parameter (libobs gets it wrong often).
parameter_type _type;
// Real size of the parameter (libobs gets it wrong often).
size_t _size;
// Order of the parameter in a list/map.
int32_t _order; int32_t _order;
// Key for the parameter (group) in a list/map.
std::string _key; std::string _key;
// Visibility, name and description.
bool _visible;
std::string _name; std::string _name;
std::string _description; std::string _description;
protected:
parameter(gs::effect_parameter param, std::string key_prefix); parameter(gs::effect_parameter param, std::string key_prefix);
virtual ~parameter(){}; virtual ~parameter(){};
public:
virtual void defaults(obs_data_t* settings); virtual void defaults(obs_data_t* settings);
virtual void properties(obs_properties_t* props, obs_data_t* settings); virtual void properties(obs_properties_t* props, obs_data_t* settings);
@ -56,8 +91,20 @@ namespace gfx {
virtual void assign(); virtual void assign();
public: public:
gs::effect_parameter get_parameter();
parameter_type get_type();
size_t get_size();
int32_t get_order(); int32_t get_order();
const std::string& get_key();
bool is_visible();
bool has_name();
const std::string& get_name(); const std::string& get_name();
bool has_description(); bool has_description();