Exemple #1
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;
}
Exemple #2
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));
    }
  }
}
Exemple #3
0
bool PixlyFormat::onLoad(FileOp* fop)
{
  try {
    // load XML metadata
    XmlDocumentRef doc = open_xml(fop->filename());
    TiXmlHandle xml(doc.get());
    fop->setProgress(0.25);

    TiXmlElement* xmlAnim = check(xml.FirstChild("PixlyAnimation").ToElement());
    double version = check_number<double>(xmlAnim->Attribute("version"));
    if (version < 1.5) {
      throw Exception("version 1.5 or above required");
    }

    TiXmlElement* xmlInfo = check(xmlAnim->FirstChild("Info"))->ToElement();

    int layerCount  = check_number<int>(xmlInfo->Attribute("layerCount"));
    int frameWidth  = check_number<int>(xmlInfo->Attribute("frameWidth"));
    int frameHeight = check_number<int>(xmlInfo->Attribute("frameHeight"));

    UniquePtr<Sprite> sprite(new Sprite(IMAGE_RGB, frameWidth, frameHeight, 0));

    TiXmlElement* xmlFrames = check(xmlAnim->FirstChild("Frames"))->ToElement();
    int imageCount = check_number<int>(xmlFrames->Attribute("length"));

    if (layerCount <= 0 || imageCount <= 0) {
      throw Exception("No cels found");
    }

    int frameCount = imageCount / layerCount;
    sprite->setTotalFrames(frame_t(frameCount));
    sprite->setDurationForAllFrames(200);

    for (int i=0; i<layerCount; i++) {
      sprite->folder()->addLayer(new LayerImage(sprite));
    }

    // load image sheet
    Document* sheet_doc = load_document(nullptr, base::replace_extension(fop->filename(),"png").c_str());
    fop->setProgress(0.5);

    if (sheet_doc == NULL) {
      throw Exception("Pixly loader requires a valid PNG file");
    }

    Image* sheet = sheet_doc->sprite()->layer(0)->cel(0)->image();

    if (sheet->pixelFormat() != IMAGE_RGB) {
      throw Exception("Pixly loader requires a RGBA PNG");
    }

    int sheetWidth = sheet->width();
    int sheetHeight = sheet->height();

    // slice cels from sheet
    std::vector<int> visible(layerCount, 0);

    TiXmlElement* xmlFrame = check(xmlFrames->FirstChild("Frame"))->ToElement();
    while (xmlFrame) {
      TiXmlElement* xmlRegion = check(xmlFrame->FirstChild("Region"))->ToElement();
      TiXmlElement* xmlIndex = check(xmlFrame->FirstChild("Index"))->ToElement();

      int index = check_number<int>(xmlIndex->Attribute("linear"));
      frame_t frame(index / layerCount);
      LayerIndex layer_index(index % layerCount);
      Layer *layer = sprite->indexToLayer(layer_index);

      const char * duration = xmlFrame->Attribute("duration");
      if (duration) {
        sprite->setFrameDuration(frame, base::convert_to<int>(std::string(duration)));
      }

      visible[(int)layer_index] += (int)(std::string(check(xmlFrame->Attribute("visible"),"false")) == "true");

      int x0 = check_number<int>(xmlRegion->Attribute("x"));
      int y0_up = check_number<int>(xmlRegion->Attribute("y")); // inverted

      if (y0_up < 0 || y0_up + frameHeight > sheetHeight || x0 < 0 || x0 + frameWidth > sheetWidth) {
        throw Exception("looking for cels outside the bounds of the PNG");
      }

      // read cel images
      ImageRef image(Image::create(IMAGE_RGB, frameWidth, frameHeight));

      for (int y = 0; y < frameHeight; y++) {
        // RGB_ALPHA
        int y0_down = sheetHeight-1 - y0_up - (frameHeight-1) + y;
        uint32_t* src_begin = (uint32_t*)sheet->getPixelAddress(x0           , y0_down);
        uint32_t* src_end   = (uint32_t*)sheet->getPixelAddress(x0+frameWidth, y0_down);
        uint32_t* dst_begin = (uint32_t*)image->getPixelAddress(0, y);

        std::copy(src_begin, src_end, dst_begin);
      }

      // make cel trimmed or empty
      gfx::Rect bounds;
      if (algorithm::shrink_bounds(image.get(), bounds, image->maskColor())) {
        ImageRef trim_image(crop_image(image.get(),
                                  bounds.x, bounds.y,
                                  bounds.w, bounds.h,
                                  image->maskColor()));


        Cel* cel = NULL;
        if ((int)frame > 0) {
          // link identical neighbors
          Cel *prev_cel = static_cast<LayerImage*>(layer)->cel(frame-1);
          if (prev_cel && prev_cel->x() == bounds.x && prev_cel->y() == bounds.y) {
            Image *prev_image = prev_cel->image();
            if (prev_image && doc::count_diff_between_images(prev_image, trim_image.get()) == 0) {
              cel = Cel::createLink(prev_cel);
              cel->setFrame(frame);
            } // count_diff_between_images
          } // prev_cel
        } // frame > 0

        if (cel == NULL) {
          cel = new Cel(frame, trim_image);
          cel->setPosition(bounds.x, bounds.y);
        }

        static_cast<LayerImage*>(layer)->addCel(cel);

      }

      xmlFrame = xmlFrame->NextSiblingElement();
      fop->setProgress(0.5 + 0.5 * ((float)(index+1) / (float)imageCount));
    }

    for (int i=0; i<layerCount; i++) {
      LayerIndex layer_index(i);
      Layer *layer = sprite->indexToLayer(layer_index);
      layer->setVisible(visible[i] > frameCount/2);
    }

    fop->createDocument(sprite);
    sprite.release();
  }
  catch(Exception &e) {
    fop->setError((std::string("Pixly file format: ")+std::string(e.what())+"\n").c_str());
    return false;
  }

  return true;
}