/** * \brief Clears this surface. * * The surface becomes fully transparent and its size remains unchanged. * The opacity property of the surface is preserved. */ void Surface::clear() { clear_subsurfaces(); delete internal_color; internal_color = NULL; if (internal_texture != NULL) { SDL_DestroyTexture(internal_texture); internal_texture = NULL; } if (internal_surface != NULL) { if (software_destination) { SDL_FillRect( internal_surface, NULL, Color::get_transparent().get_internal_value() ); } else { SDL_FreeSurface(internal_surface); internal_surface = NULL; } } }
/** * \brief Add a SubSurface to draw on this surface. * \param src_surface The Surface to draw. * \param region The subrectangle to draw in the source surface. * \param dst_position Coordinates on this surface. */ void Surface::add_subsurface( const SurfacePtr& src_surface, const Rectangle& region, const Point& dst_position) { SubSurfaceNodePtr node(new SubSurfaceNode( src_surface, region, Rectangle(dst_position), src_surface->subsurfaces )); // Clear the subsurface queue if the current dst_surface has already been rendered. if (is_rendered) { clear_subsurfaces(); } subsurfaces.push_back(node); }
/** * \brief Add a SubSurface to draw on this surface. * \param src_surface The Surface to draw. * \param region The subrectangle to draw in the source surface. * \param dst_position Coordinates on this surface. * The width and height of this rectangle are ignored. */ void Surface::add_subsurface( Surface& src_surface, const Rectangle& region, const Rectangle& dst_position) { SubSurfaceNode* node = new SubSurfaceNode( &src_surface, region, dst_position, src_surface.subsurfaces ); RefCountable::ref(node); // Clear the subsurface queue if the current dst_surface has already been rendered. if (is_rendered) { clear_subsurfaces(); } subsurfaces.push_back(node); }
/** * \brief Clears this surface. * * The surface becomes fully transparent and its size remains unchanged. * The opacity property of the surface is preserved. */ void Surface::clear() { clear_subsurfaces(); internal_color = nullptr; if (internal_texture != nullptr) { internal_texture = nullptr; } if (internal_surface != nullptr) { if (software_destination) { SDL_FillRect( internal_surface.get(), nullptr, get_color_value(Color::transparent) ); } else { internal_surface = nullptr; } } }
/** * \brief Draws a subrectangle of this surface on another surface. * \param region The subrectangle to draw in this object. * \param dst_surface The destination surface. * \param dst_position Coordinates on the destination surface. */ void Surface::raw_draw_region( const Rectangle& region, Surface& dst_surface, const Point& dst_position) { if (dst_surface.software_destination // The destination surface is in RAM. || !Video::is_acceleration_enabled() // The rendering is in RAM. ) { if (dst_surface.internal_surface == nullptr) { dst_surface.create_software_surface(); } // First, draw subsurfaces if any. // They can exist if the video mode recently switched from an accelerated // one to a software one. if (!subsurfaces.empty()) { if (this->internal_surface == nullptr) { create_software_surface(); } std::vector<SubSurfaceNodePtr> subsurfaces = this->subsurfaces; this->subsurfaces.clear(); // Avoid infinite recursive calls if there are cycles. for (SubSurfaceNodePtr& subsurface: subsurfaces) { // TODO draw the subsurfaces of the whole tree recursively instead. // The current version is not correct because it handles only one level // (it ignores subsurface->subsurfaces). // Plus it needs the workaround above to avoid a stack overflow. subsurface->src_surface->raw_draw_region( subsurface->src_rect, *this, subsurface->dst_rect.get_xy() ); subsurface = nullptr; } clear_subsurfaces(); } if (this->internal_surface != nullptr) { // The source surface is not empty: draw it onto the destination. SDL_SetSurfaceBlendMode( this->internal_surface.get(), get_sdl_blend_mode() ); SDL_BlitSurface( this->internal_surface.get(), region.get_internal_rect(), dst_surface.internal_surface.get(), Rectangle(dst_position).get_internal_rect() ); } else if (internal_color != nullptr) { // No internal surface to draw: this may be a color. if (get_blend_mode() == BlendMode::BLEND && internal_color->get_alpha() == 255) { // Fill with opaque color: we can directly modify the destination pixels. Rectangle dst_rect( dst_position, region.get_size() ); SDL_FillRect( dst_surface.internal_surface.get(), dst_rect.get_internal_rect(), get_color_value(*internal_color) ); } else { // Fill with semi-transparent pixels: perform alpha-blending. create_software_surface(); SDL_FillRect( this->internal_surface.get(), nullptr, get_color_value(*internal_color) ); SDL_BlitSurface( this->internal_surface.get(), region.get_internal_rect(), dst_surface.internal_surface.get(), Rectangle(dst_position).get_internal_rect() ); } } } else { // The destination is a GPU surface (a texture). // Do not draw anything, just store the operation in the tree instead. // The actual drawing will be done at rendering time in GPU. SurfacePtr src_surface = std::static_pointer_cast<Surface>(shared_from_this()); dst_surface.add_subsurface(src_surface, region, dst_position); } dst_surface.is_rendered = false; }
/** * \brief Draws a subrectangle of this surface on another surface. * \param region The subrectangle to draw in this object. * \param dst_surface The destination surface. * \param dst_position Coordinates on the destination surface. * The width and height of this rectangle are ignored. */ void Surface::raw_draw_region( const Rectangle& region, Surface& dst_surface, const Rectangle& dst_position) { if (dst_surface.software_destination // The destination surface is in RAM. || !Video::is_acceleration_enabled() // The rendering is in RAM. ) { if (dst_surface.internal_surface == NULL) { dst_surface.create_software_surface(); } // First, draw subsurfaces if any. // They can exist if the video mode recently switched from an accelerated // one to a software one. if (!subsurfaces.empty()) { if (this->internal_surface == NULL) { create_software_surface(); } std::vector<SubSurfaceNode*> subsurfaces = this->subsurfaces; this->subsurfaces.clear(); // Avoid infinite recursive calls if there are cycles. 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; // TODO draw the subsurfaces of the whole tree recursively instead. // The current version is not correct because it handles only one level // (it ignores subsurface->subsurfaces). // Plus it needs the workaround above to avoid a stack overflow. subsurface->src_surface->raw_draw_region( subsurface->src_rect, *this, subsurface->dst_rect ); RefCountable::unref(subsurface); } clear_subsurfaces(); } if (this->internal_surface != NULL) { // The source surface is not empty: draw it onto the destination. SDL_BlitSurface( this->internal_surface, region.get_internal_rect(), dst_surface.internal_surface, Rectangle(dst_position).get_internal_rect() ); } else if (internal_color != NULL) { // No internal surface to draw: this may be a color. if (internal_color->get_internal_color()->a == 255) { // Fill with opaque color: we can directly modify the destination pixels. Rectangle dst_rect( dst_position.get_x(), dst_position.get_y(), region.get_width(), region.get_height() ); SDL_FillRect( dst_surface.internal_surface, dst_rect.get_internal_rect(), this->internal_color->get_internal_value() ); } else { // Fill with semi-transparent pixels: perform alpha-blending. create_software_surface(); SDL_FillRect( this->internal_surface, NULL, this->internal_color->get_internal_value() ); SDL_BlitSurface( this->internal_surface, region.get_internal_rect(), dst_surface.internal_surface, Rectangle(dst_position).get_internal_rect() ); } } } else { // The destination is a GPU surface (a texture). // Do not draw anything, just store the operation in the tree instead. // The actual drawing will be done at rendering time in GPU. dst_surface.add_subsurface(*this, region, dst_position); } dst_surface.is_rendered = false; }