blob: 534eabb339e863ac0b3502bc816876d25bf7c10d [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
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +000040 mPixelHLSL = NULL;
41 mVertexHLSL = NULL;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000042 mInfoLog = NULL;
43
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000044 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
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000110int Program::getAttachedShadersCount() const
111{
112 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
113}
114
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000115IDirect3DPixelShader9 *Program::getPixelShader()
116{
117 return mPixelExecutable;
118}
119
120IDirect3DVertexShader9 *Program::getVertexShader()
121{
122 return mVertexExecutable;
123}
124
125void Program::bindAttributeLocation(GLuint index, const char *name)
126{
127 if (index < MAX_VERTEX_ATTRIBS)
128 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000129 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
130 {
131 mAttributeBinding[i].erase(name);
132 }
133
134 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000135 }
136}
137
138GLuint Program::getAttributeLocation(const char *name)
139{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000140 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000141 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000142 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000144 if (mLinkedAttribute[index] == std::string(name))
145 {
146 return index;
147 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000148 }
149 }
150
151 return -1;
152}
153
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000154int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000155{
156 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
157 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000158 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000159 }
160
161 return -1;
162}
163
164// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
165// index referenced in the compiled HLSL shader
166GLint Program::getSamplerMapping(unsigned int samplerIndex)
167{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000168 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
169
170 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000172 return mSamplers[samplerIndex].logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000173 }
174
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000175 return -1;
176}
177
178SamplerType Program::getSamplerType(unsigned int samplerIndex)
179{
180 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
181 assert(mSamplers[samplerIndex].active);
182
183 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000184}
185
186GLint Program::getUniformLocation(const char *name)
187{
188 for (unsigned int location = 0; location < mUniforms.size(); location++)
189 {
daniel@transgaming.com72d0b522010-04-13 19:53:44 +0000190 if (mUniforms[location]->name == decorate(name))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000191 {
192 return location;
193 }
194 }
195
196 return -1;
197}
198
199bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
200{
201 if (location < 0 || location >= (int)mUniforms.size())
202 {
203 return false;
204 }
205
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000206 if (mUniforms[location]->type == GL_FLOAT)
207 {
208 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat);
209
210 if (arraySize == 1 && count > 1)
211 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
212
213 count = std::min(arraySize, count);
214
215 memcpy(mUniforms[location]->data, v, sizeof(GLfloat) * count);
216 }
217 else if (mUniforms[location]->type == GL_BOOL)
218 {
219 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean);
220
221 if (arraySize == 1 && count > 1)
222 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
223
224 count = std::min(arraySize, count);
225 GLboolean *boolParams = new GLboolean[count];
226
227 for (int i = 0; i < count; ++i)
228 {
229 if (v[i] == 0.0f)
230 {
231 boolParams[i] = GL_FALSE;
232 }
233 else
234 {
235 boolParams[i] = GL_TRUE;
236 }
237 }
238
239 memcpy(mUniforms[location]->data, boolParams, sizeof(GLboolean) * count);
240
241 delete [] boolParams;
242 }
243 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000244 {
245 return false;
246 }
247
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000248 return true;
249}
250
251bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
252{
253 if (location < 0 || location >= (int)mUniforms.size())
254 {
255 return false;
256 }
257
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000258 if (mUniforms[location]->type == GL_FLOAT_VEC2)
259 {
260 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat) / 2;
261
262 if (arraySize == 1 && count > 1)
263 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
264
265 count = std::min(arraySize, count);
266
267 memcpy(mUniforms[location]->data, v, 2 * sizeof(GLfloat) * count);
268 }
269 else if (mUniforms[location]->type == GL_BOOL_VEC2)
270 {
271 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean) / 2;
272
273 if (arraySize == 1 && count > 1)
274 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
275
276 count = std::min(arraySize, count);
277 GLboolean *boolParams = new GLboolean[count * 2];
278
279 for (int i = 0; i < count * 2; ++i)
280 {
281 if (v[i] == 0.0f)
282 {
283 boolParams[i] = GL_FALSE;
284 }
285 else
286 {
287 boolParams[i] = GL_TRUE;
288 }
289 }
290
291 memcpy(mUniforms[location]->data, boolParams, 2 * sizeof(GLboolean) * count);
292
293 delete [] boolParams;
294 }
295 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296 {
297 return false;
298 }
299
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000300 return true;
301}
302
303bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
304{
305 if (location < 0 || location >= (int)mUniforms.size())
306 {
307 return false;
308 }
309
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000310 if (mUniforms[location]->type == GL_FLOAT_VEC3)
311 {
312 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat) / 3;
313
314 if (arraySize == 1 && count > 1)
315 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
316
317 count = std::min(arraySize, count);
318
319 memcpy(mUniforms[location]->data, v, 3 * sizeof(GLfloat) * count);
320 }
321 else if (mUniforms[location]->type == GL_BOOL_VEC3)
322 {
323 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean) / 3;
324
325 if (arraySize == 1 && count > 1)
326 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
327
328 count = std::min(arraySize, count);
329 GLboolean *boolParams = new GLboolean[count * 3];
330
331 for (int i = 0; i < count * 3; ++i)
332 {
333 if (v[i] == 0.0f)
334 {
335 boolParams[i] = GL_FALSE;
336 }
337 else
338 {
339 boolParams[i] = GL_TRUE;
340 }
341 }
342
343 memcpy(mUniforms[location]->data, boolParams, 3 * sizeof(GLboolean) * count);
344
345 delete [] boolParams;
346 }
347 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000348 {
349 return false;
350 }
351
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352 return true;
353}
354
355bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
356{
357 if (location < 0 || location >= (int)mUniforms.size())
358 {
359 return false;
360 }
361
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000362 if (mUniforms[location]->type == GL_FLOAT_VEC4)
363 {
364 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat) / 4;
365
366 if (arraySize == 1 && count > 1)
367 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
368
369 count = std::min(arraySize, count);
370
371 memcpy(mUniforms[location]->data, v, 4 * sizeof(GLfloat) * count);
372 }
373 else if (mUniforms[location]->type == GL_BOOL_VEC4)
374 {
375 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean) / 4;
376
377 if (arraySize == 1 && count > 1)
378 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
379
380 count = std::min(arraySize, count);
381 GLboolean *boolParams = new GLboolean[count * 4];
382
383 for (int i = 0; i < count * 4; ++i)
384 {
385 if (v[i] == 0.0f)
386 {
387 boolParams[i] = GL_FALSE;
388 }
389 else
390 {
391 boolParams[i] = GL_TRUE;
392 }
393 }
394
395 memcpy(mUniforms[location]->data, boolParams, 4 * sizeof(GLboolean) * count);
396
397 delete [] boolParams;
398 }
399 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000400 {
401 return false;
402 }
403
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000404 return true;
405}
406
407bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
408{
409 if (location < 0 || location >= (int)mUniforms.size())
410 {
411 return false;
412 }
413
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000414 if (mUniforms[location]->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000415 {
416 return false;
417 }
418
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000419 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat) / 4;
420
421 if (arraySize == 1 && count > 1)
422 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
423
424 count = std::min(arraySize, count);
425
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000426 memcpy(mUniforms[location]->data, value, 4 * sizeof(GLfloat) * count);
427
428 return true;
429}
430
431bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
432{
433 if (location < 0 || location >= (int)mUniforms.size())
434 {
435 return false;
436 }
437
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000438 if (mUniforms[location]->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000439 {
440 return false;
441 }
442
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000443 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat) / 9;
444
445 if (arraySize == 1 && count > 1)
446 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
447
448 count = std::min(arraySize, count);
449
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000450 memcpy(mUniforms[location]->data, value, 9 * sizeof(GLfloat) * count);
451
452 return true;
453}
454
455bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
456{
457 if (location < 0 || location >= (int)mUniforms.size())
458 {
459 return false;
460 }
461
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000462 if (mUniforms[location]->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000463 {
464 return false;
465 }
466
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000467 int arraySize = mUniforms[location]->bytes / sizeof(GLfloat) / 16;
468
469 if (arraySize == 1 && count > 1)
470 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
471
472 count = std::min(arraySize, count);
473
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000474 memcpy(mUniforms[location]->data, value, 16 * sizeof(GLfloat) * count);
475
476 return true;
477}
478
479bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
480{
481 if (location < 0 || location >= (int)mUniforms.size())
482 {
483 return false;
484 }
485
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000486 if (mUniforms[location]->type == GL_INT)
487 {
488 int arraySize = mUniforms[location]->bytes / sizeof(GLint);
489
490 if (arraySize == 1 && count > 1)
491 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
492
493 count = std::min(arraySize, count);
494
495 memcpy(mUniforms[location]->data, v, sizeof(GLint) * count);
496 }
497 else if (mUniforms[location]->type == GL_BOOL)
498 {
499 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean);
500
501 if (arraySize == 1 && count > 1)
502 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
503
504 count = std::min(arraySize, count);
505 GLboolean *boolParams = new GLboolean[count];
506
507 for (int i = 0; i < count; ++i)
508 {
509 if (v[i] == 0)
510 {
511 boolParams[i] = GL_FALSE;
512 }
513 else
514 {
515 boolParams[i] = GL_TRUE;
516 }
517 }
518
519 memcpy(mUniforms[location]->data, boolParams, sizeof(GLboolean) * count);
520
521 delete [] boolParams;
522 }
523 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000524 {
525 return false;
526 }
527
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000528 return true;
529}
530
531bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
532{
533 if (location < 0 || location >= (int)mUniforms.size())
534 {
535 return false;
536 }
537
538 if (mUniforms[location]->type == GL_INT_VEC2)
539 {
540 int arraySize = mUniforms[location]->bytes / sizeof(GLint) / 2;
541
542 if (arraySize == 1 && count > 1)
543 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
544
545 count = std::min(arraySize, count);
546
547 memcpy(mUniforms[location]->data, v, 2 * sizeof(GLint) * count);
548 }
549 else if (mUniforms[location]->type == GL_BOOL_VEC2)
550 {
551 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean) / 2;
552
553 if (arraySize == 1 && count > 1)
554 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
555
556 count = std::min(arraySize, count);
557 GLboolean *boolParams = new GLboolean[count * 2];
558
559 for (int i = 0; i < count * 2; ++i)
560 {
561 if (v[i] == 0)
562 {
563 boolParams[i] = GL_FALSE;
564 }
565 else
566 {
567 boolParams[i] = GL_TRUE;
568 }
569 }
570
571 memcpy(mUniforms[location]->data, boolParams, 2 * sizeof(GLboolean) * count);
572
573 delete [] boolParams;
574 }
575 else
576 {
577 return false;
578 }
579
580 return true;
581}
582
583bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
584{
585 if (location < 0 || location >= (int)mUniforms.size())
586 {
587 return false;
588 }
589
590 if (mUniforms[location]->type == GL_INT_VEC3)
591 {
592 int arraySize = mUniforms[location]->bytes / sizeof(GLint) / 3;
593
594 if (arraySize == 1 && count > 1)
595 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
596
597 count = std::min(arraySize, count);
598
599 memcpy(mUniforms[location]->data, v, 3 * sizeof(GLint) * count);
600 }
601 else if (mUniforms[location]->type == GL_BOOL_VEC3)
602 {
603 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean) / 3;
604
605 if (arraySize == 1 && count > 1)
606 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
607
608 count = std::min(arraySize, count);
609 GLboolean *boolParams = new GLboolean[count * 3];
610
611 for (int i = 0; i < count * 3; ++i)
612 {
613 if (v[i] == 0)
614 {
615 boolParams[i] = GL_FALSE;
616 }
617 else
618 {
619 boolParams[i] = GL_TRUE;
620 }
621 }
622
623 memcpy(mUniforms[location]->data, boolParams, 3 * sizeof(GLboolean) * count);
624
625 delete [] boolParams;
626 }
627 else
628 {
629 return false;
630 }
631
632 return true;
633}
634
635bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
636{
637 if (location < 0 || location >= (int)mUniforms.size())
638 {
639 return false;
640 }
641
642 if (mUniforms[location]->type == GL_INT_VEC4)
643 {
644 int arraySize = mUniforms[location]->bytes / sizeof(GLint) / 4;
645
646 if (arraySize == 1 && count > 1)
647 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
648
649 count = std::min(arraySize, count);
650
651 memcpy(mUniforms[location]->data, v, 4 * sizeof(GLint) * count);
652 }
653 else if (mUniforms[location]->type == GL_BOOL_VEC4)
654 {
655 int arraySize = mUniforms[location]->bytes / sizeof(GLboolean) / 4;
656
657 if (arraySize == 1 && count > 1)
658 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
659
660 count = std::min(arraySize, count);
661 GLboolean *boolParams = new GLboolean[count * 4];
662
663 for (int i = 0; i < count * 4; ++i)
664 {
665 if (v[i] == 0)
666 {
667 boolParams[i] = GL_FALSE;
668 }
669 else
670 {
671 boolParams[i] = GL_TRUE;
672 }
673 }
674
675 memcpy(mUniforms[location]->data, boolParams, 4 * sizeof(GLboolean) * count);
676
677 delete [] boolParams;
678 }
679 else
680 {
681 return false;
682 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000683
684 return true;
685}
686
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000687bool Program::getUniformfv(GLint location, GLfloat *params)
688{
689 if (location < 0 || location >= (int)mUniforms.size())
690 {
691 return false;
692 }
693
694 unsigned int count = 0;
695
696 switch (mUniforms[location]->type)
697 {
698 case GL_FLOAT:
699 case GL_BOOL:
700 count = 1;
701 break;
702 case GL_FLOAT_VEC2:
703 case GL_BOOL_VEC2:
704 count = 2;
705 break;
706 case GL_FLOAT_VEC3:
707 case GL_BOOL_VEC3:
708 count = 3;
709 break;
710 case GL_FLOAT_VEC4:
711 case GL_BOOL_VEC4:
712 case GL_FLOAT_MAT2:
713 count = 4;
714 break;
715 case GL_FLOAT_MAT3:
716 count = 9;
717 break;
718 case GL_FLOAT_MAT4:
719 count = 16;
720 break;
721 default:
722 return false;
723 }
724
725 if (mUniforms[location]->type == GL_BOOL || mUniforms[location]->type == GL_BOOL_VEC2 ||
726 mUniforms[location]->type == GL_BOOL_VEC3 || mUniforms[location]->type == GL_BOOL_VEC4)
727 {
728 GLboolean *boolParams = mUniforms[location]->data;
729
730 for (unsigned int i = 0; i < count; ++i)
731 {
732 if (boolParams[i] == GL_FALSE)
733 params[i] = 0.0f;
734 else
735 params[i] = 1.0f;
736 }
737 }
738 else
739 {
740 memcpy(params, mUniforms[location]->data, count * sizeof(GLfloat));
741 }
742
743 return true;
744}
745
746bool Program::getUniformiv(GLint location, GLint *params)
747{
748 if (location < 0 || location >= (int)mUniforms.size())
749 {
750 return false;
751 }
752
753 unsigned int count = 0;
754
755 switch (mUniforms[location]->type)
756 {
757 case GL_INT:
758 case GL_BOOL:
759 count = 1;
760 break;
761 case GL_INT_VEC2:
762 case GL_BOOL_VEC2:
763 count = 2;
764 break;
765 case GL_INT_VEC3:
766 case GL_BOOL_VEC3:
767 count = 3;
768 break;
769 case GL_INT_VEC4:
770 case GL_BOOL_VEC4:
771 count = 4;
772 break;
773 default:
774 return false;
775 }
776
777 if (mUniforms[location]->type == GL_BOOL || mUniforms[location]->type == GL_BOOL_VEC2 ||
778 mUniforms[location]->type == GL_BOOL_VEC3 || mUniforms[location]->type == GL_BOOL_VEC4)
779 {
780 GLboolean *boolParams = mUniforms[location]->data;
781
782 for (unsigned int i = 0; i < count; ++i)
783 {
784 if (boolParams[i] == GL_FALSE)
785 params[i] = 0;
786 else
787 params[i] = 1;
788 }
789 }
790 else
791 {
792 memcpy(params, mUniforms[location]->data, count * sizeof(GLint));
793 }
794
795 return true;
796}
797
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000798// Applies all the uniforms set for this program object to the Direct3D 9 device
799void Program::applyUniforms()
800{
801 for (unsigned int location = 0; location < mUniforms.size(); location++)
802 {
803 int bytes = mUniforms[location]->bytes;
804 GLfloat *f = (GLfloat*)mUniforms[location]->data;
805 GLint *i = (GLint*)mUniforms[location]->data;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000806 GLboolean *b = (GLboolean*)mUniforms[location]->data;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000807
808 switch (mUniforms[location]->type)
809 {
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000810 case GL_BOOL: applyUniform1bv(location, bytes / sizeof(GLboolean), b); break;
811 case GL_BOOL_VEC2: applyUniform2bv(location, bytes / 2 / sizeof(GLboolean), b); break;
812 case GL_BOOL_VEC3: applyUniform3bv(location, bytes / 3 / sizeof(GLboolean), b); break;
813 case GL_BOOL_VEC4: applyUniform4bv(location, bytes / 4 / sizeof(GLboolean), b); break;
daniel@transgaming.com0361b922010-03-28 19:36:15 +0000814 case GL_FLOAT: applyUniform1fv(location, bytes / sizeof(GLfloat), f); break;
815 case GL_FLOAT_VEC2: applyUniform2fv(location, bytes / 2 / sizeof(GLfloat), f); break;
816 case GL_FLOAT_VEC3: applyUniform3fv(location, bytes / 3 / sizeof(GLfloat), f); break;
817 case GL_FLOAT_VEC4: applyUniform4fv(location, bytes / 4 / sizeof(GLfloat), f); break;
818 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, bytes / 4 / sizeof(GLfloat), f); break;
819 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, bytes / 9 / sizeof(GLfloat), f); break;
820 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, bytes / 16 / sizeof(GLfloat), f); break;
821 case GL_INT: applyUniform1iv(location, bytes / sizeof(GLint), i); break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000822 case GL_INT_VEC2: applyUniform2iv(location, bytes / 2 / sizeof(GLint), i); break;
823 case GL_INT_VEC3: applyUniform3iv(location, bytes / 3 / sizeof(GLint), i); break;
824 case GL_INT_VEC4: applyUniform4iv(location, bytes / 4 / sizeof(GLint), i); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000825 default:
826 UNIMPLEMENTED(); // FIXME
827 UNREACHABLE();
828 }
829 }
830}
831
832// Compiles the HLSL code of the attached shaders into executable binaries
833ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
834{
835 if (!hlsl)
836 {
837 return NULL;
838 }
839
840 ID3DXBuffer *binary = NULL;
841 ID3DXBuffer *errorMessage = NULL;
842
daniel@transgaming.comcbbca002010-04-01 13:39:32 +0000843 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000844
845 if (SUCCEEDED(result))
846 {
847 return binary;
848 }
849
850 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
851 {
852 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
853 }
854
855 if (errorMessage)
856 {
857 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000858
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000859 TRACE("\n%s", hlsl);
860 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000861 }
862
863 return NULL;
864}
865
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000866void Program::parseVaryings(const char *structure, char *hlsl, VaryingArray &varyings)
867{
868 char *input = strstr(hlsl, structure);
869 input += strlen(structure);
870
871 while (input && *input != '}')
872 {
873 char varyingType[256];
874 char varyingName[256];
875 unsigned int semanticIndex;
876 int matches = sscanf(input, " %s %s : TEXCOORD%d;", varyingType, varyingName, &semanticIndex);
877
878 if (matches == 3)
879 {
880 ASSERT(semanticIndex <= 9); // Single character
881
882 varyings.push_back(Varying(varyingName, input));
883 }
884
885 input = strstr(input, ";");
886 input += 2;
887 }
888}
889
890bool Program::linkVaryings()
891{
892 if (!mPixelHLSL || !mVertexHLSL)
893 {
894 return false;
895 }
896
897 VaryingArray vertexVaryings;
898 VaryingArray pixelVaryings;
899
900 parseVaryings("struct VS_OUTPUT\n{\n", mVertexHLSL, vertexVaryings);
901 parseVaryings("struct PS_INPUT\n{\n", mPixelHLSL, pixelVaryings);
902
903 for (unsigned int out = 0; out < vertexVaryings.size(); out++)
904 {
905 unsigned int in;
906 for (in = 0; in < pixelVaryings.size(); in++)
907 {
908 if (vertexVaryings[out].name == pixelVaryings[in].name)
909 {
910 pixelVaryings[in].link = out;
911 vertexVaryings[out].link = in;
912
913 break;
914 }
915 }
916
917 if (in != pixelVaryings.size())
918 {
919 // FIXME: Verify matching type and qualifiers
920
921 char *outputSemantic = strstr(vertexVaryings[out].declaration, " : TEXCOORD");
922 char *inputSemantic = strstr(pixelVaryings[in].declaration, " : TEXCOORD");
923 outputSemantic[11] = inputSemantic[11];
924 }
925 else
926 {
927 // Comment out the declaration and output assignment
928 vertexVaryings[out].declaration[0] = '/';
929 vertexVaryings[out].declaration[1] = '/';
930
931 char outputString[256];
932 sprintf(outputString, " output.%s = ", vertexVaryings[out].name.c_str());
933 char *varyingOutput = strstr(mVertexHLSL, outputString);
934
935 varyingOutput[0] = '/';
936 varyingOutput[1] = '/';
937 }
938 }
939
940 // Verify that each pixel varying has been linked to a vertex varying
941 for (unsigned int in = 0; in < pixelVaryings.size(); in++)
942 {
943 if (pixelVaryings[in].link < 0)
944 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000945 appendToInfoLog("Pixel varying (%s) does not match any vertex varying", pixelVaryings[in].name);
946
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000947 return false;
948 }
949 }
950
951 return true;
952}
953
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000954// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
955// compiling them into binaries, determining the attribute mappings, and collecting
956// a list of uniforms
957void Program::link()
958{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000959 unlink();
960
961 if (!mFragmentShader || !mFragmentShader->isCompiled())
962 {
963 return;
964 }
965
966 if (!mVertexShader || !mVertexShader->isCompiled())
967 {
968 return;
969 }
970
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +0000971 Context *context = getContext();
972 const char *vertexProfile = context->getVertexShaderProfile();
973 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +0000974
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000975 const char *ps = mFragmentShader->getHLSL();
976 const char *vs = mVertexShader->getHLSL();
977
978 mPixelHLSL = new char[strlen(ps) + 1];
979 strcpy(mPixelHLSL, ps);
980 mVertexHLSL = new char[strlen(vs) + 1];
981 strcpy(mVertexHLSL, vs);
982
983 if (!linkVaryings())
984 {
985 return;
986 }
987
988 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL, vertexProfile, &mConstantTableVS);
989 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000990
991 if (vertexBinary && pixelBinary)
992 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +0000993 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000994 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
995 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
996
997 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
998 {
999 return error(GL_OUT_OF_MEMORY);
1000 }
1001
1002 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001003
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001004 vertexBinary->Release();
1005 pixelBinary->Release();
1006 vertexBinary = NULL;
1007 pixelBinary = NULL;
1008
1009 if (mVertexExecutable && mPixelExecutable)
1010 {
1011 if (!linkAttributes())
1012 {
1013 return;
1014 }
1015
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001016 for (int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
1017 {
1018 mSamplers[i].active = false;
1019 }
1020
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001021 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001022 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001023 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001024 }
1025
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001026 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001027 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001028 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001029 }
1030
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001031 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001032 }
1033 }
1034}
1035
1036// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1037bool Program::linkAttributes()
1038{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001039 // Link attributes that have a binding location
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001040 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1041 {
1042 const char *name = mVertexShader->getAttributeName(attributeIndex);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001043 int location = getAttributeBinding(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001044
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001045 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001046 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001047 if (!mLinkedAttribute[location].empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001048 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001049 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001050 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001051
1052 mLinkedAttribute[location] = name;
1053 }
1054 }
1055
1056 // Link attributes that don't have a binding location
1057 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS + 1; attributeIndex++)
1058 {
1059 const char *name = mVertexShader->getAttributeName(attributeIndex);
1060 int location = getAttributeBinding(name);
1061
1062 if (location == -1) // Not set by glBindAttribLocation
1063 {
1064 int availableIndex = 0;
1065
1066 while (availableIndex < MAX_VERTEX_ATTRIBS && !mLinkedAttribute[availableIndex].empty())
1067 {
1068 availableIndex++;
1069 }
1070
1071 if (availableIndex == MAX_VERTEX_ATTRIBS)
1072 {
1073 appendToInfoLog("Too many active attributes (%s)", name);
1074
1075 return false; // Fail to link
1076 }
1077
1078 mLinkedAttribute[availableIndex] = name;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001079 }
1080 }
1081
1082 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1083 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001084 mSemanticIndex[attributeIndex] = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001085 }
1086
1087 return true;
1088}
1089
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001090int Program::getAttributeBinding(const char *name)
1091{
1092 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1093 {
1094 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1095 {
1096 return location;
1097 }
1098 }
1099
1100 return -1;
1101}
1102
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001103bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1104{
1105 D3DXCONSTANTTABLE_DESC constantTableDescription;
1106 D3DXCONSTANT_DESC constantDescription;
1107 UINT descriptionCount = 1;
1108
1109 constantTable->GetDesc(&constantTableDescription);
1110
1111 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1112 {
1113 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1114 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1115
1116 if (!defineUniform(constantHandle, constantDescription))
1117 {
1118 return false;
1119 }
1120 }
1121
1122 return true;
1123}
1124
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001125// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001126// Returns true if succesful (uniform not already defined)
1127bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1128{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001129 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1130 {
1131 unsigned int samplerIndex = constantDescription.RegisterIndex;
1132
1133 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1134
1135 mSamplers[samplerIndex].active = true;
1136 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1137 mSamplers[samplerIndex].logicalTextureUnit = 0;
1138 }
1139
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001140 switch(constantDescription.Class)
1141 {
1142 case D3DXPC_STRUCT:
1143 {
1144 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1145 {
1146 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1147
1148 D3DXCONSTANT_DESC fieldDescription;
1149 UINT descriptionCount = 1;
1150
1151 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1152
1153 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1154 {
1155 return false;
1156 }
1157 }
1158
1159 return true;
1160 }
1161 case D3DXPC_SCALAR:
1162 case D3DXPC_VECTOR:
1163 case D3DXPC_MATRIX_COLUMNS:
1164 case D3DXPC_OBJECT:
1165 return defineUniform(constantDescription, name + constantDescription.Name);
1166 default:
1167 UNREACHABLE();
1168 return false;
1169 }
1170}
1171
1172bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1173{
1174 Uniform *uniform = createUniform(constantDescription, name);
1175
1176 if(!uniform)
1177 {
1178 return false;
1179 }
1180
1181 // Check if already defined
1182 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001183 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001184
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001185 if (location >= 0)
1186 {
1187 delete uniform;
1188
1189 if (mUniforms[location]->type != type)
1190 {
1191 return false;
1192 }
1193 else
1194 {
1195 return true;
1196 }
1197 }
1198
1199 mUniforms.push_back(uniform);
1200
1201 return true;
1202}
1203
1204Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001205{
1206 if (constantDescription.Rows == 1) // Vectors and scalars
1207 {
1208 switch (constantDescription.Type)
1209 {
1210 case D3DXPT_SAMPLER2D:
1211 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001212 switch (constantDescription.Columns)
1213 {
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001214 case 1: return new Uniform(GL_INT, name, 1 * sizeof(GLint) * constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001215 default: UNREACHABLE();
1216 }
1217 break;
1218 case D3DXPT_BOOL:
1219 switch (constantDescription.Columns)
1220 {
1221 case 1: return new Uniform(GL_BOOL, name, 1 * sizeof(GLboolean) * constantDescription.Elements);
1222 case 2: return new Uniform(GL_BOOL_VEC2, name, 2 * sizeof(GLboolean) * constantDescription.Elements);
1223 case 3: return new Uniform(GL_BOOL_VEC3, name, 3 * sizeof(GLboolean) * constantDescription.Elements);
1224 case 4: return new Uniform(GL_BOOL_VEC4, name, 4 * sizeof(GLboolean) * constantDescription.Elements);
1225 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001226 }
1227 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001228 case D3DXPT_INT:
1229 switch (constantDescription.Columns)
1230 {
1231 case 1: return new Uniform(GL_INT, name, 1 * sizeof(GLint) * constantDescription.Elements);
1232 case 2: return new Uniform(GL_INT_VEC2, name, 2 * sizeof(GLint) * constantDescription.Elements);
1233 case 3: return new Uniform(GL_INT_VEC3, name, 3 * sizeof(GLint) * constantDescription.Elements);
1234 case 4: return new Uniform(GL_INT_VEC4, name, 4 * sizeof(GLint) * constantDescription.Elements);
1235 default: UNREACHABLE();
1236 }
1237 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001238 case D3DXPT_FLOAT:
1239 switch (constantDescription.Columns)
1240 {
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001241 case 1: return new Uniform(GL_FLOAT, name, 1 * sizeof(GLfloat) * constantDescription.Elements);
1242 case 2: return new Uniform(GL_FLOAT_VEC2, name, 2 * sizeof(GLfloat) * constantDescription.Elements);
1243 case 3: return new Uniform(GL_FLOAT_VEC3, name, 3 * sizeof(GLfloat) * constantDescription.Elements);
1244 case 4: return new Uniform(GL_FLOAT_VEC4, name, 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001245 default: UNREACHABLE();
1246 }
1247 break;
1248 default:
1249 UNIMPLEMENTED(); // FIXME
1250 UNREACHABLE();
1251 }
1252 }
1253 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1254 {
1255 switch (constantDescription.Type)
1256 {
1257 case D3DXPT_FLOAT:
1258 switch (constantDescription.Rows)
1259 {
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001260 case 2: return new Uniform(GL_FLOAT_MAT2, name, 2 * 2 * sizeof(GLfloat) * constantDescription.Elements);
1261 case 3: return new Uniform(GL_FLOAT_MAT3, name, 3 * 3 * sizeof(GLfloat) * constantDescription.Elements);
1262 case 4: return new Uniform(GL_FLOAT_MAT4, name, 4 * 4 * sizeof(GLfloat) * constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001263 default: UNREACHABLE();
1264 }
1265 break;
1266 default: UNREACHABLE();
1267 }
1268 }
1269 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001270
1271 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001272}
1273
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001274// This methods needs to match OutputHLSL::decorate
1275std::string Program::decorate(const std::string &string)
1276{
1277 if (string.substr(0, 3) != "gl_")
1278 {
1279 return "_" + string;
1280 }
1281 else
1282 {
1283 return string;
1284 }
1285}
1286
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001287bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1288{
1289 BOOL *vector = new BOOL[count];
1290 for (int i = 0; i < count; i++)
1291 {
1292 if (v[i] == GL_FALSE)
1293 vector[i] = 0;
1294 else
1295 vector[i] = 1;
1296 }
1297
1298 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1299 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1300 IDirect3DDevice9 *device = getDevice();
1301
1302 if (constantPS)
1303 {
1304 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1305 }
1306
1307 if (constantVS)
1308 {
1309 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1310 }
1311
1312 delete [] vector;
1313
1314 return true;
1315}
1316
1317bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1318{
1319 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1320
1321 for (int i = 0; i < count; i++)
1322 {
1323 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1324 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1325
1326 v += 2;
1327 }
1328
1329 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1330 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1331 IDirect3DDevice9 *device = getDevice();
1332
1333 if (constantPS)
1334 {
1335 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1336 }
1337
1338 if (constantVS)
1339 {
1340 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1341 }
1342
1343 delete[] vector;
1344
1345 return true;
1346}
1347
1348bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1349{
1350 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1351
1352 for (int i = 0; i < count; i++)
1353 {
1354 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1355 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1356 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1357
1358 v += 3;
1359 }
1360
1361 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1362 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1363 IDirect3DDevice9 *device = getDevice();
1364
1365 if (constantPS)
1366 {
1367 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1368 }
1369
1370 if (constantVS)
1371 {
1372 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1373 }
1374
1375 delete[] vector;
1376
1377 return true;
1378}
1379
1380bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1381{
1382 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1383
1384 for (int i = 0; i < count; i++)
1385 {
1386 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1387 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1388 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1389 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1390
1391 v += 3;
1392 }
1393
1394 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1395 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1396 IDirect3DDevice9 *device = getDevice();
1397
1398 if (constantPS)
1399 {
1400 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1401 }
1402
1403 if (constantVS)
1404 {
1405 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1406 }
1407
1408 delete [] vector;
1409
1410 return true;
1411}
1412
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001413bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1414{
1415 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1416 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1417 IDirect3DDevice9 *device = getDevice();
1418
1419 if (constantPS)
1420 {
1421 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1422 }
1423
1424 if (constantVS)
1425 {
1426 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1427 }
1428
1429 return true;
1430}
1431
1432bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1433{
1434 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1435
1436 for (int i = 0; i < count; i++)
1437 {
1438 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1439
1440 v += 2;
1441 }
1442
1443 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1444 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1445 IDirect3DDevice9 *device = getDevice();
1446
1447 if (constantPS)
1448 {
1449 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1450 }
1451
1452 if (constantVS)
1453 {
1454 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1455 }
1456
1457 delete[] vector;
1458
1459 return true;
1460}
1461
1462bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1463{
1464 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1465
1466 for (int i = 0; i < count; i++)
1467 {
1468 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1469
1470 v += 3;
1471 }
1472
1473 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1474 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1475 IDirect3DDevice9 *device = getDevice();
1476
1477 if (constantPS)
1478 {
1479 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1480 }
1481
1482 if (constantVS)
1483 {
1484 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1485 }
1486
1487 delete[] vector;
1488
1489 return true;
1490}
1491
1492bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1493{
1494 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1495 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1496 IDirect3DDevice9 *device = getDevice();
1497
1498 if (constantPS)
1499 {
1500 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
1501 }
1502
1503 if (constantVS)
1504 {
1505 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
1506 }
1507
1508 return true;
1509}
1510
1511bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
1512{
1513 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1514
1515 for (int i = 0; i < count; i++)
1516 {
1517 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
1518 value[1], value[3], 0, 0,
1519 0, 0, 1, 0,
1520 0, 0, 0, 1);
1521
1522 value += 4;
1523 }
1524
1525 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1526 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1527 IDirect3DDevice9 *device = getDevice();
1528
1529 if (constantPS)
1530 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001531 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001532 }
1533
1534 if (constantVS)
1535 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001536 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001537 }
1538
1539 delete[] matrix;
1540
1541 return true;
1542}
1543
1544bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
1545{
1546 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1547
1548 for (int i = 0; i < count; i++)
1549 {
1550 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
1551 value[1], value[4], value[7], 0,
1552 value[2], value[5], value[8], 0,
1553 0, 0, 0, 1);
1554
1555 value += 9;
1556 }
1557
1558 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1559 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1560 IDirect3DDevice9 *device = getDevice();
1561
1562 if (constantPS)
1563 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001564 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001565 }
1566
1567 if (constantVS)
1568 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001569 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001570 }
1571
1572 delete[] matrix;
1573
1574 return true;
1575}
1576
1577bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
1578{
1579 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1580
1581 for (int i = 0; i < count; i++)
1582 {
1583 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
1584 value[1], value[5], value[9], value[13],
1585 value[2], value[6], value[10], value[14],
1586 value[3], value[7], value[11], value[15]);
1587
1588 value += 16;
1589 }
1590
1591 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1592 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1593 IDirect3DDevice9 *device = getDevice();
1594
1595 if (constantPS)
1596 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001597 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001598 }
1599
1600 if (constantVS)
1601 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001602 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001603 }
1604
1605 delete[] matrix;
1606
1607 return true;
1608}
1609
1610bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
1611{
1612 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1613 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1614 IDirect3DDevice9 *device = getDevice();
1615
1616 if (constantPS)
1617 {
1618 D3DXCONSTANT_DESC constantDescription;
1619 UINT descriptionCount = 1;
1620 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
1621
daniel@transgaming.com2884b782010-03-08 21:30:48 +00001622 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001623 {
1624 return false;
1625 }
1626
1627 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1628 {
1629 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
1630
1631 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
1632 {
1633 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001634
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001635 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
1636 {
1637 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1638 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001639 ASSERT(mSamplers[samplerIndex].active);
1640 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001641 }
1642 }
1643 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001644
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001645 return true;
1646 }
1647 }
1648
1649 if (constantPS)
1650 {
1651 mConstantTablePS->SetIntArray(device, constantPS, v, count);
1652 }
1653
1654 if (constantVS)
1655 {
1656 mConstantTableVS->SetIntArray(device, constantVS, v, count);
1657 }
1658
1659 return true;
1660}
1661
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001662bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
1663{
1664 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1665
1666 for (int i = 0; i < count; i++)
1667 {
1668 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
1669
1670 v += 2;
1671 }
1672
1673 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1674 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1675 IDirect3DDevice9 *device = getDevice();
1676
1677 if (constantPS)
1678 {
1679 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1680 }
1681
1682 if (constantVS)
1683 {
1684 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1685 }
1686
1687 delete[] vector;
1688
1689 return true;
1690}
1691
1692bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
1693{
1694 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1695
1696 for (int i = 0; i < count; i++)
1697 {
1698 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
1699
1700 v += 3;
1701 }
1702
1703 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1704 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1705 IDirect3DDevice9 *device = getDevice();
1706
1707 if (constantPS)
1708 {
1709 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1710 }
1711
1712 if (constantVS)
1713 {
1714 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1715 }
1716
1717 delete[] vector;
1718
1719 return true;
1720}
1721
1722bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
1723{
1724 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1725
1726 for (int i = 0; i < count; i++)
1727 {
1728 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
1729
1730 v += 4;
1731 }
1732
1733 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str());
1734 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str());
1735 IDirect3DDevice9 *device = getDevice();
1736
1737 if (constantPS)
1738 {
1739 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1740 }
1741
1742 if (constantVS)
1743 {
1744 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1745 }
1746
1747 delete [] vector;
1748
1749 return true;
1750}
1751
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001752void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001753{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001754 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001755 {
1756 return;
1757 }
1758
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001759 char info[1024];
1760
1761 va_list vararg;
1762 va_start(vararg, format);
1763 vsnprintf(info, sizeof(info), format, vararg);
1764 va_end(vararg);
1765
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001766 size_t infoLength = strlen(info);
1767
1768 if (!mInfoLog)
1769 {
1770 mInfoLog = new char[infoLength + 1];
1771 strcpy(mInfoLog, info);
1772 }
1773 else
1774 {
1775 size_t logLength = strlen(mInfoLog);
1776 char *newLog = new char[logLength + infoLength + 1];
1777 strcpy(newLog, mInfoLog);
1778 strcpy(newLog + logLength, info);
1779
1780 delete[] mInfoLog;
1781 mInfoLog = newLog;
1782 }
1783}
1784
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001785// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
1786void Program::unlink(bool destroy)
1787{
1788 if (destroy) // Object being destructed
1789 {
1790 if (mFragmentShader)
1791 {
1792 mFragmentShader->detach();
1793 mFragmentShader = NULL;
1794 }
1795
1796 if (mVertexShader)
1797 {
1798 mVertexShader->detach();
1799 mVertexShader = NULL;
1800 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001801 }
1802
1803 if (mPixelExecutable)
1804 {
1805 mPixelExecutable->Release();
1806 mPixelExecutable = NULL;
1807 }
1808
1809 if (mVertexExecutable)
1810 {
1811 mVertexExecutable->Release();
1812 mVertexExecutable = NULL;
1813 }
1814
1815 if (mConstantTablePS)
1816 {
1817 mConstantTablePS->Release();
1818 mConstantTablePS = NULL;
1819 }
1820
1821 if (mConstantTableVS)
1822 {
1823 mConstantTableVS->Release();
1824 mConstantTableVS = NULL;
1825 }
1826
1827 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1828 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001829 mLinkedAttribute[index].clear();
1830 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001831 }
1832
1833 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
1834 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001835 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001836 }
1837
1838 while (!mUniforms.empty())
1839 {
1840 delete mUniforms.back();
1841 mUniforms.pop_back();
1842 }
1843
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001844 delete[] mPixelHLSL;
1845 mPixelHLSL = NULL;
1846
1847 delete[] mVertexHLSL;
1848 mVertexHLSL = NULL;
1849
1850 delete[] mInfoLog;
1851 mInfoLog = NULL;
1852
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001853 mLinked = false;
1854}
1855
1856bool Program::isLinked()
1857{
1858 return mLinked;
1859}
1860
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001861int Program::getInfoLogLength() const
1862{
1863 if (!mInfoLog)
1864 {
1865 return 0;
1866 }
1867 else
1868 {
1869 return strlen(mInfoLog) + 1;
1870 }
1871}
1872
1873void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
1874{
1875 int index = 0;
1876
1877 if (mInfoLog)
1878 {
1879 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
1880 {
1881 infoLog[index] = mInfoLog[index];
1882 index++;
1883 }
1884 }
1885
1886 if (bufSize)
1887 {
1888 infoLog[index] = '\0';
1889 }
1890
1891 if (length)
1892 {
1893 *length = index;
1894 }
1895}
1896
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001897void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
1898{
1899 int total = 0;
1900
1901 if (mVertexShader)
1902 {
1903 if (total < maxCount)
1904 {
1905 shaders[total] = mVertexShader->getHandle();
1906 }
1907
1908 total++;
1909 }
1910
1911 if (mFragmentShader)
1912 {
1913 if (total < maxCount)
1914 {
1915 shaders[total] = mFragmentShader->getHandle();
1916 }
1917
1918 total++;
1919 }
1920
1921 if (count)
1922 {
1923 *count = total;
1924 }
1925}
1926
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001927void Program::flagForDeletion()
1928{
1929 mDeleteStatus = true;
1930}
1931
1932bool Program::isFlaggedForDeletion() const
1933{
1934 return mDeleteStatus;
1935}
1936}