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

464 lines
13 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. /*
  2. * Copyright (C) 2017-2019 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 "resource-loader.hpp"
  20. #include "resource-manager.hpp"
  21. #include <algorithm>
  22. #include <stdexcept>
  23. #include <sstream>
  24. #include <vector>
  25. #include <emergent/emergent.hpp>
  26. using namespace Emergent;
  27. static bool loadShaderInt(ShaderInt* variable, const std::vector<std::vector<std::string>>& elements)
  28. {
  29. for (int i = 0; i < elements.size(); ++i)
  30. {
  31. int value;
  32. std::stringstream stream;
  33. stream << elements[i][0];
  34. stream >> value;
  35. variable->setValue(i, value);
  36. }
  37. return true;
  38. }
  39. static bool loadShaderFloat(ShaderFloat* variable, const std::vector<std::vector<std::string>>& elements)
  40. {
  41. for (int i = 0; i < elements.size(); ++i)
  42. {
  43. float value;
  44. std::stringstream stream;
  45. stream << elements[i][0];
  46. stream >> value;
  47. variable->setValue(i, value);
  48. }
  49. return true;
  50. }
  51. static bool loadShaderVector2(ShaderVector2* variable, const std::vector<std::vector<std::string>>& elements)
  52. {
  53. for (int i = 0; i < elements.size(); ++i)
  54. {
  55. Vector2 value;
  56. for (int j = 0; j < 2; ++j)
  57. {
  58. std::stringstream stream;
  59. stream << elements[i][j];
  60. stream >> value[j];
  61. }
  62. variable->setValue(i, value);
  63. }
  64. return true;
  65. }
  66. static bool loadShaderVector3(ShaderVector3* variable, const std::vector<std::vector<std::string>>& elements)
  67. {
  68. for (int i = 0; i < elements.size(); ++i)
  69. {
  70. Vector3 value;
  71. for (int j = 0; j < 3; ++j)
  72. {
  73. std::stringstream stream;
  74. stream << elements[i][j];
  75. stream >> value[j];
  76. }
  77. variable->setValue(i, value);
  78. }
  79. return true;
  80. }
  81. static bool loadShaderVector4(ShaderVector4* variable, const std::vector<std::vector<std::string>>& elements)
  82. {
  83. for (int i = 0; i < elements.size(); ++i)
  84. {
  85. Vector4 value;
  86. for (int j = 0; j < 4; ++j)
  87. {
  88. std::stringstream stream;
  89. stream << elements[i][j];
  90. stream >> value[j];
  91. }
  92. variable->setValue(i, value);
  93. }
  94. return true;
  95. }
  96. static bool loadShaderMatrix3(ShaderMatrix3* variable, const std::vector<std::vector<std::string>>& elements)
  97. {
  98. for (int i = 0; i < elements.size(); ++i)
  99. {
  100. Matrix3 value;
  101. for (int j = 0; j < 3; ++j)
  102. {
  103. for (int k = 0; k < 3; ++k)
  104. {
  105. std::stringstream stream;
  106. stream << elements[i][k * 3 + j];
  107. stream >> value[j][k];
  108. }
  109. }
  110. variable->setValue(i, value);
  111. }
  112. return true;
  113. }
  114. static bool loadShaderMatrix4(ShaderMatrix4* variable, const std::vector<std::vector<std::string>>& elements)
  115. {
  116. for (int i = 0; i < elements.size(); ++i)
  117. {
  118. Matrix4 value;
  119. for (int j = 0; j < 4; ++j)
  120. {
  121. for (int k = 0; k < 4; ++k)
  122. {
  123. std::stringstream stream;
  124. stream << elements[i][k * 4 + j];
  125. stream >> value[j][k];
  126. }
  127. }
  128. variable->setValue(i, value);
  129. }
  130. return true;
  131. }
  132. static bool loadShaderTexture2D(ResourceManager* resourceManager, ShaderTexture2D* variable, const std::vector<std::vector<std::string>>& elements)
  133. {
  134. for (int i = 0; i < elements.size(); ++i)
  135. {
  136. std::string filename;
  137. std::stringstream stream;
  138. stream << elements[i][0];
  139. stream >> filename;
  140. Texture2D* value = resourceManager->load<Texture2D>(filename);
  141. variable->setValue(i, value);
  142. }
  143. return true;
  144. }
  145. static bool loadShaderTextureCube(ResourceManager* resourceManager, ShaderTextureCube* variable, const std::vector<std::vector<std::string>>& elements)
  146. {
  147. for (int i = 0; i < elements.size(); ++i)
  148. {
  149. std::string filename;
  150. std::stringstream stream;
  151. stream << elements[i][0];
  152. stream >> filename;
  153. TextureCube* value = resourceManager->load<TextureCube>(filename);
  154. variable->setValue(i, value);
  155. }
  156. return true;
  157. }
  158. template <>
  159. Material* ResourceLoader<Material>::load(ResourceManager* resourceManager, std::istream* is)
  160. {
  161. // Allocate new material
  162. Material* material = new Material();
  163. std::string line;
  164. std::size_t lineNumber = 0;
  165. const std::string whitespace = " \t\r\n";
  166. // Parse lines
  167. while (is->good() && std::getline(*is, line))
  168. {
  169. if (is->bad() || is->fail())
  170. {
  171. break;
  172. }
  173. // Increment current line number
  174. ++lineNumber;
  175. // Skip empty lines
  176. if (line.empty())
  177. {
  178. continue;
  179. }
  180. // Find position of first character in the command
  181. std::size_t commandPosition = line.find_first_not_of(whitespace, 0);
  182. if (commandPosition == std::string::npos)
  183. {
  184. // Skip whitespace-only lines
  185. continue;
  186. }
  187. // Determine command type
  188. std::string command = line.substr(commandPosition, line.find_first_of(" \t=", commandPosition) - commandPosition);
  189. // Parse command
  190. if (command == "shader" || command == "flags")
  191. {
  192. // Find position of equals sign
  193. std::size_t equalsSignPosition = line.find_first_of("=", commandPosition);
  194. if (equalsSignPosition == std::string::npos)
  195. {
  196. // Line has no equals sign
  197. std::stringstream stream;
  198. stream << "ResourceLoader<Material>::load(): Invalid line " << lineNumber << ".";
  199. throw std::runtime_error(stream.str().c_str());
  200. }
  201. // Find position of first character in the value string
  202. std::size_t valueStartPosition = line.find_first_not_of(whitespace, equalsSignPosition + 1);
  203. if (valueStartPosition == std::string::npos)
  204. {
  205. // Line has no value
  206. std::stringstream stream;
  207. stream << "ResourceLoader<Material>::load(): Invalid line " << lineNumber << ".";
  208. throw std::runtime_error(stream.str().c_str());
  209. }
  210. // Find position the end of the value string
  211. std::size_t valueEndPosition = line.find_first_of(" \t;\r\n", valueStartPosition);
  212. // Determine value string
  213. std::string valueString;
  214. if (valueEndPosition == std::string::npos)
  215. {
  216. valueString = line.substr(valueStartPosition);
  217. }
  218. else
  219. {
  220. valueString = line.substr(valueStartPosition, valueEndPosition - valueStartPosition);
  221. }
  222. // Execute command
  223. if (command == "shader")
  224. {
  225. // Load shader
  226. Shader* shader = nullptr;
  227. try
  228. {
  229. shader = resourceManager->load<Shader>(valueString);
  230. }
  231. catch (const std::exception& e)
  232. {
  233. std::string error = std::string("ResourceLoader<Material>::load(): Failed to load shader \"") + valueString + std::string("\": \"") + e.what() + std::string("\"");
  234. throw std::runtime_error(error.c_str());
  235. }
  236. material->setShader(shader);
  237. }
  238. else
  239. {
  240. // Parse flags
  241. std::uint64_t flags;
  242. std::stringstream stream;
  243. stream << valueString;
  244. stream >> flags;
  245. material->setFlags(flags);
  246. }
  247. }
  248. else if (command == "var")
  249. {
  250. // Find position of first character in variable name
  251. std::size_t variableNamePosition = line.find_first_not_of(whitespace, commandPosition + command.length());
  252. if (variableNamePosition == std::string::npos)
  253. {
  254. // Skip lines with no variable name
  255. std::stringstream stream;
  256. stream << "ResourceLoader<Material>::load(): Invalid variable on line " << lineNumber << ".";
  257. throw std::runtime_error(stream.str().c_str());
  258. }
  259. // Find position of equals sign
  260. std::size_t equalsSignPosition = line.find_first_of("=", variableNamePosition);
  261. if (equalsSignPosition == std::string::npos)
  262. {
  263. // Skip lines with no equals sign
  264. std::stringstream stream;
  265. stream << "ResourceLoader<Material>::load(): Invalid variable on line " << lineNumber << ".";
  266. throw std::runtime_error(stream.str().c_str());
  267. }
  268. // Find position of first character in variable type
  269. std::size_t variableTypePosition = line.find_first_not_of(whitespace, equalsSignPosition + 1);
  270. if (variableTypePosition == std::string::npos)
  271. {
  272. // Skip lines with no variable type definition
  273. std::stringstream stream;
  274. stream << "ResourceLoader<Material>::load(): Invalid variable on line " << lineNumber << ".";
  275. throw std::runtime_error(stream.str().c_str());
  276. }
  277. // Count parentheses
  278. std::size_t leftParenthesisCount = std::count(line.begin() + variableNamePosition, line.end(), '(');
  279. std::size_t rightParenthesisCount = std::count(line.begin() + variableNamePosition, line.end(), ')');
  280. if (leftParenthesisCount != rightParenthesisCount || leftParenthesisCount == 0)
  281. {
  282. // Skip lines with invalid number of parentheses
  283. std::stringstream stream;
  284. stream << "ResourceLoader<Material>::load(): Invalid variable on line " << lineNumber << ".";
  285. throw std::runtime_error(stream.str().c_str());
  286. }
  287. std::string variableName = line.substr(variableNamePosition, line.find_first_of(" \t=", variableNamePosition) - variableNamePosition);
  288. std::string variableType = line.substr(variableTypePosition, line.find_first_of(" \t[(", variableTypePosition) - variableTypePosition);
  289. std::size_t elementCount = leftParenthesisCount;
  290. std::size_t currentPosition = variableTypePosition;
  291. std::vector<std::vector<std::string>> elements;
  292. bool invalid = false;
  293. for (std::size_t i = 0; i < elementCount; ++i)
  294. {
  295. std::size_t leftParenthesisPosition = line.find_first_of("(", currentPosition);
  296. std::size_t rightParenthesisPosition = line.find_first_of(")", leftParenthesisPosition + 1);
  297. if (leftParenthesisPosition == std::string::npos || rightParenthesisPosition == std::string::npos)
  298. {
  299. invalid = true;
  300. break;
  301. }
  302. currentPosition = leftParenthesisPosition + 1;
  303. std::size_t argumentCount = std::count(line.begin() + leftParenthesisPosition + 1, line.begin() + rightParenthesisPosition, ',') + 1;
  304. std::vector<std::string> arguments;
  305. for (std::size_t j = 0; j < argumentCount; ++j)
  306. {
  307. std::size_t argumentStart = line.find_first_not_of(whitespace, currentPosition);
  308. std::size_t argumentEnd = line.find_first_of(" \t,)", argumentStart + 1);
  309. if (argumentStart == std::string::npos || argumentEnd == std::string::npos)
  310. {
  311. // Unable to parse argument
  312. invalid = true;
  313. break;
  314. }
  315. std::string argument = line.substr(argumentStart, argumentEnd - argumentStart);
  316. arguments.push_back(argument);
  317. currentPosition = argumentEnd + 1;
  318. }
  319. if (invalid)
  320. {
  321. std::stringstream stream;
  322. stream << "ResourceLoader<Material>::load(): Unable to parse element on line " << lineNumber << ".";
  323. throw std::runtime_error(stream.str().c_str());
  324. }
  325. elements.push_back(arguments);
  326. currentPosition = rightParenthesisPosition + 1;
  327. }
  328. if (invalid)
  329. {
  330. // Unable to parse line
  331. std::stringstream stream;
  332. stream << "ResourceLoader<Material>::load(): Unable to parse line " << lineNumber << ".";
  333. throw std::runtime_error(stream.str().c_str());
  334. }
  335. if (variableType == "int")
  336. {
  337. ShaderInt* variable = material->addVariable<int>(variableName, elements.size());
  338. loadShaderInt(variable, elements);
  339. }
  340. else if (variableType == "float")
  341. {
  342. ShaderFloat* variable = material->addVariable<float>(variableName, elements.size());
  343. loadShaderFloat(variable, elements);
  344. }
  345. else if (variableType == "vec2")
  346. {
  347. ShaderVector2* variable = material->addVariable<Vector2>(variableName, elements.size());
  348. loadShaderVector2(variable, elements);
  349. }
  350. else if (variableType == "vec3")
  351. {
  352. ShaderVector3* variable = material->addVariable<Vector3>(variableName, elements.size());
  353. loadShaderVector3(variable, elements);
  354. }
  355. else if (variableType == "vec4")
  356. {
  357. ShaderVector4* variable = material->addVariable<Vector4>(variableName, elements.size());
  358. loadShaderVector4(variable, elements);
  359. }
  360. else if (variableType == "mat3")
  361. {
  362. ShaderMatrix3* variable = material->addVariable<Matrix3>(variableName, elements.size());
  363. loadShaderMatrix3(variable, elements);
  364. }
  365. else if (variableType == "mat4")
  366. {
  367. ShaderMatrix4* variable = material->addVariable<Matrix4>(variableName, elements.size());
  368. loadShaderMatrix4(variable, elements);
  369. }
  370. else if (variableType == "texture")
  371. {
  372. ShaderTexture2D* variable = material->addVariable<const Texture2D*>(variableName, elements.size());
  373. loadShaderTexture2D(resourceManager, variable, elements);
  374. }
  375. else if (variableType == "textureCube")
  376. {
  377. ShaderTextureCube* variable = material->addVariable<const TextureCube*>(variableName, elements.size());
  378. loadShaderTextureCube(resourceManager, variable, elements);
  379. }
  380. }
  381. else
  382. {
  383. if (command[0] == '#')
  384. {
  385. // Skip comments
  386. continue;
  387. }
  388. // Invalid command
  389. std::stringstream stream;
  390. stream << "ResourceLoader<Material>::load(): Invalid command \"" << command << "\" on line " << lineNumber << ".";
  391. throw std::runtime_error(stream.str().c_str());
  392. }
  393. }
  394. return material;
  395. }