diff --git a/Projects/Skylicht/Engine/Source/Material/CMaterial.cpp b/Projects/Skylicht/Engine/Source/Material/CMaterial.cpp index dbf1cbdd1..61f04e023 100644 --- a/Projects/Skylicht/Engine/Source/Material/CMaterial.cpp +++ b/Projects/Skylicht/Engine/Source/Material/CMaterial.cpp @@ -50,7 +50,7 @@ namespace Skylicht m_textures[i] = NULL; } - for (int i = 0; i < CShader::RResourceCount; i++) + for (int i = 0; i < CShader::ResourceCount; i++) m_overrideTextures[i] = NULL; initMaterial(); @@ -68,6 +68,7 @@ namespace Skylicht } deleteAllParams(); + deleteExtramParams(); clearAllAffectMesh(); } @@ -118,6 +119,24 @@ namespace Skylicht m_uniformTextures.clear(); } + void CMaterial::deleteExtramParams() + { + for (SExtraParams *&e : m_extras) + { + for (SUniformValue *&uniform : e->UniformParams) + delete uniform; + e->UniformParams.clear(); + + for (SUniformTexture *&uniform : e->UniformTextures) + delete uniform; + e->UniformTextures.clear(); + + delete e; + } + + m_extras.clear(); + } + void CMaterial::setUniform(const char *name, float f) { SUniformValue* p = getUniform(name); @@ -392,19 +411,19 @@ namespace Skylicht } else { - if (r->Type == CShader::RTexture) + if (r->Type == CShader::Texture) { texture = textureManager->getTexture(r->Path.c_str()); } - else if (r->Type == CShader::RCubeTexture) + else if (r->Type == CShader::CubeTexture) { } - else if (r->Type == CShader::RStaticCubeTexture) + else if (r->Type == CShader::StaticCubeTexture) { } - else if (r->Type == CShader::RShadowMapTexture) + else if (r->Type == CShader::ShadowMapTexture) { } @@ -488,6 +507,8 @@ namespace Skylicht } } + // PUBLIC FOR USE + void CMaterial::applyMaterial(SMaterial& mat) { loadDefaultTexture(); @@ -517,6 +538,59 @@ namespace Skylicht } } + void CMaterial::changeShader(CShader *shader) + { + // save current shader params + saveExtraParams(); + + // new shader path + m_shaderPath = shader->getShaderPath(); + + // init default params + initMaterial(); + + // try load from extra params + reloadExtraParams(m_shaderPath.c_str()); + } + + void CMaterial::changeShader(const char *path) + { + CShaderManager *shaderManager = CShaderManager::getInstance(); + CShader* shader = shaderManager->getShaderByPath(path); + if (shader != NULL) + { + changeShader(shader); + } + else + { + // try load shader + CShader *shader = shaderManager->loadShader(path); + if (shader != NULL) + { + changeShader(shader); + } + } + } + + void CMaterial::autoDetectLoadTexture() + { + CShaderManager *shaderManager = CShaderManager::getInstance(); + CShader* shader = shaderManager->getShaderByPath(m_shaderPath.c_str()); + if (shader != NULL) + { + for (SUniformTexture *texture : m_uniformTextures) + { + CShader::SUniformUI* ui = shader->getUniformUIByName(texture->Name.c_str()); + + // need try to fill and load texture + if (ui != NULL && texture->Texture == NULL) + { + + } + } + } + } + // PRIVATE & PROTECTED void CMaterial::initDefaultValue() @@ -788,4 +862,144 @@ namespace Skylicht v->ShaderDefaultValue = true; } + + CMaterial::SExtraParams* CMaterial::getExtraParams(const char *shaderPath) + { + for (SExtraParams* e : m_extras) + { + if (e->ShaderPath == shaderPath) + return e; + } + + return NULL; + } + + void CMaterial::saveExtraParams() + { + // get or create extra + SExtraParams *e = getExtraParams(m_shaderPath.c_str()); + if (e == NULL) + { + e = new SExtraParams(); + e->ShaderPath = m_shaderPath; + m_extras.push_back(e); + } + + // clear old params + for (SUniformValue *&uniform : e->UniformParams) + delete uniform; + e->UniformParams.clear(); + + for (SUniformTexture *&uniform : e->UniformTextures) + delete uniform; + e->UniformTextures.clear(); + + // add current params + for (SUniformTexture *&t : m_uniformTextures) + { + e->UniformTextures.push_back(t->clone()); + } + + for (SUniformValue *&v : m_uniformParams) + { + e->UniformParams.push_back(v->clone()); + } + } + + void CMaterial::reloadExtraParams(const char *shaderPath) + { + SExtraParams *e = getExtraParams(m_shaderPath.c_str()); + if (e == NULL) + { + // no extra data + // try find in same shader params + for (SUniformTexture *&t : m_uniformTextures) + { + if (t->Texture != NULL) + continue; + + SUniformTexture *uniform = findExtraTexture(t->Name.c_str()); + if (uniform != NULL) + { + t->Path = uniform->Path; + t->Texture = uniform->Texture; + break; + } + } + + for (SUniformValue *&v : m_uniformParams) + { + SUniformValue *uniform = findExtraParam(v->Name.c_str(), v->FloatSize); + if (uniform != NULL) + { + v->FloatValue[0] = uniform->FloatValue[0]; + v->FloatValue[1] = uniform->FloatValue[1]; + v->FloatValue[2] = uniform->FloatValue[2]; + v->FloatValue[3] = uniform->FloatValue[3]; + break; + } + } + + return; + } + + for (SUniformTexture *&t : m_uniformTextures) + { + if (t->Texture != NULL) + continue; + + for (SUniformTexture *&uniform : e->UniformTextures) + { + if (t->Name == uniform->Name) + { + t->Path = uniform->Path; + t->Texture = uniform->Texture; + break; + } + } + } + + for (SUniformValue *&v : m_uniformParams) + { + for (SUniformValue *&uniform : e->UniformParams) + { + if (v->Name == uniform->Name && v->FloatSize == uniform->FloatSize) + { + v->FloatValue[0] = uniform->FloatValue[0]; + v->FloatValue[1] = uniform->FloatValue[1]; + v->FloatValue[2] = uniform->FloatValue[2]; + v->FloatValue[3] = uniform->FloatValue[3]; + break; + } + } + } + } + + CMaterial::SUniformTexture *CMaterial::findExtraTexture(const char *name) + { + for (SExtraParams* e : m_extras) + { + for (CMaterial::SUniformTexture *t : e->UniformTextures) + { + if (t->Name == name && t->Texture != NULL) + return t; + } + } + + return NULL; + } + + CMaterial::SUniformValue *CMaterial::findExtraParam(const char *name, int floatSize) + { + for (SExtraParams* e : m_extras) + { + for (CMaterial::SUniformValue *v : e->UniformParams) + { + if (v->Name == name && v->FloatSize == floatSize) + return v; + } + } + + return NULL; + } } \ No newline at end of file diff --git a/Projects/Skylicht/Engine/Source/Material/CMaterial.h b/Projects/Skylicht/Engine/Source/Material/CMaterial.h index 97e220e66..923de696f 100644 --- a/Projects/Skylicht/Engine/Source/Material/CMaterial.h +++ b/Projects/Skylicht/Engine/Source/Material/CMaterial.h @@ -80,6 +80,13 @@ namespace Skylicht } }; + struct SExtraParams + { + std::string ShaderPath; + std::vector UniformParams; + std::vector UniformTextures; + }; + private: CShaderParams m_shaderParams; @@ -91,9 +98,11 @@ namespace Skylicht std::vector m_meshBuffers; + std::vector m_extras; + ITexture *m_resourceTexture[MATERIAL_MAX_TEXTURES]; ITexture *m_textures[MATERIAL_MAX_TEXTURES]; - ITexture *m_overrideTextures[CShader::RResourceCount]; + ITexture *m_overrideTextures[CShader::ResourceCount]; video::E_COMPARISON_FUNC m_zBuffer; bool m_zWriteEnable; @@ -121,9 +130,15 @@ namespace Skylicht return m_materialName.c_str(); } + inline const char* getShaderPath() + { + return m_shaderPath.c_str(); + } + CMaterial* clone(CGameObject *gameObject); void deleteAllParams(); + void deleteExtramParams(); void setUniform(const char *name, float f); void setUniform2(const char *name, float *f); @@ -135,6 +150,21 @@ namespace Skylicht void setUniformTexture(const char *name, const char *path, std::vector& folder, bool loadTexture = true); void setUniformTexture(const char *name, ITexture *texture); + inline std::vector& getUniformParams() + { + return m_uniformParams; + } + + inline std::vector& getUniformTexture() + { + return m_uniformTextures; + } + + inline std::vector& getExtraParams() + { + return m_extras; + } + SUniformValue* getUniform(const char *name); SUniformTexture* getUniformTexture(const char *name); @@ -166,11 +196,18 @@ namespace Skylicht public: + void changeShader(CShader *shader); + + void changeShader(const char *path); + + void autoDetectLoadTexture(); + void applyMaterial(); void applyMaterial(SMaterial& mat); protected: + void initDefaultValue(); void updateTexture(SMaterial& mat); @@ -186,6 +223,16 @@ namespace Skylicht SUniformTexture *newUniformTexture(const char *name); void addShaderUI(CShader::SUniformUI* ui); + + SExtraParams* getExtraParams(const char *shaderPath); + + void saveExtraParams(); + + void reloadExtraParams(const char *shaderPath); + + SUniformTexture *findExtraTexture(const char *name); + + SUniformValue *findExtraParam(const char *name, int floatSize); }; typedef std::vector ArrayMaterial; diff --git a/Projects/Skylicht/Engine/Source/Material/CMaterialManager.cpp b/Projects/Skylicht/Engine/Source/Material/CMaterialManager.cpp index a928da3d5..9572e42df 100644 --- a/Projects/Skylicht/Engine/Source/Material/CMaterialManager.cpp +++ b/Projects/Skylicht/Engine/Source/Material/CMaterialManager.cpp @@ -195,11 +195,118 @@ namespace Skylicht return result; } - void CMaterialManager::exportMaterial(CEntityPrefab *prefab, const char *folder, const char *filename) + void CMaterialManager::saveMaterial(ArrayMaterial &materials, const char *filename) { - std::string matFile = folder; - matFile += "/"; - matFile += filename; + std::string matFile = filename; + + IrrlichtDevice *device = getIrrlichtDevice(); + io::IFileSystem *fs = device->getFileSystem(); + + io::IWriteFile *writeFile = fs->createAndWriteFile(matFile.c_str()); + if (writeFile == NULL) + return; + + std::string buffer; + std::map saved; + + char data[1024]; + + buffer += "\n"; + + for (CMaterial *material : materials) + { + sprintf(data, "\t\n", material->getName(), material->getShaderPath()); + buffer += data; + + std::vector& textures = material->getUniformTexture(); + std::vector& params = material->getUniformParams(); + std::vector& extras = material->getExtraParams(); + + if (textures.size() > 0) + { + // write uniform texture + buffer += "\t\t\n"; + for (CMaterial::SUniformTexture* texture : textures) + { + sprintf(data, "\t\t\t\n", texture->Name.c_str(), texture->Path.c_str()); + buffer += data; + } + buffer += "\t\t\n"; + } + + if (params.size() > 0) + { + // write uniform value + buffer += "\t\t\n"; + for (CMaterial::SUniformValue* param : params) + { + sprintf(data, "\t\t\t\n", + param->Name.c_str(), + param->FloatSize, + param->FloatValue[0], + param->FloatValue[1], + param->FloatValue[2], + param->FloatValue[3]); + buffer += data; + } + buffer += "\t\t\n"; + } + + // write extra data + if (extras.size() > 0) + { + buffer += "\t\t\n"; + for (CMaterial::SExtraParams* e : extras) + { + sprintf(data, "\t\t\t\n", e->ShaderPath.c_str()); + buffer += data; + + if (e->UniformTextures.size() > 0) + { + // write uniform texture + buffer += "\t\t\t\t\n"; + for (CMaterial::SUniformTexture* texture : e->UniformTextures) + { + sprintf(data, "\t\t\t\t\t\n", texture->Name.c_str(), texture->Path.c_str()); + buffer += data; + } + buffer += "\t\t\t\t\n"; + } + + if (e->UniformParams.size() > 0) + { + // write uniform value + buffer += "\t\t\t\t\n"; + for (CMaterial::SUniformValue* param : e->UniformParams) + { + sprintf(data, "\t\t\t\t\t\n", + param->Name.c_str(), + param->FloatSize, + param->FloatValue[0], + param->FloatValue[1], + param->FloatValue[2], + param->FloatValue[3]); + buffer += data; + } + buffer += "\t\t\t\t\n"; + } + + buffer += "\t\t\t\n"; + } + buffer += "\t\t\n"; + } + + buffer += "\t\n"; + } + + buffer += ""; + writeFile->write(buffer.c_str(), buffer.size()); + writeFile->drop(); + } + + void CMaterialManager::exportMaterial(CEntityPrefab *prefab, const char *filename) + { + std::string matFile = filename; IrrlichtDevice *device = getIrrlichtDevice(); io::IFileSystem *fs = device->getFileSystem(); diff --git a/Projects/Skylicht/Engine/Source/Material/CMaterialManager.h b/Projects/Skylicht/Engine/Source/Material/CMaterialManager.h index 79a181319..a6e5d8180 100644 --- a/Projects/Skylicht/Engine/Source/Material/CMaterialManager.h +++ b/Projects/Skylicht/Engine/Source/Material/CMaterialManager.h @@ -44,6 +44,8 @@ namespace Skylicht ArrayMaterial& loadMaterial(const char *filename, bool loadTexture, std::vector& textureFolders); - void exportMaterial(CEntityPrefab *prefab, const char *folder, const char *filename); + void saveMaterial(ArrayMaterial &materials, const char *filename); + + void exportMaterial(CEntityPrefab *prefab, const char *filename); }; } \ No newline at end of file diff --git a/Projects/Skylicht/Engine/Source/Material/Shader/CShader.cpp b/Projects/Skylicht/Engine/Source/Material/Shader/CShader.cpp index 7e39823d3..336c947d5 100644 --- a/Projects/Skylicht/Engine/Source/Material/Shader/CShader.cpp +++ b/Projects/Skylicht/Engine/Source/Material/Shader/CShader.cpp @@ -185,7 +185,7 @@ namespace Skylicht if (wtext != NULL) { CStringImp::convertUnicodeToUTF8(wtext, text); - uniform->AutoReplace = text; + CStringImp::splitString(text, ";", uniform->AutoReplace); } wtext = xmlReader->getAttributeValue(L"step"); @@ -274,7 +274,7 @@ namespace Skylicht "ShadowMapTexture" }; - for (u32 i = 0, n = RResourceCount; i < n; i++) + for (u32 i = 0, n = ResourceCount; i < n; i++) { if (CStringImp::comp(text, type[i]) == 0) { diff --git a/Projects/Skylicht/Engine/Source/Material/Shader/CShader.h b/Projects/Skylicht/Engine/Source/Material/Shader/CShader.h index 8dfaa9fa4..090246760 100644 --- a/Projects/Skylicht/Engine/Source/Material/Shader/CShader.h +++ b/Projects/Skylicht/Engine/Source/Material/Shader/CShader.h @@ -138,18 +138,18 @@ namespace Skylicht enum EResourceType { - RTexture = 0, - RCubeTexture, - RStaticCubeTexture, - RShadowMapTexture, - RResourceCount + Texture = 0, + CubeTexture, + StaticCubeTexture, + ShadowMapTexture, + ResourceCount }; struct SUniformUI { EUIControlType ControlType; std::string Name; - std::string AutoReplace; + std::vector AutoReplace; int SliderStep; SUniform *UniformInfo;