1+ #include " Shader.h"
2+
3+
4+ Shader::Shader (void )
5+ {
6+ mEffect = 0 ;
7+ mTechnique = 0 ;
8+ mLayout = 0 ;
9+
10+ mWorldMatrix = 0 ;
11+ mViewMatrix = 0 ;
12+ mProjectionMatrix = 0 ;
13+ }
14+
15+ Shader::~Shader (void )
16+ {
17+ ShutdownShader ();
18+ }
19+
20+ /* The Initialize function will call the initialization function for the shader.
21+ We pass in the name of the HLSL shader file*/
22+ bool Shader::Initialize (ID3D10Device* device, HWND hwnd)
23+ {
24+ bool result;
25+
26+ // Initialize the shader that will be used to draw the triangle.
27+ result = InitializeShader (device, hwnd, L" Shaders/color2.fx" );
28+ if (!result){
29+ return false ;
30+ }
31+
32+ return true ;
33+ }
34+
35+ // The Shutdown function will call the shutdown of the shader.
36+ void Shader::Shutdown (){
37+ // Shutdown the shader effect.
38+ ShutdownShader ();
39+ }
40+
41+ /* Render will first set the parameters inside the shader using the SetShaderParameters function.
42+ Once the parameters are set it then calls RenderShader to draw using the HLSL shader.*/
43+ void Shader::Render (ID3D10Device* device, int indexCount, D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
44+ {
45+ // Set the shader parameters that it will use for rendering.
46+ SetShaderParameters (worldMatrix, viewMatrix, projectionMatrix);
47+
48+ // Now render the prepared buffers with the shader.
49+ RenderShader (device, indexCount);
50+ }
51+
52+ /* This function is what actually loads the shader file and makes it usable to DirectX and the GPU.
53+ You will also see the setup of the layout and how the vertex buffer data is going to look
54+ on the graphics pipeline in the GPU. The layout will need the match the Vertex struct in GameObject.h
55+ as well as the one defined in the shader.fx file*/
56+ bool Shader::InitializeShader (ID3D10Device* device, HWND hwnd, WCHAR* filename)
57+ {
58+ HRESULT result;
59+ ID3D10Blob* errorMessage;
60+ D3D10_INPUT_ELEMENT_DESC polygonLayout[2 ];
61+ unsigned int numElements;
62+ D3D10_PASS_DESC passDesc;
63+
64+ // Initialize the error message.
65+ errorMessage = 0 ;
66+
67+ // Initialize shader flags
68+ DWORD shaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
69+ #if defined( DEBUG ) || defined( _DEBUG )
70+ shaderFlags |= D3D10_SHADER_DEBUG;
71+ shaderFlags |= D3D10_SHADER_SKIP_OPTIMIZATION;
72+ #endif
73+
74+ /* Here is where we compile the shader program into an effect. We give it the name of the shader file,
75+ the shader version (4.0 in DirectX 10), and the effect to compile the shader into.*/
76+ // Load the shader in from the file.
77+ result = D3DX10CreateEffectFromFile (filename, NULL , NULL , " fx_4_0" , shaderFlags, 0 ,
78+ device, NULL , NULL , &mEffect , &errorMessage, NULL );
79+ if (FAILED (result))
80+ {
81+ // If the shader failed to compile it should have writen something to the error message.
82+ if (errorMessage)
83+ {
84+ OutputShaderErrorMessage (errorMessage, hwnd, filename);
85+ }
86+ // If there was nothing in the error message then it simply could not find the shader file itself.
87+ else
88+ {
89+ MessageBox (hwnd, filename, L" Missing Shader File" , MB_OK);
90+ }
91+
92+ return false ;
93+ }
94+
95+ /* Once the shader code has successfully compiled into an effect we then use that effect to get
96+ the technique inside the shader. We will use the technique to draw with the shader from this point forward.*/
97+
98+ // Get a pointer to the technique inside the shader.
99+ mTechnique = mEffect ->GetTechniqueByName (" ColorTechnique" );
100+ if (!mTechnique )
101+ {
102+ return false ;
103+ }
104+
105+ // Now setup the layout of the data that goes into the shader.
106+ // This setup needs to match the VertexType stucture in the GameObject class and in the shader.
107+ polygonLayout[0 ].SemanticName = " POSITION" ;
108+ polygonLayout[0 ].SemanticIndex = 0 ;
109+ polygonLayout[0 ].Format = DXGI_FORMAT_R32G32B32_FLOAT;
110+ polygonLayout[0 ].InputSlot = 0 ;
111+ polygonLayout[0 ].AlignedByteOffset = 0 ;
112+ polygonLayout[0 ].InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA;
113+ polygonLayout[0 ].InstanceDataStepRate = 0 ;
114+
115+ polygonLayout[1 ].SemanticName = " COLOR" ;
116+ polygonLayout[1 ].SemanticIndex = 0 ;
117+ polygonLayout[1 ].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
118+ polygonLayout[1 ].InputSlot = 0 ;
119+ polygonLayout[1 ].AlignedByteOffset = D3D10_APPEND_ALIGNED_ELEMENT;
120+ polygonLayout[1 ].InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA;
121+ polygonLayout[1 ].InstanceDataStepRate = 0 ;
122+
123+ /* Once the layout description has been setup we can get the size of it and then create
124+ the input layout using the D3D device.*/
125+
126+ // Get a count of the elements in the layout.
127+ numElements = sizeof (polygonLayout) / sizeof (polygonLayout[0 ]);
128+
129+ // Get the description of the first pass described in the shader technique.
130+ mTechnique ->GetPassByIndex (0 )->GetDesc (&passDesc);
131+
132+ // Create the input lay9out.
133+ result = device->CreateInputLayout (polygonLayout, numElements, passDesc.pIAInputSignature , passDesc.IAInputSignatureSize ,
134+ &mLayout );
135+ if (FAILED (result)){
136+ return false ;
137+ }
138+
139+ /* We will also grab pointers to the global matrices that are inside the shader file.
140+ This way when we set a matrix from the main app inside the shader easily by just using these pointers.*/
141+
142+ // Get pointers to the three matrices inside the shader so we can update them from this class.
143+ mWorldMatrix = mEffect ->GetVariableByName (" worldMatrix" )->AsMatrix ();
144+ mViewMatrix = mEffect ->GetVariableByName (" viewMatrix" )->AsMatrix ();
145+ mProjectionMatrix = mEffect ->GetVariableByName (" projectionMatrix" )->AsMatrix ();
146+ mWVPMatrix = mEffect ->GetVariableByName (" wvpMatrix" )->AsMatrix ();
147+
148+ return true ;
149+ }
150+
151+ // ShutdownShader releases the interfaces and pointers that were setup in the InitializeShader function.
152+
153+ void Shader::ShutdownShader (){
154+ // Release the pointers to the matrices inside the shader.
155+ mWorldMatrix = 0 ;
156+ mViewMatrix = 0 ;
157+ mProjectionMatrix = 0 ;
158+
159+ // Release the pointer to the shader layout.
160+ ReleaseCOM (mLayout );
161+
162+ // Release the pointer to the shader technique.
163+ mTechnique = 0 ;
164+
165+ // Release the pointer to the shader.
166+ ReleaseCOM (mEffect );
167+ }
168+
169+ /* The OutputShaderErrorMessage writes out error messages that are generating when compiling
170+ either vertex shaders or pixel shaders.*/
171+ void Shader::OutputShaderErrorMessage (ID3D10Blob* errorMessage, HWND hwnd, WCHAR* shaderFilename)
172+ {
173+ char * compileErrors;
174+ unsigned long bufferSize, i;
175+ std::ofstream fout;
176+
177+ // Get a pointer to the error message text buffer.
178+ compileErrors = (char *)(errorMessage->GetBufferPointer ());
179+
180+ // Get the length of the message.
181+ bufferSize = errorMessage->GetBufferSize ();
182+
183+ // Open a file to write the error message to.
184+ fout.open (" shader-error.txt" );
185+
186+ // Write out the error message.
187+ for (i=0 ; i<bufferSize; i++){
188+ fout << compileErrors[i];
189+ }
190+
191+ // Close the file.
192+ fout.close ();
193+
194+ // Release the error message.
195+ ReleaseCOM (errorMessage);
196+
197+ // Pop a message up on the screen to notify the user to check the text file for compile errors.
198+ MessageBox (hwnd, L" Error compiling shader. Check shader-error.txt for message." , shaderFilename, MB_OK);
199+ }
200+
201+ /* The SetShaderVariables function exists to make setting the global variables in the shader easier.
202+ The matrices used in this function are created inside the main app, after which
203+ this function is called to send them from there into the shader during the Render function call.*/
204+ void Shader::SetShaderParameters (D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
205+ {
206+ // Set the wvp matrix inside the shader
207+ D3DXMATRIX mWVP = worldMatrix*viewMatrix*projectionMatrix;
208+ mWVPMatrix ->SetMatrix ((float *)&mWVP );
209+
210+ // Set the world matrix variable inside the shader.
211+ mWorldMatrix ->SetMatrix ((float *)&worldMatrix);
212+
213+ // Set the view matrix variable inside the shader.
214+ mViewMatrix ->SetMatrix ((float *)&viewMatrix);
215+
216+ // Set the projection matrix variable inside the shader.
217+ mProjectionMatrix ->SetMatrix ((float *)&projectionMatrix);
218+ }
219+
220+ // RenderShader will invoke the HLSL shader program through the technique pointer.
221+ void Shader::RenderShader (ID3D10Device* device, int indexCount)
222+ {
223+ D3D10_TECHNIQUE_DESC techniqueDesc;
224+
225+ // Set the input layout.
226+ device->IASetInputLayout (mLayout );
227+
228+ // Get the description structure of the technique from inside the shader so it can be used for rendering.
229+ mTechnique ->GetDesc (&techniqueDesc);
230+
231+ // Go through each pass in the technique (should be just one currently) and render the triangles.
232+ for (unsigned int i = 0 ; i < techniqueDesc.Passes ; i++)
233+ {
234+ mTechnique ->GetPassByIndex (i)->Apply (0 );
235+ device->DrawIndexed (indexCount, 0 , 0 );
236+ }
237+ }
0 commit comments