TextureDatabase.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #include "TextureDatabase.h"
  2. #include "../../Include/RmlUi/Core/Log.h"
  3. #include "../../Include/RmlUi/Core/RenderInterface.h"
  4. namespace Rml {
  5. CallbackTextureDatabase::CallbackTextureDatabase()
  6. {
  7. constexpr size_t reserve_callback_textures = 30;
  8. texture_list.reserve(reserve_callback_textures);
  9. }
  10. CallbackTextureDatabase::~CallbackTextureDatabase()
  11. {
  12. if (!texture_list.empty())
  13. {
  14. Log::Message(Log::LT_ERROR, "TextureDatabase destroyed with outstanding callback textures. Will likely result in memory corruption.");
  15. RMLUI_ERROR;
  16. }
  17. }
  18. StableVectorIndex CallbackTextureDatabase::CreateTexture(CallbackTextureFunction&& callback)
  19. {
  20. RMLUI_ASSERT(callback);
  21. return texture_list.insert(CallbackTextureEntry{std::move(callback), TextureHandle(), Vector2i()});
  22. }
  23. void CallbackTextureDatabase::ReleaseTexture(RenderInterface* render_interface, StableVectorIndex callback_index)
  24. {
  25. CallbackTextureEntry& data = texture_list[callback_index];
  26. if (data.texture_handle)
  27. render_interface->ReleaseTexture(data.texture_handle);
  28. texture_list.erase(callback_index);
  29. }
  30. Vector2i CallbackTextureDatabase::GetDimensions(RenderManager* render_manager, RenderInterface* render_interface, StableVectorIndex callback_index)
  31. {
  32. return EnsureLoaded(render_manager, render_interface, callback_index).dimensions;
  33. }
  34. TextureHandle CallbackTextureDatabase::GetHandle(RenderManager* render_manager, RenderInterface* render_interface, StableVectorIndex callback_index)
  35. {
  36. return EnsureLoaded(render_manager, render_interface, callback_index).texture_handle;
  37. }
  38. auto CallbackTextureDatabase::EnsureLoaded(RenderManager* render_manager, RenderInterface* render_interface, StableVectorIndex callback_index)
  39. -> CallbackTextureEntry&
  40. {
  41. CallbackTextureEntry& data = texture_list[callback_index];
  42. if (!data.texture_handle && !data.load_failed)
  43. {
  44. if (!data.callback(CallbackTextureInterface(*render_manager, *render_interface, data.texture_handle, data.dimensions)))
  45. {
  46. data.load_failed = true;
  47. data.texture_handle = {};
  48. data.dimensions = {};
  49. }
  50. }
  51. return data;
  52. }
  53. size_t CallbackTextureDatabase::size() const
  54. {
  55. return texture_list.size();
  56. }
  57. void CallbackTextureDatabase::ReleaseAllTextures(RenderInterface* render_interface)
  58. {
  59. texture_list.for_each([render_interface](CallbackTextureEntry& texture) {
  60. if (texture.texture_handle)
  61. {
  62. render_interface->ReleaseTexture(texture.texture_handle);
  63. texture.texture_handle = {};
  64. texture.dimensions = {};
  65. }
  66. });
  67. }
  68. FileTextureDatabase::FileTextureDatabase() {}
  69. FileTextureDatabase::~FileTextureDatabase()
  70. {
  71. #ifdef RMLUI_DEBUG
  72. for (const FileTextureEntry& texture : texture_list)
  73. {
  74. RMLUI_ASSERTMSG(!texture.texture_handle,
  75. "TextureDatabase destroyed without releasing all file textures first. Ensure that 'ReleaseAllTextures' is called before destruction.");
  76. }
  77. #endif
  78. }
  79. TextureFileIndex FileTextureDatabase::InsertTexture(const String& source)
  80. {
  81. auto it = texture_map.find(source);
  82. if (it != texture_map.end())
  83. return it->second;
  84. // The texture is not yet loaded from the render interface. That is deferred until the texture is needed, such as when it becomes visible.
  85. const auto index = TextureFileIndex(texture_list.size());
  86. texture_map[source] = index;
  87. texture_list.push_back({});
  88. return index;
  89. }
  90. FileTextureDatabase::FileTextureEntry FileTextureDatabase::LoadTextureEntry(RenderInterface* render_interface, const String& source)
  91. {
  92. FileTextureEntry result = {};
  93. result.texture_handle = render_interface->LoadTexture(result.dimensions, source);
  94. if (!result.texture_handle)
  95. {
  96. result.load_texture_failed = true;
  97. Rml::Log::Message(Rml::Log::LT_WARNING, "Could not load texture: %s", source.c_str());
  98. }
  99. return result;
  100. }
  101. FileTextureDatabase::FileTextureEntry& FileTextureDatabase::EnsureLoaded(RenderInterface* render_interface, TextureFileIndex index)
  102. {
  103. FileTextureEntry& entry = texture_list[size_t(index)];
  104. if (!entry.texture_handle)
  105. {
  106. auto it = std::find_if(texture_map.begin(), texture_map.end(), [index](const auto& pair) { return pair.second == index; });
  107. RMLUI_ASSERT(it != texture_map.end());
  108. const String& source = it->first;
  109. if (!entry.load_texture_failed)
  110. entry = LoadTextureEntry(render_interface, source);
  111. }
  112. return entry;
  113. }
  114. TextureHandle FileTextureDatabase::GetHandle(RenderInterface* render_interface, TextureFileIndex index)
  115. {
  116. RMLUI_ASSERT(size_t(index) < texture_list.size());
  117. return EnsureLoaded(render_interface, index).texture_handle;
  118. }
  119. Vector2i FileTextureDatabase::GetDimensions(RenderInterface* render_interface, TextureFileIndex index)
  120. {
  121. RMLUI_ASSERT(size_t(index) < texture_list.size());
  122. return EnsureLoaded(render_interface, index).dimensions;
  123. }
  124. void FileTextureDatabase::GetSourceList(StringList& source_list) const
  125. {
  126. source_list.reserve(source_list.size() + texture_list.size());
  127. for (const auto& texture : texture_map)
  128. source_list.push_back(texture.first);
  129. }
  130. bool FileTextureDatabase::ReleaseTexture(RenderInterface* render_interface, const String& source)
  131. {
  132. auto it = texture_map.find(source);
  133. if (it == texture_map.end())
  134. return false;
  135. FileTextureEntry& texture = texture_list[size_t(it->second)];
  136. if (texture.texture_handle)
  137. {
  138. render_interface->ReleaseTexture(texture.texture_handle);
  139. texture = {};
  140. return true;
  141. }
  142. return false;
  143. }
  144. void FileTextureDatabase::ReleaseAllTextures(RenderInterface* render_interface)
  145. {
  146. for (FileTextureEntry& texture : texture_list)
  147. {
  148. if (texture.texture_handle)
  149. {
  150. render_interface->ReleaseTexture(texture.texture_handle);
  151. texture = {};
  152. }
  153. }
  154. }
  155. } // namespace Rml