diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index c0b0e8e73923dc782a161aeda950d228014cb242..80420ee4c292a32ea02d20056ebc2cff37016cd9 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -625,6 +625,8 @@ void fillUniformArrayFromImage(float* array, const QImage& img, int size) Note that the sprite image will be scaled to a square based on the size of the particle being rendered. + + For full details, see the \l{Sprite Animation} overview. */ /*! \qmlproperty url QtQuick.Particles2::ImageParticle::colorTable diff --git a/src/quick/doc/images/spritecutting.png b/src/quick/doc/images/spritecutting.png new file mode 100644 index 0000000000000000000000000000000000000000..1958ee222d1ff2939313bdfedfd708183f307e2d Binary files /dev/null and b/src/quick/doc/images/spritecutting.png differ diff --git a/src/quick/doc/images/spriteenginegraph.png b/src/quick/doc/images/spriteenginegraph.png new file mode 100644 index 0000000000000000000000000000000000000000..ef09df43ef1b70b1ac0922f5b7b81e998f42109b Binary files /dev/null and b/src/quick/doc/images/spriteenginegraph.png differ diff --git a/src/quick/doc/src/elements.qdoc b/src/quick/doc/src/elements.qdoc index 63fcd1aa2987c71134fe399b0a60ec2c44af6155..40533867df4854196e7ff53629b17b42e3b9366d 100644 --- a/src/quick/doc/src/elements.qdoc +++ b/src/quick/doc/src/elements.qdoc @@ -50,11 +50,13 @@ two elements. \li \l {Rectangle} - A rectangle element \li \l {Image} - For incorporating bitmaps into a scene \li \l {BorderImage} - Allows the use of images as borders -\li \l {AnimatedImage} - For playing animations stored in a series of frames +\li \l {AnimatedSprite} - For playing animations stored as a series of frames +\li \l {AnimatedImage} - For playing animations stored as an animated GIF \li \l {Gradient} - For defining a color gradient \li \l {GradientStop} - Used to define a color within a \l {Gradient} \li \l {SystemPalette} - Provides access to the Qt palettes \li \l {Canvas} - Provides a 2D canvas element +\li \l {SpriteSequence} - For playing and transitioning between multiple animations stored as a series of frames \endlist \section1 Text Handling diff --git a/src/quick/doc/src/sprites.qdoc b/src/quick/doc/src/sprites.qdoc new file mode 100644 index 0000000000000000000000000000000000000000..e59b30855e9c5aeefc09085a0173c1f2ad3e6435 --- /dev/null +++ b/src/quick/doc/src/sprites.qdoc @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms +** and conditions contained in a signed written agreement between you +** and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page qtquick-spriteengine.html +\ingroup qml-features +\title Sprite Animations +\brief Sprite-based animations with flexible transitioning + +\section1 Sprite Engine + +The QtQuick sprite engine is a stochastic state machine combined with the ability +to chop up images containing multiple frames of an animation. + +\section2 State Machine + +A primary function of the sprite engine is its internal state machine. This is not the same as +the states and transitions in Qt Quick, and is more like a conventional state machine. Sprites +can have weighted transitions to other sprites, or back to themselves. When a sprite animation +finishes, the sprite engine will choose the next sprite randomly, based on the weighted transitions +available for the sprite that just finished. + +You can affect the currently playing sprite in two ways. You can arbitrarily force it to immediately +start playing any sprite, or you can tell it to gradually transition to a given sprite. If you +instruct it to gradually transition, then it will reach the target sprite by going through valid +state transitions using the fewest number of intervening sprites (but ignoring relative weightings). +This allows you to easily insert a transitional animation between two different sprites. + +\image spriteenginegraph.png + +As an example, consider the above diagram which illustrates the sprites for a hypothetical 2D +platform game character. The character starts by displaying the standing state. From this state, +barring external input, he will transition to either the waiting animation, the walking animation, +or play the standing animation again. Because the weights for those transitions are one, zero and three +respectively, he has a one in four chance of playing the waiting animation when the standing animation +finishes, and a three in four chance of playing the standing animation again. This allows for a character +who has a slightly animated and variable behavior while waiting. + +Because there is a zero weight transition to the walking animation, the standing animation will not normally +transition there. But if you set the goal animation to be the walking animation, it would play the walking +animation when it finished the standing animation. If it was previously in the waiting animation, it would +finish playing that, then play the standing animation, then play the walking animation. It would then continue to +play the walking animation until the goal animation is unset, at which point it would switch to the standing +animation after finishing the walking animation. + +If you set the goal state then to the jumping animation, it would finish the walking animation before +playing the jumping animation. Because the jumping animation does not transition to other states, it will still +keep playing the jumping animation until the state is forced to change. In this example, you could set it back to +walking and change to goal animation to walking or to nothing (which would lead it to play the standing animation +after the walking animation). Note that by forcibly setting the animation, you can start playing the animation +immediately. + +\section2 Input Format + +The file formats accepted by the sprite engine is the same as the file formats accepted by other QML elements, +such as \l Image. In order to animate the image however, the sprite engine requires the image file to contain +all of the frames of the animation. They should be arranged in a contiguous line, which may wrap from the right +edge of the file to a lower row starting from the left edge of the file (and which is placed directly below the +previous row). + +\image spritecutting.png + +As an example, take the above image. For now just consider the black numbers, and assume the squares are 40x40 pixels. +Normally, the image is read from the top-left corner. If you specified the frame size as 40x40 pixels, and a frame count +of 8, then it would read in the frames as they are numbered. The frame in the top left would be the first frame, the frame +in the top right would be the fifth frame, and then it would wrap to the next row (at pixel location 0,40 in the file) to read +the sixth frame. It would stop reading after the frame marked 8, and if there was any image data in the square below frame four +then it would not be included in the animation. + +It is possible to load animations from an arbitrary offset, but they will still follow the same pattern. +Consider now the red numbers. If we specify that the animation begins at pixel location 120,0, with a +frame count of 5 and the same frame size as before, then it will load the frames as they are numbered in red. +The first 120x40 of the image will not be used, as it starts reading 40x40 blocks from the location of 120,0. +When it reaches the end of the file at 160,0, it then starts to read the next row from 0,40. + +The blue numbers show the frame numbers if you tried to load two frames of that size, starting from 40,40. Note +that it is possible to load multiple sprites out of the one image file. The red, blue and black numbers can all +be loaded as separate animations to the same sprite engine. The following code loads the animations as per the image. +It also specifies that animations are to played at 20 frames per second. + +\code +Sprite { + name: "black" + source: "image.png" + frameCount: 8 + frameWidth: 40 + frameHeight: 40 + frameRate: 20 +} +Sprite { + name: "red" + source: "image.png" + frameX: 120 + frameCount: 5 + frameWidth: 40 + frameHeight: 40 + frameRate: 20 +} +Sprite { + name: "blue" + source: "image.png" + frameX: 40 + frameX: 40 + frameCount: 2 + frameWidth: 40 + frameHeight: 40 + frameRate: 20 +} +\endcode + +Frames within one animation must be the same size, however multiple animations within the same file +do not. Sprites without a frameCount specified assume that they take the entire file, and you must specify +the frame size. Sprites without a frame size assume that they are square and take the entire file without wrapping, +and you must specify a frame count. + +The sprite engine internally copies and cuts up images to fit in an easier to read internal format, which leads +to some graphics memory limitations. Because it requires all the sprites for a single engine to be in the same +texture, attempting to load many different animations can run into texture memory limits on embedded devices. In +these situations, a warning will be output to the console containing the maximum texture size. + +There are several software tools to help turn images into sprite sheets, here are some examples: +Photoshop plugin: +http://www.personal.psu.edu/zez1/blogs/my_blog/2011/05/scripts-4-photoshop-file-sequence-to-layers-to-sprite-sheet.html +Gimp plugin: +http://registry.gimp.org/node/20943 +Cmd-line tool: +http://www.imagemagick.org/script/montage.php + + +\section2 Elements Using the Sprite Engine + +Sprites for the sprite engine can be defined using the \l Sprite element. This element includes the input parameters +as well as the length of the animation and weighted transitions to other animations. It is purely a data class, and +does not render anything. + +\l SpriteSequence is an element which uses a sprite engine to draw the sprites defined in it. It is a single and +self-contained sprite engine, and does not interact with other sprite engines. \l Sprite elements can be shared between +sprite engine using elements, but this is not done automatically. So if you have defined a sprite in one \l SpriteSequence +you will need to redefine it (or reference the same \l Sprite element) in the sprites property of another \l SpriteSequence +in order to transition to that animation. + +Additionally, \l ImageParticle can use \l Sprite elements to define sprites for each particle. This is again a single +sprite engine per element. This works similarly to SpriteSequence, but it also has the parametrized variability provided +by the \l ImageParticle element. + +\section1 AnimatedSprite + +For use-cases which do not need to transition between animations, consider the \l AnimatedSprite element. +This element displays sprite animations with the same input format, but only one at a time. It also provides more fine-grained +manual control, as there is no sprite engine managing the timing and transitions behind the scenes. + +*/ diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp index 204900177c0a28d5d0b3c9daae4b2cfcfca67e57..a5e5d99bcd293ba79e7d2ce4faffb4bb23a42ef9 100644 --- a/src/quick/items/qquickanimatedsprite.cpp +++ b/src/quick/items/qquickanimatedsprite.cpp @@ -215,6 +215,14 @@ struct AnimatedSpriteVertices { \inqmlmodule QtQuick 2 \inherits Item \brief The AnimatedSprite element draws a sprite animation + + AnimatedSprite provides rendering and control over animations which are provided + as multiple frames in the same image file. You can play it at a fixed speed, at the + frame rate of your display, or manually advance and control the progress. + + For details of how a sprite animation is defined see the \l{Sprite Animation} overview. + Note that the AnimatedSprite element does not use Sprite elements to define multiple animations, + but instead encapsulates a single animation itself. */ /*! diff --git a/src/quick/items/qquicksprite.cpp b/src/quick/items/qquicksprite.cpp index 724bf8fef182a75c422a487cdc5af91fc7d7115c..8b77d2327095c4c299e9c130fb24dd9dcf95b82a 100644 --- a/src/quick/items/qquicksprite.cpp +++ b/src/quick/items/qquicksprite.cpp @@ -54,16 +54,7 @@ QT_BEGIN_NAMESPACE can be in the middle of an image file, or split along multiple rows, as long as they form a contiguous line wrapping to the next row of the file from the left edge of the file. - Sprites within one animation must be the same size, however sprites within the same file - do not. Sprites without a frameCount specified assume that they take the entire file. - - There are several software tools to help turn images into sprite sheets, here are some examples: - Photoshop plugin: - http://www.personal.psu.edu/zez1/blogs/my_blog/2011/05/scripts-4-photoshop-file-sequence-to-layers-to-sprite-sheet.html - Gimp plugin: - http://registry.gimp.org/node/20943 - Cmd-line tool: - http://www.imagemagick.org/script/montage.php + For full details, see the \l{Sprite Animation} overview. */ /*! \qmlproperty int QtQuick2::Sprite::duration diff --git a/src/quick/items/qquickspritesequence.cpp b/src/quick/items/qquickspritesequence.cpp index 80dad16fe3817f9d09b0c2f1dfb11c2ff81c1db7..7f7d1ccecbe82657a53028586afd9a8ac0976f48 100644 --- a/src/quick/items/qquickspritesequence.cpp +++ b/src/quick/items/qquickspritesequence.cpp @@ -215,6 +215,10 @@ struct SpriteVertices { \inherits Item \brief The SpriteSequence element draws a sprite animation + SpriteSequence renders and controls a list of animations defined + by \l Sprite elements. + + For full details, see the \l{Sprite Animation} overview. */ /*! \qmlproperty bool QtQuick2::SpriteSequence::running