RenderHandler.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /*
  2. * RenderHandler.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "RenderHandler.h"
  12. #include "SDLImage.h"
  13. #include "../render/CAnimation.h"
  14. #include "../render/CDefFile.h"
  15. #include "../../lib/json/JsonUtils.h"
  16. #include "../../lib/filesystem/Filesystem.h"
  17. #include <vcmi/ArtifactService.h>
  18. #include <vcmi/CreatureService.h>
  19. #include <vcmi/Entity.h>
  20. #include <vcmi/FactionService.h>
  21. #include <vcmi/HeroTypeService.h>
  22. #include <vcmi/Services.h>
  23. #include <vcmi/SkillService.h>
  24. #include <vcmi/spells/Service.h>
  25. std::shared_ptr<CDefFile> RenderHandler::getAnimationFile(const AnimationPath & path)
  26. {
  27. AnimationPath actualPath = boost::starts_with(path.getName(), "SPRITES") ? path : path.addPrefix("SPRITES/");
  28. auto it = animationFiles.find(actualPath);
  29. if (it != animationFiles.end())
  30. return it->second;
  31. if (!CResourceHandler::get()->existsResource(actualPath))
  32. {
  33. animationFiles[actualPath] = nullptr;
  34. return nullptr;
  35. }
  36. auto result = std::make_shared<CDefFile>(actualPath);
  37. animationFiles[actualPath] = result;
  38. return result;
  39. }
  40. void RenderHandler::initFromJson(AnimationLayoutMap & source, const JsonNode & config)
  41. {
  42. std::string basepath;
  43. basepath = config["basepath"].String();
  44. JsonNode base;
  45. base["margins"] = config["margins"];
  46. base["width"] = config["width"];
  47. base["height"] = config["height"];
  48. for(const JsonNode & group : config["sequences"].Vector())
  49. {
  50. size_t groupID = group["group"].Integer();//TODO: string-to-value conversion("moving" -> MOVING)
  51. source[groupID].clear();
  52. for(const JsonNode & frame : group["frames"].Vector())
  53. {
  54. JsonNode toAdd = frame;
  55. JsonUtils::inherit(toAdd, base);
  56. toAdd["file"].String() = basepath + frame.String();
  57. source[groupID].emplace_back(toAdd);
  58. }
  59. }
  60. for(const JsonNode & node : config["images"].Vector())
  61. {
  62. size_t group = node["group"].Integer();
  63. size_t frame = node["frame"].Integer();
  64. if (source[group].size() <= frame)
  65. source[group].resize(frame+1);
  66. JsonNode toAdd = node;
  67. JsonUtils::inherit(toAdd, base);
  68. toAdd["file"].String() = basepath + node["file"].String();
  69. source[group][frame] = ImageLocator(toAdd);
  70. }
  71. }
  72. RenderHandler::AnimationLayoutMap & RenderHandler::getAnimationLayout(const AnimationPath & path)
  73. {
  74. AnimationPath actualPath = boost::starts_with(path.getName(), "SPRITES") ? path : path.addPrefix("SPRITES/");
  75. auto it = animationLayouts.find(actualPath);
  76. if (it != animationLayouts.end())
  77. return it->second;
  78. AnimationLayoutMap result;
  79. auto defFile = getAnimationFile(actualPath);
  80. if(defFile)
  81. {
  82. const std::map<size_t, size_t> defEntries = defFile->getEntries();
  83. for (const auto & defEntry : defEntries)
  84. result[defEntry.first].resize(defEntry.second);
  85. }
  86. auto jsonResource = actualPath.toType<EResType::JSON>();
  87. auto configList = CResourceHandler::get()->getResourcesWithName(jsonResource);
  88. for(auto & loader : configList)
  89. {
  90. auto stream = loader->load(jsonResource);
  91. std::unique_ptr<ui8[]> textData(new ui8[stream->getSize()]);
  92. stream->read(textData.get(), stream->getSize());
  93. const JsonNode config(reinterpret_cast<const std::byte*>(textData.get()), stream->getSize(), path.getOriginalName());
  94. initFromJson(result, config);
  95. }
  96. animationLayouts[actualPath] = result;
  97. return animationLayouts[actualPath];
  98. }
  99. std::shared_ptr<IConstImage> RenderHandler::loadImageFromSingleFile(const ImagePath & path)
  100. {
  101. auto result = std::make_shared<SDLImageConst>(path);
  102. imageFiles[ImageLocator(path)] = result;
  103. return result;
  104. }
  105. std::shared_ptr<IConstImage> RenderHandler::loadImageFromAnimationFileUncached(const AnimationPath & path, int frame, int group)
  106. {
  107. const auto & layout = getAnimationLayout(path);
  108. if (!layout.count(group))
  109. return loadImageFromSingleFile(ImagePath::builtin("DEFAULT"));
  110. if (frame >= layout.at(group).size())
  111. return loadImageFromSingleFile(ImagePath::builtin("DEFAULT"));
  112. const auto & locator = layout.at(group).at(frame);
  113. if (locator.image)
  114. {
  115. return loadImageImpl(locator);
  116. }
  117. else
  118. {
  119. auto defFile = getAnimationFile(path);
  120. return std::make_shared<SDLImageConst>(defFile.get(), frame, group);
  121. }
  122. }
  123. std::shared_ptr<IConstImage> RenderHandler::loadImageFromAnimationFile(const AnimationPath & path, int frame, int group)
  124. {
  125. auto result = loadImageFromAnimationFileUncached(path, frame, group);
  126. imageFiles[ImageLocator(path, frame, group)] = result;
  127. return result;
  128. }
  129. std::shared_ptr<IConstImage> RenderHandler::loadImageImpl(const ImageLocator & locator)
  130. {
  131. auto it = imageFiles.find(locator);
  132. if (it != imageFiles.end())
  133. return it->second;
  134. std::shared_ptr<IConstImage> result;
  135. if (locator.image)
  136. result = loadImageFromSingleFile(*locator.image);
  137. else if (locator.defFile)
  138. result = loadImageFromAnimationFile(*locator.defFile, locator.defFrame, locator.defGroup);
  139. if (!result)
  140. result = loadImageFromSingleFile(ImagePath::builtin("DEFAULT"));
  141. if (locator.verticalFlip)
  142. result = result->verticalFlip();
  143. if (locator.horizontalFlip)
  144. result = result->horizontalFlip();
  145. imageFiles[locator] = result;
  146. return result;
  147. }
  148. std::shared_ptr<IImage> RenderHandler::loadImage(const ImageLocator & locator, EImageBlitMode mode)
  149. {
  150. return loadImageImpl(locator)->createImageReference(mode);
  151. }
  152. std::shared_ptr<IImage> RenderHandler::loadImage(const AnimationPath & path, int frame, int group, EImageBlitMode mode)
  153. {
  154. return loadImageFromAnimationFile(path, frame, group)->createImageReference(mode);
  155. }
  156. std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path, EImageBlitMode mode)
  157. {
  158. return loadImageImpl(ImageLocator(path))->createImageReference(mode);
  159. }
  160. std::shared_ptr<IImage> RenderHandler::createImage(SDL_Surface * source)
  161. {
  162. return std::make_shared<SDLImageConst>(source)->createImageReference(EImageBlitMode::ALPHA);
  163. }
  164. std::shared_ptr<CAnimation> RenderHandler::loadAnimation(const AnimationPath & path, EImageBlitMode mode)
  165. {
  166. return std::make_shared<CAnimation>(path, getAnimationLayout(path), mode);
  167. }
  168. void RenderHandler::addImageListEntries(const EntityService * service)
  169. {
  170. service->forEachBase([this](const Entity * entity, bool & stop)
  171. {
  172. entity->registerIcons([this](size_t index, size_t group, const std::string & listName, const std::string & imageName)
  173. {
  174. if (imageName.empty())
  175. return;
  176. auto & layout = getAnimationLayout(AnimationPath::builtin("SPRITES/" + listName));
  177. JsonNode entry;
  178. entry["file"].String() = imageName;
  179. if (index >= layout[group].size())
  180. layout[group].resize(index + 1);
  181. layout[group][index] = ImageLocator(entry);
  182. });
  183. });
  184. }
  185. void RenderHandler::onLibraryLoadingFinished(const Services * services)
  186. {
  187. addImageListEntries(services->creatures());
  188. addImageListEntries(services->heroTypes());
  189. addImageListEntries(services->artifacts());
  190. addImageListEntries(services->factions());
  191. addImageListEntries(services->spells());
  192. addImageListEntries(services->skills());
  193. }