/*========================================================================= Program: Visualization Toolkit Module: vtkUniformVariables.cxx 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. =========================================================================*/ #include "vtkUniformVariables.h" #include "vtkgl.h" #include #include "vtkObjectFactory.h" #include "vtkOpenGLError.h" #include //----------------------------------------------------------------------------- vtkStandardNewMacro(vtkUniformVariables); class ltstr { public: bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } }; class vtkUniform { public: // just because dynamic__cast is forbidden in VTK. Sucks. enum { ClassTypeVectorInt=0, ClassTypeVectorFloat=1, ClassTypeMatrix=2, ClassTypeArrayInt=3, ClassTypeArrayFloat=4 }; int GetClassType() const { return this->ClassType; } vtkUniform() { this->ClassType=-1; this->Name=0; } const char *GetName() const { return this->Name; } void SetName(const char *n) { if(this->Name==0 && n==0) { return; } if(this->Name!=0 && n!=0 && strcmp(this->Name,n)==0) { return; } delete[] this->Name; if(n!=0) // copy { size_t l=strlen(n)+1; this->Name=new char[l]; strncpy(this->Name,n,l); } else { this->Name=0; } } virtual ~vtkUniform() { delete[] Name; } virtual void Send(int location)=0; virtual void PrintSelf(ostream &os, vtkIndent indent)=0; virtual vtkUniform *Clone() const=0; protected: char *Name; int ClassType; // just because dynamic__cast is forbidden in VTK. Sucks. }; class vtkUniformVectorInt : public vtkUniform { public: vtkUniformVectorInt(int size, int *values) { this->ClassType=ClassTypeVectorInt; this->Size=size; this->Values=new int[size]; int i=0; while(iValues[i]=values[i]; ++i; } } ~vtkUniformVectorInt() override { delete[] this->Values; } int GetSize() { return this->Size; } void SetValues(int *values) { int i=0; while(iSize) { this->Values[i]=values[i]; ++i; } } const int *GetValues() { return this->Values; } void Send(int location) override { switch(this->Size) { case 1: vtkgl::Uniform1i(location,this->Values[0]); break; case 2: vtkgl::Uniform2i(location,this->Values[0],this->Values[1]); break; case 3: vtkgl::Uniform3i(location,this->Values[0],this->Values[1], this->Values[2]); break; case 4: vtkgl::Uniform4i(location,this->Values[0],this->Values[1], this->Values[2],this->Values[3]); break; } vtkOpenGLStaticCheckErrorMacro("failed at glUniform*i"); } void PrintSelf(ostream &os, vtkIndent indent) override { os << indent << this->Name << " (uniform" << this->Size << "i): "; int i=0; while(iSize) { os << this->Values[i]; if(i<(this->Size-1)) { os <<","; } ++i; } os << endl; } vtkUniform *Clone() const override { vtkUniformVectorInt *result=new vtkUniformVectorInt(this->Size, this->Values); result->SetName(this->Name); return result; } protected: int Size; int *Values; }; class vtkUniformVectorFloat : public vtkUniform { public: vtkUniformVectorFloat(int size, float *values) { this->ClassType=ClassTypeVectorFloat; this->Size=size; this->Values=new float[size]; int i=0; while(iValues[i]=values[i]; ++i; } } ~vtkUniformVectorFloat() override { delete[] this->Values; } int GetSize() { return this->Size; } void SetValues(float *values) { int i=0; while(iSize) { this->Values[i]=values[i]; ++i; } } const float *GetValues() { return this->Values; } void Send(int location) override { switch(this->Size) { case 1: vtkgl::Uniform1f(location,this->Values[0]); break; case 2: vtkgl::Uniform2f(location,this->Values[0],this->Values[1]); break; case 3: vtkgl::Uniform3f(location,this->Values[0],this->Values[1], this->Values[2]); break; case 4: vtkgl::Uniform4f(location,this->Values[0],this->Values[1], this->Values[2],this->Values[3]); break; } vtkOpenGLStaticCheckErrorMacro("failed at glUniform*f"); } void PrintSelf(ostream &os, vtkIndent indent) override { os << indent << this->Name << " (uniform" << this->Size << "f): "; int i=0; while(iSize) { os << this->Values[i]; if(i<(this->Size-1)) { os <<","; } ++i; } os << endl; } vtkUniform *Clone() const override { vtkUniformVectorFloat *result=new vtkUniformVectorFloat(this->Size, this->Values); result->SetName(this->Name); return result; } protected: int Size; float *Values; }; class vtkUniformArrayInt : public vtkUniform { public: vtkUniformArrayInt(int size, int arraySize, int *values) { this->ClassType=ClassTypeArrayInt; this->Size=size; this->ArraySize=arraySize; this->Values=new GLint[size*arraySize]; int i=0; while(iSize*this->ArraySize) { this->Values[i]=values[i]; ++i; } } // this constructor is used inside Clone() // It is required because GLint is long on Mac, not int. vtkUniformArrayInt(int size, int arraySize, const GLint *values) { this->ClassType=ClassTypeArrayInt; this->Size=size; this->ArraySize=arraySize; this->Values=new GLint[size*arraySize]; int i=0; while(iSize*this->ArraySize) { this->Values[i]=values[i]; ++i; } } ~vtkUniformArrayInt() override { delete[] this->Values; } int GetSize() { return this->Size; } int GetArraySize() { return this->ArraySize; } void SetValues(int *values) { int i=0; while(iSize*this->ArraySize) { this->Values[i]=values[i]; ++i; } } const GLint *GetValues() { return this->Values; } void Send(int location) override { switch(this->Size) { case 1: vtkgl::Uniform1iv(location,this->ArraySize,this->Values); break; case 2: vtkgl::Uniform2iv(location,this->ArraySize,this->Values); break; case 3: vtkgl::Uniform3iv(location,this->ArraySize,this->Values); break; case 4: vtkgl::Uniform4iv(location,this->ArraySize,this->Values); break; } vtkOpenGLStaticCheckErrorMacro("failed at glUniform*iv"); } void PrintSelf(ostream &os, vtkIndent indent) override { os << indent << this->Name << " (uniform" << this->Size << "iv[" << this->ArraySize << "]): "; int j=0; while(jArraySize) { os << "("; int i=0; while(iSize) { os << this->Values[i]; if(i<(this->Size-1)) { os <<","; } ++i; } os << endl; ++j; } } vtkUniform *Clone() const override { vtkUniformArrayInt *result=new vtkUniformArrayInt(this->Size, this->ArraySize, this->Values); result->SetName(this->Name); return result; } protected: int Size; // size of element (eq. to float, vec2, vec2, vec4) int ArraySize; // number of elements GLint *Values; // GLint is long on Mac }; class vtkUniformArrayFloat : public vtkUniform { public: vtkUniformArrayFloat(int size, int arraySize, float *values) { this->ClassType=ClassTypeArrayFloat; this->Size=size; this->ArraySize=arraySize; this->Values=new float[size*arraySize]; int i=0; while(iSize*this->ArraySize) { this->Values[i]=values[i]; ++i; } } ~vtkUniformArrayFloat() override { delete[] this->Values; } int GetSize() { return this->Size; } int GetArraySize() { return this->ArraySize; } void SetValues(float *values) { int i=0; while(iSize*this->ArraySize) { this->Values[i]=values[i]; ++i; } } const float *GetValues() { return this->Values; } void Send(int location) override { switch(this->Size) { case 1: vtkgl::Uniform1fv(location,this->ArraySize,this->Values); break; case 2: vtkgl::Uniform2fv(location,this->ArraySize,this->Values); break; case 3: vtkgl::Uniform3fv(location,this->ArraySize,this->Values); break; case 4: vtkgl::Uniform4fv(location,this->ArraySize,this->Values); break; } vtkOpenGLStaticCheckErrorMacro("failed at glUniform*fv"); } void PrintSelf(ostream &os, vtkIndent indent) override { os << indent << this->Name << " (uniform" << this->Size << "fv[" << this->ArraySize << "]): "; int j=0; while(jArraySize) { os << "("; int i=0; while(iSize) { os << this->Values[i]; if(i<(this->Size-1)) { os <<","; } ++i; } os << endl; ++j; } } vtkUniform *Clone() const override { vtkUniformArrayFloat *result=new vtkUniformArrayFloat(this->Size, this->ArraySize, this->Values); result->SetName(this->Name); return result; } protected: int Size; // size of element (eq. to float, vec2, vec2, vec4) int ArraySize; // number of elements float *Values; }; // rows or columns are 2,3,4. class vtkUniformMatrix : public vtkUniform { public: vtkUniformMatrix(int rows, int columns, float *values) { this->ClassType=ClassTypeMatrix; this->Rows=rows; this->Columns=columns; this->Values=new float[rows*columns]; int i=0; while(iValues[index]=values[index]; ++j; } ++i; } } ~vtkUniformMatrix() override { delete[] this->Values; } int GetRows() { return this->Rows; } int GetColumns() { return this->Columns; } void SetValues(float *values) { int i=0; while(iRows) { int j=0; while(jColumns) { int index=i*this->Columns+j; this->Values[index]=values[index]; ++j; } ++i; } } const float* GetValues() { return this->Values; } void Send(int location) override { switch(this->Rows) { case 2: switch(this->Columns) { case 2: vtkgl::UniformMatrix2fv(location,1,GL_FALSE,this->Values); break; case 3: vtkgl::UniformMatrix2x3fv(location,1,GL_FALSE,this->Values); break; case 4: vtkgl::UniformMatrix2x4fv(location,1,GL_FALSE,this->Values); break; } break; case 3: switch(this->Columns) { case 2: vtkgl::UniformMatrix3x2fv(location,1,GL_FALSE,this->Values); break; case 3: vtkgl::UniformMatrix3fv(location,1,GL_FALSE,this->Values); break; case 4: vtkgl::UniformMatrix3x4fv(location,1,GL_FALSE,this->Values); break; } break; case 4: switch(this->Columns) { case 2: vtkgl::UniformMatrix4x2fv(location,1,GL_FALSE,this->Values); break; case 3: vtkgl::UniformMatrix4x3fv(location,1,GL_FALSE,this->Values); break; case 4: vtkgl::UniformMatrix4fv(location,1,GL_FALSE,this->Values); break; } break; } vtkOpenGLStaticCheckErrorMacro("failed at glUniformMatrix*fv"); } void PrintSelf(ostream &os, vtkIndent indent) override { os << indent << this->Name << " (matrix " << this->Rows << "x" << this->Columns << "): "; int i=0; while(iRows) { int j=0; while(jColumns) { int index=i*this->Columns+j; os << this->Values[index]; if(j<(this->Columns-1)) os << ","; ++j; } os << endl; ++i; } } vtkUniform *Clone() const override { vtkUniformMatrix *result=new vtkUniformMatrix(this->Rows,this->Columns, this->Values); result->SetName(this->Name); return result; } protected: float *Values; int Rows; int Columns; }; typedef std::map UniformMap; typedef std::map::iterator UniformMapIt; class vtkUniformVariablesMap { public: UniformMap Map; UniformMapIt It; // used for external iteration. ~vtkUniformVariablesMap() { UniformMapIt i=this->Map.begin(); UniformMapIt e=this->Map.end(); while(i!=e) { vtkUniform *u=(*i).second; delete u; ++i; } } }; // ---------------------------------------------------------------------------- vtkUniformVariables::vtkUniformVariables() { this->Map=new vtkUniformVariablesMap; } // ---------------------------------------------------------------------------- vtkUniformVariables::~vtkUniformVariables() { delete this->Map; } // ---------------------------------------------------------------------------- void vtkUniformVariables::SetUniformi(const char *name, int numberOfComponents, int *value) { assert("pre: name_exists" && name!=0); assert("pre: value_exists" && value!=0); assert("pre: valid_numberOfComponents" && numberOfComponents>=1 && numberOfComponents<=4); UniformMapIt cur=this->Map->Map.find(name); if(cur!=this->Map->Map.end()) { vtkUniform *u=(*cur).second; vtkUniformVectorInt *ui=0; if(u->GetClassType()==vtkUniform::ClassTypeVectorInt) { ui=static_cast(u); } if(ui==0) { vtkErrorMacro(<<"try to overwrite a value with different type."); } else { if(ui->GetSize()!=numberOfComponents) { vtkErrorMacro(<<"try to overwrite a value of same type but different number of components."); } else { bool changed=false; int i=0; while(!changed && iGetValues()[i]; ++i; } if(changed) { ui->SetValues(value); this->Modified(); } } } } else { vtkUniform *u=0; u=new vtkUniformVectorInt(numberOfComponents,value); u->SetName(name); std::pair p; p.first=u->GetName(); // cannot be `name' because // we don't manage this pointer. p.second=u; this->Map->Map.insert(p); this->Modified(); } } // ---------------------------------------------------------------------------- void vtkUniformVariables::SetUniformf(const char *name, int numberOfComponents, float *value) { assert("pre: name_exists" && name!=0); assert("pre: value_exists" && value!=0); assert("pre: valid_numberOfComponents" && numberOfComponents>=1 && numberOfComponents<=4); UniformMapIt cur=this->Map->Map.find(name); if(cur!=this->Map->Map.end()) { vtkUniform *u=(*cur).second; vtkUniformVectorFloat *uf=0; if(u->GetClassType()==vtkUniform::ClassTypeVectorFloat) { uf=static_cast(u); } if(uf==0) { vtkErrorMacro(<<"try to overwrite a value with different type."); } else { if(uf->GetSize()!=numberOfComponents) { vtkErrorMacro(<<"try to overwrite a value of same type but different number of components."); } else { bool changed=false; int i=0; while(!changed && iGetValues()[i]; ++i; } if(changed) { uf->SetValues(value); this->Modified(); } } } } else { vtkUniform *u=0; u=new vtkUniformVectorFloat(numberOfComponents,value); u->SetName(name); std::pair p; p.first=u->GetName(); // cannot be `name' because // we don't manage this pointer. p.second=u; this->Map->Map.insert(p); this->Modified(); } } // ---------------------------------------------------------------------------- void vtkUniformVariables::SetUniformiv(const char *name, int numberOfComponents, int numberOfElements, int *value) { assert("pre: name_exists" && name!=0); assert("pre: value_exists" && value!=0); assert("pre: valid_numberOfComponents" && numberOfComponents>=1 && numberOfComponents<=4); assert("pre: valid_numberOfElements" && numberOfElements>=1); UniformMapIt cur=this->Map->Map.find(name); if(cur!=this->Map->Map.end()) { vtkUniform *u=(*cur).second; vtkUniformArrayInt *ui=0; if(u->GetClassType()==vtkUniform::ClassTypeArrayInt) { ui=static_cast(u); } if(ui==0) { vtkErrorMacro(<<"try to overwrite a value with different type."); } else { if(ui->GetSize()!=numberOfComponents) { vtkErrorMacro(<<"try to overwrite a value of same type but different number of components."); } if(ui->GetArraySize()!=numberOfElements) { vtkErrorMacro(<<"try to overwrite a value of same type but different number of elements."); } else { bool changed=false; int i=0; while(!changed && iGetValues()[i]; ++i; } if(changed) { ui->SetValues(value); this->Modified(); } } } } else { vtkUniform *u=0; u=new vtkUniformArrayInt(numberOfComponents,numberOfElements,value); u->SetName(name); std::pair p; p.first=u->GetName(); // cannot be `name' because // we don't manage this pointer. p.second=u; this->Map->Map.insert(p); this->Modified(); } } // ---------------------------------------------------------------------------- void vtkUniformVariables::SetUniformfv(const char *name, int numberOfComponents, int numberOfElements, float *value) { assert("pre: name_exists" && name!=0); assert("pre: value_exists" && value!=0); assert("pre: valid_numberOfComponents" && numberOfComponents>=1 && numberOfComponents<=4); assert("pre: valid_numberOfElements" && numberOfElements>=1); UniformMapIt cur=this->Map->Map.find(name); if(cur!=this->Map->Map.end()) { vtkUniform *u=(*cur).second; vtkUniformArrayFloat *uf=0; if(u->GetClassType()==vtkUniform::ClassTypeArrayFloat) { uf=static_cast(u); } if(uf==0) { vtkErrorMacro(<<"try to overwrite a value with different type."); } else { if(uf->GetSize()!=numberOfComponents) { vtkErrorMacro(<<"try to overwrite a value of same type but different number of components."); } if(uf->GetArraySize()!=numberOfElements) { vtkErrorMacro(<<"try to overwrite a value of same type but different number of elements."); } else { bool changed=false; int i=0; while(!changed && iGetValues()[i]; ++i; } if(changed) { uf->SetValues(value); this->Modified(); } } } } else { vtkUniform *u=0; u=new vtkUniformArrayFloat(numberOfComponents,numberOfElements,value); u->SetName(name); std::pair p; p.first=u->GetName(); // cannot be `name' because // we don't manage this pointer. p.second=u; this->Map->Map.insert(p); this->Modified(); } } // ---------------------------------------------------------------------------- void vtkUniformVariables::SetUniformMatrix(const char *name, int rows, int columns, float *value) { assert("pre: name_exists" && name!=0); assert("pre: value_exists" && value!=0); assert("pre: valid_rows" && rows>=2 && rows<=4); assert("pre: valid_columns" && columns>=2 && columns<=4); UniformMapIt cur=this->Map->Map.find(name); if(cur!=this->Map->Map.end()) { vtkUniform *u=(*cur).second; vtkUniformMatrix *um=0; if(u->GetClassType()==vtkUniform::ClassTypeMatrix) { um=static_cast(u); } if(um==0) { vtkErrorMacro(<<"try to overwrite a value with different type."); } else { if(um->GetRows()!=rows || um->GetColumns()!=columns) { vtkErrorMacro(<<"try to overwrite a value of same type but different number of components."); } else { bool changed=false; int i=0; while(!changed && iGetValues()[i]; ++i; } if(changed) { um->SetValues(value); this->Modified(); } } } } else { vtkUniform *u=new vtkUniformMatrix(rows,columns,value); u->SetName(name); std::pair p; p.first=u->GetName(); // cannot be `name' because // we don't manage this pointer. p.second=u; this->Map->Map.insert(p); this->Modified(); } } // ---------------------------------------------------------------------------- // Description: // Remove uniform `name' from the list. void vtkUniformVariables::RemoveUniform(const char *name) { UniformMapIt cur=this->Map->Map.find(name); if(cur!=this->Map->Map.end()) { this->Map->Map.erase(cur); this->Modified(); } } // ---------------------------------------------------------------------------- // Description: // \pre need a valid OpenGL context and a shader program in use. void vtkUniformVariables::Send(const char *name, int uniformIndex) { UniformMapIt cur=this->Map->Map.find(name); (*cur).second->Send(uniformIndex); } // ---------------------------------------------------------------------------- // Description: // Place the internal cursor on the first uniform. void vtkUniformVariables::Start() { this->Map->It=this->Map->Map.begin(); } // ---------------------------------------------------------------------------- // Description: // Is the iteration done? bool vtkUniformVariables::IsAtEnd() { return this->Map->It==this->Map->Map.end(); } // ---------------------------------------------------------------------------- // Description: // Name of the uniform at the current cursor position. // \pre not_done: !this->IsAtEnd() const char *vtkUniformVariables::GetCurrentName() { assert("pre: not_done" && !this->IsAtEnd()); return (*this->Map->It).first; } // ---------------------------------------------------------------------------- // Description: // \pre need a valid OpenGL context and a shader program in use. // \pre not_done: !this->IsAtEnd() void vtkUniformVariables::SendCurrentUniform(int uniformIndex) { assert("pre: not_done" && !this->IsAtEnd()); (*this->Map->It).second->Send(uniformIndex); } // ---------------------------------------------------------------------------- // Description: // Move the cursor to the next uniform. // \pre not_done: !this->IsAtEnd() void vtkUniformVariables::Next() { assert("pre: not_done" && !this->IsAtEnd()); ++this->Map->It; } // ---------------------------------------------------------------------------- // Description: // Copy all the variables from `other'. Any existing variable will be // overwritten. // \pre other_exists: other!=0 // \pre not_self: other!=this void vtkUniformVariables::Merge(vtkUniformVariables *other) { assert("pre: other_exists" && other != 0); assert("pre: not_self" && other != this); other->Start(); while (!other->IsAtEnd()) { const char *name = other->GetCurrentName(); UniformMapIt prev = this->Map->Map.find(name); if (prev != this->Map->Map.end()) { delete prev->second; this->Map->Map.erase(prev); } vtkUniform* clone = other->Map->It->second->Clone(); this->Map->Map[clone->GetName()] = clone; other->Next(); } if (other->Map->Map.size() > 0) { this->Modified(); } } // ---------------------------------------------------------------------------- // Description: // Copy all the variables from `other'. Any existing variable will be // deleted first. // \pre other_exists: other!=0 // \pre not_self: other!=this void vtkUniformVariables::DeepCopy(vtkUniformVariables *other) { assert("pre: other_exists" && other!=0); assert("pre: not_self" && other!=this); if(this->Map->Map.size()>0) { delete this->Map; this->Map=new vtkUniformVariablesMap; this->Modified(); } this->Merge(other); } // ---------------------------------------------------------------------------- void vtkUniformVariables::RemoveAllUniforms() { if(this->Map->Map.size()>0) { delete this->Map; this->Map=new vtkUniformVariablesMap; this->Modified(); } } // ---------------------------------------------------------------------------- void vtkUniformVariables::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); this->Start(); while(!this->IsAtEnd()) { const char *name=this->GetCurrentName(); UniformMapIt cur=this->Map->Map.find(name); (*cur).second->PrintSelf(os,indent); this->Next(); } }