2 // Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
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.
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.
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/>.
17 #include "video/sdl/sdl_painter.hpp"
21 #include "util/log.hpp"
22 #include "video/drawing_request.hpp"
23 #include "video/sdl/sdl_texture.hpp"
27 SDL_BlendMode blend2sdl(const Blend& blend)
29 if (blend.sfactor == GL_ONE &&
30 blend.dfactor == GL_ZERO)
32 return SDL_BLENDMODE_NONE;
34 else if (blend.sfactor == GL_SRC_ALPHA &&
35 blend.dfactor == GL_ONE_MINUS_SRC_ALPHA)
37 return SDL_BLENDMODE_BLEND;
39 else if (blend.sfactor == GL_SRC_ALPHA &&
40 blend.dfactor == GL_ONE)
42 return SDL_BLENDMODE_ADD;
44 else if (blend.sfactor == GL_DST_COLOR &&
45 blend.dfactor == GL_ZERO)
47 return SDL_BLENDMODE_MOD;
51 log_warning << "unknown blend mode combinations: sfactor=" << blend.sfactor << " dfactor=" << blend.dfactor << std::endl;
52 return SDL_BLENDMODE_BLEND;
59 SDLPainter::draw_surface(SDL_Renderer* renderer, const DrawingRequest& request)
61 const Surface* surface = static_cast<const SurfaceRequest*>(request.request_data)->surface;
62 std::shared_ptr<SDLTexture> sdltexture = std::dynamic_pointer_cast<SDLTexture>(surface->get_texture());
65 dst_rect.x = request.pos.x;
66 dst_rect.y = request.pos.y;
67 dst_rect.w = sdltexture->get_image_width();
68 dst_rect.h = sdltexture->get_image_height();
70 Uint8 r = static_cast<Uint8>(request.color.red * 255);
71 Uint8 g = static_cast<Uint8>(request.color.green * 255);
72 Uint8 b = static_cast<Uint8>(request.color.blue * 255);
73 Uint8 a = static_cast<Uint8>(request.color.alpha * request.alpha * 255);
74 SDL_SetTextureColorMod(sdltexture->get_texture(), r, g, b);
75 SDL_SetTextureAlphaMod(sdltexture->get_texture(), a);
76 SDL_SetTextureBlendMode(sdltexture->get_texture(), blend2sdl(request.blend));
78 SDL_RendererFlip flip = SDL_FLIP_NONE;
79 if (surface->get_flipx() || request.drawing_effect & HORIZONTAL_FLIP)
81 flip = static_cast<SDL_RendererFlip>(flip | SDL_FLIP_HORIZONTAL);
84 if (request.drawing_effect & VERTICAL_FLIP)
86 flip = static_cast<SDL_RendererFlip>(flip | SDL_FLIP_VERTICAL);
89 SDL_RenderCopyEx(renderer, sdltexture->get_texture(), NULL, &dst_rect, request.angle, NULL, flip);
93 SDLPainter::draw_surface_part(SDL_Renderer* renderer, const DrawingRequest& request)
95 //FIXME: support parameters request.blend
96 const SurfacePartRequest* surface = static_cast<const SurfacePartRequest*>(request.request_data);
97 const SurfacePartRequest* surfacepartrequest = static_cast<SurfacePartRequest*>(request.request_data);
99 std::shared_ptr<SDLTexture> sdltexture = std::dynamic_pointer_cast<SDLTexture>(surface->surface->get_texture());
102 src_rect.x = surfacepartrequest->srcrect.p1.x;
103 src_rect.y = surfacepartrequest->srcrect.p1.y;
104 src_rect.w = surfacepartrequest->srcrect.get_width();
105 src_rect.h = surfacepartrequest->srcrect.get_height();
108 dst_rect.x = request.pos.x;
109 dst_rect.y = request.pos.y;
110 dst_rect.w = surfacepartrequest->dstsize.width;
111 dst_rect.h = surfacepartrequest->dstsize.height;
113 Uint8 r = static_cast<Uint8>(request.color.red * 255);
114 Uint8 g = static_cast<Uint8>(request.color.green * 255);
115 Uint8 b = static_cast<Uint8>(request.color.blue * 255);
116 Uint8 a = static_cast<Uint8>(request.color.alpha * request.alpha * 255);
117 SDL_SetTextureColorMod(sdltexture->get_texture(), r, g, b);
118 SDL_SetTextureAlphaMod(sdltexture->get_texture(), a);
119 SDL_SetTextureBlendMode(sdltexture->get_texture(), blend2sdl(request.blend));
121 SDL_RendererFlip flip = SDL_FLIP_NONE;
122 if (surface->surface->get_flipx() || request.drawing_effect & HORIZONTAL_FLIP)
124 flip = static_cast<SDL_RendererFlip>(flip | SDL_FLIP_HORIZONTAL);
127 if (request.drawing_effect & VERTICAL_FLIP)
129 flip = static_cast<SDL_RendererFlip>(flip | SDL_FLIP_VERTICAL);
132 SDL_RenderCopyEx(renderer, sdltexture->get_texture(), &src_rect, &dst_rect, request.angle, NULL, flip);
136 SDLPainter::draw_gradient(SDL_Renderer* renderer, const DrawingRequest& request)
138 const GradientRequest* gradientrequest
139 = static_cast<GradientRequest*>(request.request_data);
140 const Color& top = gradientrequest->top;
141 const Color& bottom = gradientrequest->bottom;
143 // calculate the maximum number of steps needed for the gradient
144 int n = static_cast<int>(std::max(std::max(fabsf(top.red - bottom.red),
145 fabsf(top.green - bottom.green)),
146 std::max(fabsf(top.blue - bottom.blue),
147 fabsf(top.alpha - bottom.alpha))) * 255);
149 for(int i = 0; i < n; ++i)
153 rect.y = SCREEN_HEIGHT * i / n;
154 rect.w = SCREEN_WIDTH;
155 rect.h = (SCREEN_HEIGHT * (i+1) / n) - rect.y;
157 float p = static_cast<float>(i+1) / static_cast<float>(n);
158 Uint8 r = static_cast<Uint8>(((1.0f - p) * top.red + p * bottom.red) * 255);
159 Uint8 g = static_cast<Uint8>(((1.0f - p) * top.green + p * bottom.green) * 255);
160 Uint8 b = static_cast<Uint8>(((1.0f - p) * top.blue + p * bottom.blue) * 255);
161 Uint8 a = static_cast<Uint8>(((1.0f - p) * top.alpha + p * bottom.alpha) * 255);
163 SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
164 SDL_SetRenderDrawColor(renderer, r, g, b, a);
165 SDL_RenderFillRect(renderer, &rect);
170 SDLPainter::draw_filled_rect(SDL_Renderer* renderer, const DrawingRequest& request)
172 const FillRectRequest* fillrectrequest
173 = static_cast<FillRectRequest*>(request.request_data);
176 rect.x = request.pos.x;
177 rect.y = request.pos.y;
178 rect.w = fillrectrequest->size.x;
179 rect.h = fillrectrequest->size.y;
181 Uint8 r = static_cast<Uint8>(fillrectrequest->color.red * 255);
182 Uint8 g = static_cast<Uint8>(fillrectrequest->color.green * 255);
183 Uint8 b = static_cast<Uint8>(fillrectrequest->color.blue * 255);
184 Uint8 a = static_cast<Uint8>(fillrectrequest->color.alpha * 255);
186 int radius = std::min(std::min(rect.h / 2, rect.w / 2),
187 static_cast<int>(fillrectrequest->radius));
193 // rounded top and bottom parts
194 std::vector<SDL_Rect> rects;
195 rects.reserve(2*slices + 1);
196 for(int i = 0; i < slices; ++i)
198 float p = (static_cast<float>(i) + 0.5f) / static_cast<float>(slices);
199 int xoff = radius - static_cast<int>(sqrtf(1.0f - p*p) * radius);
202 tmp.x = rect.x + xoff;
203 tmp.y = rect.y + (radius - i);
204 tmp.w = rect.w - 2*(xoff);
206 rects.push_back(tmp);
209 tmp2.x = rect.x + xoff;
210 tmp2.y = rect.y + rect.h - radius + i;
211 tmp2.w = rect.w - 2*xoff;
216 rects.push_back(tmp2);
220 if (2*radius < rect.h)
225 tmp.y = rect.y + radius + 1;
227 tmp.h = rect.h - 2*radius - 1;
228 rects.push_back(tmp);
231 SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
232 SDL_SetRenderDrawColor(renderer, r, g, b, a);
233 SDL_RenderFillRects(renderer, &*rects.begin(), rects.size());
237 if((rect.w != 0) && (rect.h != 0))
239 SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
240 SDL_SetRenderDrawColor(renderer, r, g, b, a);
241 SDL_RenderFillRect(renderer, &rect);
247 SDLPainter::draw_inverse_ellipse(SDL_Renderer* renderer, const DrawingRequest& request)
249 const InverseEllipseRequest* ellipse = static_cast<InverseEllipseRequest*>(request.request_data);
251 float x = request.pos.x;
252 float w = ellipse->size.x;
253 float h = ellipse->size.y;
255 int top = request.pos.y - (h / 2);
257 const int max_slices = 256;
258 SDL_Rect rects[2*max_slices+2];
259 int slices = std::min(static_cast<int>(ellipse->size.y), max_slices);
260 for(int i = 0; i < slices; ++i)
262 float p = ((static_cast<float>(i) + 0.5f) / static_cast<float>(slices)) * 2.0f - 1.0f;
263 int xoff = static_cast<int>(sqrtf(1.0f - p*p) * w / 2);
265 SDL_Rect& left = rects[2*i+0];
266 SDL_Rect& right = rects[2*i+1];
269 left.y = top + (i * h / slices);
271 left.h = (top + ((i+1) * h / slices)) - left.y;
275 right.w = SCREEN_WIDTH - right.x;
279 SDL_Rect& top_rect = rects[2*slices+0];
280 SDL_Rect& bottom_rect = rects[2*slices+1];
284 top_rect.w = SCREEN_WIDTH;
288 bottom_rect.y = top + h;
289 bottom_rect.w = SCREEN_WIDTH;
290 bottom_rect.h = SCREEN_HEIGHT - bottom_rect.y;
292 Uint8 r = static_cast<Uint8>(ellipse->color.red * 255);
293 Uint8 g = static_cast<Uint8>(ellipse->color.green * 255);
294 Uint8 b = static_cast<Uint8>(ellipse->color.blue * 255);
295 Uint8 a = static_cast<Uint8>(ellipse->color.alpha * 255);
297 SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
298 SDL_SetRenderDrawColor(renderer, r, g, b, a);
299 SDL_RenderFillRects(renderer, rects, 2*slices+2);