SOL9 Sample: Direct3D12ScintillaStarSystem

SOL9 2.0 Samples

1 Screenshot


2 Source code

/*
 * Direct3D12ScintillaStarSystem.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/Direct3D12Debug.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/D3D12Transform.h>

#include <sol/direct3d12/D3D12GraphicsPipelineStateDesc.h>

#include <sol/direct3d12/Direct3D12Synchronizer.h>

#include <sol/direct3d12/Direct3DX12Sphere.h>
#include <sol/direct3d12/Direct3DX12Circle.h>

#include <sol/direct3d12/DirectXTransformLight.h>
#include <sol/direct3d12/DirectX3D12TimerThread.h>

#include "resource.h"

namespace SOL {
  
class MainView :public DirectX3D12MainView {
private:
  static const int NUMBER_OF_SPHERES = 5;
  static const int NUMBER_OF_PLANETS = 4;
  
  static const int NUMBER_OF_CONSTANT_BUFFER_VIEWS = NUMBER_OF_SPHERES;
  static const int NUMBER_OF_SHADER_RESOURCE_VIEWS = 1;
  
  //Inner class starts.
  class SimpleView :public DirectX3D12View {
  private:
    SmartPtr<Direct3D12CommandAllocator>     commandAllocator;
    SmartPtr<Direct3D12RenderTargetView>     renderTargetView;
    SmartPtr<Direct3D12DepthStencilView>     depthStencilView;
    SmartPtr<Direct3D12RootSignature>        rootSignature;
    SmartPtr<Direct3D12CommonDescriptorHeap>  commonDescriptorHeap;
    SmartPtr<Direct3D12TransformLightConstantBufferView>   sunConstantBufferView;
    SmartPtr<Direct3D12TransformLightConstantBufferView>   planetConstantBufferViews[NUMBER_OF_PLANETS];
    SmartPtr<Direct3D12GraphicsCommandList>  graphicsCommandList;
    SmartPtr<Direct3D12PipelineState>        pipelineState;
    
    SmartPtr<Direct3D12Synchronizer>         synchronizer;
    
    SmartPtr<Direct3DX12Sphere>              sun;
    SmartPtr<Direct3DX12Sphere>              planets[NUMBER_OF_PLANETS];
    SmartPtr<Direct3DX12Circle>              orbits [NUMBER_OF_PLANETS];

    UINT                              frameIndex;
    
    SmartPtr<DirectX3D12TimerThread>  timerThread;
    int                               renderingInterval;
    
    DirectXTransformLight             sunWorldViewProjection;
    
    DirectXTransformLight             planetWorldViewProjections[NUMBER_OF_PLANETS];
 
    float                             angles[NUMBER_OF_PLANETS];
    
    StringT<TCHAR>                    directory;

    static const int                  CIRCLE_ANGLE = 360;
    
  private:
    void createPipelineStates(ID3D12Device* device)
    {
      D3D12RasterizerDesc  solid( D3D12_FILL_MODE_SOLID,  D3D12_CULL_MODE_NONE, true);
      D3D12BlendDesc       blendDesc;
      UINT count = 0;
      const D3D12_INPUT_ELEMENT_DESC* inputElements = sun->getInputElementDesc(count);
        
      StringT<TCHAR> vsshaderFile = getShaderFilePath(directory, _T("VertexShader.cso"));
        
      StringT<TCHAR> psshaderFile = getShaderFilePath(directory, _T("PixelShader.cso"));
      //Create a pipelineState by using a new constructor(2017/01/10).
      pipelineState = new Direct3D12PipelineState(
              device,
              *rootSignature,
              inputElements,
              count,
              solid,
              blendDesc,
              vsshaderFile,
              psshaderFile);
    }
      
    XMFLOAT3 getPlanetOrbitPosition(int pindex, float angle)
    {
      if (pindex >= 0 && pindex <NUMBER_OF_PLANETS) {
        return orbits[pindex]->getOrbitPosition(angle);
      } else {
        throw IException("Invalid planet index.");
      }
    }

    //Set the constantBufferView to the sun of sphere[0].
    void setSunDirectXTransform()
    {
      int width  = 0;
      int height = 0;
      getClientSize(width, height);
      int index = 0;
      
      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);

        sunWorldViewProjection.world = DirectXMatrix::rotationY((float)0.0f);
        sunWorldViewProjection.view = DirectXMatrix::lookAtLH(eye, at, up);
        sunWorldViewProjection.projection = DirectXMatrix::perspectiveFovLH( XM_PIDIV2*0.3f, 
            width / (FLOAT)height, 0.01f, 100.0f );
        sunWorldViewProjection.lightDirection = XMFLOAT4( 0.0f, 1.0f, 0.0f, 1.0f );
        sunWorldViewProjection.lightColor = XMFLOAT4(1.0f, 0.2f, 0.0f, 1.0f);

        if (sunConstantBufferView) {
          sunConstantBufferView->update(sunWorldViewProjection);
        }
      } catch (Exception& ex) {
        caught(ex);      
      }
    }
    //Set a constantBufferView to each planet (index-th sphere). 
    void setPlanetDirectXTransform(int index, float angle)
    {
      int width  = 0;
      int height = 0;
      getClientSize(width, height);
      if (index >=0 && index < NUMBER_OF_PLANETS) {
        try {
          // Get a position on an orbit.
          XMFLOAT3 position = getPlanetOrbitPosition(index, angle);
          //Translate the position of the planet.      
          DirectXMatrix world = DirectXMatrix::scaling( 1.0f, 1.0f, 1.0f);
          DirectXMatrix m = DirectXMatrix::translation(position.x, position.y, position.z);
          world += m;
 
          planetWorldViewProjections[index].world = world;
    
          XMVECTOR eye = XMVectorSet(2.0f, 4.0f, -8.0f, 0.0f);

          XMVECTOR at = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
          XMVECTOR up = XMVectorSet(0.0f, 1.0f, 1.0f, 0.0f);

          planetWorldViewProjections[index].view = DirectXMatrix::lookAtLH(eye, at, up);
          planetWorldViewProjections[index].projection = DirectXMatrix::perspectiveFovLH( XM_PIDIV2*0.3f, 
            width / (FLOAT)height, 0.01f, 100.0f );
        
          planetWorldViewProjections[index].lightDirection = XMFLOAT4( 0.0f, -0.0f, 1.0f, 1.0f );
          XMFLOAT4 planetColors[NUMBER_OF_PLANETS] = {
            XMFLOAT4(0.0f, 1.0f, 1.0f, 1.0f),
            XMFLOAT4(1.0f, 1.0f, 0.0f, 1.0f),
            XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f),
            XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f)
          };
          planetWorldViewProjections[index].lightColor = planetColors[index];

          if (planetConstantBufferViews[index]) {
            planetConstantBufferViews[index]->update(planetWorldViewProjections[index]);
          }
        } catch (Exception& ex) {
         caught(ex);      
        }
      }
    }
 
  public:
    //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)
      graphicsCommandList->setOMRenderTargets(0, nullptr, FALSE, nullptr);
      renderTargetView = NULL;
      depthStencilView = NULL;
    }
    
    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);

        renderTargetView = new Direct3D12RenderTargetView(*device, *swapChain);

        depthStencilView = new Direct3D12DepthStencilView(*device, width, height);

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

        //1 Create rootSignature specified parameters:
        // NUMBER_OF_CONSTANT_BUFFER_VIEWS and NUMBER_OF_SHADER_RESOURCE_VIEWS
        rootSignature = new Direct3D12RootSignature(*device,
          NUMBER_OF_CONSTANT_BUFFER_VIEWS, NUMBER_OF_SHADER_RESOURCE_VIEWS);

        //2 Create commonDescriptorHeap of size of NUMBER_OF_SPHERES.
        commonDescriptorHeap = new Direct3D12CommonDescriptorHeap(*device, NUMBER_OF_SPHERES);

        //3 Create constantBufferViews for the spheres of NUMBER_OF_SPHERES.
        sunConstantBufferView = new Direct3D12TransformLightConstantBufferView(*device,
          commonDescriptorHeap->getCPUHandle(CBV_HANDLE));

        for (size_t i = 0; i < NUMBER_OF_PLANETS; i++) {
          planetConstantBufferViews[i] = new Direct3D12TransformLightConstantBufferView(*device,
            commonDescriptorHeap->getCPUHandle(CBV_HANDLE + 1 + i));
        }

        synchronizer = new Direct3D12Synchronizer(*device, *commandQueue);

        //4 Create a renderTargetView and depthStencilView
        createViews(*device, *swapChain, width, height);

        //5 Create orbits for 4 planets.
        int index = 0;
        orbits[index++] = new Direct3DX12Circle(*device, 0.0f, 0.0f, 0.0f, 1.9f);
        orbits[index++] = new Direct3DX12Circle(*device, 0.0f, 0.0f, 0.0f, 2.6f);
        orbits[index++] = new Direct3DX12Circle(*device, 0.0f, 0.0f, 0.0f, 3.4f);
        orbits[index] = new Direct3DX12Circle(*device, 0.0f, 0.0f, 0.0f, 3.9f);

        //6 Creat a shperes for sun.
        sun = new Direct3DX12Sphere(*device, 0.38f, 20, 20);

        //7 Create 4 spheres for planets.
        index = 0;
        planets[index++] = new Direct3DX12Sphere(*device, 0.10f, 20, 20);
        planets[index++] = new Direct3DX12Sphere(*device, 0.18f, 20, 20);
        planets[index++] = new Direct3DX12Sphere(*device, 0.18f, 20, 20);
        planets[index] = new Direct3DX12Sphere(*device, 0.12f, 20, 20);

        //8 Create a pipelineState from the sphere.
        createPipelineStates(*device);

        //9 Set world, view and projection to the constantBuffer.
        setSunDirectXTransform();
        for (size_t i = 0; i < NUMBER_OF_PLANETS; i++) {
         setPlanetDirectXTransform(i, angles[i]);
        }
        //10 Create a rendering TimerThread.
        timerThread = new DirectX3D12TimerThread(this, renderingInterval, true); // queuing
        timerThread -> start();

      } 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 ||
        graphicsCommandList       == nullptr ||
        pipelineState             == nullptr ||
        timerThread               == nullptr ||
        synchronizer              == nullptr ) {
        return false;
      }
      return true;
    }
    
    virtual void display()
    {
      int width  = 0;
      int height = 0;
      validateClientSize(width, height);
      if ( !ready() ) {
        return;
      }
      try {
        DirectXGISwapChain3*    swapChain = getSwapChain3();
        Direct3D12CommandQueue* commandQueue = getCommandQueue();

        static const float INCREMENT[NUMBER_OF_PLANETS] = { 2.0f, 1.5f, 1.0f, 0.5f };
        for (int i = 0; i < NUMBER_OF_PLANETS; i++) {
          if (angles[i] < CIRCLE_ANGLE - INCREMENT[i]) {
            angles[i] += INCREMENT[i];
          }
          else {
            angles[i] = INCREMENT[i];
          }
        }
        
        commandAllocator    -> reset();
        
        graphicsCommandList -> reset(*commandAllocator, *pipelineState);
        
        frameIndex = swapChain -> getCurrentBackBufferIndex();
        
        D3D12ResourceBarrier barrier(renderTargetView->getResource(frameIndex));
        
        barrier.startRendering();

        graphicsCommandList->resourceBarrier(1, barrier);

        
        graphicsCommandList->setDescriptorHeap(*commonDescriptorHeap);

        graphicsCommandList->setGraphicsRootSignature(*rootSignature);

        graphicsCommandList->setPipelineState(*pipelineState);
        

        graphicsCommandList -> setRSViewport(0, 0, width, height);

        graphicsCommandList -> setRSScissorRect(0, 0, 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);
        
        //Draw the sun.
        setSunDirectXTransform();        
        graphicsCommandList->setGraphicsRootDescriptorTable(CBV_HANDLE, 
            commonDescriptorHeap->getGPUHandle(CBV_HANDLE));
        sun -> drawIndexedInstanced(graphicsCommandList);

        //Draw the planets on the worldViewProjection.
        for (size_t i = 0; i<NUMBER_OF_PLANETS; i++) {
          setPlanetDirectXTransform(i, angles[i]);

          graphicsCommandList->setGraphicsRootDescriptorTable(CBV_HANDLE, 
              commonDescriptorHeap->getGPUHandle(CBV_HANDLE + 1 + i));
          planets[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);
      }
    }
    
  public:
    //Constructor
    SimpleView(DirectX3D12MainView* parent, const TCHAR* name, Args& args)
    :DirectX3D12View(parent, name, args),
    //angle (30),
    frameIndex(0),
    directory(_T("")),
    renderingInterval(100)
    {
      for (size_t i = 0; i < NUMBER_OF_PLANETS; i++) {
        angles[i] = 30.0f * i;
      }
      directory = (const TCHAR*)args.get(XmNapplicationDirectory);
      renderingInterval = (int)args.get(XmNrenderingInterval);

      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);
    int renderingInterval  = (int) args.get(XmNrenderingInterval);

    // 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(XmNrenderingInterval, renderingInterval); 

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


//////////////////////////////////////////////
//
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);
    args.set(XmNrenderingInterval, 30); //30ms

    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.