Ejemplo n.º 1
0
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);
}
Ejemplo n.º 2
0
/**
 * 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();
}
Ejemplo n.º 3
0
// 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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
// 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;
}
Ejemplo n.º 6
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;
}