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

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