kick
/Users/morten/Programmering/cpp/kick/src/kick/material/material.cpp
00001 //
00002 //  material.cpp
00003 //  KickCPP
00004 //
00005 //  Created by morten on 8/25/13.
00006 //  Copyright (c) 2013 Morten Nobel-Joergensen. All rights reserved.
00007 //
00008 
00009 #include "kick/material/material.h"
00010 
00011 #include <functional>
00012 #include <utility>
00013 #include <string>
00014 #include <glm/gtc/type_ptr.hpp>
00015 #include <glm/gtx/string_cast.hpp>
00016 #include "kick/material/shader.h"
00017 #include "kick/core/debug.h"
00018 
00019 using namespace std;
00020 
00021 namespace kick {
00022     MaterialData::MaterialData(const MaterialData & val)
00023     :shaderLocation(val.shaderLocation),
00024     glType(val.glType),
00025     value(0),
00026     defaultUniform(val.defaultUniform)
00027     {
00028         setValue(val.value);
00029     }
00030 
00031     MaterialData& MaterialData::operator=(const MaterialData& other){
00032         shaderLocation = other.shaderLocation;
00033         glType = other.glType;
00034         setValue(other.value);
00035         defaultUniform = other.defaultUniform;
00036         return *this;
00037     }
00038 
00039     void MaterialData::setValue(MaterialValueType val) {
00040         for (int i=0;i<16;i++){
00041             value.floatValue[i] = val.floatValue[i];
00042         }
00043     }
00044     
00045     Material::Material(std::shared_ptr<Shader> s)
00046     {
00047         setShader(s);
00048     }
00049 
00050     Material::Material(const Material& copy)
00051             :currentUniformData(copy.currentUniformData),
00052              mShader(nullptr),
00053              shaderChangedListener(),
00054              mRenderOrder(copy.mRenderOrder),
00055              texture2DRef(copy.texture2DRef),
00056              textureCubeRef(copy.textureCubeRef)
00057     {
00058         setShader(copy.mShader);
00059     }
00060 
00061 
00062     Material::~Material(){
00063     }
00064     
00065     void Material::setShader(std::shared_ptr<Shader> shader){
00066         if (this->mShader == shader) return;
00067         this->mShader = shader;
00068         if (shader){
00069             using namespace std::placeholders;
00070             auto f = std::bind(&Material::shaderChanged, this, _1);
00071             shaderChangedListener = shader->shaderChanged.createListener(f);
00072             shaderChanged({shader.get(), ShaderEventType::all });
00073             setDefaultUniforms();
00074         } else {
00075             shaderChangedListener = EventListener<ShaderEvent>();
00076         }
00077     }
00078 
00079     std::shared_ptr<Shader> Material::shader(){
00080         return mShader;
00081     }
00082         
00083     void Material::shaderChanged(ShaderEvent se){
00084         if (se.eventType == ShaderEventType::all || se.eventType == ShaderEventType::shader) {
00085             for (auto &pair : currentUniformData) {
00086                 updateShaderLocation(pair.first, pair.second);
00087             }
00088             mRenderOrder = mShader ? mShader->getRenderOrder() : 0;
00089         }
00090         if (se.eventType == ShaderEventType::all || se.eventType == ShaderEventType::defaultUniform) {
00091             setDefaultUniforms();
00092         }
00093     }
00094     
00095     void Material::updateShaderLocation(std::string name, MaterialData& value){
00096         if (mShader == nullptr){
00097             value.shaderLocation = -1;
00098             return;
00099         }
00100         auto descriptor = mShader->getShaderUniform(name);
00101         if (descriptor == nullptr){
00102             value.shaderLocation = -1;
00103         } else {
00104             value.shaderLocation = descriptor->index;
00105         }
00106     }
00107     
00108     void Material::setUniformData(std::string name, MaterialData&& value){
00109         auto pos = currentUniformData.find(name);
00110         if (pos != currentUniformData.end()){
00111             pos->second.setValue(value.value);
00112             if (pos->second.glType != value.glType){
00113                 pos->second.glType = value.glType;
00114                 updateShaderLocation(name, pos->second);
00115             }
00116         } else {
00117             // not found insert new
00118             auto insertedElement = currentUniformData.emplace(make_pair(name, move(value)));
00119             bool didInsert = insertedElement.second;
00120             assert(didInsert);
00121             auto insertedIterator = insertedElement.first;
00122             updateShaderLocation(name, insertedIterator->second);
00123         }
00124     }
00125     
00126     int Material::bind(){
00127         int currentTexture = 0;
00128         for (auto & uniform : currentUniformData) {
00129             auto & materialData = uniform.second;
00130             if (materialData.shaderLocation == -1){
00131                 continue;
00132             }
00133             GLint location = materialData.shaderLocation;
00134             auto & value = materialData.value;
00135             switch (materialData.glType) {
00136                 case GL_FLOAT:
00137                     glUniform1f(location, value.floatValue[0]);
00138                     break;
00139                 case GL_FLOAT_MAT2:
00140                     //glUniformMatrix2fv(location, false, value.mat2Value);
00141 //                    throw invalid_argument();
00142                     logError("GL_FLOAT_MAT2 is currently unsupported");
00143                     break;
00144                 case GL_FLOAT_MAT3:
00145                     glUniformMatrix3fv(location, 1, GL_FALSE, value.floatValue);
00146                     break;
00147                 case GL_FLOAT_MAT4:
00148                     glUniformMatrix4fv(location, 1, GL_FALSE, value.floatValue);
00149                     break;
00150                 case GL_FLOAT_VEC2:
00151                     //glUniform2fv(location, value.vec4Value);
00152 //                    throw invalid_argument("GL_FLOAT_VEC2 is currently unsupported");
00153                     logError("GL_FLOAT_VEC2 is currently unsupported");
00154                     break;
00155                 case GL_FLOAT_VEC3:
00156 //                    throw invalid_argument("GL_FLOAT_VEC3 is currently unsupported");
00157                     logError("GL_FLOAT_VEC3 is currently unsupported");
00158                     break;
00159                 case GL_FLOAT_VEC4:
00160                     glUniform4fv(location, 1, value.floatValue);
00161                     break;
00162                 case GL_INT:
00163                     glUniform1i(location, value.intValue);
00164                     break;
00165                 case GL_INT_VEC2:
00166 //                    throw invalid_argument("GL_INT_VEC2 is currently unsupported");
00167                     logError("GL_INT_VEC2 is currently unsupported");
00168                     break;
00169                 case GL_INT_VEC3:
00170 //                    throw invalid_argument("GL_INT_VEC3 is currently unsupported");
00171                     logError("GL_INT_VEC3 is currently unsupported");
00172                     break;
00173                 case GL_INT_VEC4:
00174 //                    throw invalid_argument("GL_INT_VEC4 is currently unsupported");
00175                     logError("GL_INT_VEC4 is currently unsupported");
00176                     break;
00177                 case GL_SAMPLER_CUBE:
00178                     value.textureCube->bind(currentTexture);
00179                     glUniform1i(location, currentTexture);
00180                     currentTexture++;
00181                     break;
00182                 case GL_SAMPLER_2D:
00183                     value.texture2D->bind(currentTexture);
00184                     glUniform1i(location, currentTexture);
00185                     currentTexture++;
00186                     break;
00187                 default:
00188 //                    throw invalid_argument("Unhandled type");
00189                     logError("Unhandled type");
00190             }
00191         }
00192         return currentTexture;
00193     }
00194     
00195     std::string to_string(MaterialData & data){
00196         auto res = std::string{"MaterialData{ shaderLocation: "}+std::to_string(data.shaderLocation)+" glType: ";
00197         switch (data.glType){
00198             case GL_INT:
00199                 res = res + "GL_INT value: "+std::to_string(data.value.intValue);
00200                 break;
00201             case GL_FLOAT:
00202                 res = res + "GL_FLOAT value: "+std::to_string(data.value.floatValue[0]);
00203                 break;
00204             case GL_FLOAT_VEC4:
00205                 res = res + "GL_FLOAT_VEC4 value: ";
00206                 for (int i=0;i<4;i++){
00207                     res += std::to_string(data.value.floatValue[i]);
00208                 }
00209                 break;
00210             case GL_FLOAT_MAT3:
00211                 res = res + "GL_FLOAT_MAT3 value: ";
00212                 for (int i=0;i<9;i++){
00213                     res += std::to_string(data.value.floatValue[i]);
00214                 }
00215                 break;
00216             case GL_FLOAT_MAT4:
00217                 res = res + "GL_FLOAT_MAT4 value: ";
00218                 for (int i=0;i<16;i++){
00219                     res += std::to_string(data.value.floatValue[i]);
00220                 }
00221                 break;
00222             default:break;
00223                 res = res + "unknown type";
00224                 break;
00225         }
00226         return res;
00227     }
00228 
00229     void Material::setDefaultUniforms() {
00230         vector<string> unmappedOrDefaultUniforms;
00231         for (auto& u : mShader->getShaderUniforms()){
00232             bool isAutoMapped = u.name.length()>0 && u.name[0] == '_';
00233             if (isAutoMapped){
00234                 continue;
00235             }
00236             auto currentValue = currentUniformData.find(u.name);
00237             bool isUnmapped = currentValue == currentUniformData.end();
00238             if (isUnmapped || currentValue->second.defaultUniform){
00239                 unmappedOrDefaultUniforms.push_back(u.name);
00240             }
00241         }
00242         for (auto & name : unmappedOrDefaultUniforms){
00243             MaterialData mat{0};
00244             if (mShader->tryGetDefaultUniform(name, mat)){
00245                 setUniformData(name, move(mat));
00246             }
00247         }
00248     }
00249 
00250     int Material::renderOrder() {
00251         return mRenderOrder;
00252     }
00253 
00254     void Material::setUniform(std::string name, int value) {
00255         setUniformInternal(name, value);
00256     }
00257 
00258     void Material::setUniform(std::string name, float value) {
00259         setUniformInternal(name, value);
00260     }
00261 
00262     void Material::setUniform(std::string name, glm::vec4 value) {
00263         setUniformInternal(name, value);
00264     }
00265 
00266     void Material::setUniform(std::string name, glm::mat3 value) {
00267         setUniformInternal(name, value);
00268     }
00269 
00270     void Material::setUniform(std::string name, glm::mat4 value) {
00271         setUniformInternal(name, value);
00272     }
00273 
00274     void Material::setUniform(std::string name, std::shared_ptr<Texture2D> value) {
00275         texture2DRef[name] = value;
00276         setUniformInternal(name, value.get());
00277     }
00278 
00279     void Material::setUniform(std::string name, std::shared_ptr<TextureCube> value) {
00280         textureCubeRef[name] = value;
00281         setUniformInternal(name, value.get());
00282     }
00283 }
 All Classes Functions Variables