1 //
2 //   Copyright 2015 Pixar
3 //
4 //   Licensed under the Apache License, Version 2.0 (the "Apache License")
5 //   with the following modification; you may not use this file except in
6 //   compliance with the Apache License and the following modification to it:
7 //   Section 6. Trademarks. is deleted and replaced with:
8 //
9 //   6. Trademarks. This License does not grant permission to use the trade
10 //      names, trademarks, service marks, or product names of the Licensor
11 //      and its affiliates, except as required to comply with Section 4(c) of
12 //      the License and to reproduce the content of the NOTICE file.
13 //
14 //   You may obtain a copy of the Apache License at
15 //
16 //       http://www.apache.org/licenses/LICENSE-2.0
17 //
18 //   Unless required by applicable law or agreed to in writing, software
19 //   distributed under the Apache License with the above modification is
20 //   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 //   KIND, either express or implied. See the Apache License for the specific
22 //   language governing permissions and limitations under the Apache License.
23 //
24 
25 #include "d3d11ControlMeshDisplay.h"
26 #include "../common/d3d11Utils.h"
27 
28 #include <vector>
29 
30 #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
31 
32 static const char *s_VS =
33 "cbuffer cbPerFrame : register( b0 ) { matrix g_mViewProjection; };        \n"
34 "struct vertexIn { float3 pos : POSITION0; float sharpness : COLOR0; };    \n"
35 "struct vertexOut { float4 pos : SV_POSITION; float sharpness : COLOR0; }; \n"
36 "vertexOut vs_main(vertexIn IN) {                                          \n"
37 "  vertexOut vout;                                                         \n"
38 "  vout.pos = mul(g_mViewProjection, float4(IN.pos, 1));                   \n"
39 "  vout.sharpness = IN.sharpness;                                          \n"
40 "  return vout;                                                            \n"
41 "}                                                                         \n";
42 
43 static const char *s_PS =
44 "struct pixelIn { float4 pos : SV_POSITION; float sharpness : COLOR0; };   \n"
45 "Buffer<float> edgeSharpness : register(t0);                               \n"
46 "float4 sharpnessToColor(float s) {                                        \n"
47 "  //  0.0       2.0       4.0                                             \n"
48 "  // green --- yellow --- red                                             \n"
49 "  return float4(min(1, s * 0.5),                                          \n"
50 "                min(1, 2 - s * 0.5),                                      \n"
51 "                0, 1);                                                    \n"
52 "}                                                                         \n"
53 "float4 ps_main(pixelIn IN, uint primitiveID : SV_PrimitiveID)             \n"
54 "  : SV_Target {                                                           \n"
55 "  float sharpness = edgeSharpness[primitiveID];                           \n"
56 "  return sharpnessToColor(sharpness);                                     \n"
57 "}                                                                         \n";
58 
59 namespace {
60     struct CB_CONTROL_MESH_DISPLAY
61     {
62         float mViewProjection[16];
63     };
64 };
65 
D3D11ControlMeshDisplay(ID3D11DeviceContext * deviceContext)66 D3D11ControlMeshDisplay::D3D11ControlMeshDisplay(
67     ID3D11DeviceContext *deviceContext) :
68     _displayEdges(true), _displayVertices(false),
69     _deviceContext(deviceContext), _inputLayout(0), _vertexShader(0),
70     _pixelShader(0), _rasterizerState(0), _constantBuffer(0),
71     _edgeSharpnessSRV(0), _edgeSharpness(0), _edgeIndices(0),
72     _numEdges(0), _numPoints(0) {
73 }
74 
~D3D11ControlMeshDisplay()75 D3D11ControlMeshDisplay::~D3D11ControlMeshDisplay() {
76     SAFE_RELEASE(_inputLayout);
77     SAFE_RELEASE(_vertexShader);
78     SAFE_RELEASE(_pixelShader);
79     SAFE_RELEASE(_rasterizerState);
80     SAFE_RELEASE(_constantBuffer);
81     SAFE_RELEASE(_edgeSharpness);
82     SAFE_RELEASE(_edgeSharpnessSRV);
83     SAFE_RELEASE(_edgeIndices);
84 }
85 
86 bool
createProgram()87 D3D11ControlMeshDisplay::createProgram() {
88     ID3D11Device *device = NULL;
89     _deviceContext->GetDevice(&device);
90 
91     ID3DBlob* pVSBlob;
92     ID3DBlob* pPSBlob;
93     pVSBlob = D3D11Utils::CompileShader(s_VS, "vs_main", "vs_4_0");
94     pPSBlob = D3D11Utils::CompileShader(s_PS, "ps_main", "ps_4_0");
95     assert(pVSBlob);
96     assert(pPSBlob);
97 
98     D3D11_INPUT_ELEMENT_DESC inputElementDesc[] = {
99         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,               0,
100           D3D11_INPUT_PER_VERTEX_DATA, 0 },
101         { "COLOR",    0, DXGI_FORMAT_R32_FLOAT,       0, sizeof(float)*3,
102           D3D11_INPUT_PER_VERTEX_DATA, 0 },
103     };
104     device->CreateInputLayout(inputElementDesc, ARRAYSIZE(inputElementDesc),
105         pVSBlob->GetBufferPointer(),
106         pVSBlob->GetBufferSize(),
107         &_inputLayout);
108     assert(_inputLayout);
109 
110     device->CreateVertexShader(pVSBlob->GetBufferPointer(),
111         pVSBlob->GetBufferSize(),
112         NULL, &_vertexShader);
113     assert(_vertexShader);
114 
115     device->CreatePixelShader(pPSBlob->GetBufferPointer(),
116         pPSBlob->GetBufferSize(),
117         NULL, &_pixelShader);
118     assert(_pixelShader);
119 
120     D3D11_RASTERIZER_DESC rasDesc;
121     rasDesc.FillMode = D3D11_FILL_SOLID;
122     rasDesc.CullMode = D3D11_CULL_NONE;
123     rasDesc.FrontCounterClockwise = FALSE;
124     rasDesc.DepthBias = 0;
125     rasDesc.DepthBiasClamp = 0;
126     rasDesc.SlopeScaledDepthBias = 0.0f;
127     rasDesc.DepthClipEnable = FALSE;
128     rasDesc.ScissorEnable = FALSE;
129     rasDesc.MultisampleEnable = FALSE;
130     rasDesc.AntialiasedLineEnable = FALSE;
131     device->CreateRasterizerState(&rasDesc, &_rasterizerState);
132     assert(_rasterizerState);
133 
134     // constant buffer
135     D3D11_BUFFER_DESC cbDesc;
136     cbDesc.Usage = D3D11_USAGE_DYNAMIC;
137     cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
138     cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
139     cbDesc.MiscFlags = 0;
140     cbDesc.ByteWidth = sizeof(CB_CONTROL_MESH_DISPLAY);
141 
142     device->CreateBuffer(&cbDesc, NULL, &_constantBuffer);
143     assert(_constantBuffer);
144     return true;
145 }
146 
147 
148 void
Draw(ID3D11Buffer * buffer,int stride,const float * modelViewProjectionMatrix)149 D3D11ControlMeshDisplay::Draw(ID3D11Buffer *buffer, int stride,
150                               const float *modelViewProjectionMatrix) {
151 
152     if (_displayEdges == false && _displayVertices == false) return;
153 
154     if (_vertexShader == NULL) createProgram();
155     if (_vertexShader == NULL) return;
156 
157     UINT hStrides = stride*sizeof(float);
158     UINT hOffsets = 0;
159     _deviceContext->IASetVertexBuffers(0, 1, &buffer, &hStrides, &hOffsets);
160 
161     D3D11_MAPPED_SUBRESOURCE MappedResource;
162     _deviceContext->Map(_constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource);
163     CB_CONTROL_MESH_DISPLAY * pData = (CB_CONTROL_MESH_DISPLAY *)MappedResource.pData;
164     memcpy(pData->mViewProjection, modelViewProjectionMatrix, sizeof(float) * 16);
165     _deviceContext->Unmap(_constantBuffer, 0);
166 
167     _deviceContext->IASetInputLayout(_inputLayout);
168     _deviceContext->VSSetShader(_vertexShader, NULL, 0);
169     _deviceContext->HSSetShader(NULL, NULL, 0);
170     _deviceContext->DSSetShader(NULL, NULL, 0);
171     _deviceContext->GSSetShader(NULL, NULL, 0);
172     _deviceContext->PSSetShaderResources(0, 1, &_edgeSharpnessSRV);
173     _deviceContext->PSSetShader(_pixelShader, NULL, 0);
174     _deviceContext->RSSetState(_rasterizerState);
175     _deviceContext->VSSetConstantBuffers(0, 1, &_constantBuffer);
176 
177     if (_displayEdges) {
178         _deviceContext->IASetIndexBuffer(_edgeIndices, DXGI_FORMAT_R32_UINT, 0);
179         _deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
180         _deviceContext->DrawIndexed(_numEdges * 2, 0, 0);
181     }
182     if (_displayVertices) {
183         // TODO: need geometry shader to draw bigger points
184         _deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
185         _deviceContext->Draw(_numPoints, 0);
186     }
187 
188 }
189 
190 void
SetTopology(OpenSubdiv::Far::TopologyLevel const & level)191 D3D11ControlMeshDisplay::SetTopology(
192     OpenSubdiv::Far::TopologyLevel const &level) {
193     int nEdges = level.GetNumEdges();
194     int nVerts = level.GetNumVertices();
195 
196     std::vector<int> edgeIndices;
197     std::vector<float> edgeSharpnesses;
198     std::vector<float> vertSharpnesses;
199 
200     edgeIndices.reserve(nEdges * 2);
201     edgeSharpnesses.reserve(nEdges);
202     vertSharpnesses.reserve(nVerts);
203 
204     for (int i = 0; i < nEdges; ++i) {
205         OpenSubdiv::Far::ConstIndexArray verts = level.GetEdgeVertices(i);
206         edgeIndices.push_back(verts[0]);
207         edgeIndices.push_back(verts[1]);
208         edgeSharpnesses.push_back(level.GetEdgeSharpness(i));
209     }
210 
211     for (int i = 0; i < nVerts; ++i) {
212         vertSharpnesses.push_back(level.GetVertexSharpness(i));
213     }
214 
215     _numEdges = nEdges;
216     _numPoints = nVerts;
217 
218     ID3D11Device *device = NULL;
219     _deviceContext->GetDevice(&device);
220 
221     SAFE_RELEASE(_edgeIndices);
222     // create edge index buffer
223     D3D11_BUFFER_DESC bufferDesc;
224     ZeroMemory(&bufferDesc, sizeof(bufferDesc));
225     bufferDesc.ByteWidth = (int)edgeIndices.size() * sizeof(int);
226     bufferDesc.Usage = D3D11_USAGE_DEFAULT;
227     bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
228     bufferDesc.CPUAccessFlags = 0;
229     bufferDesc.MiscFlags = 0;
230     bufferDesc.StructureByteStride = sizeof(int);
231 
232     D3D11_SUBRESOURCE_DATA subData;
233     ZeroMemory(&subData, sizeof(subData));
234     subData.pSysMem = &edgeIndices[0];
235     subData.SysMemPitch = 0;
236     subData.SysMemSlicePitch = 0;
237 
238     HRESULT hr = device->CreateBuffer(&bufferDesc, &subData, &_edgeIndices);
239     assert(_edgeIndices);
240 
241     // edge sharpness
242     SAFE_RELEASE(_edgeSharpness);
243     SAFE_RELEASE(_edgeSharpnessSRV);
244     ZeroMemory(&bufferDesc, sizeof(bufferDesc));
245     bufferDesc.ByteWidth = (int)edgeSharpnesses.size() * sizeof(float);
246     bufferDesc.Usage = D3D11_USAGE_DEFAULT;
247     bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
248     bufferDesc.CPUAccessFlags = 0;
249     bufferDesc.MiscFlags = 0;
250     bufferDesc.StructureByteStride = sizeof(float);
251 
252     ZeroMemory(&subData, sizeof(subData));
253     subData.pSysMem = &edgeSharpnesses[0];
254     subData.SysMemPitch = 0;
255     subData.SysMemSlicePitch = 0;
256 
257     hr = device->CreateBuffer(&bufferDesc, &subData, &_edgeSharpness);
258     assert(_edgeSharpness);
259 
260     D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
261     ZeroMemory(&srvDesc, sizeof(srvDesc));
262     srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
263     srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
264     srvDesc.Buffer.NumElements = _numEdges;
265     hr = device->CreateShaderResourceView(_edgeSharpness, &srvDesc, &_edgeSharpnessSRV);
266     assert(_edgeSharpnessSRV);
267 }
268 
269