blob: f8d14b1c1506ad17ea246d158c04aba1767030ee [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
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010#include "libGLESv2/Program.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000011
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000012#include "common/debug.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000013
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000014#include "libGLESv2/main.h"
15#include "libGLESv2/Shader.h"
16
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000017namespace gl
18{
daniel@transgaming.com0361b922010-03-28 19:36:15 +000019Uniform::Uniform(GLenum type, const std::string &name, unsigned int bytes) : type(type), name(name), bytes(bytes)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000020{
21 this->data = new unsigned char[bytes];
22 memset(this->data, 0, bytes);
23}
24
25Uniform::~Uniform()
26{
27 delete[] data;
28}
29
30Program::Program()
31{
32 mFragmentShader = NULL;
33 mVertexShader = NULL;
34
35 mPixelExecutable = NULL;
36 mVertexExecutable = NULL;
37 mConstantTablePS = NULL;
38 mConstantTableVS = NULL;
39
40 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
41 {
42 mAttributeName[index] = NULL;
43 }
44
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +000045 mPixelHLSL = NULL;
46 mVertexHLSL = NULL;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000047 mInfoLog = NULL;
48
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000049 unlink();
50
51 mDeleteStatus = false;
52}
53
54Program::~Program()
55{
56 unlink(true);
57}
58
59bool Program::attachShader(Shader *shader)
60{
61 if (shader->getType() == GL_VERTEX_SHADER)
62 {
63 if (mVertexShader)
64 {
65 return false;
66 }
67
68 mVertexShader = (VertexShader*)shader;
69 mVertexShader->attach();
70 }
71 else if (shader->getType() == GL_FRAGMENT_SHADER)
72 {
73 if (mFragmentShader)
74 {
75 return false;
76 }
77
78 mFragmentShader = (FragmentShader*)shader;
79 mFragmentShader->attach();
80 }
81 else UNREACHABLE();
82
83 return true;
84}
85
86bool Program::detachShader(Shader *shader)
87{
88 if (shader->getType() == GL_VERTEX_SHADER)
89 {
90 if (mVertexShader != shader)
91 {
92 return false;
93 }
94
95 mVertexShader->detach();
96 mVertexShader = NULL;
97 }
98 else if (shader->getType() == GL_FRAGMENT_SHADER)
99 {
100 if (mFragmentShader != shader)
101 {
102 return false;
103 }
104
105 mFragmentShader->detach();
106 mFragmentShader = NULL;
107 }
108 else UNREACHABLE();
109
110 unlink();
111
112 return true;
113}
114
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000115int Program::getAttachedShadersCount() const
116{
117 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
118}
119
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000120IDirect3DPixelShader9 *Program::getPixelShader()
121{
122 return mPixelExecutable;
123}
124
125IDirect3DVertexShader9 *Program::getVertexShader()
126{
127 return mVertexExecutable;
128}
129
130void Program::bindAttributeLocation(GLuint index, const char *name)
131{
132 if (index < MAX_VERTEX_ATTRIBS)
133 {
134 delete[] mAttributeName[index];
135 mAttributeName[index] = new char[strlen(name) + 1];
136 strcpy(mAttributeName[index], name);
137 }
138}
139
140GLuint Program::getAttributeLocation(const char *name)
141{
142 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
143 {
144 if (mAttributeName[index] && strcmp(mAttributeName[index], name) == 0)
145 {
146 return index;
147 }
148 }
149
150 return -1;
151}
152
153bool Program::isActiveAttribute(int attributeIndex)
154{
155 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
156 {
157 return mInputMapping[attributeIndex] != -1;
158 }
159
160 return false;
161}
162
163int Program::getInputMapping(int attributeIndex)
164{
165 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
166 {
167 return mInputMapping[attributeIndex];
168 }
169
170 return -1;
171}
172
173// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
174// index referenced in the compiled HLSL shader
175GLint Program::getSamplerMapping(unsigned int samplerIndex)
176{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000177 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
178
179 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000180 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000181 return mSamplers[samplerIndex].logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182 }
183
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000184 return -1;
185}
186
187SamplerType Program::getSamplerType(unsigned int samplerIndex)
188{
189 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
190 assert(mSamplers[samplerIndex].active);
191
192 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000193}
194
195GLint Program::getUniformLocation(const char *name)
196{
197 for (unsigned int location = 0; location < mUniforms.size(); location++)
198 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000199 if (mUniforms[location]->name == decorate(name))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000200 {
201 return location;
202 }
203 }
204
205 return -1;
206}
207
208bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
209{
210 if (location < 0 || location >= (int)mUniforms.size())
211 {
212 return false;
213 }
214
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000215 if (mUniforms[location]->type == GL_FLOAT)
216 {
217 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat);
218
219 if (arraySize == 1 && count > 1)
220 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
221
222 count = std::min(arraySize, count);
223
224 memcpy(mUniforms[location]->data, v, sizeof(GLfloat) * count);
225 }
226 else if (mUniforms[location]->type == GL_BOOL)
227 {
228 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean);
229
230 if (arraySize == 1 && count > 1)
231 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
232
233 count = std::min(arraySize, count);
234 GLboolean *boolParams = new GLboolean[count];
235
236 for (int i = 0; i < count; ++i)
237 {
238 if (v[i] == 0.0f)
239 {
240 boolParams[i] = GL_FALSE;
241 }
242 else
243 {
244 boolParams[i] = GL_TRUE;
245 }
246 }
247
248 memcpy(mUniforms[location]->data, boolParams, sizeof(GLboolean) * count);
249
250 delete [] boolParams;
251 }
252 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000253 {
254 return false;
255 }
256
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000257 return true;
258}
259
260bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
261{
262 if (location < 0 || location >= (int)mUniforms.size())
263 {
264 return false;
265 }
266
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000267 if (mUniforms[location]->type == GL_FLOAT_VEC2)
268 {
269 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat) / 2;
270
271 if (arraySize == 1 && count > 1)
272 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
273
274 count = std::min(arraySize, count);
275
276 memcpy(mUniforms[location]->data, v, 2 * sizeof(GLfloat) * count);
277 }
278 else if (mUniforms[location]->type == GL_BOOL_VEC2)
279 {
280 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean) / 2;
281
282 if (arraySize == 1 && count > 1)
283 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
284
285 count = std::min(arraySize, count);
286 GLboolean *boolParams = new GLboolean[count * 2];
287
288 for (int i = 0; i < count * 2; ++i)
289 {
290 if (v[i] == 0.0f)
291 {
292 boolParams[i] = GL_FALSE;
293 }
294 else
295 {
296 boolParams[i] = GL_TRUE;
297 }
298 }
299
300 memcpy(mUniforms[location]->data, boolParams, 2 * sizeof(GLboolean) * count);
301
302 delete [] boolParams;
303 }
304 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000305 {
306 return false;
307 }
308
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000309 return true;
310}
311
312bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
313{
314 if (location < 0 || location >= (int)mUniforms.size())
315 {
316 return false;
317 }
318
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000319 if (mUniforms[location]->type == GL_FLOAT_VEC3)
320 {
321 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat) / 3;
322
323 if (arraySize == 1 && count > 1)
324 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
325
326 count = std::min(arraySize, count);
327
328 memcpy(mUniforms[location]->data, v, 3 * sizeof(GLfloat) * count);
329 }
330 else if (mUniforms[location]->type == GL_BOOL_VEC3)
331 {
332 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean) / 3;
333
334 if (arraySize == 1 && count > 1)
335 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
336
337 count = std::min(arraySize, count);
338 GLboolean *boolParams = new GLboolean[count * 3];
339
340 for (int i = 0; i < count * 3; ++i)
341 {
342 if (v[i] == 0.0f)
343 {
344 boolParams[i] = GL_FALSE;
345 }
346 else
347 {
348 boolParams[i] = GL_TRUE;
349 }
350 }
351
352 memcpy(mUniforms[location]->data, boolParams, 3 * sizeof(GLboolean) * count);
353
354 delete [] boolParams;
355 }
356 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000357 {
358 return false;
359 }
360
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000361 return true;
362}
363
364bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
365{
366 if (location < 0 || location >= (int)mUniforms.size())
367 {
368 return false;
369 }
370
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000371 if (mUniforms[location]->type == GL_FLOAT_VEC4)
372 {
373 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat) / 4;
374
375 if (arraySize == 1 && count > 1)
376 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
377
378 count = std::min(arraySize, count);
379
380 memcpy(mUniforms[location]->data, v, 4 * sizeof(GLfloat) * count);
381 }
382 else if (mUniforms[location]->type == GL_BOOL_VEC4)
383 {
384 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean) / 4;
385
386 if (arraySize == 1 && count > 1)
387 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
388
389 count = std::min(arraySize, count);
390 GLboolean *boolParams = new GLboolean[count * 4];
391
392 for (int i = 0; i < count * 4; ++i)
393 {
394 if (v[i] == 0.0f)
395 {
396 boolParams[i] = GL_FALSE;
397 }
398 else
399 {
400 boolParams[i] = GL_TRUE;
401 }
402 }
403
404 memcpy(mUniforms[location]->data, boolParams, 4 * sizeof(GLboolean) * count);
405
406 delete [] boolParams;
407 }
408 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000409 {
410 return false;
411 }
412
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000413 return true;
414}
415
416bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
417{
418 if (location < 0 || location >= (int)mUniforms.size())
419 {
420 return false;
421 }
422
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000423 if (mUniforms[location]->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000424 {
425 return false;
426 }
427
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000428 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat) / 4;
429
430 if (arraySize == 1 && count > 1)
431 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
432
433 count = std::min(arraySize, count);
434
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000435 memcpy(mUniforms[location]->data, value, 4 * sizeof(GLfloat) * count);
436
437 return true;
438}
439
440bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
441{
442 if (location < 0 || location >= (int)mUniforms.size())
443 {
444 return false;
445 }
446
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000447 if (mUniforms[location]->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 {
449 return false;
450 }
451
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000452 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat) / 9;
453
454 if (arraySize == 1 && count > 1)
455 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
456
457 count = std::min(arraySize, count);
458
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000459 memcpy(mUniforms[location]->data, value, 9 * sizeof(GLfloat) * count);
460
461 return true;
462}
463
464bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
465{
466 if (location < 0 || location >= (int)mUniforms.size())
467 {
468 return false;
469 }
470
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000471 if (mUniforms[location]->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000472 {
473 return false;
474 }
475
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000476 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat) / 16;
477
478 if (arraySize == 1 && count > 1)
479 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
480
481 count = std::min(arraySize, count);
482
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000483 memcpy(mUniforms[location]->data, value, 16 * sizeof(GLfloat) * count);
484
485 return true;
486}
487
488bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
489{
490 if (location < 0 || location >= (int)mUniforms.size())
491 {
492 return false;
493 }
494
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000495 if (mUniforms[location]->type == GL_INT)
496 {
497 int arraySize = mUniforms[location]->bytes / sizeof(GLint);
498
499 if (arraySize == 1 && count > 1)
500 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
501
502 count = std::min(arraySize, count);
503
504 memcpy(mUniforms[location]->data, v, sizeof(GLint) * count);
505 }
506 else if (mUniforms[location]->type == GL_BOOL)
507 {
508 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean);
509
510 if (arraySize == 1 && count > 1)
511 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
512
513 count = std::min(arraySize, count);
514 GLboolean *boolParams = new GLboolean[count];
515
516 for (int i = 0; i < count; ++i)
517 {
518 if (v[i] == 0)
519 {
520 boolParams[i] = GL_FALSE;
521 }
522 else
523 {
524 boolParams[i] = GL_TRUE;
525 }
526 }
527
528 memcpy(mUniforms[location]->data, boolParams, sizeof(GLboolean) * count);
529
530 delete [] boolParams;
531 }
532 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000533 {
534 return false;
535 }
536
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000537 return true;
538}
539
540bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
541{
542 if (location < 0 || location >= (int)mUniforms.size())
543 {
544 return false;
545 }
546
547 if (mUniforms[location]->type == GL_INT_VEC2)
548 {
549 int arraySize = mUniforms[location]->bytes / sizeof(GLint) / 2;
550
551 if (arraySize == 1 && count > 1)
552 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
553
554 count = std::min(arraySize, count);
555
556 memcpy(mUniforms[location]->data, v, 2 * sizeof(GLint) * count);
557 }
558 else if (mUniforms[location]->type == GL_BOOL_VEC2)
559 {
560 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean) / 2;
561
562 if (arraySize == 1 && count > 1)
563 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
564
565 count = std::min(arraySize, count);
566 GLboolean *boolParams = new GLboolean[count * 2];
567
568 for (int i = 0; i < count * 2; ++i)
569 {
570 if (v[i] == 0)
571 {
572 boolParams[i] = GL_FALSE;
573 }
574 else
575 {
576 boolParams[i] = GL_TRUE;
577 }
578 }
579
580 memcpy(mUniforms[location]->data, boolParams, 2 * sizeof(GLboolean) * count);
581
582 delete [] boolParams;
583 }
584 else
585 {
586 return false;
587 }
588
589 return true;
590}
591
592bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
593{
594 if (location < 0 || location >= (int)mUniforms.size())
595 {
596 return false;
597 }
598
599 if (mUniforms[location]->type == GL_INT_VEC3)
600 {
601 int arraySize = mUniforms[location]->bytes / sizeof(GLint) / 3;
602
603 if (arraySize == 1 && count > 1)
604 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
605
606 count = std::min(arraySize, count);
607
608 memcpy(mUniforms[location]->data, v, 3 * sizeof(GLint) * count);
609 }
610 else if (mUniforms[location]->type == GL_BOOL_VEC3)
611 {
612 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean) / 3;
613
614 if (arraySize == 1 && count > 1)
615 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
616
617 count = std::min(arraySize, count);
618 GLboolean *boolParams = new GLboolean[count * 3];
619
620 for (int i = 0; i < count * 3; ++i)
621 {
622 if (v[i] == 0)
623 {
624 boolParams[i] = GL_FALSE;
625 }
626 else
627 {
628 boolParams[i] = GL_TRUE;
629 }
630 }
631
632 memcpy(mUniforms[location]->data, boolParams, 3 * sizeof(GLboolean) * count);
633
634 delete [] boolParams;
635 }
636 else
637 {
638 return false;
639 }
640
641 return true;
642}
643
644bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
645{
646 if (location < 0 || location >= (int)mUniforms.size())
647 {
648 return false;
649 }
650
651 if (mUniforms[location]->type == GL_INT_VEC4)
652 {
653 int arraySize = mUniforms[location]->bytes / sizeof(GLint) / 4;
654
655 if (arraySize == 1 && count > 1)
656 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
657
658 count = std::min(arraySize, count);
659
660 memcpy(mUniforms[location]->data, v, 4 * sizeof(GLint) * count);
661 }
662 else if (mUniforms[location]->type == GL_BOOL_VEC4)
663 {
664 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean) / 4;
665
666 if (arraySize == 1 && count > 1)
667 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
668
669 count = std::min(arraySize, count);
670 GLboolean *boolParams = new GLboolean[count * 4];
671
672 for (int i = 0; i < count * 4; ++i)
673 {
674 if (v[i] == 0)
675 {
676 boolParams[i] = GL_FALSE;
677 }
678 else
679 {
680 boolParams[i] = GL_TRUE;
681 }
682 }
683
684 memcpy(mUniforms[location]->data, boolParams, 4 * sizeof(GLboolean) * count);
685
686 delete [] boolParams;
687 }
688 else
689 {
690 return false;
691 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000692
693 return true;
694}
695
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000696bool Program::getUniformfv(GLint location, GLfloat *params)
697{
698 if (location < 0 || location >= (int)mUniforms.size())
699 {
700 return false;
701 }
702
703 unsigned int count = 0;
704
705 switch (mUniforms[location]->type)
706 {
707 case GL_FLOAT:
708 case GL_BOOL:
709 count = 1;
710 break;
711 case GL_FLOAT_VEC2:
712 case GL_BOOL_VEC2:
713 count = 2;
714 break;
715 case GL_FLOAT_VEC3:
716 case GL_BOOL_VEC3:
717 count = 3;
718 break;
719 case GL_FLOAT_VEC4:
720 case GL_BOOL_VEC4:
721 case GL_FLOAT_MAT2:
722 count = 4;
723 break;
724 case GL_FLOAT_MAT3:
725 count = 9;
726 break;
727 case GL_FLOAT_MAT4:
728 count = 16;
729 break;
730 default:
731 return false;
732 }
733
734 if (mUniforms[location]->type == GL_BOOL || mUniforms[location]->type == GL_BOOL_VEC2 ||
735 mUniforms[location]->type == GL_BOOL_VEC3 || mUniforms[location]->type == GL_BOOL_VEC4)
736 {
737 GLboolean *boolParams = mUniforms[location]->data;
738
739 for (unsigned int i = 0; i < count; ++i)
740 {
741 if (boolParams[i] == GL_FALSE)
742 params[i] = 0.0f;
743 else
744 params[i] = 1.0f;
745 }
746 }
747 else
748 {
749 memcpy(params, mUniforms[location]->data, count * sizeof(GLfloat));
750 }
751
752 return true;
753}
754
755bool Program::getUniformiv(GLint location, GLint *params)
756{
757 if (location < 0 || location >= (int)mUniforms.size())
758 {
759 return false;
760 }
761
762 unsigned int count = 0;
763
764 switch (mUniforms[location]->type)
765 {
766 case GL_INT:
767 case GL_BOOL:
768 count = 1;
769 break;
770 case GL_INT_VEC2:
771 case GL_BOOL_VEC2:
772 count = 2;
773 break;
774 case GL_INT_VEC3:
775 case GL_BOOL_VEC3:
776 count = 3;
777 break;
778 case GL_INT_VEC4:
779 case GL_BOOL_VEC4:
780 count = 4;
781 break;
782 default:
783 return false;
784 }
785
786 if (mUniforms[location]->type == GL_BOOL || mUniforms[location]->type == GL_BOOL_VEC2 ||
787 mUniforms[location]->type == GL_BOOL_VEC3 || mUniforms[location]->type == GL_BOOL_VEC4)
788 {
789 GLboolean *boolParams = mUniforms[location]->data;
790
791 for (unsigned int i = 0; i < count; ++i)
792 {
793 if (boolParams[i] == GL_FALSE)
794 params[i] = 0;
795 else
796 params[i] = 1;
797 }
798 }
799 else
800 {
801 memcpy(params, mUniforms[location]->data, count * sizeof(GLint));
802 }
803
804 return true;
805}
806
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000807// Applies all the uniforms set for this program object to the Direct3D 9 device
808void Program::applyUniforms()
809{
810 for (unsigned int location = 0; location < mUniforms.size(); location++)
811 {
812 int bytes = mUniforms[location]->bytes;
813 GLfloat *f = (GLfloat*)mUniforms[location]->data;
814 GLint *i = (GLint*)mUniforms[location]->data;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000815 GLboolean *b = (GLboolean*)mUniforms[location]->data;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000816
817 switch (mUniforms[location]->type)
818 {
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000819 case GL_BOOL: applyUniform1bv(location, bytes / sizeof(GLboolean), b); break;
820 case GL_BOOL_VEC2: applyUniform2bv(location, bytes / 2 / sizeof(GLboolean), b); break;
821 case GL_BOOL_VEC3: applyUniform3bv(location, bytes / 3 / sizeof(GLboolean), b); break;
822 case GL_BOOL_VEC4: applyUniform4bv(location, bytes / 4 / sizeof(GLboolean), b); break;
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000823 case GL_FLOAT: applyUniform1fv(location, bytes / sizeof(GLfloat), f); break;
824 case GL_FLOAT_VEC2: applyUniform2fv(location, bytes / 2 / sizeof(GLfloat), f); break;
825 case GL_FLOAT_VEC3: applyUniform3fv(location, bytes / 3 / sizeof(GLfloat), f); break;
826 case GL_FLOAT_VEC4: applyUniform4fv(location, bytes / 4 / sizeof(GLfloat), f); break;
827 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, bytes / 4 / sizeof(GLfloat), f); break;
828 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, bytes / 9 / sizeof(GLfloat), f); break;
829 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, bytes / 16 / sizeof(GLfloat), f); break;
830 case GL_INT: applyUniform1iv(location, bytes / sizeof(GLint), i); break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000831 case GL_INT_VEC2: applyUniform2iv(location, bytes / 2 / sizeof(GLint), i); break;
832 case GL_INT_VEC3: applyUniform3iv(location, bytes / 3 / sizeof(GLint), i); break;
833 case GL_INT_VEC4: applyUniform4iv(location, bytes / 4 / sizeof(GLint), i); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000834 default:
835 UNIMPLEMENTED(); // FIXME
836 UNREACHABLE();
837 }
838 }
839}
840
841// Compiles the HLSL code of the attached shaders into executable binaries
842ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
843{
844 if (!hlsl)
845 {
846 return NULL;
847 }
848
849 ID3DXBuffer *binary = NULL;
850 ID3DXBuffer *errorMessage = NULL;
851
daniel@transgaming.comcbbca002010-04-01 13:39:32 +0000852 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000853
854 if (SUCCEEDED(result))
855 {
856 return binary;
857 }
858
859 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
860 {
861 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
862 }
863
864 if (errorMessage)
865 {
866 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000867
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000868 TRACE("\n%s", hlsl);
869 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000870 }
871
872 return NULL;
873}
874
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000875void Program::parseVaryings(const char *structure, char *hlsl, VaryingArray &varyings)
876{
877 char *input = strstr(hlsl, structure);
878 input += strlen(structure);
879
880 while (input && *input != '}')
881 {
882 char varyingType[256];
883 char varyingName[256];
884 unsigned int semanticIndex;
885 int matches = sscanf(input, " %s %s : TEXCOORD%d;", varyingType, varyingName, &semanticIndex);
886
887 if (matches == 3)
888 {
889 ASSERT(semanticIndex <= 9); // Single character
890
891 varyings.push_back(Varying(varyingName, input));
892 }
893
894 input = strstr(input, ";");
895 input += 2;
896 }
897}
898
899bool Program::linkVaryings()
900{
901 if (!mPixelHLSL || !mVertexHLSL)
902 {
903 return false;
904 }
905
906 VaryingArray vertexVaryings;
907 VaryingArray pixelVaryings;
908
909 parseVaryings("struct VS_OUTPUT\n{\n", mVertexHLSL, vertexVaryings);
910 parseVaryings("struct PS_INPUT\n{\n", mPixelHLSL, pixelVaryings);
911
912 for (unsigned int out = 0; out < vertexVaryings.size(); out++)
913 {
914 unsigned int in;
915 for (in = 0; in < pixelVaryings.size(); in++)
916 {
917 if (vertexVaryings[out].name == pixelVaryings[in].name)
918 {
919 pixelVaryings[in].link = out;
920 vertexVaryings[out].link = in;
921
922 break;
923 }
924 }
925
926 if (in != pixelVaryings.size())
927 {
928 // FIXME: Verify matching type and qualifiers
929
930 char *outputSemantic = strstr(vertexVaryings[out].declaration, " : TEXCOORD");
931 char *inputSemantic = strstr(pixelVaryings[in].declaration, " : TEXCOORD");
932 outputSemantic[11] = inputSemantic[11];
933 }
934 else
935 {
936 // Comment out the declaration and output assignment
937 vertexVaryings[out].declaration[0] = '/';
938 vertexVaryings[out].declaration[1] = '/';
939
940 char outputString[256];
941 sprintf(outputString, " output.%s = ", vertexVaryings[out].name.c_str());
942 char *varyingOutput = strstr(mVertexHLSL, outputString);
943
944 varyingOutput[0] = '/';
945 varyingOutput[1] = '/';
946 }
947 }
948
949 // Verify that each pixel varying has been linked to a vertex varying
950 for (unsigned int in = 0; in < pixelVaryings.size(); in++)
951 {
952 if (pixelVaryings[in].link < 0)
953 {
954 return false;
955 }
956 }
957
958 return true;
959}
960
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000961// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
962// compiling them into binaries, determining the attribute mappings, and collecting
963// a list of uniforms
964void Program::link()
965{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000966 unlink();
967
968 if (!mFragmentShader || !mFragmentShader->isCompiled())
969 {
970 return;
971 }
972
973 if (!mVertexShader || !mVertexShader->isCompiled())
974 {
975 return;
976 }
977
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +0000978 Context *context = getContext();
979 const char *vertexProfile = context->getVertexShaderProfile();
980 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +0000981
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000982 const char *ps = mFragmentShader->getHLSL();
983 const char *vs = mVertexShader->getHLSL();
984
985 mPixelHLSL = new char[strlen(ps) + 1];
986 strcpy(mPixelHLSL, ps);
987 mVertexHLSL = new char[strlen(vs) + 1];
988 strcpy(mVertexHLSL, vs);
989
990 if (!linkVaryings())
991 {
992 return;
993 }
994
995 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL, vertexProfile, &mConstantTableVS);
996 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000997
998 if (vertexBinary && pixelBinary)
999 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001000 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001001 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1002 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1003
1004 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1005 {
1006 return error(GL_OUT_OF_MEMORY);
1007 }
1008
1009 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001010
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001011 vertexBinary->Release();
1012 pixelBinary->Release();
1013 vertexBinary = NULL;
1014 pixelBinary = NULL;
1015
1016 if (mVertexExecutable && mPixelExecutable)
1017 {
1018 if (!linkAttributes())
1019 {
1020 return;
1021 }
1022
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001023 for (int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
1024 {
1025 mSamplers[i].active = false;
1026 }
1027
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001028 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001029 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001030 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001031 }
1032
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001033 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001034 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001035 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001036 }
1037
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001038 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001039 }
1040 }
1041}
1042
1043// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1044bool Program::linkAttributes()
1045{
1046 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1047 {
1048 const char *name = mVertexShader->getAttributeName(attributeIndex);
1049
1050 if (name)
1051 {
1052 GLuint location = getAttributeLocation(name);
1053
1054 if (location == -1) // Not set by glBindAttribLocation
1055 {
1056 int availableIndex = 0;
1057
1058 while (availableIndex < MAX_VERTEX_ATTRIBS && mAttributeName[availableIndex] && mVertexShader->isActiveAttribute(mAttributeName[availableIndex]))
1059 {
1060 availableIndex++;
1061 }
1062
1063 if (availableIndex == MAX_VERTEX_ATTRIBS)
1064 {
1065 return false; // Fail to link
1066 }
1067
1068 delete[] mAttributeName[availableIndex];
1069 mAttributeName[availableIndex] = new char[strlen(name) + 1]; // FIXME: Check allocation
1070 strcpy(mAttributeName[availableIndex], name);
1071 }
1072 }
1073 }
1074
1075 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1076 {
1077 mInputMapping[attributeIndex] = mVertexShader->getInputMapping(mAttributeName[attributeIndex]);
1078 }
1079
1080 return true;
1081}
1082
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001083bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1084{
1085 D3DXCONSTANTTABLE_DESC constantTableDescription;
1086 D3DXCONSTANT_DESC constantDescription;
1087 UINT descriptionCount = 1;
1088
1089 constantTable->GetDesc(&constantTableDescription);
1090
1091 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1092 {
1093 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1094 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1095
1096 if (!defineUniform(constantHandle, constantDescription))
1097 {
1098 return false;
1099 }
1100 }
1101
1102 return true;
1103}
1104
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001105// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001106// Returns true if succesful (uniform not already defined)
1107bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1108{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001109 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1110 {
1111 unsigned int samplerIndex = constantDescription.RegisterIndex;
1112
1113 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1114
1115 mSamplers[samplerIndex].active = true;
1116 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1117 mSamplers[samplerIndex].logicalTextureUnit = 0;
1118 }
1119
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001120 switch(constantDescription.Class)
1121 {
1122 case D3DXPC_STRUCT:
1123 {
1124 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1125 {
1126 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1127
1128 D3DXCONSTANT_DESC fieldDescription;
1129 UINT descriptionCount = 1;
1130
1131 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1132
1133 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1134 {
1135 return false;
1136 }
1137 }
1138
1139 return true;
1140 }
1141 case D3DXPC_SCALAR:
1142 case D3DXPC_VECTOR:
1143 case D3DXPC_MATRIX_COLUMNS:
1144 case D3DXPC_OBJECT:
1145 return defineUniform(constantDescription, name + constantDescription.Name);
1146 default:
1147 UNREACHABLE();
1148 return false;
1149 }
1150}
1151
1152bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1153{
1154 Uniform *uniform = createUniform(constantDescription, name);
1155
1156 if(!uniform)
1157 {
1158 return false;
1159 }
1160
1161 // Check if already defined
1162 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001163 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001164
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001165 if (location >= 0)
1166 {
1167 delete uniform;
1168
1169 if (mUniforms[location]->type != type)
1170 {
1171 return false;
1172 }
1173 else
1174 {
1175 return true;
1176 }
1177 }
1178
1179 mUniforms.push_back(uniform);
1180
1181 return true;
1182}
1183
1184Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001185{
1186 if (constantDescription.Rows == 1) // Vectors and scalars
1187 {
1188 switch (constantDescription.Type)
1189 {
1190 case D3DXPT_SAMPLER2D:
1191 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001192 switch (constantDescription.Columns)
1193 {
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001194 case 1: return new Uniform(GL_INT, name, 1 * sizeof(GLint) * constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001195 default: UNREACHABLE();
1196 }
1197 break;
1198 case D3DXPT_BOOL:
1199 switch (constantDescription.Columns)
1200 {
1201 case 1: return new Uniform(GL_BOOL, name, 1 * sizeof(GLboolean) * constantDescription.Elements);
1202 case 2: return new Uniform(GL_BOOL_VEC2, name, 2 * sizeof(GLboolean) * constantDescription.Elements);
1203 case 3: return new Uniform(GL_BOOL_VEC3, name, 3 * sizeof(GLboolean) * constantDescription.Elements);
1204 case 4: return new Uniform(GL_BOOL_VEC4, name, 4 * sizeof(GLboolean) * constantDescription.Elements);
1205 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001206 }
1207 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001208 case D3DXPT_INT:
1209 switch (constantDescription.Columns)
1210 {
1211 case 1: return new Uniform(GL_INT, name, 1 * sizeof(GLint) * constantDescription.Elements);
1212 case 2: return new Uniform(GL_INT_VEC2, name, 2 * sizeof(GLint) * constantDescription.Elements);
1213 case 3: return new Uniform(GL_INT_VEC3, name, 3 * sizeof(GLint) * constantDescription.Elements);
1214 case 4: return new Uniform(GL_INT_VEC4, name, 4 * sizeof(GLint) * constantDescription.Elements);
1215 default: UNREACHABLE();
1216 }
1217 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001218 case D3DXPT_FLOAT:
1219 switch (constantDescription.Columns)
1220 {
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001221 case 1: return new Uniform(GL_FLOAT, name, 1 * sizeof(GLfloat) * constantDescription.Elements);
1222 case 2: return new Uniform(GL_FLOAT_VEC2, name, 2 * sizeof(GLfloat) * constantDescription.Elements);
1223 case 3: return new Uniform(GL_FLOAT_VEC3, name, 3 * sizeof(GLfloat) * constantDescription.Elements);
1224 case 4: return new Uniform(GL_FLOAT_VEC4, name, 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001225 default: UNREACHABLE();
1226 }
1227 break;
1228 default:
1229 UNIMPLEMENTED(); // FIXME
1230 UNREACHABLE();
1231 }
1232 }
1233 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1234 {
1235 switch (constantDescription.Type)
1236 {
1237 case D3DXPT_FLOAT:
1238 switch (constantDescription.Rows)
1239 {
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001240 case 2: return new Uniform(GL_FLOAT_MAT2, name, 2 * 2 * sizeof(GLfloat) * constantDescription.Elements);
1241 case 3: return new Uniform(GL_FLOAT_MAT3, name, 3 * 3 * sizeof(GLfloat) * constantDescription.Elements);
1242 case 4: return new Uniform(GL_FLOAT_MAT4, name, 4 * 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001243 default: UNREACHABLE();
1244 }
1245 break;
1246 default: UNREACHABLE();
1247 }
1248 }
1249 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001250
1251 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001252}
1253
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001254// This methods needs to match OutputHLSL::decorate
1255std::string Program::decorate(const std::string &string)
1256{
1257 if (string.substr(0, 3) != "gl_")
1258 {
1259 return "_" + string;
1260 }
1261 else
1262 {
1263 return string;
1264 }
1265}
1266
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001267bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1268{
1269 BOOL *vector = new BOOL[count];
1270 for (int i = 0; i < count; i++)
1271 {
1272 if (v[i] == GL_FALSE)
1273 vector[i] = 0;
1274 else
1275 vector[i] = 1;
1276 }
1277
1278 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1279 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1280 IDirect3DDevice9 *device = getDevice();
1281
1282 if (constantPS)
1283 {
1284 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1285 }
1286
1287 if (constantVS)
1288 {
1289 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1290 }
1291
1292 delete [] vector;
1293
1294 return true;
1295}
1296
1297bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1298{
1299 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1300
1301 for (int i = 0; i < count; i++)
1302 {
1303 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1304 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1305
1306 v += 2;
1307 }
1308
1309 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1310 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1311 IDirect3DDevice9 *device = getDevice();
1312
1313 if (constantPS)
1314 {
1315 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1316 }
1317
1318 if (constantVS)
1319 {
1320 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1321 }
1322
1323 delete[] vector;
1324
1325 return true;
1326}
1327
1328bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1329{
1330 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1331
1332 for (int i = 0; i < count; i++)
1333 {
1334 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1335 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1336 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1337
1338 v += 3;
1339 }
1340
1341 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1342 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1343 IDirect3DDevice9 *device = getDevice();
1344
1345 if (constantPS)
1346 {
1347 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1348 }
1349
1350 if (constantVS)
1351 {
1352 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1353 }
1354
1355 delete[] vector;
1356
1357 return true;
1358}
1359
1360bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1361{
1362 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1363
1364 for (int i = 0; i < count; i++)
1365 {
1366 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1367 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1368 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1369 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1370
1371 v += 3;
1372 }
1373
1374 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1375 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1376 IDirect3DDevice9 *device = getDevice();
1377
1378 if (constantPS)
1379 {
1380 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1381 }
1382
1383 if (constantVS)
1384 {
1385 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1386 }
1387
1388 delete [] vector;
1389
1390 return true;
1391}
1392
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001393bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1394{
1395 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1396 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1397 IDirect3DDevice9 *device = getDevice();
1398
1399 if (constantPS)
1400 {
1401 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1402 }
1403
1404 if (constantVS)
1405 {
1406 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1407 }
1408
1409 return true;
1410}
1411
1412bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1413{
1414 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1415
1416 for (int i = 0; i < count; i++)
1417 {
1418 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1419
1420 v += 2;
1421 }
1422
1423 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1424 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1425 IDirect3DDevice9 *device = getDevice();
1426
1427 if (constantPS)
1428 {
1429 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1430 }
1431
1432 if (constantVS)
1433 {
1434 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1435 }
1436
1437 delete[] vector;
1438
1439 return true;
1440}
1441
1442bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1443{
1444 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1445
1446 for (int i = 0; i < count; i++)
1447 {
1448 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1449
1450 v += 3;
1451 }
1452
1453 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1454 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1455 IDirect3DDevice9 *device = getDevice();
1456
1457 if (constantPS)
1458 {
1459 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1460 }
1461
1462 if (constantVS)
1463 {
1464 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1465 }
1466
1467 delete[] vector;
1468
1469 return true;
1470}
1471
1472bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1473{
1474 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1475 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1476 IDirect3DDevice9 *device = getDevice();
1477
1478 if (constantPS)
1479 {
1480 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
1481 }
1482
1483 if (constantVS)
1484 {
1485 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
1486 }
1487
1488 return true;
1489}
1490
1491bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
1492{
1493 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1494
1495 for (int i = 0; i < count; i++)
1496 {
1497 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
1498 value[1], value[3], 0, 0,
1499 0, 0, 1, 0,
1500 0, 0, 0, 1);
1501
1502 value += 4;
1503 }
1504
1505 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1506 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1507 IDirect3DDevice9 *device = getDevice();
1508
1509 if (constantPS)
1510 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001511 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001512 }
1513
1514 if (constantVS)
1515 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001516 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001517 }
1518
1519 delete[] matrix;
1520
1521 return true;
1522}
1523
1524bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
1525{
1526 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1527
1528 for (int i = 0; i < count; i++)
1529 {
1530 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
1531 value[1], value[4], value[7], 0,
1532 value[2], value[5], value[8], 0,
1533 0, 0, 0, 1);
1534
1535 value += 9;
1536 }
1537
1538 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1539 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1540 IDirect3DDevice9 *device = getDevice();
1541
1542 if (constantPS)
1543 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001544 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001545 }
1546
1547 if (constantVS)
1548 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001549 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001550 }
1551
1552 delete[] matrix;
1553
1554 return true;
1555}
1556
1557bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
1558{
1559 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1560
1561 for (int i = 0; i < count; i++)
1562 {
1563 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
1564 value[1], value[5], value[9], value[13],
1565 value[2], value[6], value[10], value[14],
1566 value[3], value[7], value[11], value[15]);
1567
1568 value += 16;
1569 }
1570
1571 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1572 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1573 IDirect3DDevice9 *device = getDevice();
1574
1575 if (constantPS)
1576 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001577 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001578 }
1579
1580 if (constantVS)
1581 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001582 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001583 }
1584
1585 delete[] matrix;
1586
1587 return true;
1588}
1589
1590bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
1591{
1592 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1593 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1594 IDirect3DDevice9 *device = getDevice();
1595
1596 if (constantPS)
1597 {
1598 D3DXCONSTANT_DESC constantDescription;
1599 UINT descriptionCount = 1;
1600 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
1601
daniel@transgaming.com2884b782010-03-08 21:30:48 +00001602 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001603 {
1604 return false;
1605 }
1606
1607 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1608 {
1609 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
1610
1611 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
1612 {
1613 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001614
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001615 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
1616 {
1617 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1618 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001619 ASSERT(mSamplers[samplerIndex].active);
1620 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001621 }
1622 }
1623 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001624
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001625 return true;
1626 }
1627 }
1628
1629 if (constantPS)
1630 {
1631 mConstantTablePS->SetIntArray(device, constantPS, v, count);
1632 }
1633
1634 if (constantVS)
1635 {
1636 mConstantTableVS->SetIntArray(device, constantVS, v, count);
1637 }
1638
1639 return true;
1640}
1641
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001642bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
1643{
1644 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1645
1646 for (int i = 0; i < count; i++)
1647 {
1648 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
1649
1650 v += 2;
1651 }
1652
1653 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1654 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1655 IDirect3DDevice9 *device = getDevice();
1656
1657 if (constantPS)
1658 {
1659 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1660 }
1661
1662 if (constantVS)
1663 {
1664 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1665 }
1666
1667 delete[] vector;
1668
1669 return true;
1670}
1671
1672bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
1673{
1674 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1675
1676 for (int i = 0; i < count; i++)
1677 {
1678 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
1679
1680 v += 3;
1681 }
1682
1683 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1684 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1685 IDirect3DDevice9 *device = getDevice();
1686
1687 if (constantPS)
1688 {
1689 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1690 }
1691
1692 if (constantVS)
1693 {
1694 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1695 }
1696
1697 delete[] vector;
1698
1699 return true;
1700}
1701
1702bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
1703{
1704 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1705
1706 for (int i = 0; i < count; i++)
1707 {
1708 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
1709
1710 v += 4;
1711 }
1712
1713 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1714 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1715 IDirect3DDevice9 *device = getDevice();
1716
1717 if (constantPS)
1718 {
1719 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1720 }
1721
1722 if (constantVS)
1723 {
1724 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1725 }
1726
1727 delete [] vector;
1728
1729 return true;
1730}
1731
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001732void Program::appendToInfoLog(const char *info)
1733{
1734 if (!info)
1735 {
1736 return;
1737 }
1738
1739 size_t infoLength = strlen(info);
1740
1741 if (!mInfoLog)
1742 {
1743 mInfoLog = new char[infoLength + 1];
1744 strcpy(mInfoLog, info);
1745 }
1746 else
1747 {
1748 size_t logLength = strlen(mInfoLog);
1749 char *newLog = new char[logLength + infoLength + 1];
1750 strcpy(newLog, mInfoLog);
1751 strcpy(newLog + logLength, info);
1752
1753 delete[] mInfoLog;
1754 mInfoLog = newLog;
1755 }
1756}
1757
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001758// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
1759void Program::unlink(bool destroy)
1760{
1761 if (destroy) // Object being destructed
1762 {
1763 if (mFragmentShader)
1764 {
1765 mFragmentShader->detach();
1766 mFragmentShader = NULL;
1767 }
1768
1769 if (mVertexShader)
1770 {
1771 mVertexShader->detach();
1772 mVertexShader = NULL;
1773 }
1774
1775 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1776 {
1777 delete[] mAttributeName[index];
1778 mAttributeName[index] = NULL;
1779 }
1780 }
1781
1782 if (mPixelExecutable)
1783 {
1784 mPixelExecutable->Release();
1785 mPixelExecutable = NULL;
1786 }
1787
1788 if (mVertexExecutable)
1789 {
1790 mVertexExecutable->Release();
1791 mVertexExecutable = NULL;
1792 }
1793
1794 if (mConstantTablePS)
1795 {
1796 mConstantTablePS->Release();
1797 mConstantTablePS = NULL;
1798 }
1799
1800 if (mConstantTableVS)
1801 {
1802 mConstantTableVS->Release();
1803 mConstantTableVS = NULL;
1804 }
1805
1806 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1807 {
1808 mInputMapping[index] = 0;
1809 }
1810
1811 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
1812 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001813 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001814 }
1815
1816 while (!mUniforms.empty())
1817 {
1818 delete mUniforms.back();
1819 mUniforms.pop_back();
1820 }
1821
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001822 delete[] mPixelHLSL;
1823 mPixelHLSL = NULL;
1824
1825 delete[] mVertexHLSL;
1826 mVertexHLSL = NULL;
1827
1828 delete[] mInfoLog;
1829 mInfoLog = NULL;
1830
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001831 mLinked = false;
1832}
1833
1834bool Program::isLinked()
1835{
1836 return mLinked;
1837}
1838
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001839int Program::getInfoLogLength() const
1840{
1841 if (!mInfoLog)
1842 {
1843 return 0;
1844 }
1845 else
1846 {
1847 return strlen(mInfoLog) + 1;
1848 }
1849}
1850
1851void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
1852{
1853 int index = 0;
1854
1855 if (mInfoLog)
1856 {
1857 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
1858 {
1859 infoLog[index] = mInfoLog[index];
1860 index++;
1861 }
1862 }
1863
1864 if (bufSize)
1865 {
1866 infoLog[index] = '\0';
1867 }
1868
1869 if (length)
1870 {
1871 *length = index;
1872 }
1873}
1874
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001875void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
1876{
1877 int total = 0;
1878
1879 if (mVertexShader)
1880 {
1881 if (total < maxCount)
1882 {
1883 shaders[total] = mVertexShader->getHandle();
1884 }
1885
1886 total++;
1887 }
1888
1889 if (mFragmentShader)
1890 {
1891 if (total < maxCount)
1892 {
1893 shaders[total] = mFragmentShader->getHandle();
1894 }
1895
1896 total++;
1897 }
1898
1899 if (count)
1900 {
1901 *count = total;
1902 }
1903}
1904
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001905void Program::flagForDeletion()
1906{
1907 mDeleteStatus = true;
1908}
1909
1910bool Program::isFlaggedForDeletion() const
1911{
1912 return mDeleteStatus;
1913}
1914}