4.14 How to render multiple textured rectangles in Direct3D12?

 We have updated the following two classes:

1. Direct3DX12TexturedRectange to create a Direct3DX12Rectangle specified by D3D12Rectangle structure .

2. Direct3D12RootSignature to create an ID3D12RootSignature with the specified number of descriptors of ConstantantBufferViews and ShaderResourceViews .

Direct3D12Object
Direct3DX12Shape
Direct3DX12TexturedRectangle
Direct3D12DeviceChild
Direct3D12RootSignature
 
The following Direct3D12MultiPNGTexturedRectangles is a simple sample program to render four PNG textured rectangles which can be rotated by the left and right keys.




/*
 * Direct3D12MultiPNGTexturedRectangles.cpp 
 * Copyright (c) 2016 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
 */


// 2016/12/15
// This is a simple example to render multiple textured rectangles 
//with multiple shaderResourceViews.

#define COMMONCONTROLS_V6
#define WIN10

#include <sol/COMInitializer.h>

#include <sol/WCharModuleFileName.h>

#include <sol/direct3d12/DirectX3D12MainView.h>
#include <sol/direct3d12/DirectX3D12View.h>
#include <sol/direct3d12/DirectXMatrix.h>
#include <sol/direct3d12/Direct3D12CommandAllocator.h>
#include <sol/direct3d12/Direct3D12RenderTargetView.h>
#include <sol/direct3d12/Direct3D12DepthStencilView.h>
#include <sol/direct3d12/Direct3D12CommonDescriptorHeap.h>

#include <sol/direct3d12/Direct3D12TransformConstantBufferView.h>

#include <sol/direct3d12/Direct3D12TextureRootSignature.h>
#include <sol/direct3d12/Direct3D12GraphicsCommandList.h>
#include <sol/direct3d12/Direct3D12Fence.h>
#include <sol/direct3d12/Direct3D12PipelineState.h>

#include <sol/direct3d12/D3D12RasterizerDesc.h>
#include <sol/direct3d12/D3D12BlendDesc.h>
#include <sol/direct3d12/D3D12GraphicsPipelineStateDesc.h>
#include <sol/direct3d12/D3D12ResourceBarrier.h>
#include <sol/direct3d12/D3D12Transform.h>

#include <sol/direct3d12/Direct3D12GraphicsCommandList.h>

#include <sol/direct3d12/Direct3D12Synchronizer.h>

#include <sol/direct3d12/Direct3D12Texture2D.h>
#include <sol/direct3d12/Direct3DX12TexturedRectangle.h>

#include <sol/direct3d12/Direct3D12ShaderResourceView.h>
#include <sol/direct3d12/Direct3D12Sampler.h>

#include <sol/direct3d12/Direct3DX12ColoredRectangle.h>
#include <sol/direct3d12/DirectXTransform.h>
#include <sol/direct3d12/Direct3D12Subresources.h>

#include <sol/wic/WICBitmapFileReader.h>

#include <sol/direct3d12/D3D12SubresourceData.h>
#include <sol/direct3d12/D3D12Rectangle.h>

#include "resource.h"

namespace SOL {
  
class MainView :public DirectX3D12MainView {
private:
  static const UINT  NUMBER_OF_CONSTANT_BUFFER_VIEW = 1;
  static const UINT  NUMBER_OF_SHADER_RESOURCE_VIEW = 4; //The number of rectangles;

  //Inner class starts.
  class SimpleView :public DirectX3D12View {
  private:
    SmartPtr<Direct3D12CommandAllocator>     commandAllocator;
    SmartPtr<Direct3D12RenderTargetView>     renderTargetView;
    SmartPtr<Direct3D12DepthStencilView>     depthStencilView;
    SmartPtr<Direct3D12RootSignature>        rootSignature;
    SmartPtr<Direct3D12CommonDescriptorHeap>   commonDescriptorHeap;
    SmartPtr<Direct3D12TransformConstantBufferView>   constantBufferView;
    SmartPtr<Direct3D12ShaderResourceView>   shaderResourceView[NUMBER_OF_SHADER_RESOURCE_VIEW];
    SmartPtr<Direct3D12GraphicsCommandList>  graphicsCommandList;
    SmartPtr<Direct3D12PipelineState>        pipelineState;
    SmartPtr<Direct3D12Synchronizer>         synchronizer;
    SmartPtr<Direct3DX12TexturedRectangle>   texturedRectangle[NUMBER_OF_SHADER_RESOURCE_VIEW];
    SmartPtr<Direct3D12Subresources>         subresources[NUMBER_OF_SHADER_RESOURCE_VIEW];
    SmartPtr<Direct3D12Texture2D>            texture2D[NUMBER_OF_SHADER_RESOURCE_VIEW];
    UINT                            frameIndex;
        
    DirectXTransform                worldViewProjection;
    float                           angle;
    StringT<TCHAR>                  directory;

private:
    virtual void createPipelineState(ID3D12Device* device)
    {
      //Create a graphicPipelineStateDes.
      D3D12GraphicsPipelineStateDesc graphicsPipelineStateDesc(*rootSignature);

      UINT count = 0;
      const D3D12_INPUT_ELEMENT_DESC* inputElements = texturedRectangle[0]->getInputElementDesc(count);
      
      D3D12RasterizerDesc  rasterDesc(
        D3D12_FILL_MODE_SOLID, 
        D3D12_CULL_MODE_NONE, 
        false);
      
      D3D12BlendDesc       blendDesc;
            
      graphicsPipelineStateDesc.setInputLayput(inputElements, count);
      
      graphicsPipelineStateDesc.setRasterizerState(rasterDesc);
      graphicsPipelineStateDesc.setBlendState(blendDesc);
      
      StringT<TCHAR> vsshaderFile = getShaderFilePath(directory, _T("VertexShader.cso"));
      StringT<TCHAR> psshaderFile = getShaderFilePath(directory, _T("PixelShader.cso"));

      graphicsPipelineStateDesc.setVertexShader(vsshaderFile);
      graphicsPipelineStateDesc.setPixelShader(psshaderFile);

      pipelineState = new Direct3D12PipelineState(device, graphicsPipelineStateDesc);
    }
    
    void setDirectXTransform()
    {
      int width = 0;
      int height = 0;
      getClientSize(width, height);

      try {        
        XMVECTOR eye = XMVectorSet(  0.0f,  0.0f, -4.0f,  0.0f );
        XMVECTOR at  = XMVectorSet(  0.0f,  0.0f,  0.0f,  0.0f );
        XMVECTOR up  = XMVectorSet(  0.0f,  1.0f,  0.0f,  0.0f );

        worldViewProjection.world      = DirectXMatrix::rotationY( angle );
        worldViewProjection.view       = DirectXMatrix::lookAtLH(eye, at, up);
        worldViewProjection.projection = DirectXMatrix::perspectiveFovLH( XM_PIDIV2*0.4f, width / (FLOAT)height, 0.01f, 100.0f );
       
        if (constantBufferView != nullptr) {
          constantBufferView->update(worldViewProjection);
        }
      } catch (Exception& ex) {
        caught(ex);      
      }
    }
    
    //Create a renderTargetView and a depthStencilView.
    void createViews(ID3D12Device* device, IDXGISwapChain3* swapChain,
                  int width, int height)
    {
      renderTargetView = new Direct3D12RenderTargetView(device, swapChain);
      depthStencilView = new Direct3D12DepthStencilView(device,  width, height);
    }
    
    //Delete a renderTargetView and a depthStencilView.
    void deleteViews()
    {
      if (graphicsCommandList == nullptr) {
        throw IException("graphicsCommandList is NULL.")
      }
      graphicsCommandList->setOMRenderTargets(0, nullptr, FALSE, nullptr);
    
      renderTargetView = NULL;
      depthStencilView = NULL;
    }
    
    void readImageFile(int width, int height, D3D12SubresourceData& subresource, 
                      const wchar_t* filename)
    {
      WCharModuleFileName moduleFileName;
      const wchar_t* dir = moduleFileName.getDir();
      wchar_t path[MAX_PATH];
      swprintf_s(path, CountOf(path), L"%s\\..\\image\\%s", dir, filename);

      WICImagingFactory factory;
      WICBitmapFileReader reader(factory, (const wchar_t*)path);
      reader.read(width, height, subresource);
    }
    
  public:
    
    virtual void initialize()
    {
      int width  = 0;
      int height = 0;
      validateClientSize(width, height);
      Direct3D12Device*    device    = getD3D12Device();
      DirectXGISwapChain3* swapChain = getSwapChain3();
      Direct3D12CommandQueue* commandQueue = getCommandQueue();
      
      try {
        commandAllocator         = new Direct3D12CommandAllocator(*device);

        graphicsCommandList      = new Direct3D12GraphicsCommandList(*device, *commandAllocator);

        //Create a rootSignature specified by the arguments 
        // NUMBER_OF_CONSTANT_BUFFER_VIEW and NUMBER_OF_SHADER_RESOURCE_VIEW.
        rootSignature            = new Direct3D12RootSignature(*device, 
                                                      NUMBER_OF_CONSTANT_BUFFER_VIEW,
                                                      NUMBER_OF_SHADER_RESOURCE_VIEW);
        
        synchronizer             = new Direct3D12Synchronizer(*device, *commandQueue);

        createViews(*device, *swapChain, width, height);
        
        //Create a commonDescriptorHeap of the size of 
        // NUMBER_OF_CONSTANT_BUFFER_VIEW + NUMBER_OF_SHADER_RESOURCE_VIEW.
        commonDescriptorHeap     = new Direct3D12CommonDescriptorHeap(*device, 
                NUMBER_OF_CONSTANT_BUFFER_VIEW + NUMBER_OF_SHADER_RESOURCE_VIEW);
 
        constantBufferView       = new Direct3D12TransformConstantBufferView(*device, 
                                    commonDescriptorHeap->getCPUHandle(CBV_HANDLE));
        
        const wchar_t* filenames[NUMBER_OF_SHADER_RESOURCE_VIEW] = {
                L"flower1.png", 
                L"flower2.png",
                L"flower3.png", 
                L"flower4.png",
        };
        const D3D12Rectangle rectangles[NUMBER_OF_SHADER_RESOURCE_VIEW] = {
          {-0.8f,  0.7f, -0.8f, 0.6f, 0.4f},
          { 0.8f,  0.7f, -0.8f, 0.6f, 0.4f},
          { 0.8f, -0.7f,  0.8f, 0.6f, 0.4f},
          {-0.8f, -0.7f,  0.8f, 0.6f, 0.4f},
        };
        
        for (size_t i = 0; i < NUMBER_OF_SHADER_RESOURCE_VIEW; i++) {
          texturedRectangle[i]     = new Direct3DX12TexturedRectangle(*device, rectangles[i]); 
        
          D3D12SubresourceData imageResource;
        
          readImageFile((UINT&)width, (UINT&)height, imageResource, filenames[i]);
        
          texture2D[i]            = new Direct3D12Texture2D(*device, width, height);
        
          subresources[i]         = new Direct3D12Subresources(*device, *texture2D[i]);
        
          subresources[i] -> update(*graphicsCommandList,
                  *commandAllocator,
                  *commandQueue,
                  imageResource,
                  synchronizer);
        
          shaderResourceView[i]  = new Direct3D12ShaderResourceView(*device, 
                                      commonDescriptorHeap->getCPUHandle(SRV_HANDLE + i),
                                      *texture2D[i]);
        }
        
        createPipelineState(*device);
        
        setDirectXTransform();

      } catch (Exception& ex) {
        caught(ex);
      }
    }

    bool ready()
    {
      Direct3D12Device*    device          = getD3D12Device();
      DirectXGISwapChain3* swapChain       = getSwapChain3();
      Direct3D12CommandQueue* commandQueue = getCommandQueue();
      
      if (
        device                    == nullptr ||
        commandQueue              == nullptr ||
        swapChain                 == nullptr ||
        
        commandAllocator          == nullptr ||
        renderTargetView          == nullptr ||
        depthStencilView          == nullptr ||

        rootSignature             == nullptr ||

        constantBufferView        == nullptr ||

        graphicsCommandList       == nullptr ||
        pipelineState             == nullptr ||
        synchronizer              == nullptr ) {

        return false;
      }
      return true;
    }
    
    virtual void display()
    {
      int width  = 0;
      int height = 0;
      validateClientSize(width, height);
      if ( !ready() ) {
        return;
      }

      try {
        Direct3D12Device*       device       = getD3D12Device();
        DirectXGISwapChain3*    swapChain    = getSwapChain3();
        Direct3D12CommandQueue* commandQueue = getCommandQueue();

        worldViewProjection.world = DirectXMatrix::rotationY( angle );

        constantBufferView->update(worldViewProjection);

        commandAllocator    -> reset();
        
        graphicsCommandList->reset(*commandAllocator, nullptr);

        frameIndex = swapChain -> getCurrentBackBufferIndex();

        D3D12ResourceBarrier barrier(renderTargetView->getResource(frameIndex));

        barrier.startRendering();

        graphicsCommandList->resourceBarrier(1, barrier);
                 
        graphicsCommandList->setDescriptorHeap(*commonDescriptorHeap);

        graphicsCommandList->setGraphicsRootSignature(*rootSignature);

        graphicsCommandList->setPipelineState(*pipelineState);
        
        graphicsCommandList->setGraphicsRootDescriptorTable(CBV_HANDLE, 
                  commonDescriptorHeap->getGPUHandle(CBV_HANDLE));  //ConstantBufferView
        
        graphicsCommandList -> setRSViewport(width, height);

        graphicsCommandList -> setRSScissorRect(width, height);

        D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = renderTargetView->getHandle(frameIndex);
                
        graphicsCommandList->clearRenderTargetView(rtvHandle, XMColor(0.0f, 0.0f, 0.0f, 1.0f));

        D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = *depthStencilView;
        
        graphicsCommandList->clearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH);
        
        graphicsCommandList->setOMRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
        
        for (size_t i = 0; i<NUMBER_OF_SHADER_RESOURCE_VIEW; i++) {
          graphicsCommandList->setGraphicsRootDescriptorTable(SRV_HANDLE,
                  commonDescriptorHeap->getGPUHandle(SRV_HANDLE + i)); 
          texturedRectangle[i] -> drawIndexedInstanced(graphicsCommandList);
        }
        
        barrier.endRendering();
        
        graphicsCommandList->resourceBarrier(1, barrier);

        graphicsCommandList->close();

        commandQueue->executeCommandList(*graphicsCommandList);

        swapChain->present(1, 0);
        
        synchronizer->waitForCompletion();

      } catch (Exception& ex) {
        caught(ex);
      }
    }
    
    virtual void resize(int width, int height)
    {
      Direct3D12Device*   device = getD3D12Device();
      DirectXGISwapChain3* swapChain = getSwapChain3();
      if (device           == NULL || 
         swapChain        == NULL) { 
        return ;
      }
      
      try {
        deleteViews();
        
        swapChain->resizeBuffers(width, height);

        createViews(*device, *swapChain, width, height);
        
      } catch (Exception& ex) {
        caught(ex);
      }
    }
    
    void render()
    {
      angle += 0.02f;
      display();
    }
      
    void incrementAngle()
    {
      angle += 0.1f;
      display();
    }
    
    void decrementAngle()
    {
      angle -= 0.1f;
      display();
    }
    
  public:
    //Constructor
    SimpleView(DirectX3D12MainView* parent, const TCHAR* name, Args& args)
    :DirectX3D12View(parent, name, args),
    angle (0.6f),
    frameIndex(0),
    directory(_T(""))
    {
      directory = (const TCHAR*)args.get(XmNapplicationDirectory);

      postResizeRequest();
    }
    
    ~SimpleView()
    {
    }
  };
  // Inner class ends.
  
private:
  SmartPtr<SimpleView> view;

public:
  /**
   * Constructor
   */
  MainView(Application& applet, const TCHAR* name, Args& args)
  :DirectX3D12MainView(applet, name,
                 args.set(XmNstyle, (ulong)WS_CLIPCHILDREN|WS_CLIPSIBLINGS) ),
  view(NULL)
  {
    const TCHAR* directory = (const TCHAR*)args.get(XmNapplicationDirectory);

    // 1 Restore the replacement of MainView 
    restorePlacement();

    // 2 Create a view of SimpleView.
    Args ar;
    int width  = 0;
    int height = 0;
    getClientSize(width, height);

    ar.set(XmNwidth, width);
    ar.set(XmNheight,height);
    ar.set(XmNapplicationDirectory, (const TCHAR*)directory);
    view = new SimpleView(this, _T(""), ar);

    // 3 Post a resize request to this MainView.
    postResizeRequest();
  }

public:
  ~MainView()
  {
  }

  void resize(int width, int height)
  {
    if (view != nullptr) {
      view -> reshape(0, 0, width, height);      
    }
  }  
  virtual void keyDown(Event& event)
  {
    WPARAM wparam = event.getWParam();
    switch(wparam) {
    case VK_LEFT:
      view -> decrementAngle();
      break;
        
    case VK_RIGHT:
      view -> incrementAngle();
      break;
    }  
  }
};
}


//////////////////////////////////////////////
//
void  Main(int argc, TCHAR** argv)
{
  TCHAR directory[MAX_PATH];
  appDirectory(argv[0], directory, CountOf(directory));

  const TCHAR* appClass = appName(argv[0]); 
  try {
    //For DXGI components.
    COMInitializer initializer( COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

    Application applet(appClass, argc, argv);

    Args args;
    args.set(XmNwidth,  480);
    args.set(XmNheight, 480);
    args.set(XmNapplicationDirectory, directory);

    MainView mainView(applet, appClass, args);
    mainView.realize();

    applet.run();
  } catch (Exception& ex) {
    caught(ex);
  }
}


Last modified: 14 Dec 2016

Copyright (c) 2016 Antillia.com ALL RIGHTS RESERVED.