// ***************************************************************************** gbt_link_format::gbt_link_format() { frame_packet[0] = frame_t(); frame_packet[1] = frame_t(); return; }
void SetLoopSectionCommand::onLoadParams(const Params& params) { std::string action = params.get("action"); if (action == "on") m_action = Action::On; else if (action == "off") m_action = Action::Off; else m_action = Action::Auto; std::string begin = params.get("begin"); std::string end = params.get("end"); m_begin = frame_t(strtol(begin.c_str(), NULL, 10)); m_end = frame_t(strtol(end.c_str(), NULL, 10)); }
void reverse_frames(Document* doc, const DocumentRange& range) { const app::Context* context = static_cast<app::Context*>(doc->context()); const ContextReader reader(context); ContextWriter writer(reader); Transaction transaction(writer.context(), "Reverse Frames"); DocumentApi api = doc->getApi(transaction); Sprite* sprite = doc->sprite(); frame_t frameBegin, frameEnd; int layerBegin, layerEnd; bool moveFrames = false; switch (range.type()) { case DocumentRange::kCels: frameBegin = range.frameBegin(); frameEnd = range.frameEnd(); layerBegin = range.layerBegin(); layerEnd = range.layerEnd() + 1; break; case DocumentRange::kFrames: frameBegin = range.frameBegin(); frameEnd = range.frameEnd(); moveFrames = true; break; case DocumentRange::kLayers: frameBegin = frame_t(0); frameEnd = sprite->totalFrames()-1; layerBegin = range.layerBegin(); layerEnd = range.layerEnd() + 1; break; } if (moveFrames) { for (frame_t frameRev = frameEnd+1; frameRev > frameBegin; --frameRev) { api.moveFrame(sprite, frameBegin, frameRev); } } else { std::vector<Layer*> layers; sprite->getLayersList(layers); for (int layerIdx = layerBegin; layerIdx != layerEnd; ++layerIdx) { for (frame_t frame = frameBegin, frameRev = frameEnd; frame != (frameBegin+frameEnd)/2+1; ++frame, --frameRev) { LayerImage* layer = static_cast<LayerImage*>(layers[layerIdx]); api.swapCel(layer, frame, frameRev); } } } transaction.commit(); }
void Sprite::setTotalFrames(frame_t frames) { frames = MAX(frame_t(1), frames); m_frlens.resize(frames); if (frames > m_frames) { for (frame_t c=m_frames; c<frames; ++c) m_frlens[c] = m_frlens[m_frames-1]; } m_frames = frames; }
Sprite::Sprite(PixelFormat format, int width, int height, int ncolors) : Object(ObjectType::Sprite) , m_document(NULL) , m_format(format) , m_width(width) , m_height(height) , m_frames(1) , m_frameTags(this) { ASSERT(width > 0 && height > 0); m_frlens.push_back(100); // First frame with 100 msecs of duration m_folder = new LayerFolder(this); // Generate palette switch (format) { case IMAGE_GRAYSCALE: ncolors = 256; break; case IMAGE_BITMAP: ncolors = 2; break; } Palette pal(frame_t(0), ncolors); switch (format) { // For black and white images case IMAGE_GRAYSCALE: case IMAGE_BITMAP: for (int c=0; c<ncolors; c++) { int g = 255 * c / (ncolors-1); g = MID(0, g, 255); pal.setEntry(c, rgba(g, g, g, 255)); } break; } // Initial RGB map m_rgbMap = NULL; // The transparent color for indexed images is 0 by default m_transparentColor = 0; setPalette(&pal, true); }
void reverse_frames(Doc* doc, const DocRange& range) { const app::Context* context = static_cast<app::Context*>(doc->context()); const ContextReader reader(context); ContextWriter writer(reader, 500); Transaction transaction(writer.context(), "Reverse Frames"); DocApi api = doc->getApi(transaction); Sprite* sprite = doc->sprite(); LayerList layers; frame_t frameBegin, frameEnd; bool moveFrames = false; bool swapCels = false; switch (range.type()) { case DocRange::kCels: frameBegin = range.firstFrame(); frameEnd = range.lastFrame(); layers = range.selectedLayers().toLayerList(); swapCels = true; break; case DocRange::kFrames: frameBegin = range.firstFrame(); frameEnd = range.lastFrame(); layers = sprite->allLayers(); moveFrames = true; break; case DocRange::kLayers: frameBegin = frame_t(0); frameEnd = sprite->totalFrames()-1; layers = range.selectedLayers().toLayerList(); swapCels = true; break; } if (moveFrames) { for (frame_t frameRev = frameEnd+1; frameRev > frameBegin; --frameRev) { api.moveFrame(sprite, frameBegin, frameRev, kDropBeforeFrame, kDontAdjustTags); } } else if (swapCels) { for (Layer* layer : layers) { if (!layer->isImage()) continue; for (frame_t frame = frameBegin, frameRev = frameEnd; frame != (frameBegin+frameEnd)/2+1; ++frame, --frameRev) { if (frame == frameRev) continue; LayerImage* imageLayer = static_cast<LayerImage*>(layer); api.swapCel(imageLayer, frame, frameRev); } } } transaction.setNewDocRange(range); transaction.commit(); }
static DocumentRange drop_range_op( Document* doc, Op op, const DocumentRange& from, DocumentRangePlace place, const DocumentRange& to) { if (place != kDocumentRangeBefore && place != kDocumentRangeAfter) { ASSERT(false); throw std::invalid_argument("Invalid 'place' argument"); } Sprite* sprite = doc->sprite(); // Check noop/trivial/do nothing cases, i.e., move a range to the same place. // Also check invalid cases, like moving a Background layer. switch (from.type()) { case DocumentRange::kCels: if (from == to) return from; break; case DocumentRange::kFrames: if (op == Move) { if ((to.frameBegin() >= from.frameBegin() && to.frameEnd() <= from.frameEnd()) || (place == kDocumentRangeBefore && to.frameBegin() == from.frameEnd()+1) || (place == kDocumentRangeAfter && to.frameEnd() == from.frameBegin()-1)) return from; } break; case DocumentRange::kLayers: if (op == Move) { if ((to.layerBegin() >= from.layerBegin() && to.layerEnd() <= from.layerEnd()) || (place == kDocumentRangeBefore && to.layerBegin() == from.layerEnd()+1) || (place == kDocumentRangeAfter && to.layerEnd() == from.layerBegin()-1)) return from; // We cannot move the background for (LayerIndex i = from.layerBegin(); i <= from.layerEnd(); ++i) if (sprite->indexToLayer(i)->isBackground()) throw std::runtime_error("The background layer cannot be moved"); // Before background if (place == kDocumentRangeBefore) { Layer* background = sprite->indexToLayer(to.layerBegin()); if (background && background->isBackground()) throw std::runtime_error("You cannot move something below the background layer"); } } break; } const char* undoLabel = NULL; switch (op) { case Move: undoLabel = "Move Range"; break; case Copy: undoLabel = "Copy Range"; break; default: ASSERT(false); throw std::invalid_argument("Invalid 'op' argument"); } DocumentRange resultRange; { const app::Context* context = static_cast<app::Context*>(doc->context()); const ContextReader reader(context); ContextWriter writer(reader); Transaction transaction(writer.context(), undoLabel, ModifyDocument); DocumentApi api = doc->getApi(transaction); // TODO Try to add the range with just one call to DocumentApi // methods, to avoid generating a lot of SetCelFrame undoers (see // DocumentApi::setCelFramePosition). switch (from.type()) { case DocumentRange::kCels: { std::vector<Layer*> layers; sprite->getLayersList(layers); int srcLayerBegin, srcLayerStep, srcLayerEnd; int dstLayerBegin, dstLayerStep; frame_t srcFrameBegin, srcFrameStep, srcFrameEnd; frame_t dstFrameBegin, dstFrameStep; if (to.layerBegin() <= from.layerBegin()) { srcLayerBegin = from.layerBegin(); srcLayerStep = 1; srcLayerEnd = from.layerEnd()+1; dstLayerBegin = to.layerBegin(); dstLayerStep = 1; } else { srcLayerBegin = from.layerEnd(); srcLayerStep = -1; srcLayerEnd = from.layerBegin()-1; dstLayerBegin = to.layerEnd(); dstLayerStep = -1; } if (to.frameBegin() <= from.frameBegin()) { srcFrameBegin = from.frameBegin(); srcFrameStep = frame_t(1); srcFrameEnd = from.frameEnd()+1; dstFrameBegin = to.frameBegin(); dstFrameStep = frame_t(1); } else { srcFrameBegin = from.frameEnd(); srcFrameStep = frame_t(-1); srcFrameEnd = from.frameBegin()-1; dstFrameBegin = to.frameEnd(); dstFrameStep = frame_t(-1); } for (int srcLayerIdx = srcLayerBegin, dstLayerIdx = dstLayerBegin; srcLayerIdx != srcLayerEnd; ) { for (frame_t srcFrame = srcFrameBegin, dstFrame = dstFrameBegin; srcFrame != srcFrameEnd; ) { LayerImage* srcLayer = static_cast<LayerImage*>(layers[srcLayerIdx]); LayerImage* dstLayer = static_cast<LayerImage*>(layers[dstLayerIdx]); switch (op) { case Move: api.moveCel(srcLayer, srcFrame, dstLayer, dstFrame); break; case Copy: api.copyCel(srcLayer, srcFrame, dstLayer, dstFrame); break; } srcFrame += srcFrameStep; dstFrame += dstFrameStep; } srcLayerIdx += srcLayerStep; dstLayerIdx += dstLayerStep; } resultRange = to; } break; case DocumentRange::kFrames: { frame_t srcFrameBegin = 0, srcFrameStep, srcFrameEnd = 0; frame_t dstFrameBegin = 0, dstFrameStep; switch (op) { case Move: if (place == kDocumentRangeBefore) { if (to.frameBegin() <= from.frameBegin()) { srcFrameBegin = from.frameBegin(); srcFrameStep = frame_t(1); srcFrameEnd = from.frameEnd()+1; dstFrameBegin = to.frameBegin(); dstFrameStep = frame_t(1); } else { srcFrameBegin = from.frameEnd(); srcFrameStep = frame_t(-1); srcFrameEnd = from.frameBegin()-1; dstFrameBegin = to.frameBegin(); dstFrameStep = frame_t(-1); } } else if (place == kDocumentRangeAfter) { if (to.frameEnd() <= from.frameBegin()) { srcFrameBegin = from.frameBegin(); srcFrameStep = frame_t(1); srcFrameEnd = from.frameEnd()+1; dstFrameBegin = to.frameEnd()+1; dstFrameStep = frame_t(1); } else { srcFrameBegin = from.frameEnd(); srcFrameStep = frame_t(-1); srcFrameEnd = from.frameBegin()-1; dstFrameBegin = to.frameEnd()+1; dstFrameStep = frame_t(-1); } } break; case Copy: if (place == kDocumentRangeBefore) { if (to.frameBegin() <= from.frameBegin()) { srcFrameBegin = from.frameBegin(); srcFrameStep = frame_t(2); srcFrameEnd = from.frameBegin() + 2*from.frames(); dstFrameBegin = to.frameBegin(); dstFrameStep = frame_t(1); } else { srcFrameBegin = from.frameEnd(); srcFrameStep = frame_t(-1); srcFrameEnd = from.frameBegin()-1; dstFrameBegin = to.frameBegin(); dstFrameStep = frame_t(0); } } else if (place == kDocumentRangeAfter) { if (to.frameEnd() <= from.frameBegin()) { srcFrameBegin = from.frameBegin(); srcFrameStep = frame_t(2); srcFrameEnd = from.frameBegin() + 2*from.frames(); dstFrameBegin = to.frameEnd()+1; dstFrameStep = frame_t(1); } else { srcFrameBegin = from.frameEnd(); srcFrameStep = frame_t(-1); srcFrameEnd = from.frameBegin()-1; dstFrameBegin = to.frameEnd()+1; dstFrameStep = frame_t(0); } } break; } for (frame_t srcFrame = srcFrameBegin, dstFrame = dstFrameBegin; srcFrame != srcFrameEnd; ) { switch (op) { case Move: api.moveFrame(sprite, srcFrame, dstFrame); break; case Copy: api.copyFrame(sprite, srcFrame, dstFrame); break; } srcFrame += srcFrameStep; dstFrame += dstFrameStep; } if (place == kDocumentRangeBefore) { resultRange.startRange(LayerIndex::NoLayer, frame_t(to.frameBegin()), from.type()); resultRange.endRange(LayerIndex::NoLayer, frame_t(to.frameBegin()+from.frames()-1)); } else if (place == kDocumentRangeAfter) { resultRange.startRange(LayerIndex::NoLayer, frame_t(to.frameEnd()+1), from.type()); resultRange.endRange(LayerIndex::NoLayer, frame_t(to.frameEnd()+1+from.frames()-1)); } if (op == Move && from.frameBegin() < to.frameBegin()) resultRange.displace(0, -from.frames()); } break; case DocumentRange::kLayers: { std::vector<Layer*> layers; sprite->getLayersList(layers); if (layers.empty()) break; switch (op) { case Move: if (place == kDocumentRangeBefore) { for (LayerIndex i = from.layerBegin(); i <= from.layerEnd(); ++i) { api.restackLayerBefore( layers[i], layers[to.layerBegin()]); } } else if (place == kDocumentRangeAfter) { for (LayerIndex i = from.layerEnd(); i >= from.layerBegin(); --i) { api.restackLayerAfter( layers[i], layers[to.layerEnd()]); } } break; case Copy: if (place == kDocumentRangeBefore) { for (LayerIndex i = from.layerBegin(); i <= from.layerEnd(); ++i) { api.duplicateLayerBefore( layers[i], layers[to.layerBegin()]); } } else if (place == kDocumentRangeAfter) { for (LayerIndex i = from.layerEnd(); i >= from.layerBegin(); --i) { api.duplicateLayerAfter( layers[i], layers[to.layerEnd()]); } } break; } if (place == kDocumentRangeBefore) { resultRange.startRange(LayerIndex(to.layerBegin()), frame_t(-1), from.type()); resultRange.endRange(LayerIndex(to.layerBegin()+from.layers()-1), frame_t(-1)); } else if (place == kDocumentRangeAfter) { resultRange.startRange(LayerIndex(to.layerEnd()+1), frame_t(-1), from.type()); resultRange.endRange(LayerIndex(to.layerEnd()+1+from.layers()-1), frame_t(-1)); } if (op == Move && from.layerBegin() < to.layerBegin()) resultRange.displace(-from.layers(), 0); } break; } transaction.commit(); } return resultRange; }
/** * 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(); } } }
int init_module_palette() { ase_default_palette = new Palette(frame_t(0), 256); ase_current_palette = new Palette(frame_t(0), 256); return 0; }
CelsRange Sprite::uniqueCels() const { return CelsRange(this, frame_t(0), lastFrame(), CelsRange::UNIQUE); }
CelsRange Sprite::cels() const { return CelsRange(this, frame_t(0), lastFrame()); }
/** * 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(); } } }