void UndoTransaction::pasteImage(const Image* src_image, int x, int y, int opacity) { const Layer* layer = m_sprite->getCurrentLayer(); ASSERT(layer); ASSERT(layer->is_image()); ASSERT(layer->is_readable()); ASSERT(layer->is_writable()); Cel* cel = ((LayerImage*)layer)->getCel(m_sprite->getCurrentFrame()); ASSERT(cel); Image* cel_image = m_sprite->getStock()->getImage(cel->getImage()); Image* cel_image2 = Image::createCopy(cel_image); image_merge(cel_image2, src_image, x-cel->getX(), y-cel->getY(), opacity, BLEND_MODE_NORMAL); replaceStockImage(cel->getImage(), cel_image2); // TODO fix this, improve, avoid replacing the whole image }
/** * Moves every frame in @a layer with the offset (@a dx, @a dy). */ void UndoTransaction::displaceLayers(Layer* layer, int dx, int dy) { switch (layer->getType()) { case GFXOBJ_LAYER_IMAGE: { CelIterator it = ((LayerImage*)layer)->getCelBegin(); CelIterator end = ((LayerImage*)layer)->getCelEnd(); for (; it != end; ++it) { Cel* cel = *it; setCelPosition(cel, cel->getX()+dx, cel->getY()+dy); } break; } case GFXOBJ_LAYER_FOLDER: { LayerIterator it = ((LayerFolder*)layer)->get_layer_begin(); LayerIterator end = ((LayerFolder*)layer)->get_layer_end(); for (; it != end; ++it) displaceLayers(*it, dx, dy); break; } } }
/** * [working thread] */ virtual void onJob() { UndoTransaction undoTransaction(m_writer.context(), "Rotate Canvas"); DocumentApi api = m_document->getApi(); // get all sprite cels CelList cels; m_sprite->getCels(cels); // for each cel... for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; Image* image = m_sprite->getStock()->getImage(cel->getImage()); // change it location switch (m_angle) { case 180: api.setCelPosition(m_sprite, cel, m_sprite->getWidth() - cel->getX() - image->getWidth(), m_sprite->getHeight() - cel->getY() - image->getHeight()); break; case 90: api.setCelPosition(m_sprite, cel, m_sprite->getHeight() - cel->getY() - image->getHeight(), cel->getX()); break; case -90: api.setCelPosition(m_sprite, cel, cel->getY(), m_sprite->getWidth() - cel->getX() - image->getWidth()); break; } } // for each stock's image for (int i=0; i<m_sprite->getStock()->size(); ++i) { Image* image = m_sprite->getStock()->getImage(i); if (!image) continue; // rotate the image Image* new_image = Image::create(image->getPixelFormat(), m_angle == 180 ? image->getWidth(): image->getHeight(), m_angle == 180 ? image->getHeight(): image->getWidth()); raster::rotate_image(image, new_image, m_angle); api.replaceStockImage(m_sprite, i, new_image); jobProgress((float)i / m_sprite->getStock()->size()); // cancel all the operation? if (isCanceled()) return; // UndoTransaction destructor will undo all operations } // rotate mask if (m_document->isMaskVisible()) { Mask* origMask = m_document->getMask(); base::UniquePtr<Mask> new_mask(new Mask()); const gfx::Rect& origBounds = origMask->getBounds(); int x = 0, y = 0; switch (m_angle) { case 180: x = m_sprite->getWidth() - origBounds.x - origBounds.w; y = m_sprite->getHeight() - origBounds.y - origBounds.h; break; case 90: x = m_sprite->getHeight() - origBounds.y - origBounds.h; y = origBounds.x; break; case -90: x = origBounds.y; y = m_sprite->getWidth() - origBounds.x - origBounds.w; break; } // create the new rotated mask new_mask->replace(x, y, m_angle == 180 ? origBounds.w: origBounds.h, m_angle == 180 ? origBounds.h: origBounds.w); raster::rotate_image(origMask->getBitmap(), new_mask->getBitmap(), m_angle); // Copy new mask api.copyToCurrentMask(new_mask); // Regenerate mask m_document->resetTransformation(); m_document->generateMaskBoundaries(); } // change the sprite's size if (m_angle != 180) api.setSpriteSize(m_sprite, m_sprite->getHeight(), m_sprite->getWidth()); // commit changes undoTransaction.commit(); }
/** * [working thread] */ virtual void onJob() { UndoTransaction undoTransaction(m_document, "Rotate Canvas"); // get all sprite cels CelList cels; m_sprite->getCels(cels); // for each cel... for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; Image* image = m_sprite->getStock()->getImage(cel->getImage()); // change it location switch (m_angle) { case 180: undoTransaction.setCelPosition(cel, m_sprite->getWidth() - cel->getX() - image->w, m_sprite->getHeight() - cel->getY() - image->h); break; case 90: undoTransaction.setCelPosition(cel, m_sprite->getHeight() - cel->getY() - image->h, cel->getX()); break; case -90: undoTransaction.setCelPosition(cel, cel->getY(), m_sprite->getWidth() - cel->getX() - image->w); break; } } // for each stock's image for (int i=0; i<m_sprite->getStock()->size(); ++i) { Image* image = m_sprite->getStock()->getImage(i); if (!image) continue; // rotate the image Image* new_image = image_new(image->imgtype, m_angle == 180 ? image->w: image->h, m_angle == 180 ? image->h: image->w); image_rotate(image, new_image, m_angle); undoTransaction.replaceStockImage(i, new_image); jobProgress((float)i / m_sprite->getStock()->size()); // cancel all the operation? if (isCanceled()) return; // UndoTransaction destructor will undo all operations } // rotate mask if (m_document->isMaskVisible()) { Mask* origMask = m_document->getMask(); Mask* new_mask = mask_new(); int x = 0, y = 0; switch (m_angle) { case 180: x = m_sprite->getWidth() - origMask->x - origMask->w; y = m_sprite->getHeight() - origMask->y - origMask->h; break; case 90: x = m_sprite->getHeight() - origMask->y - origMask->h; y = origMask->x; break; case -90: x = origMask->y; y = m_sprite->getWidth() - origMask->x - origMask->w; break; } // create the new rotated mask mask_replace(new_mask, x, y, m_angle == 180 ? origMask->w: origMask->h, m_angle == 180 ? origMask->h: origMask->w); image_rotate(origMask->bitmap, new_mask->bitmap, m_angle); // copy new mask undoTransaction.copyToCurrentMask(new_mask); mask_free(new_mask); // regenerate mask m_document->generateMaskBoundaries(); } // change the sprite's size if (m_angle != 180) undoTransaction.setSpriteSize(m_sprite->getHeight(), m_sprite->getWidth()); // commit changes undoTransaction.commit(); }
void FlipCommand::onExecute(Context* context) { ContextWriter writer(context); Document* document = writer.document(); Sprite* sprite = writer.sprite(); DocumentApi api = document->getApi(); { UndoTransaction undoTransaction(writer.context(), m_flipMask ? (m_flipType == raster::algorithm::FlipHorizontal ? "Flip Horizontal": "Flip Vertical"): (m_flipType == raster::algorithm::FlipHorizontal ? "Flip Canvas Horizontal": "Flip Canvas Vertical")); if (m_flipMask) { int x, y; Image* image = writer.image(&x, &y); if (!image) return; Mask* mask = NULL; bool alreadyFlipped = false; // This variable will be the area to be flipped inside the image. gfx::Rect bounds(image->getBounds()); // If there is some portion of sprite selected, we flip the // selected region only. If the mask isn't visible, we flip the // whole image. if (document->isMaskVisible()) { mask = document->getMask(); // Intersect the full area of the image with the mask's // bounds, so we don't request to flip an area outside the // image's bounds. bounds = bounds.createIntersect(gfx::Rect(mask->getBounds()).offset(-x, -y)); // If the mask isn't a rectangular area, we've to flip the mask too. if (mask->getBitmap() != NULL && !mask->isRectangular()) { int bgcolor = app_get_color_to_clear_layer(writer.layer()); // Flip the portion of image specified by the mask. mask->offsetOrigin(-x, -y); api.flipImageWithMask(image, mask, m_flipType, bgcolor); mask->offsetOrigin(x, y); alreadyFlipped = true; // Flip the mask. Image* maskBitmap = mask->getBitmap(); if (maskBitmap != NULL) { // Create a flipped copy of the current mask. base::UniquePtr<Mask> newMask(new Mask(*mask)); newMask->freeze(); raster::algorithm::flip_image(newMask->getBitmap(), maskBitmap->getBounds(), m_flipType); newMask->unfreeze(); // Change the current mask and generate the new boundaries. api.copyToCurrentMask(newMask); document->generateMaskBoundaries(); } } } // Flip the portion of image specified by "bounds" variable. if (!alreadyFlipped) { api.flipImage(image, bounds, m_flipType); } } else { // get all sprite cels CelList cels; sprite->getCels(cels); // for each cel... for (CelIterator it = cels.begin(); it != cels.end(); ++it) { Cel* cel = *it; Image* image = sprite->getStock()->getImage(cel->getImage()); api.setCelPosition (sprite, cel, (m_flipType == raster::algorithm::FlipHorizontal ? sprite->getWidth() - image->getWidth() - cel->getX(): cel->getX()), (m_flipType == raster::algorithm::FlipVertical ? sprite->getHeight() - image->getHeight() - cel->getY(): cel->getY())); api.flipImage(image, image->getBounds(), m_flipType); } } undoTransaction.commit(); } update_screen_for_document(document); }
// 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; }
// clears the mask region in the current sprite with the specified background color void UndoTransaction::clearMask(int bgcolor) { Cel* cel = getCurrentCel(); if (!cel) return; Image* image = getCelImage(cel); if (!image) return; Mask* mask = m_document->getMask(); // If the mask is empty or is not visible then we have to clear the // entire image in the cel. if (!m_document->isMaskVisible()) { // If the layer is the background then we clear the image. if (m_sprite->getCurrentLayer()->is_background()) { if (isEnabled()) m_undoHistory->pushUndoer(new undoers::ImageArea(m_undoHistory->getObjects(), image, 0, 0, image->w, image->h)); // clear all image_clear(image, bgcolor); } // If the layer is transparent we can remove the cel (and its // associated image). else { removeCel(static_cast<LayerImage*>(m_sprite->getCurrentLayer()), cel); } } else { int offset_x = mask->getBounds().x-cel->getX(); int offset_y = mask->getBounds().y-cel->getY(); int u, v, putx, puty; int x1 = MAX(0, offset_x); int y1 = MAX(0, offset_y); int x2 = MIN(image->w-1, offset_x+mask->getBounds().w-1); int y2 = MIN(image->h-1, offset_y+mask->getBounds().h-1); // do nothing if (x1 > x2 || y1 > y2) return; if (isEnabled()) m_undoHistory->pushUndoer(new undoers::ImageArea(m_undoHistory->getObjects(), image, x1, y1, x2-x1+1, y2-y1+1)); // clear the masked zones for (v=0; v<mask->getBounds().h; v++) { div_t d = div(0, 8); uint8_t* address = ((uint8_t**)mask->getBitmap()->line)[v]+d.quot; for (u=0; u<mask->getBounds().w; u++) { if ((*address & (1<<d.rem))) { putx = u + offset_x; puty = v + offset_y; image_putpixel(image, putx, puty, bgcolor); } _image_bitmap_next_bit(d, address); } } } }
void UndoTransaction::backgroundFromLayer(LayerImage* layer, int bgcolor) { ASSERT(layer); ASSERT(layer->is_image()); ASSERT(layer->is_readable()); ASSERT(layer->is_writable()); ASSERT(layer->getSprite() == m_sprite); ASSERT(m_sprite->getBackgroundLayer() == NULL); // create a temporary image to draw each frame of the new // `Background' layer UniquePtr<Image> bg_image_wrap(Image::create(m_sprite->getPixelFormat(), m_sprite->getWidth(), m_sprite->getHeight())); Image* bg_image = bg_image_wrap.get(); CelIterator it = layer->getCelBegin(); CelIterator end = layer->getCelEnd(); for (; it != end; ++it) { Cel* cel = *it; ASSERT((cel->getImage() > 0) && (cel->getImage() < m_sprite->getStock()->size())); // get the image from the sprite's stock of images Image* cel_image = m_sprite->getStock()->getImage(cel->getImage()); ASSERT(cel_image); image_clear(bg_image, bgcolor); image_merge(bg_image, cel_image, cel->getX(), cel->getY(), MID(0, cel->getOpacity(), 255), layer->getBlendMode()); // now we have to copy the new image (bg_image) to the cel... setCelPosition(cel, 0, 0); // same size of cel-image and bg-image if (bg_image->w == cel_image->w && bg_image->h == cel_image->h) { if (isEnabled()) m_undoHistory->pushUndoer(new undoers::ImageArea(m_undoHistory->getObjects(), cel_image, 0, 0, cel_image->w, cel_image->h)); image_copy(cel_image, bg_image, 0, 0); } else { replaceStockImage(cel->getImage(), Image::createCopy(bg_image)); } } // Fill all empty cels with a flat-image filled with bgcolor for (int frame=0; frame<m_sprite->getTotalFrames(); frame++) { Cel* cel = layer->getCel(frame); if (!cel) { Image* cel_image = Image::create(m_sprite->getPixelFormat(), m_sprite->getWidth(), m_sprite->getHeight()); image_clear(cel_image, bgcolor); // Add the new image in the stock int image_index = addImageInStock(cel_image); // Create the new cel and add it to the new background layer cel = new Cel(frame, image_index); addCel(layer, cel); } } configureLayerAsBackground(layer); }