C
Qt Quick Ultralite sprite_animations Example
Demonstrates how to create a sprite animation.
Overview
The sprite_animations
example shows how to create a sprite animation from frame sequences in an image file.
The image source for this example consist of 16 frames, where each frame size is 180x160.
Target platforms
- EK-RA6M3G
- MCIMX93-EVK
- MIMXRT1050
- MIMXRT1060
- MIMXRT1064
- MIMXRT1170
- STM32F769i
- STM32H750b
- STM32F469I-DISCOVERY
- RH850 D1M1A
- Infineon TRAVEO™ T2G
Image formats
Qt Quick Ultralite lets you use a hardware image decoder instead of the default. Both the AnimatedSprite and AnimatedSpriteDirectory QML types support the registered image format for the sprite animation.
The example shows the use case of the image decoder on the STM32F769i, STM32H750b, RH850/D1M1A Evaluation Board and Infineon TRAVEO™ T2G CYT4DN boards. For these boards, the project configures the JPEG decoder and uses the raw image data of JPEG files in the ImageFiles node. The image decoder enables to decode and render the image data at runtime. See Qt Quick Ultralite imagedecoder Example and Using JPEG decoder for more details.
Note: Due to a limitation of the Graphics Driver, currently the only supported subsampling mode for source JPEG images is YUV420. See Sample application user guide for JPEG decode driver TRAVEO™ T2G cluster series User Manual for more information. To convert source images to the YUV420 subsampling format, you can use ImageMagick Convert tool: convert input.jpg -sampling-factor 4:2:0 output.jpg
.
Note: For Infineon TRAVEO™ T2G CYT4DN, set the mandatory CMake variable TVII_JPEG_DRIVER_DIR
. It should point to the root folder of the JPEG decode driver SDK.
On the RH850 platform, add the following compile definitions to configure the JPEG driver:
USE_OUTPUT_SPLIT_MODE
Configures the Renesas JCUA hardware in division mode where the decoding is performed in chunks. This definition can be skipped if normal mode is to be used where complete image is decoded at once.
DECODE_BUFFER_PIXEL_LINES
If
USE_OUTPUT_SPLIT_MODE
is enabled,DECODE_BUFFER_PIXEL_LINES
sets the number of output buffer pixel lines which will be processed in one iteration. This value must be multiple of 16.The default value of
DECODE_BUFFER_PIXEL_LINES
is 16.CHROMA_SUBSAMPLING
Sets the chroma-subsampling format of the images in use. The possible values are as follows:
R_JCUA_JPEG_FORMAT_YCBCR420
R_JCUA_JPEG_FORMAT_YCBCR411
R_JCUA_JPEG_FORMAT_YCBCR422
R_JCUA_JPEG_FORMAT_YCBCR444
The default value of
CHROMA_SUBSAMPLING
is R_JCUA_JPEG_FORMAT_YCBCR420.Note: Currently, the chroma-subsampling cannot be determined at runtime and has to be specified at compile time. All jpeg images used in the application must be saved with same chroma-subsampling.
For the other boards and platforms, the project uses PNG image file and the resource compiler to decode the image at build time.
Project structure
CMake project file
The following CMake example shows how to decode images on platforms that does not use the JPEG decoder:
qul_add_target(sprite_animations QML_PROJECT mcu_sprite_animations.qmlproject GENERATE_ENTRYPOINT )
The following QmlProject example show how you can configure a JPEG decoder with the necessary image resource properties and platform configuration:
qul_add_target(sprite_animations QML_PROJECT mcu_sprite_animations_jpeg.qmlproject os/${QUL_OS_LOWERCASE}/main.cpp )
QmlProject file
The Qmlproject file includes the required Qml and Image files.
import QmlProject 1.3 Project { mainFile: "sprite_animations.qml" QmlFiles { files: [ "ToggleButton.qml" ] } ImageFiles { files: [ "qt-image-sequence.png" ] MCU.resourceAnimatedSpriteFrameWidth: 180 MCU.resourceAnimatedSpriteFrameHeight: 160 } }
QmlProject offers ImageFiles.MCU.resourceAnimatedSpriteFrameWidth, ImageFiles.MCU.resourceAnimatedSpriteFrameHeight, and ImageFiles.MCU.resourceAnimatedSpriteOptimizations to let you optimize the image sources.
The resource compiler splits the image source into 16 frames internally, and applies the cropping technique to optimize them for better performance and lower memory footprint. This enables rendering only the changed parts between a series of the frames.
Application UI
The sprite_animations.qml
file defines AnimatedSprite type. It defines the size of a single frame, number of frames in an image, and source of the image. The animation starts by default. When a user clicks the image, it runs or stops the animations based on the current running
value.
AnimatedSprite { id: sprite anchors.centerIn: parent source: "qt-image-sequence.png" frameDuration: 80 frameCount: 16 frameWidth: 180 frameHeight: 160 loops: AnimatedSprite.Infinite onFinished: { txtMsg.text = "Finished" } onRunningChanged: { if (sprite.running) { txtMsg.text = "" } } MouseArea { anchors.fill: parent onClicked: { if (sprite.running) { sprite.stop() } else { sprite.start() } } } }
On the top-left corner of the UI, the number and the duration of the current frame (in milliseconds) of each frame of the animation.
Column { id: spriteInfo anchors.top: parent.top anchors.left: parent.left anchors.margins: 16 spacing: 4 Text { id: txtFrameNo text: "frame: " + (sprite.currentFrame + 1) + " / " + sprite.frameCount font.pixelSize: 14 color: "white" } Text { id: txtDuration text: "duration: " + sprite.frameDuration font.pixelSize: 14 color: "white" } Text { id: txtMsg font.pixelSize: 14 text: "" color: "white" } }
The application has a button on the top-right corner to toggle the loops
property value between AnimatedSprite.Infinite and 1.
ToggleButton { id: toggleLoops width: parent.width / 4 height: parent.height / 9 anchors.right: parent.right anchors.top: parent.top anchors.margins: 8 checkedText: "Infinite" uncheckedText: "Once" onCheckedChanged: { if (toggleLoops.checked) { sprite.loops = AnimatedSprite.Infinite } else { sprite.loops = 1 } } }
The ToggleButton is a custom component using the simple visual QML types such as Rectangle, MouseArea, Text, and Row.
import QtQuick 2.15 Rectangle { id: control color: "white" property bool checked: true readonly property color foregroundColor: "black" readonly property int borderWidth: 1 readonly property alias checkedText: txtChecked.text readonly property alias uncheckedText: txtUnchecked.text Row { x: control.borderWidth y: control.borderWidth spacing: control.borderWidth Rectangle { id: leftPart width: (control.width - control.borderWidth * 3) / 2 height: (control.height - control.borderWidth * 2) color: control.checked? control.color : control.foregroundColor Text { id: txtChecked anchors.centerIn: parent color: control.checked? control.foregroundColor : control.color font.pixelSize: 14 } } Rectangle { id: rightPart width: leftPart.width height: leftPart.height color: control.checked? control.foregroundColor : control.color Text { id: txtUnchecked anchors.centerIn: parent color: control.checked? control.color : control.foregroundColor font.pixelSize: 14 } } } MouseArea { anchors.fill: parent onClicked: control.checked = !control.checked } }
Using JPEG decoder
On platforms that use a JPEG decoder, you can use the MCU.resourceKeepRawData QmlProject property to bundle the JPEG files as the raw image data. You can also define MCU.Config.maxResourceCacheSize to make sure there is enough space to store the decoded image data at runtime.
import QmlProject 1.3 Project { MCU.Config { // enough size to contain one decoded image maxResourceCacheSize: 153600 } QmlFiles { files: [ "ToggleButton.qml", "sprite_animations_jpeg.qml" ] } ImageFiles { files: [ "qt-image-sequence/00.jpg", "qt-image-sequence/01.jpg", "qt-image-sequence/02.jpg", "qt-image-sequence/03.jpg", "qt-image-sequence/04.jpg", "qt-image-sequence/05.jpg", "qt-image-sequence/06.jpg", "qt-image-sequence/07.jpg", "qt-image-sequence/08.jpg", "qt-image-sequence/09.jpg", "qt-image-sequence/10.jpg", "qt-image-sequence/11.jpg", "qt-image-sequence/12.jpg", "qt-image-sequence/13.jpg", "qt-image-sequence/14.jpg", "qt-image-sequence/15.jpg" ] MCU.resourceAnimatedSprite: true MCU.resourceKeepRawData: true } }
The example uses a series of frame images with AnimatedSpriteDirectory to emphasize the benefit of the hardware decoding. This reduces memory usage and CPU load for the sprite animation.
AnimatedSpriteDirectory { id: sprite anchors.centerIn: parent sourcePath: "qt-image-sequence" frameDuration: 80 loops: AnimatedSprite.Infinite readonly property int frameCount: 16 ...
Files:
- sprite_animations/CMakeLists.txt
- sprite_animations/ToggleButton.qml
- sprite_animations/mcu_sprite_animations.qmlproject
- sprite_animations/mcu_sprite_animations_jpeg.qmlproject
- sprite_animations/os/baremetal/main.cpp
- sprite_animations/sprite_animations.qml
- sprite_animations/sprite_animations_jpeg.qml
Images:
- sprite_animations/qt-image-sequence.png
- sprite_animations/qt-image-sequence/00.jpg
- sprite_animations/qt-image-sequence/01.jpg
- sprite_animations/qt-image-sequence/02.jpg
- sprite_animations/qt-image-sequence/03.jpg
- sprite_animations/qt-image-sequence/04.jpg
- sprite_animations/qt-image-sequence/05.jpg
- sprite_animations/qt-image-sequence/06.jpg
- sprite_animations/qt-image-sequence/07.jpg
- sprite_animations/qt-image-sequence/08.jpg
- sprite_animations/qt-image-sequence/09.jpg
- sprite_animations/qt-image-sequence/10.jpg
- sprite_animations/qt-image-sequence/11.jpg
- sprite_animations/qt-image-sequence/12.jpg
- sprite_animations/qt-image-sequence/13.jpg
- sprite_animations/qt-image-sequence/14.jpg
- sprite_animations/qt-image-sequence/15.jpg
See also Managing Resources.
Available under certain Qt licenses.
Find out more.