void DuplicateLayerCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document = writer.document();
  Sprite* sprite = writer.sprite();
  UndoTransaction undo(writer.context(), "Layer Duplication");
  LayerImage* sourceLayer = static_cast<LayerImage*>(writer.layer());

  // Create a new layer
  UniquePtr<LayerImage> newLayerPtr(new LayerImage(sprite));

  // Disable undo because the layer content is added as a whole with
  // AddLayer() undoer.
  document->getUndo()->setEnabled(false);

  // Copy the layer content (cels + images)
  document->copyLayerContent(sourceLayer, document, newLayerPtr);

  // Restore enabled status.
  document->getUndo()->setEnabled(undo.isEnabled());

  // Copy the layer name
  newLayerPtr->setName(newLayerPtr->getName() + " Copy");

  // Add the new layer in the sprite.
  document->getApi().addLayer(sourceLayer->getParent(), newLayerPtr, sourceLayer);

  // Release the pointer as it is owned by the sprite now
  Layer* newLayer = newLayerPtr.release();

  undo.commit();

  update_screen_for_document(document);
}
void SetCelFrame::revert(ObjectsContainer* objects, UndoersCollector* redoers)
{
  LayerImage* layer = objects->getObjectT<LayerImage>(m_layerId);
  Cel* cel = objects->getObjectT<Cel>(m_celId);

  // Push another SetCelFrame as redoer
  redoers->pushUndoer(new SetCelFrame(objects, layer, cel));

  layer->moveCel(cel, m_frame);
}
Example #3
0
TEST(File, SeveralSizes)
{
  she::ScopedHandle<she::System> system(she::CreateSystem());
  // Register all possible image formats.
  FileFormatsManager::instance().registerAllFormats();
  std::vector<char> fn(256);

  for (int w=10; w<=10+503*2; w+=503) {
    for (int h=10; h<=10+503*2; h+=503) {
      //std::sprintf(&fn[0], "test_%dx%d.ase", w, h);
      std::sprintf(&fn[0], "test.ase");

      {
        UniquePtr<Document> doc(Document::createBasicDocument(IMAGE_INDEXED, w, h, 256));
        doc->setFilename(&fn[0]);

        // Random pixels
        LayerImage* layer = dynamic_cast<LayerImage*>(doc->getSprite()->getFolder()->getFirstLayer());
        ASSERT_TRUE(layer != NULL);
        Image* image = doc->getSprite()->getStock()->getImage(layer->getCel(FrameNumber(0))->getImage());
        std::srand(w*h);
        int c = std::rand()%256;
        for (int y=0; y<h; y++) {
          for (int x=0; x<w; x++) {
            image_putpixel_fast<IndexedTraits>(image, x, y, c);
            if ((std::rand()&4) == 0)
              c = std::rand()%256;
          }
        }

        save_document(doc);
      }

      {
        UniquePtr<Document> doc(load_document(&fn[0]));
        ASSERT_EQ(w, doc->getSprite()->getWidth());
        ASSERT_EQ(h, doc->getSprite()->getHeight());

        // Same random pixels (see the seed)
        LayerImage* layer = dynamic_cast<LayerImage*>(doc->getSprite()->getFolder()->getFirstLayer());
        ASSERT_TRUE(layer != NULL);
        Image* image = doc->getSprite()->getStock()->getImage(layer->getCel(FrameNumber(0))->getImage());
        std::srand(w*h);
        int c = std::rand()%256;
        for (int y=0; y<h; y++) {
          for (int x=0; x<w; x++) {
            ASSERT_EQ(c, image_getpixel_fast<IndexedTraits>(image, x, y));
            if ((std::rand()&4) == 0)
              c = std::rand()%256;
          }
        }
      }
    }
  }
}
Example #4
0
void UnlinkCelCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());
  bool nonEditableLayers = false;
  {
    Transaction transaction(writer.context(), "Unlink Cel");

    // TODO the range of selected frames should be in doc::Site.
    auto range = App::instance()->timeline()->range();
    if (range.enabled()) {
      Sprite* sprite = writer.sprite();

      for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) {
        Layer* layer = sprite->indexToLayer(layerIdx);
        if (!layer->isImage())
          continue;

        LayerImage* layerImage = static_cast<LayerImage*>(layer);

        for (frame_t frame = range.frameEnd(),
               begin = range.frameBegin()-1;
             frame != begin;
             --frame) {
          Cel* cel = layerImage->cel(frame);
          if (cel && cel->links()) {
            if (layerImage->isEditable())
              transaction.execute(new cmd::UnlinkCel(cel));
            else
              nonEditableLayers = true;
          }
        }
      }
    }
    else {
      Cel* cel = writer.cel();
      if (cel && cel->links()) {
        if (cel->layer()->isEditable())
          transaction.execute(new cmd::UnlinkCel(writer.cel()));
        else
          nonEditableLayers = true;
      }
    }

    transaction.commit();
  }

  if (nonEditableLayers)
    StatusBar::instance()->showTip(1000,
      "There are locked layers");

  update_screen_for_document(document);
}
Example #5
0
void LinkCelsCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());
  bool nonEditableLayers = false;
  {
    // TODO the range of selected frames should be in doc::Site.
    Timeline::Range range = App::instance()->getMainWindow()->getTimeline()->range();
    if (!range.enabled())
      return;

    Transaction transaction(writer.context(), friendlyName());
    Sprite* sprite = writer.sprite();
    frame_t begin = range.frameBegin();
    frame_t end = range.frameEnd();

    for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) {
      Layer* layer = sprite->indexToLayer(layerIdx);
      if (!layer->isImage())
        continue;

      if (!layer->isEditable()) {
        nonEditableLayers = true;
        continue;
      }

      LayerImage* layerImage = static_cast<LayerImage*>(layer);
      for (frame_t frame=begin; frame < end+1; ++frame) {
        Cel* cel = layerImage->cel(frame);
        if (cel) {
          for (frame = cel->frame()+1;
               frame < end+1; ++frame) {
            transaction.execute(
              new cmd::CopyCel(
                layerImage, cel->frame(),
                layerImage, frame,
                true));         // true = force links
          }
          break;
        }
      }
    }

    transaction.commit();
  }

  if (nonEditableLayers)
    StatusBar::instance()->showTip(1000,
      "There are locked layers");

  update_screen_for_document(document);
}
Example #6
0
void LinkCelsCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Doc* document(writer.document());
  bool nonEditableLayers = false;
  {
    auto site = context->activeSite();
    if (!site.inTimeline())
      return;

    Tx tx(writer.context(), friendlyName());

    for (Layer* layer : site.selectedLayers()) {
      if (!layer->isImage())
        continue;

      if (!layer->isEditableHierarchy()) {
        nonEditableLayers = true;
        continue;
      }

      LayerImage* layerImage = static_cast<LayerImage*>(layer);

      for (auto it=site.selectedFrames().begin(), end=site.selectedFrames().end();
           it != end; ++it) {
        frame_t frame = *it;
        Cel* cel = layerImage->cel(frame);
        if (cel) {
          for (++it; it != end; ++it) {
            tx(
              new cmd::CopyCel(
                layerImage, cel->frame(),
                layerImage, *it,
                true));         // true = force links
          }
          break;
        }
      }
    }

    tx.commit();
  }

  if (nonEditableLayers)
    StatusBar::instance()->showTip(1000,
      "There are locked layers");

  update_screen_for_document(document);
}
Example #7
0
void UnlinkCelCommand::onExecute(Context* context)
{
  ContextWriter writer(context);
  Document* document(writer.document());
  bool nonEditableLayers = false;
  {
    Transaction transaction(writer.context(), "Unlink Cel");

    const Site* site = writer.site();
    if (site->inTimeline() &&
        !site->selectedLayers().empty()) {
      for (Layer* layer : site->selectedLayers()) {
        if (!layer->isImage())
          continue;

        if (!layer->isEditableHierarchy()) {
          nonEditableLayers = true;
          continue;
        }

        LayerImage* layerImage = static_cast<LayerImage*>(layer);

        for (frame_t frame : site->selectedFrames().reversed()) {
          Cel* cel = layerImage->cel(frame);
          if (cel && cel->links())
            transaction.execute(new cmd::UnlinkCel(cel));
        }
      }
    }
    else {
      Cel* cel = writer.cel();
      if (cel && cel->links()) {
        if (cel->layer()->isEditableHierarchy())
          transaction.execute(new cmd::UnlinkCel(writer.cel()));
        else
          nonEditableLayers = true;
      }
    }

    transaction.commit();
  }

  if (nonEditableLayers)
    StatusBar::instance()->showTip(1000,
      "There are locked layers");

  update_screen_for_document(document);
}
  DocRangeOps() {
    black = rgba(0, 0, 0, 0);
    white = rgba(255, 255, 255, 255);

    doc.reset(static_cast<app::Document*>(ctx.documents().add(4, 4)));
    sprite = doc->sprite();
    layer1 = dynamic_cast<LayerImage*>(sprite->folder()->getFirstLayer());
    layer2 = new LayerImage(sprite);
    layer3 = new LayerImage(sprite);
    layer4 = new LayerImage(sprite);
    sprite->folder()->addLayer(layer2);
    sprite->folder()->addLayer(layer3);
    sprite->folder()->addLayer(layer4);
    EXPECT_LAYER_ORDER(layer1, layer2, layer3, layer4);

    layer1->setName("layer1");
    layer2->setName("layer2");
    layer3->setName("layer3");
    layer4->setName("layer4");

    sprite->setTotalFrames(frame_t(4));
    sprite->setFrameDuration(frame_t(0), 1); // These durations can be used to identify
    sprite->setFrameDuration(frame_t(1), 2); // frames after a move operation
    sprite->setFrameDuration(frame_t(2), 3);
    sprite->setFrameDuration(frame_t(3), 4);

    for (int i=0; i<4; i++) {
      LayerImage* layer = static_cast<LayerImage*>(sprite->indexToLayer(LayerIndex(i)));

      for (int j=0; j<4; j++) {
        Cel* cel = layer->cel(frame_t(j));
        ImageRef image;
        if (cel)
          image = cel->imageRef();
        else {
          image.reset(Image::create(IMAGE_RGB, 4, 4));
          cel = new Cel(frame_t(j), image);
          layer->addCel(cel);
        }

        clear_image(image.get(), black);
        put_pixel(image.get(), i, j, white);
      }
    }
  }
Example #9
0
static void move_or_copy_cels(
  DocApi& api, Op op,
  const LayerList& srcLayers,
  const LayerList& dstLayers,
  const SelectedFrames& srcFrames,
  const SelectedFrames& dstFrames)
{
  ASSERT(srcLayers.size() == dstLayers.size());

  for (layer_t i=0; i<srcLayers.size(); ++i) {
    auto srcFrame = srcFrames.begin();
    auto dstFrame = dstFrames.begin();
    auto srcFrameEnd = srcFrames.end();
    auto dstFrameEnd = dstFrames.end();

    for (; srcFrame != srcFrameEnd &&
           dstFrame != dstFrameEnd; ++srcFrame, ++dstFrame) {
      if (i >= 0 && i < srcLayers.size() && srcLayers[i]->isImage()) {
        LayerImage* srcLayer = static_cast<LayerImage*>(srcLayers[i]);

        if (i < dstLayers.size() && dstLayers[i]->isImage()) {
          LayerImage* srcLayer = static_cast<LayerImage*>(srcLayers[i]);
          LayerImage* dstLayer = static_cast<LayerImage*>(dstLayers[i]);

#ifdef TRACE_RANGE_OPS
          std::clog << (op == Move ? "Moving": "Copying")
                    << " cel " << srcLayer->name() << "[" << *srcFrame << "]"
                    << " into " << dstLayer->name() << "[" << *dstFrame << "]\n";
#endif

          switch (op) {
            case Move: api.moveCel(srcLayer, *srcFrame, dstLayer, *dstFrame); break;
            case Copy: api.copyCel(srcLayer, *srcFrame, dstLayer, *dstFrame); break;
          }
        }
        else if (op == Move) {
          api.clearCel(srcLayer, *srcFrame);
        }
      }
    }
  }
}
Example #10
0
bool save_palette(const char *filename, Palette* pal)
{
  std::string ext = base::string_to_lower(base::get_file_extension(filename));
  bool success = false;

  if (ext == "col") {
    success = doc::file::save_col_file(pal, filename);
  }
  else if (ext == "gpl") {
    success = doc::file::save_gpl_file(pal, filename);
  }
  else {
    FileFormat* ff = FileFormatsManager::instance()->getFileFormatByExtension(ext.c_str());
    if (ff->support(FILE_SUPPORT_SAVE)) {
      app::Context tmpContext;
      doc::Document* doc = tmpContext.documents().add(
        16, 16, doc::ColorMode::INDEXED,
        Palette::MaxColors);

      Sprite* sprite = doc->sprite();
      doc->sprite()->setPalette(pal, false);

      LayerImage* layer = dynamic_cast<LayerImage*>(sprite->folder()->getFirstLayer());
      Image* image = layer->getCel(FrameNumber(0))->image();

      int x, y, c;
      for (y=c=0; y<16; y++)
        for (x=0; x<16; x++)
          image->putPixel(x, y, c++);

      doc->setFilename(filename);
      success = (save_document(&tmpContext, doc) == 0);

      doc->close();
      delete doc;
    }
  }

  return success;
}
Example #11
0
// TODO the DocumentRange should be "iteratable" to replace this function
CelList get_cels_in_range(Sprite* sprite, const DocumentRange& range)
{
  CelList cels;

  for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) {
    Layer* layer = sprite->indexToLayer(layerIdx);
    if (!layer->isImage())
      continue;

    LayerImage* layerImage = static_cast<LayerImage*>(layer);

    for (FrameNumber frame = range.frameEnd(),
           begin = range.frameBegin().previous();
         frame != begin;
         frame = frame.previous()) {
      Cel* cel = layerImage->getCel(frame);
      if (cel)
        cels.push_back(cel);
    }
  }
  return cels;
}
Example #12
0
MovingCelState::MovingCelState(Editor* editor, MouseMessage* msg)
  : m_canceled(false)
{
  ContextWriter writer(UIContext::instance(), 500);
  Document* document = editor->document();
  auto range = App::instance()->timeline()->range();
  LayerImage* layer = static_cast<LayerImage*>(editor->layer());
  ASSERT(layer->isImage());

  Cel* currentCel = layer->cel(editor->frame());
  ASSERT(currentCel); // The cel cannot be null

  if (!range.enabled())
    range = DocumentRange(currentCel);

  // Record start positions of all cels in selected range
  for (Cel* cel : get_unique_cels(writer.sprite(), range)) {
    Layer* layer = cel->layer();
    ASSERT(layer);

    if (layer && layer->isMovable() && !layer->isBackground()) {
      m_celList.push_back(cel);
      m_celStarts.push_back(cel->position());
    }
  }

  m_cursorStart = editor->screenToEditor(msg->position());
  m_celOffset = gfx::Point(0, 0);
  editor->captureMouse();

  // Hide the mask (temporarily, until mouse-up event)
  m_maskVisible = document->isMaskVisible();
  if (m_maskVisible) {
    document->setMaskVisible(false);
    document->generateMaskBoundaries();
  }
}
Example #13
0
void CopyCel::onExecute()
{
  LayerImage* srcLayer = static_cast<LayerImage*>(m_srcLayer.layer());
  LayerImage* dstLayer = static_cast<LayerImage*>(m_dstLayer.layer());

  ASSERT(srcLayer);
  ASSERT(dstLayer);

  Sprite* srcSprite = srcLayer->sprite();
  Sprite* dstSprite = dstLayer->sprite();
  ASSERT(srcSprite);
  ASSERT(dstSprite);
  ASSERT(m_srcFrame >= 0 && m_srcFrame < srcSprite->totalFrames());
  ASSERT(m_dstFrame >= 0);
  (void)srcSprite;              // To avoid unused variable warning on Release mode

  Cel* srcCel = srcLayer->cel(m_srcFrame);
  Cel* dstCel = dstLayer->cel(m_dstFrame);

  // Clear destination cel if it does exist. It'll be overriden by the
  // copy of srcCel.
  if (dstCel) {
    if (dstCel->links())
      executeAndAdd(new cmd::UnlinkCel(dstCel));
    executeAndAdd(new cmd::ClearCel(dstCel));
  }

  // Add empty frames until newFrame
  while (dstSprite->totalFrames() <= m_dstFrame)
    executeAndAdd(new cmd::AddFrame(dstSprite, dstSprite->totalFrames()));

  Image* srcImage = (srcCel ? srcCel->image(): NULL);
  ImageRef dstImage;
  dstCel = dstLayer->cel(m_dstFrame);
  if (dstCel)
    dstImage = dstCel->imageRef();

  bool createLink =
    (srcLayer == dstLayer && dstLayer->isContinuous());

  // For background layer
  if (dstLayer->isBackground()) {
    ASSERT(dstCel);
    ASSERT(dstImage);
    if (!dstCel || !dstImage ||
        !srcCel || !srcImage)
      return;

    if (createLink) {
      executeAndAdd(new cmd::SetCelData(dstCel, srcCel->dataRef()));
    }
    else {
      BlendMode blend = (srcLayer->isBackground() ?
                         BlendMode::SRC:
                         BlendMode::NORMAL);

      ImageRef tmp(Image::createCopy(dstImage.get()));
      render::composite_image(tmp.get(), srcImage,
                              srcCel->x(), srcCel->y(), 255, blend);
      executeAndAdd(new cmd::CopyRect(dstImage.get(), tmp.get(), gfx::Clip(tmp->bounds())));
    }
  }
  // For transparent layers
  else {
    if (dstCel)
      executeAndAdd(new cmd::RemoveCel(dstCel));

    if (srcCel) {
      if (createLink)
        dstCel = Cel::createLink(srcCel);
      else
        dstCel = Cel::createCopy(srcCel);
      dstCel->setFrame(m_dstFrame);

      executeAndAdd(new cmd::AddCel(dstLayer, dstCel));
    }
  }
}
Example #14
0
bool FliFormat::onLoad(FileOp* fop)
{
#define SETPAL()                                                \
  do {                                                          \
      for (c=0; c<256; c++) {                                   \
        pal->setEntry(c, _rgba(cmap[c*3],                       \
                               cmap[c*3+1],                     \
                               cmap[c*3+2], 255));              \
      }                                                         \
      pal->setFrame(frpos_out);                                 \
      sprite->setPalette(pal, true);                            \
    } while (0)

  unsigned char cmap[768];
  unsigned char omap[768];
  s_fli_header fli_header;
  Image *bmp, *old, *image;
  Sprite *sprite;
  LayerImage *layer;
  Palette *pal;
  int c, w, h;
  FrameNumber frpos_in;
  FrameNumber frpos_out;
  int index = 0;
  Cel *cel;

  /* open the file to read in binary mode */
  FileHandle f(fop->filename.c_str(), "rb");

  fli_read_header(f, &fli_header);
  fseek(f, 128, SEEK_SET);

  if (fli_header.magic == NO_HEADER) {
    fop_error(fop, "The file doesn't have a FLIC header\n");
    return false;
  }

  /* size by frame */
  w = fli_header.width;
  h = fli_header.height;

  /* create the bitmaps */
  bmp = Image::create(IMAGE_INDEXED, w, h);
  old = Image::create(IMAGE_INDEXED, w, h);
  pal = new Palette(FrameNumber(0), 256);
  if (!bmp || !old || !pal) {
    fop_error(fop, "Not enough memory.\n");
    if (bmp) image_free(bmp);
    if (old) image_free(old);
    if (pal) delete pal;
    return false;
  }

  // Create the image
  sprite = new Sprite(IMAGE_INDEXED, w, h, 256);
  layer = new LayerImage(sprite);
  sprite->getFolder()->addLayer(layer);
  layer->configureAsBackground();

  // Set frames and speed
  sprite->setTotalFrames(FrameNumber(fli_header.frames));
  sprite->setDurationForAllFrames(fli_header.speed);

  /* write frame by frame */
  for (frpos_in = frpos_out = FrameNumber(0);
       frpos_in < sprite->getTotalFrames();
       ++frpos_in) {
    /* read the frame */
    fli_read_frame(f, &fli_header,
                   (unsigned char *)old->dat, omap,
                   (unsigned char *)bmp->dat, cmap);

    /* first frame, or the frames changes, or the palette changes */
    if ((frpos_in == 0) ||
        (image_count_diff(old, bmp))
#ifndef USE_LINK /* TODO this should be configurable through a check-box */
        || (memcmp(omap, cmap, 768) != 0)
#endif
        ) {
      /* the image changes? */
      if (frpos_in != 0)
        ++frpos_out;

      /* add the new frame */
      image = Image::createCopy(bmp);
      if (!image) {
        fop_error(fop, "Not enough memory\n");
        break;
      }

      index = sprite->getStock()->addImage(image);
      if (index < 0) {
        image_free(image);
        fop_error(fop, "Not enough memory\n");
        break;
      }

      cel = new Cel(frpos_out, index);
      layer->addCel(cel);

      /* first frame or the palette changes */
      if ((frpos_in == 0) || (memcmp(omap, cmap, 768) != 0))
        SETPAL();
    }
#ifdef USE_LINK
    /* the palette changes */
    else if (memcmp(omap, cmap, 768) != 0) {
      ++frpos_out;
      SETPAL();

      // Add link
      cel = new Cel(frpos_out, index);
      layer_add_cel(layer, cel);
    }
#endif
    // The palette and the image don't change: add duration to the last added frame
    else {
      sprite->setFrameDuration(frpos_out,
                               sprite->getFrameDuration(frpos_out)+fli_header.speed);
    }

    /* update the old image and color-map to the new ones to compare later */
    image_copy(old, bmp, 0, 0);
    memcpy(omap, cmap, 768);

    /* update progress */
    fop_progress(fop, (float)(frpos_in+1) / (float)(sprite->getTotalFrames()));
    if (fop_is_stop(fop))
      break;

    /* just one frame? */
    if (fop->oneframe)
      break;
  }

  // Update number of frames
  sprite->setTotalFrames(frpos_out.next());

  // Destroy the bitmaps
  image_free(bmp);
  image_free(old);
  delete pal;

  fop->document = new Document(sprite);
  return true;
}
Example #15
0
/**
 * Shows the "New Sprite" dialog.
 */
void NewFileCommand::onExecute(Context* context)
{
  PixelFormat format;
  int w, h, bg, ncolors = get_default_palette()->size();
  char buf[1024];
  app::Color bg_table[] = {
    app::Color::fromMask(),
    app::Color::fromRgb(0, 0, 0),
    app::Color::fromRgb(255, 255, 255),
    app::Color::fromRgb(255, 0, 255)
  };

  // Load the window widget
  app::gen::NewSprite window;

  // Default values: Indexed, 320x240, Background color
  format = static_cast<PixelFormat>(get_config_int("NewSprite", "Type", IMAGE_INDEXED));
  // Invalid format in config file.
  if (format != IMAGE_RGB && format != IMAGE_INDEXED && format != IMAGE_GRAYSCALE) {
    format = IMAGE_INDEXED;
  }
  w = get_config_int("NewSprite", "Width", 320);
  h = get_config_int("NewSprite", "Height", 240);
  bg = get_config_int("NewSprite", "Background", 1); // Default = Black

  if (bg == 4) // Convert old default (Background color) to new default (Black)
    bg = 1;
  bg = MID(0, bg, 3);

  // If the clipboard contains an image, we can show the size of the
  // clipboard as default image size.
  gfx::Size clipboardSize;
  if (clipboard::get_image_size(clipboardSize)) {
    w = clipboardSize.w;
    h = clipboardSize.h;
  }

  window.width()->setTextf("%d", MAX(1, w));
  window.height()->setTextf("%d", MAX(1, h));

  // Select image-type
  switch (format) {
    case IMAGE_RGB:       window.rgbMode()->setSelected(true); break;
    case IMAGE_GRAYSCALE: window.grayscaleMode()->setSelected(true); break;
    case IMAGE_INDEXED:   window.indexedMode()->setSelected(true); break;
  }

  // Select background color
  window.bgBox()->selectIndex(bg);

  // Open the window
  window.openWindowInForeground();

  if (window.getKiller() == window.okButton()) {
    bool ok = false;

    // Get the options
    if (window.rgbMode()->isSelected())
      format = IMAGE_RGB;
    else if (window.grayscaleMode()->isSelected())
      format = IMAGE_GRAYSCALE;
    else if (window.indexedMode()->isSelected())
      format = IMAGE_INDEXED;

    w = window.width()->getTextInt();
    h = window.height()->getTextInt();
    bg = window.bgBox()->getSelectedIndex();

    w = MID(1, w, 65535);
    h = MID(1, h, 65535);

    // Select the color
    app::Color color = app::Color::fromMask();

    if (bg >= 0 && bg <= 3) {
      color = bg_table[bg];
      ok = true;
    }

    if (ok) {
      // Save the configuration
      set_config_int("NewSprite", "Type", format);
      set_config_int("NewSprite", "Width", w);
      set_config_int("NewSprite", "Height", h);
      set_config_int("NewSprite", "Background", bg);

      // Create the new sprite
      ASSERT(format == IMAGE_RGB || format == IMAGE_GRAYSCALE || format == IMAGE_INDEXED);
      ASSERT(w > 0 && h > 0);

      base::UniquePtr<Sprite> sprite(Sprite::createBasicSprite(format, w, h, ncolors));

      if (sprite->pixelFormat() != IMAGE_GRAYSCALE)
        get_default_palette()->copyColorsTo(sprite->palette(frame_t(0)));

      // If the background color isn't transparent, we have to
      // convert the `Layer 1' in a `Background'
      if (color.getType() != app::Color::MaskType) {
        Layer* layer = sprite->folder()->getFirstLayer();

        if (layer && layer->isImage()) {
          LayerImage* layerImage = static_cast<LayerImage*>(layer);
          layerImage->configureAsBackground();

          Image* image = layerImage->cel(frame_t(0))->image();
          doc::clear_image(image,
            color_utils::color_for_target(color,
              ColorTarget(
                ColorTarget::BackgroundLayer,
                sprite->pixelFormat(),
                sprite->transparentColor())));
        }
      }

      // Show the sprite to the user
      base::UniquePtr<Document> doc(new Document(sprite));
      sprite.release();
      sprintf(buf, "Sprite-%04d", ++_sprite_counter);
      doc->setFilename(buf);
      doc->setContext(context);
      doc.release();
    }
  }
}
Example #16
0
Document* Document::duplicate(DuplicateType type) const
{
  const Sprite* sourceSprite = sprite();
  base::UniquePtr<Sprite> spriteCopyPtr(new Sprite(
      sourceSprite->pixelFormat(),
      sourceSprite->width(),
      sourceSprite->height(),
      sourceSprite->getPalette(FrameNumber(0))->size()));

  base::UniquePtr<Document> documentCopy(new Document(spriteCopyPtr));
  Sprite* spriteCopy = spriteCopyPtr.release();

  spriteCopy->setTotalFrames(sourceSprite->totalFrames());

  // Copy frames duration
  for (FrameNumber i(0); i < sourceSprite->totalFrames(); ++i)
    spriteCopy->setFrameDuration(i, sourceSprite->getFrameDuration(i));

  // Copy color palettes
  {
    PalettesList::const_iterator it = sourceSprite->getPalettes().begin();
    PalettesList::const_iterator end = sourceSprite->getPalettes().end();
    for (; it != end; ++it) {
      const Palette* pal = *it;
      spriteCopy->setPalette(pal, true);
    }
  }

  switch (type) {

    case DuplicateExactCopy:
      // Copy the layer folder
      copyLayerContent(sourceSprite->folder(), documentCopy, spriteCopy->folder());

      if (sourceSprite->backgroundLayer() != NULL) {
        ASSERT(spriteCopy->folder()->getFirstLayer());
        static_cast<LayerImage*>(spriteCopy->folder()->getFirstLayer())->configureAsBackground();
      }
      break;

    case DuplicateWithFlattenLayers:
      {
        // Flatten layers
        ASSERT(sourceSprite->folder() != NULL);

        LayerImage* flatLayer = create_flatten_layer_copy
            (spriteCopy,
             sourceSprite->folder(),
             gfx::Rect(0, 0, sourceSprite->width(), sourceSprite->height()),
             FrameNumber(0), sourceSprite->lastFrame());

        // Add and select the new flat layer
        spriteCopy->folder()->addLayer(flatLayer);

        // Configure the layer as background only if the original
        // sprite has a background layer.
        if (sourceSprite->backgroundLayer() != NULL)
          flatLayer->configureAsBackground();
      }
      break;
  }

  documentCopy->setMask(mask());
  documentCopy->m_maskVisible = m_maskVisible;
  documentCopy->generateMaskBoundaries();

  return documentCopy.release();
}
Example #17
0
void Document::copyLayerContent(const Layer* sourceLayer0, Document* destDoc, Layer* destLayer0) const
{
  // Copy the layer name
  destLayer0->setName(sourceLayer0->name());

  if (sourceLayer0->isImage() && destLayer0->isImage()) {
    const LayerImage* sourceLayer = static_cast<const LayerImage*>(sourceLayer0);
    LayerImage* destLayer = static_cast<LayerImage*>(destLayer0);

    // copy cels
    CelConstIterator it = sourceLayer->getCelBegin();
    CelConstIterator end = sourceLayer->getCelEnd();

    for (; it != end; ++it) {
      const Cel* sourceCel = *it;
      if (sourceCel->frame() > destLayer->sprite()->lastFrame())
        break;

      base::UniquePtr<Cel> newCel(new Cel(*sourceCel));

      const Image* sourceImage = sourceCel->image();
      ASSERT(sourceImage != NULL);

      Image* newImage = Image::createCopy(sourceImage);
      newCel->setImage(destLayer->sprite()->stock()->addImage(newImage));

      destLayer->addCel(newCel);
      newCel.release();
    }
  }
  else if (sourceLayer0->isFolder() && destLayer0->isFolder()) {
    const LayerFolder* sourceLayer = static_cast<const LayerFolder*>(sourceLayer0);
    LayerFolder* destLayer = static_cast<LayerFolder*>(destLayer0);

    LayerConstIterator it = sourceLayer->getLayerBegin();
    LayerConstIterator end = sourceLayer->getLayerEnd();

    for (; it != end; ++it) {
      Layer* sourceChild = *it;
      base::UniquePtr<Layer> destChild(NULL);

      if (sourceChild->isImage()) {
        destChild.reset(new LayerImage(destLayer->sprite()));
        copyLayerContent(sourceChild, destDoc, destChild);
      }
      else if (sourceChild->isFolder()) {
        destChild.reset(new LayerFolder(destLayer->sprite()));
        copyLayerContent(sourceChild, destDoc, destChild);
      }
      else {
        ASSERT(false);
      }

      ASSERT(destChild != NULL);

      // Add the new layer in the sprite.

      Layer* newLayer = destChild.release();
      Layer* afterThis = destLayer->getLastLayer();

      destLayer->addLayer(newLayer);
      destChild.release();

      destLayer->stackLayer(newLayer, afterThis);
    }
  }
  else  {
    ASSERT(false && "Trying to copy two incompatible layers");
  }
}
Example #18
0
void Document::copyLayerContent(const Layer* sourceLayer0, Document* destDoc, Layer* destLayer0) const
{
  LayerFlags dstFlags = sourceLayer0->flags();

  // Remove the "background" flag if the destDoc already has a background layer.
  if (((int)dstFlags & (int)LayerFlags::Background) == (int)LayerFlags::Background &&
      (destDoc->sprite()->backgroundLayer())) {
    dstFlags = (LayerFlags)((int)dstFlags & ~(int)(LayerFlags::BackgroundLayerFlags));
  }

  // Copy the layer name
  destLayer0->setName(sourceLayer0->name());
  destLayer0->setFlags(dstFlags);

  if (sourceLayer0->isImage() && destLayer0->isImage()) {
    const LayerImage* sourceLayer = static_cast<const LayerImage*>(sourceLayer0);
    LayerImage* destLayer = static_cast<LayerImage*>(destLayer0);

    // copy cels
    CelConstIterator it = sourceLayer->getCelBegin();
    CelConstIterator end = sourceLayer->getCelEnd();

    std::map<ObjectId, Cel*> linked;

    for (; it != end; ++it) {
      const Cel* sourceCel = *it;
      if (sourceCel->frame() > destLayer->sprite()->lastFrame())
        break;

      base::UniquePtr<Cel> newCel;

      auto it = linked.find(sourceCel->data()->id());
      if (it != linked.end()) {
        newCel.reset(Cel::createLink(it->second));
        newCel->setFrame(sourceCel->frame());
      }
      else {
        newCel.reset(Cel::createCopy(sourceCel));
        linked.insert(std::make_pair(sourceCel->data()->id(), newCel.get()));
      }

      destLayer->addCel(newCel);
      newCel.release();
    }
  }
  else if (sourceLayer0->isFolder() && destLayer0->isFolder()) {
    const LayerFolder* sourceLayer = static_cast<const LayerFolder*>(sourceLayer0);
    LayerFolder* destLayer = static_cast<LayerFolder*>(destLayer0);

    LayerConstIterator it = sourceLayer->getLayerBegin();
    LayerConstIterator end = sourceLayer->getLayerEnd();

    for (; it != end; ++it) {
      Layer* sourceChild = *it;
      base::UniquePtr<Layer> destChild(NULL);

      if (sourceChild->isImage()) {
        destChild.reset(new LayerImage(destLayer->sprite()));
        copyLayerContent(sourceChild, destDoc, destChild);
      }
      else if (sourceChild->isFolder()) {
        destChild.reset(new LayerFolder(destLayer->sprite()));
        copyLayerContent(sourceChild, destDoc, destChild);
      }
      else {
        ASSERT(false);
      }

      ASSERT(destChild != NULL);

      // Add the new layer in the sprite.

      Layer* newLayer = destChild.release();
      Layer* afterThis = destLayer->getLastLayer();

      destLayer->addLayer(newLayer);
      destChild.release();

      destLayer->stackLayer(newLayer, afterThis);
    }
  }
  else  {
    ASSERT(false && "Trying to copy two incompatible layers");
  }
}
Example #19
0
// Gives to the user the possibility to move the sprite's layer in the
// current editor, returns true if the position was changed.
int interactive_move_layer(int mode, bool use_undo, int (*callback)())
{
    Editor* editor = current_editor;
    Document* document = editor->getDocument();
    undo::UndoHistory* undo = document->getUndoHistory();
    Sprite* sprite = document->getSprite();

    ASSERT(sprite->getCurrentLayer()->is_image());

    LayerImage* layer = static_cast<LayerImage*>(sprite->getCurrentLayer());
    Cel *cel = layer->getCel(sprite->getCurrentFrame());
    int start_x, new_x;
    int start_y, new_y;
    int start_b;
    int ret;
    int update = false;
    int quiet_clock = -1;
    int first_time = true;
    int begin_x;
    int begin_y;

    if (!cel)
        return false;

    begin_x = cel->getX();
    begin_y = cel->getY();

    editor->hideDrawingCursor();
    jmouse_set_cursor(JI_CURSOR_MOVE);

    editor->editor_click_start(mode, &start_x, &start_y, &start_b);

    do {
        if (update) {
            cel->setPosition(begin_x - start_x + new_x,
                             begin_y - start_y + new_y);

            // Update layer-bounds.
            editor->invalidate();

            // Update status bar.
            app_get_statusbar()->setStatusText
            (0,
             "Pos %3d %3d Offset %3d %3d",
             (int)cel->getX(),
             (int)cel->getY(),
             (int)(cel->getX() - begin_x),
             (int)(cel->getY() - begin_y));

            /* update clock */
            quiet_clock = ji_clock;
            first_time = false;
        }

        /* call the user's routine */
        if (callback)
            (*callback)();

        /* redraw dirty widgets */
        jwidget_flush_redraw(ji_get_default_manager());
        jmanager_dispatch_messages(ji_get_default_manager());

        gui_feedback();
    } while (editor->editor_click(&new_x, &new_y, &update, NULL));

    new_x = cel->getX();
    new_y = cel->getY();
    cel->setPosition(begin_x, begin_y);

    /* the position was changed */
    if (!editor->editor_click_cancel()) {
        if (use_undo && undo->isEnabled()) {
            undo->setLabel("Cel Movement");
            undo->setModification(undo::ModifyDocument);

            undo->pushUndoer(new undoers::SetCelPosition(undo->getObjects(), cel));
        }

        cel->setPosition(new_x, new_y);
        ret = true;
    }
    /* the position wasn't changed */
    else {
        ret = false;
    }

    /* redraw the sprite in all editors */
    update_screen_for_document(document);

    /* restore the cursor */
    editor->showDrawingCursor();

    editor->editor_click_done();

    return ret;
}
Example #20
0
/**
 * Shows the "New Sprite" dialog.
 */
void NewFileCommand::onExecute(Context* context)
{
  Preferences& pref = Preferences::instance();
  int ncolors = get_default_palette()->size();
  char buf[1024];
  app::Color bg_table[] = {
    app::Color::fromMask(),
    app::Color::fromRgb(255, 255, 255),
    app::Color::fromRgb(0, 0, 0),
  };

  // Load the window widget
  app::gen::NewSprite window;

  // Default values: Indexed, 320x240, Background color
  PixelFormat format = pref.newFile.colorMode();
  // Invalid format in config file.
  if (format != IMAGE_RGB &&
      format != IMAGE_INDEXED &&
      format != IMAGE_GRAYSCALE) {
    format = IMAGE_INDEXED;
  }
  int w = pref.newFile.width();
  int h = pref.newFile.height();
  int bg = pref.newFile.backgroundColor();
  bg = MID(0, bg, 2);

  // If the clipboard contains an image, we can show the size of the
  // clipboard as default image size.
  gfx::Size clipboardSize;
  if (clipboard::get_image_size(clipboardSize)) {
    w = clipboardSize.w;
    h = clipboardSize.h;
  }

  window.width()->setTextf("%d", MAX(1, w));
  window.height()->setTextf("%d", MAX(1, h));

  // Select image-type
  window.colorMode()->setSelectedItem(format);

  // Select background color
  window.bgColor()->setSelectedItem(bg);

  // Advance options
  bool advanced = pref.newFile.advanced();
  window.advancedCheck()->setSelected(advanced);
  window.advancedCheck()->Click.connect(
    base::Bind<void>(
      [&]{
        gfx::Rect bounds = window.bounds();
        window.advanced()->setVisible(window.advancedCheck()->isSelected());
        window.setBounds(gfx::Rect(window.bounds().origin(),
                                   window.sizeHint()));
        window.layout();

        window.manager()->invalidateRect(bounds);
      }));
  window.advanced()->setVisible(advanced);
  if (advanced)
    window.pixelRatio()->setValue(pref.newFile.pixelRatio());
  else
    window.pixelRatio()->setValue("1:1");

  // Open the window
  window.openWindowInForeground();

  if (window.closer() == window.okButton()) {
    bool ok = false;

    // Get the options
    format = (doc::PixelFormat)window.colorMode()->selectedItem();
    w = window.width()->textInt();
    h = window.height()->textInt();
    bg = window.bgColor()->selectedItem();

    static_assert(IMAGE_RGB == 0, "RGB pixel format should be 0");
    static_assert(IMAGE_INDEXED == 2, "Indexed pixel format should be 2");

    format = MID(IMAGE_RGB, format, IMAGE_INDEXED);
    w = MID(1, w, DOC_SPRITE_MAX_WIDTH);
    h = MID(1, h, DOC_SPRITE_MAX_HEIGHT);
    bg = MID(0, bg, 2);

    // Select the color
    app::Color color = app::Color::fromMask();

    if (bg >= 0 && bg <= 3) {
      color = bg_table[bg];
      ok = true;
    }

    if (ok) {
      // Save the configuration
      pref.newFile.width(w);
      pref.newFile.height(h);
      pref.newFile.colorMode(format);
      pref.newFile.backgroundColor(bg);
      pref.newFile.advanced(window.advancedCheck()->isSelected());
      pref.newFile.pixelRatio(window.pixelRatio()->getValue());

      // Create the new sprite
      ASSERT(format == IMAGE_RGB || format == IMAGE_GRAYSCALE || format == IMAGE_INDEXED);
      ASSERT(w > 0 && h > 0);

      std::unique_ptr<Sprite> sprite(Sprite::createBasicSprite(format, w, h, ncolors));

      if (window.advancedCheck()->isSelected()) {
        sprite->setPixelRatio(
          base::convert_to<PixelRatio>(window.pixelRatio()->getValue()));
      }

      if (sprite->pixelFormat() != IMAGE_GRAYSCALE)
        get_default_palette()->copyColorsTo(sprite->palette(frame_t(0)));

      // If the background color isn't transparent, we have to
      // convert the `Layer 1' in a `Background'
      if (color.getType() != app::Color::MaskType) {
        Layer* layer = sprite->root()->firstLayer();

        if (layer && layer->isImage()) {
          LayerImage* layerImage = static_cast<LayerImage*>(layer);
          layerImage->configureAsBackground();

          Image* image = layerImage->cel(frame_t(0))->image();

          // TODO Replace this adding a new parameter to color utils
          Palette oldPal = *get_current_palette();
          set_current_palette(get_default_palette(), false);

          doc::clear_image(image,
            color_utils::color_for_target(color,
              ColorTarget(
                ColorTarget::BackgroundLayer,
                sprite->pixelFormat(),
                sprite->transparentColor())));

          set_current_palette(&oldPal, false);
        }
      }

      // Show the sprite to the user
      std::unique_ptr<Doc> doc(new Doc(sprite.get()));
      sprite.release();
      sprintf(buf, "Sprite-%04d", ++_sprite_counter);
      doc->setFilename(buf);
      doc->setContext(context);
      doc.release();
    }
  }
}
Example #21
0
void Document::copyLayerContent(const Layer* sourceLayer0, Document* destDoc, Layer* destLayer0) const
{
  DocumentUndo* undo = destDoc->getUndo();

  // Copy the layer name
  destLayer0->setName(sourceLayer0->getName());

  if (sourceLayer0->isImage() && destLayer0->isImage()) {
    const LayerImage* sourceLayer = static_cast<const LayerImage*>(sourceLayer0);
    LayerImage* destLayer = static_cast<LayerImage*>(destLayer0);

    // copy cels
    CelConstIterator it = sourceLayer->getCelBegin();
    CelConstIterator end = sourceLayer->getCelEnd();

    for (; it != end; ++it) {
      const Cel* sourceCel = *it;
      UniquePtr<Cel> newCel(new Cel(*sourceCel));

      ASSERT((sourceCel->getImage() >= 0) &&
             (sourceCel->getImage() < sourceLayer->getSprite()->getStock()->size()));

      const Image* sourceImage = sourceLayer->getSprite()->getStock()->getImage(sourceCel->getImage());
      ASSERT(sourceImage != NULL);

      Image* newImage = Image::createCopy(sourceImage);
      newCel->setImage(destLayer->getSprite()->getStock()->addImage(newImage));

      if (undo->isEnabled()) {
        undo->pushUndoer(new undoers::AddImage(undo->getObjects(),
            destLayer->getSprite()->getStock(),
            newCel->getImage()));
      }

      destLayer->addCel(newCel);
      newCel.release();
    }
  }
  else if (sourceLayer0->isFolder() && destLayer0->isFolder()) {
    const LayerFolder* sourceLayer = static_cast<const LayerFolder*>(sourceLayer0);
    LayerFolder* destLayer = static_cast<LayerFolder*>(destLayer0);

    LayerConstIterator it = sourceLayer->getLayerBegin();
    LayerConstIterator end = sourceLayer->getLayerEnd();

    for (; it != end; ++it) {
      Layer* sourceChild = *it;
      UniquePtr<Layer> destChild(NULL);

      if (sourceChild->isImage()) {
        destChild.reset(new LayerImage(destLayer->getSprite()));
        copyLayerContent(sourceChild, destDoc, destChild);
      }
      else if (sourceChild->isFolder()) {
        destChild.reset(new LayerFolder(destLayer->getSprite()));
        copyLayerContent(sourceChild, destDoc, destChild);
      }
      else {
        ASSERT(false);
      }

      ASSERT(destChild != NULL);

      // Add the new layer in the sprite.
      destDoc->getApi().addLayer(destLayer,
                                 destChild.release(),
                                 destLayer->getLastLayer());
    }
  }
  else  {
    ASSERT(false && "Trying to copy two incompatible layers");
  }
}
Example #22
0
void UndoTransaction::flattenLayers(int bgcolor)
{
  Image* cel_image;
  Cel* cel;
  int frame;

  // create a temporary image
  UniquePtr<Image> image_wrap(Image::create(m_sprite->getPixelFormat(),
                                            m_sprite->getWidth(),
                                            m_sprite->getHeight()));
  Image* image = image_wrap.get();

  /* get the background layer from the sprite */
  LayerImage* background = m_sprite->getBackgroundLayer();
  if (!background) {
    /* if there aren't a background layer we must to create the background */
    background = new LayerImage(m_sprite);

    if (isEnabled())
      m_undoHistory->pushUndoer(new undoers::AddLayer(m_undoHistory->getObjects(),
          m_sprite->getFolder(), background));

    m_sprite->getFolder()->add_layer(background);

    if (isEnabled())
      m_undoHistory->pushUndoer(new undoers::MoveLayer(m_undoHistory->getObjects(),
          background));

    background->configureAsBackground();
  }

  /* copy all frames to the background */
  for (frame=0; frame<m_sprite->getTotalFrames(); frame++) {
    /* clear the image and render this frame */
    image_clear(image, bgcolor);
    layer_render(m_sprite->getFolder(), image, 0, 0, frame);

    cel = background->getCel(frame);
    if (cel) {
      cel_image = m_sprite->getStock()->getImage(cel->getImage());
      ASSERT(cel_image != NULL);

      /* we have to save the current state of `cel_image' in the undo */
      if (isEnabled()) {
        Dirty* dirty = new Dirty(cel_image, image);
        dirty->saveImagePixels(cel_image);
        m_undoHistory->pushUndoer(new undoers::DirtyArea(
            m_undoHistory->getObjects(), cel_image, dirty));
        delete dirty;
      }
    }
    else {
      /* if there aren't a cel in this frame in the background, we
         have to create a copy of the image for the new cel */
      cel_image = Image::createCopy(image);
      /* TODO error handling: if (!cel_image) { ... } */

      /* here we create the new cel (with the new image `cel_image') */
      cel = new Cel(frame, m_sprite->getStock()->addImage(cel_image));
      /* TODO error handling: if (!cel) { ... } */

      /* and finally we add the cel in the background */
      background->addCel(cel);
    }

    image_copy(cel_image, image, 0, 0);
  }

  /* select the background */
  if (m_sprite->getCurrentLayer() != background) {
    if (isEnabled())
      m_undoHistory->pushUndoer(new undoers::SetCurrentLayer(
          m_undoHistory->getObjects(), m_sprite));

    m_sprite->setCurrentLayer(background);
  }

  // Remove old layers.
  LayerList layers = m_sprite->getFolder()->get_layers_list();
  LayerIterator it = layers.begin();
  LayerIterator end = layers.end();

  for (; it != end; ++it) {
    if (*it != background) {
      Layer* old_layer = *it;

      // Remove the layer
      if (isEnabled())
        m_undoHistory->pushUndoer(new undoers::RemoveLayer(m_undoHistory->getObjects(),
            old_layer));

      m_sprite->getFolder()->remove_layer(old_layer);

      // Destroy the layer
      delete old_layer;
    }
  }
}
Example #23
0
bool FliFormat::onLoad(FileOp* fop)
{
#define SETPAL()                                                \
  do {                                                          \
      for (c=0; c<256; c++) {                                   \
        pal->setEntry(c, rgba(cmap[c*3],                       \
                               cmap[c*3+1],                     \
                               cmap[c*3+2], 255));              \
      }                                                         \
      pal->setFrame(frpos_out);                                 \
      sprite->setPalette(pal, true);                            \
    } while (0)

  unsigned char cmap[768];
  unsigned char omap[768];
  s_fli_header fli_header;
  int c, w, h;
  FrameNumber frpos_in;
  FrameNumber frpos_out;
  int index = 0;

  // Open the file to read in binary mode
  FileHandle f(open_file_with_exception(fop->filename, "rb"));

  fli_read_header(f, &fli_header);
  fseek(f, 128, SEEK_SET);

  if (fli_header.magic == NO_HEADER) {
    fop_error(fop, "The file doesn't have a FLIC header\n");
    return false;
  }

  /* size by frame */
  w = fli_header.width;
  h = fli_header.height;

  // Create the bitmaps
  base::UniquePtr<Image> bmp(Image::create(IMAGE_INDEXED, w, h));
  base::UniquePtr<Image> old(Image::create(IMAGE_INDEXED, w, h));
  base::UniquePtr<Palette> pal(new Palette(FrameNumber(0), 256));

  // Create the image
  Sprite* sprite = new Sprite(IMAGE_INDEXED, w, h, 256);
  LayerImage* layer = new LayerImage(sprite);
  sprite->folder()->addLayer(layer);
  layer->configureAsBackground();

  // Set frames and speed
  sprite->setTotalFrames(FrameNumber(fli_header.frames));
  sprite->setDurationForAllFrames(fli_header.speed);

  /* write frame by frame */
  for (frpos_in = frpos_out = FrameNumber(0);
       frpos_in < sprite->totalFrames();
       ++frpos_in) {
    /* read the frame */
    fli_read_frame(f, &fli_header,
                   (unsigned char *)old->getPixelAddress(0, 0), omap,
                   (unsigned char *)bmp->getPixelAddress(0, 0), cmap);

    /* first frame, or the frames changes, or the palette changes */
    if ((frpos_in == 0) ||
        (count_diff_between_images(old, bmp))
#ifndef USE_LINK /* TODO this should be configurable through a check-box */
        || (memcmp(omap, cmap, 768) != 0)
#endif
        ) {
      /* the image changes? */
      if (frpos_in != 0)
        ++frpos_out;

      // Add the new frame
      Image* image = Image::createCopy(bmp);
      index = sprite->stock()->addImage(image);

      Cel* cel = new Cel(frpos_out, index);
      layer->addCel(cel);

      /* first frame or the palette changes */
      if ((frpos_in == 0) || (memcmp(omap, cmap, 768) != 0))
        SETPAL();
    }
#ifdef USE_LINK
    /* the palette changes */
    else if (memcmp(omap, cmap, 768) != 0) {
      ++frpos_out;
      SETPAL();

      // Add link
      Cel* cel = new Cel(frpos_out, index);
      layer_add_cel(layer, cel);
    }
#endif
    // The palette and the image don't change: add duration to the last added frame
    else {
      sprite->setFrameDuration(frpos_out,
                               sprite->getFrameDuration(frpos_out)+fli_header.speed);
    }

    /* update the old image and color-map to the new ones to compare later */
    copy_image(old, bmp, 0, 0);
    memcpy(omap, cmap, 768);

    /* update progress */
    fop_progress(fop, (float)(frpos_in+1) / (float)(sprite->totalFrames()));
    if (fop_is_stop(fop))
      break;

    /* just one frame? */
    if (fop->oneframe)
      break;
  }

  // Update number of frames
  sprite->setTotalFrames(frpos_out.next());

  fop->createDocument(sprite);
  return true;
}
Example #24
0
bool FliFormat::onLoad(FileOp* fop)
{
  // Open the file to read in binary mode
  FileHandle handle(open_file_with_exception(fop->filename, "rb"));
  FILE* f = handle.get();
  flic::StdioFileInterface finterface(f);
  flic::Decoder decoder(&finterface);

  flic::Header header;
  if (!decoder.readHeader(header)) {
    fop_error(fop, "The file doesn't have a FLIC header\n");
    return false;
  }

  // Size by frame
  int w = header.width;
  int h = header.height;

  // Create a temporal bitmap
  ImageRef bmp(Image::create(IMAGE_INDEXED, w, h));
  Palette pal(0, 1);
  Cel* prevCel = nullptr;

  // Create the sprite
  Sprite* sprite = new Sprite(IMAGE_INDEXED, w, h, 256);
  LayerImage* layer = new LayerImage(sprite);
  sprite->folder()->addLayer(layer);
  layer->configureAsBackground();

  // Set frames and speed
  sprite->setTotalFrames(frame_t(header.frames));
  sprite->setDurationForAllFrames(header.speed);

  flic::Frame fliFrame;
  flic::Colormap oldFliColormap;
  fliFrame.pixels = bmp->getPixelAddress(0, 0);
  fliFrame.rowstride = IndexedTraits::getRowStrideBytes(bmp->width());

  frame_t frame_out = 0;
  for (frame_t frame_in=0;
       frame_in<sprite->totalFrames();
       ++frame_in) {
    // Read the frame
    if (!decoder.readFrame(fliFrame)) {
      fop_error(fop, "Error reading frame %d\n", frame_in);
      continue;
    }

    // Palette change
    bool palChange = false;
    if (frame_out == 0 || oldFliColormap != fliFrame.colormap) {
      oldFliColormap = fliFrame.colormap;

      pal.resize(fliFrame.colormap.size());
      for (int c=0; c<int(fliFrame.colormap.size()); c++) {
        pal.setEntry(c, rgba(fliFrame.colormap[c].r,
                             fliFrame.colormap[c].g,
                             fliFrame.colormap[c].b, 255));
      }
      pal.setFrame(frame_out);
      sprite->setPalette(&pal, true);

      palChange = true;
    }

    // First frame, or the frame changes
    if (!prevCel ||
        (count_diff_between_images(prevCel->image(), bmp.get()))) {
      // Add the new frame
      ImageRef image(Image::createCopy(bmp.get()));
      Cel* cel = new Cel(frame_out, image);
      layer->addCel(cel);

      prevCel = cel;
      ++frame_out;
    }
    else if (palChange) {
      Cel* cel = Cel::createLink(prevCel);
      cel->setFrame(frame_out);
      layer->addCel(cel);

      ++frame_out;
    }
    // The palette and the image don't change: add duration to the last added frame
    else {
      sprite->setFrameDuration(
        frame_out-1, sprite->frameDuration(frame_out-1) + header.speed);
    }

    if (header.frames > 0)
      fop_progress(fop, (float)(frame_in+1) / (float)(header.frames));

    if (fop_is_stop(fop))
      break;

    if (fop->oneframe)
      break;
  }

  if (frame_out > 0)
    sprite->setTotalFrames(frame_out);

  fop->createDocument(sprite);
  return true;
}
Example #25
0
void FlattenLayers::onExecute()
{
  Sprite* sprite = this->sprite();
  auto doc = static_cast<Doc*>(sprite->document());

  // Create a temporary image.
  ImageRef image(Image::create(sprite->pixelFormat(),
      sprite->width(),
      sprite->height()));

  LayerImage* flatLayer;  // The layer onto which everything will be flattened.
  color_t     bgcolor;    // The background color to use for flatLayer.

  flatLayer = sprite->backgroundLayer();
  if (flatLayer && flatLayer->isVisible()) {
    // There exists a visible background layer, so we will flatten onto that.
    bgcolor = doc->bgColor(flatLayer);
  }
  else {
    // Create a new transparent layer to flatten everything onto.
    flatLayer = new LayerImage(sprite);
    ASSERT(flatLayer->isVisible());
    executeAndAdd(new cmd::AddLayer(sprite->root(), flatLayer, nullptr));
    executeAndAdd(new cmd::SetLayerName(flatLayer, "Flattened"));
    bgcolor = sprite->transparentColor();
  }

  render::Render render;
  render.setBgType(render::BgType::NONE);

  // Copy all frames to the background.
  for (frame_t frame(0); frame<sprite->totalFrames(); ++frame) {
    // Clear the image and render this frame.
    clear_image(image.get(), bgcolor);
    render.renderSprite(image.get(), sprite, frame);

    // TODO Keep cel links when possible

    ImageRef cel_image;
    Cel* cel = flatLayer->cel(frame);
    if (cel) {
      if (cel->links())
        executeAndAdd(new cmd::UnlinkCel(cel));

      cel_image = cel->imageRef();
      ASSERT(cel_image);

      executeAndAdd(new cmd::CopyRect(cel_image.get(), image.get(),
          gfx::Clip(0, 0, image->bounds())));
    }
    else {
      cel_image.reset(Image::createCopy(image.get()));
      cel = new Cel(frame, cel_image);
      flatLayer->addCel(cel);
    }
  }

  // Delete old layers.
  LayerList layers = sprite->root()->layers();
  for (Layer* layer : layers)
    if (layer != flatLayer)
      executeAndAdd(new cmd::RemoveLayer(layer));
}
Example #26
0
void DocumentApi::flattenLayers(Sprite* sprite, int bgcolor)
{
  Image* cel_image;
  Cel* cel;

  DocumentUndo* undo = m_document->getUndo();

  // Create a temporary image.
  UniquePtr<Image> image_wrap(Image::create(sprite->getPixelFormat(),
                                            sprite->getWidth(),
                                            sprite->getHeight()));
  Image* image = image_wrap.get();

  // Get the background layer from the sprite.
  LayerImage* background = sprite->getBackgroundLayer();
  if (!background) {
    // If there aren't a background layer we must to create the background.
    background = new LayerImage(sprite);

    addLayer(sprite->getFolder(), background, NULL);
    configureLayerAsBackground(background);
  }

  // Copy all frames to the background.
  for (FrameNumber frame(0); frame<sprite->getTotalFrames(); ++frame) {
    // Clear the image and render this frame.
    image_clear(image, bgcolor);
    layer_render(sprite->getFolder(), image, 0, 0, frame);

    cel = background->getCel(frame);
    if (cel) {
      cel_image = sprite->getStock()->getImage(cel->getImage());
      ASSERT(cel_image != NULL);

      // We have to save the current state of `cel_image' in the undo.
      if (undo->isEnabled()) {
        Dirty* dirty = new Dirty(cel_image, image);
        dirty->saveImagePixels(cel_image);
        m_undoers->pushUndoer(new undoers::DirtyArea(
            getObjects(), cel_image, dirty));
        delete dirty;
      }
    }
    else {
      // If there aren't a cel in this frame in the background, we
      // have to create a copy of the image for the new cel.
      cel_image = Image::createCopy(image);
      // TODO error handling: if createCopy throws

      // Here we create the new cel (with the new image `cel_image').
      cel = new Cel(frame, sprite->getStock()->addImage(cel_image));
      // TODO error handling: if new Cel throws

      // And finally we add the cel in the background.
      background->addCel(cel);
    }

    image_copy(cel_image, image, 0, 0);
  }

  // Delete old layers.
  LayerList layers = sprite->getFolder()->getLayersList();
  LayerIterator it = layers.begin();
  LayerIterator end = layers.end();
  for (; it != end; ++it)
    if (*it != background)
      removeLayer(*it);
}