Quantcast
Channel: directxtk Wiki Rss Feed
Viewing all articles
Browse latest Browse all 874

Updated Wiki: SpriteSheet

$
0
0
This is an example of a C++ port of the C# MonoGame sprite loader and renderer for using sprite sheets created by the CodeAndWeb tool TexturePacker using the built-in MonoGame project type. This makes use of SpriteBatch to render.

https://www.codeandweb.com/texturepacker/monogame

You can change this code to work with other sprite sheet creation tools by modifying the metadata reading code in Load.

SpriteSheet.h
class SpriteSheet
{
public:
    struct SpriteFrame
    {
        RECT                sourceRect;
        DirectX::XMFLOAT2   size;
        DirectX::XMFLOAT2   origin;
        bool                rotated;
    };

    void Load( ID3D11ShaderResourceView* texture, constwchar_t* szFileName )
    {
        mSprites.clear();

        mTexture = texture;

        if (szFileName)
        {
            //// This code parses the 'MonoGame' project txt file that is produced by// CodeAndWeb's TexturePacker.// https://www.codeandweb.com/texturepacker//// You can modify it to match whatever sprite-sheet tool you are using//

            std::wifstream inFile( szFileName );
            if( !inFile )
                throw std::exception( "SpriteSheet failed to load .txt data" );

            wchar_t strLine[1024];
            for(;;)
            {
                inFile >> strLine;
                if( !inFile )
                    break;

                if( 0 == wcscmp( strLine, L"#" ) )
                {
                    // Comment
                }
                else
                {
                    staticconstwchar_t* delim = L";\n";

                    wchar_t* context = nullptr;
                    wchar_t* name = wcstok_s(strLine, delim, &context);
                    if ( !name || !*name )
                        throw std::exception();

                    if ( mSprites.find( name ) != mSprites.cend() )
                        throw std::exception();

                    wchar_t* str = wcstok_s(nullptr, delim, &context);
                    if ( !str )
                        throw std::exception();

                    SpriteFrame frame;
                    frame.rotated = (_wtoi(str) == 1);

                    str = wcstok_s(nullptr, delim, &context);
                    if ( !str )
                        throw std::exception();
                    frame.sourceRect.left = _wtol(str);

                    str = wcstok_s(nullptr, delim, &context);
                    if ( !str )
                        throw std::exception();
                    frame.sourceRect.top = _wtol(str);

                    str = wcstok_s(nullptr, delim, &context);
                    if ( !str )
                        throw std::exception();
                    LONG dx = _wtol(str);
                    frame.sourceRect.right = frame.sourceRect.left + dx;

                    str = wcstok_s(nullptr, delim, &context);
                    if ( !str )
                        throw std::exception();
                    LONG dy = + _wtol(str);
                    frame.sourceRect.bottom = frame.sourceRect.top + dy;

                    str = wcstok_s(nullptr, delim, &context);
                    if ( !str )
                        throw std::exception();
                    frame.size.x = static_cast<float>( _wtof(str) );

                    str = wcstok_s(nullptr, delim, &context);
                    if ( !str )
                        throw std::exception();
                    frame.size.y = static_cast<float>( _wtof(str) );

                    str = wcstok_s(nullptr, delim, &context);
                    if ( !str )
                        throw std::exception();
                    float pivotX = static_cast<float>( _wtof(str) );

                    str = wcstok_s(nullptr, delim, &context);
                    if ( !str )
                        throw std::exception();
                    float pivotY = static_cast<float>( _wtof(str) );

                    if (frame.rotated)
                    {
                        frame.origin.x = dx * (1.f - pivotY);
                        frame.origin.y = dy * pivotX;
                    }
                    else
                    {
                        frame.origin.x = dx * pivotX;
                        frame.origin.y = dy * pivotY;
                    }

                    mSprites.insert( std::pair<std::wstring,SpriteFrame>(
                        std::wstring(name), frame) );
                }

                inFile.ignore( 1000, '\n' );
            }
        }
    }

    const SpriteFrame* Find(constwchar_t* name) const
    {
        auto it = mSprites.find(name);
        if (it == mSprites.cend())
            returnnullptr;

        return&it->second;
    }

    void XM_CALLCONV Draw(DirectX::SpriteBatch* batch, const SpriteFrame& frame,
        DirectX::XMFLOAT2 const& position,
        DirectX::FXMVECTOR color = DirectX::Colors::White, float rotation = 0,
        float scale = 1,
        DirectX::SpriteEffects effects = DirectX::SpriteEffects_None,
        float layerDepth = 0) const
    {
        assert(batch != 0);
        usingnamespace DirectX;

        if (frame.rotated)
        {
            rotation -= XM_PIDIV2;
            switch(effects)
            {
            case SpriteEffects_FlipHorizontally:
                effects = SpriteEffects_FlipVertically;
                break;
            case SpriteEffects_FlipVertically:
                effects = SpriteEffects_FlipHorizontally;
                break;
            }
        }

        XMFLOAT2 origin = frame.origin;
        switch (effects)
        {
        case SpriteEffects_FlipHorizontally:
                origin.x = frame.sourceRect.right - frame.sourceRect.left - origin.x;
                break;
        case SpriteEffects_FlipVertically:
                origin.y = frame.sourceRect.bottom - frame.sourceRect.top - origin.y;
                break;
        }

        batch->Draw(mTexture.Get(), position, &frame.sourceRect, color, rotation,
                origin, scale, effects, layerDepth );
    }

    void XM_CALLCONV Draw(DirectX::SpriteBatch* batch, const SpriteFrame& frame,
        DirectX::XMFLOAT2 const& position,
        DirectX::FXMVECTOR color, float rotation, DirectX::XMFLOAT2 const& scale,
        DirectX::SpriteEffects effects = DirectX::SpriteEffects_None,
        float layerDepth = 0) const
    {
        ...
    }

    // Draw overloads specifying position and scale via the first two components of// an XMVECTOR.void XM_CALLCONV Draw(DirectX::SpriteBatch* batch, const SpriteFrame& frame,
        DirectX::FXMVECTOR position,
        DirectX::FXMVECTOR color = DirectX::Colors::White, float rotation = 0,
        float scale = 1,
        DirectX::SpriteEffects effects = DirectX::SpriteEffects_None,
        float layerDepth = 0) const
    {
        ...
    }

    void XM_CALLCONV Draw(DirectX::SpriteBatch* batch, const SpriteFrame& frame,
        DirectX::FXMVECTOR position,
        DirectX::FXMVECTOR color, float rotation, DirectX::GXMVECTOR scale,
        DirectX::SpriteEffects effects = DirectX::SpriteEffects_None,
        float layerDepth = 0) const
    {
        ...
    }

    // Draw overloads specifying position as a RECT.void XM_CALLCONV Draw(DirectX::SpriteBatch* batch, const SpriteFrame& frame,
        RECT const& destinationRectangle,
        DirectX::FXMVECTOR color = DirectX::Colors::White, float rotation = 0,
        DirectX::SpriteEffects effects = DirectX::SpriteEffects_None,
        float layerDepth = 0) const
    {
        ...
    }

private:
    Microsoft::WRL::ComPtr<ID3D11ShaderResourceView>    mTexture;
    std::map<std::wstring, SpriteFrame>                 mSprites;
};

Example

This example uses a sprite sheet created from the content in the original C# XNA Game Studio SpriteSheetSample.

http://xbox.create.msdn.com/en-US/education/catalog/sample/sprite_sheet

The resulting sprite sheet is (spritesheetsample.png):
spritesheetsample.png

and the resulting metadata SpriteSheetSample.txt file is:
#
# Sprite sheet data for MonoGame.
#
# To learn how to import these sprites into your MonoGame project visit:
# http://www.codeandweb.com/texturepacker/monogame
#
# Sprite sheet: SpriteSheetSample.png (204 x 200)
# $TexturePacker:SmartUpdate:0368b25d54aeeee939136b8605cf8eb5:68e5ed36fde793856b1138fb021ac1d9:f18d998871cf5eafdd9feca9b014994a$
#

cat;0;2;2;66;100;100;100;0.5151515151515151;0.5
glow1;0;2;104;64;64;64;64;0.5;0.5
glow2;0;70;2;64;64;64;64;0.5;0.5
glow3;0;136;2;64;64;64;64;0.5;0.5
glow4;0;70;68;64;64;64;64;0.5;0.5
glow5;0;68;134;64;64;64;64;0.5;0.5
glow6;0;134;134;64;64;64;64;0.5;0.5
glow7;0;136;68;64;64;64;64;0.5;0.5

#include "SpriteBatch.h"
#include "SpriteSheet.h"
#include "WICTextureLoader.h"// Create a texture using our sprite sheet
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> texture;
hr = CreateWICTextureFromFile( device, L"SpriteSheetSample.png", nullptr, texture.GetAddressOf() );

...

// Create a SpriteBatch for rendering
std::unique_ptr<DirectX::SpriteBatch> spriteBatch( new SpriteBatch( context ) );

// Create an SpriteSheet helper class instance 
std::unique_ptr<SpriteSheet> sprites( new SpriteSheet );
sprites->Load( texture.Get(), L"SpriteSheetSample.txt" );

...

// Render a sprite from the sheet
spriteBatch->Begin();

auto frame = sprites->Find( L"cat" );
assert( frame != 0 );

sprites->Draw( spriteBatch.get(), *frame, screenPos );

// TODO - More sprites or text here
spriteBatch->End();

Texture Packer notes

If you are making use of CodeAndWeb's Texture Packer tool, you will be writing out the sprite sheet texture as a PNG which you will be using at runtime along with the 'data file' .txt that is defined as part of the "MonoGame" project. Note that you will not be making use of the '.cs' file Texture Packer generates as part of the "MonoGame" project type.

You can optionally convert the PNG to a DDS using DirectXTex's texconv tool or the Visual Studio 2012/2013 texture content processor, ideally using BC2 or BC3 for runtime compression. This will result in a larger DDS file on disk than a PNG, but will use less video memory when loaded. You would use DDSTextureLoader instead of WICTextureLoader in this case.

If you are using premultiplied alpha, you should under Texture \ show advanced set the Premultiply alpha check box option. If using DDS rather than PNG, you should leave this option unchecked and add the -pmalpha option to DirectXTex's texconv to get the premultipled alpha conversion as part of creating the DDS.

In most cases you won't need mipmap levels generated so specify -m 1 when converting the DDS. If you do want mipmaps levels and want to support all feature levels (i.e. Feature Levesl 9.x), then in your Texture Packer project under Layout / Size constraints set it to "POW (Power of 2)" and do not use -m 1.

Open a Command Prompt, and change to the directory containing Texconv.exe (i.e. ...\DirectXTex\Texconv\Release)
http://windows.microsoft.com/en-us/windows/command-prompt-faq

Enter the following command-line after changing to the appropriate directory:
texconv.exe SpriteSheetSample.png -f BC3_UNORM -m 1 -pmalpha

https://directxtex.codeplex.com/wikipage?title=Texconv


Viewing all articles
Browse latest Browse all 874

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>