SOL9 Sample: Direct3D12MultipleLightedShapes

SOL9 2.0 Samples

1 Screenshot


2 Source code

/*
 * Direct3D12MultipleLightedShapes.cpp 
 * Copyright (c) 2015 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
 */


// 2016/10/10
// 2017/01/28 Updated to use ModuleFileName class and caught macro.

#define COMMONCONTROLS_V6
#define WIN10

#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/Direct3D12TransformLightConstantBufferView.h>
#include <sol/direct3d12/Direct3D12RootSignature.h>
#include <sol/direct3d12/Direct3D12GraphicsCommandList.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/D3D12TransformLight.h>

#include <sol/direct3d12/Direct3D12Synchronizer.h>

#include <sol/direct3d12/Direct3DX12Box.h>
#include <sol/direct3d12/Direct3DX12Cylinder.h>
#include <sol/direct3d12/Direct3DX12Sphere.h>
#include <sol/direct3d12/Direct3DX12Torus.h>

#include <sol/direct3d12/DirectXTransformLight.h>

#include "resource.h"

namespace SOL {
  
class MainView :public DirectX3D12MainView {
  
  /////////////////////////////////////////////////////////////////
  //Inner class ContantBufferRootSignatureForShapes
  class SimpleRootSignature : public Direct3D12RootSignature {
  protected:
  //Define your own serializeRootSignature method in the subclass derived from this class.
  //2016/12/15 Updated to take the parameteers numberOfConstantBufferView and numberOfSharderResourcerView.
  virtual void serializeRootSignature(
    ID3DBlob**                  blobSignature, 
    UINT                        numberOfConstantBufferView   =1,
    UINT                        numberOfSharderResourcerView =0,
    D3D12_DESCRIPTOR_RANGE_TYPE rangeType      = D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 
    D3D12_ROOT_PARAMETER_TYPE   parameterType  = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
    D3D12_ROOT_SIGNATURE_FLAGS  signatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT
    )  
  {
    D3D12_DESCRIPTOR_RANGE range[1];
    int i = 0;
      range[i].RangeType          = rangeType;;
      range[i].NumDescriptors     = numberOfConstantBufferView;
      range[i].BaseShaderRegister = i;
      range[i].RegisterSpace      = 0;
      range[i].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

    D3D12_ROOT_PARAMETER param[1];
    i = 0;
      param[i].ParameterType                       = parameterType; 
      param[i].ShaderVisibility                    = D3D12_SHADER_VISIBILITY_ALL;
      param[i].DescriptorTable.NumDescriptorRanges = 1;
      param[i].DescriptorTable.pDescriptorRanges   = &range[i];
    
    D3D12_ROOT_SIGNATURE_DESC desc;
    desc.NumParameters     = _countof(param);
    desc.pParameters       = param;
    desc.NumStaticSamplers = 0;
    desc.pStaticSamplers   = nullptr;
    desc.Flags             = signatureFlags;
    
    ID3DBlob* errors = NULL;
    HRESULT hr = D3D12SerializeRootSignature(&desc, 
                    D3D_ROOT_SIGNATURE_VERSION_1, blobSignature, &errors);
    if (errors) {
      const char* msg = (const char*)errors->GetBufferPointer();
      const char* title = "Error";
      if (strstr(msg, "warning")) {
        title = "Warning";
      }
      MessageBoxA(NULL,(const char*)msg, title, MB_OK);
      errors->Release();
      errors = NULL;
    }
    if (FAILED(hr)) {
      throw IException("Failed to D3D12SerializeRootSignature. HRESULT(0x%lx)", hr);      
    }
  }
  
  public:
    SimpleRootSignature(
      __in ID3D12Device* device)
    :Direct3D12RootSignature(device)
    {
    }
  };
      
  /////////////////////////////////////////////////////////////////
  //Inner class 
  class SimpleView :public DirectX3D12View {
  private:
    static const int                SHAPES = 2;  //Sphere and Torus only.
    
    SmartPtr<Direct3D12CommandAllocator>     commandAllocator;
    SmartPtr<Direct3D12RenderTargetView>     renderTargetView;
    SmartPtr<Direct3D12DepthStencilView>     depthStencilView;
    SmartPtr<SimpleRootSignature>            rootSignature;
    SmartPtr<Direct3D12CommonDescriptorHeap> commonDescriptorHeap;
    SmartPtr<Direct3D12GraphicsCommandList>  graphicsCommandList;
    SmartPtr<Direct3D12PipelineState>        pipelineState;
    SmartPtr<Direct3D12Synchronizer>         synchronizer;
    SmartPtr<Direct3DX12Shape>               shapes[SHAPES];
    SmartPtr<Direct3D12TransformLightConstantBufferView>   constantBufferView;
      
    UINT                           frameIndex;
    DirectXTransformLight          lightedConstantBuffer;
    float                          angle;
    StringT<TCHAR>                 directory;

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

      
      UINT count = 0;
      static const D3D12_INPUT_ELEMENT_DESC* inputElements = D3D12InputElements::getPosNormalDesc(count); 
          
      D3D12RasterizerDesc  rasterDesc(
        D3D12_FILL_MODE_SOLID, 
        D3D12_CULL_MODE_NONE, 
        true);

      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 setDirectXTransformLight()
    {
      int width = 0;
      int height = 0;
      getClientSize(width, height);
      try {        
        XMVECTOR eye = XMVectorSet(  0.0f,  2.0f, -8.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 );

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

        lightedConstantBuffer.view       = DirectXMatrix::lookAtLH(eye, at, up);
        lightedConstantBuffer.projection = DirectXMatrix::perspectiveFovLH( XM_PIDIV2*0.3f, width / (FLOAT)height, 0.01f, 100.0f );
        lightedConstantBuffer.lightDirection = XMFLOAT4( -0.8f, 0.8f, 0.3f, 1.0f );
        lightedConstantBuffer.lightColor     = XMFLOAT4(  1.0f, 0.2f, 0.0f, 1.0f );
        
         constantBufferView->update(lightedConstantBuffer);

      } 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()
    {
      graphicsCommandList->setOMRenderTargets(0, nullptr, FALSE, nullptr);
    
      renderTargetView = NULL;
      depthStencilView = NULL;
    }
   
    void createShapes(ID3D12Device* device)
    {
      try {
 
        int i = 0;
        //1 Create a sphere.
        {
          float fRadius = 0.3f;
          UINT  uSlices = 20;
          UINT  uStacks = 20;      
          shapes[i++] = new Direct3DX12Sphere(device,
                              fRadius, uSlices, uStacks);
        }

        //2 Create a torus.
        {
          float fInnerRadius = 0.2f;
          float fOuterRadius = 1.0f;
          UINT uSides  = 30;
          UINT uRings  = 30; 
          shapes[i  ] = new Direct3DX12Torus(device, 
                              fInnerRadius, fOuterRadius, uSides,
                                uRings);
        }
        
      } catch (Exception& ex) {
        caught(ex);
      }
    }
    
  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);

        rootSignature            = new SimpleRootSignature(*device);

        commonDescriptorHeap     = new Direct3D12CommonDescriptorHeap(*device, SHAPES);

        constantBufferView       = new Direct3D12TransformLightConstantBufferView(*device,
                                                  commonDescriptorHeap->getCPUHandle(CBV_HANDLE));
        synchronizer             = new Direct3D12Synchronizer(*device, *commandQueue);

        createViews(*device, *swapChain, width, height);
        
        //1 Create your own shape
        createShapes(*device);
        
        //2 Create a pipelineState from the cube.
        createPipelineState(*device);
        
        //3 Set world, view and projection to the constantBuffer.
        //setDirectXTransformLight();

      } 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 ||
        commonDescriptorHeap      == 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;
      }
      
      Direct3D12Device*       device       = getD3D12Device();
      DirectXGISwapChain3*    swapChain    = getSwapChain3();
      Direct3D12CommandQueue* commandQueue = getCommandQueue();

      try {
       
        commandAllocator->reset();

        graphicsCommandList->reset(*commandAllocator, nullptr);

        frameIndex = swapChain->getCurrentBackBufferIndex();

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

        barrier.startTransition();

        graphicsCommandList->resourceBarrier(1, barrier);

        graphicsCommandList->setGraphicsRootSignature(*rootSignature);
 
        graphicsCommandList->setDescriptorHeap(*commonDescriptorHeap);

        graphicsCommandList->setGraphicsRootDescriptorTable(CBV_HANDLE,
              commonDescriptorHeap->getGPUHandle(CBV_HANDLE));

        graphicsCommandList->setPipelineState(*pipelineState);
        
        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);

        graphicsCommandList->setOMRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);

        for (int i = 0; i<SHAPES; i++) {
          setDirectXTransformLight(); //Update the constantBufferView 
          shapes[i]->drawIndexedInstanced(graphicsCommandList);
        }
        
        barrier.endTransition();

        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);

    ar.set(XmNstyle, WS_BORDER|WS_CHILD|WS_VISIBLE);
    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)
{
  ModuleFileName module(argv[0]);
  const TCHAR* directory = module.getDirectory();
  const TCHAR* appClass =  module.getAppName(); 

  try {    
    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: 1 Feb 2017

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