OpenSubdiv/examples/common/d3d11_hud.cpp
2013-01-31 15:29:45 -08:00

352 lines
14 KiB
C++

//
// Copyright (C) Pixar. All rights reserved.
//
// This license governs use of the accompanying software. If you
// use the software, you accept this license. If you do not accept
// the license, do not use the software.
//
// 1. Definitions
// The terms "reproduce," "reproduction," "derivative works," and
// "distribution" have the same meaning here as under U.S.
// copyright law. A "contribution" is the original software, or
// any additions or changes to the software.
// A "contributor" is any person or entity that distributes its
// contribution under this license.
// "Licensed patents" are a contributor's patent claims that read
// directly on its contribution.
//
// 2. Grant of Rights
// (A) Copyright Grant- Subject to the terms of this license,
// including the license conditions and limitations in section 3,
// each contributor grants you a non-exclusive, worldwide,
// royalty-free copyright license to reproduce its contribution,
// prepare derivative works of its contribution, and distribute
// its contribution or any derivative works that you create.
// (B) Patent Grant- Subject to the terms of this license,
// including the license conditions and limitations in section 3,
// each contributor grants you a non-exclusive, worldwide,
// royalty-free license under its licensed patents to make, have
// made, use, sell, offer for sale, import, and/or otherwise
// dispose of its contribution in the software or derivative works
// of the contribution in the software.
//
// 3. Conditions and Limitations
// (A) No Trademark License- This license does not grant you
// rights to use any contributor's name, logo, or trademarks.
// (B) If you bring a patent claim against any contributor over
// patents that you claim are infringed by the software, your
// patent license from such contributor to the software ends
// automatically.
// (C) If you distribute any portion of the software, you must
// retain all copyright, patent, trademark, and attribution
// notices that are present in the software.
// (D) If you distribute any portion of the software in source
// code form, you may do so only under this license by including a
// complete copy of this license with your distribution. If you
// distribute any portion of the software in compiled or object
// code form, you may only do so under a license that complies
// with this license.
// (E) The software is licensed "as-is." You bear the risk of
// using it. The contributors give no express warranties,
// guarantees or conditions. You may have additional consumer
// rights under your local laws which this license cannot change.
// To the extent permitted under your local laws, the contributors
// exclude the implied warranties of merchantability, fitness for
// a particular purpose and non-infringement.
//
#include <D3D11.h>
#include <string.h>
#include <stdio.h>
#include <cassert>
#include "d3d11_hud.h"
#include "d3d11_compile.h"
#include "font_image.h"
#include "../common/simple_math.h"
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
static const char *s_VS =
"cbuffer cbPerFrame : register( b0 )\n"
"{\n"
" matrix g_mViewProjection;\n"
"};\n"
"struct vertexIn { float2 pos : POSITION0; float3 color : COLOR0; float2 uv : TEXCOORD0; };\n"
"struct vertexOut { float4 pos : SV_POSITION; float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
"vertexOut vs_main(vertexIn IN) {\n"
" vertexOut vout;\n"
" vout.pos = mul(float4(IN.pos.x, IN.pos.y, 0, 1), g_mViewProjection);\n"
" vout.color = float4(IN.color, 1);\n"
" vout.uv = IN.uv;\n"
" return vout;\n"
"}";
static const char *s_PS =
"struct pixelIn { float4 pos : SV_POSITION; float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
"Texture2D tx : register(t0); \n"
"SamplerState sm : register(s0); \n"
"float4 ps_main(pixelIn IN) : SV_Target {\n"
" float4 c = tx.Sample(sm, IN.uv);\n"
" if( c.a == 0.0 ) \n"
" discard;\n"
" return IN.color * c;\n"
"}";
struct CB_HUD_PROJECTION
{
float mViewProjection[16];
};
D3D11hud::D3D11hud(ID3D11DeviceContext *deviceContext)
: _deviceContext(deviceContext),
_vbo(0), _staticVbo(0), _fontTexture(0), _inputLayout(0),
_shaderResourceView(0), _samplerState(0), _vertexShader(0),
_pixelShader(0), _rasterizerState(0)
{
}
D3D11hud::~D3D11hud()
{
SAFE_RELEASE(_vbo);
SAFE_RELEASE(_staticVbo);
SAFE_RELEASE(_fontTexture);
SAFE_RELEASE(_inputLayout);
SAFE_RELEASE(_shaderResourceView);
SAFE_RELEASE(_samplerState);
SAFE_RELEASE(_vertexShader);
SAFE_RELEASE(_pixelShader);
SAFE_RELEASE(_rasterizerState);
}
void
D3D11hud::Init(int width, int height)
{
Hud::Init(width, height);
ID3D11Device *device = NULL;
_deviceContext->GetDevice(&device);
// define font texture
D3D11_TEXTURE2D_DESC texDesc;
texDesc.Width = FONT_TEXTURE_WIDTH;
texDesc.Height = FONT_TEXTURE_HEIGHT;
texDesc.MipLevels = 1;
texDesc.ArraySize = 1;
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D11_USAGE_DEFAULT;
texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
texDesc.CPUAccessFlags = 0;
texDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA subData;
subData.pSysMem = font_image;
subData.SysMemPitch = FONT_TEXTURE_WIDTH*4;
subData.SysMemSlicePitch = FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT*4;
HRESULT hr = device->CreateTexture2D(&texDesc, &subData, &_fontTexture);
assert(_fontTexture);
// shader resource view
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = texDesc.Format;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = texDesc.MipLevels;
device->CreateShaderResourceView(_fontTexture, &srvDesc, &_shaderResourceView);
assert(_shaderResourceView);
D3D11_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(samplerDesc));
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU = samplerDesc.AddressV = samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
device->CreateSamplerState(&samplerDesc, &_samplerState);
assert(_samplerState);
ID3DBlob* pVSBlob;
ID3DBlob* pPSBlob;
pVSBlob = d3d11CompileShader(s_VS, "vs_main", "vs_4_0");
pPSBlob = d3d11CompileShader(s_PS, "ps_main", "ps_4_0");
assert(pVSBlob);
assert(pPSBlob);
D3D11_INPUT_ELEMENT_DESC inputElementDesc[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, sizeof(float)*2, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, sizeof(float)*5, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
device->CreateInputLayout(inputElementDesc, ARRAYSIZE(inputElementDesc),
pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(),
&_inputLayout);
assert(_inputLayout);
device->CreateVertexShader(pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(),
NULL, &_vertexShader);
assert(_vertexShader);
device->CreatePixelShader(pPSBlob->GetBufferPointer(),
pPSBlob->GetBufferSize(),
NULL, &_pixelShader);
assert(_pixelShader);
D3D11_RASTERIZER_DESC rasDesc;
rasDesc.FillMode = D3D11_FILL_SOLID;
rasDesc.CullMode = D3D11_CULL_NONE;
rasDesc.FrontCounterClockwise = FALSE;
rasDesc.DepthBias = 0;
rasDesc.DepthBiasClamp = 0;
rasDesc.SlopeScaledDepthBias = 0.0f;
rasDesc.DepthClipEnable = FALSE;
rasDesc.ScissorEnable = FALSE;
rasDesc.MultisampleEnable = FALSE;
rasDesc.AntialiasedLineEnable = FALSE;
device->CreateRasterizerState(&rasDesc, &_rasterizerState);
assert(_rasterizerState);
// constant buffer
D3D11_BUFFER_DESC cbDesc;
cbDesc.Usage = D3D11_USAGE_DYNAMIC;
cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
cbDesc.MiscFlags = 0;
cbDesc.ByteWidth = sizeof(CB_HUD_PROJECTION);
device->CreateBuffer(&cbDesc, NULL, &_constantBuffer);
assert(_constantBuffer);
}
void
D3D11hud::Rebuild(int width, int height)
{
Hud::Rebuild(width, height);
// XXX: move this code to Hud
std::vector<float> vboSource;
// add UI elements
for (std::vector<RadioButton>::const_iterator it = getRadioButtons().begin();
it != getRadioButtons().end(); ++it) {
int x = it->x > 0 ? it->x : GetWidth() + it->x;
int y = it->y > 0 ? it->y : GetHeight() + it->y;
if (it->checked) {
x = drawChar(vboSource, x, y, 1, 1, 1, FONT_RADIO_BUTTON_ON);
drawString(vboSource, x, y, 1, 1, 0, it->label.c_str());
} else {
x = drawChar(vboSource, x, y, 1, 1, 1, ' ');
drawString(vboSource, x, y, .5f, .5f, .5f, it->label.c_str());
}
}
for (std::vector<CheckBox>::const_iterator it = getCheckBoxes().begin();
it != getCheckBoxes().end(); ++it) {
int x = it->x > 0 ? it->x : GetWidth() + it->x;
int y = it->y > 0 ? it->y : GetHeight() + it->y;
if( it->checked) {
x = drawChar(vboSource, x, y, 1, 1, 1, FONT_CHECK_BOX_ON);
drawString(vboSource, x, y, 1, 1, 0, it->label.c_str());
} else {
x = drawChar(vboSource, x, y, 1, 1, 1, FONT_CHECK_BOX_OFF);
drawString(vboSource, x, y, .5f, .5f, .5f, it->label.c_str());
}
}
drawString(vboSource, GetWidth()-80, GetHeight()-48, .5, .5, .5, "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f");
drawString(vboSource, GetWidth()-80, GetHeight()-32, .5, .5, .5, "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f");
// --------------------------------
SAFE_RELEASE(_staticVbo);
if (vboSource.size()) {
D3D11_BUFFER_DESC bufferDesc;
bufferDesc.ByteWidth = (int)vboSource.size() * sizeof(float);
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 4*sizeof(float);
D3D11_SUBRESOURCE_DATA subData;
subData.pSysMem = &vboSource[0];
subData.SysMemPitch = 0;
subData.SysMemSlicePitch = 0;
ID3D11Device *device = NULL;
_deviceContext->GetDevice(&device);
HRESULT hr = device->CreateBuffer(&bufferDesc, &subData, &_staticVbo);
assert(_staticVbo);
_staticVboCount = (int)vboSource.size() / 7;
}
}
bool
D3D11hud::Flush()
{
if (!Hud::Flush())
return false;
// update dynamic text
D3D11_BUFFER_DESC bufferDesc;
bufferDesc.ByteWidth = (int)getVboSource().size() * sizeof(float);
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 4*sizeof(float);
D3D11_SUBRESOURCE_DATA subData;
subData.pSysMem = &getVboSource()[0];
subData.SysMemPitch = 0;
subData.SysMemSlicePitch = 0;
SAFE_RELEASE(_vbo);
ID3D11Device *device = NULL;
_deviceContext->GetDevice(&device);
HRESULT hr = device->CreateBuffer(&bufferDesc, &subData, &_vbo);
assert(_vbo);
int numVertices = (int)getVboSource().size()/7; /* (x, y, r, g, b, u, v) = 7*/
// reserved space of the vector remains for the next frame.
getVboSource().clear();
D3D11_MAPPED_SUBRESOURCE MappedResource;
_deviceContext->Map(_constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource);
CB_HUD_PROJECTION * pData = (CB_HUD_PROJECTION *)MappedResource.pData;
ortho(pData->mViewProjection, 0, 0, (float)GetWidth(), (float)GetHeight());
transpose(pData->mViewProjection);
_deviceContext->Unmap( _constantBuffer, 0 );
// setup graphics pipeline
_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
_deviceContext->IASetInputLayout(_inputLayout);
_deviceContext->VSSetShader(_vertexShader, NULL, 0);
_deviceContext->HSSetShader(NULL, NULL, 0);
_deviceContext->DSSetShader(NULL, NULL, 0);
_deviceContext->GSSetShader(NULL, NULL, 0);
_deviceContext->PSSetShader(_pixelShader, NULL, 0);
_deviceContext->PSSetShaderResources(0, 1, &_shaderResourceView);
_deviceContext->PSSetSamplers(0, 1, &_samplerState);
_deviceContext->RSSetState(_rasterizerState);
_deviceContext->VSSetConstantBuffers(0, 1, &_constantBuffer);
UINT strides = 7*sizeof(float);
UINT offsets = 0;
_deviceContext->IASetVertexBuffers(0, 1, &_vbo, &strides, &offsets);
_deviceContext->Draw(numVertices, 0);
_deviceContext->IASetVertexBuffers(0, 1, &_staticVbo, &strides, &offsets);
_deviceContext->Draw(_staticVboCount, 0);
return true;
}