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

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