Beispiel #1
0
/**
 * \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;
    }
  }
}
Beispiel #2
0
/**
 * \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);
}
Beispiel #3
0
/**
 * \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);
}
Beispiel #4
0
/**
 * \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;
    }
  }
}
Beispiel #5
0
/**
 * \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;
}
Beispiel #6
0
/**
 * \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;
}