Skip to content

Frame Transition

Hapaxia edited this page Feb 20, 2025 · 4 revisions

Introduction

A class to aid with transition animation.

Frame Transition draws a couple of quads (frames) designed to be transitioned.

The easiest way to visualise the transitions is to consider transitions in video. Things like wipes and scrolls/pushes can be done with Frame Transition plus much more!

Remember always that Frame Transition always draws only 2 frames (quads) at once. These are Frame A (the source - or starting - frame) and Frame B (the destination - or finishing - frame).

There are two main types of transition in Frame Transition: TexCrop and Zoom.

Type: TexCrop

TexCrop is the default type and draws 2 frames side-by-side and squeezes them so that they fit within the overall size. The amount of squeeze applied to each frame is determined by the "ratio": a value from 0 to 1 that represents which frame should be currently visible - Frame A at 0 and Frame B at 1.

That what happens to the actual quads - they never overlap - but what about the actual textures applied to those frames?
Well, if the entire texture ("entire texture" here means 'entire texture with the texture rectangle') is drawn to the frame, the texture is squashed/squeezed.
However, the texture does not need to be squashed, it can be cropped, hence why this type is called TexCrop!

The texture can be cropped by its start or end side, neither (squash) or both.
This can be applied to each frame separately and the combination of how each frame can be cropped can form many different transition types.
For example, if Frame A crops its end and Frame B crops its start, then the transition is a wipe - the frame look static but the "lower"-looking one is revealed as the ratio is increased. However, if Frame A crops its start and Frame B crops its end, then the transition is a push - Frame A "moves" into view from the side while Frame B "moves" out of view in the opposite direction.

There are many combinations. See the example video (or run the example) for a demonstration of some of them.

There is a special type of TexCrop version called "shuffle" that crops the end (or the start for B) for the first half of the transition and the crops the start (or the end for B) for the second half. This appears as if the frame are moving apart from each other and then moved back together in the opposite order - similar to shuffling cards.

Type: Zoom

Zoom is another type that can be used. This type is very different in that it always draws both frames - one on top of the other!

The frames can be individually zoomed in or out, in and then out, out and then in, or none.

One way of zooming can be cropping the texture, making the appearance of being "zoomed in" while the size of the frame does not change (it's still at full size). The other way of zooming is to scale the frame, making the actual frame edge visible as it becomes smaller.
Note that this is not designed to increase the size of the frame.

The way of zooming determines the frame's start and end position.
For example, if zooming in: If the way of zooming is crop, the frame will start at full size and end up "zoomed in" to the texture. If the way of zooming is scale, the frame will start scaled smaller and end up at full, normal size.

It's worth experimenting as many interesting effects can be mixing zooms, ways of zooms, and different "fades".
With that said, if a specific type of effect is required, some planning could be useful.

Fades

As with types and their "ways", fades can set per frame.
Note also that fades are global, meaning that they can be used with both TexCrop or Zoom.

If a frame's fade is set to "none", the colours of the frames are not adjusted. This is the setting for a usual TexCrop but others can be used too.

If a frame's fade is set to "off", the colour of the frame has its alpha set to zero, allowing that frame to be invisible for the entire transition.

If a frame's fade is set to "step", its colour has its alpha at zero for half of the transition and its normal alpha for the other half. Frame A has its normal alpha first whereas Frame B has its normal alpha last. If both are set to step, B will become visible at the point where A becomes invisible.

If a frame's fade is set to "linear", its alpha is interpolated from its normal alpha to zero. A will start normal and end at zero where B will start at zero and end at normal.

Since these can be set per frame, it's possible to have one set to "step" and the other set to "linear", for example.


Usage

Declaration

Its size can be specified at creation or left empty, creating a frame of a default size: 64 x 8.

sw::FrameTransition frameTransition;
creates a Frame Transition that has its default size (see above).

sw::Starfield starfield(sf::Vector2f size);
creates a Frame Transition of the specified size.

Drawing

This class inherits from sf::Drawable so it is drawn in the same way as all SFML drawables:
window.draw(frameTransition);
where window is an sf::RenderWindow.

Note: actually, window could be any sf::RenderTarget.

Transformations

This class inherits from sf::Transformable so it has all the usual SFML transformations available.

Manipulation

Set-up

There quite a few things to set up with Frame Transition.
However, the most comprehensize (and maybe be considered complicated) is the specification of the transition; it is specified using an enum that can be orred together to create a transition formed from multiple settings.

  • setSize(sf::Vector2f size)
    sets the new size for the Frame Transition.

  • setDrawOrderToAOverB()
    sets the draw order so that Frame A is drawn over (after) Frame B. This is the default order and can optimise draw calls if possible so should be always used unless a specific reason requires otherwise.

  • setDrawOrderToBOverA()
    sets the draw order so that Frame B is drawn over (after) Frame A. This always takes 2 separate draw calls so should be avoided unless required.

  • setTransition(T transitionId)
    sets the translation ID. This is a compound enum that specifies all of the settings of the transition including its type. See below (Transition ID) for more details. T is the transition ID type: sw::FrameTransition::T.

  • setColors(sf::Color colorA, sf::Color colorB)
    sets the colours of each frame. This is colour of the quad used to show the frame; it is multiplied with the texture as usual (unless a shader affects this behaviour). colorA is the colour of Frame A and colorB is the colour of Frame B.

  • setColors(sf::Color color)
    sets the colours of both frames the same colour.

  • setColor(FrameId frameId, sf::Color color)
    sets the colour of the frame specified by the frame ID. FrameId (sw::FrameTransition::FrameId) is an enum class with just two members: A and B.

  • setTextures(const sf::Texture& textureA, const sf::Texture& textureB)
    sets both frames' textures at once.

  • setTextures(const sf::Texture& texture)
    sets both frames' textures to the same sf::Texture.

  • setTextures()
    clears (nullifies) both textures.

  • setTexture(FrameId frameId, const sf::Texture& texture, bool resetRect)
    sets the texture for the specified frame. If resetRect is true, the texture rect for the frame is set to the size of the texture. The default value for resetRect - if omitted - is false.

  • setTexture(FrameId frameId)
    clears (nullifies) the texture for the specified frame.

  • setTextureRect(FrameId frameId, sf::IntRect textureRectangle)
    sets the texture rectangle for the specified frame. If textureRectangle is omitted, it's a default sf::IntRect (position of 0,0 and size or 0x0).

  • setParameter1(float parameter1)
    sets parameter 1 to the given value. The parameters can be used to customise certain aspects of the transitions. Currently, only the transition type of Zoom makes use of the parameters; parameter 1 is the amount to scale Frame A or crop its texture. Only values between 0 and 1 should be used. If parameter1 is omitted, parameter 1 is reset to a value of zero.

  • setParameter2(float parameter2)
    sets parameter 2 to the given value. The parameters can be used to customise certain aspects of the transitions. Currently, only the transition type of Zoom makes use of the parameters; parameter 2 is the amount to scale Frame B or crop its texture. Only values between 0 and 1 should be used. If parameter2 is omitted, parameter 2 is reset to a value of zero.

  • resetParameters()
    resets both parameters. This sets them both to a value of zero.

Amounts

The amounts are the way to specify at what stage of the transition to be, starting from Frame A and ending at Frame B.

  • setRatio(float ratio)
    sets the amount to the given ratio (in the range of 0 to 1). 0 is the start position (Source Frame: A) and 1 is the end position (Destination Frame: B).

  • setPercentage(float percentage)
    sets the amount to the given percentage(in the range of 0 to 100). 0 is the start position (Source Frame: A) and 100 is the end position (Destination Frame: B).

  • setFromValueInRange(value, min, max)
    sets the amount to a value from within a range specified by the min and max values. value, min and max must be the same type and that type can be any that can be casted to a float. A value of min would represent the start position and a value of max would represent the end position.

  • setFromValueInRange(value, range)
    sets the amount to a value from within a range specified by range. This range is the maximum value and zero is the minimum value. value and range must be the same type and that type can be any that can be casted to a float. A value of 0 would represent the start position and a value of range would represent the end position.

Information

  • getSize()
    returns an sf::Vector2f representing its size.

  • getTransition()
    returns the transition ID (represented by sw::FrameTransition::T - see below). This represents all of the current settings for the transition.

  • getRatio()
    returns the amount as a ratio (as a float).

  • getPercentage()
    returns the amount as a percentage (as a float).

  • getColor(FrameId)
    returns the current colour of the specified frame.

  • getTexture(FrameId)
    returns the current texture assigned to the specified frame. Note that this is a const reference to an sf::Texture (const sf::Texture&).

  • getParameter1()
    returns the current value of parameter 1 as a float.

  • getParameter2()
    returns the current value of parameter 2 as a float.

  • getLocalBounds()
    returns the local bounds (before transformations) as an sf::FloatRect.

  • getGlobalBounds()
    returns the global bounds (after transformations) as an sf::FloatRect.

Types

There are two types that come with Frame Transition: Frame ID and Transition ID.

  • FrameId sw::FrameTransition::FrameId
    FrameId is the representation of a Frame ID that identifies which frame. Its values can be either A or B.

  • T
    sw::FrameTransition::T
    T is the representation of the Transition ID that contains all of the settings for the transition. Its value is an enum that has values that can be orred together to create multiple forms.

This is the heart of Frame Transition but may seem complicated at first. However, it's just an enum that acts as a bitmask allowing multiple values to be set as one.

T

These are the values of T (the Transition ID).
Note that similar information is available in the Frame Transition header file within its comments.

The Bits

The first (least significant bit) bit is the Type. This specifies whether the transition is of type TexCrop (0) or Zoom (1).

The next 4 bits are the Fades: 2 bits each - Frame A's fade first 2 bits, Frame B's fade second 2 bits. Each 2 bits represent a number from 0 to 3: 0 is "None", 1 is "Off", 2 is "Step", and 3 is "Linear".
e.g. 1001 would be: Frame A = None, Frame B = Step.

The next bits depend on the type. There are 8 bits per type and they are split into 6 bits and 2 bits for both types.

When type is TexCrop
The next 6 bits are the crop types: 3 bits for each frame - Frame A's crop is first 3 bits and Frame B's crop is second 3 bits.
The first bit is Start crop.
The second bit is End crop.
Both bits together represent Both crops (Start and End).
The third bit represent Shuffle crop; this must not be used with the Start and/or End bits.

The next 2 bits are the direction: a value from 0 to 3. 0 is "Right", 1 is "Left", 2 is "Up" and 3 is "Up".

When type is Zoom
The next 6 bits are the zoom (z direction): 3 bits for each frame - Frame A's zoom is first 3 bits and Frame B's zoom is second 3 bits.
The first bit is In zoom.
The second bit is Out zoom.
Both bits together represent both zooms (In and Out) and means (InOut) "In and then Out".
The third bit means (OutIn) "Out and then In" and must not be used with the first 2 bits.

The next 2 bits are the type: 1 bit for each frame - Frame A's type is first bit and Frame B's type is second bit. For each bit/frame, 0 is "Crop" and 1 is "Scale".

Values

For the transition type (1 bit):
The bitmask for this value is Type.
The value can be Type_TexCrop or Type_Zoom.

For the fades (4 bits):
The bitmask for both frames' fades is Fade.
The bitmask for Frame A's fade is Fade_A.
The bitmask for Frame B's fade is Fade_B.
The value of Frame A's fade can be Fade_A_None, Fade_A_Off, Fade_A_Step or Fade_A_Linear.
The value of Frame B's fade can be Fade_B_None, Fade_B_Off, Fade_B_Step or Fade_B_Linear.

When type is TexCrop
For the crops (6 bits):
The bitmask for both frames' crops is TexCrop.
The bitmask for Frame A's crop is TexCrop_A.
The bitmask for Frame B's crop is TexCrop_B.
The value of Frame A's crop can be TexCrop_A_None, TexCrop_A_Start, TexCrop_A_End, TexCrop_A_Both or TexCrop_A_Shuffle. Note that TexCrop_A_Both is a shortcut for using (TexCrop_A_Start | TexCrop_A_End).
The value of Frame B's crop can be TexCrop_B_None, TexCrop_B_Start, TexCrop_B_End, TexCrop_B_Both or TexCrop_B_Shuffle. Note that TexCrop_B_Both is a shortcut for using (TexCrop_B_Start | TexCrop_B_End).

For the direction (2 bits):
The bitmask for the direction is Direction.
The value can be Direction_Right, Direction_Left, Direction_Down or Direction_Up.

When type is Zoom For the zooms (6 bits):
The bitmask for both frames' zooms is Zoom.
The bitmask for Frame A's zoom is Zoom_A.
The bitmask for Frame B's zoom is Zoom_B.
The value of Frame A's zoom can be Zoom_A_None, Zoom_A_In, Zoom_A_Out, Zoom_A_InOut or Zoom_A_OutIn. Note that Zoom_A_InOut is a shortcut for using (Zoom_A_In | Zoom_A_Out).
The value of Frame B's zoom can be Zoom_B_None, Zoom_B_In, Zoom_B_Out, Zoom_B_InOut or Zoom_B_OutIn. Note that Zoom_B_InOut is a shortcut for using (Zoom_B_In | Zoom_B_Out).

For the types (2 bits):
The bitmask for both frames' zoom type is ZoomType.
The bitmask for Frame A's zoom type is ZoomType_A.
The bitmask for Frame B's zoom type is ZoomType_B.
The value of Frame A's zoom type can be ZoomType_A_Crop or ZoomType_A_Scale.
The value of Frame B's zoom type can be ZoomType_B_Crop or ZoomType_B_Scale.

Special

The special value of None can be used in place of any or all values that end with "None".

Directions

The direction for TexCrop type transitions can be one of four values that represent Right, Left, Down and Up.
It's not immediately obvious what this means (unless you apply it to a transition and see it in action, of course!).

It is the direction that the dividing edge - that joins both frames - moves.
So, when it is at its default, right, when the amount is at its start position (ratio = 0), only Frame A will be visible (full size) and Frame B will be infinitely thin, but... it will be on the left side of Frame A. As the amount progresses, Frame B will stretch out towards the right (the direction) and fill the space while Frame A will squash towards the right (the direction) until invisible.
This definition applies to all directions (the dividing edge moves in that direction).
In fact, this applies for all TexCrop transitions. Only the cropping affects the style of the transition.

Simple Example 1

#include <SFML/Graphics.hpp>
#include <SelbaWard.hpp>
int main()
{
    sf::Texture textureA{};
    sf::Texture textureB{};
    if (!(textureA.loadFromFile("resources/uv map.jpg") && textureB.loadFromFile("resources/Simple Tileset.png")))
        return EXIT_FAILURE;
    sw::FrameTransition frameTransition{};
    frameTransition.setSize({ 256.f, 256.f });
    frameTransition.setTexture(sw::FrameTransition::FrameId::A, textureA, true);
    frameTransition.setTexture(sw::FrameTransition::FrameId::B, textureB, true);
    sf::RenderWindow window(sf::VideoMode({ 256u, 256u }), "Frame Transition simple example 1");
    sf::Clock clock;
    while (window.isOpen())
    {
        const float currentTime{ clock.getElapsedTime().asSeconds() / 2.f }; // transition takes 2 seconds
        frameTransition.setRatio(currentTime - std::trunc(currentTime));
        window.clear();
        window.draw(frameTransition);
        window.display();
        while (const auto event{ window.pollEvent() })
        {
            if (event->is<sf::Event::Closed>())
                window.close();
        }
    }
}

The code above displays something similar to:
Simple Example 1
This is an example of a wipe and is the default style.

Simple Example 2

#include <SFML/Graphics.hpp>
#include <SelbaWard.hpp>
int main()
{
    sf::Texture textureA{};
    sf::Texture textureB{};
    if (!(textureA.loadFromFile("resources/uv map.jpg") && textureB.loadFromFile("resources/Simple Tileset.png")))
        return EXIT_FAILURE;
    sw::FrameTransition frameTransition{};
    frameTransition.setSize({ 256.f, 256.f });
    frameTransition.setTexture(sw::FrameTransition::FrameId::A, textureA, true);
    frameTransition.setTexture(sw::FrameTransition::FrameId::B, textureB, true);
    frameTransition.setTransition(sw::FrameTransition::T::TexCrop_A_End | sw::FrameTransition::T::TexCrop_B_Start);
    sf::RenderWindow window(sf::VideoMode({ 256u, 256u }), "Frame Transition simple example 2");
    sf::Clock clock;
    while (window.isOpen())
    {
        const float currentTime{ clock.getElapsedTime().asSeconds() / 2.f }; // transition takes 2 seconds
        frameTransition.setRatio(currentTime - std::trunc(currentTime));
        window.clear();
        window.draw(frameTransition);
        window.display();
        while (const auto event{ window.pollEvent() })
        {
            if (event->is<sf::Event::Closed>())
                window.close();
        }
    }
}

The code above displays something similar to:
Simple Example 2
This is an example of a push/slide.

Note: the textures used in these examples are available, along with more examples, in the examples folder, although you can use your own images.

This Frame Transition example (https://github.com/Hapaxia/SelbaWard/blob/master/examples/frameTransitionExample.cpp) was used to create this video that demonstrates multiple forms of transitions:
Frame Transition example

(Frame Transition v1.0)