renderer.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #include "simple/support/enum.hpp"
  2. #include "window.h"
  3. #include "surface.h"
  4. #include "renderer.h"
  5. #include "renderer_window.h"
  6. using namespace simple;
  7. using namespace simple::graphical;
  8. static void set_scale_quality_hint(quality_hint hint)
  9. {
  10. static const char* quality_hint_names[] = { "nearest", "linear", "best" };
  11. SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, quality_hint_names[static_cast<int>(hint)]);
  12. }
  13. renderer::renderer(const surface& target)
  14. : sdl_renderer_wrapper
  15. (
  16. SDL_CreateSoftwareRenderer(target.guts().get()),
  17. SDL_DestroyRenderer
  18. )
  19. {}
  20. renderer::renderer(SDL_Renderer* rend, quality_hint scale_quality, sdl_renderer_wrapper::Deleter deleter)
  21. : sdl_renderer_wrapper(rend, deleter), _default_scale_quality(scale_quality)
  22. {
  23. }
  24. void renderer::update() const noexcept
  25. {
  26. SDL_RenderPresent(guts().get());
  27. }
  28. rgba_pixel renderer::color() const noexcept
  29. {
  30. rgba_pixel result;
  31. SDL_GetRenderDrawColor(guts().get(), &result.r(), &result.g(), &result.b(), &result.a());
  32. return result;
  33. }
  34. void renderer::color(const rgba_pixel& new_value) const noexcept
  35. {
  36. SDL_SetRenderDrawColor(guts().get(), new_value.r(), new_value.g(), new_value.b(), new_value.a());
  37. }
  38. blend_mode renderer::blend() const noexcept
  39. {
  40. SDL_BlendMode result;
  41. SDL_GetRenderDrawBlendMode(guts().get(), &result);
  42. return static_cast<blend_mode>(result);
  43. }
  44. void renderer::blend(blend_mode new_value) const noexcept
  45. {
  46. SDL_SetRenderDrawBlendMode
  47. (
  48. guts().get(),
  49. static_cast<SDL_BlendMode>(support::to_integer(new_value))
  50. );
  51. }
  52. quality_hint renderer::default_scale_quality() const noexcept
  53. {
  54. return _default_scale_quality;
  55. }
  56. int2 renderer::target_size() const noexcept
  57. {
  58. auto result = -int2::one();
  59. SDL_GetRendererOutputSize(guts().get(), &result.x(), &result.y());
  60. return result;
  61. }
  62. basic_texture renderer::get_texture(const surface& surface) const
  63. {
  64. return get_texture(surface, _default_scale_quality);
  65. }
  66. basic_texture renderer::get_texture(const surface& surface, quality_hint scale_quality) const
  67. {
  68. set_scale_quality_hint(scale_quality);
  69. auto result = basic_texture(guts().get(), surface.guts().get());
  70. return result;
  71. }
  72. streaming_texture renderer::get_texture(int2 size, pixel_format::type format) const
  73. {
  74. return get_texture(size, _default_scale_quality, format);
  75. }
  76. streaming_texture renderer::get_texture(int2 size, quality_hint scale_quality, pixel_format::type format) const
  77. {
  78. set_scale_quality_hint(scale_quality);
  79. return streaming_texture(guts().get(), format, size, texture::access::streaming);
  80. }
  81. render_texture renderer::get_render_texture(int2 size, pixel_format::type format) const
  82. {
  83. return get_render_texture(size, _default_scale_quality, format);
  84. }
  85. render_texture renderer::get_render_texture(int2 size, quality_hint scale_quality, pixel_format::type format) const
  86. {
  87. set_scale_quality_hint(scale_quality);
  88. return render_texture(guts().get(), format, size, texture::access::render_target);
  89. }
  90. void renderer::destroy_texture(texture& tex) const
  91. {
  92. SDL_DestroyTexture(tex.guts());
  93. #ifndef NDEBUG
  94. tex._guts = nullptr;
  95. #endif
  96. }
  97. blend_mode renderer::texture_blend(const texture& tex) const noexcept
  98. {
  99. SDL_BlendMode result;
  100. SDL_GetTextureBlendMode(tex.guts(), &result);
  101. return static_cast<blend_mode>(result);
  102. }
  103. void renderer::texture_blend(const texture& tex, blend_mode new_value) const noexcept
  104. {
  105. SDL_SetTextureBlendMode
  106. (
  107. tex.guts(),
  108. static_cast<SDL_BlendMode>(support::to_integer(new_value))
  109. );
  110. }
  111. rgb_pixel renderer::texture_color(const texture& tex) const noexcept
  112. {
  113. rgb_pixel result;
  114. SDL_GetTextureColorMod(tex.guts(), &result.r(), &result.g(), &result.b());
  115. return result;
  116. }
  117. void renderer::texture_color(const texture& tex, const rgb_pixel& new_value) const noexcept
  118. {
  119. SDL_SetTextureColorMod(tex.guts(), new_value.r(), new_value.g(), new_value.b());
  120. }
  121. uint8_t renderer::texture_alpha(const texture& tex) const noexcept
  122. {
  123. uint8_t result;
  124. SDL_GetTextureAlphaMod(tex.guts(), &result);
  125. return result;
  126. }
  127. void renderer::texture_alpha(const texture& tex, uint8_t new_value) const noexcept
  128. {
  129. SDL_SetTextureAlphaMod(tex.guts(), new_value);
  130. }
  131. void renderer::update(const texture& tex, pixel_reader_variant data_variant, int2 destination) const
  132. {
  133. std::visit([&tex, &destination](auto&& data)
  134. {
  135. auto dr = sdlcore::utils::to_rect<SDL_Rect>(rect{data.size()});
  136. dr.x = destination.x();
  137. dr.y = destination.y();
  138. sdlcore::utils::throw_error(
  139. SDL_UpdateTexture(tex.guts(), &dr, data.row(), data.row(1) - data.row()) );
  140. }, data_variant);
  141. }
  142. void renderer::update(const streaming_texture& tex, std::function<void(pixel_writer_variant)> callback, range2D area) const
  143. {
  144. const auto [ignore0, ignore1, ignore2, format] = tex.info();
  145. ((void)ignore0, (void)ignore1, (void)ignore2); // silence unused variable warning
  146. void* pixels;
  147. int pitch;
  148. auto rect = sdlcore::utils::to_rect<SDL_Rect>(area);
  149. sdlcore::utils::throw_error(
  150. SDL_LockTexture(tex.guts(), &rect, &pixels, &pitch) );
  151. callback(pixel_writer_from_format(
  152. reinterpret_cast<pixel_byte*>(pixels),
  153. area.upper() - area.lower(),
  154. pitch,
  155. SDL_BYTESPERPIXEL(support::to_integer(format)) ));
  156. SDL_UnlockTexture(tex.guts());
  157. }
  158. void renderer::update(const streaming_texture& tex, std::function<void(pixel_writer_variant)> callback) const
  159. {
  160. const auto [ignore0, ignore1, size, format] = tex.info();
  161. ((void)ignore0, (void)ignore1); // silence unused variable warning
  162. void* pixels;
  163. int pitch;
  164. sdlcore::utils::throw_error(
  165. SDL_LockTexture(tex.guts(), NULL, &pixels, &pitch) );
  166. callback(pixel_writer_from_format(
  167. reinterpret_cast<pixel_byte*>(pixels),
  168. size,
  169. pitch,
  170. SDL_BYTESPERPIXEL(support::to_integer(format)) ));
  171. SDL_UnlockTexture(tex.guts());
  172. }
  173. std::optional<render_texture> renderer::target() const noexcept
  174. {
  175. const auto tex = SDL_GetRenderTarget(guts().get());
  176. return NULL == tex ? std::make_optional(render_texture(tex)) : std::nullopt;
  177. }
  178. void renderer::target(render_texture tex) const
  179. {
  180. sdlcore::utils::throw_error(SDL_SetRenderTarget(guts().get(), tex.guts()));
  181. }
  182. void renderer::target_default() const noexcept
  183. {
  184. SDL_SetRenderTarget(guts().get(), NULL);
  185. }
  186. bool renderer::render(const texture& source) const
  187. {
  188. return !sdlcore::utils::check_error(SDL_RenderCopy(guts().get(), source.guts(), NULL, NULL));
  189. }
  190. bool renderer::render(const texture& source, const range2D& destination) const
  191. {
  192. auto dr = sdlcore::utils::to_rect<SDL_Rect>(destination);
  193. return !sdlcore::utils::check_error(SDL_RenderCopy(guts().get(), source.guts(), NULL, &dr));
  194. }
  195. static bool render_copy_ex(SDL_Renderer* rend, SDL_Texture* tex, range2D src, range2D dest, double angle, int2 center, texture::flip_direction flip)
  196. {
  197. auto sr = sdlcore::utils::to_rect<SDL_Rect>(src);
  198. auto dr = sdlcore::utils::to_rect<SDL_Rect>(dest);
  199. auto c = SDL_Point{center.x(), center.y()};
  200. return !sdlcore::utils::check_error(SDL_RenderCopyEx(rend, tex, &sr, &dr,
  201. angle, &c, static_cast<SDL_RendererFlip>(support::to_integer(flip))));
  202. }
  203. bool renderer::render(const texture_view& source, int2 position) const
  204. {
  205. return render_copy_ex(
  206. guts().get(), source.texture.guts(),
  207. source.region, source.region + position,
  208. 0, source.pivot,
  209. source.flip);
  210. }
  211. bool renderer::render(const texture_view& source, const range2D& destination) const
  212. {
  213. return render_copy_ex(
  214. guts().get(), source.texture.guts(),
  215. source.region, destination,
  216. 0, source.pivot,
  217. source.flip);
  218. }
  219. bool renderer::render(const texture_view& source, int2 position, double angle) const
  220. {
  221. return render_copy_ex(
  222. guts().get(), source.texture.guts(),
  223. source.region, source.region + position,
  224. angle, source.pivot,
  225. source.flip);
  226. }
  227. bool renderer::render(const texture_view& source, const range2D& destination, double angle) const
  228. {
  229. return render_copy_ex(
  230. guts().get(), source.texture.guts(),
  231. source.region, destination,
  232. angle, source.pivot,
  233. source.flip);
  234. }