blob: 52d4016ec8514335b769a6ad34e436ea5809fa5a [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.com0b6b8342010-04-26 15:33:45 +00001078 unsigned int usedLocations = 0;
1079
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001080 // Link attributes that have a binding location
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001081 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1082 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001083 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1084 int location = getAttributeBinding(attribute.name);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001085
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001086 if (location != -1) // Set by glBindAttribLocation
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001087 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001088 if (!mLinkedAttribute[location].name.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001089 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001090 // Multiple active attributes bound to the same location; not an error
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001091 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001092
daniel@transgaming.com85423182010-04-22 13:35:27 +00001093 mLinkedAttribute[location] = attribute;
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001094
1095 int size = AttributeVectorCount(attribute.type);
1096
1097 if (size + location > MAX_VERTEX_ATTRIBS)
1098 {
1099 appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
1100
1101 return false;
1102 }
1103
1104 for (int i = 0; i < size; i++)
1105 {
1106 usedLocations |= 1 << (location + i);
1107 }
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001108 }
1109 }
1110
1111 // Link attributes that don't have a binding location
1112 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS + 1; attributeIndex++)
1113 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001114 const Attribute &attribute = mVertexShader->getAttribute(attributeIndex);
1115 int location = getAttributeBinding(attribute.name);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001116
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001117 if (!attribute.name.empty() && location == -1) // Not set by glBindAttribLocation
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001118 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001119 int size = AttributeVectorCount(attribute.type);
1120 int availableIndex = AllocateFirstFreeBits(&usedLocations, size, MAX_VERTEX_ATTRIBS);
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001121
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001122 if (availableIndex == -1 || availableIndex + size > MAX_VERTEX_ATTRIBS)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001123 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001124 appendToInfoLog("Too many active attributes (%s)", attribute.name.c_str());
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001125
1126 return false; // Fail to link
1127 }
1128
daniel@transgaming.com85423182010-04-22 13:35:27 +00001129 mLinkedAttribute[availableIndex] = attribute;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001130 }
1131 }
1132
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001133 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001134 {
daniel@transgaming.com0b6b8342010-04-26 15:33:45 +00001135 int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1136
1137 if (index == -1)
1138 {
1139 mSemanticIndex[attributeIndex++] = -1;
1140 }
1141 else
1142 {
1143 int size = AttributeVectorCount(mVertexShader->getAttribute(index).type);
1144
1145 for (int i = 0; i < size; i++)
1146 {
1147 mSemanticIndex[attributeIndex++] = index++;
1148 }
1149 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001150 }
1151
1152 return true;
1153}
1154
daniel@transgaming.com85423182010-04-22 13:35:27 +00001155int Program::getAttributeBinding(const std::string &name)
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001156{
1157 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
1158 {
1159 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
1160 {
1161 return location;
1162 }
1163 }
1164
1165 return -1;
1166}
1167
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001168bool Program::linkUniforms(ID3DXConstantTable *constantTable)
1169{
1170 D3DXCONSTANTTABLE_DESC constantTableDescription;
1171 D3DXCONSTANT_DESC constantDescription;
1172 UINT descriptionCount = 1;
1173
1174 constantTable->GetDesc(&constantTableDescription);
1175
1176 for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
1177 {
1178 D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
1179 constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
1180
1181 if (!defineUniform(constantHandle, constantDescription))
1182 {
1183 return false;
1184 }
1185 }
1186
1187 return true;
1188}
1189
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001190// Adds the description of a constant found in the binary shader to the list of uniforms
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001191// Returns true if succesful (uniform not already defined)
1192bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
1193{
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001194 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1195 {
1196 unsigned int samplerIndex = constantDescription.RegisterIndex;
1197
1198 assert(samplerIndex < sizeof(mSamplers)/sizeof(mSamplers[0]));
1199
1200 mSamplers[samplerIndex].active = true;
1201 mSamplers[samplerIndex].type = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? SAMPLER_CUBE : SAMPLER_2D;
1202 mSamplers[samplerIndex].logicalTextureUnit = 0;
1203 }
1204
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001205 switch(constantDescription.Class)
1206 {
1207 case D3DXPC_STRUCT:
1208 {
1209 for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
1210 {
1211 D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
1212
1213 D3DXCONSTANT_DESC fieldDescription;
1214 UINT descriptionCount = 1;
1215
1216 mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
1217
1218 if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + "."))
1219 {
1220 return false;
1221 }
1222 }
1223
1224 return true;
1225 }
1226 case D3DXPC_SCALAR:
1227 case D3DXPC_VECTOR:
1228 case D3DXPC_MATRIX_COLUMNS:
1229 case D3DXPC_OBJECT:
1230 return defineUniform(constantDescription, name + constantDescription.Name);
1231 default:
1232 UNREACHABLE();
1233 return false;
1234 }
1235}
1236
1237bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
1238{
1239 Uniform *uniform = createUniform(constantDescription, name);
1240
1241 if(!uniform)
1242 {
1243 return false;
1244 }
1245
1246 // Check if already defined
1247 GLint location = getUniformLocation(name.c_str());
daniel@transgaming.com0361b922010-03-28 19:36:15 +00001248 GLenum type = uniform->type;
daniel@transgaming.comc7d8a932010-03-16 06:16:45 +00001249
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001250 if (location >= 0)
1251 {
1252 delete uniform;
1253
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001254 if (mUniforms[mUniformIndex[location].index]->type != type)
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001255 {
1256 return false;
1257 }
1258 else
1259 {
1260 return true;
1261 }
1262 }
1263
1264 mUniforms.push_back(uniform);
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001265 unsigned int uniformIndex = mUniforms.size() - 1;
1266
1267 for (unsigned int i = 0; i < uniform->arraySize; ++i)
1268 {
1269 mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
1270 }
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001271
1272 return true;
1273}
1274
1275Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001276{
1277 if (constantDescription.Rows == 1) // Vectors and scalars
1278 {
1279 switch (constantDescription.Type)
1280 {
1281 case D3DXPT_SAMPLER2D:
1282 case D3DXPT_SAMPLERCUBE:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001283 switch (constantDescription.Columns)
1284 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001285 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001286 default: UNREACHABLE();
1287 }
1288 break;
1289 case D3DXPT_BOOL:
1290 switch (constantDescription.Columns)
1291 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001292 case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
1293 case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
1294 case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
1295 case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001296 default: UNREACHABLE();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001297 }
1298 break;
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001299 case D3DXPT_INT:
1300 switch (constantDescription.Columns)
1301 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001302 case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
1303 case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
1304 case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
1305 case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001306 default: UNREACHABLE();
1307 }
1308 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001309 case D3DXPT_FLOAT:
1310 switch (constantDescription.Columns)
1311 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001312 case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
1313 case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
1314 case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
1315 case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001316 default: UNREACHABLE();
1317 }
1318 break;
1319 default:
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001320 UNREACHABLE();
1321 }
1322 }
1323 else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
1324 {
1325 switch (constantDescription.Type)
1326 {
1327 case D3DXPT_FLOAT:
1328 switch (constantDescription.Rows)
1329 {
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00001330 case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
1331 case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
1332 case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001333 default: UNREACHABLE();
1334 }
1335 break;
1336 default: UNREACHABLE();
1337 }
1338 }
1339 else UNREACHABLE();
daniel@transgaming.com86487c22010-03-11 19:41:43 +00001340
1341 return 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001342}
1343
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001344// This methods needs to match OutputHLSL::decorate
1345std::string Program::decorate(const std::string &string)
1346{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00001347 if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
daniel@transgaming.com72d0b522010-04-13 19:53:44 +00001348 {
1349 return "_" + string;
1350 }
1351 else
1352 {
1353 return string;
1354 }
1355}
1356
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001357bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
1358{
1359 BOOL *vector = new BOOL[count];
1360 for (int i = 0; i < count; i++)
1361 {
1362 if (v[i] == GL_FALSE)
1363 vector[i] = 0;
1364 else
1365 vector[i] = 1;
1366 }
1367
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001368 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1369
1370 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1371 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001372 IDirect3DDevice9 *device = getDevice();
1373
1374 if (constantPS)
1375 {
1376 mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
1377 }
1378
1379 if (constantVS)
1380 {
1381 mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
1382 }
1383
1384 delete [] vector;
1385
1386 return true;
1387}
1388
1389bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
1390{
1391 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1392
1393 for (int i = 0; i < count; i++)
1394 {
1395 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1396 (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
1397
1398 v += 2;
1399 }
1400
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001401 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1402
1403 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1404 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001405 IDirect3DDevice9 *device = getDevice();
1406
1407 if (constantPS)
1408 {
1409 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1410 }
1411
1412 if (constantVS)
1413 {
1414 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1415 }
1416
1417 delete[] vector;
1418
1419 return true;
1420}
1421
1422bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
1423{
1424 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1425
1426 for (int i = 0; i < count; i++)
1427 {
1428 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1429 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1430 (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
1431
1432 v += 3;
1433 }
1434
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001435 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1436
1437 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1438 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001439 IDirect3DDevice9 *device = getDevice();
1440
1441 if (constantPS)
1442 {
1443 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1444 }
1445
1446 if (constantVS)
1447 {
1448 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1449 }
1450
1451 delete[] vector;
1452
1453 return true;
1454}
1455
1456bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
1457{
1458 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1459
1460 for (int i = 0; i < count; i++)
1461 {
1462 vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
1463 (v[1] == GL_FALSE ? 0.0f : 1.0f),
1464 (v[2] == GL_FALSE ? 0.0f : 1.0f),
1465 (v[3] == GL_FALSE ? 0.0f : 1.0f));
1466
1467 v += 3;
1468 }
1469
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001470 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1471
1472 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1473 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.comf4a0c8e2010-04-13 03:26:01 +00001474 IDirect3DDevice9 *device = getDevice();
1475
1476 if (constantPS)
1477 {
1478 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1479 }
1480
1481 if (constantVS)
1482 {
1483 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1484 }
1485
1486 delete [] vector;
1487
1488 return true;
1489}
1490
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001491bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
1492{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001493 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1494
1495 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1496 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001497 IDirect3DDevice9 *device = getDevice();
1498
1499 if (constantPS)
1500 {
1501 mConstantTablePS->SetFloatArray(device, constantPS, v, count);
1502 }
1503
1504 if (constantVS)
1505 {
1506 mConstantTableVS->SetFloatArray(device, constantVS, v, count);
1507 }
1508
1509 return true;
1510}
1511
1512bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
1513{
1514 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1515
1516 for (int i = 0; i < count; i++)
1517 {
1518 vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
1519
1520 v += 2;
1521 }
1522
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001523 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1524
1525 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1526 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001527 IDirect3DDevice9 *device = getDevice();
1528
1529 if (constantPS)
1530 {
1531 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1532 }
1533
1534 if (constantVS)
1535 {
1536 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1537 }
1538
1539 delete[] vector;
1540
1541 return true;
1542}
1543
1544bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
1545{
1546 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1547
1548 for (int i = 0; i < count; i++)
1549 {
1550 vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
1551
1552 v += 3;
1553 }
1554
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001555 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1556
1557 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1558 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001559 IDirect3DDevice9 *device = getDevice();
1560
1561 if (constantPS)
1562 {
1563 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1564 }
1565
1566 if (constantVS)
1567 {
1568 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1569 }
1570
1571 delete[] vector;
1572
1573 return true;
1574}
1575
1576bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
1577{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001578 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1579
1580 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1581 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001582 IDirect3DDevice9 *device = getDevice();
1583
1584 if (constantPS)
1585 {
1586 mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
1587 }
1588
1589 if (constantVS)
1590 {
1591 mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
1592 }
1593
1594 return true;
1595}
1596
1597bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
1598{
1599 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1600
1601 for (int i = 0; i < count; i++)
1602 {
1603 matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
1604 value[1], value[3], 0, 0,
1605 0, 0, 1, 0,
1606 0, 0, 0, 1);
1607
1608 value += 4;
1609 }
1610
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001611 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1612
1613 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1614 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001615 IDirect3DDevice9 *device = getDevice();
1616
1617 if (constantPS)
1618 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001619 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001620 }
1621
1622 if (constantVS)
1623 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001624 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001625 }
1626
1627 delete[] matrix;
1628
1629 return true;
1630}
1631
1632bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
1633{
1634 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1635
1636 for (int i = 0; i < count; i++)
1637 {
1638 matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
1639 value[1], value[4], value[7], 0,
1640 value[2], value[5], value[8], 0,
1641 0, 0, 0, 1);
1642
1643 value += 9;
1644 }
1645
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001646 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1647
1648 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1649 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001650 IDirect3DDevice9 *device = getDevice();
1651
1652 if (constantPS)
1653 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001654 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001655 }
1656
1657 if (constantVS)
1658 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001659 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001660 }
1661
1662 delete[] matrix;
1663
1664 return true;
1665}
1666
1667bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
1668{
1669 D3DXMATRIX *matrix = new D3DXMATRIX[count];
1670
1671 for (int i = 0; i < count; i++)
1672 {
1673 matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
1674 value[1], value[5], value[9], value[13],
1675 value[2], value[6], value[10], value[14],
1676 value[3], value[7], value[11], value[15]);
1677
1678 value += 16;
1679 }
1680
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001681 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1682
1683 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1684 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001685 IDirect3DDevice9 *device = getDevice();
1686
1687 if (constantPS)
1688 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001689 mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001690 }
1691
1692 if (constantVS)
1693 {
daniel@transgaming.com279e38a2010-04-03 20:56:13 +00001694 mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001695 }
1696
1697 delete[] matrix;
1698
1699 return true;
1700}
1701
1702bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
1703{
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001704 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1705
1706 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1707 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001708 IDirect3DDevice9 *device = getDevice();
1709
1710 if (constantPS)
1711 {
1712 D3DXCONSTANT_DESC constantDescription;
1713 UINT descriptionCount = 1;
1714 HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
1715
daniel@transgaming.com2884b782010-03-08 21:30:48 +00001716 if (FAILED(result))
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001717 {
1718 return false;
1719 }
1720
1721 if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
1722 {
1723 unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
1724
1725 for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++)
1726 {
1727 GLint mappedSampler = v[0];
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001728
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001729 if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS)
1730 {
1731 if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
1732 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001733 ASSERT(mSamplers[samplerIndex].active);
1734 mSamplers[samplerIndex].logicalTextureUnit = mappedSampler;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001735 }
1736 }
1737 }
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001738
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001739 return true;
1740 }
1741 }
1742
1743 if (constantPS)
1744 {
1745 mConstantTablePS->SetIntArray(device, constantPS, v, count);
1746 }
1747
1748 if (constantVS)
1749 {
1750 mConstantTableVS->SetIntArray(device, constantVS, v, count);
1751 }
1752
1753 return true;
1754}
1755
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001756bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
1757{
1758 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1759
1760 for (int i = 0; i < count; i++)
1761 {
1762 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
1763
1764 v += 2;
1765 }
1766
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001767 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1768
1769 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1770 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001771 IDirect3DDevice9 *device = getDevice();
1772
1773 if (constantPS)
1774 {
1775 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1776 }
1777
1778 if (constantVS)
1779 {
1780 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1781 }
1782
1783 delete[] vector;
1784
1785 return true;
1786}
1787
1788bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
1789{
1790 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1791
1792 for (int i = 0; i < count; i++)
1793 {
1794 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
1795
1796 v += 3;
1797 }
1798
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001799 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1800
1801 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1802 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001803 IDirect3DDevice9 *device = getDevice();
1804
1805 if (constantPS)
1806 {
1807 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1808 }
1809
1810 if (constantVS)
1811 {
1812 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1813 }
1814
1815 delete[] vector;
1816
1817 return true;
1818}
1819
1820bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
1821{
1822 D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
1823
1824 for (int i = 0; i < count; i++)
1825 {
1826 vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
1827
1828 v += 4;
1829 }
1830
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001831 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
1832
1833 D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
1834 D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
daniel@transgaming.com9a95e2b2010-04-13 03:26:03 +00001835 IDirect3DDevice9 *device = getDevice();
1836
1837 if (constantPS)
1838 {
1839 mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
1840 }
1841
1842 if (constantVS)
1843 {
1844 mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
1845 }
1846
1847 delete [] vector;
1848
1849 return true;
1850}
1851
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001852void Program::appendToInfoLog(const char *format, ...)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001853{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001854 if (!format)
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001855 {
1856 return;
1857 }
1858
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001859 char info[1024];
1860
1861 va_list vararg;
1862 va_start(vararg, format);
1863 vsnprintf(info, sizeof(info), format, vararg);
1864 va_end(vararg);
1865
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001866 size_t infoLength = strlen(info);
1867
1868 if (!mInfoLog)
1869 {
1870 mInfoLog = new char[infoLength + 1];
1871 strcpy(mInfoLog, info);
1872 }
1873 else
1874 {
1875 size_t logLength = strlen(mInfoLog);
1876 char *newLog = new char[logLength + infoLength + 1];
1877 strcpy(newLog, mInfoLog);
1878 strcpy(newLog + logLength, info);
1879
1880 delete[] mInfoLog;
1881 mInfoLog = newLog;
1882 }
1883}
1884
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001885// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
1886void Program::unlink(bool destroy)
1887{
1888 if (destroy) // Object being destructed
1889 {
1890 if (mFragmentShader)
1891 {
1892 mFragmentShader->detach();
1893 mFragmentShader = NULL;
1894 }
1895
1896 if (mVertexShader)
1897 {
1898 mVertexShader->detach();
1899 mVertexShader = NULL;
1900 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001901 }
1902
1903 if (mPixelExecutable)
1904 {
1905 mPixelExecutable->Release();
1906 mPixelExecutable = NULL;
1907 }
1908
1909 if (mVertexExecutable)
1910 {
1911 mVertexExecutable->Release();
1912 mVertexExecutable = NULL;
1913 }
1914
1915 if (mConstantTablePS)
1916 {
1917 mConstantTablePS->Release();
1918 mConstantTablePS = NULL;
1919 }
1920
1921 if (mConstantTableVS)
1922 {
1923 mConstantTableVS->Release();
1924 mConstantTableVS = NULL;
1925 }
1926
1927 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
1928 {
daniel@transgaming.com85423182010-04-22 13:35:27 +00001929 mLinkedAttribute[index].name.clear();
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +00001930 mSemanticIndex[index] = -1;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001931 }
1932
1933 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
1934 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001935 mSamplers[index].active = false;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001936 }
1937
1938 while (!mUniforms.empty())
1939 {
1940 delete mUniforms.back();
1941 mUniforms.pop_back();
1942 }
1943
daniel@transgaming.com916ffaa2010-04-23 18:34:52 +00001944 mUniformIndex.clear();
1945
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +00001946 delete[] mPixelHLSL;
1947 mPixelHLSL = NULL;
1948
1949 delete[] mVertexHLSL;
1950 mVertexHLSL = NULL;
1951
1952 delete[] mInfoLog;
1953 mInfoLog = NULL;
1954
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001955 mLinked = false;
1956}
1957
1958bool Program::isLinked()
1959{
1960 return mLinked;
1961}
1962
daniel@transgaming.comcba50572010-03-28 19:36:09 +00001963int Program::getInfoLogLength() const
1964{
1965 if (!mInfoLog)
1966 {
1967 return 0;
1968 }
1969 else
1970 {
1971 return strlen(mInfoLog) + 1;
1972 }
1973}
1974
1975void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
1976{
1977 int index = 0;
1978
1979 if (mInfoLog)
1980 {
1981 while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
1982 {
1983 infoLog[index] = mInfoLog[index];
1984 index++;
1985 }
1986 }
1987
1988 if (bufSize)
1989 {
1990 infoLog[index] = '\0';
1991 }
1992
1993 if (length)
1994 {
1995 *length = index;
1996 }
1997}
1998
daniel@transgaming.com6c785212010-03-30 03:36:17 +00001999void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
2000{
2001 int total = 0;
2002
2003 if (mVertexShader)
2004 {
2005 if (total < maxCount)
2006 {
2007 shaders[total] = mVertexShader->getHandle();
2008 }
2009
2010 total++;
2011 }
2012
2013 if (mFragmentShader)
2014 {
2015 if (total < maxCount)
2016 {
2017 shaders[total] = mFragmentShader->getHandle();
2018 }
2019
2020 total++;
2021 }
2022
2023 if (count)
2024 {
2025 *count = total;
2026 }
2027}
2028
daniel@transgaming.com85423182010-04-22 13:35:27 +00002029void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2030{
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002031 unsigned int attribute = 0;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002032 for (unsigned int i = 0; i < index; i++)
2033 {
2034 do
2035 {
2036 attribute++;
2037
2038 ASSERT(attribute < MAX_VERTEX_ATTRIBS); // index must be smaller than getActiveAttributeCount()
2039 }
2040 while (mLinkedAttribute[attribute].name.empty());
2041 }
2042
2043 if (bufsize > 0)
2044 {
2045 const char *string = mLinkedAttribute[attribute].name.c_str();
2046
2047 strncpy(name, string, bufsize);
2048 name[bufsize - 1] = '\0';
2049
2050 if (length)
2051 {
2052 *length = strlen(name);
2053 }
2054 }
2055
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002056 *size = 1; // Always a single 'type' instance
daniel@transgaming.com85423182010-04-22 13:35:27 +00002057
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002058 *type = mLinkedAttribute[attribute].type;
daniel@transgaming.com85423182010-04-22 13:35:27 +00002059}
2060
2061GLint Program::getActiveAttributeCount()
2062{
2063 int count = 0;
2064
2065 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2066 {
2067 if (!mLinkedAttribute[attributeIndex].name.empty())
2068 {
2069 count++;
2070 }
2071 }
2072
2073 return count;
2074}
2075
2076GLint Program::getActiveAttributeMaxLength()
2077{
2078 int maxLength = 0;
2079
2080 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2081 {
2082 if (!mLinkedAttribute[attributeIndex].name.empty())
2083 {
2084 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2085 }
2086 }
2087
2088 return maxLength;
2089}
2090
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002091void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2092{
2093 unsigned int uniform = 0;
2094 for (unsigned int i = 0; i < index; i++)
2095 {
2096 do
2097 {
2098 uniform++;
2099
2100 ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
2101 }
2102 while (mUniforms[uniform]->name.substr(0, 3) == "dx_");
2103 }
2104
2105 if (bufsize > 0)
2106 {
2107 const char *string = mUniforms[uniform]->name.c_str();
2108
2109 if(string[0] == '_') // Undecorate
2110 {
2111 string++;
2112 }
2113
2114 strncpy(name, string, bufsize);
2115 name[bufsize - 1] = '\0';
2116
2117 if (length)
2118 {
2119 *length = strlen(name);
2120 }
2121 }
2122
daniel@transgaming.com1b3a8152010-04-22 13:35:37 +00002123 *size = mUniforms[uniform]->arraySize;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +00002124
2125 *type = mUniforms[uniform]->type;
2126}
2127
2128GLint Program::getActiveUniformCount()
2129{
2130 int count = 0;
2131
2132 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2133 {
2134 if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2135 {
2136 count++;
2137 }
2138 }
2139
2140 return count;
2141}
2142
2143GLint Program::getActiveUniformMaxLength()
2144{
2145 int maxLength = 0;
2146
2147 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2148 {
2149 if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
2150 {
2151 maxLength = std::max((int)(mUniforms[uniformIndex]->name.length() + 1), maxLength);
2152 }
2153 }
2154
2155 return maxLength;
2156}
2157
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002158void Program::flagForDeletion()
2159{
2160 mDeleteStatus = true;
2161}
2162
2163bool Program::isFlaggedForDeletion() const
2164{
2165 return mDeleteStatus;
2166}
2167}