blob: a9086fbf9c1c86f020a046e22aecfb70d26a9f1f [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;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000931
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000932 int matches = sscanf(input, " %s %s : TEXCOORD%d;", varyingType, varyingName, &semanticIndex);
933
934 if (matches == 3)
935 {
936 ASSERT(semanticIndex <= 9); // Single character
937
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000938 char *array = strstr(varyingName, "[");
939
940 if (array)
941 {
942 *array = '\0';
943 }
944
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000945 varyings.push_back(Varying(varyingName, input));
946 }
947
948 input = strstr(input, ";");
949 input += 2;
950 }
951}
952
953bool Program::linkVaryings()
954{
955 if (!mPixelHLSL || !mVertexHLSL)
956 {
957 return false;
958 }
959
960 VaryingArray vertexVaryings;
961 VaryingArray pixelVaryings;
962
963 parseVaryings("struct VS_OUTPUT\n{\n", mVertexHLSL, vertexVaryings);
964 parseVaryings("struct PS_INPUT\n{\n", mPixelHLSL, pixelVaryings);
965
966 for (unsigned int out = 0; out < vertexVaryings.size(); out++)
967 {
968 unsigned int in;
969 for (in = 0; in < pixelVaryings.size(); in++)
970 {
971 if (vertexVaryings[out].name == pixelVaryings[in].name)
972 {
973 pixelVaryings[in].link = out;
974 vertexVaryings[out].link = in;
975
976 break;
977 }
978 }
979
980 if (in != pixelVaryings.size())
981 {
982 // FIXME: Verify matching type and qualifiers
983
984 char *outputSemantic = strstr(vertexVaryings[out].declaration, " : TEXCOORD");
985 char *inputSemantic = strstr(pixelVaryings[in].declaration, " : TEXCOORD");
986 outputSemantic[11] = inputSemantic[11];
987 }
988 else
989 {
990 // Comment out the declaration and output assignment
991 vertexVaryings[out].declaration[0] = '/';
992 vertexVaryings[out].declaration[1] = '/';
993
994 char outputString[256];
995 sprintf(outputString, " output.%s = ", vertexVaryings[out].name.c_str());
996 char *varyingOutput = strstr(mVertexHLSL, outputString);
997
998 varyingOutput[0] = '/';
999 varyingOutput[1] = '/';
1000 }
1001 }
1002
1003 // Verify that each pixel varying has been linked to a vertex varying
1004 for (unsigned int in = 0; in < pixelVaryings.size(); in++)
1005 {
1006 if (pixelVaryings[in].link < 0)
1007 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001008 appendToInfoLog("Pixel varying (%s) does not match any vertex varying", pixelVaryings[in].name);
1009
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001010 return false;
1011 }
1012 }
1013
1014 return true;
1015}
1016
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001017// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1018// compiling them into binaries, determining the attribute mappings, and collecting
1019// a list of uniforms
1020void Program::link()
1021{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001022 unlink();
1023
1024 if (!mFragmentShader || !mFragmentShader->isCompiled())
1025 {
1026 return;
1027 }
1028
1029 if (!mVertexShader || !mVertexShader->isCompiled())
1030 {
1031 return;
1032 }
1033
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001034 Context *context = getContext();
1035 const char *vertexProfile = context->getVertexShaderProfile();
1036 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +00001037
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001038 const char *ps = mFragmentShader->getHLSL();
1039 const char *vs = mVertexShader->getHLSL();
1040
1041 mPixelHLSL = new char[strlen(ps) + 1];
1042 strcpy(mPixelHLSL, ps);
1043 mVertexHLSL = new char[strlen(vs) + 1];
1044 strcpy(mVertexHLSL, vs);
1045
1046 if (!linkVaryings())
1047 {
1048 return;
1049 }
1050
1051 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL, vertexProfile, &mConstantTableVS);
1052 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001053
1054 if (vertexBinary && pixelBinary)
1055 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001056 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001057 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1058 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1059
1060 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1061 {
1062 return error(GL_OUT_OF_MEMORY);
1063 }
1064
1065 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001066
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001067 vertexBinary->Release();
1068 pixelBinary->Release();
1069 vertexBinary = NULL;
1070 pixelBinary = NULL;
1071
1072 if (mVertexExecutable && mPixelExecutable)
1073 {
1074 if (!linkAttributes())
1075 {
1076 return;
1077 }
1078
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001079 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001080 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001081 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001082 }
1083
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001084 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001085 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001086 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001087 }
1088
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001089 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001090 }
1091 }
1092}
1093
1094// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1095bool Program::linkAttributes()
1096{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001097 unsigned int usedLocations = 0;
1098
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001099 // Link attributes that have a binding location
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001100 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1101 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001102 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1103 int location = getAttributeBinding(attribute.name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001104
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001105 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001106 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001107 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001108 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001109 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001110 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001111
daniel@transgaming.com85423182010-04-22 13:35:27 +00001112 mLinkedAttribute[location] = attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001113
1114 int size = AttributeVectorCount(attribute.type);
1115
1116 if (size + location > MAX_VERTEX_ATTRIBS)
1117 {
1118 appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
1119
1120 return false;
1121 }
1122
1123 for (int i = 0; i < size; i++)
1124 {
1125 usedLocations |= 1 << (location + i);
1126 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001127 }
1128 }
1129
1130 // Link attributes that don't have a binding location
1131 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS + 1; attributeIndex++)
1132 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001133 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1134 int location = getAttributeBinding(attribute.name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001135
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001136 if (!attribute.name.empty() && location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001137 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001138 int size = AttributeVectorCount(attribute.type);
1139 int availableIndex = AllocateFirstFreeBits(&usedLocations, size, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001140
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001141 if (availableIndex == -1 || availableIndex + size > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001142 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001143 appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001144
1145 return false; // Fail to link
1146 }
1147
daniel@transgaming.com85423182010-04-22 13:35:27 +00001148 mLinkedAttribute[availableIndex] = attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001149 }
1150 }
1151
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001152 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001153 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001154 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1155
1156 if (index == -1)
1157 {
1158 mSemanticIndex[attributeIndex++] = -1;
1159 }
1160 else
1161 {
1162 int size = AttributeVectorCount(mVertexShader->getAttribute(index).type);
1163
1164 for (int i = 0; i < size; i++)
1165 {
1166 mSemanticIndex[attributeIndex++] = index++;
1167 }
1168 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001169 }
1170
1171 return true;
1172}
1173
daniel@transgaming.com85423182010-04-22 13:35:27 +00001174int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001175{
1176 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1177 {
1178 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1179 {
1180 return location;
1181 }
1182 }
1183
1184 return -1;
1185}
1186
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001187bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1188{
1189 D3DXCONSTANTTABLE_DESC constantTableDescription;
1190 D3DXCONSTANT_DESC constantDescription;
1191 UINT descriptionCount = 1;
1192
1193 constantTable->GetDesc(&constantTableDescription);
1194
1195 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1196 {
1197 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1198 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1199
1200 if (!defineUniform(constantHandle, constantDescription))
1201 {
1202 return false;
1203 }
1204 }
1205
1206 return true;
1207}
1208
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001209// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001210// Returns true if succesful (uniform not already defined)
1211bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1212{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001213 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1214 {
1215 unsigned int samplerIndex = constantDescription.RegisterIndex;
1216
1217 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1218
1219 mSamplers[samplerIndex].active = true;
1220 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1221 mSamplers[samplerIndex].logicalTextureUnit = 0;
1222 }
1223
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001224 switch(constantDescription.Class)
1225 {
1226 case D3DXPC_STRUCT:
1227 {
1228 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1229 {
1230 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1231
1232 D3DXCONSTANT_DESC fieldDescription;
1233 UINT descriptionCount = 1;
1234
1235 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1236
1237 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1238 {
1239 return false;
1240 }
1241 }
1242
1243 return true;
1244 }
1245 case D3DXPC_SCALAR:
1246 case D3DXPC_VECTOR:
1247 case D3DXPC_MATRIX_COLUMNS:
1248 case D3DXPC_OBJECT:
1249 return defineUniform(constantDescription, name + constantDescription.Name);
1250 default:
1251 UNREACHABLE();
1252 return false;
1253 }
1254}
1255
1256bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1257{
1258 Uniform *uniform = createUniform(constantDescription, name);
1259
1260 if(!uniform)
1261 {
1262 return false;
1263 }
1264
1265 // Check if already defined
1266 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001267 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001268
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001269 if (location >= 0)
1270 {
1271 delete uniform;
1272
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001273 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001274 {
1275 return false;
1276 }
1277 else
1278 {
1279 return true;
1280 }
1281 }
1282
1283 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001284 unsigned int uniformIndex = mUniforms.size() - 1;
1285
1286 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1287 {
1288 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1289 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001290
1291 return true;
1292}
1293
1294Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001295{
1296 if (constantDescription.Rows == 1) // Vectors and scalars
1297 {
1298 switch (constantDescription.Type)
1299 {
1300 case D3DXPT_SAMPLER2D:
1301 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001302 switch (constantDescription.Columns)
1303 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001304 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001305 default: UNREACHABLE();
1306 }
1307 break;
1308 case D3DXPT_BOOL:
1309 switch (constantDescription.Columns)
1310 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001311 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1312 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1313 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1314 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001315 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001316 }
1317 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001318 case D3DXPT_INT:
1319 switch (constantDescription.Columns)
1320 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001321 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1322 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1323 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1324 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001325 default: UNREACHABLE();
1326 }
1327 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001328 case D3DXPT_FLOAT:
1329 switch (constantDescription.Columns)
1330 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001331 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1332 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1333 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1334 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001335 default: UNREACHABLE();
1336 }
1337 break;
1338 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001339 UNREACHABLE();
1340 }
1341 }
1342 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1343 {
1344 switch (constantDescription.Type)
1345 {
1346 case D3DXPT_FLOAT:
1347 switch (constantDescription.Rows)
1348 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001349 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1350 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1351 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001352 default: UNREACHABLE();
1353 }
1354 break;
1355 default: UNREACHABLE();
1356 }
1357 }
1358 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001359
1360 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001361}
1362
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001363// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001364std::string Program::decorate(const std::string &string)
1365{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001366 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001367 {
1368 return "_" + string;
1369 }
1370 else
1371 {
1372 return string;
1373 }
1374}
1375
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001376std::string Program::undecorate(const std::string &string)
1377{
1378 if (string.substr(0, 1) == "_")
1379 {
1380 return string.substr(1);
1381 }
1382 else
1383 {
1384 return string;
1385 }
1386}
1387
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001388bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1389{
1390 BOOL *vector = new BOOL[count];
1391 for (int i = 0; i < count; i++)
1392 {
1393 if (v[i] == GL_FALSE)
1394 vector[i] = 0;
1395 else
1396 vector[i] = 1;
1397 }
1398
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001399 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1400
1401 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1402 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001403 IDirect3DDevice9 *device = getDevice();
1404
1405 if (constantPS)
1406 {
1407 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1408 }
1409
1410 if (constantVS)
1411 {
1412 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1413 }
1414
1415 delete [] vector;
1416
1417 return true;
1418}
1419
1420bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1421{
1422 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1423
1424 for (int i = 0; i < count; i++)
1425 {
1426 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1427 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1428
1429 v += 2;
1430 }
1431
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001432 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1433
1434 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1435 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001436 IDirect3DDevice9 *device = getDevice();
1437
1438 if (constantPS)
1439 {
1440 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1441 }
1442
1443 if (constantVS)
1444 {
1445 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1446 }
1447
1448 delete[] vector;
1449
1450 return true;
1451}
1452
1453bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1454{
1455 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1456
1457 for (int i = 0; i < count; i++)
1458 {
1459 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1460 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1461 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1462
1463 v += 3;
1464 }
1465
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001466 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1467
1468 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1469 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001470 IDirect3DDevice9 *device = getDevice();
1471
1472 if (constantPS)
1473 {
1474 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1475 }
1476
1477 if (constantVS)
1478 {
1479 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1480 }
1481
1482 delete[] vector;
1483
1484 return true;
1485}
1486
1487bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1488{
1489 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1490
1491 for (int i = 0; i < count; i++)
1492 {
1493 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1494 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1495 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1496 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1497
1498 v += 3;
1499 }
1500
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001501 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1502
1503 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1504 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001505 IDirect3DDevice9 *device = getDevice();
1506
1507 if (constantPS)
1508 {
1509 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1510 }
1511
1512 if (constantVS)
1513 {
1514 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1515 }
1516
1517 delete [] vector;
1518
1519 return true;
1520}
1521
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001522bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1523{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001524 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1525
1526 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1527 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001528 IDirect3DDevice9 *device = getDevice();
1529
1530 if (constantPS)
1531 {
1532 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1533 }
1534
1535 if (constantVS)
1536 {
1537 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1538 }
1539
1540 return true;
1541}
1542
1543bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1544{
1545 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1546
1547 for (int i = 0; i < count; i++)
1548 {
1549 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1550
1551 v += 2;
1552 }
1553
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001554 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1555
1556 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1557 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001558 IDirect3DDevice9 *device = getDevice();
1559
1560 if (constantPS)
1561 {
1562 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1563 }
1564
1565 if (constantVS)
1566 {
1567 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1568 }
1569
1570 delete[] vector;
1571
1572 return true;
1573}
1574
1575bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1576{
1577 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1578
1579 for (int i = 0; i < count; i++)
1580 {
1581 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1582
1583 v += 3;
1584 }
1585
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001586 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1587
1588 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1589 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001590 IDirect3DDevice9 *device = getDevice();
1591
1592 if (constantPS)
1593 {
1594 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1595 }
1596
1597 if (constantVS)
1598 {
1599 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1600 }
1601
1602 delete[] vector;
1603
1604 return true;
1605}
1606
1607bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1608{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001609 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1610
1611 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1612 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001613 IDirect3DDevice9 *device = getDevice();
1614
1615 if (constantPS)
1616 {
1617 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
1618 }
1619
1620 if (constantVS)
1621 {
1622 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
1623 }
1624
1625 return true;
1626}
1627
1628bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
1629{
1630 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1631
1632 for (int i = 0; i < count; i++)
1633 {
1634 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
1635 value[1], value[3], 0, 0,
1636 0, 0, 1, 0,
1637 0, 0, 0, 1);
1638
1639 value += 4;
1640 }
1641
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001642 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1643
1644 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1645 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001646 IDirect3DDevice9 *device = getDevice();
1647
1648 if (constantPS)
1649 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001650 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001651 }
1652
1653 if (constantVS)
1654 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001655 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001656 }
1657
1658 delete[] matrix;
1659
1660 return true;
1661}
1662
1663bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
1664{
1665 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1666
1667 for (int i = 0; i < count; i++)
1668 {
1669 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
1670 value[1], value[4], value[7], 0,
1671 value[2], value[5], value[8], 0,
1672 0, 0, 0, 1);
1673
1674 value += 9;
1675 }
1676
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001677 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1678
1679 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1680 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001681 IDirect3DDevice9 *device = getDevice();
1682
1683 if (constantPS)
1684 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001685 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001686 }
1687
1688 if (constantVS)
1689 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001690 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001691 }
1692
1693 delete[] matrix;
1694
1695 return true;
1696}
1697
1698bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
1699{
1700 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1701
1702 for (int i = 0; i < count; i++)
1703 {
1704 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
1705 value[1], value[5], value[9], value[13],
1706 value[2], value[6], value[10], value[14],
1707 value[3], value[7], value[11], value[15]);
1708
1709 value += 16;
1710 }
1711
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001712 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1713
1714 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1715 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001716 IDirect3DDevice9 *device = getDevice();
1717
1718 if (constantPS)
1719 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001720 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001721 }
1722
1723 if (constantVS)
1724 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001725 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001726 }
1727
1728 delete[] matrix;
1729
1730 return true;
1731}
1732
1733bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
1734{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001735 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1736
1737 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1738 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001739 IDirect3DDevice9 *device = getDevice();
1740
1741 if (constantPS)
1742 {
1743 D3DXCONSTANT_DESC constantDescription;
1744 UINT descriptionCount = 1;
1745 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
1746
daniel@transgaming.com2884b782010-03-08 21:30:48 +00001747 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001748 {
1749 return false;
1750 }
1751
1752 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1753 {
1754 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
1755
1756 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
1757 {
1758 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001759
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001760 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
1761 {
1762 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1763 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001764 ASSERT(mSamplers[samplerIndex].active);
1765 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001766 }
1767 }
1768 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001769
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001770 return true;
1771 }
1772 }
1773
1774 if (constantPS)
1775 {
1776 mConstantTablePS->SetIntArray(device, constantPS, v, count);
1777 }
1778
1779 if (constantVS)
1780 {
1781 mConstantTableVS->SetIntArray(device, constantVS, v, count);
1782 }
1783
1784 return true;
1785}
1786
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001787bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
1788{
1789 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1790
1791 for (int i = 0; i < count; i++)
1792 {
1793 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
1794
1795 v += 2;
1796 }
1797
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001798 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1799
1800 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1801 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001802 IDirect3DDevice9 *device = getDevice();
1803
1804 if (constantPS)
1805 {
1806 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1807 }
1808
1809 if (constantVS)
1810 {
1811 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1812 }
1813
1814 delete[] vector;
1815
1816 return true;
1817}
1818
1819bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
1820{
1821 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1822
1823 for (int i = 0; i < count; i++)
1824 {
1825 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
1826
1827 v += 3;
1828 }
1829
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001830 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1831
1832 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1833 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001834 IDirect3DDevice9 *device = getDevice();
1835
1836 if (constantPS)
1837 {
1838 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1839 }
1840
1841 if (constantVS)
1842 {
1843 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1844 }
1845
1846 delete[] vector;
1847
1848 return true;
1849}
1850
1851bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
1852{
1853 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1854
1855 for (int i = 0; i < count; i++)
1856 {
1857 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
1858
1859 v += 4;
1860 }
1861
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001862 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1863
1864 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1865 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001866 IDirect3DDevice9 *device = getDevice();
1867
1868 if (constantPS)
1869 {
1870 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1871 }
1872
1873 if (constantVS)
1874 {
1875 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1876 }
1877
1878 delete [] vector;
1879
1880 return true;
1881}
1882
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001883void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001884{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001885 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001886 {
1887 return;
1888 }
1889
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001890 char info[1024];
1891
1892 va_list vararg;
1893 va_start(vararg, format);
1894 vsnprintf(info, sizeof(info), format, vararg);
1895 va_end(vararg);
1896
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001897 size_t infoLength = strlen(info);
1898
1899 if (!mInfoLog)
1900 {
1901 mInfoLog = new char[infoLength + 1];
1902 strcpy(mInfoLog, info);
1903 }
1904 else
1905 {
1906 size_t logLength = strlen(mInfoLog);
1907 char *newLog = new char[logLength + infoLength + 1];
1908 strcpy(newLog, mInfoLog);
1909 strcpy(newLog + logLength, info);
1910
1911 delete[] mInfoLog;
1912 mInfoLog = newLog;
1913 }
1914}
1915
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001916void Program::resetInfoLog()
1917{
1918 if (mInfoLog)
1919 {
1920 delete [] mInfoLog;
1921 }
1922}
1923
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001924// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
1925void Program::unlink(bool destroy)
1926{
1927 if (destroy) // Object being destructed
1928 {
1929 if (mFragmentShader)
1930 {
1931 mFragmentShader->detach();
1932 mFragmentShader = NULL;
1933 }
1934
1935 if (mVertexShader)
1936 {
1937 mVertexShader->detach();
1938 mVertexShader = NULL;
1939 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001940 }
1941
1942 if (mPixelExecutable)
1943 {
1944 mPixelExecutable->Release();
1945 mPixelExecutable = NULL;
1946 }
1947
1948 if (mVertexExecutable)
1949 {
1950 mVertexExecutable->Release();
1951 mVertexExecutable = NULL;
1952 }
1953
1954 if (mConstantTablePS)
1955 {
1956 mConstantTablePS->Release();
1957 mConstantTablePS = NULL;
1958 }
1959
1960 if (mConstantTableVS)
1961 {
1962 mConstantTableVS->Release();
1963 mConstantTableVS = NULL;
1964 }
1965
1966 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1967 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001968 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001969 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001970 }
1971
1972 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
1973 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001974 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001975 }
1976
1977 while (!mUniforms.empty())
1978 {
1979 delete mUniforms.back();
1980 mUniforms.pop_back();
1981 }
1982
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001983 mUniformIndex.clear();
1984
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001985 delete[] mPixelHLSL;
1986 mPixelHLSL = NULL;
1987
1988 delete[] mVertexHLSL;
1989 mVertexHLSL = NULL;
1990
1991 delete[] mInfoLog;
1992 mInfoLog = NULL;
1993
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001994 mLinked = false;
1995}
1996
1997bool Program::isLinked()
1998{
1999 return mLinked;
2000}
2001
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002002bool Program::isValidated() const
2003{
2004 return mValidated;
2005}
2006
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002007int Program::getInfoLogLength() const
2008{
2009 if (!mInfoLog)
2010 {
2011 return 0;
2012 }
2013 else
2014 {
2015 return strlen(mInfoLog) + 1;
2016 }
2017}
2018
2019void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2020{
2021 int index = 0;
2022
2023 if (mInfoLog)
2024 {
2025 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2026 {
2027 infoLog[index] = mInfoLog[index];
2028 index++;
2029 }
2030 }
2031
2032 if (bufSize)
2033 {
2034 infoLog[index] = '\0';
2035 }
2036
2037 if (length)
2038 {
2039 *length = index;
2040 }
2041}
2042
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002043void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2044{
2045 int total = 0;
2046
2047 if (mVertexShader)
2048 {
2049 if (total < maxCount)
2050 {
2051 shaders[total] = mVertexShader->getHandle();
2052 }
2053
2054 total++;
2055 }
2056
2057 if (mFragmentShader)
2058 {
2059 if (total < maxCount)
2060 {
2061 shaders[total] = mFragmentShader->getHandle();
2062 }
2063
2064 total++;
2065 }
2066
2067 if (count)
2068 {
2069 *count = total;
2070 }
2071}
2072
daniel@transgaming.com85423182010-04-22 13:35:27 +00002073void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2074{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002075 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002076 for (unsigned int i = 0; i < index; i++)
2077 {
2078 do
2079 {
2080 attribute++;
2081
2082 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2083 }
2084 while (mLinkedAttribute[attribute].name.empty());
2085 }
2086
2087 if (bufsize > 0)
2088 {
2089 const char *string = mLinkedAttribute[attribute].name.c_str();
2090
2091 strncpy(name, string, bufsize);
2092 name[bufsize - 1] = '\0';
2093
2094 if (length)
2095 {
2096 *length = strlen(name);
2097 }
2098 }
2099
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002100 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002101
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002102 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002103}
2104
2105GLint Program::getActiveAttributeCount()
2106{
2107 int count = 0;
2108
2109 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2110 {
2111 if (!mLinkedAttribute[attributeIndex].name.empty())
2112 {
2113 count++;
2114 }
2115 }
2116
2117 return count;
2118}
2119
2120GLint Program::getActiveAttributeMaxLength()
2121{
2122 int maxLength = 0;
2123
2124 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2125 {
2126 if (!mLinkedAttribute[attributeIndex].name.empty())
2127 {
2128 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2129 }
2130 }
2131
2132 return maxLength;
2133}
2134
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002135void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2136{
2137 unsigned int uniform = 0;
2138 for (unsigned int i = 0; i < index; i++)
2139 {
2140 do
2141 {
2142 uniform++;
2143
2144 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2145 }
2146 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2147 }
2148
2149 if (bufsize > 0)
2150 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002151 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002152
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002153 if (mUniforms[uniform]->arraySize != 1)
2154 {
2155 string += "[0]";
2156 }
2157
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002158 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002159 name[bufsize - 1] = '\0';
2160
2161 if (length)
2162 {
2163 *length = strlen(name);
2164 }
2165 }
2166
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002167 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002168
2169 *type = mUniforms[uniform]->type;
2170}
2171
2172GLint Program::getActiveUniformCount()
2173{
2174 int count = 0;
2175
2176 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2177 {
2178 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2179 {
2180 count++;
2181 }
2182 }
2183
2184 return count;
2185}
2186
2187GLint Program::getActiveUniformMaxLength()
2188{
2189 int maxLength = 0;
2190
2191 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2192 {
2193 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2194 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002195 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002196 }
2197 }
2198
2199 return maxLength;
2200}
2201
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002202void Program::flagForDeletion()
2203{
2204 mDeleteStatus = true;
2205}
2206
2207bool Program::isFlaggedForDeletion() const
2208{
2209 return mDeleteStatus;
2210}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002211
2212void Program::validate()
2213{
2214 resetInfoLog();
2215
2216 if (!isLinked())
2217 {
2218 appendToInfoLog("Program has not been successfully linked.");
2219 mValidated = false;
2220 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002221 else
2222 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002223 applyUniforms();
2224 if (!validateSamplers())
2225 {
2226 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2227 mValidated = false;
2228 }
2229 else
2230 {
2231 mValidated = true;
2232 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002233 }
2234}
2235
2236bool Program::validateSamplers() const
2237{
2238 // if any two active samplers in a program are of different types, but refer to the same
2239 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2240 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2241 std::map<int, SamplerType> samplerMap;
2242 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2243 {
2244 if (mSamplers[i].active)
2245 {
2246 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2247 {
2248 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2249 return false;
2250 }
2251 else
2252 {
2253 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2254 }
2255 }
2256 }
2257
2258 return true;
2259}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002260}