1// SuperTux
2// Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17#include "video/sdl/sdl_painter.hpp"
18
19#include <SDL.h>
20#include <algorithm>
21#include <array>
22#include <assert.h>
23#include <math.h>
24
25#include "supertux/globals.hpp"
26#include "math/util.hpp"
27#include "util/log.hpp"
28#include "video/drawing_request.hpp"
29#include "video/renderer.hpp"
30#include "video/sdl/sdl_texture.hpp"
31#include "video/sdl/sdl_video_system.hpp"
32#include "video/viewport.hpp"
33
34namespace {
35
36SDL_Rect to_sdl_rect(const Rectf& rect)
37{
38 SDL_Rect sdl_rect;
39
40 // floorf() here due to int(-0.5) and int(0.5) both rounding to 0,
41 // thus creating a jump in coordinates at 0
42 sdl_rect.x = static_cast<int>(floorf(rect.get_left()));
43 sdl_rect.y = static_cast<int>(floorf(rect.get_top()));
44
45 // roundf() here due to int(rect.get_right()y - rect.get_left()y) being
46 // off-by-one due to float errors
47 sdl_rect.w = static_cast<int>(roundf(rect.get_width()));
48 sdl_rect.h = static_cast<int>(roundf(rect.get_height()));
49
50 return sdl_rect;
51}
52
53SDL_BlendMode blend2sdl(const Blend& blend)
54{
55 if (blend == Blend::NONE)
56 {
57 return SDL_BLENDMODE_NONE;
58 }
59 else if (blend == Blend::BLEND)
60 {
61 return SDL_BLENDMODE_BLEND;
62 }
63 else if (blend == Blend::ADD)
64 {
65 return SDL_BLENDMODE_ADD;
66 }
67 else if (blend == Blend::MOD)
68 {
69 return SDL_BLENDMODE_MOD;
70 }
71 else
72 {
73 log_warning << "unknown blend mode combinations: blend=" << static_cast<int>(blend) << std::endl;
74 return SDL_BLENDMODE_BLEND;
75 }
76}
77
78/* Creates a new rectangle covering the area where srcrect and imgrect
79 overlap, in addition create four more rectangles for the areas
80 where srcrect is outside of imgrect, some of those rects will be
81 empty. The rectangles will be returned in the order inside, top,
82 left, right, bottom */
83std::tuple<Rect, Rect, Rect, Rect, Rect>
84intersect(const Rect& srcrect, const Rect& imgrect)
85{
86 return std::make_tuple(
87 // inside
88 Rect(std::max(srcrect.left, imgrect.left), std::max(srcrect.top, imgrect.top),
89 std::min(srcrect.right, imgrect.right), std::min(srcrect.bottom, imgrect.bottom)),
90
91 // top
92 Rect(srcrect.left, srcrect.top,
93 srcrect.right, imgrect.top),
94
95 // left
96 Rect(srcrect.left, std::max(srcrect.top, imgrect.top),
97 imgrect.left, std::min(srcrect.bottom, imgrect.bottom)),
98
99 // right
100 Rect(imgrect.right, std::max(srcrect.top, imgrect.top),
101 srcrect.right, std::min(srcrect.bottom, imgrect.bottom)),
102
103 // bottom
104 Rect(srcrect.left, imgrect.bottom,
105 srcrect.right, srcrect.bottom)
106 );
107}
108
109/* Map the area covered by inside in srcrect to dstrect */
110Rect relative_map(const Rect& inside, const Rect& srcrect, const Rect& dstrect)
111{
112 assert(srcrect.contains(inside));
113
114 Rect result(dstrect.left + (inside.left - srcrect.left) * dstrect.get_width() / srcrect.get_width(),
115 dstrect.top + (inside.top - srcrect.top) * dstrect.get_height() / srcrect.get_height(),
116 dstrect.left + (inside.right - srcrect.left) * dstrect.get_width() / srcrect.get_width(),
117 dstrect.top + (inside.bottom - srcrect.top) * dstrect.get_height() / srcrect.get_height());
118
119 assert(dstrect.contains(result));
120
121 return result;
122}
123
124void render_texture(SDL_Renderer* renderer,
125 SDL_Texture* texture, const Rect& imgrect,
126 const Rect& srcrect, const Rect& dstrect)
127{
128 assert(imgrect.contains(srcrect.left, srcrect.top));
129
130 if (srcrect.empty() || dstrect.empty())
131 return;
132
133 if (imgrect.contains(srcrect))
134 {
135 SDL_Rect sdl_srcrect = srcrect.to_sdl();
136 SDL_Rect sdl_dstrect = dstrect.to_sdl();
137 SDL_RenderCopy(renderer, texture, &sdl_srcrect, &sdl_dstrect);
138 }
139 else
140 {
141 Rect inside;
142 std::array<Rect, 4> rest;
143 std::tie(inside, rest[0], rest[1], rest[2], rest[3]) = intersect(srcrect, imgrect);
144
145 render_texture(renderer, texture, imgrect, inside, relative_map(inside, srcrect, dstrect));
146
147 for (const Rect& rect : rest)
148 {
149 const Rect new_srcrect(math::positive_mod(rect.left, imgrect.get_width()),
150 math::positive_mod(rect.top, imgrect.get_height()),
151 rect.get_size());
152 render_texture(renderer, texture, imgrect,
153 new_srcrect, relative_map(rect, srcrect, dstrect));
154 }
155 }
156}
157
158/* A version SDL_RenderCopyEx that supports texture animation as specified by Sampler */
159void RenderCopyEx(SDL_Renderer* renderer,
160 SDL_Texture* texture,
161 const SDL_Rect* sdl_srcrect,
162 const SDL_Rect* sdl_dstrect,
163 const double angle,
164 const SDL_Point* center,
165 const SDL_RendererFlip flip,
166 const Sampler& sampler)
167{
168 Vector animate = sampler.get_animate();
169 if (animate.x == 0.0f && animate.y == 0.0f)
170 {
171 SDL_RenderCopyEx(renderer, texture, sdl_srcrect, sdl_dstrect, angle, nullptr, flip);
172 }
173 else
174 {
175 // This part deals with texture animation. Texture animation is
176 // accomplished by shifting the srcrect across the input texture.
177 // If the srcrect goes out of bounds of the texture, it is broken
178 // up into multiple rectangles that wrap around and fall back into
179 // the texture space.
180 //
181 // If a srcrect is passed to SDL that goes out of bounds SDL will
182 // clip it to be inside the bounds, without adjusting dstrect,
183 // thus result in stretching artifacts.
184 //
185 // FIXME: Neither flipping nor wrap modes are supported at the
186 // moment. wrap is treated as if it was set to 'repeat'.
187 int width;
188 int height;
189
190 SDL_QueryTexture(texture, nullptr, nullptr, &width, &height);
191
192 animate *= g_game_time;
193
194 int tex_off_x = math::positive_mod(static_cast<int>(animate.x), width);
195 int tex_off_y = math::positive_mod(static_cast<int>(animate.y), height);
196
197 if ((tex_off_x == 0 && tex_off_y == 0) ||
198 flip ||
199 angle != 0.0)
200 {
201 SDL_RenderCopyEx(renderer, texture, sdl_srcrect, sdl_dstrect, angle, nullptr, flip);
202 }
203 else
204 {
205 Rect imgrect(0, 0, Size(width, height));
206 Rect srcrect(math::positive_mod(sdl_srcrect->x + tex_off_x, width),
207 math::positive_mod(sdl_srcrect->y + tex_off_y, height),
208 Size(sdl_srcrect->w, sdl_srcrect->h));
209
210 render_texture(renderer, texture, imgrect, srcrect, Rect(*sdl_dstrect));
211 }
212 }
213}
214
215} // namespace
216
217SDLPainter::SDLPainter(SDLVideoSystem& video_system, Renderer& renderer, SDL_Renderer* sdl_renderer) :
218 m_video_system(video_system),
219 m_renderer(renderer),
220 m_sdl_renderer(sdl_renderer),
221 m_cliprect()
222{}
223
224void
225SDLPainter::draw_texture(const TextureRequest& request)
226{
227 const auto& texture = static_cast<const SDLTexture&>(*request.texture);
228
229 assert(request.srcrects.size() == request.dstrects.size());
230 assert(request.srcrects.size() == request.angles.size());
231
232 for (size_t i = 0; i < request.srcrects.size(); ++i)
233 {
234 const SDL_Rect& src_rect = to_sdl_rect(request.srcrects[i]);
235 const SDL_Rect& dst_rect = to_sdl_rect(request.dstrects[i]);
236
237 Uint8 r = static_cast<Uint8>(request.color.red * 255);
238 Uint8 g = static_cast<Uint8>(request.color.green * 255);
239 Uint8 b = static_cast<Uint8>(request.color.blue * 255);
240 Uint8 a = static_cast<Uint8>(request.color.alpha * request.alpha * 255);
241
242 SDL_SetTextureColorMod(texture.get_texture(), r, g, b);
243 SDL_SetTextureAlphaMod(texture.get_texture(), a);
244 SDL_SetTextureBlendMode(texture.get_texture(), blend2sdl(request.blend));
245
246 SDL_RendererFlip flip = SDL_FLIP_NONE;
247 if ((request.flip & HORIZONTAL_FLIP) != 0)
248 {
249 flip = static_cast<SDL_RendererFlip>(flip | SDL_FLIP_HORIZONTAL);
250 }
251
252 if ((request.flip & VERTICAL_FLIP) != 0)
253 {
254 flip = static_cast<SDL_RendererFlip>(flip | SDL_FLIP_VERTICAL);
255 }
256
257 RenderCopyEx(m_sdl_renderer, texture.get_texture(),
258 &src_rect, &dst_rect,
259 static_cast<double>(request.angles[i]), nullptr, flip,
260 texture.get_sampler());
261 }
262}
263
264void
265SDLPainter::draw_gradient(const GradientRequest& request)
266{
267 const Color& top = request.top;
268 const Color& bottom = request.bottom;
269 const GradientDirection& direction = request.direction;
270 const Rectf& region = request.region;
271
272 // calculate the maximum number of steps needed for the gradient
273 int n = static_cast<int>(std::max(std::max(fabsf(top.red - bottom.red),
274 fabsf(top.green - bottom.green)),
275 std::max(fabsf(top.blue - bottom.blue),
276 fabsf(top.alpha - bottom.alpha))) * 255);
277 n = std::max(n, 1);
278 for (int i = 0; i < n; ++i)
279 {
280 SDL_Rect rect;
281 if (direction == VERTICAL || direction == VERTICAL_SECTOR)
282 {
283 rect.x = static_cast<int>(region.get_left());
284 rect.y = static_cast<int>(region.get_bottom() * static_cast<float>(i) / static_cast<float>(n));
285 rect.w = static_cast<int>(region.get_right());
286 rect.h = static_cast<int>((region.get_bottom() * static_cast<float>(i+1) / static_cast<float>(n)) - static_cast<float>(rect.y));
287 }
288 else
289 {
290 rect.x = static_cast<int>(region.get_right() * static_cast<float>(i) / static_cast<float>(n));
291 rect.y = static_cast<int>(region.get_top());
292 rect.w = static_cast<int>((region.get_right() * static_cast<float>(i+1) / static_cast<float>(n)) - static_cast<float>(rect.x));
293 rect.h = static_cast<int>(region.get_bottom());
294 }
295
296 float p = static_cast<float>(i+1) / static_cast<float>(n);
297 Uint8 r, g, b, a;
298
299 if ( direction == HORIZONTAL_SECTOR || direction == VERTICAL_SECTOR)
300 {
301 float begin_percentage = region.get_left() * -1 / region.get_right();
302 r = static_cast<Uint8>(((1.0f - begin_percentage - p) * top.red + (p + begin_percentage) * bottom.red) * 255);
303 g = static_cast<Uint8>(((1.0f - begin_percentage - p) * top.green + (p + begin_percentage) * bottom.green) * 255);
304 b = static_cast<Uint8>(((1.0f - begin_percentage - p) * top.blue + (p + begin_percentage) * bottom.blue) * 255);
305 a = static_cast<Uint8>(((1.0f - begin_percentage - p) * top.alpha + (p + begin_percentage) * bottom.alpha) * 255);
306 }
307 else
308 {
309 r = static_cast<Uint8>(((1.0f - p) * top.red + p * bottom.red) * 255);
310 g = static_cast<Uint8>(((1.0f - p) * top.green + p * bottom.green) * 255);
311 b = static_cast<Uint8>(((1.0f - p) * top.blue + p * bottom.blue) * 255);
312 a = static_cast<Uint8>(((1.0f - p) * top.alpha + p * bottom.alpha) * 255);
313 }
314
315 SDL_SetRenderDrawBlendMode(m_sdl_renderer, blend2sdl(request.blend));
316 SDL_SetRenderDrawColor(m_sdl_renderer, r, g, b, a);
317 SDL_RenderFillRect(m_sdl_renderer, &rect);
318 }
319}
320
321void
322SDLPainter::draw_filled_rect(const FillRectRequest& request)
323{
324 SDL_Rect rect = to_sdl_rect(request.rect);
325
326 Uint8 r = static_cast<Uint8>(request.color.red * 255);
327 Uint8 g = static_cast<Uint8>(request.color.green * 255);
328 Uint8 b = static_cast<Uint8>(request.color.blue * 255);
329 Uint8 a = static_cast<Uint8>(request.color.alpha * 255);
330
331 int radius = std::min(std::min(rect.h / 2, rect.w / 2),
332 static_cast<int>(request.radius));
333
334 if (radius)
335 {
336 int slices = radius;
337
338 // rounded top and bottom parts
339 std::vector<SDL_Rect> rects;
340 rects.reserve(2*slices + 1);
341 for (int i = 0; i < slices; ++i)
342 {
343 float p = (static_cast<float>(i) + 0.5f) / static_cast<float>(slices);
344 int xoff = radius - static_cast<int>(sqrtf(1.0f - p * p) * static_cast<float>(radius));
345
346 SDL_Rect tmp;
347 tmp.x = rect.x + xoff;
348 tmp.y = rect.y + (radius - i);
349 tmp.w = rect.w - 2*(xoff);
350 tmp.h = 1;
351 rects.push_back(tmp);
352
353 SDL_Rect tmp2;
354 tmp2.x = rect.x + xoff;
355 tmp2.y = rect.y + rect.h - radius + i;
356 tmp2.w = rect.w - 2*xoff;
357 tmp2.h = 1;
358
359 if (tmp2.y != tmp.y)
360 {
361 rects.push_back(tmp2);
362 }
363 }
364
365 if (2*radius < rect.h)
366 {
367 // center rectangle
368 SDL_Rect tmp;
369 tmp.x = rect.x;
370 tmp.y = rect.y + radius + 1;
371 tmp.w = rect.w;
372 tmp.h = rect.h - 2*radius - 1;
373 rects.push_back(tmp);
374 }
375
376 SDL_SetRenderDrawBlendMode(m_sdl_renderer, SDL_BLENDMODE_BLEND);
377 SDL_SetRenderDrawColor(m_sdl_renderer, r, g, b, a);
378 SDL_RenderFillRects(m_sdl_renderer, &*rects.begin(), static_cast<int>(rects.size()));
379 }
380 else
381 {
382 if ((rect.w != 0) && (rect.h != 0))
383 {
384 SDL_SetRenderDrawBlendMode(m_sdl_renderer, SDL_BLENDMODE_BLEND);
385 SDL_SetRenderDrawColor(m_sdl_renderer, r, g, b, a);
386 SDL_RenderFillRect(m_sdl_renderer, &rect);
387 }
388 }
389}
390
391void
392SDLPainter::draw_inverse_ellipse(const InverseEllipseRequest& request)
393{
394 float x = request.pos.x;
395 float w = request.size.x;
396 float h = request.size.y;
397
398 int top = static_cast<int>(request.pos.y - (h / 2));
399
400 const Viewport& viewport = m_video_system.get_viewport();
401
402 const int max_slices = 256;
403 SDL_Rect rects[2*max_slices+2];
404 int slices = std::min(static_cast<int>(request.size.y), max_slices);
405 for (int i = 0; i < slices; ++i)
406 {
407 float p = ((static_cast<float>(i) + 0.5f) / static_cast<float>(slices)) * 2.0f - 1.0f;
408 int xoff = static_cast<int>(sqrtf(1.0f - p*p) * w / 2);
409
410 SDL_Rect& left = rects[2*i+0];
411 SDL_Rect& right = rects[2*i+1];
412
413 left.x = 0;
414 left.y = top + (i * static_cast<int>(h) / slices);
415 left.w = static_cast<int>(x) - xoff;
416 left.h = top + ((i+1) * static_cast<int>(h) / slices) - left.y;
417
418 right.x = static_cast<int>(x) + xoff;
419 right.y = left.y;
420 right.w = viewport.get_screen_width() - right.x;
421 right.h = left.h;
422 }
423
424 SDL_Rect& top_rect = rects[2*slices+0];
425 SDL_Rect& bottom_rect = rects[2*slices+1];
426
427 top_rect.x = 0;
428 top_rect.y = 0;
429 top_rect.w = viewport.get_screen_width();
430 top_rect.h = top;
431
432 bottom_rect.x = 0;
433 bottom_rect.y = top + static_cast<int>(h);
434 bottom_rect.w = viewport.get_screen_width();
435 bottom_rect.h = viewport.get_screen_height() - bottom_rect.y;
436
437 Uint8 r = static_cast<Uint8>(request.color.red * 255);
438 Uint8 g = static_cast<Uint8>(request.color.green * 255);
439 Uint8 b = static_cast<Uint8>(request.color.blue * 255);
440 Uint8 a = static_cast<Uint8>(request.color.alpha * 255);
441
442 SDL_SetRenderDrawBlendMode(m_sdl_renderer, SDL_BLENDMODE_BLEND);
443 SDL_SetRenderDrawColor(m_sdl_renderer, r, g, b, a);
444 SDL_RenderFillRects(m_sdl_renderer, rects, 2*slices+2);
445}
446
447void
448SDLPainter::draw_line(const LineRequest& request)
449{
450 Uint8 r = static_cast<Uint8>(request.color.red * 255);
451 Uint8 g = static_cast<Uint8>(request.color.green * 255);
452 Uint8 b = static_cast<Uint8>(request.color.blue * 255);
453 Uint8 a = static_cast<Uint8>(request.color.alpha * 255);
454
455 int x1 = static_cast<int>(request.pos.x);
456 int y1 = static_cast<int>(request.pos.y);
457 int x2 = static_cast<int>(request.dest_pos.x);
458 int y2 = static_cast<int>(request.dest_pos.y);
459
460 SDL_SetRenderDrawBlendMode(m_sdl_renderer, SDL_BLENDMODE_BLEND);
461 SDL_SetRenderDrawColor(m_sdl_renderer, r, g, b, a);
462 SDL_RenderDrawLine(m_sdl_renderer, x1, y1, x2, y2);
463}
464
465namespace {
466
467Rectf
468make_edge(int x1, int y1, int x2, int y2)
469{
470 if (y1 < y2)
471 {
472 return Rectf(Vector(static_cast<float>(x1), static_cast<float>(y1)),
473 Vector(static_cast<float>(x2), static_cast<float>(y2)));
474 }
475 else
476 {
477 return Rectf(Vector(static_cast<float>(x2), static_cast<float>(y2)),
478 Vector(static_cast<float>(x1), static_cast<float>(y1)));
479 }
480}
481
482void
483draw_span_between_edges(SDL_Renderer* renderer, const Rectf& e1, const Rectf& e2)
484{
485 // calculate difference between the y coordinates
486 // of the first edge and return if 0
487 float e1ydiff = static_cast<float>(e1.get_bottom() - e1.get_top());
488 if (e1ydiff == 0.0f)
489 return;
490
491 // calculate difference between the y coordinates
492 // of the second edge and return if 0
493 float e2ydiff = static_cast<float>(e2.get_bottom() - e2.get_top());
494 if (e2ydiff == 0.0f)
495 return;
496
497 float e1xdiff = e1.get_right() - e1.get_left();
498 float e2xdiff = e2.get_right() - e2.get_left();
499 float factor1 = (e2.get_top() - e1.get_top()) / e1ydiff;
500 float factorStep1 = 1.0f / e1ydiff;
501 float factor2 = 0.0f;
502 float factorStep2 = 1.0f / e2ydiff;
503
504 for (int y = static_cast<int>(e2.get_top()); y < static_cast<int>(e2.get_bottom()); y++) {
505 SDL_RenderDrawLine(renderer,
506 static_cast<int>(e1.get_left() + e1xdiff * factor1), y,
507 static_cast<int>(e2.get_left() + e2xdiff * factor2), y);
508 factor1 += factorStep1;
509 factor2 += factorStep2;
510 }
511}
512
513} //namespace
514
515void
516SDLPainter::draw_triangle(const TriangleRequest& request)
517{
518 Uint8 r = static_cast<Uint8>(request.color.red * 255);
519 Uint8 g = static_cast<Uint8>(request.color.green * 255);
520 Uint8 b = static_cast<Uint8>(request.color.blue * 255);
521 Uint8 a = static_cast<Uint8>(request.color.alpha * 255);
522
523 int x1 = static_cast<int>(request.pos1.x);
524 int y1 = static_cast<int>(request.pos1.y);
525 int x2 = static_cast<int>(request.pos2.x);
526 int y2 = static_cast<int>(request.pos2.y);
527 int x3 = static_cast<int>(request.pos3.x);
528 int y3 = static_cast<int>(request.pos3.y);
529
530 Rectf edges[3];
531 edges[0] = make_edge(x1, y1, x2, y2);
532 edges[1] = make_edge(x2, y2, x3, y3);
533 edges[2] = make_edge(x3, y3, x1, y1);
534
535 int maxLength = 0;
536 int longEdge = 0;
537
538 // find edge with the greatest length in the y axis
539 for (int i = 0; i < 3; i++) {
540 int length = static_cast<int>(edges[i].get_bottom() - edges[i].get_top());
541 if (length > maxLength) {
542 maxLength = length;
543 longEdge = i;
544 }
545 }
546 int shortEdge1 = (longEdge + 1) % 3;
547 int shortEdge2 = (longEdge + 2) % 3;
548
549 SDL_SetRenderDrawBlendMode(m_sdl_renderer, SDL_BLENDMODE_BLEND);
550 SDL_SetRenderDrawColor(m_sdl_renderer, r, g, b, a);
551
552 draw_span_between_edges(m_sdl_renderer, edges[longEdge], edges[shortEdge1]);
553 draw_span_between_edges(m_sdl_renderer, edges[longEdge], edges[shortEdge2]);
554}
555
556void
557SDLPainter::clear(const Color& color)
558{
559 SDL_SetRenderDrawColor(m_sdl_renderer, color.r8(), color.g8(), color.b8(), color.a8());
560
561 if (m_cliprect)
562 {
563 SDL_SetRenderDrawBlendMode(m_sdl_renderer, SDL_BLENDMODE_NONE);
564 SDL_RenderFillRect(m_sdl_renderer, &*m_cliprect);
565 }
566 else
567 {
568 // This ignores the cliprect:
569 SDL_RenderClear(m_sdl_renderer);
570 }
571}
572
573void
574SDLPainter::set_clip_rect(const Rect& rect)
575{
576 m_cliprect = SDL_Rect{ rect.left,
577 rect.top,
578 rect.get_width(),
579 rect.get_height() };
580
581 int ret = SDL_RenderSetClipRect(m_sdl_renderer, &*m_cliprect);
582 if (ret < 0)
583 {
584 log_warning << "SDLPainter::set_clip_rect(): SDL_RenderSetClipRect() failed: " << SDL_GetError() << std::endl;
585 }
586}
587
588void
589SDLPainter::clear_clip_rect()
590{
591 m_cliprect.reset();
592
593 int ret = SDL_RenderSetClipRect(m_sdl_renderer, nullptr);
594 if (ret < 0)
595 {
596 log_warning << "SDLPainter::clear_clip_rect(): SDL_RenderSetClipRect() failed: " << SDL_GetError() << std::endl;
597 }
598}
599
600void
601SDLPainter::get_pixel(const GetPixelRequest& request) const
602{
603 const Rect& rect = m_renderer.get_rect();
604 const Size& logical_size = m_renderer.get_logical_size();
605
606 SDL_Rect srcrect;
607 srcrect.x = rect.left + static_cast<int>(request.pos.x * static_cast<float>(rect.get_width()) / static_cast<float>(logical_size.width));
608 srcrect.y = rect.top + static_cast<int>(request.pos.y * static_cast<float>(rect.get_height()) / static_cast<float>(logical_size.height));
609 srcrect.w = 1;
610 srcrect.h = 1;
611
612 Uint8 pixel[4];
613 int ret = SDL_RenderReadPixels(m_sdl_renderer, &srcrect,
614 SDL_PIXELFORMAT_RGB888,
615 pixel,
616 1);
617 if (ret != 0)
618 {
619 log_warning << "failed to read pixels: " << SDL_GetError() << std::endl;
620 }
621
622 *(request.color_ptr) = Color::from_rgb888(pixel[2], pixel[1], pixel[0]);
623}
624
625/* EOF */
626