Пример #1
0
void ClearMask::clear()
{
  Cel* cel = this->cel();
  Image* image = m_dstImage->image();
  app::Document* doc = static_cast<app::Document*>(cel->document());
  Mask* mask = doc->mask();

  ASSERT(mask->bitmap());
  if (!mask->bitmap())
    return;

  const LockImageBits<BitmapTraits> maskBits(mask->bitmap());
  LockImageBits<BitmapTraits>::const_iterator it = maskBits.begin();

  // Clear the masked zones
  int u, v;
  for (v=0; v<mask->bounds().h; ++v) {
    for (u=0; u<mask->bounds().w; ++u, ++it) {
      ASSERT(it != maskBits.end());
      if (*it) {
        put_pixel(image,
          u + m_offsetX,
          v + m_offsetY, m_bgcolor);
      }
    }
  }

  ASSERT(it == maskBits.end());
}
Пример #2
0
void InvertMaskCommand::onExecute(Context* context)
{
  bool hasMask = false;
  {
    const ContextReader reader(context);
    if (reader.document()->isMaskVisible())
      hasMask = true;
  }

  // without mask?...
  if (!hasMask) {
    // so we select all
    Command* mask_all_cmd =
      CommandsModule::instance()->getCommandByName(CommandId::MaskAll);
    context->executeCommand(mask_all_cmd);
  }
  // invert the current mask
  else {
    ContextWriter writer(context);
    Document* document(writer.document());
    Sprite* sprite(writer.sprite());

    // Select all the sprite area
    base::UniquePtr<Mask> mask(new Mask());
    mask->replace(sprite->bounds());

    // Remove in the new mask the current sprite marked region
    const gfx::Rect& maskBounds = document->mask()->bounds();
    doc::fill_rect(mask->bitmap(),
      maskBounds.x, maskBounds.y,
      maskBounds.x + maskBounds.w-1,
      maskBounds.y + maskBounds.h-1, 0);

    Mask* curMask = document->mask();
    if (curMask->bitmap()) {
      // Copy the inverted region in the new mask (we just modify the
      // document's mask temporaly here)
      curMask->freeze();
      curMask->invert();
      doc::copy_image(mask->bitmap(),
        curMask->bitmap(),
        curMask->bounds().x,
        curMask->bounds().y);
      curMask->invert();
      curMask->unfreeze();
    }

    // We need only need the area inside the sprite
    mask->intersect(sprite->bounds());

    // Set the new mask
    Transaction transaction(writer.context(), "Mask Invert", DoesntModifyDocument);
    transaction.execute(new cmd::SetMask(document, mask));
    transaction.commit();

    document->generateMaskBoundaries();
    update_screen_for_document(document);
  }
}
Пример #3
0
void stroke_selection(Image* image,
                      const gfx::Point& offset,
                      const Mask* origMask,
                      const color_t color)
{
  ASSERT(origMask);
  ASSERT(origMask->bitmap());
  if (!origMask || !origMask->bitmap())
    return;

  gfx::Rect bounds = origMask->bounds();
  if (bounds.isEmpty())
    return;

  Mask mask;
  mask.reserve(bounds);
  mask.freeze();
  modify_selection(
    SelectionModifier::Border,
    origMask, &mask, 1,
    BrushType::kCircleBrushType);
  mask.unfreeze();

  // Both mask must have the same bounds.
  ASSERT(mask.bounds() == origMask->bounds());

  if (mask.bitmap())
    fill_selection(image, offset, &mask, color);
}
Пример #4
0
void ShiftMaskedCel::shift(int dx, int dy)
{
  Cel* cel = this->cel();
  Image* image = cel->image();
  Mask* mask = static_cast<app::Document*>(cel->document())->mask();
  ASSERT(mask->bitmap());
  if (!mask->bitmap())
    return;

  int x = cel->x();
  int y = cel->y();

  mask->offsetOrigin(-x, -y);
  doc::algorithm::shift_image_with_mask(image, mask, dx, dy);
  mask->offsetOrigin(x, y);

  image->incrementVersion();
}
Пример #5
0
// Loads a MSK file (Animator and Animator Pro format)
Mask* load_msk_file(const char* filename)
{
  int orig_size = base::file_size(filename);
  int i, c, u, v, byte, magic, size;
  Mask* mask = NULL;

  FILE* f = base::open_file_raw(filename, "r");
  if (!f)
    return NULL;

  size = base::fgetl(f);
  magic = base::fgetw(f);

  // Animator Pro MSK format
  if ((size == orig_size) && (magic == 0x9500)) {
    int x, y;

    fclose(f);

    // Just load an Animator Pro PIC file
    base::UniquePtr<Image> image(load_pic_file(filename, &x, &y, NULL));
    if (image != NULL && (image->pixelFormat() == IMAGE_BITMAP))
      mask = new Mask(x, y, image.release());
  }
  // Animator MSK format
  else if (orig_size == 8000) {
    mask = new Mask();
    mask->replace(0, 0, 320, 200);

    u = v = 0;
    for (i=0; i<8000; i++) {
      byte = getc(f);
      for (c=0; c<8; c++) {
        mask->bitmap()->putPixel(u, v, byte & (1<<(7-c)));
        u++;
        if (u == 320) {
          u = 0;
          v++;
        }
      }
    }
    fclose(f);
  }
  else {
    fclose(f);
  }

  return mask;
}
Пример #6
0
void FlipCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document = writer.document();
  Sprite* sprite = writer.sprite();

  {
    Transaction transaction(writer.context(),
      m_flipMask ?
      (m_flipType == doc::algorithm::FlipHorizontal ?
        "Flip Horizontal":
        "Flip Vertical"):
      (m_flipType == doc::algorithm::FlipHorizontal ?
        "Flip Canvas Horizontal":
        "Flip Canvas Vertical"));
    DocumentApi api = document->getApi(transaction);

    CelList cels;
    if (m_flipMask) {
      auto range = App::instance()->timeline()->range();
      if (range.enabled())
        cels = get_unique_cels(sprite, range);
      else if (writer.cel())
        cels.push_back(writer.cel());
    }
    else {
      for (Cel* cel : sprite->uniqueCels())
        cels.push_back(cel);
    }

    Mask* mask = document->mask();
    if (m_flipMask && document->isMaskVisible()) {
      Site site = *writer.site();

      for (Cel* cel : cels) {
        site.frame(cel->frame());
        site.layer(cel->layer());

        int x, y;
        Image* image = site.image(&x, &y);
        if (!image)
          continue;

        // When the mask is inside the cel, we can try to flip the
        // pixels inside the image.
        if (cel->bounds().contains(mask->bounds())) {
          gfx::Rect flipBounds = mask->bounds();
          flipBounds.offset(-x, -y);
          flipBounds &= image->bounds();
          if (flipBounds.isEmpty())
            continue;

          if (mask->bitmap() && !mask->isRectangular())
            transaction.execute(new cmd::FlipMaskedCel(cel, m_flipType));
          else
            api.flipImage(image, flipBounds, m_flipType);

          if (cel->layer()->isTransparent())
            transaction.execute(new cmd::TrimCel(cel));
        }
        // When the mask is bigger than the cel bounds, we have to
        // expand the cel, make the flip, and shrink it again.
        else {
          gfx::Rect flipBounds = (sprite->bounds() & mask->bounds());
          if (flipBounds.isEmpty())
            continue;

          ExpandCelCanvas expand(
            site, cel->layer(),
            TiledMode::NONE, transaction,
            ExpandCelCanvas::None);

          expand.validateDestCanvas(gfx::Region(flipBounds));

          if (mask->bitmap() && !mask->isRectangular())
            doc::algorithm::flip_image_with_mask(
              expand.getDestCanvas(), mask, m_flipType,
              document->bgColor(cel->layer()));
          else
            doc::algorithm::flip_image(
              expand.getDestCanvas(),
              flipBounds, m_flipType);

          expand.commit();
        }
      }
    }
    else {
      for (Cel* cel : cels) {
        Image* image = cel->image();

        api.setCelPosition
          (sprite, cel,
            (m_flipType == doc::algorithm::FlipHorizontal ?
              sprite->width() - image->width() - cel->x():
              cel->x()),
            (m_flipType == doc::algorithm::FlipVertical ?
              sprite->height() - image->height() - cel->y():
              cel->y()));

        api.flipImage(image, image->bounds(), m_flipType);
      }
    }

    // Flip the mask.
    Image* maskBitmap = mask->bitmap();
    if (maskBitmap) {
      transaction.execute(new cmd::FlipMask(document, m_flipType));

      // Flip the mask position because the
      if (!m_flipMask)
        transaction.execute(
          new cmd::SetMaskPosition(
            document,
            gfx::Point(
              (m_flipType == doc::algorithm::FlipHorizontal ?
               sprite->width() - mask->bounds().x2():
               mask->bounds().x),
              (m_flipType == doc::algorithm::FlipVertical ?
               sprite->height() - mask->bounds().y2():
               mask->bounds().y))));

      document->generateMaskBoundaries();
    }

    transaction.commit();
  }

  update_screen_for_document(document);
}
Пример #7
0
  // [working thread]
  virtual void onJob()
  {
    Transaction transaction(m_writer.context(), "Rotate Canvas");
    DocumentApi api = m_document->getApi(transaction);

    // 1) Rotate cel positions
    for (Cel* cel : m_cels) {
      Image* image = cel->image();
      if (!image)
        continue;

      switch (m_angle) {
        case 180:
          api.setCelPosition(m_sprite, cel,
            m_sprite->width() - cel->x() - image->width(),
            m_sprite->height() - cel->y() - image->height());
          break;
        case 90:
          api.setCelPosition(m_sprite, cel,
            m_sprite->height() - cel->y() - image->height(),
            cel->x());
          break;
        case -90:
          api.setCelPosition(m_sprite, cel,
            cel->y(),
            m_sprite->width() - cel->x() - image->width());
          break;
      }
    }

    // 2) Rotate images
    int i = 0;
    for (Cel* cel : m_cels) {
      Image* image = cel->image();
      if (image) {
        ImageRef new_image(Image::create(image->pixelFormat(),
            m_angle == 180 ? image->width(): image->height(),
            m_angle == 180 ? image->height(): image->width()));
        doc::rotate_image(image, new_image.get(), m_angle);

        api.replaceImage(m_sprite, cel->imageRef(), new_image);
      }

      jobProgress((float)i / m_cels.size());
      ++i;

      // cancel all the operation?
      if (isCanceled())
        return;        // Transaction destructor will undo all operations
    }

    // rotate mask
    if (m_document->isMaskVisible()) {
      Mask* origMask = m_document->mask();
      base::UniquePtr<Mask> new_mask(new Mask());
      const gfx::Rect& origBounds = origMask->bounds();
      int x = 0, y = 0;

      switch (m_angle) {
        case 180:
          x = m_sprite->width() - origBounds.x - origBounds.w;
          y = m_sprite->height() - origBounds.y - origBounds.h;
          break;
        case 90:
          x = m_sprite->height() - origBounds.y - origBounds.h;
          y = origBounds.x;
          break;
        case -90:
          x = origBounds.y;
          y = m_sprite->width() - origBounds.x - origBounds.w;
          break;
      }

      // create the new rotated mask
      new_mask->replace(
        gfx::Rect(x, y,
          m_angle == 180 ? origBounds.w: origBounds.h,
          m_angle == 180 ? origBounds.h: origBounds.w));
      doc::rotate_image(origMask->bitmap(), new_mask->bitmap(), m_angle);

      // Copy new mask
      api.copyToCurrentMask(new_mask);

      // Regenerate mask
      m_document->resetTransformation();
      m_document->generateMaskBoundaries();
    }

    // change the sprite's size
    if (m_rotateSprite && m_angle != 180)
      api.setSpriteSize(m_sprite, m_sprite->height(), m_sprite->width());

    // commit changes
    transaction.commit();
  }