blob: 10ab4a17fdd78d794a66ee956d45e93440424ddf [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);
61}
62
63bool Program::attachShader(Shader *shader)
64{
65 if (shader->getType() == GL_VERTEX_SHADER)
66 {
67 if (mVertexShader)
68 {
69 return false;
70 }
71
72 mVertexShader = (VertexShader*)shader;
73 mVertexShader->attach();
74 }
75 else if (shader->getType() == GL_FRAGMENT_SHADER)
76 {
77 if (mFragmentShader)
78 {
79 return false;
80 }
81
82 mFragmentShader = (FragmentShader*)shader;
83 mFragmentShader->attach();
84 }
85 else UNREACHABLE();
86
87 return true;
88}
89
90bool Program::detachShader(Shader *shader)
91{
92 if (shader->getType() == GL_VERTEX_SHADER)
93 {
94 if (mVertexShader != shader)
95 {
96 return false;
97 }
98
99 mVertexShader->detach();
100 mVertexShader = NULL;
101 }
102 else if (shader->getType() == GL_FRAGMENT_SHADER)
103 {
104 if (mFragmentShader != shader)
105 {
106 return false;
107 }
108
109 mFragmentShader->detach();
110 mFragmentShader = NULL;
111 }
112 else UNREACHABLE();
113
114 unlink();
115
116 return true;
117}
118
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000119int Program::getAttachedShadersCount() const
120{
121 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
122}
123
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000124IDirect3DPixelShader9 *Program::getPixelShader()
125{
126 return mPixelExecutable;
127}
128
129IDirect3DVertexShader9 *Program::getVertexShader()
130{
131 return mVertexExecutable;
132}
133
134void Program::bindAttributeLocation(GLuint index, const char *name)
135{
136 if (index < MAX_VERTEX_ATTRIBS)
137 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000138 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
139 {
140 mAttributeBinding[i].erase(name);
141 }
142
143 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000144 }
145}
146
147GLuint Program::getAttributeLocation(const char *name)
148{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000149 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000150 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000151 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000152 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000153 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000154 {
155 return index;
156 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000157 }
158 }
159
160 return -1;
161}
162
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000163int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164{
165 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
166 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000167 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000168 }
169
170 return -1;
171}
172
173// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
174// index referenced in the compiled HLSL shader
175GLint Program::getSamplerMapping(unsigned int samplerIndex)
176{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000177 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
178
179 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000180 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000181 return mSamplers[samplerIndex].logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182 }
183
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000184 return -1;
185}
186
187SamplerType Program::getSamplerType(unsigned int samplerIndex)
188{
189 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
190 assert(mSamplers[samplerIndex].active);
191
192 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000193}
194
195GLint Program::getUniformLocation(const char *name)
196{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000197 std::string nameStr(name);
198 int subscript = 0;
199 size_t beginB = nameStr.find('[');
200 size_t endB = nameStr.find(']');
201 if (beginB != std::string::npos && endB != std::string::npos)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000202 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000203 std::string subscrStr = nameStr.substr(beginB + 1, beginB - endB - 1);
204 nameStr.erase(beginB);
205 subscript = atoi(subscrStr.c_str());
206 }
207
208 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
209 {
210 if (mUniformIndex[location].name == decorate(nameStr) &&
211 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000212 {
213 return location;
214 }
215 }
216
217 return -1;
218}
219
220bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
221{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000222 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000223 {
224 return false;
225 }
226
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000227 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
228
229 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000230 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000231 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000232
233 if (arraySize == 1 && count > 1)
234 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
235
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000236 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000237
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000238 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
239 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000240 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000241 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000242 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000243 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000244
245 if (arraySize == 1 && count > 1)
246 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000247
248 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000249 GLboolean *boolParams = new GLboolean[count];
250
251 for (int i = 0; i < count; ++i)
252 {
253 if (v[i] == 0.0f)
254 {
255 boolParams[i] = GL_FALSE;
256 }
257 else
258 {
259 boolParams[i] = GL_TRUE;
260 }
261 }
262
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000263 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
264 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000265
266 delete [] boolParams;
267 }
268 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000269 {
270 return false;
271 }
272
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000273 return true;
274}
275
276bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
277{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000278 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000279 {
280 return false;
281 }
282
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000283 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
284
285 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000286 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000287 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000288
289 if (arraySize == 1 && count > 1)
290 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
291
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000292 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000293
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000294 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
295 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000296 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000297 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000298 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000299 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000300
301 if (arraySize == 1 && count > 1)
302 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
303
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000304 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
305
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000306 GLboolean *boolParams = new GLboolean[count * 2];
307
308 for (int i = 0; i < count * 2; ++i)
309 {
310 if (v[i] == 0.0f)
311 {
312 boolParams[i] = GL_FALSE;
313 }
314 else
315 {
316 boolParams[i] = GL_TRUE;
317 }
318 }
319
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000320 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
321 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000322
323 delete [] boolParams;
324 }
325 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000326 {
327 return false;
328 }
329
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330 return true;
331}
332
333bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
334{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000335 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000336 {
337 return false;
338 }
339
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000340 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
341
342 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000343 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000344 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000345
346 if (arraySize == 1 && count > 1)
347 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
348
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000349 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000350
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000351 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
352 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000353 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000354 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000355 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000356 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000357
358 if (arraySize == 1 && count > 1)
359 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
360
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000361 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000362 GLboolean *boolParams = new GLboolean[count * 3];
363
364 for (int i = 0; i < count * 3; ++i)
365 {
366 if (v[i] == 0.0f)
367 {
368 boolParams[i] = GL_FALSE;
369 }
370 else
371 {
372 boolParams[i] = GL_TRUE;
373 }
374 }
375
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000376 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
377 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000378
379 delete [] boolParams;
380 }
381 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000382 {
383 return false;
384 }
385
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000386 return true;
387}
388
389bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
390{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000391 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000392 {
393 return false;
394 }
395
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000396 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
397
398 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000399 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000400 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000401
402 if (arraySize == 1 && count > 1)
403 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
404
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000405 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000406
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000407 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
408 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000409 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000410 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000411 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000412 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000413
414 if (arraySize == 1 && count > 1)
415 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
416
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000417 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000418 GLboolean *boolParams = new GLboolean[count * 4];
419
420 for (int i = 0; i < count * 4; ++i)
421 {
422 if (v[i] == 0.0f)
423 {
424 boolParams[i] = GL_FALSE;
425 }
426 else
427 {
428 boolParams[i] = GL_TRUE;
429 }
430 }
431
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000432 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
433 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000434
435 delete [] boolParams;
436 }
437 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000438 {
439 return false;
440 }
441
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000442 return true;
443}
444
445bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
446{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000447 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000448 {
449 return false;
450 }
451
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000452 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
453
454 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000455 {
456 return false;
457 }
458
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000459 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000460
461 if (arraySize == 1 && count > 1)
462 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
463
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000464 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000465
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000466 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
467 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000468
469 return true;
470}
471
472bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
473{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000474 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000475 {
476 return false;
477 }
478
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000479 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
480
481 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000482 {
483 return false;
484 }
485
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000486 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000487
488 if (arraySize == 1 && count > 1)
489 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
490
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000491 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000492
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000493 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
494 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000495
496 return true;
497}
498
499bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
500{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000501 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000502 {
503 return false;
504 }
505
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000506 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
507
508 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000509 {
510 return false;
511 }
512
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000513 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000514
515 if (arraySize == 1 && count > 1)
516 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
517
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000518 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000519
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000520 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
521 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000522
523 return true;
524}
525
526bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
527{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000528 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000529 {
530 return false;
531 }
532
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000533 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
534
535 if (targetUniform->type == GL_INT)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000536 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000537 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000538
539 if (arraySize == 1 && count > 1)
540 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
541
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000542 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000543
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000544 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
545 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000546 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000547 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000548 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000549 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000550
551 if (arraySize == 1 && count > 1)
552 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
553
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000554 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000555 GLboolean *boolParams = new GLboolean[count];
556
557 for (int i = 0; i < count; ++i)
558 {
559 if (v[i] == 0)
560 {
561 boolParams[i] = GL_FALSE;
562 }
563 else
564 {
565 boolParams[i] = GL_TRUE;
566 }
567 }
568
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000569 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
570 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000571
572 delete [] boolParams;
573 }
574 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000575 {
576 return false;
577 }
578
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000579 return true;
580}
581
582bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
583{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000584 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000585 {
586 return false;
587 }
588
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000589 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
590
591 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000592 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000593 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000594
595 if (arraySize == 1 && count > 1)
596 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
597
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000598 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000599
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000600 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
601 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000602 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000603 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000604 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000605 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000606
607 if (arraySize == 1 && count > 1)
608 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
609
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000610 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000611 GLboolean *boolParams = new GLboolean[count * 2];
612
613 for (int i = 0; i < count * 2; ++i)
614 {
615 if (v[i] == 0)
616 {
617 boolParams[i] = GL_FALSE;
618 }
619 else
620 {
621 boolParams[i] = GL_TRUE;
622 }
623 }
624
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000625 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
626 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000627
628 delete [] boolParams;
629 }
630 else
631 {
632 return false;
633 }
634
635 return true;
636}
637
638bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
639{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000640 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000641 {
642 return false;
643 }
644
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000645 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
646
647 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000648 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000649 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000650
651 if (arraySize == 1 && count > 1)
652 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
653
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000654 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000655
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000656 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
657 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000658 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000659 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000660 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000661 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000662
663 if (arraySize == 1 && count > 1)
664 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
665
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000666 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000667 GLboolean *boolParams = new GLboolean[count * 3];
668
669 for (int i = 0; i < count * 3; ++i)
670 {
671 if (v[i] == 0)
672 {
673 boolParams[i] = GL_FALSE;
674 }
675 else
676 {
677 boolParams[i] = GL_TRUE;
678 }
679 }
680
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000681 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
682 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000683
684 delete [] boolParams;
685 }
686 else
687 {
688 return false;
689 }
690
691 return true;
692}
693
694bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
695{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000696 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000697 {
698 return false;
699 }
700
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000701 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
702
703 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000704 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000705 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000706
707 if (arraySize == 1 && count > 1)
708 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
709
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000710 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000711
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000712 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
713 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000714 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000715 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000716 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000717 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000718
719 if (arraySize == 1 && count > 1)
720 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
721
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000722 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000723 GLboolean *boolParams = new GLboolean[count * 4];
724
725 for (int i = 0; i < count * 4; ++i)
726 {
727 if (v[i] == 0)
728 {
729 boolParams[i] = GL_FALSE;
730 }
731 else
732 {
733 boolParams[i] = GL_TRUE;
734 }
735 }
736
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000737 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
738 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000739
740 delete [] boolParams;
741 }
742 else
743 {
744 return false;
745 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000746
747 return true;
748}
749
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000750bool Program::getUniformfv(GLint location, GLfloat *params)
751{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000752 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000753 {
754 return false;
755 }
756
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000757 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000758
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000759 unsigned int count = UniformComponentCount(targetUniform->type);
760
761 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000762 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000763 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000764 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000765 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000766
767 for (unsigned int i = 0; i < count; ++i)
768 {
769 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
770 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000771 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000772 break;
773 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000774 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
775 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000776 break;
777 case GL_INT:
778 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000779 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000780
781 for (unsigned int i = 0; i < count; ++i)
782 {
783 params[i] = (float)intParams[i];
784 }
785 }
786 break;
787 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000788 }
789
790 return true;
791}
792
793bool Program::getUniformiv(GLint location, GLint *params)
794{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000795 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000796 {
797 return false;
798 }
799
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000800 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000801
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000802 unsigned int count = UniformComponentCount(targetUniform->type);
803
804 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000805 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000806 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000807 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000808 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000809
810 for (unsigned int i = 0; i < count; ++i)
811 {
812 params[i] = (GLint)boolParams[i];
813 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000814 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000815 break;
816 case GL_FLOAT:
817 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000818 GLfloat *floatParams = (GLfloat*)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)floatParams[i];
823 }
824 }
825 break;
826 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000827 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
828 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000829 break;
830 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000831 }
832
833 return true;
834}
835
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000836// Applies all the uniforms set for this program object to the Direct3D 9 device
837void Program::applyUniforms()
838{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000839 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000840 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000841 if (mUniformIndex[location].element != 0)
842 {
843 continue;
844 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000845
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000846 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
847
848 int arraySize = targetUniform->arraySize;
849 GLfloat *f = (GLfloat*)targetUniform->data;
850 GLint *i = (GLint*)targetUniform->data;
851 GLboolean *b = (GLboolean*)targetUniform->data;
852
853 switch (targetUniform->type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000854 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000855 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
856 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
857 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
858 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
859 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
860 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
861 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
862 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
863 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
864 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
865 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
866 case GL_INT: applyUniform1iv(location, arraySize, i); break;
867 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
868 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
869 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000870 default:
871 UNIMPLEMENTED(); // FIXME
872 UNREACHABLE();
873 }
874 }
875}
876
877// Compiles the HLSL code of the attached shaders into executable binaries
878ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
879{
880 if (!hlsl)
881 {
882 return NULL;
883 }
884
885 ID3DXBuffer *binary = NULL;
886 ID3DXBuffer *errorMessage = NULL;
887
daniel@transgaming.comcbbca002010-04-01 13:39:32 +0000888 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000889
890 if (SUCCEEDED(result))
891 {
892 return binary;
893 }
894
895 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
896 {
897 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
898 }
899
900 if (errorMessage)
901 {
902 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000903
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000904 TRACE("\n%s", hlsl);
905 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000906 }
907
908 return NULL;
909}
910
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000911void Program::parseVaryings(const char *structure, char *hlsl, VaryingArray &varyings)
912{
913 char *input = strstr(hlsl, structure);
914 input += strlen(structure);
915
916 while (input && *input != '}')
917 {
918 char varyingType[256];
919 char varyingName[256];
920 unsigned int semanticIndex;
921 int matches = sscanf(input, " %s %s : TEXCOORD%d;", varyingType, varyingName, &semanticIndex);
922
923 if (matches == 3)
924 {
925 ASSERT(semanticIndex <= 9); // Single character
926
927 varyings.push_back(Varying(varyingName, input));
928 }
929
930 input = strstr(input, ";");
931 input += 2;
932 }
933}
934
935bool Program::linkVaryings()
936{
937 if (!mPixelHLSL || !mVertexHLSL)
938 {
939 return false;
940 }
941
942 VaryingArray vertexVaryings;
943 VaryingArray pixelVaryings;
944
945 parseVaryings("struct VS_OUTPUT\n{\n", mVertexHLSL, vertexVaryings);
946 parseVaryings("struct PS_INPUT\n{\n", mPixelHLSL, pixelVaryings);
947
948 for (unsigned int out = 0; out < vertexVaryings.size(); out++)
949 {
950 unsigned int in;
951 for (in = 0; in < pixelVaryings.size(); in++)
952 {
953 if (vertexVaryings[out].name == pixelVaryings[in].name)
954 {
955 pixelVaryings[in].link = out;
956 vertexVaryings[out].link = in;
957
958 break;
959 }
960 }
961
962 if (in != pixelVaryings.size())
963 {
964 // FIXME: Verify matching type and qualifiers
965
966 char *outputSemantic = strstr(vertexVaryings[out].declaration, " : TEXCOORD");
967 char *inputSemantic = strstr(pixelVaryings[in].declaration, " : TEXCOORD");
968 outputSemantic[11] = inputSemantic[11];
969 }
970 else
971 {
972 // Comment out the declaration and output assignment
973 vertexVaryings[out].declaration[0] = '/';
974 vertexVaryings[out].declaration[1] = '/';
975
976 char outputString[256];
977 sprintf(outputString, " output.%s = ", vertexVaryings[out].name.c_str());
978 char *varyingOutput = strstr(mVertexHLSL, outputString);
979
980 varyingOutput[0] = '/';
981 varyingOutput[1] = '/';
982 }
983 }
984
985 // Verify that each pixel varying has been linked to a vertex varying
986 for (unsigned int in = 0; in < pixelVaryings.size(); in++)
987 {
988 if (pixelVaryings[in].link < 0)
989 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000990 appendToInfoLog("Pixel varying (%s) does not match any vertex varying", pixelVaryings[in].name);
991
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000992 return false;
993 }
994 }
995
996 return true;
997}
998
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000999// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1000// compiling them into binaries, determining the attribute mappings, and collecting
1001// a list of uniforms
1002void Program::link()
1003{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001004 unlink();
1005
1006 if (!mFragmentShader || !mFragmentShader->isCompiled())
1007 {
1008 return;
1009 }
1010
1011 if (!mVertexShader || !mVertexShader->isCompiled())
1012 {
1013 return;
1014 }
1015
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001016 Context *context = getContext();
1017 const char *vertexProfile = context->getVertexShaderProfile();
1018 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +00001019
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001020 const char *ps = mFragmentShader->getHLSL();
1021 const char *vs = mVertexShader->getHLSL();
1022
1023 mPixelHLSL = new char[strlen(ps) + 1];
1024 strcpy(mPixelHLSL, ps);
1025 mVertexHLSL = new char[strlen(vs) + 1];
1026 strcpy(mVertexHLSL, vs);
1027
1028 if (!linkVaryings())
1029 {
1030 return;
1031 }
1032
1033 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL, vertexProfile, &mConstantTableVS);
1034 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001035
1036 if (vertexBinary && pixelBinary)
1037 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001038 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001039 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1040 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1041
1042 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1043 {
1044 return error(GL_OUT_OF_MEMORY);
1045 }
1046
1047 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001048
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001049 vertexBinary->Release();
1050 pixelBinary->Release();
1051 vertexBinary = NULL;
1052 pixelBinary = NULL;
1053
1054 if (mVertexExecutable && mPixelExecutable)
1055 {
1056 if (!linkAttributes())
1057 {
1058 return;
1059 }
1060
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001061 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001062 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001063 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001064 }
1065
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001066 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001067 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001068 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001069 }
1070
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001071 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001072 }
1073 }
1074}
1075
1076// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1077bool Program::linkAttributes()
1078{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001079 unsigned int usedLocations = 0;
1080
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001081 // Link attributes that have a binding location
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001082 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1083 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001084 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1085 int location = getAttributeBinding(attribute.name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001086
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001087 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001088 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001089 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001090 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001091 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001092 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001093
daniel@transgaming.com85423182010-04-22 13:35:27 +00001094 mLinkedAttribute[location] = attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001095
1096 int size = AttributeVectorCount(attribute.type);
1097
1098 if (size + location > MAX_VERTEX_ATTRIBS)
1099 {
1100 appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
1101
1102 return false;
1103 }
1104
1105 for (int i = 0; i < size; i++)
1106 {
1107 usedLocations |= 1 << (location + i);
1108 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001109 }
1110 }
1111
1112 // Link attributes that don't have a binding location
1113 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS + 1; attributeIndex++)
1114 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001115 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1116 int location = getAttributeBinding(attribute.name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001117
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001118 if (!attribute.name.empty() && location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001119 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001120 int size = AttributeVectorCount(attribute.type);
1121 int availableIndex = AllocateFirstFreeBits(&usedLocations, size, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001122
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001123 if (availableIndex == -1 || availableIndex + size > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001124 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001125 appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001126
1127 return false; // Fail to link
1128 }
1129
daniel@transgaming.com85423182010-04-22 13:35:27 +00001130 mLinkedAttribute[availableIndex] = attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001131 }
1132 }
1133
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001134 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001135 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001136 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1137
1138 if (index == -1)
1139 {
1140 mSemanticIndex[attributeIndex++] = -1;
1141 }
1142 else
1143 {
1144 int size = AttributeVectorCount(mVertexShader->getAttribute(index).type);
1145
1146 for (int i = 0; i < size; i++)
1147 {
1148 mSemanticIndex[attributeIndex++] = index++;
1149 }
1150 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001151 }
1152
1153 return true;
1154}
1155
daniel@transgaming.com85423182010-04-22 13:35:27 +00001156int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001157{
1158 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1159 {
1160 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1161 {
1162 return location;
1163 }
1164 }
1165
1166 return -1;
1167}
1168
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001169bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1170{
1171 D3DXCONSTANTTABLE_DESC constantTableDescription;
1172 D3DXCONSTANT_DESC constantDescription;
1173 UINT descriptionCount = 1;
1174
1175 constantTable->GetDesc(&constantTableDescription);
1176
1177 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1178 {
1179 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1180 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1181
1182 if (!defineUniform(constantHandle, constantDescription))
1183 {
1184 return false;
1185 }
1186 }
1187
1188 return true;
1189}
1190
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001191// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001192// Returns true if succesful (uniform not already defined)
1193bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1194{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001195 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1196 {
1197 unsigned int samplerIndex = constantDescription.RegisterIndex;
1198
1199 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1200
1201 mSamplers[samplerIndex].active = true;
1202 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1203 mSamplers[samplerIndex].logicalTextureUnit = 0;
1204 }
1205
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001206 switch(constantDescription.Class)
1207 {
1208 case D3DXPC_STRUCT:
1209 {
1210 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1211 {
1212 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1213
1214 D3DXCONSTANT_DESC fieldDescription;
1215 UINT descriptionCount = 1;
1216
1217 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1218
1219 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1220 {
1221 return false;
1222 }
1223 }
1224
1225 return true;
1226 }
1227 case D3DXPC_SCALAR:
1228 case D3DXPC_VECTOR:
1229 case D3DXPC_MATRIX_COLUMNS:
1230 case D3DXPC_OBJECT:
1231 return defineUniform(constantDescription, name + constantDescription.Name);
1232 default:
1233 UNREACHABLE();
1234 return false;
1235 }
1236}
1237
1238bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1239{
1240 Uniform *uniform = createUniform(constantDescription, name);
1241
1242 if(!uniform)
1243 {
1244 return false;
1245 }
1246
1247 // Check if already defined
1248 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001249 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001250
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001251 if (location >= 0)
1252 {
1253 delete uniform;
1254
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001255 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001256 {
1257 return false;
1258 }
1259 else
1260 {
1261 return true;
1262 }
1263 }
1264
1265 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001266 unsigned int uniformIndex = mUniforms.size() - 1;
1267
1268 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1269 {
1270 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1271 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001272
1273 return true;
1274}
1275
1276Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001277{
1278 if (constantDescription.Rows == 1) // Vectors and scalars
1279 {
1280 switch (constantDescription.Type)
1281 {
1282 case D3DXPT_SAMPLER2D:
1283 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001284 switch (constantDescription.Columns)
1285 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001286 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001287 default: UNREACHABLE();
1288 }
1289 break;
1290 case D3DXPT_BOOL:
1291 switch (constantDescription.Columns)
1292 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001293 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1294 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1295 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1296 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001297 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001298 }
1299 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001300 case D3DXPT_INT:
1301 switch (constantDescription.Columns)
1302 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001303 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1304 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1305 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1306 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001307 default: UNREACHABLE();
1308 }
1309 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001310 case D3DXPT_FLOAT:
1311 switch (constantDescription.Columns)
1312 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001313 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1314 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1315 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1316 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001317 default: UNREACHABLE();
1318 }
1319 break;
1320 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001321 UNREACHABLE();
1322 }
1323 }
1324 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1325 {
1326 switch (constantDescription.Type)
1327 {
1328 case D3DXPT_FLOAT:
1329 switch (constantDescription.Rows)
1330 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001331 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1332 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1333 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001334 default: UNREACHABLE();
1335 }
1336 break;
1337 default: UNREACHABLE();
1338 }
1339 }
1340 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001341
1342 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001343}
1344
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001345// This methods needs to match OutputHLSL::decorate
1346std::string Program::decorate(const std::string &string)
1347{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001348 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001349 {
1350 return "_" + string;
1351 }
1352 else
1353 {
1354 return string;
1355 }
1356}
1357
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001358bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1359{
1360 BOOL *vector = new BOOL[count];
1361 for (int i = 0; i < count; i++)
1362 {
1363 if (v[i] == GL_FALSE)
1364 vector[i] = 0;
1365 else
1366 vector[i] = 1;
1367 }
1368
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001369 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1370
1371 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1372 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001373 IDirect3DDevice9 *device = getDevice();
1374
1375 if (constantPS)
1376 {
1377 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1378 }
1379
1380 if (constantVS)
1381 {
1382 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1383 }
1384
1385 delete [] vector;
1386
1387 return true;
1388}
1389
1390bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1391{
1392 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1393
1394 for (int i = 0; i < count; i++)
1395 {
1396 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1397 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1398
1399 v += 2;
1400 }
1401
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001402 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1403
1404 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1405 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001406 IDirect3DDevice9 *device = getDevice();
1407
1408 if (constantPS)
1409 {
1410 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1411 }
1412
1413 if (constantVS)
1414 {
1415 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1416 }
1417
1418 delete[] vector;
1419
1420 return true;
1421}
1422
1423bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1424{
1425 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1426
1427 for (int i = 0; i < count; i++)
1428 {
1429 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1430 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1431 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1432
1433 v += 3;
1434 }
1435
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001436 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1437
1438 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1439 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001440 IDirect3DDevice9 *device = getDevice();
1441
1442 if (constantPS)
1443 {
1444 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1445 }
1446
1447 if (constantVS)
1448 {
1449 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1450 }
1451
1452 delete[] vector;
1453
1454 return true;
1455}
1456
1457bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1458{
1459 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1460
1461 for (int i = 0; i < count; i++)
1462 {
1463 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1464 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1465 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1466 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1467
1468 v += 3;
1469 }
1470
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001471 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1472
1473 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1474 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001475 IDirect3DDevice9 *device = getDevice();
1476
1477 if (constantPS)
1478 {
1479 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1480 }
1481
1482 if (constantVS)
1483 {
1484 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1485 }
1486
1487 delete [] vector;
1488
1489 return true;
1490}
1491
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001492bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1493{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001494 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1495
1496 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1497 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001498 IDirect3DDevice9 *device = getDevice();
1499
1500 if (constantPS)
1501 {
1502 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1503 }
1504
1505 if (constantVS)
1506 {
1507 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1508 }
1509
1510 return true;
1511}
1512
1513bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1514{
1515 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1516
1517 for (int i = 0; i < count; i++)
1518 {
1519 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1520
1521 v += 2;
1522 }
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->SetVectorArray(device, constantPS, vector, count);
1533 }
1534
1535 if (constantVS)
1536 {
1537 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1538 }
1539
1540 delete[] vector;
1541
1542 return true;
1543}
1544
1545bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1546{
1547 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1548
1549 for (int i = 0; i < count; i++)
1550 {
1551 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1552
1553 v += 3;
1554 }
1555
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001556 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1557
1558 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1559 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001560 IDirect3DDevice9 *device = getDevice();
1561
1562 if (constantPS)
1563 {
1564 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1565 }
1566
1567 if (constantVS)
1568 {
1569 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1570 }
1571
1572 delete[] vector;
1573
1574 return true;
1575}
1576
1577bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1578{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001579 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1580
1581 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1582 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001583 IDirect3DDevice9 *device = getDevice();
1584
1585 if (constantPS)
1586 {
1587 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
1588 }
1589
1590 if (constantVS)
1591 {
1592 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
1593 }
1594
1595 return true;
1596}
1597
1598bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
1599{
1600 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1601
1602 for (int i = 0; i < count; i++)
1603 {
1604 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
1605 value[1], value[3], 0, 0,
1606 0, 0, 1, 0,
1607 0, 0, 0, 1);
1608
1609 value += 4;
1610 }
1611
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001612 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1613
1614 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1615 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001616 IDirect3DDevice9 *device = getDevice();
1617
1618 if (constantPS)
1619 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001620 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001621 }
1622
1623 if (constantVS)
1624 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001625 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001626 }
1627
1628 delete[] matrix;
1629
1630 return true;
1631}
1632
1633bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
1634{
1635 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1636
1637 for (int i = 0; i < count; i++)
1638 {
1639 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
1640 value[1], value[4], value[7], 0,
1641 value[2], value[5], value[8], 0,
1642 0, 0, 0, 1);
1643
1644 value += 9;
1645 }
1646
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001647 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1648
1649 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1650 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001651 IDirect3DDevice9 *device = getDevice();
1652
1653 if (constantPS)
1654 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001655 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001656 }
1657
1658 if (constantVS)
1659 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001660 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001661 }
1662
1663 delete[] matrix;
1664
1665 return true;
1666}
1667
1668bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
1669{
1670 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1671
1672 for (int i = 0; i < count; i++)
1673 {
1674 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
1675 value[1], value[5], value[9], value[13],
1676 value[2], value[6], value[10], value[14],
1677 value[3], value[7], value[11], value[15]);
1678
1679 value += 16;
1680 }
1681
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001682 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1683
1684 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1685 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001686 IDirect3DDevice9 *device = getDevice();
1687
1688 if (constantPS)
1689 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001690 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001691 }
1692
1693 if (constantVS)
1694 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001695 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001696 }
1697
1698 delete[] matrix;
1699
1700 return true;
1701}
1702
1703bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
1704{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001705 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1706
1707 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1708 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001709 IDirect3DDevice9 *device = getDevice();
1710
1711 if (constantPS)
1712 {
1713 D3DXCONSTANT_DESC constantDescription;
1714 UINT descriptionCount = 1;
1715 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
1716
daniel@transgaming.com2884b782010-03-08 21:30:48 +00001717 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001718 {
1719 return false;
1720 }
1721
1722 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1723 {
1724 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
1725
1726 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
1727 {
1728 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001729
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001730 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
1731 {
1732 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1733 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001734 ASSERT(mSamplers[samplerIndex].active);
1735 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001736 }
1737 }
1738 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001739
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001740 return true;
1741 }
1742 }
1743
1744 if (constantPS)
1745 {
1746 mConstantTablePS->SetIntArray(device, constantPS, v, count);
1747 }
1748
1749 if (constantVS)
1750 {
1751 mConstantTableVS->SetIntArray(device, constantVS, v, count);
1752 }
1753
1754 return true;
1755}
1756
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001757bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
1758{
1759 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1760
1761 for (int i = 0; i < count; i++)
1762 {
1763 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
1764
1765 v += 2;
1766 }
1767
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001768 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1769
1770 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1771 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001772 IDirect3DDevice9 *device = getDevice();
1773
1774 if (constantPS)
1775 {
1776 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1777 }
1778
1779 if (constantVS)
1780 {
1781 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1782 }
1783
1784 delete[] vector;
1785
1786 return true;
1787}
1788
1789bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
1790{
1791 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1792
1793 for (int i = 0; i < count; i++)
1794 {
1795 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
1796
1797 v += 3;
1798 }
1799
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001800 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1801
1802 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1803 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001804 IDirect3DDevice9 *device = getDevice();
1805
1806 if (constantPS)
1807 {
1808 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1809 }
1810
1811 if (constantVS)
1812 {
1813 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1814 }
1815
1816 delete[] vector;
1817
1818 return true;
1819}
1820
1821bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
1822{
1823 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1824
1825 for (int i = 0; i < count; i++)
1826 {
1827 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
1828
1829 v += 4;
1830 }
1831
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001832 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1833
1834 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1835 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001836 IDirect3DDevice9 *device = getDevice();
1837
1838 if (constantPS)
1839 {
1840 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1841 }
1842
1843 if (constantVS)
1844 {
1845 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1846 }
1847
1848 delete [] vector;
1849
1850 return true;
1851}
1852
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001853void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001854{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001855 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001856 {
1857 return;
1858 }
1859
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001860 char info[1024];
1861
1862 va_list vararg;
1863 va_start(vararg, format);
1864 vsnprintf(info, sizeof(info), format, vararg);
1865 va_end(vararg);
1866
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001867 size_t infoLength = strlen(info);
1868
1869 if (!mInfoLog)
1870 {
1871 mInfoLog = new char[infoLength + 1];
1872 strcpy(mInfoLog, info);
1873 }
1874 else
1875 {
1876 size_t logLength = strlen(mInfoLog);
1877 char *newLog = new char[logLength + infoLength + 1];
1878 strcpy(newLog, mInfoLog);
1879 strcpy(newLog + logLength, info);
1880
1881 delete[] mInfoLog;
1882 mInfoLog = newLog;
1883 }
1884}
1885
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001886void Program::resetInfoLog()
1887{
1888 if (mInfoLog)
1889 {
1890 delete [] mInfoLog;
1891 }
1892}
1893
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001894// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
1895void Program::unlink(bool destroy)
1896{
1897 if (destroy) // Object being destructed
1898 {
1899 if (mFragmentShader)
1900 {
1901 mFragmentShader->detach();
1902 mFragmentShader = NULL;
1903 }
1904
1905 if (mVertexShader)
1906 {
1907 mVertexShader->detach();
1908 mVertexShader = NULL;
1909 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001910 }
1911
1912 if (mPixelExecutable)
1913 {
1914 mPixelExecutable->Release();
1915 mPixelExecutable = NULL;
1916 }
1917
1918 if (mVertexExecutable)
1919 {
1920 mVertexExecutable->Release();
1921 mVertexExecutable = NULL;
1922 }
1923
1924 if (mConstantTablePS)
1925 {
1926 mConstantTablePS->Release();
1927 mConstantTablePS = NULL;
1928 }
1929
1930 if (mConstantTableVS)
1931 {
1932 mConstantTableVS->Release();
1933 mConstantTableVS = NULL;
1934 }
1935
1936 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1937 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001938 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001939 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001940 }
1941
1942 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
1943 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001944 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001945 }
1946
1947 while (!mUniforms.empty())
1948 {
1949 delete mUniforms.back();
1950 mUniforms.pop_back();
1951 }
1952
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001953 mUniformIndex.clear();
1954
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001955 delete[] mPixelHLSL;
1956 mPixelHLSL = NULL;
1957
1958 delete[] mVertexHLSL;
1959 mVertexHLSL = NULL;
1960
1961 delete[] mInfoLog;
1962 mInfoLog = NULL;
1963
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001964 mLinked = false;
1965}
1966
1967bool Program::isLinked()
1968{
1969 return mLinked;
1970}
1971
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001972bool Program::isValidated() const
1973{
1974 return mValidated;
1975}
1976
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001977int Program::getInfoLogLength() const
1978{
1979 if (!mInfoLog)
1980 {
1981 return 0;
1982 }
1983 else
1984 {
1985 return strlen(mInfoLog) + 1;
1986 }
1987}
1988
1989void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
1990{
1991 int index = 0;
1992
1993 if (mInfoLog)
1994 {
1995 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
1996 {
1997 infoLog[index] = mInfoLog[index];
1998 index++;
1999 }
2000 }
2001
2002 if (bufSize)
2003 {
2004 infoLog[index] = '\0';
2005 }
2006
2007 if (length)
2008 {
2009 *length = index;
2010 }
2011}
2012
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002013void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2014{
2015 int total = 0;
2016
2017 if (mVertexShader)
2018 {
2019 if (total < maxCount)
2020 {
2021 shaders[total] = mVertexShader->getHandle();
2022 }
2023
2024 total++;
2025 }
2026
2027 if (mFragmentShader)
2028 {
2029 if (total < maxCount)
2030 {
2031 shaders[total] = mFragmentShader->getHandle();
2032 }
2033
2034 total++;
2035 }
2036
2037 if (count)
2038 {
2039 *count = total;
2040 }
2041}
2042
daniel@transgaming.com85423182010-04-22 13:35:27 +00002043void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2044{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002045 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002046 for (unsigned int i = 0; i < index; i++)
2047 {
2048 do
2049 {
2050 attribute++;
2051
2052 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2053 }
2054 while (mLinkedAttribute[attribute].name.empty());
2055 }
2056
2057 if (bufsize > 0)
2058 {
2059 const char *string = mLinkedAttribute[attribute].name.c_str();
2060
2061 strncpy(name, string, bufsize);
2062 name[bufsize - 1] = '\0';
2063
2064 if (length)
2065 {
2066 *length = strlen(name);
2067 }
2068 }
2069
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002070 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002071
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002072 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002073}
2074
2075GLint Program::getActiveAttributeCount()
2076{
2077 int count = 0;
2078
2079 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2080 {
2081 if (!mLinkedAttribute[attributeIndex].name.empty())
2082 {
2083 count++;
2084 }
2085 }
2086
2087 return count;
2088}
2089
2090GLint Program::getActiveAttributeMaxLength()
2091{
2092 int maxLength = 0;
2093
2094 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2095 {
2096 if (!mLinkedAttribute[attributeIndex].name.empty())
2097 {
2098 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2099 }
2100 }
2101
2102 return maxLength;
2103}
2104
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002105void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2106{
2107 unsigned int uniform = 0;
2108 for (unsigned int i = 0; i < index; i++)
2109 {
2110 do
2111 {
2112 uniform++;
2113
2114 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2115 }
2116 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2117 }
2118
2119 if (bufsize > 0)
2120 {
2121 const char *string = mUniforms[uniform]->name.c_str();
2122
2123 if(string[0] == '_') // Undecorate
2124 {
2125 string++;
2126 }
2127
2128 strncpy(name, string, bufsize);
2129 name[bufsize - 1] = '\0';
2130
2131 if (length)
2132 {
2133 *length = strlen(name);
2134 }
2135 }
2136
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002137 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002138
2139 *type = mUniforms[uniform]->type;
2140}
2141
2142GLint Program::getActiveUniformCount()
2143{
2144 int count = 0;
2145
2146 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2147 {
2148 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2149 {
2150 count++;
2151 }
2152 }
2153
2154 return count;
2155}
2156
2157GLint Program::getActiveUniformMaxLength()
2158{
2159 int maxLength = 0;
2160
2161 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2162 {
2163 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2164 {
2165 maxLength = std::max((int)(mUniforms[uniformIndex]->name.length() + 1), maxLength);
2166 }
2167 }
2168
2169 return maxLength;
2170}
2171
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002172void Program::flagForDeletion()
2173{
2174 mDeleteStatus = true;
2175}
2176
2177bool Program::isFlaggedForDeletion() const
2178{
2179 return mDeleteStatus;
2180}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002181
2182void Program::validate()
2183{
2184 resetInfoLog();
2185
2186 if (!isLinked())
2187 {
2188 appendToInfoLog("Program has not been successfully linked.");
2189 mValidated = false;
2190 }
2191 else if (!validateSamplers())
2192 {
2193 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2194 mValidated = false;
2195 }
2196 else
2197 {
2198 mValidated = true;
2199 }
2200}
2201
2202bool Program::validateSamplers() const
2203{
2204 // if any two active samplers in a program are of different types, but refer to the same
2205 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2206 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2207 std::map<int, SamplerType> samplerMap;
2208 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2209 {
2210 if (mSamplers[i].active)
2211 {
2212 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2213 {
2214 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2215 return false;
2216 }
2217 else
2218 {
2219 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2220 }
2221 }
2222 }
2223
2224 return true;
2225}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002226}