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

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