vtkShaderProgram.cxx 22.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*=========================================================================

  Program:   Visualization Toolkit

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
14 15
#include "vtkShaderProgram.h"
#include "vtkObjectFactory.h"
16

Ken Martin's avatar
Ken Martin committed
17
#include "vtk_glew.h"
18
#include "vtkShader.h"
19 20
#include "vtkMatrix3x3.h"
#include "vtkMatrix4x4.h"
21 22
#include "vtkOpenGLRenderWindow.h"
#include "vtkOpenGLShaderCache.h"
23
#include "vtkTransformFeedback.h"
24
#include "vtkTypeTraits.h"
25

26
# include <sstream>
27 28 29 30 31

namespace {

inline GLenum convertTypeToGL(int type)
{
32
  switch (type)
33
  {
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
    case VTK_CHAR:
      return GL_BYTE;
    case VTK_UNSIGNED_CHAR:
      return GL_UNSIGNED_BYTE;
    case VTK_SHORT:
      return GL_SHORT;
    case VTK_UNSIGNED_SHORT:
      return GL_UNSIGNED_SHORT;
    case VTK_INT:
      return GL_INT;
    case VTK_UNSIGNED_INT:
      return GL_UNSIGNED_INT;
    case VTK_FLOAT:
      return GL_FLOAT;
    case VTK_DOUBLE:
49
#ifdef GL_DOUBLE
50
      return GL_DOUBLE;
51
#else
Ken Martin's avatar
Ken Martin committed
52
      vtkGenericWarningMacro(<< "Attempt to use GL_DOUBLE when not supported");
53
      return 0;
54
#endif
55 56
    default:
      return 0;
57
  }
58
}
59

60 61
} // end anon namespace

62 63
typedef std::map<const char *, int, vtkShaderProgram::cmp_str>::iterator IterT;

64 65
vtkStandardNewMacro(vtkShaderProgram)

66 67 68
vtkCxxSetObjectMacro(vtkShaderProgram,VertexShader,vtkShader)
vtkCxxSetObjectMacro(vtkShaderProgram,FragmentShader,vtkShader)
vtkCxxSetObjectMacro(vtkShaderProgram,GeometryShader,vtkShader)
69
vtkCxxSetObjectMacro(vtkShaderProgram, TransformFeedback, vtkTransformFeedback)
70

71
vtkShaderProgram::vtkShaderProgram()
72
{
73 74 75 76 77 78 79
  this->VertexShader = vtkShader::New();
  this->VertexShader->SetType(vtkShader::Vertex);
  this->FragmentShader = vtkShader::New();
  this->FragmentShader->SetType(vtkShader::Fragment);
  this->GeometryShader = vtkShader::New();
  this->GeometryShader->SetType(vtkShader::Geometry);

80 81
  this->TransformFeedback = NULL;

82 83 84 85 86 87 88 89
  this->Compiled = false;
  this->NumberOfOutputs = 0;
  this->Handle = 0;
  this->VertexShaderHandle = 0;
  this->FragmentShaderHandle = 0;
  this->GeometryShaderHandle = 0;
  this->Linked = false;
  this->Bound = false;
90 91
}

92
vtkShaderProgram::~vtkShaderProgram()
93
{
94
  this->ClearMaps();
95
  if (this->VertexShader)
96
  {
97 98
    this->VertexShader->Delete();
    this->VertexShader = NULL;
99
  }
100
  if (this->FragmentShader)
101
  {
102 103
    this->FragmentShader->Delete();
    this->FragmentShader = NULL;
104
  }
105
  if (this->GeometryShader)
106
  {
107 108
    this->GeometryShader->Delete();
    this->GeometryShader = NULL;
109
  }
110
  if (this->TransformFeedback)
111
  {
112 113
    this->TransformFeedback->Delete();
    this->TransformFeedback = NULL;
114
  }
115 116
}

Ken Martin's avatar
Ken Martin committed
117 118
// Process the string, and return a version with replacements.
bool vtkShaderProgram::Substitute(std::string &source, const std::string &search,
119
             const std::string &replace, bool all)
Ken Martin's avatar
Ken Martin committed
120 121 122
{
  std::string::size_type pos = 0;
  bool replaced = false;
123
  while ((pos = source.find(search, pos)) != std::string::npos)
124
  {
Ken Martin's avatar
Ken Martin committed
125 126
    source.replace(pos, search.length(), replace);
    if (!all)
127
    {
Ken Martin's avatar
Ken Martin committed
128
      return true;
129
    }
130
    pos += replace.length();
Ken Martin's avatar
Ken Martin committed
131
    replaced = true;
132
  }
Ken Martin's avatar
Ken Martin committed
133 134 135 136 137
  return replaced;
}



138
template <class T> bool vtkShaderProgram::SetAttributeArray(const char *name,
139 140
                                                const T &array, int tupleSize,
                                                NormalizeOption normalize)
141
{
142
  if (array.empty())
143
  {
Ken Martin's avatar
Ken Martin committed
144
    this->Error = "Refusing to upload empty array for attribute " + std::string(name) + ".";
145
    return false;
146
  }
147 148 149 150 151 152 153 154
  int type = vtkTypeTraits<typename T::value_type>::VTKTypeID();
  return this->SetAttributeArrayInternal(name, &array[0], type, tupleSize,
                                         normalize);
}

bool vtkShaderProgram::AttachShader(const vtkShader *shader)
{
  if (shader->GetHandle() == 0)
155
  {
156
    this->Error = "Shader object was not initialized, cannot attach it.";
157
    return false;
158
  }
159
  if (shader->GetType() == vtkShader::Unknown)
160
  {
161
    this->Error = "Shader object is of type Unknown and cannot be used.";
162
    return false;
163
  }
164

165
  if (this->Handle == 0)
166
  {
167
    GLuint handle_ = glCreateProgram();
168
    if (handle_ == 0)
169
    {
170
      this->Error = "Could not create shader program.";
171
      return false;
172
    }
173 174
    this->Handle = static_cast<int>(handle_);
    this->Linked = false;
175
  }
176

177
  if (shader->GetType() == vtkShader::Vertex)
178
  {
179
    if (this->VertexShaderHandle != 0)
180
    {
181 182
      glDetachShader(static_cast<GLuint>(this->Handle),
                     static_cast<GLuint>(this->VertexShaderHandle));
183
    }
184 185
    this->VertexShaderHandle = shader->GetHandle();
  }
186
  else if (shader->GetType() == vtkShader::Fragment)
187
  {
188
    if (this->FragmentShaderHandle != 0)
189
    {
190 191
      glDetachShader(static_cast<GLuint>(this->Handle),
                     static_cast<GLuint>(this->FragmentShaderHandle));
192
    }
193 194
    this->FragmentShaderHandle = shader->GetHandle();
  }
195
  else if (shader->GetType() == vtkShader::Geometry)
196
  {
197
    if (this->GeometryShaderHandle != 0)
198
    {
199 200
      glDetachShader(static_cast<GLuint>(this->Handle),
                     static_cast<GLuint>(this->GeometryShaderHandle));
201
    }
202 203
// only use GS if supported
#ifdef GL_GEOMETRY_SHADER
204
    this->GeometryShaderHandle = shader->GetHandle();
205
#endif
206
  }
207
  else
208
  {
209
    this->Error = "Unknown shader type encountered - this should not happen.";
210 211 212
    return false;
  }

213
  glAttachShader(static_cast<GLuint>(this->Handle),
214
                 static_cast<GLuint>(shader->GetHandle()));
215
  this->Linked = false;
216 217 218
  return true;
}

219
bool vtkShaderProgram::DetachShader(const vtkShader *shader)
220
{
221
  if (shader->GetHandle() == 0)
222
  {
223
    this->Error = "Shader object was not initialized, cannot attach it.";
224
    return false;
225
  }
226
  if (shader->GetType() == vtkShader::Unknown)
227
  {
228
    this->Error = "Shader object is of type Unknown and cannot be used.";
229
    return false;
230
  }
231
  if (this->Handle == 0)
232
  {
233
    this->Error = "This shader prorgram has not been initialized yet.";
234
  }
235

236
  switch (shader->GetType())
237
  {
238 239
    case vtkShader::Vertex:
      if (this->VertexShaderHandle != shader->GetHandle())
240
      {
241 242
        Error = "The supplied shader was not attached to this program.";
        return false;
243
      }
244
      else
245
      {
246
        glDetachShader(static_cast<GLuint>(this->Handle),
247
                       static_cast<GLuint>(shader->GetHandle()));
248 249 250
        this->VertexShaderHandle = 0;
        this->Linked = false;
        return true;
251
      }
252 253
    case vtkShader::Fragment:
      if (this->FragmentShaderHandle != shader->GetHandle())
254
      {
255 256
        this->Error = "The supplied shader was not attached to this program.";
        return false;
257
      }
258
      else
259
      {
260
        glDetachShader(static_cast<GLuint>(this->Handle),
261
                       static_cast<GLuint>(shader->GetHandle()));
262 263 264
        this->FragmentShaderHandle = 0;
        this->Linked = false;
        return true;
265
      }
266
#ifdef GL_GEOMETRY_SHADER
267 268
    case vtkShader::Geometry:
      if (this->GeometryShaderHandle != shader->GetHandle())
269
      {
270 271
        this->Error = "The supplied shader was not attached to this program.";
        return false;
272
      }
273
      else
274
      {
275 276 277 278 279
        glDetachShader(static_cast<GLuint>(this->Handle),
                       static_cast<GLuint>(shader->GetHandle()));
        this->GeometryShaderHandle = 0;
        this->Linked = false;
        return true;
280
      }
281
#endif
282
    default:
283
      return false;
284
  }
285 286
}

287 288 289
void vtkShaderProgram::ClearMaps()
{
  for (IterT i = this->UniformLocs.begin(); i != this->UniformLocs.end(); i++)
290
  {
291
    free(const_cast<char *>(i->first));
292
  }
293 294
  this->UniformLocs.clear();
  for (IterT i = this->AttributeLocs.begin(); i != this->AttributeLocs.end(); i++)
295
  {
296
    free(const_cast<char *>(i->first));
297
  }
298 299 300
  this->AttributeLocs.clear();
}

301
bool vtkShaderProgram::Link()
302
{
303
  if (this->Linked)
304
  {
305
    return true;
306
  }
307

308
  if (this->Handle == 0)
309
  {
310
    this->Error = "Program has not been initialized, and/or does not have shaders.";
311
    return false;
312
  }
313

314
  // clear out the list of uniforms used
315
  this->ClearMaps();
316

317
#if GL_ES_VERSION_3_0 != 1
318 319
  // bind the outputs if specified
  if (this->NumberOfOutputs)
320
  {
321
    for (unsigned int i = 0; i < this->NumberOfOutputs; i++)
322
    {
323
      // this naming has to match the bindings
324
      // in vtkOpenGLShaderCache.cxx
325 326 327 328 329
      std::ostringstream dst;
      dst << "fragOutput" << i;
      glBindFragDataLocation(static_cast<GLuint>(this->Handle), i,
        dst.str().c_str());
    }
330
  }
331
#endif
332

333
  GLint isCompiled;
334 335 336
  glLinkProgram(static_cast<GLuint>(this->Handle));
  glGetProgramiv(static_cast<GLuint>(this->Handle), GL_LINK_STATUS, &isCompiled);
  if (isCompiled == 0)
337
  {
338
    GLint length(0);
339
    glGetProgramiv(static_cast<GLuint>(this->Handle), GL_INFO_LOG_LENGTH, &length);
340
    if (length > 1)
341
    {
342
      char *logMessage = new char[length];
343
      glGetProgramInfoLog(static_cast<GLuint>(this->Handle), length, NULL, logMessage);
344
      this->Error = logMessage;
345
      delete[] logMessage;
346
    }
347 348
    return false;
  }
349
  this->Linked = true;
350 351 352
  return true;
}

353
bool vtkShaderProgram::Bind()
354
{
355
  if (!this->Linked && !this->Link())
356
  {
357
    return false;
358
  }
359

360
  glUseProgram(static_cast<GLuint>(this->Handle));
361
  this->Bound = true;
362 363 364
  return true;
}

365 366 367 368
// return 0 if there is an issue
int vtkShaderProgram::CompileShader()
{
  if (!this->GetVertexShader()->Compile())
369
  {
370 371 372 373 374
    int lineNum = 1;
    std::istringstream stream(this->GetVertexShader()->GetSource());
    std::stringstream sstm;
    std::string aline;
    while (std::getline(stream, aline))
375
    {
376 377
      sstm << lineNum << ": " << aline << "\n";
      lineNum++;
378
    }
379
    vtkErrorMacro(<< sstm.str());
380
    vtkErrorMacro(<< this->GetVertexShader()->GetError());
381
    return 0;
382
  }
383
  if (!this->GetFragmentShader()->Compile())
384
  {
385 386 387 388 389
    int lineNum = 1;
    std::istringstream stream(this->GetFragmentShader()->GetSource());
    std::stringstream sstm;
    std::string aline;
    while (std::getline(stream, aline))
390
    {
391 392
      sstm << lineNum << ": " << aline << "\n";
      lineNum++;
393
    }
394
    vtkErrorMacro(<< sstm.str());
395
    vtkErrorMacro(<< this->GetFragmentShader()->GetError());
396
    return 0;
397
  }
398
#ifdef GL_GEOMETRY_SHADER
399 400
  if (this->GetGeometryShader()->GetSource().size() > 0 &&
      !this->GetGeometryShader()->Compile())
401
  {
402 403 404 405 406
    int lineNum = 1;
    std::istringstream stream(this->GetGeometryShader()->GetSource());
    std::stringstream sstm;
    std::string aline;
    while (std::getline(stream, aline))
407
    {
408 409
      sstm << lineNum << ": " << aline << "\n";
      lineNum++;
410
    }
411 412 413
    vtkErrorMacro(<< sstm.str());
    vtkErrorMacro(<< this->GetGeometryShader()->GetError());
    return 0;
414
  }
415 416
  if (this->GetGeometryShader()->GetSource().size() > 0 &&
      !this->AttachShader(this->GetGeometryShader()))
417
  {
418 419
    vtkErrorMacro(<< this->GetError());
    return 0;
420
  }
421 422
#endif
  if (!this->AttachShader(this->GetVertexShader()))
423
  {
424 425
    vtkErrorMacro(<< this->GetError());
    return 0;
426
  }
427
  if (!this->AttachShader(this->GetFragmentShader()))
428
  {
429 430
    vtkErrorMacro(<< this->GetError());
    return 0;
431
  }
432 433 434

  // Setup transform feedback:
  if (this->TransformFeedback)
435
  {
436
    this->TransformFeedback->BindVaryings(this);
437
  }
438

439
  if (!this->Link())
440
  {
441 442
    vtkErrorMacro(<< "Links failed: " << this->GetError());
    return 0;
443
  }
444 445 446 447 448 449

  this->Compiled = true;
  return 1;
}

void vtkShaderProgram::Release()
450 451
{
  glUseProgram(0);
452
  this->Bound = false;
453 454
}

455
void vtkShaderProgram::ReleaseGraphicsResources(vtkWindow *win)
456 457
{
  this->Release();
458 459

  if (this->Compiled)
460
  {
461 462
    this->DetachShader(this->VertexShader);
    this->DetachShader(this->FragmentShader);
463
    this->DetachShader(this->GeometryShader);
464 465
    this->VertexShader->Cleanup();
    this->FragmentShader->Cleanup();
466
    this->GeometryShader->Cleanup();
467
    this->Compiled = false;
468
  }
469 470

  vtkOpenGLRenderWindow *renWin = vtkOpenGLRenderWindow::SafeDownCast(win);
471
  if (renWin && renWin->GetShaderCache()->GetLastShaderBound() == this)
472
  {
473
    renWin->GetShaderCache()->ClearLastShaderBound();
474
  }
475

476
  if (this->Handle != 0)
477
  {
478 479 480
    glDeleteProgram(this->Handle);
    this->Handle = 0;
    this->Linked = false;
481
  }
482

483
  if (this->TransformFeedback)
484
  {
485
    this->TransformFeedback->ReleaseGraphicsResources();
486
  }
487 488
}

489
bool vtkShaderProgram::EnableAttributeArray(const char *name)
490
{
491 492
  GLint location = static_cast<GLint>(this->FindAttributeArray(name));
  if (location == -1)
493
  {
494
    this->Error = "Could not enable attribute " + std::string(name) + ". No such attribute.";
495
    return false;
496
  }
497 498 499 500
  glEnableVertexAttribArray(location);
  return true;
}

501
bool vtkShaderProgram::DisableAttributeArray(const char *name)
502
{
503 504
  GLint location = static_cast<GLint>(this->FindAttributeArray(name));
  if (location == -1)
505
  {
506
    this->Error = "Could not disable attribute " + std::string(name) + ". No such attribute.";
507
    return false;
508
  }
509 510 511 512 513 514
  glDisableVertexAttribArray(location);
  return true;
}

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

515
bool vtkShaderProgram::UseAttributeArray(const char *name, int offset,
516 517 518 519
                                      size_t stride, int elementType,
                                      int elementTupleSize,
                                      NormalizeOption normalize)
{
520 521
  GLint location = static_cast<GLint>(this->FindAttributeArray(name));
  if (location == -1)
522
  {
523 524
    this->Error = "Could not use attribute (does not exist) ";
    this->Error += name;
525
    return false;
526
  }
527 528 529 530 531 532
  glVertexAttribPointer(location, elementTupleSize, convertTypeToGL(elementType),
                        normalize == Normalize ? GL_TRUE : GL_FALSE,
                        static_cast<GLsizei>(stride), BUFFER_OFFSET(offset));
  return true;
}

533
bool vtkShaderProgram::SetUniformi(const char *name, int i)
534
{
535 536
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
537
  {
538 539
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
540
    return false;
541
  }
542 543 544 545
  glUniform1i(location, static_cast<GLint>(i));
  return true;
}

546
bool vtkShaderProgram::SetUniformf(const char *name, float f)
547
{
548 549
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
550
  {
551 552
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
553
    return false;
554
  }
555 556 557 558
  glUniform1f(location, static_cast<GLfloat>(f));
  return true;
}

559
bool vtkShaderProgram::SetUniformMatrix(const char *name,
560 561
                                    vtkMatrix4x4 *matrix)
{
562 563
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
564
  {
565 566
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
567
    return false;
568
  }
569 570
  float data[16];
  for (int i = 0; i < 16; ++i)
571
  {
572
    data[i] = matrix->Element[i / 4][i % 4];
573
  }
574
  glUniformMatrix4fv(location, 1, GL_FALSE, data);
575 576 577
  return true;
}

578
bool vtkShaderProgram::SetUniformMatrix3x3(const char *name,
579 580 581 582
                                           float *matrix)
{
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
583
  {
584 585
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
586
    return false;
587
  }
588 589 590 591
  glUniformMatrix3fv(location, 1, GL_FALSE, matrix);
  return true;
}

592
bool vtkShaderProgram::SetUniformMatrix4x4(const char *name,
593
                                           float *matrix)
594 595 596 597 598 599 600 601
{
  return this->SetUniformMatrix4x4v(name,1,matrix);
}

bool vtkShaderProgram::SetUniformMatrix4x4v(
  const char *name,
  const int count,
  float *matrix)
602 603 604
{
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
605
  {
606 607
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
608
    return false;
609
  }
610
  glUniformMatrix4fv(location, count, GL_FALSE, matrix);
611 612 613
  return true;
}

614
bool vtkShaderProgram::SetUniformMatrix(const char *name,
615 616
                                    vtkMatrix3x3 *matrix)
{
617 618
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
619
  {
620 621
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
622
    return false;
623
  }
624 625
  float data[9];
  for (int i = 0; i < 9; ++i)
626
  {
627
    data[i] = matrix->GetElement(i / 3, i % 3);
628
  }
629
  glUniformMatrix3fv(location, 1, GL_FALSE, data);
630 631 632
  return true;
}

633
bool vtkShaderProgram::SetUniform1fv(const char *name, const int count,
634 635
                                    const float *v)
{
636 637
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
638
  {
639 640
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
641
    return false;
642
  }
643
  glUniform1fv(location, count, static_cast<const GLfloat *>(v));
644 645 646
  return true;
}

647
bool vtkShaderProgram::SetUniform1iv(const char *name, const int count,
648 649
                                    const int *v)
{
650 651
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
652
  {
653 654
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
655
    return false;
656
  }
657
  glUniform1iv(location, count, static_cast<const GLint *>(v));
658 659 660
  return true;
}

661
bool vtkShaderProgram::SetUniform3fv(const char *name, const int count,
662 663
                                    const float (*v)[3])
{
664 665
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
666
  {
667 668
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
669
    return false;
670
  }
671
  glUniform3fv(location, count, (const GLfloat *)v);
672 673 674
  return true;
}

675
bool vtkShaderProgram::SetUniform4fv(const char *name, const int count,
676 677 678 679
                                    const float (*v)[4])
{
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
680
  {
681 682
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
683
    return false;
684
  }
685
  glUniform4fv(location, count, (const GLfloat *)v);
686 687 688
  return true;
}

689
bool vtkShaderProgram::SetUniform2f(const char *name, const float v[2])
690 691 692
{
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
693
  {
694 695
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
696
    return false;
697
  }
698 699 700 701
  glUniform2fv(location, 1, v);
  return true;
}

702 703 704 705 706
bool vtkShaderProgram::SetUniform2fv(const char *name, const int count,
                                    const float (*f)[2])
{
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
707
  {
708 709
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
710
    return false;
711
  }
712 713 714 715
  glUniform2fv(location, count, (const GLfloat *)f);
  return true;
}

716
bool vtkShaderProgram::SetUniform3f(const char *name, const float v[3])
717 718 719
{
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
720
  {
721 722
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
723
    return false;
724
  }
725 726 727 728
  glUniform3fv(location, 1, v);
  return true;
}

729
bool vtkShaderProgram::SetUniform4f(const char *name, const float v[4])
730
{
731 732
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
733
  {
734 735
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
736
    return false;
737
  }
738
  glUniform4fv(location, 1, v);
739 740 741
  return true;
}

742
bool vtkShaderProgram::SetUniform2i(const char *name, const int v[2])
743
{
744 745
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
746
  {
747 748
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
749
    return false;
750
  }
751
  glUniform2iv(location, 1, v);
752 753 754
  return true;
}

755
bool vtkShaderProgram::SetUniform3uc(const char *name,
756
                                    const unsigned char v[3])
757
{
758 759
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
760
  {
761 762
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
763
    return false;
764
  }
765 766
  float colorf[3] = {v[0] / 255.0f, v[1] / 255.0f, v[2] / 255.0f};
  glUniform3fv(location, 1, colorf);
767 768 769
  return true;
}

770
bool vtkShaderProgram::SetUniform4uc(const char *name,
771
                                    const unsigned char v[4])
772 773 774
{
  GLint location = static_cast<GLint>(this->FindUniform(name));
  if (location == -1)
775
  {
776 777
    this->Error = "Could not set uniform (does not exist) ";
    this->Error += name;
778
    return false;
779
  }
780 781
  float colorf[4] = {v[0] / 255.0f, v[1] / 255.0f, v[2] / 255.0f, v[3] / 255.0f};
  glUniform4fv(location, 1, colorf);
782 783 784
  return true;
}

785
bool vtkShaderProgram::SetAttributeArrayInternal(
786
    const char *name, void *buffer, int type, int tupleSize,
787
    vtkShaderProgram::NormalizeOption normalize)
788
{
789
  if (type == -1)
790
  {
791 792
    this->Error = "Unrecognized data type for attribute ";
    this->Error += name;
793
    return false;
794
  }
795 796
  GLint location = static_cast<GLint>(this->FindAttributeArray(name));
  if (location == -1)
797
  {
798 799
    this->Error = "Could not set attribute (does not exist) ";
    this->Error += name;
800
    return false;
801
  }
802 803 804 805 806 807
  const GLvoid *data = static_cast<const GLvoid *>(buffer);
  glVertexAttribPointer(location, tupleSize, convertTypeToGL(type),
                        normalize == Normalize ? GL_TRUE : GL_FALSE, 0, data);
  return true;
}

808
inline int vtkShaderProgram::FindAttributeArray(const char *cname)
809
{
810
  if (cname == NULL || !this->Linked)
811
  {
812
    return -1;
813
  }
814 815 816

  GLint loc = -1;

817
  IterT iter = this->AttributeLocs.find(cname);
818
  if (iter == this->AttributeLocs.end())
819
  {
820 821
    loc = glGetAttribLocation(static_cast<GLuint>(Handle),
                              static_cast<const GLchar *>(cname));
822 823
    const char *allocStr = strdup(cname);
    this->AttributeLocs.insert(std::make_pair(allocStr, static_cast<int>(loc)));
824
  }
825
  else
826
  {
827
    loc = iter->second;
828
  }
829
  return loc;
830 831
}

832
inline int vtkShaderProgram::FindUniform(const char *cname)
833
{
834
  if (cname == NULL || !this->Linked)
835
  {
836
    return -1;
837
  }
838 839 840

  GLint loc = -1;

841
  IterT iter = this->UniformLocs.find(cname);
842
  if (iter == this->UniformLocs.end())
843
  {
844 845
    loc = static_cast<int>(glGetUniformLocation(static_cast<GLuint>(Handle),
                                                (const GLchar *)cname));
846 847
    const char *allocStr = strdup(cname);
    this->UniformLocs.insert(std::make_pair(allocStr, static_cast<int>(loc)));
848
  }
849
  else
850
  {
851
    loc = iter->second;
852
  }
853
  return loc;
854 855
}

856
bool vtkShaderProgram::IsUniformUsed(const char *cname)
857
{
858
  int result = this->FindUniform(cname);
859

860
  if (result == -1 && !this->Linked)
861
  {
862
    vtkErrorMacro("attempt to find uniform when the shader program is not linked");
863
  }
864
  return (result != -1);
865 866
}

867 868 869
// ----------------------------------------------------------------------------
bool vtkShaderProgram::IsAttributeUsed(const char *cname)
{
870
  int result = this->FindAttributeArray(cname);
871

872
  if (result == -1 && !this->Linked)
873
  {
874
    vtkErrorMacro("attempt to find attribute when the shader program is not linked");
875
  }
876
  return (result != -1);
877
}
878

879 880 881 882
// ----------------------------------------------------------------------------
void vtkShaderProgram::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
883
}