X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fvideo%2Fsdl%2Fsdl_renderer.cpp;h=38cd046d61913c149e14285b896111c5dcfd9bec;hb=636ab5c26242dce0072e3944878ea2750965a343;hp=6d6a357a5ce2a1d1083fdda52e7892243159c947;hpb=df9768e9b68682b60942fa49fc044fbcbf4253e6;p=supertux.git diff --git a/src/video/sdl/sdl_renderer.cpp b/src/video/sdl/sdl_renderer.cpp index 6d6a357a5..38cd046d6 100644 --- a/src/video/sdl/sdl_renderer.cpp +++ b/src/video/sdl/sdl_renderer.cpp @@ -1,5 +1,6 @@ // SuperTux // Copyright (C) 2006 Matthias Braun +// Updated by GiBy 2013 for SDL2 // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -16,6 +17,7 @@ #include "video/sdl/sdl_renderer.hpp" +#include "util/log.hpp" #include "video/drawing_request.hpp" #include "video/sdl/sdl_surface_data.hpp" #include "video/sdl/sdl_texture.hpp" @@ -25,6 +27,7 @@ #include #include #include +#include "SDL2/SDL_video.h" namespace { @@ -111,37 +114,46 @@ SDL_Surface *apply_alpha(SDL_Surface *src, float alpha_factor) } // namespace SDLRenderer::SDLRenderer() : - screen(), + window(), + renderer(), numerator(), denominator() { Renderer::instance_ = this; - const SDL_VideoInfo *info = SDL_GetVideoInfo(); - log_info << "Hardware surfaces are " << (info->hw_available ? "" : "not ") << "available." << std::endl; - log_info << "Hardware to hardware blits are " << (info->blit_hw ? "" : "not ") << "accelerated." << std::endl; - log_info << "Hardware to hardware blits with colorkey are " << (info->blit_hw_CC ? "" : "not ") << "accelerated." << std::endl; - log_info << "Hardware to hardware blits with alpha are " << (info->blit_hw_A ? "" : "not ") << "accelerated." << std::endl; - log_info << "Software to hardware blits are " << (info->blit_sw ? "" : "not ") << "accelerated." << std::endl; - log_info << "Software to hardware blits with colorkey are " << (info->blit_sw_CC ? "" : "not ") << "accelerated." << std::endl; - log_info << "Software to hardware blits with alpha are " << (info->blit_sw_A ? "" : "not ") << "accelerated." << std::endl; - log_info << "Color fills are " << (info->blit_fill ? "" : "not ") << "accelerated." << std::endl; - - int flags = SDL_SWSURFACE | SDL_ANYFORMAT; - if(g_config->use_fullscreen) - flags |= SDL_FULLSCREEN; + // Cannot currently find a way to do this with SDL2 + //const SDL_VideoInfo *info = SDL_GetVideoInfo(); + //log_info << "Hardware surfaces are " << (info->hw_available ? "" : "not ") << "available." << std::endl; + //log_info << "Hardware to hardware blits are " << (info->blit_hw ? "" : "not ") << "accelerated." << std::endl; + //log_info << "Hardware to hardware blits with colorkey are " << (info->blit_hw_CC ? "" : "not ") << "accelerated." << std::endl; + //log_info << "Hardware to hardware blits with alpha are " << (info->blit_hw_A ? "" : "not ") << "accelerated." << std::endl; + //log_info << "Software to hardware blits are " << (info->blit_sw ? "" : "not ") << "accelerated." << std::endl; + //log_info << "Software to hardware blits with colorkey are " << (info->blit_sw_CC ? "" : "not ") << "accelerated." << std::endl; + //log_info << "Software to hardware blits with alpha are " << (info->blit_sw_A ? "" : "not ") << "accelerated." << std::endl; + //log_info << "Color fills are " << (info->blit_fill ? "" : "not ") << "accelerated." << std::endl; + + // int flags = SDL_SWSURFACE | SDL_ANYFORMAT; + // if(g_config->use_fullscreen) + // flags |= SDL_FULLSCREEN; + log_info << "creating SDLRenderer" << std::endl; int width = 800; //FIXME: config->screenwidth; int height = 600; //FIXME: config->screenheight; + int flags = 0; + int ret = SDL_CreateWindowAndRenderer(width, height, flags, + &window, &renderer); - screen = SDL_SetVideoMode(width, height, 0, flags); - if(screen == 0) { + if(ret != 0) { std::stringstream msg; msg << "Couldn't set video mode (" << width << "x" << height << "): " << SDL_GetError(); throw std::runtime_error(msg.str()); } + SDL_SetWindowTitle(window, "SuperTux"); + if(texture_manager == 0) + texture_manager = new TextureManager(); +#ifdef OLD_SDL1 numerator = 1; denominator = 1; /* FIXME: @@ -158,12 +170,13 @@ SDLRenderer::SDLRenderer() : denominator = SCREEN_HEIGHT; } */ - if(texture_manager == 0) - texture_manager = new TextureManager(); +#endif } SDLRenderer::~SDLRenderer() { + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); } void @@ -172,6 +185,37 @@ SDLRenderer::draw_surface(const DrawingRequest& request) //FIXME: support parameters request.alpha, request.angle, request.blend const Surface* surface = (const Surface*) request.request_data; boost::shared_ptr sdltexture = boost::dynamic_pointer_cast(surface->get_texture()); + + SDL_Rect dst_rect; + dst_rect.x = request.pos.x; + dst_rect.y = request.pos.y; + dst_rect.w = sdltexture->get_image_width(); + dst_rect.h = sdltexture->get_image_height(); + + if (surface->get_flipx()) + { + SDL_RenderCopyEx(renderer, sdltexture->get_texture(), NULL, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL); + } + else + { + switch(request.drawing_effect) + { + case VERTICAL_FLIP: + SDL_RenderCopyEx(renderer, sdltexture->get_texture(), NULL, &dst_rect, 0, NULL, SDL_FLIP_VERTICAL); + break; + + case HORIZONTAL_FLIP: + SDL_RenderCopyEx(renderer, sdltexture->get_texture(), NULL, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL); + break; + + default: + case NO_EFFECT: + SDL_RenderCopy(renderer, sdltexture->get_texture(), NULL, &dst_rect); + break; + } + } + +#ifdef OLD_SDL1 SDLSurfaceData *surface_data = reinterpret_cast(surface->get_surface_data()); DrawingEffect effect = request.drawing_effect; @@ -203,7 +247,7 @@ SDLRenderer::draw_surface(const DrawingRequest& request) { alpha = 255; } - SDL_SetAlpha(transform, SDL_SRCALPHA, (Uint8) (request.alpha * alpha)); + SDL_SetSurfaceAlphaMod(transform, (Uint8) (request.alpha * alpha)); } /*else { @@ -219,11 +263,11 @@ SDLRenderer::draw_surface(const DrawingRequest& request) { if(alpha == 255) { - SDL_SetAlpha(transform, SDL_RLEACCEL, 0); + SDL_SetSurfaceAlphaMod(transform, 0); } else { - SDL_SetAlpha(transform, SDL_SRCALPHA | SDL_RLEACCEL, alpha); + SDL_SetSurfaceAlphaMod(transform, alpha); } } /*else @@ -231,11 +275,54 @@ SDLRenderer::draw_surface(const DrawingRequest& request) SDL_FreeSurface(transform); }*/ } +#endif } void SDLRenderer::draw_surface_part(const DrawingRequest& request) { + //FIXME: support parameters request.alpha, request.angle, request.blend + const SurfacePartRequest* surface = (const SurfacePartRequest*) request.request_data; + const SurfacePartRequest* surfacepartrequest = (SurfacePartRequest*) request.request_data; + + boost::shared_ptr sdltexture = boost::dynamic_pointer_cast(surface->surface->get_texture()); + + SDL_Rect src_rect; + src_rect.x = surfacepartrequest->source.x; + src_rect.y = surfacepartrequest->source.y; + src_rect.w = surfacepartrequest->size.x; + src_rect.h = surfacepartrequest->size.y; + + SDL_Rect dst_rect; + dst_rect.x = request.pos.x; + dst_rect.y = request.pos.y; + dst_rect.w = surfacepartrequest->size.x; + dst_rect.h = surfacepartrequest->size.y; + + if (surface->surface->get_flipx()) + { + SDL_RenderCopyEx(renderer, sdltexture->get_texture(), &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL); + } + else + { + switch(request.drawing_effect) + { + case VERTICAL_FLIP: + SDL_RenderCopyEx(renderer, sdltexture->get_texture(), &src_rect, &dst_rect, 0, NULL, SDL_FLIP_VERTICAL); + break; + + case HORIZONTAL_FLIP: + SDL_RenderCopyEx(renderer, sdltexture->get_texture(), &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL); + break; + + default: + case NO_EFFECT: + SDL_RenderCopy(renderer, sdltexture->get_texture(), &src_rect, &dst_rect); + break; + } + } + +#ifdef OLD_SDL1 const SurfacePartRequest* surfacepartrequest = (SurfacePartRequest*) request.request_data; @@ -294,27 +381,31 @@ SDLRenderer::draw_surface_part(const DrawingRequest& request) { alpha = 255; } - SDL_SetAlpha(transform, SDL_SRCALPHA, (Uint8) (request.alpha * alpha)); + SDL_SetSurfaceAlphaMod(transform, (Uint8) (request.alpha * alpha)); } /*else { transform = apply_alpha(transform, request.alpha); }*/ } +#endif +#ifdef OLD_SDL1 SDL_BlitSurface(transform, &src_rect, screen, &dst_rect); +#endif +#ifdef OLD_SDL1 if(request.alpha != 1.0) { if(!transform->format->Amask) { if(alpha == 255) { - SDL_SetAlpha(transform, SDL_RLEACCEL, 0); + SDL_SetSurfaceAlphaMod(transform, 0); } else { - SDL_SetAlpha(transform, SDL_SRCALPHA | SDL_RLEACCEL, alpha); + SDL_SetSurfaceAlphaMod(transform, alpha); } } /*else @@ -322,6 +413,7 @@ SDLRenderer::draw_surface_part(const DrawingRequest& request) SDL_FreeSurface(transform); }*/ } +#endif } void @@ -332,6 +424,40 @@ SDLRenderer::draw_gradient(const DrawingRequest& request) const Color& top = gradientrequest->top; const Color& bottom = gradientrequest->bottom; + int w; + int h; + SDL_GetWindowSize(window, &w, &h); + + // calculate the maximum number of steps needed for the gradient + int n = static_cast(std::max(std::max(fabsf(top.red - bottom.red), + fabsf(top.green - bottom.green)), + std::max(fabsf(top.blue - bottom.blue), + fabsf(top.alpha - bottom.alpha))) * 255); + for(int i = 0; i < n; ++i) + { + SDL_Rect rect; + rect.x = 0; + rect.y = h * i / n; + rect.w = w; + rect.h = (h * (i+1) / n) - rect.y; + + float p = static_cast(i+1) / static_cast(n); + Uint8 r = static_cast(((1.0f - p) * top.red + p * bottom.red) * 255); + Uint8 g = static_cast(((1.0f - p) * top.green + p * bottom.green) * 255); + Uint8 b = static_cast(((1.0f - p) * top.blue + p * bottom.blue) * 255); + Uint8 a = static_cast(((1.0f - p) * top.alpha + p * bottom.alpha) * 255); + + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(renderer, r, g, b, a); + SDL_RenderFillRect(renderer, &rect); + } + +#ifdef OLD_SDL1 + const GradientRequest* gradientrequest + = (GradientRequest*) request.request_data; + const Color& top = gradientrequest->top; + const Color& bottom = gradientrequest->bottom; + for(int y = 0;y < screen->h;++y) { Uint8 r = (Uint8)((((float)(top.red-bottom.red)/(0-screen->h)) * y + top.red) * 255); @@ -352,11 +478,12 @@ SDLRenderer::draw_gradient(const DrawingRequest& request) SDL_Surface *temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask); SDL_FillRect(temp, 0, color); - SDL_SetAlpha(temp, SDL_SRCALPHA | SDL_RLEACCEL, a); + SDL_SetSurfaceAlphaMod(temp, a); SDL_BlitSurface(temp, 0, screen, &rect); SDL_FreeSurface(temp); } } +#endif } void @@ -366,10 +493,86 @@ SDLRenderer::draw_filled_rect(const DrawingRequest& request) = (FillRectRequest*) request.request_data; SDL_Rect rect; + rect.x = request.pos.x; + rect.y = request.pos.y; + rect.w = fillrectrequest->size.x; + rect.h = fillrectrequest->size.y; + + Uint8 r = static_cast(fillrectrequest->color.red * 255); + Uint8 g = static_cast(fillrectrequest->color.green * 255); + Uint8 b = static_cast(fillrectrequest->color.blue * 255); + Uint8 a = static_cast(fillrectrequest->color.alpha * 255); + + int radius = std::min(rect.h / 2, static_cast(fillrectrequest->radius)); + + if (radius) + { + int slices = radius; + + // rounded top and bottom parts + std::vector rects; + rects.reserve(2*slices + 1); + for(int i = 0; i < slices; ++i) + { + float p = (static_cast(i) + 0.5f) / static_cast(slices); + int xoff = radius - static_cast(sqrtf(1.0f - p*p) * radius); + + SDL_Rect tmp; + tmp.x = rect.x + xoff; + tmp.y = rect.y + (radius - i); + tmp.w = rect.w - 2*(xoff); + tmp.h = 1; + rects.push_back(tmp); + + SDL_Rect tmp2; + tmp2.x = rect.x + xoff; + tmp2.y = rect.y + rect.h - radius + i; + tmp2.w = rect.w - 2*xoff; + tmp2.h = 1; + + if (tmp2.y != tmp.y) + { + rects.push_back(tmp2); + } + } + + if (2*radius < rect.h) + { + // center rectangle + SDL_Rect tmp; + tmp.x = rect.x; + tmp.y = rect.y + radius + 1; + tmp.w = rect.w; + tmp.h = rect.h - 2*radius - 1; + rects.push_back(tmp); + } + + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(renderer, r, g, b, a); + SDL_RenderFillRects(renderer, &*rects.begin(), rects.size()); + } + else + { + if((rect.w != 0) && (rect.h != 0)) + { + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(renderer, r, g, b, a); + SDL_RenderFillRect(renderer, &rect); + } + } + +#ifdef OLD_SDL1 + const FillRectRequest* fillrectrequest + = (FillRectRequest*) request.request_data; + + SDL_Rect rect; rect.x = (Sint16)request.pos.x * screen->w / SCREEN_WIDTH; rect.y = (Sint16)request.pos.y * screen->h / SCREEN_HEIGHT; rect.w = (Uint16)fillrectrequest->size.x * screen->w / SCREEN_WIDTH; rect.h = (Uint16)fillrectrequest->size.y * screen->h / SCREEN_HEIGHT; + if((rect.w == 0) || (rect.h == 0)) { + return; + } Uint8 r = static_cast(fillrectrequest->color.red * 255); Uint8 g = static_cast(fillrectrequest->color.green * 255); Uint8 b = static_cast(fillrectrequest->color.blue * 255); @@ -381,50 +584,143 @@ SDLRenderer::draw_filled_rect(const DrawingRequest& request) SDL_Surface *temp = SDL_CreateRGBSurface(screen->flags, rect.w, rect.h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask); SDL_FillRect(temp, 0, color); - SDL_SetAlpha(temp, SDL_SRCALPHA | SDL_RLEACCEL, a); + SDL_SetSurfaceAlphaMod(temp, a); SDL_BlitSurface(temp, 0, screen, &rect); SDL_FreeSurface(temp); } +#endif } void -SDLRenderer::draw_inverse_ellipse(const DrawingRequest&) +SDLRenderer::draw_inverse_ellipse(const DrawingRequest& request) { + const InverseEllipseRequest* ellipse = (InverseEllipseRequest*)request.request_data; + + int window_w; + int window_h; + SDL_GetWindowSize(window, &window_w, &window_h); + + float x = request.pos.x; + float w = ellipse->size.x; + float h = ellipse->size.y; + + int top = request.pos.y - (h / 2); + + const int max_slices = 256; + SDL_Rect rects[2*max_slices+2]; + int slices = std::min(static_cast(ellipse->size.y), max_slices); + for(int i = 0; i < slices; ++i) + { + float p = ((static_cast(i) + 0.5f) / static_cast(slices)) * 2.0f - 1.0f; + int xoff = static_cast(sqrtf(1.0f - p*p) * w / 2); + + SDL_Rect& left = rects[2*i+0]; + SDL_Rect& right = rects[2*i+1]; + + left.x = 0; + left.y = top + (i * h / slices); + left.w = x - xoff; + left.h = (top + ((i+1) * h / slices)) - left.y; + + right.x = x + xoff; + right.y = left.y; + right.w = window_w - right.x; + right.h = left.h; + } + + SDL_Rect& top_rect = rects[2*slices+0]; + SDL_Rect& bottom_rect = rects[2*slices+1]; + + top_rect.x = 0; + top_rect.y = 0; + top_rect.w = window_w; + top_rect.h = top; + + bottom_rect.x = 0; + bottom_rect.y = top + h; + bottom_rect.w = window_w; + bottom_rect.h = window_h - bottom_rect.y; + + Uint8 r = static_cast(ellipse->color.red * 255); + Uint8 g = static_cast(ellipse->color.green * 255); + Uint8 b = static_cast(ellipse->color.blue * 255); + Uint8 a = static_cast(ellipse->color.alpha * 255); + + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(renderer, r, g, b, a); + SDL_RenderFillRects(renderer, rects, 2*slices+2); } void SDLRenderer::do_take_screenshot() { // [Christoph] TODO: Yes, this method also takes care of the actual disk I/O. Split it? - - SDL_Surface *screen = SDL_GetVideoSurface(); - - // save screenshot - static const std::string writeDir = PHYSFS_getWriteDir(); - static const std::string dirSep = PHYSFS_getDirSeparator(); - static const std::string baseName = "screenshot"; - static const std::string fileExt = ".bmp"; - std::string fullFilename; - for (int num = 0; num < 1000; num++) { - std::ostringstream oss; - oss << baseName; - oss << std::setw(3) << std::setfill('0') << num; - oss << fileExt; - std::string fileName = oss.str(); - fullFilename = writeDir + dirSep + fileName; - if (!PHYSFS_exists(fileName.c_str())) { - SDL_SaveBMP(screen, fullFilename.c_str()); - log_debug << "Wrote screenshot to \"" << fullFilename << "\"" << std::endl; - return; + int width; + int height; + if (SDL_GetRendererOutputSize(renderer, &width, &height) != 0) + { + log_warning << "SDL_GetRenderOutputSize failed: " << SDL_GetError() << std::endl; + } + else + { +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + Uint32 rmask = 0xff000000; + Uint32 gmask = 0x00ff0000; + Uint32 bmask = 0x0000ff00; + Uint32 amask = 0x000000ff; +#else + Uint32 rmask = 0x000000ff; + Uint32 gmask = 0x0000ff00; + Uint32 bmask = 0x00ff0000; + Uint32 amask = 0xff000000; +#endif + SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 32, + rmask, gmask, bmask, amask); + if (!surface) + { + log_warning << "SDL_CreateRGBSurface failed: " << SDL_GetError() << std::endl; + } + else + { + int ret = SDL_RenderReadPixels(renderer, NULL, + SDL_PIXELFORMAT_ABGR8888, + surface->pixels, + surface->pitch); + if (ret != 0) + { + log_warning << "SDL_RenderReadPixels failed: " << SDL_GetError() << std::endl; + } + else + { + // save screenshot + static const std::string writeDir = PHYSFS_getWriteDir(); + static const std::string dirSep = PHYSFS_getDirSeparator(); + static const std::string baseName = "screenshot"; + static const std::string fileExt = ".bmp"; + std::string fullFilename; + for (int num = 0; num < 1000; num++) { + std::ostringstream oss; + oss << baseName; + oss << std::setw(3) << std::setfill('0') << num; + oss << fileExt; + std::string fileName = oss.str(); + fullFilename = writeDir + dirSep + fileName; + if (!PHYSFS_exists(fileName.c_str())) { + SDL_SaveBMP(surface, fullFilename.c_str()); + log_debug << "Wrote screenshot to \"" << fullFilename << "\"" << std::endl; + return; + } + } + log_warning << "Did not save screenshot, because all files up to \"" << fullFilename << "\" already existed" << std::endl; + } } } - log_warning << "Did not save screenshot, because all files up to \"" << fullFilename << "\" already existed" << std::endl; } void SDLRenderer::flip() { - SDL_Flip(screen); + SDL_RenderPresent(renderer); } void