blob: c18ee920049c5fe5d53b761d6393d4dcdbf3917b [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.com4fa08332010-05-11 02:29:27 +000020unsigned int Program::mCurrentSerial = 1;
21
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000022Uniform::Uniform(GLenum type, const std::string &name, unsigned int arraySize) : type(type), name(name), arraySize(arraySize)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000023{
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +000024 int bytes = UniformTypeSize(type) * arraySize;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000025 data = new unsigned char[bytes];
26 memset(data, 0, bytes);
27 dirty = true;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000028}
29
30Uniform::~Uniform()
31{
32 delete[] data;
33}
34
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +000035UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
36 : name(name), element(element), index(index)
37{
38}
39
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000040Program::Program()
41{
42 mFragmentShader = NULL;
43 mVertexShader = NULL;
44
45 mPixelExecutable = NULL;
46 mVertexExecutable = NULL;
47 mConstantTablePS = NULL;
48 mConstantTableVS = NULL;
49
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +000050 mPixelHLSL = NULL;
51 mVertexHLSL = NULL;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000052 mInfoLog = NULL;
daniel@transgaming.com86a7a132010-04-29 03:32:32 +000053 mValidated = false;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000054
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000055 unlink();
56
57 mDeleteStatus = false;
daniel@transgaming.com4fa08332010-05-11 02:29:27 +000058
59 mSerial = issueSerial();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000060}
61
62Program::~Program()
63{
64 unlink(true);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +000065
66 if (mVertexShader != NULL)
67 {
68 mVertexShader->detach();
69 }
70
71 if (mFragmentShader != NULL)
72 {
73 mFragmentShader->detach();
74 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000075}
76
77bool Program::attachShader(Shader *shader)
78{
79 if (shader->getType() == GL_VERTEX_SHADER)
80 {
81 if (mVertexShader)
82 {
83 return false;
84 }
85
86 mVertexShader = (VertexShader*)shader;
87 mVertexShader->attach();
88 }
89 else if (shader->getType() == GL_FRAGMENT_SHADER)
90 {
91 if (mFragmentShader)
92 {
93 return false;
94 }
95
96 mFragmentShader = (FragmentShader*)shader;
97 mFragmentShader->attach();
98 }
99 else UNREACHABLE();
100
101 return true;
102}
103
104bool Program::detachShader(Shader *shader)
105{
106 if (shader->getType() == GL_VERTEX_SHADER)
107 {
108 if (mVertexShader != shader)
109 {
110 return false;
111 }
112
113 mVertexShader->detach();
114 mVertexShader = NULL;
115 }
116 else if (shader->getType() == GL_FRAGMENT_SHADER)
117 {
118 if (mFragmentShader != shader)
119 {
120 return false;
121 }
122
123 mFragmentShader->detach();
124 mFragmentShader = NULL;
125 }
126 else UNREACHABLE();
127
128 unlink();
129
130 return true;
131}
132
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000133int Program::getAttachedShadersCount() const
134{
135 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
136}
137
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138IDirect3DPixelShader9 *Program::getPixelShader()
139{
140 return mPixelExecutable;
141}
142
143IDirect3DVertexShader9 *Program::getVertexShader()
144{
145 return mVertexExecutable;
146}
147
148void Program::bindAttributeLocation(GLuint index, const char *name)
149{
150 if (index < MAX_VERTEX_ATTRIBS)
151 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000152 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
153 {
154 mAttributeBinding[i].erase(name);
155 }
156
157 mAttributeBinding[index].insert(name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000158 }
159}
160
161GLuint Program::getAttributeLocation(const char *name)
162{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000163 if (name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000165 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000166 {
daniel@transgaming.com85423182010-04-22 13:35:27 +0000167 if (mLinkedAttribute[index].name == std::string(name))
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000168 {
169 return index;
170 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000171 }
172 }
173
174 return -1;
175}
176
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000177int Program::getSemanticIndex(int attributeIndex)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000178{
179 if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS)
180 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000181 return mSemanticIndex[attributeIndex];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000182 }
183
184 return -1;
185}
186
187// Returns the index of the texture unit corresponding to a Direct3D 9 sampler
188// index referenced in the compiled HLSL shader
189GLint Program::getSamplerMapping(unsigned int samplerIndex)
190{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000191 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
192
193 if (mSamplers[samplerIndex].active)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000194 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000195 return mSamplers[samplerIndex].logicalTextureUnit;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000196 }
197
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000198 return -1;
199}
200
201SamplerType Program::getSamplerType(unsigned int samplerIndex)
202{
203 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
204 assert(mSamplers[samplerIndex].active);
205
206 return mSamplers[samplerIndex].type;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000207}
208
209GLint Program::getUniformLocation(const char *name)
210{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000211 std::string nameStr(name);
212 int subscript = 0;
213 size_t beginB = nameStr.find('[');
214 size_t endB = nameStr.find(']');
215 if (beginB != std::string::npos && endB != std::string::npos)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000216 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000217 std::string subscrStr = nameStr.substr(beginB + 1, beginB - endB - 1);
218 nameStr.erase(beginB);
219 subscript = atoi(subscrStr.c_str());
220 }
221
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000222 nameStr = decorate(nameStr);
223
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000224 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
225 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000226 if (mUniformIndex[location].name == nameStr &&
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000227 mUniformIndex[location].element == subscript)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000228 {
229 return location;
230 }
231 }
232
233 return -1;
234}
235
236bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
237{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000238 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000239 {
240 return false;
241 }
242
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000243 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000244 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000245
246 if (targetUniform->type == GL_FLOAT)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000247 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000248 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000249
250 if (arraySize == 1 && count > 1)
251 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
252
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000253 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000254
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000255 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
256 v, sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000257 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000258 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000259 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000260 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000261
262 if (arraySize == 1 && count > 1)
263 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000264
265 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000266 GLboolean *boolParams = new GLboolean[count];
267
268 for (int i = 0; i < count; ++i)
269 {
270 if (v[i] == 0.0f)
271 {
272 boolParams[i] = GL_FALSE;
273 }
274 else
275 {
276 boolParams[i] = GL_TRUE;
277 }
278 }
279
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000280 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
281 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000282
283 delete [] boolParams;
284 }
285 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000286 {
287 return false;
288 }
289
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000290 return true;
291}
292
293bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
294{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000295 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296 {
297 return false;
298 }
299
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000300 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000301 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000302
303 if (targetUniform->type == GL_FLOAT_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000304 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000305 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000306
307 if (arraySize == 1 && count > 1)
308 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
309
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000310 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000311
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000312 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
313 v, 2 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000314 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000315 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000316 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000317 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000318
319 if (arraySize == 1 && count > 1)
320 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
321
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000322 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
323
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000324 GLboolean *boolParams = new GLboolean[count * 2];
325
326 for (int i = 0; i < count * 2; ++i)
327 {
328 if (v[i] == 0.0f)
329 {
330 boolParams[i] = GL_FALSE;
331 }
332 else
333 {
334 boolParams[i] = GL_TRUE;
335 }
336 }
337
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000338 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
339 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000340
341 delete [] boolParams;
342 }
343 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000344 {
345 return false;
346 }
347
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000348 return true;
349}
350
351bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
352{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000353 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000354 {
355 return false;
356 }
357
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000358 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000359 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000360
361 if (targetUniform->type == GL_FLOAT_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000362 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000363 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000364
365 if (arraySize == 1 && count > 1)
366 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
367
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000368 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000369
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000370 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
371 v, 3 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000372 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000373 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000374 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000375 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000376
377 if (arraySize == 1 && count > 1)
378 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
379
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000380 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000381 GLboolean *boolParams = new GLboolean[count * 3];
382
383 for (int i = 0; i < count * 3; ++i)
384 {
385 if (v[i] == 0.0f)
386 {
387 boolParams[i] = GL_FALSE;
388 }
389 else
390 {
391 boolParams[i] = GL_TRUE;
392 }
393 }
394
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000395 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
396 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000397
398 delete [] boolParams;
399 }
400 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000401 {
402 return false;
403 }
404
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000405 return true;
406}
407
408bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
409{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000410 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000411 {
412 return false;
413 }
414
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000415 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000416 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000417
418 if (targetUniform->type == GL_FLOAT_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000419 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000420 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000421
422 if (arraySize == 1 && count > 1)
423 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
424
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000425 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000426
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000427 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
428 v, 4 * sizeof(GLfloat) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000429 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000430 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000431 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000432 int arraySize = targetUniform->arraySize;
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000433
434 if (arraySize == 1 && count > 1)
435 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
436
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000437 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000438 GLboolean *boolParams = new GLboolean[count * 4];
439
440 for (int i = 0; i < count * 4; ++i)
441 {
442 if (v[i] == 0.0f)
443 {
444 boolParams[i] = GL_FALSE;
445 }
446 else
447 {
448 boolParams[i] = GL_TRUE;
449 }
450 }
451
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000452 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
453 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +0000454
455 delete [] boolParams;
456 }
457 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000458 {
459 return false;
460 }
461
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000462 return true;
463}
464
465bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
466{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000467 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000468 {
469 return false;
470 }
471
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000472 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000473 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000474
475 if (targetUniform->type != GL_FLOAT_MAT2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000476 {
477 return false;
478 }
479
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000480 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000481
482 if (arraySize == 1 && count > 1)
483 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
484
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000485 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000486
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000487 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
488 value, 4 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000489
490 return true;
491}
492
493bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
494{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000495 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000496 {
497 return false;
498 }
499
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000500 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000501 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000502
503 if (targetUniform->type != GL_FLOAT_MAT3)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000504 {
505 return false;
506 }
507
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000508 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000509
510 if (arraySize == 1 && count > 1)
511 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
512
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000513 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000514
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000515 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
516 value, 9 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000517
518 return true;
519}
520
521bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
522{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000523 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000524 {
525 return false;
526 }
527
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000528 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000529 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000530
531 if (targetUniform->type != GL_FLOAT_MAT4)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000532 {
533 return false;
534 }
535
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(GLfloat) * 16,
544 value, 16 * sizeof(GLfloat) * count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000545
546 return true;
547}
548
549bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
550{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000551 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000552 {
553 return false;
554 }
555
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000556 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000557 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000558
559 if (targetUniform->type == GL_INT)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000560 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000561 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000562
563 if (arraySize == 1 && count > 1)
564 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
565
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000566 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000567
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000568 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
569 v, sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000570 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000571 else if (targetUniform->type == GL_BOOL)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000572 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000573 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000574
575 if (arraySize == 1 && count > 1)
576 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
577
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000578 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000579 GLboolean *boolParams = new GLboolean[count];
580
581 for (int i = 0; i < count; ++i)
582 {
583 if (v[i] == 0)
584 {
585 boolParams[i] = GL_FALSE;
586 }
587 else
588 {
589 boolParams[i] = GL_TRUE;
590 }
591 }
592
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000593 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
594 boolParams, sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000595
596 delete [] boolParams;
597 }
598 else
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000599 {
600 return false;
601 }
602
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000603 return true;
604}
605
606bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
607{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000608 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000609 {
610 return false;
611 }
612
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000613 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000614 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000615
616 if (targetUniform->type == GL_INT_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000617 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000618 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000619
620 if (arraySize == 1 && count > 1)
621 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
622
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000623 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000624
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000625 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
626 v, 2 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000627 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000628 else if (targetUniform->type == GL_BOOL_VEC2)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000629 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000630 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000631
632 if (arraySize == 1 && count > 1)
633 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
634
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000635 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000636 GLboolean *boolParams = new GLboolean[count * 2];
637
638 for (int i = 0; i < count * 2; ++i)
639 {
640 if (v[i] == 0)
641 {
642 boolParams[i] = GL_FALSE;
643 }
644 else
645 {
646 boolParams[i] = GL_TRUE;
647 }
648 }
649
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000650 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
651 boolParams, 2 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000652
653 delete [] boolParams;
654 }
655 else
656 {
657 return false;
658 }
659
660 return true;
661}
662
663bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
664{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000665 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000666 {
667 return false;
668 }
669
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000670 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000671 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000672
673 if (targetUniform->type == GL_INT_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000674 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000675 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000676
677 if (arraySize == 1 && count > 1)
678 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
679
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000680 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000681
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000682 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
683 v, 3 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000684 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000685 else if (targetUniform->type == GL_BOOL_VEC3)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000686 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000687 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000688
689 if (arraySize == 1 && count > 1)
690 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
691
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000692 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000693 GLboolean *boolParams = new GLboolean[count * 3];
694
695 for (int i = 0; i < count * 3; ++i)
696 {
697 if (v[i] == 0)
698 {
699 boolParams[i] = GL_FALSE;
700 }
701 else
702 {
703 boolParams[i] = GL_TRUE;
704 }
705 }
706
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000707 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
708 boolParams, 3 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000709
710 delete [] boolParams;
711 }
712 else
713 {
714 return false;
715 }
716
717 return true;
718}
719
720bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
721{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000722 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000723 {
724 return false;
725 }
726
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000727 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000728 targetUniform->dirty = true;
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000729
730 if (targetUniform->type == GL_INT_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000731 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000732 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000733
734 if (arraySize == 1 && count > 1)
735 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
736
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000737 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000738
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000739 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
740 v, 4 * sizeof(GLint) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000741 }
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000742 else if (targetUniform->type == GL_BOOL_VEC4)
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000743 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000744 int arraySize = targetUniform->arraySize;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000745
746 if (arraySize == 1 && count > 1)
747 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
748
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000749 count = std::min(arraySize - (int)mUniformIndex[location].element, count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000750 GLboolean *boolParams = new GLboolean[count * 4];
751
752 for (int i = 0; i < count * 4; ++i)
753 {
754 if (v[i] == 0)
755 {
756 boolParams[i] = GL_FALSE;
757 }
758 else
759 {
760 boolParams[i] = GL_TRUE;
761 }
762 }
763
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000764 memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
765 boolParams, 4 * sizeof(GLboolean) * count);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +0000766
767 delete [] boolParams;
768 }
769 else
770 {
771 return false;
772 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000773
774 return true;
775}
776
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000777bool Program::getUniformfv(GLint location, GLfloat *params)
778{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000779 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000780 {
781 return false;
782 }
783
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000784 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000785
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000786 unsigned int count = UniformComponentCount(targetUniform->type);
787
788 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000789 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000790 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000791 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000792 GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000793
794 for (unsigned int i = 0; i < count; ++i)
795 {
796 params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
797 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000798 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000799 break;
800 case GL_FLOAT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000801 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
802 count * sizeof(GLfloat));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000803 break;
804 case GL_INT:
805 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000806 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000807
808 for (unsigned int i = 0; i < count; ++i)
809 {
810 params[i] = (float)intParams[i];
811 }
812 }
813 break;
814 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000815 }
816
817 return true;
818}
819
820bool Program::getUniformiv(GLint location, GLint *params)
821{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000822 if (location < 0 || location >= (int)mUniformIndex.size())
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000823 {
824 return false;
825 }
826
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000827 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000828
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000829 unsigned int count = UniformComponentCount(targetUniform->type);
830
831 switch (UniformComponentType(targetUniform->type))
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000832 {
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000833 case GL_BOOL:
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000834 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000835 GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000836
837 for (unsigned int i = 0; i < count; ++i)
838 {
839 params[i] = (GLint)boolParams[i];
840 }
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000841 }
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000842 break;
843 case GL_FLOAT:
844 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000845 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000846
847 for (unsigned int i = 0; i < count; ++i)
848 {
849 params[i] = (GLint)floatParams[i];
850 }
851 }
852 break;
853 case GL_INT:
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000854 memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
855 count * sizeof(GLint));
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +0000856 break;
857 default: UNREACHABLE();
daniel@transgaming.combb3d9d02010-04-13 03:26:06 +0000858 }
859
860 return true;
861}
862
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000863void Program::dirtyAllUniforms()
864{
865 for (unsigned int index = 0; index < mUniforms.size(); index++)
866 {
867 mUniforms[index]->dirty = true;
868 }
869}
870
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000871// Applies all the uniforms set for this program object to the Direct3D 9 device
872void Program::applyUniforms()
873{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000874 for (unsigned int location = 0; location < mUniformIndex.size(); location++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000875 {
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000876 if (mUniformIndex[location].element != 0)
877 {
878 continue;
879 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000880
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +0000881 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
882
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000883 if (targetUniform->dirty)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000884 {
daniel@transgaming.com4fa08332010-05-11 02:29:27 +0000885 int arraySize = targetUniform->arraySize;
886 GLfloat *f = (GLfloat*)targetUniform->data;
887 GLint *i = (GLint*)targetUniform->data;
888 GLboolean *b = (GLboolean*)targetUniform->data;
889
890 switch (targetUniform->type)
891 {
892 case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
893 case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
894 case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
895 case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
896 case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
897 case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
898 case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
899 case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
900 case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
901 case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
902 case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
903 case GL_INT: applyUniform1iv(location, arraySize, i); break;
904 case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
905 case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
906 case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
907 default:
908 UNREACHABLE();
909 }
910
911 targetUniform->dirty = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000912 }
913 }
914}
915
916// Compiles the HLSL code of the attached shaders into executable binaries
917ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
918{
919 if (!hlsl)
920 {
921 return NULL;
922 }
923
924 ID3DXBuffer *binary = NULL;
925 ID3DXBuffer *errorMessage = NULL;
926
daniel@transgaming.com0f189612010-05-07 13:03:36 +0000927 HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, NULL, "main", profile, 0, &binary, &errorMessage, constantTable);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000928
929 if (SUCCEEDED(result))
930 {
931 return binary;
932 }
933
934 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
935 {
936 return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL);
937 }
938
939 if (errorMessage)
940 {
941 const char *message = (const char*)errorMessage->GetBufferPointer();
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000942
daniel@transgaming.com0599dc62010-03-21 04:31:36 +0000943 TRACE("\n%s", hlsl);
944 TRACE("\n%s", message);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000945 }
946
947 return NULL;
948}
949
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000950void Program::parseVaryings(const char *structure, char *hlsl, VaryingArray &varyings)
951{
952 char *input = strstr(hlsl, structure);
953 input += strlen(structure);
954
955 while (input && *input != '}')
956 {
957 char varyingType[256];
958 char varyingName[256];
959 unsigned int semanticIndex;
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000960
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000961 int matches = sscanf(input, " %s %s : TEXCOORD%d;", varyingType, varyingName, &semanticIndex);
962
963 if (matches == 3)
964 {
965 ASSERT(semanticIndex <= 9); // Single character
966
daniel@transgaming.com51d0dc22010-04-29 03:39:11 +0000967 char *array = strstr(varyingName, "[");
968
969 if (array)
970 {
971 *array = '\0';
972 }
973
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000974 varyings.push_back(Varying(varyingName, input));
975 }
976
977 input = strstr(input, ";");
978 input += 2;
979 }
980}
981
982bool Program::linkVaryings()
983{
984 if (!mPixelHLSL || !mVertexHLSL)
985 {
986 return false;
987 }
988
989 VaryingArray vertexVaryings;
990 VaryingArray pixelVaryings;
991
992 parseVaryings("struct VS_OUTPUT\n{\n", mVertexHLSL, vertexVaryings);
993 parseVaryings("struct PS_INPUT\n{\n", mPixelHLSL, pixelVaryings);
994
995 for (unsigned int out = 0; out < vertexVaryings.size(); out++)
996 {
997 unsigned int in;
998 for (in = 0; in < pixelVaryings.size(); in++)
999 {
1000 if (vertexVaryings[out].name == pixelVaryings[in].name)
1001 {
1002 pixelVaryings[in].link = out;
1003 vertexVaryings[out].link = in;
1004
1005 break;
1006 }
1007 }
1008
1009 if (in != pixelVaryings.size())
1010 {
1011 // FIXME: Verify matching type and qualifiers
1012
1013 char *outputSemantic = strstr(vertexVaryings[out].declaration, " : TEXCOORD");
1014 char *inputSemantic = strstr(pixelVaryings[in].declaration, " : TEXCOORD");
1015 outputSemantic[11] = inputSemantic[11];
1016 }
1017 else
1018 {
1019 // Comment out the declaration and output assignment
1020 vertexVaryings[out].declaration[0] = '/';
1021 vertexVaryings[out].declaration[1] = '/';
1022
1023 char outputString[256];
1024 sprintf(outputString, " output.%s = ", vertexVaryings[out].name.c_str());
1025 char *varyingOutput = strstr(mVertexHLSL, outputString);
1026
1027 varyingOutput[0] = '/';
1028 varyingOutput[1] = '/';
1029 }
1030 }
1031
1032 // Verify that each pixel varying has been linked to a vertex varying
1033 for (unsigned int in = 0; in < pixelVaryings.size(); in++)
1034 {
1035 if (pixelVaryings[in].link < 0)
1036 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001037 appendToInfoLog("Pixel varying (%s) does not match any vertex varying", pixelVaryings[in].name);
1038
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001039 return false;
1040 }
1041 }
1042
1043 return true;
1044}
1045
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001046// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
1047// compiling them into binaries, determining the attribute mappings, and collecting
1048// a list of uniforms
1049void Program::link()
1050{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001051 unlink();
1052
1053 if (!mFragmentShader || !mFragmentShader->isCompiled())
1054 {
1055 return;
1056 }
1057
1058 if (!mVertexShader || !mVertexShader->isCompiled())
1059 {
1060 return;
1061 }
1062
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001063 Context *context = getContext();
1064 const char *vertexProfile = context->getVertexShaderProfile();
1065 const char *pixelProfile = context->getPixelShaderProfile();
daniel@transgaming.comdebe2592010-03-24 09:44:08 +00001066
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001067 const char *ps = mFragmentShader->getHLSL();
1068 const char *vs = mVertexShader->getHLSL();
1069
1070 mPixelHLSL = new char[strlen(ps) + 1];
1071 strcpy(mPixelHLSL, ps);
1072 mVertexHLSL = new char[strlen(vs) + 1];
1073 strcpy(mVertexHLSL, vs);
1074
1075 if (!linkVaryings())
1076 {
1077 return;
1078 }
1079
1080 ID3DXBuffer *vertexBinary = compileToBinary(mVertexHLSL, vertexProfile, &mConstantTableVS);
1081 ID3DXBuffer *pixelBinary = compileToBinary(mPixelHLSL, pixelProfile, &mConstantTablePS);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001082
1083 if (vertexBinary && pixelBinary)
1084 {
daniel@transgaming.com296ca9c2010-04-03 20:56:07 +00001085 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001086 HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
1087 HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
1088
1089 if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
1090 {
1091 return error(GL_OUT_OF_MEMORY);
1092 }
1093
1094 ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001095
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001096 vertexBinary->Release();
1097 pixelBinary->Release();
1098 vertexBinary = NULL;
1099 pixelBinary = NULL;
1100
1101 if (mVertexExecutable && mPixelExecutable)
1102 {
1103 if (!linkAttributes())
1104 {
1105 return;
1106 }
1107
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001108 if (!linkUniforms(mConstantTablePS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001109 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001110 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001111 }
1112
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001113 if (!linkUniforms(mConstantTableVS))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001114 {
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001115 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001116 }
1117
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001118 mLinked = true; // Success
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001119 }
1120 }
1121}
1122
1123// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
1124bool Program::linkAttributes()
1125{
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001126 unsigned int usedLocations = 0;
1127
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001128 // Link attributes that have a binding location
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001129 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1130 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001131 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1132 int location = getAttributeBinding(attribute.name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001133
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001134 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001135 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001136 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001137 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001138 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001139 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001140
daniel@transgaming.com85423182010-04-22 13:35:27 +00001141 mLinkedAttribute[location] = attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001142
1143 int size = AttributeVectorCount(attribute.type);
1144
1145 if (size + location > MAX_VERTEX_ATTRIBS)
1146 {
1147 appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
1148
1149 return false;
1150 }
1151
1152 for (int i = 0; i < size; i++)
1153 {
1154 usedLocations |= 1 << (location + i);
1155 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001156 }
1157 }
1158
1159 // Link attributes that don't have a binding location
1160 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS + 1; attributeIndex++)
1161 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001162 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1163 int location = getAttributeBinding(attribute.name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001164
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001165 if (!attribute.name.empty() && location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001166 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001167 int size = AttributeVectorCount(attribute.type);
1168 int availableIndex = AllocateFirstFreeBits(&usedLocations, size, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001169
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001170 if (availableIndex == -1 || availableIndex + size > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001171 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001172 appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001173
1174 return false; // Fail to link
1175 }
1176
daniel@transgaming.com85423182010-04-22 13:35:27 +00001177 mLinkedAttribute[availableIndex] = attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001178 }
1179 }
1180
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001181 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001182 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001183 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1184
1185 if (index == -1)
1186 {
1187 mSemanticIndex[attributeIndex++] = -1;
1188 }
1189 else
1190 {
1191 int size = AttributeVectorCount(mVertexShader->getAttribute(index).type);
1192
1193 for (int i = 0; i < size; i++)
1194 {
1195 mSemanticIndex[attributeIndex++] = index++;
1196 }
1197 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001198 }
1199
1200 return true;
1201}
1202
daniel@transgaming.com85423182010-04-22 13:35:27 +00001203int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001204{
1205 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1206 {
1207 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1208 {
1209 return location;
1210 }
1211 }
1212
1213 return -1;
1214}
1215
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001216bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1217{
1218 D3DXCONSTANTTABLE_DESC constantTableDescription;
1219 D3DXCONSTANT_DESC constantDescription;
1220 UINT descriptionCount = 1;
1221
1222 constantTable->GetDesc(&constantTableDescription);
1223
1224 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1225 {
1226 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1227 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1228
1229 if (!defineUniform(constantHandle, constantDescription))
1230 {
1231 return false;
1232 }
1233 }
1234
1235 return true;
1236}
1237
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001238// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001239// Returns true if succesful (uniform not already defined)
1240bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1241{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001242 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1243 {
1244 unsigned int samplerIndex = constantDescription.RegisterIndex;
1245
1246 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1247
1248 mSamplers[samplerIndex].active = true;
1249 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1250 mSamplers[samplerIndex].logicalTextureUnit = 0;
1251 }
1252
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001253 switch(constantDescription.Class)
1254 {
1255 case D3DXPC_STRUCT:
1256 {
1257 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1258 {
1259 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1260
1261 D3DXCONSTANT_DESC fieldDescription;
1262 UINT descriptionCount = 1;
1263
1264 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1265
1266 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1267 {
1268 return false;
1269 }
1270 }
1271
1272 return true;
1273 }
1274 case D3DXPC_SCALAR:
1275 case D3DXPC_VECTOR:
1276 case D3DXPC_MATRIX_COLUMNS:
1277 case D3DXPC_OBJECT:
1278 return defineUniform(constantDescription, name + constantDescription.Name);
1279 default:
1280 UNREACHABLE();
1281 return false;
1282 }
1283}
1284
1285bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1286{
1287 Uniform *uniform = createUniform(constantDescription, name);
1288
1289 if(!uniform)
1290 {
1291 return false;
1292 }
1293
1294 // Check if already defined
1295 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001296 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001297
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001298 if (location >= 0)
1299 {
1300 delete uniform;
1301
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001302 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001303 {
1304 return false;
1305 }
1306 else
1307 {
1308 return true;
1309 }
1310 }
1311
1312 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001313 unsigned int uniformIndex = mUniforms.size() - 1;
1314
1315 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1316 {
1317 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1318 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001319
1320 return true;
1321}
1322
1323Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001324{
1325 if (constantDescription.Rows == 1) // Vectors and scalars
1326 {
1327 switch (constantDescription.Type)
1328 {
1329 case D3DXPT_SAMPLER2D:
1330 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001331 switch (constantDescription.Columns)
1332 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001333 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001334 default: UNREACHABLE();
1335 }
1336 break;
1337 case D3DXPT_BOOL:
1338 switch (constantDescription.Columns)
1339 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001340 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1341 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1342 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1343 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001344 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001345 }
1346 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001347 case D3DXPT_INT:
1348 switch (constantDescription.Columns)
1349 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001350 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1351 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1352 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1353 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001354 default: UNREACHABLE();
1355 }
1356 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001357 case D3DXPT_FLOAT:
1358 switch (constantDescription.Columns)
1359 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001360 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1361 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1362 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1363 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001364 default: UNREACHABLE();
1365 }
1366 break;
1367 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001368 UNREACHABLE();
1369 }
1370 }
1371 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1372 {
1373 switch (constantDescription.Type)
1374 {
1375 case D3DXPT_FLOAT:
1376 switch (constantDescription.Rows)
1377 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001378 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1379 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1380 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001381 default: UNREACHABLE();
1382 }
1383 break;
1384 default: UNREACHABLE();
1385 }
1386 }
1387 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001388
1389 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001390}
1391
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001392// This method needs to match OutputHLSL::decorate
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001393std::string Program::decorate(const std::string &string)
1394{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001395 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001396 {
1397 return "_" + string;
1398 }
1399 else
1400 {
1401 return string;
1402 }
1403}
1404
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00001405std::string Program::undecorate(const std::string &string)
1406{
1407 if (string.substr(0, 1) == "_")
1408 {
1409 return string.substr(1);
1410 }
1411 else
1412 {
1413 return string;
1414 }
1415}
1416
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001417bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1418{
1419 BOOL *vector = new BOOL[count];
1420 for (int i = 0; i < count; i++)
1421 {
1422 if (v[i] == GL_FALSE)
1423 vector[i] = 0;
1424 else
1425 vector[i] = 1;
1426 }
1427
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001428 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1429
1430 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1431 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001432 IDirect3DDevice9 *device = getDevice();
1433
1434 if (constantPS)
1435 {
1436 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1437 }
1438
1439 if (constantVS)
1440 {
1441 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1442 }
1443
1444 delete [] vector;
1445
1446 return true;
1447}
1448
1449bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1450{
1451 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1452
1453 for (int i = 0; i < count; i++)
1454 {
1455 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1456 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1457
1458 v += 2;
1459 }
1460
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001461 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1462
1463 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1464 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001465 IDirect3DDevice9 *device = getDevice();
1466
1467 if (constantPS)
1468 {
1469 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1470 }
1471
1472 if (constantVS)
1473 {
1474 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1475 }
1476
1477 delete[] vector;
1478
1479 return true;
1480}
1481
1482bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1483{
1484 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1485
1486 for (int i = 0; i < count; i++)
1487 {
1488 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1489 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1490 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1491
1492 v += 3;
1493 }
1494
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001495 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1496
1497 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1498 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001499 IDirect3DDevice9 *device = getDevice();
1500
1501 if (constantPS)
1502 {
1503 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1504 }
1505
1506 if (constantVS)
1507 {
1508 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1509 }
1510
1511 delete[] vector;
1512
1513 return true;
1514}
1515
1516bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1517{
1518 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1519
1520 for (int i = 0; i < count; i++)
1521 {
1522 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1523 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1524 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1525 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1526
1527 v += 3;
1528 }
1529
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001530 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1531
1532 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1533 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001534 IDirect3DDevice9 *device = getDevice();
1535
1536 if (constantPS)
1537 {
1538 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1539 }
1540
1541 if (constantVS)
1542 {
1543 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1544 }
1545
1546 delete [] vector;
1547
1548 return true;
1549}
1550
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001551bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1552{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001553 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1554
1555 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1556 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001557 IDirect3DDevice9 *device = getDevice();
1558
1559 if (constantPS)
1560 {
1561 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1562 }
1563
1564 if (constantVS)
1565 {
1566 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1567 }
1568
1569 return true;
1570}
1571
1572bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1573{
1574 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1575
1576 for (int i = 0; i < count; i++)
1577 {
1578 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1579
1580 v += 2;
1581 }
1582
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001583 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1584
1585 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1586 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001587 IDirect3DDevice9 *device = getDevice();
1588
1589 if (constantPS)
1590 {
1591 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1592 }
1593
1594 if (constantVS)
1595 {
1596 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1597 }
1598
1599 delete[] vector;
1600
1601 return true;
1602}
1603
1604bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1605{
1606 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1607
1608 for (int i = 0; i < count; i++)
1609 {
1610 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1611
1612 v += 3;
1613 }
1614
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001615 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1616
1617 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1618 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001619 IDirect3DDevice9 *device = getDevice();
1620
1621 if (constantPS)
1622 {
1623 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1624 }
1625
1626 if (constantVS)
1627 {
1628 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1629 }
1630
1631 delete[] vector;
1632
1633 return true;
1634}
1635
1636bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1637{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001638 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1639
1640 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1641 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001642 IDirect3DDevice9 *device = getDevice();
1643
1644 if (constantPS)
1645 {
1646 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
1647 }
1648
1649 if (constantVS)
1650 {
1651 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
1652 }
1653
1654 return true;
1655}
1656
1657bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
1658{
1659 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1660
1661 for (int i = 0; i < count; i++)
1662 {
1663 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
1664 value[1], value[3], 0, 0,
1665 0, 0, 1, 0,
1666 0, 0, 0, 1);
1667
1668 value += 4;
1669 }
1670
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001671 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1672
1673 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1674 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001675 IDirect3DDevice9 *device = getDevice();
1676
1677 if (constantPS)
1678 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001679 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001680 }
1681
1682 if (constantVS)
1683 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001684 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001685 }
1686
1687 delete[] matrix;
1688
1689 return true;
1690}
1691
1692bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
1693{
1694 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1695
1696 for (int i = 0; i < count; i++)
1697 {
1698 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
1699 value[1], value[4], value[7], 0,
1700 value[2], value[5], value[8], 0,
1701 0, 0, 0, 1);
1702
1703 value += 9;
1704 }
1705
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001706 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1707
1708 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1709 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001710 IDirect3DDevice9 *device = getDevice();
1711
1712 if (constantPS)
1713 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001714 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001715 }
1716
1717 if (constantVS)
1718 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001719 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001720 }
1721
1722 delete[] matrix;
1723
1724 return true;
1725}
1726
1727bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
1728{
1729 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1730
1731 for (int i = 0; i < count; i++)
1732 {
1733 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
1734 value[1], value[5], value[9], value[13],
1735 value[2], value[6], value[10], value[14],
1736 value[3], value[7], value[11], value[15]);
1737
1738 value += 16;
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.com4f39fd92010-03-08 20:26:45 +00001745 IDirect3DDevice9 *device = getDevice();
1746
1747 if (constantPS)
1748 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001749 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001750 }
1751
1752 if (constantVS)
1753 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001754 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001755 }
1756
1757 delete[] matrix;
1758
1759 return true;
1760}
1761
1762bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
1763{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001764 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1765
1766 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1767 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001768 IDirect3DDevice9 *device = getDevice();
1769
1770 if (constantPS)
1771 {
1772 D3DXCONSTANT_DESC constantDescription;
1773 UINT descriptionCount = 1;
1774 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
1775
daniel@transgaming.com2884b782010-03-08 21:30:48 +00001776 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001777 {
1778 return false;
1779 }
1780
1781 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1782 {
1783 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
1784
1785 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
1786 {
1787 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001788
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001789 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
1790 {
1791 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1792 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001793 ASSERT(mSamplers[samplerIndex].active);
1794 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001795 }
1796 }
1797 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001798
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001799 return true;
1800 }
1801 }
1802
1803 if (constantPS)
1804 {
1805 mConstantTablePS->SetIntArray(device, constantPS, v, count);
1806 }
1807
1808 if (constantVS)
1809 {
1810 mConstantTableVS->SetIntArray(device, constantVS, v, count);
1811 }
1812
1813 return true;
1814}
1815
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001816bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
1817{
1818 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1819
1820 for (int i = 0; i < count; i++)
1821 {
1822 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
1823
1824 v += 2;
1825 }
1826
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001827 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1828
1829 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1830 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001831 IDirect3DDevice9 *device = getDevice();
1832
1833 if (constantPS)
1834 {
1835 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1836 }
1837
1838 if (constantVS)
1839 {
1840 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1841 }
1842
1843 delete[] vector;
1844
1845 return true;
1846}
1847
1848bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
1849{
1850 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1851
1852 for (int i = 0; i < count; i++)
1853 {
1854 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
1855
1856 v += 3;
1857 }
1858
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001859 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1860
1861 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1862 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001863 IDirect3DDevice9 *device = getDevice();
1864
1865 if (constantPS)
1866 {
1867 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1868 }
1869
1870 if (constantVS)
1871 {
1872 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1873 }
1874
1875 delete[] vector;
1876
1877 return true;
1878}
1879
1880bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
1881{
1882 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1883
1884 for (int i = 0; i < count; i++)
1885 {
1886 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
1887
1888 v += 4;
1889 }
1890
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001891 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1892
1893 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1894 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001895 IDirect3DDevice9 *device = getDevice();
1896
1897 if (constantPS)
1898 {
1899 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1900 }
1901
1902 if (constantVS)
1903 {
1904 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1905 }
1906
1907 delete [] vector;
1908
1909 return true;
1910}
1911
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001912void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001913{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001914 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001915 {
1916 return;
1917 }
1918
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001919 char info[1024];
1920
1921 va_list vararg;
1922 va_start(vararg, format);
1923 vsnprintf(info, sizeof(info), format, vararg);
1924 va_end(vararg);
1925
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001926 size_t infoLength = strlen(info);
1927
1928 if (!mInfoLog)
1929 {
1930 mInfoLog = new char[infoLength + 1];
1931 strcpy(mInfoLog, info);
1932 }
1933 else
1934 {
1935 size_t logLength = strlen(mInfoLog);
1936 char *newLog = new char[logLength + infoLength + 1];
1937 strcpy(newLog, mInfoLog);
1938 strcpy(newLog + logLength, info);
1939
1940 delete[] mInfoLog;
1941 mInfoLog = newLog;
1942 }
1943}
1944
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00001945void Program::resetInfoLog()
1946{
1947 if (mInfoLog)
1948 {
1949 delete [] mInfoLog;
1950 }
1951}
1952
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001953// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
1954void Program::unlink(bool destroy)
1955{
1956 if (destroy) // Object being destructed
1957 {
1958 if (mFragmentShader)
1959 {
1960 mFragmentShader->detach();
1961 mFragmentShader = NULL;
1962 }
1963
1964 if (mVertexShader)
1965 {
1966 mVertexShader->detach();
1967 mVertexShader = NULL;
1968 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001969 }
1970
1971 if (mPixelExecutable)
1972 {
1973 mPixelExecutable->Release();
1974 mPixelExecutable = NULL;
1975 }
1976
1977 if (mVertexExecutable)
1978 {
1979 mVertexExecutable->Release();
1980 mVertexExecutable = NULL;
1981 }
1982
1983 if (mConstantTablePS)
1984 {
1985 mConstantTablePS->Release();
1986 mConstantTablePS = NULL;
1987 }
1988
1989 if (mConstantTableVS)
1990 {
1991 mConstantTableVS->Release();
1992 mConstantTableVS = NULL;
1993 }
1994
1995 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1996 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001997 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001998 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001999 }
2000
2001 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
2002 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00002003 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002004 }
2005
2006 while (!mUniforms.empty())
2007 {
2008 delete mUniforms.back();
2009 mUniforms.pop_back();
2010 }
2011
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00002012 mUniformIndex.clear();
2013
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00002014 delete[] mPixelHLSL;
2015 mPixelHLSL = NULL;
2016
2017 delete[] mVertexHLSL;
2018 mVertexHLSL = NULL;
2019
2020 delete[] mInfoLog;
2021 mInfoLog = NULL;
2022
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002023 mLinked = false;
2024}
2025
2026bool Program::isLinked()
2027{
2028 return mLinked;
2029}
2030
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002031bool Program::isValidated() const
2032{
2033 return mValidated;
2034}
2035
daniel@transgaming.com4fa08332010-05-11 02:29:27 +00002036unsigned int Program::getSerial() const
2037{
2038 return mSerial;
2039}
2040
2041unsigned int Program::issueSerial()
2042{
2043 return mCurrentSerial++;
2044}
2045
daniel@transgaming.comcba50572010-03-28 19:36:09 +00002046int Program::getInfoLogLength() const
2047{
2048 if (!mInfoLog)
2049 {
2050 return 0;
2051 }
2052 else
2053 {
2054 return strlen(mInfoLog) + 1;
2055 }
2056}
2057
2058void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
2059{
2060 int index = 0;
2061
2062 if (mInfoLog)
2063 {
2064 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
2065 {
2066 infoLog[index] = mInfoLog[index];
2067 index++;
2068 }
2069 }
2070
2071 if (bufSize)
2072 {
2073 infoLog[index] = '\0';
2074 }
2075
2076 if (length)
2077 {
2078 *length = index;
2079 }
2080}
2081
daniel@transgaming.com6c785212010-03-30 03:36:17 +00002082void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2083{
2084 int total = 0;
2085
2086 if (mVertexShader)
2087 {
2088 if (total < maxCount)
2089 {
2090 shaders[total] = mVertexShader->getHandle();
2091 }
2092
2093 total++;
2094 }
2095
2096 if (mFragmentShader)
2097 {
2098 if (total < maxCount)
2099 {
2100 shaders[total] = mFragmentShader->getHandle();
2101 }
2102
2103 total++;
2104 }
2105
2106 if (count)
2107 {
2108 *count = total;
2109 }
2110}
2111
daniel@transgaming.com85423182010-04-22 13:35:27 +00002112void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2113{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002114 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002115 for (unsigned int i = 0; i < index; i++)
2116 {
2117 do
2118 {
2119 attribute++;
2120
2121 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2122 }
2123 while (mLinkedAttribute[attribute].name.empty());
2124 }
2125
2126 if (bufsize > 0)
2127 {
2128 const char *string = mLinkedAttribute[attribute].name.c_str();
2129
2130 strncpy(name, string, bufsize);
2131 name[bufsize - 1] = '\0';
2132
2133 if (length)
2134 {
2135 *length = strlen(name);
2136 }
2137 }
2138
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002139 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002140
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002141 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002142}
2143
2144GLint Program::getActiveAttributeCount()
2145{
2146 int count = 0;
2147
2148 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2149 {
2150 if (!mLinkedAttribute[attributeIndex].name.empty())
2151 {
2152 count++;
2153 }
2154 }
2155
2156 return count;
2157}
2158
2159GLint Program::getActiveAttributeMaxLength()
2160{
2161 int maxLength = 0;
2162
2163 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2164 {
2165 if (!mLinkedAttribute[attributeIndex].name.empty())
2166 {
2167 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2168 }
2169 }
2170
2171 return maxLength;
2172}
2173
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002174void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2175{
2176 unsigned int uniform = 0;
2177 for (unsigned int i = 0; i < index; i++)
2178 {
2179 do
2180 {
2181 uniform++;
2182
2183 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2184 }
2185 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2186 }
2187
2188 if (bufsize > 0)
2189 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002190 std::string string = undecorate(mUniforms[uniform]->name);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002191
daniel@transgaming.comf3140152010-04-29 03:38:50 +00002192 if (mUniforms[uniform]->arraySize != 1)
2193 {
2194 string += "[0]";
2195 }
2196
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002197 strncpy(name, string.c_str(), bufsize);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002198 name[bufsize - 1] = '\0';
2199
2200 if (length)
2201 {
2202 *length = strlen(name);
2203 }
2204 }
2205
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002206 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002207
2208 *type = mUniforms[uniform]->type;
2209}
2210
2211GLint Program::getActiveUniformCount()
2212{
2213 int count = 0;
2214
2215 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2216 {
2217 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2218 {
2219 count++;
2220 }
2221 }
2222
2223 return count;
2224}
2225
2226GLint Program::getActiveUniformMaxLength()
2227{
2228 int maxLength = 0;
2229
2230 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2231 {
2232 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2233 {
daniel@transgaming.comfeba9ba2010-04-29 03:32:45 +00002234 maxLength = std::max((int)(undecorate(mUniforms[uniformIndex]->name).length() + 1), maxLength);
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002235 }
2236 }
2237
2238 return maxLength;
2239}
2240
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002241void Program::flagForDeletion()
2242{
2243 mDeleteStatus = true;
2244}
2245
2246bool Program::isFlaggedForDeletion() const
2247{
2248 return mDeleteStatus;
2249}
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002250
2251void Program::validate()
2252{
2253 resetInfoLog();
2254
2255 if (!isLinked())
2256 {
2257 appendToInfoLog("Program has not been successfully linked.");
2258 mValidated = false;
2259 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002260 else
2261 {
daniel@transgaming.comc3a0e942010-04-29 03:35:45 +00002262 applyUniforms();
2263 if (!validateSamplers())
2264 {
2265 appendToInfoLog("Samplers of conflicting types refer to the same texture image unit.");
2266 mValidated = false;
2267 }
2268 else
2269 {
2270 mValidated = true;
2271 }
daniel@transgaming.com86a7a132010-04-29 03:32:32 +00002272 }
2273}
2274
2275bool Program::validateSamplers() const
2276{
2277 // if any two active samplers in a program are of different types, but refer to the same
2278 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2279 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2280 std::map<int, SamplerType> samplerMap;
2281 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
2282 {
2283 if (mSamplers[i].active)
2284 {
2285 if (samplerMap.find(mSamplers[i].logicalTextureUnit) != samplerMap.end())
2286 {
2287 if (mSamplers[i].type != samplerMap[mSamplers[i].logicalTextureUnit])
2288 return false;
2289 }
2290 else
2291 {
2292 samplerMap[mSamplers[i].logicalTextureUnit] = mSamplers[i].type;
2293 }
2294 }
2295 }
2296
2297 return true;
2298}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002299}