mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-30 06:32:42 +00:00
Merge branch 'master' into beta
This commit is contained in:
commit
a9f3702ba4
@ -6,8 +6,8 @@
|
||||
|
||||
## Introduction
|
||||
|
||||
**Aseprite** is an open source program to create animated sprites.
|
||||
Its main features are:
|
||||
**Aseprite** is a program to create animated sprites. Its main
|
||||
features are:
|
||||
|
||||
* Sprites are composed by [**layers** & **frames**](http://www.aseprite.org/docs/timeline/) (as separated concepts).
|
||||
* Supported [color modes](http://www.aseprite.org/docs/color/): **RGBA**, **Indexed** (palettes up to 256
|
||||
|
@ -17,10 +17,9 @@ ASE files use Intel (little-endian) byte order.
|
||||
|
||||
BYTE An 8-bit unsigned integer value
|
||||
WORD A 16-bit unsigned integer value
|
||||
SIGNED WORD A 16-bit signed integer value
|
||||
DWORD A 32-bit unsigned integer value
|
||||
LONG A 32-bit signed integer value
|
||||
BYTE[n] "n" bytes.
|
||||
RECT Four LONGs (in the order: x-pos, y-pos, width, heigth)
|
||||
STRING length=WORD (how many characters to read next)
|
||||
string=BYTE[length]
|
||||
The \0 character isn't included.
|
||||
@ -191,8 +190,8 @@ Cel Chunk (0x2005)
|
||||
layer/frame.
|
||||
|
||||
WORD Layer index (see NOTE.2)
|
||||
WORD X position
|
||||
WORD Y position
|
||||
SIGNED WORD X position
|
||||
SIGNED WORD Y position
|
||||
BYTE Opacity level
|
||||
WORD Cel type
|
||||
BYTE[7] For future (set to zero)
|
||||
@ -220,8 +219,8 @@ Cel Chunk (0x2005)
|
||||
Mask Chunk (0x2016) DEPRECATED
|
||||
----------------------------------------
|
||||
|
||||
WORD X position
|
||||
WORD Y position
|
||||
SIGNED WORD X position
|
||||
SIGNED WORD Y position
|
||||
WORD Width
|
||||
WORD Height
|
||||
BYTE[8] For future (set to zero)
|
||||
|
@ -170,6 +170,7 @@ public:
|
||||
void setInTextureBounds(const gfx::Rect& bounds) { m_bounds->setInTextureBounds(bounds); }
|
||||
|
||||
bool isDuplicated() const { return m_isDuplicated; }
|
||||
bool isEmpty() const { return m_bounds->trimmedBounds().isEmpty(); }
|
||||
SampleBoundsPtr sharedBounds() const { return m_bounds; }
|
||||
|
||||
void setSharedBounds(const SampleBoundsPtr& bounds) {
|
||||
@ -235,6 +236,11 @@ public:
|
||||
if (sample.isDuplicated())
|
||||
continue;
|
||||
|
||||
if (sample.isEmpty()) {
|
||||
sample.setInTextureBounds(gfx::Rect(0, 0, 0, 0));
|
||||
continue;
|
||||
}
|
||||
|
||||
const Sprite* sprite = sample.sprite();
|
||||
const Layer* layer = sample.layer();
|
||||
gfx::Size size = sample.requiredSize();
|
||||
@ -312,7 +318,8 @@ public:
|
||||
// TODO Add support for shape paddings
|
||||
|
||||
for (auto& sample : samples) {
|
||||
if (sample.isDuplicated())
|
||||
if (sample.isDuplicated() ||
|
||||
sample.isEmpty())
|
||||
continue;
|
||||
|
||||
pr.add(sample.requiredSize());
|
||||
@ -423,7 +430,7 @@ gfx::Size DocumentExporter::calculateSheetSize()
|
||||
return calculateSheetSize(samples);
|
||||
}
|
||||
|
||||
void DocumentExporter::captureSamples(Samples& samples) const
|
||||
void DocumentExporter::captureSamples(Samples& samples)
|
||||
{
|
||||
for (auto& item : m_documents) {
|
||||
Document* doc = item.doc;
|
||||
@ -521,7 +528,22 @@ void DocumentExporter::captureSamples(Samples& samples) const
|
||||
if (!algorithm::shrink_bounds(sampleRender, frameBounds, refColor)) {
|
||||
// If shrink_bounds() returns false, it's because the whole
|
||||
// image is transparent (equal to the mask color).
|
||||
continue;
|
||||
|
||||
// Should we ignore this empty frame? (i.e. don't include
|
||||
// the frame in the sprite sheet)
|
||||
if (m_ignoreEmptyCels) {
|
||||
for (FrameTag* tag : sprite->frameTags()) {
|
||||
auto& delta = m_tagDelta[tag->id()];
|
||||
|
||||
if (frame < tag->fromFrame()) --delta.first;
|
||||
if (frame <= tag->toFrame()) --delta.second;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create an empty entry for this completely trimmed frame
|
||||
// anyway to get its duration in the list of frames.
|
||||
sample.setTrimmedBounds(frameBounds = gfx::Rect(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
if (m_trimCels)
|
||||
@ -558,6 +580,10 @@ gfx::Size DocumentExporter::calculateSheetSize(const Samples& samples) const
|
||||
gfx::Rect fullTextureBounds(0, 0, m_textureWidth, m_textureHeight);
|
||||
|
||||
for (const auto& sample : samples) {
|
||||
if (sample.isDuplicated() ||
|
||||
sample.isEmpty())
|
||||
continue;
|
||||
|
||||
gfx::Rect sampleBounds = sample.inTextureBounds();
|
||||
|
||||
// If the user specified a fixed sprite sheet size, we add the
|
||||
@ -587,6 +613,10 @@ Document* DocumentExporter::createEmptyTexture(const Samples& samples) const
|
||||
int maxColors = 256;
|
||||
|
||||
for (const auto& sample : samples) {
|
||||
if (sample.isDuplicated() ||
|
||||
sample.isEmpty())
|
||||
continue;
|
||||
|
||||
// We try to render an indexed image. But if we find a sprite with
|
||||
// two or more palettes, or two of the sprites have different
|
||||
// palettes, we've to use RGB format.
|
||||
@ -626,7 +656,8 @@ void DocumentExporter::renderTexture(const Samples& samples, Image* textureImage
|
||||
textureImage->clear(0);
|
||||
|
||||
for (const auto& sample : samples) {
|
||||
if (sample.isDuplicated())
|
||||
if (sample.isDuplicated() ||
|
||||
sample.isEmpty())
|
||||
continue;
|
||||
|
||||
// Make the sprite compatible with the texture so the render()
|
||||
@ -644,7 +675,7 @@ void DocumentExporter::renderTexture(const Samples& samples, Image* textureImage
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentExporter::createDataFile(const Samples& samples, std::ostream& os, Image* textureImage) const
|
||||
void DocumentExporter::createDataFile(const Samples& samples, std::ostream& os, Image* textureImage)
|
||||
{
|
||||
std::string frames_begin;
|
||||
std::string frames_end;
|
||||
@ -738,9 +769,13 @@ void DocumentExporter::createDataFile(const Samples& samples, std::ostream& os,
|
||||
else
|
||||
os << ",";
|
||||
|
||||
std::pair<int, int> delta(0, 0);
|
||||
if (!m_tagDelta.empty())
|
||||
delta = m_tagDelta[tag->id()];
|
||||
|
||||
os << "\n { \"name\": \"" << escape_for_json(tag->name()) << "\","
|
||||
<< " \"from\": " << tag->fromFrame() << ","
|
||||
<< " \"to\": " << tag->toFrame() << ","
|
||||
<< " \"from\": " << (tag->fromFrame()+delta.first) << ","
|
||||
<< " \"to\": " << (tag->toFrame()+delta.second) << ","
|
||||
<< " \"direction\": \"" << escape_for_json(convert_to_string(tag->aniDir())) << "\" }";
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,13 @@
|
||||
#include "app/sprite_sheet_type.h"
|
||||
#include "base/disable_copying.h"
|
||||
#include "doc/image_buffer.h"
|
||||
#include "doc/object_id.h"
|
||||
#include "gfx/fwd.h"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace doc {
|
||||
@ -84,12 +87,12 @@ namespace app {
|
||||
class SimpleLayoutSamples;
|
||||
class BestFitLayoutSamples;
|
||||
|
||||
void captureSamples(Samples& samples) const;
|
||||
void captureSamples(Samples& samples);
|
||||
void layoutSamples(Samples& samples);
|
||||
gfx::Size calculateSheetSize(const Samples& samples) const;
|
||||
Document* createEmptyTexture(const Samples& samples) const;
|
||||
void renderTexture(const Samples& samples, doc::Image* textureImage) const;
|
||||
void createDataFile(const Samples& samples, std::ostream& os, doc::Image* textureImage) const;
|
||||
void createDataFile(const Samples& samples, std::ostream& os, doc::Image* textureImage);
|
||||
void renderSample(const Sample& sample, doc::Image* dst, int x, int y) const;
|
||||
|
||||
class Item {
|
||||
@ -130,6 +133,11 @@ namespace app {
|
||||
bool m_listFrameTags;
|
||||
bool m_listLayers;
|
||||
|
||||
// Displacement for each tag from/to frames in case we export
|
||||
// them. It's used in case we trim frames outside tags and they
|
||||
// will not be exported at all in the final result.
|
||||
std::map<doc::ObjectId, std::pair<int, int> > m_tagDelta;
|
||||
|
||||
DISABLE_COPYING(DocumentExporter);
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -205,8 +205,7 @@ void ResourcesListBox::onTick()
|
||||
insertChild(getItemsCount()-1, listItem);
|
||||
layout();
|
||||
|
||||
View* view = View::getView(this);
|
||||
if (view)
|
||||
if (View* view = View::getView(this))
|
||||
view->updateView();
|
||||
|
||||
resource.release();
|
||||
@ -215,15 +214,18 @@ void ResourcesListBox::onTick()
|
||||
|
||||
void ResourcesListBox::stop()
|
||||
{
|
||||
m_resourcesTimer.stop();
|
||||
|
||||
if (m_loadingItem) {
|
||||
removeChild(m_loadingItem);
|
||||
layout();
|
||||
|
||||
delete m_loadingItem;
|
||||
m_loadingItem = NULL;
|
||||
m_loadingItem = nullptr;
|
||||
|
||||
invalidate();
|
||||
if (View* view = View::getView(this))
|
||||
view->updateView();
|
||||
}
|
||||
|
||||
m_resourcesTimer.stop();
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
Loading…
x
Reference in New Issue
Block a user