Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

Since MS announced that they are not give more support to XNA , for me was an opportunity to start to learn DirectX , so i wanted to learn DX11, i was following this tutorials

http://www.rastertek.com/tutdx11.html

i want to build a simple 2D engine while im learning with basic thing,like render an sprite based on a spritesheet, ,animate it, scale, rotation, flip image

I started creating some simple basic structure,

  • Engine Class, this hold the initialization of the Window basically
  • RenderManager class, this hold all the DX stuff, initialize it, create the swapchain, store the device , etc

So now my next step is create the Sprite class , i wanted to create an method called "Quad2D" inside my RenderManager, so i can use it on my render method in my sprite class

//This is not actual code, is just oh i want to approach this
class Sprite{

public void Render(RenderManager *rm){

    rm->Quad2D(Texture,Position,Width,Height);

}
}

i have some experience with OpenGL and Directx9 and with those, it was easy to approach this, i just needed to create an Array with the vertices, send to the VertexBuffer, bind the Texture, and done

but because now DX10 and DX11 not used fixed pipeline, and you need create this with more advanced stuff (Shaders)

i stopped in here http://www.rastertek.com/dx11tut11.html , i can see how to render the image and everything, but i was thinking, do i need to create an separate Class just to render a Quad? if so, is this going to compile the shader everytime is used?, well one solution maybe is just declare an static atribute for the ps and vs and it will shared the same compiled shader within the instances

so i would like to hear how do you manage your Sprite class?

if is it necessary, i can attach my source code, but it doesnt has too much, just open a window

Note: i want to know how to do it in DX11, please dont reply, (used DX9,OpenGL,DX10, etc..)

share|improve this question

1 Answer 1

up vote 1 down vote accepted

I based a good deal of my Engine from the Rastertek tutorials too. For the shaders, I don't see why you'd need to compile them for each Quad... My solution was to store the shader in a Graphics class, and pass the information into the render function of the shader.

This is my layout (Sorry for the length of this, I'll try to trim out lots.)

bool TextureShader::render(ID3D11DeviceContext* deviceContext, int indexCount, const     XMMATRIX& worldMatrix, const XMMATRIX& viewMatrix, 
                                               const XMMATRIX& projectionMatrix, VEngine::Graphics::DirectX11::Material* material)
{
    bool result;


    // Set the shader parameters that it will use for rendering.
    result = setShaderParameters(deviceContext, worldMatrix, viewMatrix, projectionMatrix, material);
    if(!result)     
            return false;   

    // Now render the prepared buffers with the shader.
    renderShader(deviceContext, indexCount);

    return true;
}

bool TextureShader::setShaderParameters(ID3D11DeviceContext* deviceContext, const      XMMATRIX& worldMatrix, 
                                       const XMMATRIX& viewMatrix, const XMMATRIX& projectionMatrix, ID3D11ShaderResourceView* texture)
{
    HRESULT result;
    D3D11_MAPPED_SUBRESOURCE mappedResource;
    MatrixBuffer* dataPtr;
    unsigned int bufferNumber;

    // Transpose the matrices to prepare them for the shader.
    XMMATRIX tWorldMatrix(XMMatrixTranspose(worldMatrix));
    XMMATRIX tViewMatrix(XMMatrixTranspose(viewMatrix));
    XMMATRIX tProjectionMatrix(XMMatrixTranspose(projectionMatrix));

    // Lock the constant buffer so it can be written to.
    result = deviceContext->Map(_matrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    if(FAILED(result))
    {
            return false;
    }

    // Get a pointer to the data in the constant buffer.
    dataPtr = (MatrixBuffer*)mappedResource.pData;

    // Copy the matrices into the constant buffer.
    dataPtr->world = tWorldMatrix;
    dataPtr->view = tViewMatrix;
    dataPtr->projection = tProjectionMatrix;

    // Unlock the constant buffer.
    deviceContext->Unmap(_matrixBuffer, 0);

    // Set the position of the constant buffer in the vertex shader.
    bufferNumber = 0;

    // Finanly set the constant buffer in the vertex shader with the updated values.
    deviceContext->VSSetConstantBuffers(bufferNumber, 1, &_matrixBuffer);

    deviceContext->PSSetShaderResources(0, 1, &texture);

    return true;
}

And, for the Graphics class which calls it.

bool DX11::render()
{
    XMMATRIX viewMatrix;    

    cleanRenderQueues();

    // Generate the view matrix based on the camera's position.
    _camera->render();

    // Get the world, view, and projection matrices from the camera and d3d objects.
    viewMatrix = _camera->getViewMatrix();

    XMMATRIX projectionMatrix = getProjectionMatrix();

    XMMATRIX orthoMatrix = getOrthoMatrix();
    bool result;

    disableZBuffer();
    enableAlphaBlending();
    for(unsigned int i(0); i < _renderQueue2d.size(); i++)
    {
            XMMATRIX worldMatrix = getWorldMatrix();

            _renderQueue2d[i]->render(_deviceContext);
            result = _textureShader->render(_deviceContext, _renderQueue2d[i]->getIndexCount(), worldMatrix, viewMatrix, orthoMatrix,
                    _renderQueue2d[i]->getTexture());
            if(!result)     
                    return false;
    }

//...More here for 3d

    return true;
}

As you mentioned, I've created a Sprite class, which contains a simple Quad, and a texture that I pass through to the shader.

Sprite class is essentially this (Update buffers is pretty much identical to the one in the Rastertek tutorials. Ignore the namespaces and the interface.

Header

/*--------------------
----INCLUDES
----------------------*/
#include <d3d11.h>
#include <xnamath.h>

/*--------------------
----MY INCLUDES
----------------------*/
#include "Texture.h"
#include "../IBitmap.h"

namespace VEngine
{
    namespace Graphics
    {
            namespace DirectX11
            {
                    class Bitmap : public IBitmap
                    {
                    private:
                            struct VertexType
                            {
                                    XMFLOAT3 position;
                                    XMFLOAT2 texture;
                            };

                    public:
                            Bitmap();
                            Bitmap(const Bitmap&);
                            ~Bitmap();

                            bool initialise(ID3D11Device*, int, int, const char*, int, int);
                            void shutdown();
                            bool render(ID3D11DeviceContext*);

                            int getIndexCount();
                            ID3D11ShaderResourceView* getTexture();

                            std::array<int, 2> getPosition();
                            std::array<float, 2> getRotation();
                            void setPosition(const int&, const int&);
                            void setRotation(const float&, const float&);
                            void setImageWidth(const int&);
                            int getImageWidth();
                            void setImageHeight(const int&);
                            int getImageHeight();

                            void setTextureFile(const char*);

                    private: //functions
                            bool initialiseBuffers(ID3D11Device*);
                            void shutdownBuffers();
                            bool updateBuffers(ID3D11DeviceContext*);
                            void renderBuffers(ID3D11DeviceContext*);

                            bool loadTexture(ID3D11Device*, const char*);
                            void releaseTexture();

                            bool createVertexBuffer(ID3D11Device* device, VertexType* vertices);
                            bool createIndexBuffer(ID3D11Device* device, unsigned long* indices);

                    private: // variables
                            ID3D11Device* _device;
                            ID3D11Buffer* _vertexBuffer;
                            ID3D11Buffer* _indexBuffer;
                            Texture* _texture;
                            int _vertexCount;
                            int _indexCount;

                            int _screenWidth;
                            int _screenHeight;
                            int _bitmapWidth;
                            int _bitmapHeight;

                            int _x;
                            int _y;
                            XMFLOAT2 _rotation;
                            int _previousPosX;
                            int _previousPosY;
                    };
            }
    }
}

Implementation

bool Bitmap::render(ID3D11DeviceContext* deviceContext)
{
    bool result;
    result = updateBuffers(deviceContext);
    if(!result)     
            return false;

    renderBuffers(deviceContext);

    return true;
}

void Bitmap::renderBuffers(ID3D11DeviceContext* deviceContext)
{
    unsigned int stride;
    unsigned int offset;

    stride = sizeof(VertexType); 
    offset = 0;
    deviceContext->IASetVertexBuffers(0, 1, &_vertexBuffer, &stride, &offset);

    deviceContext->IASetIndexBuffer(_indexBuffer, DXGI_FORMAT_R32_UINT, 0);

    deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    return;
 }

I'd recommend going through the Rastertek in order. There are a few issues I have with the tutorial, and I've drifted away from quite a bit of it's architecture in my newer builds, but they're incredibly useful.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.