Esempio n. 1
0
/**
   Draws the @a frame of animation of the specified @a sprite
   in a new image and return it.

   Positions source_x, source_y, width and height must have the
   zoom applied (zoom.apply(sorce_x), zoom.apply(source_y), zoom.apply(width), etc.)
 */
Image* RenderEngine::renderSprite(int source_x, int source_y,
  int width, int height,
  FrameNumber frame, Zoom zoom,
  bool draw_tiled_bg,
  bool enable_onionskin,
  ImageBufferPtr& buffer)
{
  void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, Zoom);
  const LayerImage* background = m_sprite->backgroundLayer();
  bool need_checked_bg = (background != NULL ? !background->isVisible(): true);
  uint32_t bg_color = 0;
  Image *image;

  switch (m_sprite->pixelFormat()) {

    case IMAGE_RGB:
      zoomed_func = merge_zoomed_image<RgbTraits, RgbTraits>;
      break;

    case IMAGE_GRAYSCALE:
      zoomed_func = merge_zoomed_image<RgbTraits, GrayscaleTraits>;
      break;

    case IMAGE_INDEXED:
      zoomed_func = merge_zoomed_image<RgbTraits, IndexedTraits>;
      if (!need_checked_bg)
        bg_color = m_sprite->getPalette(frame)->getEntry(m_sprite->transparentColor());
      break;

    default:
      return NULL;
  }

  // Create a temporary RGB bitmap to draw all to it
  image = Image::create(IMAGE_RGB, width, height, buffer);
  if (!image)
    return NULL;

  // Draw checked background
  if (need_checked_bg && draw_tiled_bg)
    renderCheckedBackground(image, source_x, source_y, zoom);
  else
    clear_image(image, bg_color);

  // Draw the current frame.
  global_opacity = 255;
  renderLayer(m_sprite->folder(), image,
    source_x, source_y, frame, zoom, zoomed_func, true, true, -1);

  // Onion-skin feature: Draw previous/next frames with different
  // opacity (<255) (it is the onion-skinning)
  IDocumentSettings* docSettings = UIContext::instance()
    ->settings()->getDocumentSettings(m_document);

  if (enable_onionskin & docSettings->getUseOnionskin()) {
    int prevs = docSettings->getOnionskinPrevFrames();
    int nexts = docSettings->getOnionskinNextFrames();
    int opacity_base = docSettings->getOnionskinOpacityBase();
    int opacity_step = docSettings->getOnionskinOpacityStep();

    for (FrameNumber f=frame.previous(prevs); f <= frame.next(nexts); ++f) {
      if (f == frame || f < 0 || f > m_sprite->lastFrame())
        continue;
      else if (f < frame)
        global_opacity = opacity_base - opacity_step * ((frame - f)-1);
      else
        global_opacity = opacity_base - opacity_step * ((f - frame)-1);

      if (global_opacity > 0) {
        global_opacity = MID(0, global_opacity, 255);

        int blend_mode = -1;
        if (docSettings->getOnionskinType() == IDocumentSettings::Onionskin_Merge)
          blend_mode = BLEND_MODE_NORMAL;
        else if (docSettings->getOnionskinType() == IDocumentSettings::Onionskin_RedBlueTint)
          blend_mode = (f < frame ? BLEND_MODE_RED_TINT: BLEND_MODE_BLUE_TINT);

        renderLayer(m_sprite->folder(), image,
          source_x, source_y, f, zoom, zoomed_func,
          true, true, blend_mode);
      }
    }
  }

  return image;
}