SDLImage.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /*
  2. * SDLImage.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 "SDLImage.h"
  12. #include "SDLImageLoader.h"
  13. #include "SDL_Extensions.h"
  14. #include "../render/ColorFilter.h"
  15. #include "../render/CBitmapHandler.h"
  16. #include "../render/CDefFile.h"
  17. #include "../render/Graphics.h"
  18. #include "../../lib/JsonNode.h"
  19. #include <SDL_surface.h>
  20. class SDLImageLoader;
  21. std::shared_ptr<IImage> IImage::createFromFile( const std::string & path )
  22. {
  23. return std::shared_ptr<IImage>(new SDLImage(path));
  24. }
  25. std::shared_ptr<IImage> IImage::createFromSurface( SDL_Surface * source )
  26. {
  27. return std::shared_ptr<IImage>(new SDLImage(source, true));
  28. }
  29. IImage::IImage() = default;
  30. IImage::~IImage() = default;
  31. int IImage::width() const
  32. {
  33. return dimensions().x;
  34. }
  35. int IImage::height() const
  36. {
  37. return dimensions().y;
  38. }
  39. SDLImage::SDLImage(CDefFile * data, size_t frame, size_t group)
  40. : surf(nullptr),
  41. margins(0, 0),
  42. fullSize(0, 0),
  43. originalPalette(nullptr)
  44. {
  45. SDLImageLoader loader(this);
  46. data->loadFrame(frame, group, loader);
  47. savePalette();
  48. }
  49. SDLImage::SDLImage(SDL_Surface * from, bool extraRef)
  50. : surf(nullptr),
  51. margins(0, 0),
  52. fullSize(0, 0),
  53. originalPalette(nullptr)
  54. {
  55. surf = from;
  56. if (surf == nullptr)
  57. return;
  58. savePalette();
  59. if (extraRef)
  60. surf->refcount++;
  61. fullSize.x = surf->w;
  62. fullSize.y = surf->h;
  63. }
  64. SDLImage::SDLImage(const JsonNode & conf)
  65. : surf(nullptr),
  66. margins(0, 0),
  67. fullSize(0, 0),
  68. originalPalette(nullptr)
  69. {
  70. std::string filename = conf["file"].String();
  71. surf = BitmapHandler::loadBitmap(filename);
  72. if(surf == nullptr)
  73. return;
  74. savePalette();
  75. const JsonNode & jsonMargins = conf["margins"];
  76. margins.x = static_cast<int>(jsonMargins["left"].Integer());
  77. margins.y = static_cast<int>(jsonMargins["top"].Integer());
  78. fullSize.x = static_cast<int>(conf["width"].Integer());
  79. fullSize.y = static_cast<int>(conf["height"].Integer());
  80. if(fullSize.x == 0)
  81. {
  82. fullSize.x = margins.x + surf->w + (int)jsonMargins["right"].Integer();
  83. }
  84. if(fullSize.y == 0)
  85. {
  86. fullSize.y = margins.y + surf->h + (int)jsonMargins["bottom"].Integer();
  87. }
  88. }
  89. SDLImage::SDLImage(std::string filename)
  90. : surf(nullptr),
  91. margins(0, 0),
  92. fullSize(0, 0),
  93. originalPalette(nullptr)
  94. {
  95. surf = BitmapHandler::loadBitmap(filename);
  96. if(surf == nullptr)
  97. {
  98. logGlobal->error("Error: failed to load image %s", filename);
  99. return;
  100. }
  101. else
  102. {
  103. savePalette();
  104. fullSize.x = surf->w;
  105. fullSize.y = surf->h;
  106. }
  107. }
  108. void SDLImage::draw(SDL_Surface *where, int posX, int posY, const Rect *src) const
  109. {
  110. if(!surf)
  111. return;
  112. Rect destRect(posX, posY, surf->w, surf->h);
  113. draw(where, &destRect, src);
  114. }
  115. void SDLImage::draw(SDL_Surface* where, const Rect * dest, const Rect* src) const
  116. {
  117. if (!surf)
  118. return;
  119. Rect sourceRect(0, 0, surf->w, surf->h);
  120. Point destShift(0, 0);
  121. if(src)
  122. {
  123. if(src->x < margins.x)
  124. destShift.x += margins.x - src->x;
  125. if(src->y < margins.y)
  126. destShift.y += margins.y - src->y;
  127. sourceRect = Rect(*src).intersect(Rect(margins.x, margins.y, surf->w, surf->h));
  128. sourceRect -= margins;
  129. }
  130. else
  131. destShift = margins;
  132. if(dest)
  133. destShift += dest->topLeft();
  134. uint8_t perSurfaceAlpha;
  135. if (SDL_GetSurfaceAlphaMod(surf, &perSurfaceAlpha) != 0)
  136. logGlobal->error("SDL_GetSurfaceAlphaMod faied! %s", SDL_GetError());
  137. if(surf->format->BitsPerPixel == 8 && perSurfaceAlpha == SDL_ALPHA_OPAQUE)
  138. {
  139. CSDL_Ext::blit8bppAlphaTo24bpp(surf, sourceRect, where, destShift);
  140. }
  141. else
  142. {
  143. CSDL_Ext::blitSurface(surf, sourceRect, where, destShift);
  144. }
  145. }
  146. std::shared_ptr<IImage> SDLImage::scaleFast(const Point & size) const
  147. {
  148. float scaleX = float(size.x) / width();
  149. float scaleY = float(size.y) / height();
  150. auto scaled = CSDL_Ext::scaleSurfaceFast(surf, (int)(surf->w * scaleX), (int)(surf->h * scaleY));
  151. if (scaled->format && scaled->format->palette) // fix color keying, because SDL loses it at this point
  152. CSDL_Ext::setColorKey(scaled, scaled->format->palette->colors[0]);
  153. else if(scaled->format && scaled->format->Amask)
  154. SDL_SetSurfaceBlendMode(scaled, SDL_BLENDMODE_BLEND);//just in case
  155. else
  156. CSDL_Ext::setDefaultColorKey(scaled);//just in case
  157. SDLImage * ret = new SDLImage(scaled, false);
  158. ret->fullSize.x = (int) round((float)fullSize.x * scaleX);
  159. ret->fullSize.y = (int) round((float)fullSize.y * scaleY);
  160. ret->margins.x = (int) round((float)margins.x * scaleX);
  161. ret->margins.y = (int) round((float)margins.y * scaleY);
  162. return std::shared_ptr<IImage>(ret);
  163. }
  164. void SDLImage::exportBitmap(const boost::filesystem::path& path) const
  165. {
  166. SDL_SaveBMP(surf, path.string().c_str());
  167. }
  168. void SDLImage::playerColored(PlayerColor player)
  169. {
  170. graphics->blueToPlayersAdv(surf, player);
  171. }
  172. void SDLImage::setAlpha(uint8_t value)
  173. {
  174. CSDL_Ext::setAlpha (surf, value);
  175. SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_BLEND);
  176. }
  177. void SDLImage::setFlagColor(PlayerColor player)
  178. {
  179. if(player < PlayerColor::PLAYER_LIMIT || player==PlayerColor::NEUTRAL)
  180. CSDL_Ext::setPlayerColor(surf, player);
  181. }
  182. bool SDLImage::isTransparent(const Point & coords) const
  183. {
  184. return CSDL_Ext::isTransparent(surf, coords.x, coords.y);
  185. }
  186. Point SDLImage::dimensions() const
  187. {
  188. return fullSize;
  189. }
  190. void SDLImage::horizontalFlip()
  191. {
  192. margins.y = fullSize.y - surf->h - margins.y;
  193. //todo: modify in-place
  194. SDL_Surface * flipped = CSDL_Ext::horizontalFlip(surf);
  195. SDL_FreeSurface(surf);
  196. surf = flipped;
  197. }
  198. void SDLImage::verticalFlip()
  199. {
  200. margins.x = fullSize.x - surf->w - margins.x;
  201. //todo: modify in-place
  202. SDL_Surface * flipped = CSDL_Ext::verticalFlip(surf);
  203. SDL_FreeSurface(surf);
  204. surf = flipped;
  205. }
  206. // Keep the original palette, in order to do color switching operation
  207. void SDLImage::savePalette()
  208. {
  209. // For some images that don't have palette, skip this
  210. if(surf->format->palette == nullptr)
  211. return;
  212. if(originalPalette == nullptr)
  213. originalPalette = SDL_AllocPalette(DEFAULT_PALETTE_COLORS);
  214. SDL_SetPaletteColors(originalPalette, surf->format->palette->colors, 0, DEFAULT_PALETTE_COLORS);
  215. }
  216. void SDLImage::shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove)
  217. {
  218. if(surf->format->palette)
  219. {
  220. std::vector<SDL_Color> shifterColors(colorsToMove);
  221. for(uint32_t i=0; i<colorsToMove; ++i)
  222. {
  223. shifterColors[(i+distanceToMove)%colorsToMove] = originalPalette->colors[firstColorID + i];
  224. }
  225. CSDL_Ext::setColors(surf, shifterColors.data(), firstColorID, colorsToMove);
  226. }
  227. }
  228. void SDLImage::adjustPalette(const ColorFilter & shifter, size_t colorsToSkip)
  229. {
  230. if(originalPalette == nullptr)
  231. return;
  232. SDL_Palette* palette = surf->format->palette;
  233. // Note: here we skip first colors in the palette that are predefined in H3 images
  234. for(int i = colorsToSkip; i < palette->ncolors; i++)
  235. {
  236. palette->colors[i] = shifter.shiftColor(originalPalette->colors[i]);
  237. }
  238. }
  239. void SDLImage::resetPalette()
  240. {
  241. if(originalPalette == nullptr)
  242. return;
  243. // Always keept the original palette not changed, copy a new palette to assign to surface
  244. SDL_SetPaletteColors(surf->format->palette, originalPalette->colors, 0, originalPalette->ncolors);
  245. }
  246. void SDLImage::resetPalette( int colorID )
  247. {
  248. if(originalPalette == nullptr)
  249. return;
  250. // Always keept the original palette not changed, copy a new palette to assign to surface
  251. SDL_SetPaletteColors(surf->format->palette, originalPalette->colors + colorID, colorID, 1);
  252. }
  253. void SDLImage::setSpecialPallete(const IImage::SpecialPalette & SpecialPalette)
  254. {
  255. if(surf->format->palette)
  256. {
  257. CSDL_Ext::setColors(surf, const_cast<SDL_Color *>(SpecialPalette.data()), 1, 7);
  258. }
  259. }
  260. SDLImage::~SDLImage()
  261. {
  262. SDL_FreeSurface(surf);
  263. if(originalPalette != nullptr)
  264. {
  265. SDL_FreePalette(originalPalette);
  266. originalPalette = nullptr;
  267. }
  268. }