/** * \brief Renders the internal texture if any, and all subsurfaces that are * drawn onto it. * \param renderer The renderer where to draw. * \param src_rect The subrectangle of the texture to draw. * \param dst_rect The position where to draw on the renderer. * \param clip_rect A portion of the renderer where to restrict the drawing. * \param opacity The opacity of the parent surface. * \param subsurfaces The subsurfaces drawn onto this texture. They will be * renderered recursively. */ void Surface::render( SDL_Renderer* renderer, const Rectangle& src_rect, const Rectangle& dst_rect, const Rectangle& clip_rect, uint8_t opacity, const std::vector<SubSurfaceNodePtr>& subsurfaces ) { //FIXME SDL_RenderSetClipRect is buggy for now, but should be fixed soon. // It means that software and hardware surface doesn't have the exact same behavior for now. // Uncomment the two lines using it when https://bugzilla.libsdl.org/show_bug.cgi?id=2336 will be solved. // Accelerate the internal software surface. if (internal_surface != nullptr) { if (internal_texture == nullptr) { create_texture_from_surface(); } // If the software surface has changed, update the hardware texture. else if ( (software_destination || !Video::is_acceleration_enabled()) && !is_rendered) { SDL_UpdateTexture( internal_texture.get(), nullptr, internal_surface->pixels, internal_surface->pitch ); SDL_GetSurfaceAlphaMod(internal_surface.get(), &this->opacity); } } const uint8_t current_opacity = std::min(this->opacity, opacity); // Draw the internal color as background color. if (internal_color != nullptr) { uint8_t r, g, b, a; internal_color->get_components(r, g, b, a); SDL_SetRenderDrawColor(renderer, r, g, b, std::min((uint8_t) a, current_opacity)); //SDL_RenderSetClipRect(renderer, clip_rect.get_internal_rect()); SDL_RenderFillRect(renderer, clip_rect.get_internal_rect()); } // Draw the internal texture. if (internal_texture != nullptr) { SDL_SetTextureAlphaMod(internal_texture.get(), current_opacity); //SDL_RenderSetClipRect(renderer, clip_rect.get_internal_rect()); SDL_RenderCopy( renderer, internal_texture.get(), src_rect.get_internal_rect(), dst_rect.get_internal_rect() ); } // The surface is rendered. Now draw all subtextures. for (const SubSurfaceNodePtr& subsurface: subsurfaces) { // subsurface has to be drawn on this surface // Calculate absolute destination subrectangle position on screen. Rectangle subsurface_dst_rect( dst_rect.get_xy() + subsurface->dst_rect.get_xy() - src_rect.get_xy(), subsurface->src_rect.get_size() ); // Set the intersection of the subsurface destination and this surface's clip as clipping rectangle. Rectangle superimposed_clip_rect; if (SDL_IntersectRect(subsurface_dst_rect.get_internal_rect(), clip_rect.get_internal_rect(), superimposed_clip_rect.get_internal_rect())) { // If there is an intersection, render the subsurface. subsurface->src_surface->render( renderer, subsurface->src_rect, subsurface_dst_rect, superimposed_clip_rect, current_opacity, subsurface->subsurfaces ); } } is_rendered = true; }
/** * \brief Renders the internal texture if any, and all subsurfaces that are * drawn onto it. * \param renderer The renderer where to draw. * \param src_rect The subrectangle of the texture to draw. * \param dst_xy The position where to draw on the renderer. * The width and height of this rectangle are ignored. * \param clip_rect A portion of the renderer where to restrict the drawing. * \param opacity The opacity of the parent surface. * \param subsurfaces The subsurfaces drawn onto this texture. They will be * renderered recursively. */ void Surface::render( SDL_Renderer* renderer, const Rectangle& src_rect, const Rectangle& dst_xy, const Rectangle& clip_rect, uint8_t opacity, const std::vector<SubSurfaceNode*>& subsurfaces) { const uint8_t current_opacity = std::min(internal_opacity, opacity); // Accelerate the internal software surface. if (internal_surface != NULL) { if (internal_texture == NULL) { create_texture_from_surface(); } // If the software surface has changed, update the hardware texture. else if ( (software_destination || !Video::is_acceleration_enabled()) && !is_rendered) { convert_software_surface(); SDL_UpdateTexture( internal_texture, NULL, internal_surface->pixels, internal_surface->pitch ); SDL_GetSurfaceAlphaMod(internal_surface, &internal_opacity); } } // Draw the internal color as background color. if (internal_color != NULL) { int r, g, b, a; internal_color->get_components(r, g, b, a); SDL_SetRenderDrawColor(renderer, r, g, b, std::min((uint8_t) a, current_opacity)); //SDL_RenderSetClipRect(renderer, clip_rect.get_internal_rect()); SDL_RenderFillRect(renderer, clip_rect.get_internal_rect()); } // Draw the internal texture. if (internal_texture != NULL) { SDL_SetTextureAlphaMod(internal_texture, current_opacity); //SDL_RenderSetClipRect(renderer, clip_rect.get_internal_rect()); SDL_RenderCopy( renderer, internal_texture, src_rect.get_internal_rect(), dst_xy.get_internal_rect() ); } // The surface is renderered. Now draw all subtextures. std::vector<SubSurfaceNode*>::const_iterator it; const std::vector<SubSurfaceNode*>::const_iterator end = subsurfaces.end(); for (it = subsurfaces.begin(); it != end; ++it) { SubSurfaceNode* subsurface = *it; // subsurface has to be drawn on this surface // Calculate absolute destination subrectangle position on screen. Rectangle subsurface_dst_rect( dst_xy.get_x() + subsurface->dst_rect.get_x() - src_rect.get_x(), dst_xy.get_y() + subsurface->dst_rect.get_y() - src_rect.get_y(), subsurface->src_rect.get_width(), subsurface->src_rect.get_height() ); // Set the intersection of the subsurface destination and this surface's clip as clipping rectangle. Rectangle superimposed_clip_rect; if (SDL_IntersectRect(subsurface_dst_rect.get_internal_rect(), clip_rect.get_internal_rect(), superimposed_clip_rect.get_internal_rect())) { // If there is an intersection, render the subsurface. subsurface->src_surface->render( renderer, subsurface->src_rect, subsurface_dst_rect, superimposed_clip_rect, current_opacity, subsurface->subsurfaces ); } } is_rendered = true; }