blob: 611809cbee4129fc9efcc28d1e1b6c5f1f67cf77 [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;
51
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000052 unlink();
53
54 mDeleteStatus = false;
55}
56
57Program::~Program()
58{
59 unlink(true);
60}
61
62bool Program::attachShader(Shader *shader)
63{
64 if (shader->getType() == GL_VERTEX_SHADER)
65 {
66 if (mVertexShader)
67 {
68 return false;
69 }
70
71 mVertexShader = (VertexShader*)shader;
72 mVertexShader->attach();
73 }
74 else if (shader->getType() == GL_FRAGMENT_SHADER)
75 {
76 if (mFragmentShader)
77 {
78 return false;
79 }
80
81 mFragmentShader = (FragmentShader*)shader;
82 mFragmentShader->attach();
83 }
84 else UNREACHABLE();
85
86 return true;
87}
88
89bool Program::detachShader(Shader *shader)
90{
91 if (shader->getType() == GL_VERTEX_SHADER)
92 {
93 if (mVertexShader != shader)
94 {
95 return false;
96 }
97
98 mVertexShader->detach();
99 mVertexShader = NULL;
100 }
101 else if (shader->getType() == GL_FRAGMENT_SHADER)
102 {
103 if (mFragmentShader != shader)
104 {
105 return false;
106 }
107
108 mFragmentShader->detach();
109 mFragmentShader = NULL;
110 }
111 else UNREACHABLE();
112
113 unlink();
114
115 return true;
116}
117
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000118int Program::getAttachedShadersCount() const
119{
120 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
121}
122
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000123IDirect3DPixelShader9 *Program::getPixelShader()
124{
125 return mPixelExecutable;
126}
127
128IDirect3DVertexShader9 *Program::getVertexShader()
129{
130 return mVertexExecutable;
131}
132
133void Program::bindAttributeLocation(GLuint index, const char *name)
134{
135 if (index < MAX_VERTEX_ATTRIBS)
136 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000137 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
138 {
139 mAttributeBinding[i].erase(name);
140 }
141
142 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000143 }
144}
145
146GLuint Program::getAttributeLocation(const char *name)
147{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000148 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000150 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000151 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000152 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000153 {
154 return index;
155 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000156 }
157 }
158
159 return -1;
160}
161
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000162int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000163{
164 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
165 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000166 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000167 }
168
169 return -1;
170}
171
172// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
173// index referenced in the compiled HLSL shader
174GLint Program::getSamplerMapping(unsigned int samplerIndex)
175{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000176 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
177
178 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000179 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000180 return mSamplers[samplerIndex].logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000181 }
182
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000183 return -1;
184}
185
186SamplerType Program::getSamplerType(unsigned int samplerIndex)
187{
188 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
189 assert(mSamplers[samplerIndex].active);
190
191 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000192}
193
194GLint Program::getUniformLocation(const char *name)
195{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000196 std::string nameStr(name);
197 int subscript = 0;
198 size_t beginB = nameStr.find('[');
199 size_t endB = nameStr.find(']');
200 if (beginB != std::string::npos && endB != std::string::npos)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000201 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000202 std::string subscrStr = nameStr.substr(beginB + 1, beginB - endB - 1);
203 nameStr.erase(beginB);
204 subscript = atoi(subscrStr.c_str());
205 }
206
207 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
208 {
209 if (mUniformIndex[location].name == decorate(nameStr) &&
210 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000211 {
212 return location;
213 }
214 }
215
216 return -1;
217}
218
219bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
220{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000221 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000222 {
223 return false;
224 }
225
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000226 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
227
228 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000229 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000230 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000231
232 if (arraySize == 1 && count > 1)
233 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
234
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000235 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000236
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000237 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
238 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000239 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000240 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000241 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000242 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000243
244 if (arraySize == 1 && count > 1)
245 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000246
247 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000248 GLboolean *boolParams = new GLboolean[count];
249
250 for (int i = 0; i < count; ++i)
251 {
252 if (v[i] == 0.0f)
253 {
254 boolParams[i] = GL_FALSE;
255 }
256 else
257 {
258 boolParams[i] = GL_TRUE;
259 }
260 }
261
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000262 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
263 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000264
265 delete [] boolParams;
266 }
267 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000268 {
269 return false;
270 }
271
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000272 return true;
273}
274
275bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
276{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000277 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000278 {
279 return false;
280 }
281
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000282 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
283
284 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000285 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000286 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000287
288 if (arraySize == 1 && count > 1)
289 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
290
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000291 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000292
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000293 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
294 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000295 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000296 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000297 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000298 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000299
300 if (arraySize == 1 && count > 1)
301 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
302
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000303 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
304
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000305 GLboolean *boolParams = new GLboolean[count * 2];
306
307 for (int i = 0; i < count * 2; ++i)
308 {
309 if (v[i] == 0.0f)
310 {
311 boolParams[i] = GL_FALSE;
312 }
313 else
314 {
315 boolParams[i] = GL_TRUE;
316 }
317 }
318
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000319 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
320 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000321
322 delete [] boolParams;
323 }
324 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000325 {
326 return false;
327 }
328
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000329 return true;
330}
331
332bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
333{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000334 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000335 {
336 return false;
337 }
338
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000339 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
340
341 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000342 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000343 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000344
345 if (arraySize == 1 && count > 1)
346 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
347
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000348 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000349
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000350 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
351 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000352 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000353 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000354 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000355 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000356
357 if (arraySize == 1 && count > 1)
358 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
359
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000360 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000361 GLboolean *boolParams = new GLboolean[count * 3];
362
363 for (int i = 0; i < count * 3; ++i)
364 {
365 if (v[i] == 0.0f)
366 {
367 boolParams[i] = GL_FALSE;
368 }
369 else
370 {
371 boolParams[i] = GL_TRUE;
372 }
373 }
374
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000375 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
376 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000377
378 delete [] boolParams;
379 }
380 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000381 {
382 return false;
383 }
384
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000385 return true;
386}
387
388bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
389{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000390 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000391 {
392 return false;
393 }
394
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000395 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
396
397 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000398 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000399 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000400
401 if (arraySize == 1 && count > 1)
402 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
403
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000404 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000405
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000406 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
407 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000408 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000409 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000410 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000411 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000412
413 if (arraySize == 1 && count > 1)
414 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
415
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000416 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000417 GLboolean *boolParams = new GLboolean[count * 4];
418
419 for (int i = 0; i < count * 4; ++i)
420 {
421 if (v[i] == 0.0f)
422 {
423 boolParams[i] = GL_FALSE;
424 }
425 else
426 {
427 boolParams[i] = GL_TRUE;
428 }
429 }
430
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000431 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
432 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000433
434 delete [] boolParams;
435 }
436 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000437 {
438 return false;
439 }
440
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000441 return true;
442}
443
444bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
445{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000446 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000447 {
448 return false;
449 }
450
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000451 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
452
453 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000454 {
455 return false;
456 }
457
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000458 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000459
460 if (arraySize == 1 && count > 1)
461 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
462
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000463 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000464
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000465 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
466 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000467
468 return true;
469}
470
471bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
472{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000473 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000474 {
475 return false;
476 }
477
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000478 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
479
480 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000481 {
482 return false;
483 }
484
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000485 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000486
487 if (arraySize == 1 && count > 1)
488 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
489
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000490 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000491
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000492 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
493 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000494
495 return true;
496}
497
498bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
499{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000500 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000501 {
502 return false;
503 }
504
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000505 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
506
507 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000508 {
509 return false;
510 }
511
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000512 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000513
514 if (arraySize == 1 && count > 1)
515 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
516
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000517 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000518
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000519 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
520 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000521
522 return true;
523}
524
525bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
526{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000527 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000528 {
529 return false;
530 }
531
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000532 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
533
534 if (targetUniform->type == GL_INT)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000535 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000536 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000537
538 if (arraySize == 1 && count > 1)
539 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
540
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000541 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000542
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000543 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
544 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000545 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000546 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000547 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000548 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000549
550 if (arraySize == 1 && count > 1)
551 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
552
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000553 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000554 GLboolean *boolParams = new GLboolean[count];
555
556 for (int i = 0; i < count; ++i)
557 {
558 if (v[i] == 0)
559 {
560 boolParams[i] = GL_FALSE;
561 }
562 else
563 {
564 boolParams[i] = GL_TRUE;
565 }
566 }
567
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000568 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
569 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000570
571 delete [] boolParams;
572 }
573 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000574 {
575 return false;
576 }
577
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000578 return true;
579}
580
581bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
582{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000583 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000584 {
585 return false;
586 }
587
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000588 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
589
590 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000591 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000592 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000593
594 if (arraySize == 1 && count > 1)
595 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
596
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000597 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000598
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000599 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
600 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000601 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000602 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000603 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000604 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000605
606 if (arraySize == 1 && count > 1)
607 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
608
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000609 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000610 GLboolean *boolParams = new GLboolean[count * 2];
611
612 for (int i = 0; i < count * 2; ++i)
613 {
614 if (v[i] == 0)
615 {
616 boolParams[i] = GL_FALSE;
617 }
618 else
619 {
620 boolParams[i] = GL_TRUE;
621 }
622 }
623
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000624 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
625 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000626
627 delete [] boolParams;
628 }
629 else
630 {
631 return false;
632 }
633
634 return true;
635}
636
637bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
638{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000639 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000640 {
641 return false;
642 }
643
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000644 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
645
646 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000647 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000648 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000649
650 if (arraySize == 1 && count > 1)
651 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
652
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000653 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000654
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000655 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
656 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000657 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000658 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000659 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000660 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000661
662 if (arraySize == 1 && count > 1)
663 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
664
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000665 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000666 GLboolean *boolParams = new GLboolean[count * 3];
667
668 for (int i = 0; i < count * 3; ++i)
669 {
670 if (v[i] == 0)
671 {
672 boolParams[i] = GL_FALSE;
673 }
674 else
675 {
676 boolParams[i] = GL_TRUE;
677 }
678 }
679
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000680 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
681 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000682
683 delete [] boolParams;
684 }
685 else
686 {
687 return false;
688 }
689
690 return true;
691}
692
693bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
694{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000695 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000696 {
697 return false;
698 }
699
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000700 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
701
702 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000703 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000704 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000705
706 if (arraySize == 1 && count > 1)
707 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
708
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000709 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000710
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000711 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
712 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000713 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000714 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000715 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000716 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000717
718 if (arraySize == 1 && count > 1)
719 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
720
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000721 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000722 GLboolean *boolParams = new GLboolean[count * 4];
723
724 for (int i = 0; i < count * 4; ++i)
725 {
726 if (v[i] == 0)
727 {
728 boolParams[i] = GL_FALSE;
729 }
730 else
731 {
732 boolParams[i] = GL_TRUE;
733 }
734 }
735
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000736 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
737 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000738
739 delete [] boolParams;
740 }
741 else
742 {
743 return false;
744 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000745
746 return true;
747}
748
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000749bool Program::getUniformfv(GLint location, GLfloat *params)
750{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000751 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000752 {
753 return false;
754 }
755
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000756 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000757
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000758 unsigned int count = UniformComponentCount(targetUniform->type);
759
760 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000761 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000762 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000763 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000764 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000765
766 for (unsigned int i = 0; i < count; ++i)
767 {
768 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
769 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000770 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000771 break;
772 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000773 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
774 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000775 break;
776 case GL_INT:
777 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000778 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000779
780 for (unsigned int i = 0; i < count; ++i)
781 {
782 params[i] = (float)intParams[i];
783 }
784 }
785 break;
786 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000787 }
788
789 return true;
790}
791
792bool Program::getUniformiv(GLint location, GLint *params)
793{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000794 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000795 {
796 return false;
797 }
798
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000799 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000800
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000801 unsigned int count = UniformComponentCount(targetUniform->type);
802
803 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000804 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000805 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000806 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000807 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000808
809 for (unsigned int i = 0; i < count; ++i)
810 {
811 params[i] = (GLint)boolParams[i];
812 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000813 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000814 break;
815 case GL_FLOAT:
816 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000817 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000818
819 for (unsigned int i = 0; i < count; ++i)
820 {
821 params[i] = (GLint)floatParams[i];
822 }
823 }
824 break;
825 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000826 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
827 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000828 break;
829 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000830 }
831
832 return true;
833}
834
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000835// Applies all the uniforms set for this program object to the Direct3D 9 device
836void Program::applyUniforms()
837{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000838 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000839 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000840 if (mUniformIndex[location].element != 0)
841 {
842 continue;
843 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000844
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000845 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
846
847 int arraySize = targetUniform->arraySize;
848 GLfloat *f = (GLfloat*)targetUniform->data;
849 GLint *i = (GLint*)targetUniform->data;
850 GLboolean *b = (GLboolean*)targetUniform->data;
851
852 switch (targetUniform->type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000853 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000854 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
855 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
856 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
857 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
858 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
859 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
860 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
861 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
862 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
863 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
864 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
865 case GL_INT: applyUniform1iv(location, arraySize, i); break;
866 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
867 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
868 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000869 default:
870 UNIMPLEMENTED(); // FIXME
871 UNREACHABLE();
872 }
873 }
874}
875
876// Compiles the HLSL code of the attached shaders into executable binaries
877ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
878{
879 if (!hlsl)
880 {
881 return NULL;
882 }
883
884 ID3DXBuffer *binary = NULL;
885 ID3DXBuffer *errorMessage = NULL;
886
daniel@transgaming.comcbbca002010-04-01 13:39:32 +0000887 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000888
889 if (SUCCEEDED(result))
890 {
891 return binary;
892 }
893
894 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
895 {
896 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
897 }
898
899 if (errorMessage)
900 {
901 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000902
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000903 TRACE("\n%s", hlsl);
904 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000905 }
906
907 return NULL;
908}
909
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000910void Program::parseVaryings(const char *structure, char *hlsl, VaryingArray &varyings)
911{
912 char *input = strstr(hlsl, structure);
913 input += strlen(structure);
914
915 while (input && *input != '}')
916 {
917 char varyingType[256];
918 char varyingName[256];
919 unsigned int semanticIndex;
920 int matches = sscanf(input, " %s %s : TEXCOORD%d;", varyingType, varyingName, &semanticIndex);
921
922 if (matches == 3)
923 {
924 ASSERT(semanticIndex <= 9); // Single character
925
926 varyings.push_back(Varying(varyingName, input));
927 }
928
929 input = strstr(input, ";");
930 input += 2;
931 }
932}
933
934bool Program::linkVaryings()
935{
936 if (!mPixelHLSL || !mVertexHLSL)
937 {
938 return false;
939 }
940
941 VaryingArray vertexVaryings;
942 VaryingArray pixelVaryings;
943
944 parseVaryings("struct VS_OUTPUT\n{\n", mVertexHLSL, vertexVaryings);
945 parseVaryings("struct PS_INPUT\n{\n", mPixelHLSL, pixelVaryings);
946
947 for (unsigned int out = 0; out < vertexVaryings.size(); out++)
948 {
949 unsigned int in;
950 for (in = 0; in < pixelVaryings.size(); in++)
951 {
952 if (vertexVaryings[out].name == pixelVaryings[in].name)
953 {
954 pixelVaryings[in].link = out;
955 vertexVaryings[out].link = in;
956
957 break;
958 }
959 }
960
961 if (in != pixelVaryings.size())
962 {
963 // FIXME: Verify matching type and qualifiers
964
965 char *outputSemantic = strstr(vertexVaryings[out].declaration, " : TEXCOORD");
966 char *inputSemantic = strstr(pixelVaryings[in].declaration, " : TEXCOORD");
967 outputSemantic[11] = inputSemantic[11];
968 }
969 else
970 {
971 // Comment out the declaration and output assignment
972 vertexVaryings[out].declaration[0] = '/';
973 vertexVaryings[out].declaration[1] = '/';
974
975 char outputString[256];
976 sprintf(outputString, " output.%s = ", vertexVaryings[out].name.c_str());
977 char *varyingOutput = strstr(mVertexHLSL, outputString);
978
979 varyingOutput[0] = '/';
980 varyingOutput[1] = '/';
981 }
982 }
983
984 // Verify that each pixel varying has been linked to a vertex varying
985 for (unsigned int in = 0; in < pixelVaryings.size(); in++)
986 {
987 if (pixelVaryings[in].link < 0)
988 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000989 appendToInfoLog("Pixel varying (%s) does not match any vertex varying", pixelVaryings[in].name);
990
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000991 return false;
992 }
993 }
994
995 return true;
996}
997
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000998// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
999// compiling them into binaries, determining the attribute mappings, and collecting
1000// a list of uniforms
1001void Program::link()
1002{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001003 unlink();
1004
1005 if (!mFragmentShader || !mFragmentShader->isCompiled())
1006 {
1007 return;
1008 }
1009
1010 if (!mVertexShader || !mVertexShader->isCompiled())
1011 {
1012 return;
1013 }
1014
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001015 Context *context = getContext();
1016 const char *vertexProfile = context->getVertexShaderProfile();
1017 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +00001018
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001019 const char *ps = mFragmentShader->getHLSL();
1020 const char *vs = mVertexShader->getHLSL();
1021
1022 mPixelHLSL = new char[strlen(ps) + 1];
1023 strcpy(mPixelHLSL, ps);
1024 mVertexHLSL = new char[strlen(vs) + 1];
1025 strcpy(mVertexHLSL, vs);
1026
1027 if (!linkVaryings())
1028 {
1029 return;
1030 }
1031
1032 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL, vertexProfile, &mConstantTableVS);
1033 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001034
1035 if (vertexBinary && pixelBinary)
1036 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001037 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001038 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1039 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1040
1041 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1042 {
1043 return error(GL_OUT_OF_MEMORY);
1044 }
1045
1046 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001047
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001048 vertexBinary->Release();
1049 pixelBinary->Release();
1050 vertexBinary = NULL;
1051 pixelBinary = NULL;
1052
1053 if (mVertexExecutable && mPixelExecutable)
1054 {
1055 if (!linkAttributes())
1056 {
1057 return;
1058 }
1059
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001060 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001061 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001062 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001063 }
1064
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001065 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001066 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001067 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001068 }
1069
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001070 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001071 }
1072 }
1073}
1074
1075// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1076bool Program::linkAttributes()
1077{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001078 // Link attributes that have a binding location
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001079 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1080 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001081 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1082 int location = getAttributeBinding(attribute.name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001083
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001084 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001085 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001086 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001087 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001088 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001089 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001090
daniel@transgaming.com85423182010-04-22 13:35:27 +00001091 mLinkedAttribute[location] = attribute;
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001092 }
1093 }
1094
1095 // Link attributes that don't have a binding location
1096 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS + 1; attributeIndex++)
1097 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001098 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1099 int location = getAttributeBinding(attribute.name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001100
1101 if (location == -1) // Not set by glBindAttribLocation
1102 {
1103 int availableIndex = 0;
1104
daniel@transgaming.com85423182010-04-22 13:35:27 +00001105 while (availableIndex < MAX_VERTEX_ATTRIBS && !mLinkedAttribute[availableIndex].name.empty())
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001106 {
1107 availableIndex++;
1108 }
1109
1110 if (availableIndex == MAX_VERTEX_ATTRIBS)
1111 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001112 appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001113
1114 return false; // Fail to link
1115 }
1116
daniel@transgaming.com85423182010-04-22 13:35:27 +00001117 mLinkedAttribute[availableIndex] = attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001118 }
1119 }
1120
1121 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1122 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001123 mSemanticIndex[attributeIndex] = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001124 }
1125
1126 return true;
1127}
1128
daniel@transgaming.com85423182010-04-22 13:35:27 +00001129int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001130{
1131 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1132 {
1133 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1134 {
1135 return location;
1136 }
1137 }
1138
1139 return -1;
1140}
1141
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001142bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1143{
1144 D3DXCONSTANTTABLE_DESC constantTableDescription;
1145 D3DXCONSTANT_DESC constantDescription;
1146 UINT descriptionCount = 1;
1147
1148 constantTable->GetDesc(&constantTableDescription);
1149
1150 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1151 {
1152 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1153 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1154
1155 if (!defineUniform(constantHandle, constantDescription))
1156 {
1157 return false;
1158 }
1159 }
1160
1161 return true;
1162}
1163
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001164// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001165// Returns true if succesful (uniform not already defined)
1166bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1167{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001168 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1169 {
1170 unsigned int samplerIndex = constantDescription.RegisterIndex;
1171
1172 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1173
1174 mSamplers[samplerIndex].active = true;
1175 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1176 mSamplers[samplerIndex].logicalTextureUnit = 0;
1177 }
1178
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001179 switch(constantDescription.Class)
1180 {
1181 case D3DXPC_STRUCT:
1182 {
1183 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1184 {
1185 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1186
1187 D3DXCONSTANT_DESC fieldDescription;
1188 UINT descriptionCount = 1;
1189
1190 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1191
1192 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1193 {
1194 return false;
1195 }
1196 }
1197
1198 return true;
1199 }
1200 case D3DXPC_SCALAR:
1201 case D3DXPC_VECTOR:
1202 case D3DXPC_MATRIX_COLUMNS:
1203 case D3DXPC_OBJECT:
1204 return defineUniform(constantDescription, name + constantDescription.Name);
1205 default:
1206 UNREACHABLE();
1207 return false;
1208 }
1209}
1210
1211bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1212{
1213 Uniform *uniform = createUniform(constantDescription, name);
1214
1215 if(!uniform)
1216 {
1217 return false;
1218 }
1219
1220 // Check if already defined
1221 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001222 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001223
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001224 if (location >= 0)
1225 {
1226 delete uniform;
1227
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001228 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001229 {
1230 return false;
1231 }
1232 else
1233 {
1234 return true;
1235 }
1236 }
1237
1238 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001239 unsigned int uniformIndex = mUniforms.size() - 1;
1240
1241 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1242 {
1243 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1244 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001245
1246 return true;
1247}
1248
1249Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001250{
1251 if (constantDescription.Rows == 1) // Vectors and scalars
1252 {
1253 switch (constantDescription.Type)
1254 {
1255 case D3DXPT_SAMPLER2D:
1256 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001257 switch (constantDescription.Columns)
1258 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001259 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001260 default: UNREACHABLE();
1261 }
1262 break;
1263 case D3DXPT_BOOL:
1264 switch (constantDescription.Columns)
1265 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001266 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1267 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1268 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1269 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001270 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001271 }
1272 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001273 case D3DXPT_INT:
1274 switch (constantDescription.Columns)
1275 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001276 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1277 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1278 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1279 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001280 default: UNREACHABLE();
1281 }
1282 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001283 case D3DXPT_FLOAT:
1284 switch (constantDescription.Columns)
1285 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001286 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1287 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1288 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1289 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001290 default: UNREACHABLE();
1291 }
1292 break;
1293 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001294 UNREACHABLE();
1295 }
1296 }
1297 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1298 {
1299 switch (constantDescription.Type)
1300 {
1301 case D3DXPT_FLOAT:
1302 switch (constantDescription.Rows)
1303 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001304 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1305 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1306 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001307 default: UNREACHABLE();
1308 }
1309 break;
1310 default: UNREACHABLE();
1311 }
1312 }
1313 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001314
1315 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001316}
1317
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001318// This methods needs to match OutputHLSL::decorate
1319std::string Program::decorate(const std::string &string)
1320{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001321 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001322 {
1323 return "_" + string;
1324 }
1325 else
1326 {
1327 return string;
1328 }
1329}
1330
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001331bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1332{
1333 BOOL *vector = new BOOL[count];
1334 for (int i = 0; i < count; i++)
1335 {
1336 if (v[i] == GL_FALSE)
1337 vector[i] = 0;
1338 else
1339 vector[i] = 1;
1340 }
1341
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001342 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1343
1344 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1345 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001346 IDirect3DDevice9 *device = getDevice();
1347
1348 if (constantPS)
1349 {
1350 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1351 }
1352
1353 if (constantVS)
1354 {
1355 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1356 }
1357
1358 delete [] vector;
1359
1360 return true;
1361}
1362
1363bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1364{
1365 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1366
1367 for (int i = 0; i < count; i++)
1368 {
1369 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1370 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1371
1372 v += 2;
1373 }
1374
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001375 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1376
1377 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1378 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001379 IDirect3DDevice9 *device = getDevice();
1380
1381 if (constantPS)
1382 {
1383 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1384 }
1385
1386 if (constantVS)
1387 {
1388 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1389 }
1390
1391 delete[] vector;
1392
1393 return true;
1394}
1395
1396bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1397{
1398 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1399
1400 for (int i = 0; i < count; i++)
1401 {
1402 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1403 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1404 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1405
1406 v += 3;
1407 }
1408
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001409 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1410
1411 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1412 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001413 IDirect3DDevice9 *device = getDevice();
1414
1415 if (constantPS)
1416 {
1417 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1418 }
1419
1420 if (constantVS)
1421 {
1422 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1423 }
1424
1425 delete[] vector;
1426
1427 return true;
1428}
1429
1430bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1431{
1432 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1433
1434 for (int i = 0; i < count; i++)
1435 {
1436 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1437 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1438 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1439 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1440
1441 v += 3;
1442 }
1443
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001444 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1445
1446 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1447 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001448 IDirect3DDevice9 *device = getDevice();
1449
1450 if (constantPS)
1451 {
1452 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1453 }
1454
1455 if (constantVS)
1456 {
1457 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1458 }
1459
1460 delete [] vector;
1461
1462 return true;
1463}
1464
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001465bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1466{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001467 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1468
1469 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1470 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001471 IDirect3DDevice9 *device = getDevice();
1472
1473 if (constantPS)
1474 {
1475 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1476 }
1477
1478 if (constantVS)
1479 {
1480 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1481 }
1482
1483 return true;
1484}
1485
1486bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1487{
1488 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1489
1490 for (int i = 0; i < count; i++)
1491 {
1492 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1493
1494 v += 2;
1495 }
1496
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001497 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1498
1499 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1500 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001501 IDirect3DDevice9 *device = getDevice();
1502
1503 if (constantPS)
1504 {
1505 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1506 }
1507
1508 if (constantVS)
1509 {
1510 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1511 }
1512
1513 delete[] vector;
1514
1515 return true;
1516}
1517
1518bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1519{
1520 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1521
1522 for (int i = 0; i < count; i++)
1523 {
1524 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1525
1526 v += 3;
1527 }
1528
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001529 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1530
1531 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1532 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001533 IDirect3DDevice9 *device = getDevice();
1534
1535 if (constantPS)
1536 {
1537 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1538 }
1539
1540 if (constantVS)
1541 {
1542 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1543 }
1544
1545 delete[] vector;
1546
1547 return true;
1548}
1549
1550bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1551{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001552 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1553
1554 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1555 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001556 IDirect3DDevice9 *device = getDevice();
1557
1558 if (constantPS)
1559 {
1560 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
1561 }
1562
1563 if (constantVS)
1564 {
1565 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
1566 }
1567
1568 return true;
1569}
1570
1571bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
1572{
1573 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1574
1575 for (int i = 0; i < count; i++)
1576 {
1577 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
1578 value[1], value[3], 0, 0,
1579 0, 0, 1, 0,
1580 0, 0, 0, 1);
1581
1582 value += 4;
1583 }
1584
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001585 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1586
1587 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1588 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001589 IDirect3DDevice9 *device = getDevice();
1590
1591 if (constantPS)
1592 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001593 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001594 }
1595
1596 if (constantVS)
1597 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001598 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001599 }
1600
1601 delete[] matrix;
1602
1603 return true;
1604}
1605
1606bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
1607{
1608 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1609
1610 for (int i = 0; i < count; i++)
1611 {
1612 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
1613 value[1], value[4], value[7], 0,
1614 value[2], value[5], value[8], 0,
1615 0, 0, 0, 1);
1616
1617 value += 9;
1618 }
1619
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001620 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1621
1622 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1623 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001624 IDirect3DDevice9 *device = getDevice();
1625
1626 if (constantPS)
1627 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001628 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001629 }
1630
1631 if (constantVS)
1632 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001633 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001634 }
1635
1636 delete[] matrix;
1637
1638 return true;
1639}
1640
1641bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
1642{
1643 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1644
1645 for (int i = 0; i < count; i++)
1646 {
1647 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
1648 value[1], value[5], value[9], value[13],
1649 value[2], value[6], value[10], value[14],
1650 value[3], value[7], value[11], value[15]);
1651
1652 value += 16;
1653 }
1654
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001655 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1656
1657 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1658 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001659 IDirect3DDevice9 *device = getDevice();
1660
1661 if (constantPS)
1662 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001663 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001664 }
1665
1666 if (constantVS)
1667 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001668 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001669 }
1670
1671 delete[] matrix;
1672
1673 return true;
1674}
1675
1676bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
1677{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001678 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1679
1680 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1681 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001682 IDirect3DDevice9 *device = getDevice();
1683
1684 if (constantPS)
1685 {
1686 D3DXCONSTANT_DESC constantDescription;
1687 UINT descriptionCount = 1;
1688 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
1689
daniel@transgaming.com2884b782010-03-08 21:30:48 +00001690 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001691 {
1692 return false;
1693 }
1694
1695 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1696 {
1697 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
1698
1699 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
1700 {
1701 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001702
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001703 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
1704 {
1705 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1706 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001707 ASSERT(mSamplers[samplerIndex].active);
1708 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001709 }
1710 }
1711 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001712
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001713 return true;
1714 }
1715 }
1716
1717 if (constantPS)
1718 {
1719 mConstantTablePS->SetIntArray(device, constantPS, v, count);
1720 }
1721
1722 if (constantVS)
1723 {
1724 mConstantTableVS->SetIntArray(device, constantVS, v, count);
1725 }
1726
1727 return true;
1728}
1729
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001730bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
1731{
1732 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1733
1734 for (int i = 0; i < count; i++)
1735 {
1736 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
1737
1738 v += 2;
1739 }
1740
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001741 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1742
1743 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1744 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001745 IDirect3DDevice9 *device = getDevice();
1746
1747 if (constantPS)
1748 {
1749 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1750 }
1751
1752 if (constantVS)
1753 {
1754 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1755 }
1756
1757 delete[] vector;
1758
1759 return true;
1760}
1761
1762bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
1763{
1764 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1765
1766 for (int i = 0; i < count; i++)
1767 {
1768 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
1769
1770 v += 3;
1771 }
1772
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001773 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1774
1775 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1776 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001777 IDirect3DDevice9 *device = getDevice();
1778
1779 if (constantPS)
1780 {
1781 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1782 }
1783
1784 if (constantVS)
1785 {
1786 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1787 }
1788
1789 delete[] vector;
1790
1791 return true;
1792}
1793
1794bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
1795{
1796 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1797
1798 for (int i = 0; i < count; i++)
1799 {
1800 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
1801
1802 v += 4;
1803 }
1804
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001805 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1806
1807 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1808 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001809 IDirect3DDevice9 *device = getDevice();
1810
1811 if (constantPS)
1812 {
1813 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1814 }
1815
1816 if (constantVS)
1817 {
1818 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1819 }
1820
1821 delete [] vector;
1822
1823 return true;
1824}
1825
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001826void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001827{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001828 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001829 {
1830 return;
1831 }
1832
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001833 char info[1024];
1834
1835 va_list vararg;
1836 va_start(vararg, format);
1837 vsnprintf(info, sizeof(info), format, vararg);
1838 va_end(vararg);
1839
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001840 size_t infoLength = strlen(info);
1841
1842 if (!mInfoLog)
1843 {
1844 mInfoLog = new char[infoLength + 1];
1845 strcpy(mInfoLog, info);
1846 }
1847 else
1848 {
1849 size_t logLength = strlen(mInfoLog);
1850 char *newLog = new char[logLength + infoLength + 1];
1851 strcpy(newLog, mInfoLog);
1852 strcpy(newLog + logLength, info);
1853
1854 delete[] mInfoLog;
1855 mInfoLog = newLog;
1856 }
1857}
1858
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001859// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
1860void Program::unlink(bool destroy)
1861{
1862 if (destroy) // Object being destructed
1863 {
1864 if (mFragmentShader)
1865 {
1866 mFragmentShader->detach();
1867 mFragmentShader = NULL;
1868 }
1869
1870 if (mVertexShader)
1871 {
1872 mVertexShader->detach();
1873 mVertexShader = NULL;
1874 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001875 }
1876
1877 if (mPixelExecutable)
1878 {
1879 mPixelExecutable->Release();
1880 mPixelExecutable = NULL;
1881 }
1882
1883 if (mVertexExecutable)
1884 {
1885 mVertexExecutable->Release();
1886 mVertexExecutable = NULL;
1887 }
1888
1889 if (mConstantTablePS)
1890 {
1891 mConstantTablePS->Release();
1892 mConstantTablePS = NULL;
1893 }
1894
1895 if (mConstantTableVS)
1896 {
1897 mConstantTableVS->Release();
1898 mConstantTableVS = NULL;
1899 }
1900
1901 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1902 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001903 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001904 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001905 }
1906
1907 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
1908 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001909 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001910 }
1911
1912 while (!mUniforms.empty())
1913 {
1914 delete mUniforms.back();
1915 mUniforms.pop_back();
1916 }
1917
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001918 mUniformIndex.clear();
1919
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001920 delete[] mPixelHLSL;
1921 mPixelHLSL = NULL;
1922
1923 delete[] mVertexHLSL;
1924 mVertexHLSL = NULL;
1925
1926 delete[] mInfoLog;
1927 mInfoLog = NULL;
1928
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001929 mLinked = false;
1930}
1931
1932bool Program::isLinked()
1933{
1934 return mLinked;
1935}
1936
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001937int Program::getInfoLogLength() const
1938{
1939 if (!mInfoLog)
1940 {
1941 return 0;
1942 }
1943 else
1944 {
1945 return strlen(mInfoLog) + 1;
1946 }
1947}
1948
1949void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
1950{
1951 int index = 0;
1952
1953 if (mInfoLog)
1954 {
1955 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
1956 {
1957 infoLog[index] = mInfoLog[index];
1958 index++;
1959 }
1960 }
1961
1962 if (bufSize)
1963 {
1964 infoLog[index] = '\0';
1965 }
1966
1967 if (length)
1968 {
1969 *length = index;
1970 }
1971}
1972
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001973void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
1974{
1975 int total = 0;
1976
1977 if (mVertexShader)
1978 {
1979 if (total < maxCount)
1980 {
1981 shaders[total] = mVertexShader->getHandle();
1982 }
1983
1984 total++;
1985 }
1986
1987 if (mFragmentShader)
1988 {
1989 if (total < maxCount)
1990 {
1991 shaders[total] = mFragmentShader->getHandle();
1992 }
1993
1994 total++;
1995 }
1996
1997 if (count)
1998 {
1999 *count = total;
2000 }
2001}
2002
daniel@transgaming.com85423182010-04-22 13:35:27 +00002003void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2004{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002005 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002006 for (unsigned int i = 0; i < index; i++)
2007 {
2008 do
2009 {
2010 attribute++;
2011
2012 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2013 }
2014 while (mLinkedAttribute[attribute].name.empty());
2015 }
2016
2017 if (bufsize > 0)
2018 {
2019 const char *string = mLinkedAttribute[attribute].name.c_str();
2020
2021 strncpy(name, string, bufsize);
2022 name[bufsize - 1] = '\0';
2023
2024 if (length)
2025 {
2026 *length = strlen(name);
2027 }
2028 }
2029
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002030 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002031
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002032 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002033}
2034
2035GLint Program::getActiveAttributeCount()
2036{
2037 int count = 0;
2038
2039 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2040 {
2041 if (!mLinkedAttribute[attributeIndex].name.empty())
2042 {
2043 count++;
2044 }
2045 }
2046
2047 return count;
2048}
2049
2050GLint Program::getActiveAttributeMaxLength()
2051{
2052 int maxLength = 0;
2053
2054 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2055 {
2056 if (!mLinkedAttribute[attributeIndex].name.empty())
2057 {
2058 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2059 }
2060 }
2061
2062 return maxLength;
2063}
2064
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002065void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2066{
2067 unsigned int uniform = 0;
2068 for (unsigned int i = 0; i < index; i++)
2069 {
2070 do
2071 {
2072 uniform++;
2073
2074 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2075 }
2076 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2077 }
2078
2079 if (bufsize > 0)
2080 {
2081 const char *string = mUniforms[uniform]->name.c_str();
2082
2083 if(string[0] == '_') // Undecorate
2084 {
2085 string++;
2086 }
2087
2088 strncpy(name, string, bufsize);
2089 name[bufsize - 1] = '\0';
2090
2091 if (length)
2092 {
2093 *length = strlen(name);
2094 }
2095 }
2096
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002097 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002098
2099 *type = mUniforms[uniform]->type;
2100}
2101
2102GLint Program::getActiveUniformCount()
2103{
2104 int count = 0;
2105
2106 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2107 {
2108 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2109 {
2110 count++;
2111 }
2112 }
2113
2114 return count;
2115}
2116
2117GLint Program::getActiveUniformMaxLength()
2118{
2119 int maxLength = 0;
2120
2121 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2122 {
2123 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2124 {
2125 maxLength = std::max((int)(mUniforms[uniformIndex]->name.length() + 1), maxLength);
2126 }
2127 }
2128
2129 return maxLength;
2130}
2131
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002132void Program::flagForDeletion()
2133{
2134 mDeleteStatus = true;
2135}
2136
2137bool Program::isFlaggedForDeletion() const
2138{
2139 return mDeleteStatus;
2140}
2141}