/** * \brief Sets the opacity of this surface. * \param opacity The opacity (0 to 255). */ void Surface::set_opacity(uint8_t opacity) { this->opacity = opacity; if (software_destination // The destination surface is in RAM. || !Video::is_acceleration_enabled() // The rendering is in RAM. ) { if (internal_surface == nullptr) { create_software_surface(); } int error = SDL_SetSurfaceAlphaMod(internal_surface.get(), opacity); if (error != 0) { Debug::error(SDL_GetError()); } is_rendered = false; // The surface has changed. } // If this is a hardware surface, the opacity is applied later. }
/** * \brief Sets the opacity of this surface. * \param opacity the opacity (0 to 255). */ void Surface::set_opacity(uint8_t opacity) { if (software_destination // The destination surface is in RAM. || !Video::is_acceleration_enabled() // The rendering is in RAM. ) { if (internal_surface == NULL) { create_software_surface(); } // The surface must be 32-bit with alpha value for this function to work. convert_software_surface(); int error = SDL_SetSurfaceAlphaMod(internal_surface, opacity); if (error != 0) { Debug::error(SDL_GetError()); } is_rendered = false; // The surface has changed. } else { internal_opacity = opacity; } }
/** * \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; }