💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

443 lines
11 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_MATERIAL_PROPERTY_HPP
  20. #define ANTKEEPER_MATERIAL_PROPERTY_HPP
  21. #include "animation/tween.hpp"
  22. #include "gl/shader-variable-type.hpp"
  23. #include "gl/shader-input.hpp"
  24. #include "math/interpolation.hpp"
  25. #include "utility/fundamental-types.hpp"
  26. #include "gl/shader-program.hpp"
  27. #include "gl/texture-2d.hpp"
  28. #include "gl/texture-cube.hpp"
  29. #include <cstddef>
  30. class material;
  31. /**
  32. * Abstract base class for material properties.
  33. */
  34. class material_property_base
  35. {
  36. public:
  37. /**
  38. * Connects the material property to a shader input.
  39. *
  40. * @param input Shader input to which the material property should be connected.
  41. * @return `true` if the property was connected to the input successfully, `false` otherwise.
  42. */
  43. bool connect(const gl::shader_input* input);
  44. /**
  45. * Disconnects the material property from its shader input.
  46. */
  47. void disconnect();
  48. /**
  49. * Sets state 0 = state 1.
  50. */
  51. virtual void update_tweens() = 0;
  52. /**
  53. * Uploads the material property to its shader program.
  54. *
  55. * @param a Interpolation factor. Should be on `[0.0, 1.0]`.
  56. * @return `true` if the property was uploaded successfully, `false` otherwise.
  57. */
  58. virtual bool upload(double a) const = 0;
  59. /**
  60. * Returns the type of data which the property contains.
  61. */
  62. virtual gl::shader_variable_type get_data_type() const = 0;
  63. /**
  64. * Returns `true` if the material property is connected to a shader input, `false` otherwise.
  65. */
  66. bool is_connected() const;
  67. /**
  68. * Creates a copy of this material property.
  69. */
  70. virtual material_property_base* clone() const = 0;
  71. protected:
  72. material_property_base();
  73. const gl::shader_input* input;
  74. };
  75. inline bool material_property_base::is_connected() const
  76. {
  77. return (input != nullptr);
  78. }
  79. /**
  80. * A property of a material which can be uploaded to a shader program via a shader input.
  81. *
  82. * @tparam T Property data type.
  83. */
  84. template <class T>
  85. class material_property: public material_property_base
  86. {
  87. public:
  88. typedef tween<T> tween_type;
  89. typedef typename tween<T>::interpolator_type interpolator_type;
  90. /// Default tween interpolator function for this material property type.
  91. static T default_interpolator(const T& x, const T& y, double a);
  92. /**
  93. * Creates a material property.
  94. *
  95. * @param element_count Number of elements in the property array.
  96. */
  97. material_property(std::size_t element_count);
  98. /**
  99. * Destroys a material property.
  100. */
  101. virtual ~material_property();
  102. material_property(const material_property<T>&) = delete;
  103. material_property<T>& operator=(const material_property<T>&) = delete;
  104. /// @copydoc material_property_base::update_tweens()
  105. virtual void update_tweens();
  106. /// @copydoc material_property_base::upload() const
  107. virtual bool upload(double a) const;
  108. /**
  109. * Sets the value of this property.
  110. *
  111. * @param value Value to set.
  112. */
  113. void set_value(const T& value);
  114. /**
  115. * Sets the value of a single element in this array property.
  116. *
  117. * @param index Index of an array element.
  118. * @param value Value to set.
  119. */
  120. void set_value(std::size_t index, const T& value);
  121. /**
  122. * Sets the values of a range of elements in this array property.
  123. *
  124. * @param index Index of the first array element to set.
  125. * @param values Pointer to an array of values to set.
  126. * @param count Number of elements to set.
  127. */
  128. void set_values(std::size_t index, const T* values, std::size_t count);
  129. /**
  130. * Sets the tween interpolator function.
  131. *
  132. * @param interpolator Tween interpolator function.
  133. */
  134. void set_tween_interpolator(interpolator_type interpolator);
  135. /// Returns the value of the first element in this property.
  136. const T& get_value() const;
  137. /**
  138. * Returns the value of the first element in this property.
  139. *
  140. * @param index Index of an array element.
  141. * @return Value of the element at the specified index.
  142. */
  143. const T& get_value(std::size_t index) const;
  144. /// @copydoc material_property_base::get_data_type() const
  145. virtual gl::shader_variable_type get_data_type() const;
  146. /// @copydoc material_property_base::clone() const
  147. virtual material_property_base* clone() const;
  148. private:
  149. std::size_t element_count;
  150. tween<T>* values;
  151. };
  152. template <typename T>
  153. inline T material_property<T>::default_interpolator(const T& x, const T& y, double a)
  154. {
  155. return y;
  156. }
  157. template <>
  158. inline float material_property<float>::default_interpolator(const float& x, const float& y, double a)
  159. {
  160. return math::lerp<float, float>(x, y, static_cast<float>(a));
  161. }
  162. template <>
  163. inline float2 material_property<float2>::default_interpolator(const float2& x, const float2& y, double a)
  164. {
  165. return math::lerp<float2, float>(x, y, static_cast<float>(a));
  166. }
  167. template <>
  168. inline float3 material_property<float3>::default_interpolator(const float3& x, const float3& y, double a)
  169. {
  170. return math::lerp<float3, float>(x, y, static_cast<float>(a));
  171. }
  172. template <>
  173. inline float4 material_property<float4>::default_interpolator(const float4& x, const float4& y, double a)
  174. {
  175. return math::lerp<float4, float>(x, y, static_cast<float>(a));
  176. }
  177. template <class T>
  178. material_property<T>::material_property(std::size_t element_count):
  179. element_count(element_count),
  180. values(nullptr)
  181. {
  182. values = new tween<T>[element_count];
  183. set_tween_interpolator(default_interpolator);
  184. }
  185. template <class T>
  186. material_property<T>::~material_property()
  187. {
  188. delete[] values;
  189. }
  190. template <class T>
  191. void material_property<T>::update_tweens()
  192. {
  193. for (std::size_t i = 0; i < element_count; ++i)
  194. {
  195. values[i].update();
  196. }
  197. }
  198. template <class T>
  199. bool material_property<T>::upload(double a) const
  200. {
  201. if (!is_connected())
  202. {
  203. return false;
  204. }
  205. if (element_count > 1)
  206. {
  207. for (std::size_t i = 0; i < element_count; ++i)
  208. {
  209. if (!input->upload(i, values[i].interpolate(a)))
  210. return false;
  211. }
  212. return true;
  213. }
  214. else
  215. {
  216. return input->upload(values[0].interpolate(a));
  217. }
  218. }
  219. template <class T>
  220. void material_property<T>::set_value(const T& value)
  221. {
  222. values[0][1] = value;
  223. }
  224. template <class T>
  225. void material_property<T>::set_value(std::size_t index, const T& value)
  226. {
  227. values[index][1] = value;
  228. }
  229. template <class T>
  230. void material_property<T>::set_values(std::size_t index, const T* values, std::size_t count)
  231. {
  232. for (std::size_t i = 0; i < count; ++i)
  233. {
  234. this->values[index + i][1] = values[i];
  235. }
  236. }
  237. template <class T>
  238. void material_property<T>::set_tween_interpolator(interpolator_type interpolator)
  239. {
  240. for (std::size_t i = 0; i < element_count; ++i)
  241. {
  242. this->values[i].set_interpolator(interpolator);
  243. }
  244. }
  245. template <class T>
  246. inline const T& material_property<T>::get_value() const
  247. {
  248. return values[0][1];
  249. }
  250. template <class T>
  251. inline const T& material_property<T>::get_value(std::size_t index) const
  252. {
  253. return values[index][1];
  254. }
  255. template <>
  256. inline gl::shader_variable_type material_property<bool>::get_data_type() const
  257. {
  258. return gl::shader_variable_type::bool1;
  259. }
  260. template <>
  261. inline gl::shader_variable_type material_property<bool2>::get_data_type() const
  262. {
  263. return gl::shader_variable_type::bool2;
  264. }
  265. template <>
  266. inline gl::shader_variable_type material_property<bool3>::get_data_type() const
  267. {
  268. return gl::shader_variable_type::bool3;
  269. }
  270. template <>
  271. inline gl::shader_variable_type material_property<bool4>::get_data_type() const
  272. {
  273. return gl::shader_variable_type::bool4;
  274. }
  275. template <>
  276. inline gl::shader_variable_type material_property<int>::get_data_type() const
  277. {
  278. return gl::shader_variable_type::int1;
  279. }
  280. template <>
  281. inline gl::shader_variable_type material_property<int2>::get_data_type() const
  282. {
  283. return gl::shader_variable_type::int2;
  284. }
  285. template <>
  286. inline gl::shader_variable_type material_property<int3>::get_data_type() const
  287. {
  288. return gl::shader_variable_type::int3;
  289. }
  290. template <>
  291. inline gl::shader_variable_type material_property<int4>::get_data_type() const
  292. {
  293. return gl::shader_variable_type::int4;
  294. }
  295. template <>
  296. inline gl::shader_variable_type material_property<unsigned int>::get_data_type() const
  297. {
  298. return gl::shader_variable_type::uint1;
  299. }
  300. template <>
  301. inline gl::shader_variable_type material_property<uint2>::get_data_type() const
  302. {
  303. return gl::shader_variable_type::uint2;
  304. }
  305. template <>
  306. inline gl::shader_variable_type material_property<uint3>::get_data_type() const
  307. {
  308. return gl::shader_variable_type::uint3;
  309. }
  310. template <>
  311. inline gl::shader_variable_type material_property<uint4>::get_data_type() const
  312. {
  313. return gl::shader_variable_type::uint4;
  314. }
  315. template <>
  316. inline gl::shader_variable_type material_property<float>::get_data_type() const
  317. {
  318. return gl::shader_variable_type::float1;
  319. }
  320. template <>
  321. inline gl::shader_variable_type material_property<float2>::get_data_type() const
  322. {
  323. return gl::shader_variable_type::float2;
  324. }
  325. template <>
  326. inline gl::shader_variable_type material_property<float3>::get_data_type() const
  327. {
  328. return gl::shader_variable_type::float3;
  329. }
  330. template <>
  331. inline gl::shader_variable_type material_property<float4>::get_data_type() const
  332. {
  333. return gl::shader_variable_type::float4;
  334. }
  335. template <>
  336. inline gl::shader_variable_type material_property<float2x2>::get_data_type() const
  337. {
  338. return gl::shader_variable_type::float2x2;
  339. }
  340. template <>
  341. inline gl::shader_variable_type material_property<float3x3>::get_data_type() const
  342. {
  343. return gl::shader_variable_type::float3x3;
  344. }
  345. template <>
  346. inline gl::shader_variable_type material_property<float4x4>::get_data_type() const
  347. {
  348. return gl::shader_variable_type::float4x4;
  349. }
  350. template <>
  351. inline gl::shader_variable_type material_property<const gl::texture_2d*>::get_data_type() const
  352. {
  353. return gl::shader_variable_type::texture_2d;
  354. }
  355. template <>
  356. inline gl::shader_variable_type material_property<const gl::texture_cube*>::get_data_type() const
  357. {
  358. return gl::shader_variable_type::texture_cube;
  359. }
  360. template <class T>
  361. material_property_base* material_property<T>::clone() const
  362. {
  363. material_property<T>* property = new material_property<T>(element_count);
  364. for (std::size_t i = 0; i < element_count; ++i)
  365. {
  366. property->values[i][0] = values[i][0];
  367. property->values[i][1] = values[i][1];
  368. }
  369. property->input = input;
  370. return property;
  371. }
  372. #endif // ANTKEEPER_MATERIAL_PROPERTY_HPP