kick
|
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 }