blob: 18a46c0ada9b412506c1b1a3a9f1b7bda76a5720 [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"
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000016#include "libGLESv2/utilities.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000017
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000018namespace gl
19{
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000020Uniform::Uniform(GLenum type, const std::string &name, unsigned int arraySize) : type(type), name(name), arraySize(arraySize)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000021{
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000022 int bytes = UniformTypeSize(type) * arraySize;
23
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000024 this->data = new unsigned char[bytes];
25 memset(this->data, 0, bytes);
26}
27
28Uniform::~Uniform()
29{
30 delete[] data;
31}
32
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +000033UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
34 : name(name), element(element), index(index)
35{
36}
37
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000038Program::Program()
39{
40 mFragmentShader = NULL;
41 mVertexShader = NULL;
42
43 mPixelExecutable = NULL;
44 mVertexExecutable = NULL;
45 mConstantTablePS = NULL;
46 mConstantTableVS = NULL;
47
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +000048 mPixelHLSL = NULL;
49 mVertexHLSL = NULL;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000050 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +000051 mValidated = false;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000052
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000053 unlink();
54
55 mDeleteStatus = false;
56}
57
58Program::~Program()
59{
60 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000061
62 if (mVertexShader != NULL)
63 {
64 mVertexShader->detach();
65 }
66
67 if (mFragmentShader != NULL)
68 {
69 mFragmentShader->detach();
70 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000071}
72
73bool Program::attachShader(Shader *shader)
74{
75 if (shader->getType() == GL_VERTEX_SHADER)
76 {
77 if (mVertexShader)
78 {
79 return false;
80 }
81
82 mVertexShader = (VertexShader*)shader;
83 mVertexShader->attach();
84 }
85 else if (shader->getType() == GL_FRAGMENT_SHADER)
86 {
87 if (mFragmentShader)
88 {
89 return false;
90 }
91
92 mFragmentShader = (FragmentShader*)shader;
93 mFragmentShader->attach();
94 }
95 else UNREACHABLE();
96
97 return true;
98}
99
100bool Program::detachShader(Shader *shader)
101{
102 if (shader->getType() == GL_VERTEX_SHADER)
103 {
104 if (mVertexShader != shader)
105 {
106 return false;
107 }
108
109 mVertexShader->detach();
110 mVertexShader = NULL;
111 }
112 else if (shader->getType() == GL_FRAGMENT_SHADER)
113 {
114 if (mFragmentShader != shader)
115 {
116 return false;
117 }
118
119 mFragmentShader->detach();
120 mFragmentShader = NULL;
121 }
122 else UNREACHABLE();
123
124 unlink();
125
126 return true;
127}
128
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000129int Program::getAttachedShadersCount() const
130{
131 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
132}
133
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000134IDirect3DPixelShader9 *Program::getPixelShader()
135{
136 return mPixelExecutable;
137}
138
139IDirect3DVertexShader9 *Program::getVertexShader()
140{
141 return mVertexExecutable;
142}
143
144void Program::bindAttributeLocation(GLuint index, const char *name)
145{
146 if (index < MAX_VERTEX_ATTRIBS)
147 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000148 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
149 {
150 mAttributeBinding[i].erase(name);
151 }
152
153 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000154 }
155}
156
157GLuint Program::getAttributeLocation(const char *name)
158{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000159 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000160 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000161 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000162 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000163 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000164 {
165 return index;
166 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000167 }
168 }
169
170 return -1;
171}
172
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000173int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000174{
175 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
176 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000177 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000178 }
179
180 return -1;
181}
182
183// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
184// index referenced in the compiled HLSL shader
185GLint Program::getSamplerMapping(unsigned int samplerIndex)
186{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000187 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
188
189 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000190 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000191 return mSamplers[samplerIndex].logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000192 }
193
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000194 return -1;
195}
196
197SamplerType Program::getSamplerType(unsigned int samplerIndex)
198{
199 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
200 assert(mSamplers[samplerIndex].active);
201
202 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000203}
204
205GLint Program::getUniformLocation(const char *name)
206{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000207 std::string nameStr(name);
208 int subscript = 0;
209 size_t beginB = nameStr.find('[');
210 size_t endB = nameStr.find(']');
211 if (beginB != std::string::npos && endB != std::string::npos)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000212 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000213 std::string subscrStr = nameStr.substr(beginB + 1, beginB - endB - 1);
214 nameStr.erase(beginB);
215 subscript = atoi(subscrStr.c_str());
216 }
217
218 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
219 {
220 if (mUniformIndex[location].name == decorate(nameStr) &&
221 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000222 {
223 return location;
224 }
225 }
226
227 return -1;
228}
229
230bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
231{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000232 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000233 {
234 return false;
235 }
236
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000237 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
238
239 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000240 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000241 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000242
243 if (arraySize == 1 && count > 1)
244 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
245
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000246 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000247
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000248 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
249 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000250 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000251 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000252 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000253 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000254
255 if (arraySize == 1 && count > 1)
256 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000257
258 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000259 GLboolean *boolParams = new GLboolean[count];
260
261 for (int i = 0; i < count; ++i)
262 {
263 if (v[i] == 0.0f)
264 {
265 boolParams[i] = GL_FALSE;
266 }
267 else
268 {
269 boolParams[i] = GL_TRUE;
270 }
271 }
272
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000273 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
274 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000275
276 delete [] boolParams;
277 }
278 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279 {
280 return false;
281 }
282
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000283 return true;
284}
285
286bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
287{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000288 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000289 {
290 return false;
291 }
292
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000293 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
294
295 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000296 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000297 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000298
299 if (arraySize == 1 && count > 1)
300 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
301
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000302 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000303
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000304 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
305 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000306 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000307 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000308 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000309 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000310
311 if (arraySize == 1 && count > 1)
312 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
313
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000314 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
315
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000316 GLboolean *boolParams = new GLboolean[count * 2];
317
318 for (int i = 0; i < count * 2; ++i)
319 {
320 if (v[i] == 0.0f)
321 {
322 boolParams[i] = GL_FALSE;
323 }
324 else
325 {
326 boolParams[i] = GL_TRUE;
327 }
328 }
329
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000330 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
331 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000332
333 delete [] boolParams;
334 }
335 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000336 {
337 return false;
338 }
339
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000340 return true;
341}
342
343bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
344{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000345 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000346 {
347 return false;
348 }
349
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000350 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
351
352 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000353 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000354 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000355
356 if (arraySize == 1 && count > 1)
357 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
358
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000359 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000360
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000361 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
362 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000363 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000364 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000365 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000366 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000367
368 if (arraySize == 1 && count > 1)
369 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
370
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000371 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000372 GLboolean *boolParams = new GLboolean[count * 3];
373
374 for (int i = 0; i < count * 3; ++i)
375 {
376 if (v[i] == 0.0f)
377 {
378 boolParams[i] = GL_FALSE;
379 }
380 else
381 {
382 boolParams[i] = GL_TRUE;
383 }
384 }
385
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000386 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
387 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000388
389 delete [] boolParams;
390 }
391 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000392 {
393 return false;
394 }
395
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000396 return true;
397}
398
399bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
400{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000401 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000402 {
403 return false;
404 }
405
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000406 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
407
408 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000409 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000410 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000411
412 if (arraySize == 1 && count > 1)
413 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
414
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000415 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000416
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000417 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
418 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000419 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000420 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000421 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000422 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000423
424 if (arraySize == 1 && count > 1)
425 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
426
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000427 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000428 GLboolean *boolParams = new GLboolean[count * 4];
429
430 for (int i = 0; i < count * 4; ++i)
431 {
432 if (v[i] == 0.0f)
433 {
434 boolParams[i] = GL_FALSE;
435 }
436 else
437 {
438 boolParams[i] = GL_TRUE;
439 }
440 }
441
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000442 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
443 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000444
445 delete [] boolParams;
446 }
447 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 {
449 return false;
450 }
451
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000452 return true;
453}
454
455bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
456{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000457 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000458 {
459 return false;
460 }
461
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000462 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
463
464 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000465 {
466 return false;
467 }
468
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000469 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000470
471 if (arraySize == 1 && count > 1)
472 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
473
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000474 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000475
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000476 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
477 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000478
479 return true;
480}
481
482bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
483{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000484 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000485 {
486 return false;
487 }
488
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000489 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
490
491 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000492 {
493 return false;
494 }
495
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000496 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000497
498 if (arraySize == 1 && count > 1)
499 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
500
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000501 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000502
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000503 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
504 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000505
506 return true;
507}
508
509bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
510{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000511 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000512 {
513 return false;
514 }
515
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000516 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
517
518 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000519 {
520 return false;
521 }
522
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000523 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000524
525 if (arraySize == 1 && count > 1)
526 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
527
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000528 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000529
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000530 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
531 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000532
533 return true;
534}
535
536bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
537{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000538 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000539 {
540 return false;
541 }
542
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000543 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
544
545 if (targetUniform->type == GL_INT)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000546 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000547 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000548
549 if (arraySize == 1 && count > 1)
550 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
551
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000552 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000553
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000554 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
555 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000556 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000557 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000558 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000559 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000560
561 if (arraySize == 1 && count > 1)
562 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
563
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000564 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000565 GLboolean *boolParams = new GLboolean[count];
566
567 for (int i = 0; i < count; ++i)
568 {
569 if (v[i] == 0)
570 {
571 boolParams[i] = GL_FALSE;
572 }
573 else
574 {
575 boolParams[i] = GL_TRUE;
576 }
577 }
578
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000579 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
580 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000581
582 delete [] boolParams;
583 }
584 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000585 {
586 return false;
587 }
588
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000589 return true;
590}
591
592bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
593{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000594 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000595 {
596 return false;
597 }
598
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000599 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
600
601 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000602 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000603 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000604
605 if (arraySize == 1 && count > 1)
606 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
607
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000608 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000609
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000610 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
611 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000612 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000613 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000614 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000615 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000616
617 if (arraySize == 1 && count > 1)
618 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
619
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000620 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000621 GLboolean *boolParams = new GLboolean[count * 2];
622
623 for (int i = 0; i < count * 2; ++i)
624 {
625 if (v[i] == 0)
626 {
627 boolParams[i] = GL_FALSE;
628 }
629 else
630 {
631 boolParams[i] = GL_TRUE;
632 }
633 }
634
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000635 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
636 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000637
638 delete [] boolParams;
639 }
640 else
641 {
642 return false;
643 }
644
645 return true;
646}
647
648bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
649{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000650 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000651 {
652 return false;
653 }
654
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000655 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
656
657 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000658 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000659 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000660
661 if (arraySize == 1 && count > 1)
662 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
663
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000664 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000665
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000666 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
667 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000668 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000669 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000670 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000671 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000672
673 if (arraySize == 1 && count > 1)
674 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
675
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000676 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000677 GLboolean *boolParams = new GLboolean[count * 3];
678
679 for (int i = 0; i < count * 3; ++i)
680 {
681 if (v[i] == 0)
682 {
683 boolParams[i] = GL_FALSE;
684 }
685 else
686 {
687 boolParams[i] = GL_TRUE;
688 }
689 }
690
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000691 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
692 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000693
694 delete [] boolParams;
695 }
696 else
697 {
698 return false;
699 }
700
701 return true;
702}
703
704bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
705{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000706 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000707 {
708 return false;
709 }
710
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000711 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
712
713 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000714 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000715 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000716
717 if (arraySize == 1 && count > 1)
718 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
719
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000720 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000721
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000722 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
723 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000724 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000725 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000726 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000727 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000728
729 if (arraySize == 1 && count > 1)
730 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
731
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000732 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000733 GLboolean *boolParams = new GLboolean[count * 4];
734
735 for (int i = 0; i < count * 4; ++i)
736 {
737 if (v[i] == 0)
738 {
739 boolParams[i] = GL_FALSE;
740 }
741 else
742 {
743 boolParams[i] = GL_TRUE;
744 }
745 }
746
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000747 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
748 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000749
750 delete [] boolParams;
751 }
752 else
753 {
754 return false;
755 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000756
757 return true;
758}
759
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000760bool Program::getUniformfv(GLint location, GLfloat *params)
761{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000762 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000763 {
764 return false;
765 }
766
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000767 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000768
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000769 unsigned int count = UniformComponentCount(targetUniform->type);
770
771 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000772 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000773 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000774 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000775 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000776
777 for (unsigned int i = 0; i < count; ++i)
778 {
779 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
780 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000781 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000782 break;
783 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000784 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
785 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000786 break;
787 case GL_INT:
788 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000789 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000790
791 for (unsigned int i = 0; i < count; ++i)
792 {
793 params[i] = (float)intParams[i];
794 }
795 }
796 break;
797 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000798 }
799
800 return true;
801}
802
803bool Program::getUniformiv(GLint location, GLint *params)
804{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000805 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000806 {
807 return false;
808 }
809
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000810 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000811
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000812 unsigned int count = UniformComponentCount(targetUniform->type);
813
814 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000815 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000816 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000817 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000818 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000819
820 for (unsigned int i = 0; i < count; ++i)
821 {
822 params[i] = (GLint)boolParams[i];
823 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000824 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000825 break;
826 case GL_FLOAT:
827 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000828 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000829
830 for (unsigned int i = 0; i < count; ++i)
831 {
832 params[i] = (GLint)floatParams[i];
833 }
834 }
835 break;
836 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000837 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
838 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000839 break;
840 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000841 }
842
843 return true;
844}
845
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000846// Applies all the uniforms set for this program object to the Direct3D 9 device
847void Program::applyUniforms()
848{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000849 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000850 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000851 if (mUniformIndex[location].element != 0)
852 {
853 continue;
854 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000855
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000856 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
857
858 int arraySize = targetUniform->arraySize;
859 GLfloat *f = (GLfloat*)targetUniform->data;
860 GLint *i = (GLint*)targetUniform->data;
861 GLboolean *b = (GLboolean*)targetUniform->data;
862
863 switch (targetUniform->type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000864 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000865 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
866 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
867 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
868 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
869 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
870 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
871 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
872 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
873 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
874 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
875 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
876 case GL_INT: applyUniform1iv(location, arraySize, i); break;
877 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
878 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
879 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000880 default:
881 UNIMPLEMENTED(); // FIXME
882 UNREACHABLE();
883 }
884 }
885}
886
887// Compiles the HLSL code of the attached shaders into executable binaries
888ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
889{
890 if (!hlsl)
891 {
892 return NULL;
893 }
894
895 ID3DXBuffer *binary = NULL;
896 ID3DXBuffer *errorMessage = NULL;
897
daniel@transgaming.comcbbca002010-04-01 13:39:32 +0000898 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000899
900 if (SUCCEEDED(result))
901 {
902 return binary;
903 }
904
905 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
906 {
907 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
908 }
909
910 if (errorMessage)
911 {
912 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000913
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000914 TRACE("\n%s", hlsl);
915 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000916 }
917
918 return NULL;
919}
920
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000921void Program::parseVaryings(const char *structure, char *hlsl, VaryingArray &varyings)
922{
923 char *input = strstr(hlsl, structure);
924 input += strlen(structure);
925
926 while (input && *input != '}')
927 {
928 char varyingType[256];
929 char varyingName[256];
930 unsigned int semanticIndex;
931 int matches = sscanf(input, " %s %s : TEXCOORD%d;", varyingType, varyingName, &semanticIndex);
932
933 if (matches == 3)
934 {
935 ASSERT(semanticIndex <= 9); // Single character
936
937 varyings.push_back(Varying(varyingName, input));
938 }
939
940 input = strstr(input, ";");
941 input += 2;
942 }
943}
944
945bool Program::linkVaryings()
946{
947 if (!mPixelHLSL || !mVertexHLSL)
948 {
949 return false;
950 }
951
952 VaryingArray vertexVaryings;
953 VaryingArray pixelVaryings;
954
955 parseVaryings("struct VS_OUTPUT\n{\n", mVertexHLSL, vertexVaryings);
956 parseVaryings("struct PS_INPUT\n{\n", mPixelHLSL, pixelVaryings);
957
958 for (unsigned int out = 0; out < vertexVaryings.size(); out++)
959 {
960 unsigned int in;
961 for (in = 0; in < pixelVaryings.size(); in++)
962 {
963 if (vertexVaryings[out].name == pixelVaryings[in].name)
964 {
965 pixelVaryings[in].link = out;
966 vertexVaryings[out].link = in;
967
968 break;
969 }
970 }
971
972 if (in != pixelVaryings.size())
973 {
974 // FIXME: Verify matching type and qualifiers
975
976 char *outputSemantic = strstr(vertexVaryings[out].declaration, " : TEXCOORD");
977 char *inputSemantic = strstr(pixelVaryings[in].declaration, " : TEXCOORD");
978 outputSemantic[11] = inputSemantic[11];
979 }
980 else
981 {
982 // Comment out the declaration and output assignment
983 vertexVaryings[out].declaration[0] = '/';
984 vertexVaryings[out].declaration[1] = '/';
985
986 char outputString[256];
987 sprintf(outputString, " output.%s = ", vertexVaryings[out].name.c_str());
988 char *varyingOutput = strstr(mVertexHLSL, outputString);
989
990 varyingOutput[0] = '/';
991 varyingOutput[1] = '/';
992 }
993 }
994
995 // Verify that each pixel varying has been linked to a vertex varying
996 for (unsigned int in = 0; in < pixelVaryings.size(); in++)
997 {
998 if (pixelVaryings[in].link < 0)
999 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001000 appendToInfoLog("Pixel varying (%s) does not match any vertex varying", pixelVaryings[in].name);
1001
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001002 return false;
1003 }
1004 }
1005
1006 return true;
1007}
1008
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001009// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1010// compiling them into binaries, determining the attribute mappings, and collecting
1011// a list of uniforms
1012void Program::link()
1013{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001014 unlink();
1015
1016 if (!mFragmentShader || !mFragmentShader->isCompiled())
1017 {
1018 return;
1019 }
1020
1021 if (!mVertexShader || !mVertexShader->isCompiled())
1022 {
1023 return;
1024 }
1025
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001026 Context *context = getContext();
1027 const char *vertexProfile = context->getVertexShaderProfile();
1028 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +00001029
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001030 const char *ps = mFragmentShader->getHLSL();
1031 const char *vs = mVertexShader->getHLSL();
1032
1033 mPixelHLSL = new char[strlen(ps) + 1];
1034 strcpy(mPixelHLSL, ps);
1035 mVertexHLSL = new char[strlen(vs) + 1];
1036 strcpy(mVertexHLSL, vs);
1037
1038 if (!linkVaryings())
1039 {
1040 return;
1041 }
1042
1043 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL, vertexProfile, &mConstantTableVS);
1044 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001045
1046 if (vertexBinary && pixelBinary)
1047 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001048 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001049 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1050 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1051
1052 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1053 {
1054 return error(GL_OUT_OF_MEMORY);
1055 }
1056
1057 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001058
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001059 vertexBinary->Release();
1060 pixelBinary->Release();
1061 vertexBinary = NULL;
1062 pixelBinary = NULL;
1063
1064 if (mVertexExecutable && mPixelExecutable)
1065 {
1066 if (!linkAttributes())
1067 {
1068 return;
1069 }
1070
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001071 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001072 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001073 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001074 }
1075
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001076 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001077 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001078 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001079 }
1080
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001081 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001082 }
1083 }
1084}
1085
1086// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1087bool Program::linkAttributes()
1088{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001089 unsigned int usedLocations = 0;
1090
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001091 // Link attributes that have a binding location
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001092 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1093 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001094 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1095 int location = getAttributeBinding(attribute.name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001096
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001097 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001098 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001099 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001100 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001101 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001102 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001103
daniel@transgaming.com85423182010-04-22 13:35:27 +00001104 mLinkedAttribute[location] = attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001105
1106 int size = AttributeVectorCount(attribute.type);
1107
1108 if (size + location > MAX_VERTEX_ATTRIBS)
1109 {
1110 appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
1111
1112 return false;
1113 }
1114
1115 for (int i = 0; i < size; i++)
1116 {
1117 usedLocations |= 1 << (location + i);
1118 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001119 }
1120 }
1121
1122 // Link attributes that don't have a binding location
1123 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS + 1; attributeIndex++)
1124 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001125 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1126 int location = getAttributeBinding(attribute.name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001127
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001128 if (!attribute.name.empty() && location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001129 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001130 int size = AttributeVectorCount(attribute.type);
1131 int availableIndex = AllocateFirstFreeBits(&usedLocations, size, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001132
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001133 if (availableIndex == -1 || availableIndex + size > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001134 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001135 appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001136
1137 return false; // Fail to link
1138 }
1139
daniel@transgaming.com85423182010-04-22 13:35:27 +00001140 mLinkedAttribute[availableIndex] = attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001141 }
1142 }
1143
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001144 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001145 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001146 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1147
1148 if (index == -1)
1149 {
1150 mSemanticIndex[attributeIndex++] = -1;
1151 }
1152 else
1153 {
1154 int size = AttributeVectorCount(mVertexShader->getAttribute(index).type);
1155
1156 for (int i = 0; i < size; i++)
1157 {
1158 mSemanticIndex[attributeIndex++] = index++;
1159 }
1160 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001161 }
1162
1163 return true;
1164}
1165
daniel@transgaming.com85423182010-04-22 13:35:27 +00001166int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001167{
1168 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1169 {
1170 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1171 {
1172 return location;
1173 }
1174 }
1175
1176 return -1;
1177}
1178
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001179bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1180{
1181 D3DXCONSTANTTABLE_DESC constantTableDescription;
1182 D3DXCONSTANT_DESC constantDescription;
1183 UINT descriptionCount = 1;
1184
1185 constantTable->GetDesc(&constantTableDescription);
1186
1187 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1188 {
1189 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1190 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1191
1192 if (!defineUniform(constantHandle, constantDescription))
1193 {
1194 return false;
1195 }
1196 }
1197
1198 return true;
1199}
1200
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001201// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001202// Returns true if succesful (uniform not already defined)
1203bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1204{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001205 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1206 {
1207 unsigned int samplerIndex = constantDescription.RegisterIndex;
1208
1209 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1210
1211 mSamplers[samplerIndex].active = true;
1212 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1213 mSamplers[samplerIndex].logicalTextureUnit = 0;
1214 }
1215
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001216 switch(constantDescription.Class)
1217 {
1218 case D3DXPC_STRUCT:
1219 {
1220 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1221 {
1222 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1223
1224 D3DXCONSTANT_DESC fieldDescription;
1225 UINT descriptionCount = 1;
1226
1227 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1228
1229 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1230 {
1231 return false;
1232 }
1233 }
1234
1235 return true;
1236 }
1237 case D3DXPC_SCALAR:
1238 case D3DXPC_VECTOR:
1239 case D3DXPC_MATRIX_COLUMNS:
1240 case D3DXPC_OBJECT:
1241 return defineUniform(constantDescription, name + constantDescription.Name);
1242 default:
1243 UNREACHABLE();
1244 return false;
1245 }
1246}
1247
1248bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1249{
1250 Uniform *uniform = createUniform(constantDescription, name);
1251
1252 if(!uniform)
1253 {
1254 return false;
1255 }
1256
1257 // Check if already defined
1258 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001259 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001260
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001261 if (location >= 0)
1262 {
1263 delete uniform;
1264
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001265 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001266 {
1267 return false;
1268 }
1269 else
1270 {
1271 return true;
1272 }
1273 }
1274
1275 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001276 unsigned int uniformIndex = mUniforms.size() - 1;
1277
1278 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1279 {
1280 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1281 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001282
1283 return true;
1284}
1285
1286Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001287{
1288 if (constantDescription.Rows == 1) // Vectors and scalars
1289 {
1290 switch (constantDescription.Type)
1291 {
1292 case D3DXPT_SAMPLER2D:
1293 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001294 switch (constantDescription.Columns)
1295 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001296 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001297 default: UNREACHABLE();
1298 }
1299 break;
1300 case D3DXPT_BOOL:
1301 switch (constantDescription.Columns)
1302 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001303 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1304 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1305 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1306 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001307 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001308 }
1309 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001310 case D3DXPT_INT:
1311 switch (constantDescription.Columns)
1312 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001313 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1314 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1315 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1316 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001317 default: UNREACHABLE();
1318 }
1319 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001320 case D3DXPT_FLOAT:
1321 switch (constantDescription.Columns)
1322 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001323 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1324 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1325 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1326 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001327 default: UNREACHABLE();
1328 }
1329 break;
1330 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001331 UNREACHABLE();
1332 }
1333 }
1334 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1335 {
1336 switch (constantDescription.Type)
1337 {
1338 case D3DXPT_FLOAT:
1339 switch (constantDescription.Rows)
1340 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001341 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1342 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1343 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001344 default: UNREACHABLE();
1345 }
1346 break;
1347 default: UNREACHABLE();
1348 }
1349 }
1350 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001351
1352 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001353}
1354
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001355// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001356std::string Program::decorate(const std::string &string)
1357{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001358 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001359 {
1360 return "_" + string;
1361 }
1362 else
1363 {
1364 return string;
1365 }
1366}
1367
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001368std::string Program::undecorate(const std::string &string)
1369{
1370 if (string.substr(0, 1) == "_")
1371 {
1372 return string.substr(1);
1373 }
1374 else
1375 {
1376 return string;
1377 }
1378}
1379
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001380bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1381{
1382 BOOL *vector = new BOOL[count];
1383 for (int i = 0; i < count; i++)
1384 {
1385 if (v[i] == GL_FALSE)
1386 vector[i] = 0;
1387 else
1388 vector[i] = 1;
1389 }
1390
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001391 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1392
1393 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1394 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001395 IDirect3DDevice9 *device = getDevice();
1396
1397 if (constantPS)
1398 {
1399 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1400 }
1401
1402 if (constantVS)
1403 {
1404 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1405 }
1406
1407 delete [] vector;
1408
1409 return true;
1410}
1411
1412bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1413{
1414 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1415
1416 for (int i = 0; i < count; i++)
1417 {
1418 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1419 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1420
1421 v += 2;
1422 }
1423
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001424 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1425
1426 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1427 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001428 IDirect3DDevice9 *device = getDevice();
1429
1430 if (constantPS)
1431 {
1432 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1433 }
1434
1435 if (constantVS)
1436 {
1437 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1438 }
1439
1440 delete[] vector;
1441
1442 return true;
1443}
1444
1445bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1446{
1447 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1448
1449 for (int i = 0; i < count; i++)
1450 {
1451 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1452 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1453 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1454
1455 v += 3;
1456 }
1457
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001458 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1459
1460 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1461 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001462 IDirect3DDevice9 *device = getDevice();
1463
1464 if (constantPS)
1465 {
1466 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1467 }
1468
1469 if (constantVS)
1470 {
1471 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1472 }
1473
1474 delete[] vector;
1475
1476 return true;
1477}
1478
1479bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1480{
1481 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1482
1483 for (int i = 0; i < count; i++)
1484 {
1485 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1486 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1487 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1488 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1489
1490 v += 3;
1491 }
1492
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001493 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1494
1495 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1496 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001497 IDirect3DDevice9 *device = getDevice();
1498
1499 if (constantPS)
1500 {
1501 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1502 }
1503
1504 if (constantVS)
1505 {
1506 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1507 }
1508
1509 delete [] vector;
1510
1511 return true;
1512}
1513
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001514bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1515{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001516 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1517
1518 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1519 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001520 IDirect3DDevice9 *device = getDevice();
1521
1522 if (constantPS)
1523 {
1524 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1525 }
1526
1527 if (constantVS)
1528 {
1529 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1530 }
1531
1532 return true;
1533}
1534
1535bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1536{
1537 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1538
1539 for (int i = 0; i < count; i++)
1540 {
1541 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1542
1543 v += 2;
1544 }
1545
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001546 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1547
1548 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1549 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001550 IDirect3DDevice9 *device = getDevice();
1551
1552 if (constantPS)
1553 {
1554 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1555 }
1556
1557 if (constantVS)
1558 {
1559 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1560 }
1561
1562 delete[] vector;
1563
1564 return true;
1565}
1566
1567bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1568{
1569 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1570
1571 for (int i = 0; i < count; i++)
1572 {
1573 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1574
1575 v += 3;
1576 }
1577
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001578 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1579
1580 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1581 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001582 IDirect3DDevice9 *device = getDevice();
1583
1584 if (constantPS)
1585 {
1586 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1587 }
1588
1589 if (constantVS)
1590 {
1591 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1592 }
1593
1594 delete[] vector;
1595
1596 return true;
1597}
1598
1599bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1600{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001601 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1602
1603 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1604 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001605 IDirect3DDevice9 *device = getDevice();
1606
1607 if (constantPS)
1608 {
1609 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
1610 }
1611
1612 if (constantVS)
1613 {
1614 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
1615 }
1616
1617 return true;
1618}
1619
1620bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
1621{
1622 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1623
1624 for (int i = 0; i < count; i++)
1625 {
1626 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
1627 value[1], value[3], 0, 0,
1628 0, 0, 1, 0,
1629 0, 0, 0, 1);
1630
1631 value += 4;
1632 }
1633
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001634 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1635
1636 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1637 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001638 IDirect3DDevice9 *device = getDevice();
1639
1640 if (constantPS)
1641 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001642 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001643 }
1644
1645 if (constantVS)
1646 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001647 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001648 }
1649
1650 delete[] matrix;
1651
1652 return true;
1653}
1654
1655bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
1656{
1657 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1658
1659 for (int i = 0; i < count; i++)
1660 {
1661 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
1662 value[1], value[4], value[7], 0,
1663 value[2], value[5], value[8], 0,
1664 0, 0, 0, 1);
1665
1666 value += 9;
1667 }
1668
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001669 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1670
1671 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1672 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001673 IDirect3DDevice9 *device = getDevice();
1674
1675 if (constantPS)
1676 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001677 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001678 }
1679
1680 if (constantVS)
1681 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001682 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001683 }
1684
1685 delete[] matrix;
1686
1687 return true;
1688}
1689
1690bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
1691{
1692 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1693
1694 for (int i = 0; i < count; i++)
1695 {
1696 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
1697 value[1], value[5], value[9], value[13],
1698 value[2], value[6], value[10], value[14],
1699 value[3], value[7], value[11], value[15]);
1700
1701 value += 16;
1702 }
1703
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001704 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1705
1706 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1707 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001708 IDirect3DDevice9 *device = getDevice();
1709
1710 if (constantPS)
1711 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001712 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001713 }
1714
1715 if (constantVS)
1716 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001717 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001718 }
1719
1720 delete[] matrix;
1721
1722 return true;
1723}
1724
1725bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
1726{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001727 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1728
1729 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1730 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001731 IDirect3DDevice9 *device = getDevice();
1732
1733 if (constantPS)
1734 {
1735 D3DXCONSTANT_DESC constantDescription;
1736 UINT descriptionCount = 1;
1737 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
1738
daniel@transgaming.com2884b782010-03-08 21:30:48 +00001739 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001740 {
1741 return false;
1742 }
1743
1744 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1745 {
1746 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
1747
1748 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
1749 {
1750 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001751
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001752 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
1753 {
1754 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1755 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001756 ASSERT(mSamplers[samplerIndex].active);
1757 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001758 }
1759 }
1760 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001761
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001762 return true;
1763 }
1764 }
1765
1766 if (constantPS)
1767 {
1768 mConstantTablePS->SetIntArray(device, constantPS, v, count);
1769 }
1770
1771 if (constantVS)
1772 {
1773 mConstantTableVS->SetIntArray(device, constantVS, v, count);
1774 }
1775
1776 return true;
1777}
1778
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001779bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
1780{
1781 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1782
1783 for (int i = 0; i < count; i++)
1784 {
1785 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
1786
1787 v += 2;
1788 }
1789
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001790 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1791
1792 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1793 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001794 IDirect3DDevice9 *device = getDevice();
1795
1796 if (constantPS)
1797 {
1798 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1799 }
1800
1801 if (constantVS)
1802 {
1803 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1804 }
1805
1806 delete[] vector;
1807
1808 return true;
1809}
1810
1811bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
1812{
1813 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1814
1815 for (int i = 0; i < count; i++)
1816 {
1817 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
1818
1819 v += 3;
1820 }
1821
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001822 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1823
1824 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1825 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001826 IDirect3DDevice9 *device = getDevice();
1827
1828 if (constantPS)
1829 {
1830 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1831 }
1832
1833 if (constantVS)
1834 {
1835 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1836 }
1837
1838 delete[] vector;
1839
1840 return true;
1841}
1842
1843bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
1844{
1845 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1846
1847 for (int i = 0; i < count; i++)
1848 {
1849 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
1850
1851 v += 4;
1852 }
1853
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001854 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1855
1856 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1857 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001858 IDirect3DDevice9 *device = getDevice();
1859
1860 if (constantPS)
1861 {
1862 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1863 }
1864
1865 if (constantVS)
1866 {
1867 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1868 }
1869
1870 delete [] vector;
1871
1872 return true;
1873}
1874
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001875void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001876{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001877 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001878 {
1879 return;
1880 }
1881
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001882 char info[1024];
1883
1884 va_list vararg;
1885 va_start(vararg, format);
1886 vsnprintf(info, sizeof(info), format, vararg);
1887 va_end(vararg);
1888
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001889 size_t infoLength = strlen(info);
1890
1891 if (!mInfoLog)
1892 {
1893 mInfoLog = new char[infoLength + 1];
1894 strcpy(mInfoLog, info);
1895 }
1896 else
1897 {
1898 size_t logLength = strlen(mInfoLog);
1899 char *newLog = new char[logLength + infoLength + 1];
1900 strcpy(newLog, mInfoLog);
1901 strcpy(newLog + logLength, info);
1902
1903 delete[] mInfoLog;
1904 mInfoLog = newLog;
1905 }
1906}
1907
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001908void Program::resetInfoLog()
1909{
1910 if (mInfoLog)
1911 {
1912 delete [] mInfoLog;
1913 }
1914}
1915
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001916// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
1917void Program::unlink(bool destroy)
1918{
1919 if (destroy) // Object being destructed
1920 {
1921 if (mFragmentShader)
1922 {
1923 mFragmentShader->detach();
1924 mFragmentShader = NULL;
1925 }
1926
1927 if (mVertexShader)
1928 {
1929 mVertexShader->detach();
1930 mVertexShader = NULL;
1931 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001932 }
1933
1934 if (mPixelExecutable)
1935 {
1936 mPixelExecutable->Release();
1937 mPixelExecutable = NULL;
1938 }
1939
1940 if (mVertexExecutable)
1941 {
1942 mVertexExecutable->Release();
1943 mVertexExecutable = NULL;
1944 }
1945
1946 if (mConstantTablePS)
1947 {
1948 mConstantTablePS->Release();
1949 mConstantTablePS = NULL;
1950 }
1951
1952 if (mConstantTableVS)
1953 {
1954 mConstantTableVS->Release();
1955 mConstantTableVS = NULL;
1956 }
1957
1958 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1959 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001960 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001961 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001962 }
1963
1964 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
1965 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001966 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001967 }
1968
1969 while (!mUniforms.empty())
1970 {
1971 delete mUniforms.back();
1972 mUniforms.pop_back();
1973 }
1974
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001975 mUniformIndex.clear();
1976
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001977 delete[] mPixelHLSL;
1978 mPixelHLSL = NULL;
1979
1980 delete[] mVertexHLSL;
1981 mVertexHLSL = NULL;
1982
1983 delete[] mInfoLog;
1984 mInfoLog = NULL;
1985
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001986 mLinked = false;
1987}
1988
1989bool Program::isLinked()
1990{
1991 return mLinked;
1992}
1993
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001994bool Program::isValidated() const
1995{
1996 return mValidated;
1997}
1998
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001999int Program::getInfoLogLength() const
2000{
2001 if (!mInfoLog)
2002 {
2003 return 0;
2004 }
2005 else
2006 {
2007 return strlen(mInfoLog) + 1;
2008 }
2009}
2010
2011void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2012{
2013 int index = 0;
2014
2015 if (mInfoLog)
2016 {
2017 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2018 {
2019 infoLog[index] = mInfoLog[index];
2020 index++;
2021 }
2022 }
2023
2024 if (bufSize)
2025 {
2026 infoLog[index] = '\0';
2027 }
2028
2029 if (length)
2030 {
2031 *length = index;
2032 }
2033}
2034
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002035void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2036{
2037 int total = 0;
2038
2039 if (mVertexShader)
2040 {
2041 if (total < maxCount)
2042 {
2043 shaders[total] = mVertexShader->getHandle();
2044 }
2045
2046 total++;
2047 }
2048
2049 if (mFragmentShader)
2050 {
2051 if (total < maxCount)
2052 {
2053 shaders[total] = mFragmentShader->getHandle();
2054 }
2055
2056 total++;
2057 }
2058
2059 if (count)
2060 {
2061 *count = total;
2062 }
2063}
2064
daniel@transgaming.com85423182010-04-22 13:35:27 +00002065void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2066{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002067 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002068 for (unsigned int i = 0; i < index; i++)
2069 {
2070 do
2071 {
2072 attribute++;
2073
2074 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2075 }
2076 while (mLinkedAttribute[attribute].name.empty());
2077 }
2078
2079 if (bufsize > 0)
2080 {
2081 const char *string = mLinkedAttribute[attribute].name.c_str();
2082
2083 strncpy(name, string, bufsize);
2084 name[bufsize - 1] = '\0';
2085
2086 if (length)
2087 {
2088 *length = strlen(name);
2089 }
2090 }
2091
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002092 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002093
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002094 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002095}
2096
2097GLint Program::getActiveAttributeCount()
2098{
2099 int count = 0;
2100
2101 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2102 {
2103 if (!mLinkedAttribute[attributeIndex].name.empty())
2104 {
2105 count++;
2106 }
2107 }
2108
2109 return count;
2110}
2111
2112GLint Program::getActiveAttributeMaxLength()
2113{
2114 int maxLength = 0;
2115
2116 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2117 {
2118 if (!mLinkedAttribute[attributeIndex].name.empty())
2119 {
2120 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2121 }
2122 }
2123
2124 return maxLength;
2125}
2126
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002127void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2128{
2129 unsigned int uniform = 0;
2130 for (unsigned int i = 0; i < index; i++)
2131 {
2132 do
2133 {
2134 uniform++;
2135
2136 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2137 }
2138 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2139 }
2140
2141 if (bufsize > 0)
2142 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002143 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002144
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002145 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002146 name[bufsize - 1] = '\0';
2147
2148 if (length)
2149 {
2150 *length = strlen(name);
2151 }
2152 }
2153
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002154 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002155
2156 *type = mUniforms[uniform]->type;
2157}
2158
2159GLint Program::getActiveUniformCount()
2160{
2161 int count = 0;
2162
2163 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2164 {
2165 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2166 {
2167 count++;
2168 }
2169 }
2170
2171 return count;
2172}
2173
2174GLint Program::getActiveUniformMaxLength()
2175{
2176 int maxLength = 0;
2177
2178 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2179 {
2180 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2181 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002182 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002183 }
2184 }
2185
2186 return maxLength;
2187}
2188
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002189void Program::flagForDeletion()
2190{
2191 mDeleteStatus = true;
2192}
2193
2194bool Program::isFlaggedForDeletion() const
2195{
2196 return mDeleteStatus;
2197}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002198
2199void Program::validate()
2200{
2201 resetInfoLog();
2202
2203 if (!isLinked())
2204 {
2205 appendToInfoLog("Program has not been successfully linked.");
2206 mValidated = false;
2207 }
2208 else if (!validateSamplers())
2209 {
2210 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2211 mValidated = false;
2212 }
2213 else
2214 {
2215 mValidated = true;
2216 }
2217}
2218
2219bool Program::validateSamplers() const
2220{
2221 // if any two active samplers in a program are of different types, but refer to the same
2222 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2223 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2224 std::map<int, SamplerType> samplerMap;
2225 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2226 {
2227 if (mSamplers[i].active)
2228 {
2229 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2230 {
2231 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2232 return false;
2233 }
2234 else
2235 {
2236 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2237 }
2238 }
2239 }
2240
2241 return true;
2242}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002243}