2018-03-20 11:45:41 +00:00
|
|
|
// Modern effects for a modern Streamer
|
|
|
|
// Copyright (C) 2017 Michael Fabian Dirks
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
|
2019-01-14 10:23:21 +00:00
|
|
|
#include "gfx-effect-source.hpp"
|
|
|
|
#include <cfloat>
|
|
|
|
#include <climits>
|
|
|
|
#include <cstdint>
|
2019-03-01 11:00:30 +00:00
|
|
|
#include <fstream>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include "strings.hpp"
|
2019-01-14 10:23:21 +00:00
|
|
|
|
2019-08-07 10:42:25 +00:00
|
|
|
#define ST "Shader"
|
|
|
|
#define ST_FILE "Shader.File"
|
2018-03-20 11:45:41 +00:00
|
|
|
|
2019-08-07 10:42:25 +00:00
|
|
|
gfx::effect_source::parameter::parameter(std::shared_ptr<gs::effect> effect, std::string name)
|
|
|
|
: effect(effect), name(name), description(""), formulae(""), visible(true)
|
2018-09-28 09:55:55 +00:00
|
|
|
{
|
2019-08-07 10:42:25 +00:00
|
|
|
if (!effect)
|
|
|
|
throw std::invalid_argument("effect");
|
|
|
|
if (!effect->has_parameter(name))
|
|
|
|
throw std::invalid_argument("name");
|
|
|
|
param = effect->get_parameter(name);
|
2018-03-20 11:45:41 +00:00
|
|
|
|
2019-08-07 10:42:25 +00:00
|
|
|
if (param->has_annotation("description", gs::effect_parameter::type::String)) {
|
|
|
|
param->get_annotation("description")->get_default_string(description);
|
2018-04-09 11:27:22 +00:00
|
|
|
}
|
2019-08-07 10:42:25 +00:00
|
|
|
if (param->has_annotation("formulae", gs::effect_parameter::type::String)) {
|
|
|
|
param->get_annotation("formulae")->get_default_string(formulae);
|
|
|
|
}
|
|
|
|
if (param->has_annotation("visible", gs::effect_parameter::type::Boolean)) {
|
|
|
|
param->get_annotation("visible")->get_default_bool(visible);
|
|
|
|
} else {
|
|
|
|
visible = true;
|
2018-09-28 09:55:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 10:42:25 +00:00
|
|
|
gfx::effect_source::bool_parameter::bool_parameter(std::shared_ptr<gs::effect> effect, std::string name)
|
|
|
|
: parameter(effect, name)
|
2018-09-28 09:55:55 +00:00
|
|
|
{
|
2019-08-07 10:42:25 +00:00
|
|
|
if (param->get_type() != gs::effect_parameter::type::Boolean)
|
|
|
|
throw std::bad_cast();
|
2018-04-29 01:04:29 +00:00
|
|
|
|
2019-08-07 10:42:25 +00:00
|
|
|
param->get_default_bool(value);
|
2018-03-20 11:45:41 +00:00
|
|
|
}
|
|
|
|
|
2019-08-07 10:42:25 +00:00
|
|
|
gfx::effect_source::value_parameter::value_parameter(std::shared_ptr<gs::effect> effect, std::string name)
|
|
|
|
: parameter(effect, name)
|
2018-09-28 09:55:55 +00:00
|
|
|
{
|
2019-08-07 10:42:25 +00:00
|
|
|
std::shared_ptr<gs::effect_parameter> min = param->get_annotation("minimum");
|
|
|
|
std::shared_ptr<gs::effect_parameter> max = param->get_annotation("maximum");
|
2018-03-20 11:45:41 +00:00
|
|
|
|
2019-08-07 10:42:25 +00:00
|
|
|
switch (param->get_type()) {
|
|
|
|
case gs::effect_parameter::type::Float:
|
|
|
|
param->get_default_float(value.f[0]);
|
|
|
|
if (min)
|
|
|
|
min->get_default_float(minimum.f[0]);
|
|
|
|
if (max)
|
|
|
|
max->get_default_float(maximum.f[0]);
|
|
|
|
break;
|
|
|
|
case gs::effect_parameter::type::Float2:
|
|
|
|
param->get_default_float2(value.f[0], value.f[1]);
|
|
|
|
if (min)
|
|
|
|
min->get_default_float2(minimum.f[0], minimum.f[1]);
|
|
|
|
if (max)
|
|
|
|
max->get_default_float2(maximum.f[0], maximum.f[1]);
|
|
|
|
break;
|
|
|
|
case gs::effect_parameter::type::Float3:
|
|
|
|
param->get_default_float3(value.f[0], value.f[1], value.f[2]);
|
|
|
|
if (min)
|
|
|
|
min->get_default_float3(minimum.f[0], minimum.f[1], minimum.f[2]);
|
|
|
|
if (max)
|
|
|
|
max->get_default_float3(maximum.f[0], maximum.f[1], maximum.f[2]);
|
|
|
|
break;
|
|
|
|
case gs::effect_parameter::type::Float4:
|
|
|
|
param->get_default_float4(value.f[0], value.f[1], value.f[2], value.f[3]);
|
|
|
|
if (min)
|
|
|
|
min->get_default_float4(minimum.f[0], minimum.f[1], minimum.f[2], minimum.f[3]);
|
|
|
|
if (max)
|
|
|
|
max->get_default_float4(maximum.f[0], maximum.f[1], maximum.f[2], maximum.f[3]);
|
|
|
|
break;
|
|
|
|
case gs::effect_parameter::type::Integer:
|
|
|
|
param->get_default_int(value.i[0]);
|
|
|
|
if (min)
|
|
|
|
min->get_default_int(minimum.i[0]);
|
|
|
|
if (max)
|
|
|
|
max->get_default_int(maximum.i[0]);
|
|
|
|
break;
|
|
|
|
case gs::effect_parameter::type::Integer2:
|
|
|
|
param->get_default_int2(value.i[0], value.i[1]);
|
|
|
|
if (min)
|
|
|
|
min->get_default_int2(minimum.i[0], minimum.i[1]);
|
|
|
|
if (max)
|
|
|
|
max->get_default_int2(maximum.i[0], maximum.i[1]);
|
|
|
|
break;
|
|
|
|
case gs::effect_parameter::type::Integer3:
|
|
|
|
param->get_default_int3(value.i[0], value.i[1], value.i[2]);
|
|
|
|
if (min)
|
|
|
|
min->get_default_int3(minimum.i[0], minimum.i[1], minimum.i[2]);
|
|
|
|
if (max)
|
|
|
|
max->get_default_int3(maximum.i[0], maximum.i[1], maximum.i[2]);
|
|
|
|
break;
|
|
|
|
case gs::effect_parameter::type::Integer4:
|
|
|
|
param->get_default_int4(value.i[0], value.i[1], value.i[2], value.i[3]);
|
|
|
|
if (min)
|
|
|
|
min->get_default_int4(minimum.i[0], minimum.i[1], minimum.i[2], minimum.i[3]);
|
|
|
|
if (max)
|
|
|
|
max->get_default_int4(maximum.i[0], maximum.i[1], maximum.i[2], maximum.i[3]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw std::bad_cast();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx::effect_source::matrix_parameter::matrix_parameter(std::shared_ptr<gs::effect> effect, std::string name)
|
|
|
|
: parameter(effect, name)
|
|
|
|
{
|
|
|
|
std::shared_ptr<gs::effect_parameter> min = param->get_annotation("minimum");
|
|
|
|
std::shared_ptr<gs::effect_parameter> max = param->get_annotation("maximum");
|
|
|
|
|
|
|
|
param->get_default_matrix(value);
|
|
|
|
if (min)
|
|
|
|
min->get_default_matrix(minimum);
|
|
|
|
if (max)
|
|
|
|
max->get_default_matrix(maximum);
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx::effect_source::string_parameter::string_parameter(std::shared_ptr<gs::effect> effect, std::string name)
|
|
|
|
: parameter(effect, name)
|
|
|
|
{
|
|
|
|
param->get_default_string(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx::effect_source::texture_parameter::texture_parameter(std::shared_ptr<gs::effect> effect, std::string name)
|
|
|
|
: parameter(effect, name)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void gfx::effect_source::shader_instance::load_file(std::string file)
|
|
|
|
{
|
|
|
|
_params.clear();
|
|
|
|
_effect.reset();
|
|
|
|
_file = file;
|
|
|
|
|
|
|
|
struct stat st;
|
|
|
|
if (!os_stat(_file.c_str(), &st)) {
|
|
|
|
_last_size = 0;
|
|
|
|
_last_modify_time = 0;
|
|
|
|
_last_create_time = 0;
|
|
|
|
throw std::system_error(std::error_code(ENOENT, std::system_category()), file.c_str());
|
|
|
|
} else {
|
|
|
|
_last_size = st.st_size;
|
|
|
|
_last_modify_time = st.st_mtime;
|
|
|
|
_last_create_time = st.st_ctime;
|
|
|
|
}
|
|
|
|
|
|
|
|
_effect = gs::effect::create(file);
|
|
|
|
auto prms = _effect->get_parameters();
|
|
|
|
for (auto prm : prms) {
|
|
|
|
param_ident_t identity;
|
|
|
|
identity.first = prm->get_type();
|
|
|
|
identity.second = prm->get_name();
|
|
|
|
std::shared_ptr<parameter> parameter;
|
|
|
|
|
|
|
|
switch (prm->get_type()) {
|
|
|
|
case gs::effect_parameter::type::Boolean:
|
|
|
|
parameter = std::make_shared<bool_parameter>(_effect, prm->get_name());
|
|
|
|
break;
|
|
|
|
case gs::effect_parameter::type::Float:
|
|
|
|
case gs::effect_parameter::type::Float2:
|
|
|
|
case gs::effect_parameter::type::Float3:
|
|
|
|
case gs::effect_parameter::type::Float4:
|
|
|
|
case gs::effect_parameter::type::Integer:
|
|
|
|
case gs::effect_parameter::type::Integer2:
|
|
|
|
case gs::effect_parameter::type::Integer3:
|
|
|
|
case gs::effect_parameter::type::Integer4:
|
|
|
|
parameter = std::make_shared<value_parameter>(_effect, prm->get_name());
|
|
|
|
break;
|
|
|
|
case gs::effect_parameter::type::Matrix:
|
|
|
|
parameter = std::make_shared<matrix_parameter>(_effect, prm->get_name());
|
|
|
|
break;
|
|
|
|
case gs::effect_parameter::type::String:
|
|
|
|
parameter = std::make_shared<string_parameter>(_effect, prm->get_name());
|
|
|
|
break;
|
|
|
|
case gs::effect_parameter::type::Texture:
|
|
|
|
parameter = std::make_shared<texture_parameter>(_effect, prm->get_name());
|
|
|
|
break;
|
2018-04-09 11:27:22 +00:00
|
|
|
}
|
2019-08-07 10:42:25 +00:00
|
|
|
|
|
|
|
_params.emplace(identity, parameter);
|
2018-04-09 11:27:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 10:42:25 +00:00
|
|
|
gfx::effect_source::shader_instance::shader_instance(std::string file)
|
|
|
|
: _last_check(0), _last_size(0), _last_modify_time(0), _last_create_time(0)
|
2018-09-28 09:55:55 +00:00
|
|
|
{
|
2019-08-07 10:42:25 +00:00
|
|
|
load_file(file);
|
2018-03-20 11:45:41 +00:00
|
|
|
}
|
|
|
|
|
2019-08-07 10:42:25 +00:00
|
|
|
gfx::effect_source::shader_instance::~shader_instance() {}
|
2018-03-20 11:45:41 +00:00
|
|
|
|
2019-08-07 10:42:25 +00:00
|
|
|
void gfx::effect_source::shader_instance::tick(float_t time)
|
2018-09-28 09:55:55 +00:00
|
|
|
{
|
2019-08-07 10:42:25 +00:00
|
|
|
_last_check += time;
|
|
|
|
if (_last_check >= 0.5f) {
|
|
|
|
_last_check -= 0.5f;
|
|
|
|
bool changed = false;
|
2018-03-20 11:45:41 +00:00
|
|
|
|
2019-08-07 10:42:25 +00:00
|
|
|
struct stat st;
|
|
|
|
if (os_stat(_file.c_str(), &st)) {
|
|
|
|
changed =
|
|
|
|
(_last_size != st.st_size) || (_last_modify_time != st.st_mtime) || (_last_create_time != st.st_ctime);
|
2018-03-20 11:45:41 +00:00
|
|
|
}
|
2019-08-07 10:42:25 +00:00
|
|
|
if (changed) {
|
|
|
|
load_file(_file);
|
2018-03-20 11:45:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 10:42:25 +00:00
|
|
|
void gfx::effect_source::shader_instance::render(std::string technique)
|
2018-09-28 09:55:55 +00:00
|
|
|
{
|
2019-08-07 10:42:25 +00:00
|
|
|
gs_blend_state_push();
|
|
|
|
gs_matrix_push();
|
2018-04-29 01:04:29 +00:00
|
|
|
|
|
|
|
gs_reset_blend_state();
|
2019-08-07 10:42:25 +00:00
|
|
|
gs_enable_blending(false);
|
|
|
|
gs_enable_color(true, true, true, true);
|
2018-04-29 01:04:29 +00:00
|
|
|
gs_enable_depth_test(false);
|
2019-08-07 10:42:25 +00:00
|
|
|
gs_enable_stencil_test(false);
|
|
|
|
gs_enable_stencil_write(false);
|
|
|
|
gs_ortho(0, 1, 0, 1, -1., 1.);
|
|
|
|
|
|
|
|
while (gs_effect_loop(_effect->get_object(), technique.c_str())) {
|
2018-04-29 01:04:29 +00:00
|
|
|
}
|
|
|
|
|
2019-08-07 10:42:25 +00:00
|
|
|
gs_matrix_pop();
|
|
|
|
gs_blend_state_pop();
|
2018-03-20 11:45:41 +00:00
|
|
|
}
|