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"); } }
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; }
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)); }
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"); } }
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; }
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; frame_t frpos_in; frame_t frpos_out; #ifdef USE_LINK int index = 0; // TODO this is used to create linked cels #endif // Open the file to read in binary mode FileHandle handle(open_file_with_exception(fop->filename, "rb")); FILE* f = handle.get(); 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(frame_t(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(frame_t(fli_header.frames)); sprite->setDurationForAllFrames(fli_header.speed); // Write frame by frame for (frpos_in = frpos_out = frame_t(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 ImageRef image(Image::createCopy(bmp)); Cel* cel = new Cel(frpos_out, image); 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->frameDuration(frpos_out)+fli_header.speed); } // Update the old image and color-map to the new ones to compare later copy_image(old, bmp); 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+1); fop->createDocument(sprite); return true; }
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; } } }
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"); } }
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); }