Jump to content
  • Advertisement
Sign in to follow this  
Vanz

Direct3D Sprites

This topic is 2163 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Learning C++, can someone please explain how the following works or point me to on-line tutorial or book covering topic:

 

 

SimpleSprites::SimpleSprites() : m_numParticlesToDraw(SampleSettings::Performance::InitialParticleCount)

 

How does f::f: work and f::f::f ?

 

Basically I'm trying to really understand the following code, it's from an sdk:

//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//// PARTICULAR PURPOSE.
////
//// Copyright (c) Microsoft Corporation. All rights reserved

#include "pch.h"
#include "SimpleSprites.h"
#include "BasicLoader.h"

using namespace Microsoft::WRL;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Core;

using namespace BasicSprites;

SimpleSprites::SimpleSprites() :
    m_numParticlesToDraw(SampleSettings::Performance::InitialParticleCount)
{
}

void SimpleSprites::CreateDeviceIndependentResources()
{
    DirectXBase::CreateDeviceIndependentResources();

    // Create the performance throttler.

    m_autoThrottle = ref new AutoThrottle(SampleSettings::Performance::TargetFrameTime);
}

void SimpleSprites::CreateDeviceResources()
{
    DirectXBase::CreateDeviceResources();

    // Create the sprite batch.

    m_spriteBatch = ref new SpriteBatch();
    unsigned int capacity = SampleSettings::Performance::ParticleCountMax + SampleSettings::NumAsteroids + 1;
    if (m_featureLevel < D3D_FEATURE_LEVEL_9_3)
    {
        capacity = min(Parameters::MaximumCapacityCompatible, capacity);
    }
    m_spriteBatch->Initialize(
        m_d3dDevice.Get(),
        capacity
        );

    // Load the sprite textures.

    BasicLoader^ loader = ref new BasicLoader(m_d3dDevice.Get(), m_wicFactory.Get());

    loader->LoadTexture(
        "m31.png",
        &m_background,
        nullptr
        );
    m_spriteBatch->AddTexture(m_background.Get());

    loader->LoadTexture(
        "ida.dds",
        &m_asteroid,
        nullptr
        );
    m_spriteBatch->AddTexture(m_asteroid.Get());

    loader->LoadTexture(
        "particle.dds",
        &m_particle,
        nullptr
        );
    m_spriteBatch->AddTexture(m_particle.Get());

    // Create the Sample Overlay.

    m_sampleOverlay = ref new SampleOverlay();

    m_sampleOverlay->Initialize(
        m_d2dDevice.Get(),
        m_d2dContext.Get(),
        m_wicFactory.Get(),
        m_dwriteFactory.Get(),
        "Direct3D SpriteBatch sample"
        );
}

void SimpleSprites::CreateWindowSizeDependentResources()
{
    DirectXBase::CreateWindowSizeDependentResources();

    // Randomly generate some non-interactive asteroids to fit the screen.

    m_asteroidData.clear();
    for (int i = 0; i < SampleSettings::NumAsteroids; i++)
    {
        AsteroidData data;
        data.pos.x = RandFloat(0.0f, m_windowBounds.Width);
        data.pos.y = RandFloat(0.0f, m_windowBounds.Height);
        float tempRot = RandFloat(-PI_F, PI_F);
        float tempMag = RandFloat(0.0f, 17.0f);
        data.vel.x = tempMag * cosf(tempRot);
        data.vel.y = tempMag * sinf(tempRot);
        data.rot = RandFloat(-PI_F, PI_F);
        data.scale = RandFloat(0.1f, 1.0f);
        data.rotVel = RandFloat(-PI_F, PI_F) / (7.0f + 3.0f * data.scale);
        m_asteroidData.push_back(data);
    }


    if (m_particleData.size() == 0)
    {
        // Initialize the interactive particle buffer to fill the window if it is empty.

        for (int i = 0; i < SampleSettings::Performance::ParticleCountMax; i++)
        {
            ParticleData data;
            data.pos.x = RandFloat(0.0f, m_windowBounds.Width);
            data.pos.y = RandFloat(0.0f, m_windowBounds.Height);
            data.vel = float2(0.0f, 0.0f);
            m_particleData.push_back(data);
        }
    }
    else
    {
        // Otherwise, move the interactive particles to fit within the screen.

        for (auto particle = m_particleData.begin(); particle != m_particleData.end(); particle++)
        {
            if (particle->pos.x > m_windowBounds.Width)
            {
                particle->pos.x = m_windowBounds.Width;
            }
            if (particle->pos.y > m_windowBounds.Height)
            {
                particle->pos.y = m_windowBounds.Height;
            }
        }
    }

    m_sampleOverlay->UpdateForWindowSizeChange();
}

void SimpleSprites::Update(float timeTotal, float timeDelta)
{
    // Update the performance throttler.

    auto control = m_autoThrottle->Update(timeDelta);

    if (control == FrameWorkload::Increase)
    {
        m_numParticlesToDraw += SampleSettings::Performance::ParticleCountDelta;
    }
    if (control == FrameWorkload::Decrease)
    {
        m_numParticlesToDraw -= SampleSettings::Performance::ParticleCountDelta;
    }
    if (control != FrameWorkload::Maintain)
    {
        m_numParticlesToDraw = max(SampleSettings::Performance::ParticleCountMin, min(SampleSettings::Performance::ParticleCountMax, m_numParticlesToDraw));
        if (m_featureLevel < D3D_FEATURE_LEVEL_9_3)
        {
            m_numParticlesToDraw = min(static_cast<int>(Parameters::MaximumCapacityCompatible - SampleSettings::NumAsteroids - 1), m_numParticlesToDraw);
        }
    }

    // Update the non-interactive asteroids.
    // Their behavior is to drift across the window with a fixed translational and rotational
    // velocity.  Upon crossing a boundary outside the window, their position wraps.

    for (auto asteroid = m_asteroidData.begin(); asteroid != m_asteroidData.end(); asteroid++)
    {
        static const float border = 100.0f;
        asteroid->pos = asteroid->pos + asteroid->vel * timeDelta;
        if (asteroid->vel.x < 0)
        {
            if (asteroid->pos.x < -border)
            {
                asteroid->pos.x = m_windowBounds.Width + border;
            }
        }
        else
        {
            if (asteroid->pos.x > m_windowBounds.Width + border)
            {
                asteroid->pos.x = -border;
            }
        }
        if (asteroid->vel.y < 0)
        {
            if (asteroid->pos.y < -border)
            {
                asteroid->pos.y = m_windowBounds.Height + border;
            }
        }
        else
        {
            if (asteroid->pos.y > m_windowBounds.Height + border)
            {
                asteroid->pos.y = -border;
            }
        }

        asteroid->rot += asteroid->rotVel * timeDelta;
        if (asteroid->rot > PI_F)
        {
            asteroid->rot -= 2.0f * PI_F;
        }
        if (asteroid->rot < -PI_F)
        {
            asteroid->rot += 2.0f * PI_F;
        }
    }

    // Update the interactive particles.
    // Their behavior is to be gravitationally attracted to two oscillating gravity
    // wells and repelled by any pressed pointer points.  Upon reaching the edge of
    // the window, the particles bounce.

    // Add two gravity wells that move throughout the window.
    float2 wellPositions[] =
    {
        float2(
            (1.0f + 0.8f * cosf(timeTotal / (2.0f * PI_F) + 3.0f)) * m_windowBounds.Width / 2.0f,
            (1.0f + 0.8f * sinf(timeTotal / 5.0f)) * m_windowBounds.Height / 2.0f
            ),
        float2(
            (1.0f + 0.8f * cosf(timeTotal / (PI_F * PI_F) + 1.0f)) * m_windowBounds.Width / 2.0f,
            (1.0f + 0.8f * sinf(timeTotal / PI_F)) * m_windowBounds.Height / 2.0f
            )
    };

    for (auto particle = m_particleData.begin(); particle != m_particleData.begin() + m_numParticlesToDraw; particle++)
    {
        if (particle->pos.x < 0)
        {
            particle->vel.x = abs(particle->vel.x);
        }
        if (particle->pos.x > m_windowBounds.Width)
        {
            particle->vel.x = -abs(particle->vel.x);
        }
        if (particle->pos.y < 0)
        {
            particle->vel.y = abs(particle->vel.y);
        }
        if (particle->pos.y > m_windowBounds.Height)
        {
            particle->vel.y = -abs(particle->vel.y);
        }

        for (auto repulsor = m_repulsors.begin(); repulsor != m_repulsors.end(); repulsor++)
        {
            float2 delta = particle->pos - repulsor->second;
            float deltaLength = length(delta) + 24.0f; // Offset length to avoid division by zero.
            float deltaLengthCubed = deltaLength * deltaLength * deltaLength;
            particle->vel = particle->vel + SampleSettings::Physics::Gravity * timeDelta * delta / deltaLengthCubed;
        }

        for (int i = 0; i < ARRAYSIZE(wellPositions); i++)
        {
            float gravitySign = 1.0f;
            if ((static_cast<int>(timeTotal / 2.0f) + 1) % 10 == 0)
            {
                // Every 20 seconds, "explode" the gravity wells for 2 seconds.
                gravitySign = -1.0f;
            }
            float2 delta = wellPositions[i] - particle->pos;
            float deltaLength = length(delta) + 24.0f;
            float deltaLengthCubed = deltaLength * deltaLength * deltaLength;
            particle->vel = particle->vel + gravitySign * 0.2f * SampleSettings::Physics::Gravity * timeDelta * delta / deltaLengthCubed;
        }

        particle->vel = particle->vel * (1.0f - SampleSettings::Physics::Damping);

        // Add random noise to the velocity to prevent particles from locking together.

        particle->vel.x += RandFloat(-0.5f, 0.5f);
        particle->vel.y += RandFloat(-0.5f, 0.5f);

        particle->pos = particle->pos + particle->vel * timeDelta;
    }
}

void SimpleSprites::Render()
{
    m_d3dContext->OMSetRenderTargets(
        1,
        m_d3dRenderTargetView.GetAddressOf(),
        nullptr
        );

    m_d3dContext->ClearRenderTargetView(
        m_d3dRenderTargetView.Get(),
        reinterpret_cast<float*>(&D2D1::ColorF(D2D1::ColorF::MidnightBlue))
        );

    m_spriteBatch->Begin();

    // Draw the background.

    m_spriteBatch->Draw(
        m_background.Get(),
        float2(0.5f, 0.5f),
        PositionUnits::Normalized,
        float2(1.0f, 1.0f),
        SizeUnits::Normalized
        );

    // Draw the non-interactive asteroids.

    for (auto asteroid = m_asteroidData.begin(); asteroid != m_asteroidData.end(); asteroid++)
    {
        m_spriteBatch->Draw(
            m_asteroid.Get(),
            asteroid->pos,
            PositionUnits::DIPs,
            float2(1.0f, 1.0f) * asteroid->scale,
            SizeUnits::Normalized,
            float4(0.8f, 0.8f, 1.0f, 1.0f),
            asteroid->rot
            );
    }

    // Draw the interactive particles.

    for (auto particle = m_particleData.begin(); particle != m_particleData.begin() + m_numParticlesToDraw; particle++)
    {
        float alpha = length(particle->vel) / 200.0f;
        m_spriteBatch->Draw(
            m_particle.Get(),
            particle->pos,
            PositionUnits::DIPs,
            float2(32.0f, 32.0f),
            SizeUnits::DIPs,
            float4(0.1f, 0.02f, 0.0f, alpha),
            0.0f,
            BlendMode::Additive
            );
    }

    m_spriteBatch->End();

    // Render the Sample Overlay.

    m_sampleOverlay->Render();
}

float SimpleSprites::RandFloat(float min, float max)
{
    return (static_cast<float>(rand() % RAND_MAX) / static_cast<float>(RAND_MAX)) * (max - min) + min;
}

void SimpleSprites::AddRepulsor(_In_ uint32 id, _In_ float2 position)
{
    m_repulsors[id] = position;
}

void SimpleSprites::MoveRepulsor(_In_ uint32 id, _In_ float2 position)
{
    m_repulsors[id] = position;
}

void SimpleSprites::RemoveRepulsor(_In_ uint32 id)
{
    m_repulsors.erase(id);
}

Share this post


Link to post
Share on other sites
Advertisement

Also for this command:

 

"BasicLoader^ loader = ref new BasicLoader(m_d3dDevice.Get(), m_wicFactory.Get());"

 

What does the "ref new" and "^" exactly do, is this allocating memory for a pointer function?

Share this post


Link to post
Share on other sites

Learning C++

Nope, C++/CLI. It's .NET for C++.

SimpleSprites::SimpleSprites() : m_numParticlesToDraw(SampleSettings::Performance::InitialParticleCount)

How does f::f: work and f::f::f ?

The operator::, is the scope resolution operator. The single colon afterwards is the member initializer list. This line of code basically reads: Here follows the constructor of SimpleSprites, initialize m_numParticlesToDraw to the InitialParticleCount of Performance in SampleSettings.

Share this post


Link to post
Share on other sites

"BasicLoader^ loader = ref new BasicLoader(m_d3dDevice.Get(), m_wicFactory.Get());"
 
What does the "ref new" and "^" exactly do, is this allocating memory for a pointer function?


The caret signifies a pointer to an object in managed memory; essentially it is a handle. The ref new allocates memory on the managed heap. There is no "pointer function" here. The object, loader, is defined as a handle to a BasicLoader, and is initialized to a new instance of BasicLoader (constructed on the managed heap using m_d3dDevice and m_wicFactory as parameters). Edited by fastcall22

Share this post


Link to post
Share on other sites

 

Learning C++

Nope, C++/CLI. It's .NET for C++.

SimpleSprites::SimpleSprites() : m_numParticlesToDraw(SampleSettings::Performance::InitialParticleCount)

How does f::f: work and f::f::f ?

The operator::, is the scope resolution operator. The single colon afterwards is the member initializer list. This line of code basically reads: Here follows the constructor of SimpleSprites, initialize m_numParticlesToDraw to the InitialParticleCount of Performance in SampleSettings.

 

 

what about the double double colon:

 

SampleSettings::Performance::InitialParticleCoun

Share this post


Link to post
Share on other sites
It separates the names in InitialParticleCount's fully qualified name:

namespace abc {
    namespace def {
        class xyz {
        public:
            static const int w;
        };
    }
}

void f() {
    int w = abc::def::xyz::w;
    // the w of class xyz in namespace def in namespace abc
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!