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

371 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. #include "renderer/material.hpp"
  20. #include "resource-loader.hpp"
  21. #include "resource-manager.hpp"
  22. #include "gl/shader-variable-type.hpp"
  23. #include "gl/texture-wrapping.hpp"
  24. #include "gl/texture-filter.hpp"
  25. #include "gl/texture-2d.hpp"
  26. #include "utility/fundamental-types.hpp"
  27. #include "string-table.hpp"
  28. #include <cctype>
  29. #include <vector>
  30. #include <map>
  31. static bool load_bool_property(material* material, const string_table_row& row, int vector_size, int array_size)
  32. {
  33. if (row.size() - 4 != vector_size * array_size || vector_size < 1 || vector_size > 4)
  34. {
  35. return false;
  36. }
  37. std::size_t size = array_size * vector_size;
  38. bool* values = new bool[size];
  39. for (std::size_t i = 0; i < size; ++i)
  40. {
  41. values[i] = (std::stoi(row[4 + i]) != 0);
  42. }
  43. if (vector_size == 1)
  44. {
  45. material_property<bool>* property = material->add_property<bool>(row[1], array_size);
  46. property->set_values(0, values, array_size);
  47. }
  48. else if (vector_size == 2)
  49. {
  50. material_property<bool2>* property = material->add_property<bool2>(row[1], array_size);
  51. property->set_values(0, reinterpret_cast<const bool2*>(values), array_size);
  52. }
  53. else if (vector_size == 3)
  54. {
  55. material_property<bool3>* property = material->add_property<bool3>(row[1], array_size);
  56. property->set_values(0, reinterpret_cast<const bool3*>(values), array_size);
  57. }
  58. else if (vector_size == 4)
  59. {
  60. material_property<bool4>* property = material->add_property<bool4>(row[1], array_size);
  61. property->set_values(0, reinterpret_cast<const bool4*>(values), array_size);
  62. }
  63. delete[] values;
  64. return true;
  65. }
  66. static bool load_int_property(material* material, const string_table_row& row, int vector_size, int array_size)
  67. {
  68. if (row.size() - 4 != vector_size * array_size || vector_size < 1 || vector_size > 4)
  69. {
  70. return false;
  71. }
  72. std::size_t size = array_size * vector_size;
  73. int* values = new int[size];
  74. for (std::size_t i = 0; i < size; ++i)
  75. {
  76. values[i] = std::stoi(row[4 + i]);
  77. }
  78. if (vector_size == 1)
  79. {
  80. material_property<int>* property = material->add_property<int>(row[1], array_size);
  81. property->set_values(0, values, array_size);
  82. }
  83. else if (vector_size == 2)
  84. {
  85. material_property<int2>* property = material->add_property<int2>(row[1], array_size);
  86. property->set_values(0, reinterpret_cast<const int2*>(values), array_size);
  87. }
  88. else if (vector_size == 3)
  89. {
  90. material_property<int3>* property = material->add_property<int3>(row[1], array_size);
  91. property->set_values(0, reinterpret_cast<const int3*>(values), array_size);
  92. }
  93. else if (vector_size == 4)
  94. {
  95. material_property<int4>* property = material->add_property<int4>(row[1], array_size);
  96. property->set_values(0, reinterpret_cast<const int4*>(values), array_size);
  97. }
  98. delete[] values;
  99. return true;
  100. }
  101. static bool load_uint_property(material* material, const string_table_row& row, int vector_size, int array_size)
  102. {
  103. if (row.size() - 4 != vector_size * array_size || vector_size < 1 || vector_size > 4)
  104. {
  105. return false;
  106. }
  107. std::size_t size = array_size * vector_size;
  108. unsigned int* values = new unsigned int[size];
  109. for (std::size_t i = 0; i < size; ++i)
  110. {
  111. values[i] = static_cast<unsigned int>(std::stoul(row[4 + i]));
  112. }
  113. if (vector_size == 1)
  114. {
  115. material_property<unsigned int>* property = material->add_property<unsigned int>(row[1], array_size);
  116. property->set_values(0, values, array_size);
  117. }
  118. else if (vector_size == 2)
  119. {
  120. material_property<uint2>* property = material->add_property<uint2>(row[1], array_size);
  121. property->set_values(0, reinterpret_cast<const uint2*>(values), array_size);
  122. }
  123. else if (vector_size == 3)
  124. {
  125. material_property<uint3>* property = material->add_property<uint3>(row[1], array_size);
  126. property->set_values(0, reinterpret_cast<const uint3*>(values), array_size);
  127. }
  128. else if (vector_size == 4)
  129. {
  130. material_property<uint4>* property = material->add_property<uint4>(row[1], array_size);
  131. property->set_values(0, reinterpret_cast<const uint4*>(values), array_size);
  132. }
  133. delete[] values;
  134. return true;
  135. }
  136. static bool load_float_property(material* material, const string_table_row& row, int vector_size, int array_size)
  137. {
  138. if (row.size() - 4 != vector_size * array_size || vector_size < 1 || vector_size > 4)
  139. {
  140. return false;
  141. }
  142. std::size_t size = array_size * vector_size;
  143. float* values = new float[size];
  144. for (std::size_t i = 0; i < size; ++i)
  145. {
  146. values[i] = static_cast<float>(std::stod(row[4 + i]));
  147. }
  148. if (vector_size == 1)
  149. {
  150. material_property<float>* property = material->add_property<float>(row[1], array_size);
  151. property->set_values(0, values, array_size);
  152. }
  153. else if (vector_size == 2)
  154. {
  155. material_property<float2>* property = material->add_property<float2>(row[1], array_size);
  156. property->set_values(0, reinterpret_cast<const float2*>(values), array_size);
  157. }
  158. else if (vector_size == 3)
  159. {
  160. material_property<float3>* property = material->add_property<float3>(row[1], array_size);
  161. property->set_values(0, reinterpret_cast<const float3*>(values), array_size);
  162. }
  163. else if (vector_size == 4)
  164. {
  165. material_property<float4>* property = material->add_property<float4>(row[1], array_size);
  166. property->set_values(0, reinterpret_cast<const float4*>(values), array_size);
  167. }
  168. delete[] values;
  169. return true;
  170. }
  171. static bool load_float_matrix_property(material* material, const string_table_row& row, int matrix_columns, int matrix_rows, int array_size)
  172. {
  173. int matrix_size = matrix_columns * matrix_rows;
  174. if (row.size() - 4 != matrix_size * array_size)
  175. {
  176. return false;
  177. }
  178. std::size_t size = array_size * matrix_size;
  179. float* values = new float[size];
  180. for (std::size_t i = 0; i < size; ++i)
  181. {
  182. values[i] = static_cast<float>(std::stod(row[4 + i]));
  183. }
  184. if (matrix_size == 2*2)
  185. {
  186. material_property<float2x2>* property = material->add_property<float2x2>(row[1], array_size);
  187. property->set_values(0, reinterpret_cast<const float2x2*>(values), array_size);
  188. }
  189. else if (matrix_size == 3*3)
  190. {
  191. material_property<float3x3>* property = material->add_property<float3x3>(row[1], array_size);
  192. property->set_values(0, reinterpret_cast<const float3x3*>(values), array_size);
  193. }
  194. else if (matrix_size == 4*4)
  195. {
  196. material_property<float4x4>* property = material->add_property<float4x4>(row[1], array_size);
  197. property->set_values(0, reinterpret_cast<const float4x4*>(values), array_size);
  198. }
  199. delete[] values;
  200. return true;
  201. }
  202. static bool load_texture_2d_property(material* material, const string_table_row& row, resource_manager* resource_manager, int array_size)
  203. {
  204. if (row.size() - 4 != array_size * 1)
  205. {
  206. return false;
  207. }
  208. const gl::texture_2d** values = new const gl::texture_2d*[array_size];
  209. for (std::size_t i = 0; i < array_size; ++i)
  210. {
  211. values[i] = resource_manager->load<gl::texture_2d>(row[4 + i]);
  212. }
  213. material_property<const gl::texture_2d*>* property = material->add_property<const gl::texture_2d*>(row[1], array_size);
  214. property->set_values(0, values, array_size);
  215. delete[] values;
  216. return true;
  217. }
  218. static bool load_texture_cube_property(material* material, const string_table_row& row, resource_manager* resource_manager, int array_size)
  219. {
  220. return false;
  221. }
  222. static bool load_material_property(material* material, const string_table_row& row, resource_manager* resource_manager)
  223. {
  224. // Ensure row has at least five columns
  225. if (row.size() < 5)
  226. {
  227. return false;
  228. }
  229. const std::string& name = row[1];
  230. if (name.empty())
  231. {
  232. return false;
  233. }
  234. const std::string& type = row[2];
  235. if (type.empty())
  236. {
  237. return false;
  238. }
  239. int vector_size = 1;
  240. if (std::isdigit(type.back()))
  241. {
  242. vector_size = std::stoi(type.substr(type.size() - 1, 1));
  243. }
  244. int matrix_columns = 0;
  245. int matrix_rows = 0;
  246. if (type[type.size() - 2] == 'x' && std::isdigit(type[type.size() - 3]) && std::isdigit(type.back()))
  247. {
  248. matrix_columns = std::stoi(type.substr(type.size() - 3, 1));
  249. matrix_rows = std::stoi(type.substr(type.size() - 1, 1));
  250. }
  251. int array_size = std::stoi(row[3]);
  252. if (array_size <= 0)
  253. {
  254. return false;
  255. }
  256. if (type == "bool" || type == "bool2" || type == "bool3" || type == "bool4")
  257. {
  258. return load_bool_property(material, row, vector_size, array_size);
  259. }
  260. else if (type == "int" || type == "int2" || type == "int3" || type == "int4")
  261. {
  262. return load_int_property(material, row, vector_size, array_size);
  263. }
  264. else if (type == "uint" || type == "uint2" || type == "uint3" || type == "uint4")
  265. {
  266. return load_uint_property(material, row, vector_size, array_size);
  267. }
  268. else if (type == "float" || type == "float2" || type == "float3" || type == "float4")
  269. {
  270. return load_float_property(material, row, vector_size, array_size);
  271. }
  272. else if (type == "float2x2" || type == "float3x3" || type == "float4x4")
  273. {
  274. return load_float_matrix_property(material, row, matrix_columns, matrix_rows, array_size);
  275. }
  276. else if (type == "texture_2d")
  277. {
  278. return load_texture_2d_property(material, row, resource_manager, array_size);
  279. }
  280. else if (type == "texture_cube")
  281. {
  282. return load_texture_cube_property(material, row, resource_manager, array_size);
  283. }
  284. return false;
  285. }
  286. template <>
  287. material* resource_loader<material>::load(resource_manager* resource_manager, PHYSFS_File* file)
  288. {
  289. // Load string table from input stream
  290. string_table* table = resource_loader<string_table>::load(resource_manager, file);
  291. // Ensure table is not empty.
  292. if (!table || table->empty())
  293. {
  294. delete table;
  295. return nullptr;
  296. }
  297. // Allocate material
  298. ::material* material = new ::material();
  299. // Parse table rows
  300. for (const string_table_row& row: *table)
  301. {
  302. // Skip empty rows and comments
  303. if (row.empty() || row[0].empty() || row[0][0] == '#')
  304. {
  305. continue;
  306. }
  307. if (row[0] == "shader" && row.size() == 2)
  308. {
  309. gl::shader_program* program = resource_manager->load<gl::shader_program>(row[1]);
  310. material->set_shader_program(program);
  311. }
  312. else if (row[0] == "flags" && row.size() == 2)
  313. {
  314. std::uint32_t flags = std::stoi(row[1]);
  315. material->set_flags(flags);
  316. }
  317. else if (row[0] == "property")
  318. {
  319. load_material_property(material, row, resource_manager);
  320. }
  321. }
  322. return material;
  323. }