blob: 04de91dc024e256a7d7a54b97b4733d7d8cce7b9 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
10#include "Program.h"
11
12#include "main.h"
13#include "Shader.h"
14#include "debug.h"
15
16namespace gl
17{
18Uniform::Uniform(UniformType type, const std::string &name, unsigned int bytes) : type(type), name(name), bytes(bytes)
19{
20 this->data = new unsigned char[bytes];
21 memset(this->data, 0, bytes);
22}
23
24Uniform::~Uniform()
25{
26 delete[] data;
27}
28
29Program::Program()
30{
31 mFragmentShader = NULL;
32 mVertexShader = NULL;
33
34 mPixelExecutable = NULL;
35 mVertexExecutable = NULL;
36 mConstantTablePS = NULL;
37 mConstantTableVS = NULL;
38
39 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
40 {
41 mAttributeName[index] = NULL;
42 }
43
44 unlink();
45
46 mDeleteStatus = false;
47}
48
49Program::~Program()
50{
51 unlink(true);
52}
53
54bool Program::attachShader(Shader *shader)
55{
56 if (shader->getType() == GL_VERTEX_SHADER)
57 {
58 if (mVertexShader)
59 {
60 return false;
61 }
62
63 mVertexShader = (VertexShader*)shader;
64 mVertexShader->attach();
65 }
66 else if (shader->getType() == GL_FRAGMENT_SHADER)
67 {
68 if (mFragmentShader)
69 {
70 return false;
71 }
72
73 mFragmentShader = (FragmentShader*)shader;
74 mFragmentShader->attach();
75 }
76 else UNREACHABLE();
77
78 return true;
79}
80
81bool Program::detachShader(Shader *shader)
82{
83 if (shader->getType() == GL_VERTEX_SHADER)
84 {
85 if (mVertexShader != shader)
86 {
87 return false;
88 }
89
90 mVertexShader->detach();
91 mVertexShader = NULL;
92 }
93 else if (shader->getType() == GL_FRAGMENT_SHADER)
94 {
95 if (mFragmentShader != shader)
96 {
97 return false;
98 }
99
100 mFragmentShader->detach();
101 mFragmentShader = NULL;
102 }
103 else UNREACHABLE();
104
105 unlink();
106
107 return true;
108}
109
110IDirect3DPixelShader9 *Program::getPixelShader()
111{
112 return mPixelExecutable;
113}
114
115IDirect3DVertexShader9 *Program::getVertexShader()
116{
117 return mVertexExecutable;
118}
119
120void Program::bindAttributeLocation(GLuint index, const char *name)
121{
122 if (index < MAX_VERTEX_ATTRIBS)
123 {
124 delete[] mAttributeName[index];
125 mAttributeName[index] = new char[strlen(name) + 1];
126 strcpy(mAttributeName[index], name);
127 }
128}
129
130GLuint Program::getAttributeLocation(const char *name)
131{
132 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
133 {
134 if (mAttributeName[index] && strcmp(mAttributeName[index], name) == 0)
135 {
136 return index;
137 }
138 }
139
140 return -1;
141}
142
143bool Program::isActiveAttribute(int attributeIndex)
144{
145 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
146 {
147 return mInputMapping[attributeIndex] != -1;
148 }
149
150 return false;
151}
152
153int Program::getInputMapping(int attributeIndex)
154{
155 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
156 {
157 return mInputMapping[attributeIndex];
158 }
159
160 return -1;
161}
162
163// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
164// index referenced in the compiled HLSL shader
165GLint Program::getSamplerMapping(unsigned int samplerIndex)
166{
167 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
168 {
169 return mSamplerMapping[samplerIndex];
170 }
171
172 return 0;
173}
174
175GLint Program::getUniformLocation(const char *name)
176{
177 for (unsigned int location = 0; location < mUniforms.size(); location++)
178 {
179 if (mUniforms[location]->name == name)
180 {
181 return location;
182 }
183 }
184
185 return -1;
186}
187
188bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
189{
190 if (location < 0 || location >= (int)mUniforms.size())
191 {
192 return false;
193 }
194
195 if (mUniforms[location]->type != UNIFORM_1FV || mUniforms[location]->bytes < sizeof(GLfloat) * count)
196 {
197 return false;
198 }
199
200 memcpy(mUniforms[location]->data, v, sizeof(GLfloat) * count);
201
202 return true;
203}
204
205bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
206{
207 if (location < 0 || location >= (int)mUniforms.size())
208 {
209 return false;
210 }
211
212 if (mUniforms[location]->type != UNIFORM_2FV || mUniforms[location]->bytes < 2 * sizeof(GLfloat) * count)
213 {
214 return false;
215 }
216
217 memcpy(mUniforms[location]->data, v, 2 * sizeof(GLfloat) * count);
218
219 return true;
220}
221
222bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
223{
224 if (location < 0 || location >= (int)mUniforms.size())
225 {
226 return false;
227 }
228
229 if (mUniforms[location]->type != UNIFORM_3FV || mUniforms[location]->bytes < 3 * sizeof(GLfloat) * count)
230 {
231 return false;
232 }
233
234 memcpy(mUniforms[location]->data, v, 3 * sizeof(GLfloat) * count);
235
236 return true;
237}
238
239bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
240{
241 if (location < 0 || location >= (int)mUniforms.size())
242 {
243 return false;
244 }
245
246 if (mUniforms[location]->type != UNIFORM_4FV || mUniforms[location]->bytes < 4 * sizeof(GLfloat) * count)
247 {
248 return false;
249 }
250
251 memcpy(mUniforms[location]->data, v, 4 * sizeof(GLfloat) * count);
252
253 return true;
254}
255
256bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
257{
258 if (location < 0 || location >= (int)mUniforms.size())
259 {
260 return false;
261 }
262
263 if (mUniforms[location]->type != UNIFORM_MATRIX_2FV || mUniforms[location]->bytes < 4 * sizeof(GLfloat) * count)
264 {
265 return false;
266 }
267
268 memcpy(mUniforms[location]->data, value, 4 * sizeof(GLfloat) * count);
269
270 return true;
271}
272
273bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
274{
275 if (location < 0 || location >= (int)mUniforms.size())
276 {
277 return false;
278 }
279
280 if (mUniforms[location]->type != UNIFORM_MATRIX_3FV || mUniforms[location]->bytes < 9 * sizeof(GLfloat) * count)
281 {
282 return false;
283 }
284
285 memcpy(mUniforms[location]->data, value, 9 * sizeof(GLfloat) * count);
286
287 return true;
288}
289
290bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
291{
292 if (location < 0 || location >= (int)mUniforms.size())
293 {
294 return false;
295 }
296
297 if (mUniforms[location]->type != UNIFORM_MATRIX_4FV || mUniforms[location]->bytes < 16 * sizeof(GLfloat) * count)
298 {
299 return false;
300 }
301
302 memcpy(mUniforms[location]->data, value, 16 * sizeof(GLfloat) * count);
303
304 return true;
305}
306
307bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
308{
309 if (location < 0 || location >= (int)mUniforms.size())
310 {
311 return false;
312 }
313
314 if (mUniforms[location]->type != UNIFORM_1IV || mUniforms[location]->bytes < sizeof(GLint) * count)
315 {
316 return false;
317 }
318
319 memcpy(mUniforms[location]->data, v, sizeof(GLint) * count);
320
321 return true;
322}
323
324// Applies all the uniforms set for this program object to the Direct3D 9 device
325void Program::applyUniforms()
326{
327 for (unsigned int location = 0; location < mUniforms.size(); location++)
328 {
329 int bytes = mUniforms[location]->bytes;
330 GLfloat *f = (GLfloat*)mUniforms[location]->data;
331 GLint *i = (GLint*)mUniforms[location]->data;
332
333 switch (mUniforms[location]->type)
334 {
335 case UNIFORM_1FV: applyUniform1fv(location, bytes / sizeof(GLfloat), f); break;
336 case UNIFORM_2FV: applyUniform2fv(location, bytes / 2 / sizeof(GLfloat), f); break;
337 case UNIFORM_3FV: applyUniform3fv(location, bytes / 3 / sizeof(GLfloat), f); break;
338 case UNIFORM_4FV: applyUniform4fv(location, bytes / 4 / sizeof(GLfloat), f); break;
339 case UNIFORM_MATRIX_2FV: applyUniformMatrix2fv(location, bytes / 4 / sizeof(GLfloat), f); break;
340 case UNIFORM_MATRIX_3FV: applyUniformMatrix3fv(location, bytes / 9 / sizeof(GLfloat), f); break;
341 case UNIFORM_MATRIX_4FV: applyUniformMatrix4fv(location, bytes / 16 / sizeof(GLfloat), f); break;
342 case UNIFORM_1IV: applyUniform1iv(location, bytes / sizeof(GLint), i); break;
343 default:
344 UNIMPLEMENTED(); // FIXME
345 UNREACHABLE();
346 }
347 }
348}
349
350// Compiles the HLSL code of the attached shaders into executable binaries
351ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
352{
353 if (!hlsl)
354 {
355 return NULL;
356 }
357
358 ID3DXBuffer *binary = NULL;
359 ID3DXBuffer *errorMessage = NULL;
daniel@transgaming.comfbb6dfa2010-03-11 19:41:25 +0000360 DWORD flags = D3DXSHADER_USE_LEGACY_D3DX9_31_DLL |
361 D3DXSHADER_PREFER_FLOW_CONTROL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000362
daniel@transgaming.comfbb6dfa2010-03-11 19:41:25 +0000363 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, flags, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000364
365 if (SUCCEEDED(result))
366 {
367 return binary;
368 }
369
370 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
371 {
372 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
373 }
374
375 if (errorMessage)
376 {
377 const char *message = (const char*)errorMessage->GetBufferPointer();
378 trace(hlsl);
379 trace(message);
380 }
381
382 return NULL;
383}
384
385// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
386// compiling them into binaries, determining the attribute mappings, and collecting
387// a list of uniforms
388void Program::link()
389{
390 if (mLinked)
391 {
392 return;
393 }
394
395 unlink();
396
397 if (!mFragmentShader || !mFragmentShader->isCompiled())
398 {
399 return;
400 }
401
402 if (!mVertexShader || !mVertexShader->isCompiled())
403 {
404 return;
405 }
406
407 const char *pixelHLSL = mFragmentShader->linkHLSL();
408 const char *vertexHLSL = mVertexShader->linkHLSL(pixelHLSL);
daniel@transgaming.comfbb6dfa2010-03-11 19:41:25 +0000409 ID3DXBuffer *vertexBinary = compileToBinary(vertexHLSL, "vs_3_0", &mConstantTableVS);
410 ID3DXBuffer *pixelBinary = compileToBinary(pixelHLSL, "ps_3_0", &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000411
412 if (vertexBinary && pixelBinary)
413 {
414 IDirect3DDevice9 *device = getDevice();
415 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
416 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
417
418 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
419 {
420 return error(GL_OUT_OF_MEMORY);
421 }
422
423 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000424
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000425 vertexBinary->Release();
426 pixelBinary->Release();
427 vertexBinary = NULL;
428 pixelBinary = NULL;
429
430 if (mVertexExecutable && mPixelExecutable)
431 {
432 if (!linkAttributes())
433 {
434 return;
435 }
436
437 D3DXCONSTANTTABLE_DESC constantTableDescription;
438 D3DXCONSTANT_DESC constantDescription;
439 UINT descriptionCount = 1;
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000440
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000441 mConstantTablePS->GetDesc(&constantTableDescription);
442
443 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
444 {
445 D3DXHANDLE constantHandle = mConstantTablePS->GetConstant(0, constantIndex);
446 mConstantTablePS->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000447
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 UniformArray::iterator uniform = mUniforms.begin();
449
450 while (uniform != mUniforms.end())
451 {
452 if ((*uniform)->name == constantDescription.Name)
453 {
454 UNREACHABLE(); // Redefinition; detect at compile
455 }
456
457 uniform++;
458 }
459
460 if (uniform == mUniforms.end())
461 {
462 defineUniform(constantDescription);
463 }
464 }
465
466 mConstantTableVS->GetDesc(&constantTableDescription);
467
468 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
469 {
470 D3DXHANDLE constantHandle = mConstantTableVS->GetConstant(0, constantIndex);
471 mConstantTableVS->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
472
473 UniformArray::iterator uniform = mUniforms.begin();
474
475 while (uniform != mUniforms.end())
476 {
477 if ((*uniform)->name == constantDescription.Name)
478 {
479 UNIMPLEMENTED(); // FIXME: Verify it's the same type as the fragment uniform
480
481 if (true)
482 {
483 break;
484 }
485 else
486 {
487 return;
488 }
489 }
490
491 uniform++;
492 }
493
494 if (uniform == mUniforms.end())
495 {
496 defineUniform(constantDescription);
497 }
498 }
499
500 mLinked = true;
501
502 return;
503 }
504 }
505}
506
507// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
508bool Program::linkAttributes()
509{
510 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
511 {
512 const char *name = mVertexShader->getAttributeName(attributeIndex);
513
514 if (name)
515 {
516 GLuint location = getAttributeLocation(name);
517
518 if (location == -1) // Not set by glBindAttribLocation
519 {
520 int availableIndex = 0;
521
522 while (availableIndex < MAX_VERTEX_ATTRIBS && mAttributeName[availableIndex] && mVertexShader->isActiveAttribute(mAttributeName[availableIndex]))
523 {
524 availableIndex++;
525 }
526
527 if (availableIndex == MAX_VERTEX_ATTRIBS)
528 {
529 return false; // Fail to link
530 }
531
532 delete[] mAttributeName[availableIndex];
533 mAttributeName[availableIndex] = new char[strlen(name) + 1]; // FIXME: Check allocation
534 strcpy(mAttributeName[availableIndex], name);
535 }
536 }
537 }
538
539 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
540 {
541 mInputMapping[attributeIndex] = mVertexShader->getInputMapping(mAttributeName[attributeIndex]);
542 }
543
544 return true;
545}
546
547// Adds the description of a constant found in the binary shader to the list of uniforms
548void Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription)
549{
550 if (constantDescription.Rows == 1) // Vectors and scalars
551 {
552 switch (constantDescription.Type)
553 {
554 case D3DXPT_SAMPLER2D:
555 case D3DXPT_SAMPLERCUBE:
556 case D3DXPT_BOOL:
557 switch (constantDescription.Columns)
558 {
559 case 1:
560 mUniforms.push_back(new Uniform(UNIFORM_1IV, constantDescription.Name, 1 * sizeof(GLint) * constantDescription.Elements));
561 break;
562 default:
563 UNIMPLEMENTED(); // FIXME
564 UNREACHABLE();
565 }
566 break;
567 case D3DXPT_FLOAT:
568 switch (constantDescription.Columns)
569 {
570 case 1:
571 mUniforms.push_back(new Uniform(UNIFORM_1FV, constantDescription.Name, 1 * sizeof(GLfloat) * constantDescription.Elements));
572 break;
573 case 2:
574 mUniforms.push_back(new Uniform(UNIFORM_2FV, constantDescription.Name, 2 * sizeof(GLfloat) * constantDescription.Elements));
575 break;
576 case 3:
577 mUniforms.push_back(new Uniform(UNIFORM_3FV, constantDescription.Name, 3 * sizeof(GLfloat) * constantDescription.Elements));
578 break;
579 case 4:
580 mUniforms.push_back(new Uniform(UNIFORM_4FV, constantDescription.Name, 4 * sizeof(GLfloat) * constantDescription.Elements));
581 break;
582 default: UNREACHABLE();
583 }
584 break;
585 default:
586 UNIMPLEMENTED(); // FIXME
587 UNREACHABLE();
588 }
589 }
590 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
591 {
592 switch (constantDescription.Type)
593 {
594 case D3DXPT_FLOAT:
595 switch (constantDescription.Rows)
596 {
597 case 2:
598 mUniforms.push_back(new Uniform(UNIFORM_MATRIX_2FV, constantDescription.Name, 2 * 2 * sizeof(GLfloat) * constantDescription.Elements));
599 break;
600 case 3:
601 mUniforms.push_back(new Uniform(UNIFORM_MATRIX_3FV, constantDescription.Name, 3 * 3 * sizeof(GLfloat) * constantDescription.Elements));
602 break;
603 case 4:
604 mUniforms.push_back(new Uniform(UNIFORM_MATRIX_4FV, constantDescription.Name, 4 * 4 * sizeof(GLfloat) * constantDescription.Elements));
605 break;
606 default: UNREACHABLE();
607 }
608 break;
609 default: UNREACHABLE();
610 }
611 }
612 else UNREACHABLE();
613}
614
615bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
616{
617 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
618 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
619 IDirect3DDevice9 *device = getDevice();
620
621 if (constantPS)
622 {
623 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
624 }
625
626 if (constantVS)
627 {
628 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
629 }
630
631 return true;
632}
633
634bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
635{
636 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
637
638 for (int i = 0; i < count; i++)
639 {
640 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
641
642 v += 2;
643 }
644
645 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
646 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
647 IDirect3DDevice9 *device = getDevice();
648
649 if (constantPS)
650 {
651 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
652 }
653
654 if (constantVS)
655 {
656 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
657 }
658
659 delete[] vector;
660
661 return true;
662}
663
664bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
665{
666 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
667
668 for (int i = 0; i < count; i++)
669 {
670 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
671
672 v += 3;
673 }
674
675 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
676 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
677 IDirect3DDevice9 *device = getDevice();
678
679 if (constantPS)
680 {
681 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
682 }
683
684 if (constantVS)
685 {
686 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
687 }
688
689 delete[] vector;
690
691 return true;
692}
693
694bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
695{
696 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
697 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
698 IDirect3DDevice9 *device = getDevice();
699
700 if (constantPS)
701 {
702 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
703 }
704
705 if (constantVS)
706 {
707 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
708 }
709
710 return true;
711}
712
713bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
714{
715 D3DXMATRIX *matrix = new D3DXMATRIX[count];
716
717 for (int i = 0; i < count; i++)
718 {
719 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
720 value[1], value[3], 0, 0,
721 0, 0, 1, 0,
722 0, 0, 0, 1);
723
724 value += 4;
725 }
726
727 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
728 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
729 IDirect3DDevice9 *device = getDevice();
730
731 if (constantPS)
732 {
733 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
734 }
735
736 if (constantVS)
737 {
738 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
739 }
740
741 delete[] matrix;
742
743 return true;
744}
745
746bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
747{
748 D3DXMATRIX *matrix = new D3DXMATRIX[count];
749
750 for (int i = 0; i < count; i++)
751 {
752 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
753 value[1], value[4], value[7], 0,
754 value[2], value[5], value[8], 0,
755 0, 0, 0, 1);
756
757 value += 9;
758 }
759
760 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
761 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
762 IDirect3DDevice9 *device = getDevice();
763
764 if (constantPS)
765 {
766 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
767 }
768
769 if (constantVS)
770 {
771 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
772 }
773
774 delete[] matrix;
775
776 return true;
777}
778
779bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
780{
781 D3DXMATRIX *matrix = new D3DXMATRIX[count];
782
783 for (int i = 0; i < count; i++)
784 {
785 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
786 value[1], value[5], value[9], value[13],
787 value[2], value[6], value[10], value[14],
788 value[3], value[7], value[11], value[15]);
789
790 value += 16;
791 }
792
793 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
794 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
795 IDirect3DDevice9 *device = getDevice();
796
797 if (constantPS)
798 {
799 mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count);
800 }
801
802 if (constantVS)
803 {
804 mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count);
805 }
806
807 delete[] matrix;
808
809 return true;
810}
811
812bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
813{
814 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
815 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
816 IDirect3DDevice9 *device = getDevice();
817
818 if (constantPS)
819 {
820 D3DXCONSTANT_DESC constantDescription;
821 UINT descriptionCount = 1;
822 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
823
daniel@transgaming.com2884b782010-03-08 21:30:48 +0000824 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000825 {
826 return false;
827 }
828
829 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
830 {
831 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
832
833 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
834 {
835 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000836
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000837 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
838 {
839 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
840 {
841 mSamplerMapping[samplerIndex] = mappedSampler;
842 }
843 }
844 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000845
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000846 return true;
847 }
848 }
849
850 if (constantPS)
851 {
852 mConstantTablePS->SetIntArray(device, constantPS, v, count);
853 }
854
855 if (constantVS)
856 {
857 mConstantTableVS->SetIntArray(device, constantVS, v, count);
858 }
859
860 return true;
861}
862
863// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
864void Program::unlink(bool destroy)
865{
866 if (destroy) // Object being destructed
867 {
868 if (mFragmentShader)
869 {
870 mFragmentShader->detach();
871 mFragmentShader = NULL;
872 }
873
874 if (mVertexShader)
875 {
876 mVertexShader->detach();
877 mVertexShader = NULL;
878 }
879
880 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
881 {
882 delete[] mAttributeName[index];
883 mAttributeName[index] = NULL;
884 }
885 }
886
887 if (mPixelExecutable)
888 {
889 mPixelExecutable->Release();
890 mPixelExecutable = NULL;
891 }
892
893 if (mVertexExecutable)
894 {
895 mVertexExecutable->Release();
896 mVertexExecutable = NULL;
897 }
898
899 if (mConstantTablePS)
900 {
901 mConstantTablePS->Release();
902 mConstantTablePS = NULL;
903 }
904
905 if (mConstantTableVS)
906 {
907 mConstantTableVS->Release();
908 mConstantTableVS = NULL;
909 }
910
911 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
912 {
913 mInputMapping[index] = 0;
914 }
915
916 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
917 {
918 mSamplerMapping[index] = 0;
919 }
920
921 while (!mUniforms.empty())
922 {
923 delete mUniforms.back();
924 mUniforms.pop_back();
925 }
926
927 mLinked = false;
928}
929
930bool Program::isLinked()
931{
932 return mLinked;
933}
934
935void Program::flagForDeletion()
936{
937 mDeleteStatus = true;
938}
939
940bool Program::isFlaggedForDeletion() const
941{
942 return mDeleteStatus;
943}
944}