ResourcePool.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // zlib open source license
  2. //
  3. // Copyright (c) 2017 to 2025 David Forsgren Piuva
  4. //
  5. // This software is provided 'as-is', without any express or implied
  6. // warranty. In no event will the authors be held liable for any damages
  7. // arising from the use of this software.
  8. //
  9. // Permission is granted to anyone to use this software for any purpose,
  10. // including commercial applications, and to alter it and redistribute it
  11. // freely, subject to the following restrictions:
  12. //
  13. // 1. The origin of this software must not be misrepresented; you must not
  14. // claim that you wrote the original software. If you use this software
  15. // in a product, an acknowledgment in the product documentation would be
  16. // appreciated but is not required.
  17. //
  18. // 2. Altered source versions must be plainly marked as such, and must not be
  19. // misrepresented as being the original software.
  20. //
  21. // 3. This notice may not be removed or altered from any source
  22. // distribution.
  23. #include "ResourcePool.h"
  24. #include "../image/stbImage/stbImageWrapper.h"
  25. #include "../api/fileAPI.h"
  26. #include "../api/imageAPI.h"
  27. #include "../api/textureAPI.h"
  28. using namespace dsr;
  29. int BasicResourcePool::findImageRgba(const ReadableString& name) const {
  30. for (int i = 0; i < this->imageRgbaList.length(); i++) {
  31. // Warning!
  32. // This may cover up bugs with case sensitive matching in the Linux file system.
  33. // TODO: Make this case sensitive and enforce it on Windows or allow case insensitive loading on all systems.
  34. if (string_caseInsensitiveMatch(name, this->imageRgbaList[i].name)) {
  35. return i;
  36. }
  37. }
  38. return -1;
  39. }
  40. int BasicResourcePool::findTextureRgba(const ReadableString& name) const {
  41. for (int i = 0; i < this->textureRgbaList.length(); i++) {
  42. if (string_caseInsensitiveMatch(name, this->textureRgbaList[i].name)) {
  43. return i;
  44. }
  45. }
  46. return -1;
  47. }
  48. const ImageRgbaU8 BasicResourcePool::fetchImageRgba(const ReadableString& name) {
  49. ImageRgbaU8 result;
  50. // Using "" will return an empty reference to allow removing textures
  51. if (string_length(name) > 0) {
  52. int existingIndex = this->findImageRgba(name);
  53. if (existingIndex > -1) {
  54. result = this->imageRgbaList[existingIndex].resource;
  55. } else if (string_findFirst(name, U'.') > -1) {
  56. throwError("The image \"", name, "\" had a forbidden dot in the name. Images in resource pools are fetched without the extension to allow changing image format without changing what it's called in other resources.\n");
  57. } else if (string_findFirst(name, U'/') > -1 && string_findFirst(name, U'\\') > -1) {
  58. throwError("The image \"", name, "\" contained a path separator, which is not allowed because of ambiguity. The same file can have multiple paths to the same folder and multiple files can have the same name in different folders.\n");
  59. } else {
  60. // Look for a png image
  61. const String extensionless = file_combinePaths(this->path, name);
  62. result = image_load_RgbaU8(extensionless + ".png", false);
  63. // Look for gif
  64. if (!image_exists(result)) {
  65. result = image_load_RgbaU8(extensionless + ".gif", false);
  66. }
  67. // Look for jpg
  68. if (!image_exists(result)) {
  69. result = image_load_RgbaU8(extensionless + ".jpg", false);
  70. }
  71. if (image_exists(result)) {
  72. this->imageRgbaList.push(namedEntry<ImageRgbaU8>(name, result));
  73. } else {
  74. printText("The image ", extensionless, ".* couldn't be loaded as either png, gif nor jpg!\n");
  75. }
  76. }
  77. }
  78. return result;
  79. }
  80. const TextureRgbaU8 BasicResourcePool::fetchTextureRgba(const ReadableString& name, int32_t resolutions) {
  81. TextureRgbaU8 result;
  82. // Using "" will return an empty reference to allow removing textures
  83. if (string_length(name) > 0) {
  84. int existingTextureIndex = this->findTextureRgba(name);
  85. int existingImageIndex = this->findImageRgba(name);
  86. if (existingTextureIndex > -1) {
  87. result = this->textureRgbaList[existingTextureIndex].resource;
  88. } else if (existingImageIndex > -1) {
  89. result = texture_create_RgbaU8(this->imageRgbaList[existingImageIndex].resource, resolutions);
  90. } else {
  91. // TODO: Save memory by loading a temporary image for generating the texture
  92. // and letting the image point to the highest layer in the texture using texture_getMipLevelImage(result, 0).
  93. result = texture_create_RgbaU8(this->fetchImageRgba(name), resolutions);
  94. /* Enable this to save each texture layer as a file for debugging.
  95. if (texture_exists(result)) {
  96. for (int32_t mipLevel = 0; mipLevel < texture_getSmallestMipLevel(result); mipLevel++) {
  97. image_save(texture_getMipLevelImage(result, mipLevel), string_combine(U"Mip_", name, U"_", texture_getWidth(result, mipLevel), U"x", texture_getHeight(result, mipLevel), U".png"));
  98. }
  99. }
  100. */
  101. }
  102. if (texture_exists(result)) {
  103. this->textureRgbaList.push(namedEntry<TextureRgbaU8>(name, result));
  104. }
  105. }
  106. return result;
  107. }