💿🐜 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.

446 lines
10 KiB

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