예제 #1
0
/**
 * \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;
}
예제 #2
0
파일: Surface.cpp 프로젝트: bgalok/solarus
/**
 * \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;
}