/* * Copyright (C) 2020 Christopher J. Howard * * This file is part of Antkeeper source code. * * Antkeeper source code 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 3 of the License, or * (at your option) any later version. * * Antkeeper source code 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 Antkeeper source code. If not, see . */ #ifndef ANTKEEPER_MATERIAL_PROPERTY_HPP #define ANTKEEPER_MATERIAL_PROPERTY_HPP #include "animation/tween.hpp" #include "rasterizer/shader-variable-type.hpp" #include "rasterizer/shader-input.hpp" #include #include using namespace vmq::types; class material; class shader_program; class texture_2d; class texture_cube; /** * Abstract base class for material properties. */ class material_property_base { public: /** * Connects the material property to a shader input. * * @param input Shader input to which the material property should be connected. * @return `true` if the property was connected to the input successfully, `false` otherwise. */ bool connect(const shader_input* input); /** * Disconnects the material property from its shader input. */ void disconnect(); /** * Sets state 0 = state 1. */ virtual void update_tweens() = 0; /** * Uploads the material property to its shader program. * * @param a Interpolation factor. Should be on `[0.0, 1.0]`. * @return `true` if the property was uploaded successfully, `false` otherwise. */ virtual bool upload(double a) const = 0; /** * Returns the type of data which the property contains. */ virtual shader_variable_type get_data_type() const = 0; /** * Returns `true` if the material property is connected to a shader input, `false` otherwise. */ bool is_connected() const; /** * Creates a copy of this material property. */ virtual material_property_base* clone() const = 0; protected: material_property_base(); const shader_input* input; }; inline bool material_property_base::is_connected() const { return (input != nullptr); } /** * A property of a material which can be uploaded to a shader program via a shader input. * * @tparam T Property data type. */ template class material_property: public material_property_base { public: /** * Creates a material property. * * @param element_count Number of elements in the property array. */ material_property(std::size_t element_count); /** * Destroys a material property. */ virtual ~material_property(); material_property(const material_property&) = delete; material_property& operator=(const material_property&) = delete; /// @copydoc material_property_base::update_tweens() virtual void update_tweens(); /// @copydoc material_property_base::upload() const virtual bool upload(double a) const; /** * Sets the value of this property. * * @param value Value to set. */ void set_value(const T& value); void set_val(const T& value); /** * Sets the value of a single element in this array property. * * @param index Index of an array element. * @param value Value to set. */ void set_value(std::size_t index, const T& value); /** * Sets the values of a range of elements in this array property. * * @param index Index of the first array element to set. * @param values Pointer to an array of values to set. * @param count Number of elements to set. */ void set_values(std::size_t index, const T* values, std::size_t count); /// @copydoc material_property_base::get_data_type() const virtual shader_variable_type get_data_type() const; /// @copydoc material_property_base::clone() const virtual material_property_base* clone() const; private: std::size_t element_count; tween* values; }; template material_property::material_property(std::size_t element_count): element_count(element_count), values(nullptr) { values = new tween[element_count]; } template material_property::~material_property() { delete[] values; } template void material_property::update_tweens() { for (std::size_t i = 0; i < element_count; ++i) { values[i].update(); } } template bool material_property::upload(double a) const { if (!is_connected()) { return false; } if (element_count > 1) { for (std::size_t i = 0; i < element_count; ++i) { if (!input->upload(i, values[i].interpolate(a))) return false; } return true; } else { return input->upload(values[0].interpolate(a)); } } template void material_property::set_value(const T& value) { values[0][1] = value; } template void material_property::set_val(const T& value) { values[0][1] = value; } template void material_property::set_value(std::size_t index, const T& value) { values[index][1] = value; } template void material_property::set_values(std::size_t index, const T* values, std::size_t count) { for (std::size_t i = 0; i < count; ++i) { this->values[index + i][1] = values[i]; } } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::bool1; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::bool2; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::bool3; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::bool4; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::int1; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::int2; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::int3; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::int4; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::uint1; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::uint2; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::uint3; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::uint4; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::float1; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::float2; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::float3; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::float4; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::float2x2; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::float3x3; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::float4x4; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::texture_2d; } template <> inline shader_variable_type material_property::get_data_type() const { return shader_variable_type::texture_cube; } template material_property_base* material_property::clone() const { material_property* property = new material_property(element_count); for (std::size_t i = 0; i < element_count; ++i) { property->values[i][0] = values[i][0]; property->values[i][1] = values[i][1]; } property->input = input; return property; } #endif // ANTKEEPER_MATERIAL_PROPERTY_HPP