bool MovingCelState::onMouseMove(Editor* editor, MouseMessage* msg) { gfx::Point newCursorPos = editor->screenToEditor(msg->position()); m_celOffset = newCursorPos - m_cursorStart; if (int(editor->getCustomizationDelegate() ->getPressedKeyAction(KeyContext::TranslatingSelection) & KeyAction::LockAxis)) { if (ABS(m_celOffset.x) < ABS(m_celOffset.y)) { m_celOffset.x = 0; } else { m_celOffset.y = 0; } } for (size_t i=0; i<m_celList.size(); ++i) { Cel* cel = m_celList[i]; const gfx::Point& celStart = m_celStarts[i]; cel->setPosition(celStart + m_celOffset); } // Redraw the new cel position. editor->invalidate(); // Use StandbyState implementation return StandbyState::onMouseMove(editor, msg); }
/** * Returns a new layer (flat_layer) with all "layer" rendered frame by * frame from "frmin" to "frmax" (inclusive). "layer" can be a set of * layers, so the routine flattens all children to an unique output * layer. * * @param dst_sprite The sprite where to put the new flattened layer. * @param src_layer Generally a set of layers to be flattened. */ LayerImage* layer_new_flatten_copy(Sprite* dst_sprite, const Layer* src_layer, int x, int y, int w, int h, int frmin, int frmax) { UniquePtr<LayerImage> flatLayer(new LayerImage(dst_sprite)); for (int frame=frmin; frame<=frmax; frame++) { // Does this frame have cels to render? if (has_cels(src_layer, frame)) { // Create a new image Image* image = image_new(flatLayer->getSprite()->getImgType(), w, h); try { // Create the new cel for the output layer (add the image to stock too). Cel* cel = new Cel(frame, flatLayer->getSprite()->getStock()->addImage(image)); cel->setPosition(x, y); // Clear the image and render this frame. image_clear(image, 0); layer_render(src_layer, image, -x, -y, frame); flatLayer->addCel(cel); } catch (...) { delete image; throw; } } } return flatLayer.release(); }
// static Cel* Cel::createCopy(const Cel* other) { Cel* cel = new Cel(other->frame(), ImageRef(Image::createCopy(other->image()))); cel->setPosition(other->position()); cel->setOpacity(other->opacity()); return cel; }
bool MovingCelState::onMouseUp(Editor* editor, MouseMessage* msg) { Document* document = editor->document(); // Here we put back the cel into its original coordinate (so we can // add an undoer before). if (m_celOffset != gfx::Point(0, 0)) { // Put the cels in the original position. for (size_t i=0; i<m_celList.size(); ++i) { Cel* cel = m_celList[i]; const gfx::Point& celStart = m_celStarts[i]; cel->setPosition(celStart); } // If the user didn't cancel the operation... if (!m_canceled) { ContextWriter writer(UIContext::instance(), 500); Transaction transaction(writer.context(), "Cel Movement", ModifyDocument); DocumentApi api = document->getApi(transaction); // And now we move the cel (or all selected range) to the new position. for (Cel* cel : m_celList) { api.setCelPosition(writer.sprite(), cel, cel->x() + m_celOffset.x, cel->y() + m_celOffset.y); } // Move selection if it was visible if (m_maskVisible) api.setMaskPosition(document->mask()->bounds().x + m_celOffset.x, document->mask()->bounds().y + m_celOffset.y); transaction.commit(); } // Redraw all editors. We've to notify all views about this // general update because MovingCelState::onMouseMove() redraws // only the cels in the current editor. And at this point we'd // like to update all the editors. document->notifyGeneralUpdate(); } // Restore the mask visibility. if (m_maskVisible) { document->setMaskVisible(m_maskVisible); document->generateMaskBoundaries(); } editor->backToPreviousState(); editor->releaseMouse(); return true; }
// 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; }
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; }