123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641 |
- //
- // CustomMaterial.cpp
- // building
- //
- // Created by yanqian on 2023/5/8.
- //
- #include "CustomMaterial.hpp"
- NS_CC_BEGIN
- // Helpers declaration
- static const char* getOptionalString(Properties* properties, const char* key, const char* defaultValue);
- static bool isValidUniform(const char* name);
- CustomMaterial::CustomMaterial()
- {
- _time = 0;
- _paramFloat.clear();
- _paramVec2.clear();
- _paramVec3.clear();
- _paramVec4.clear();
- _paramMat4.clear();
- _paramString.clear();
- }
- CustomMaterial::~CustomMaterial()
- {
- _paramFloat.clear();
- _paramVec2.clear();
- _paramVec3.clear();
- _paramVec4.clear();
- _paramMat4.clear();
- _paramString.clear();
- }
- CustomMaterial* CustomMaterial::createWithFilename(const std::string& filepath)
- {
- std::string validfilename = FileUtils::getInstance()->fullPathForFilename(filepath);
- if (validfilename.size() > 0) {
- CustomMaterial* mat = new (std::nothrow) CustomMaterial();
- if (mat) {
- mat->setRelativePath(filepath); // 设置材质文件的相对路径
- if (mat->initWithFile(validfilename)) {
- mat->autorelease();
- return mat;
- }
- }
- }
- return nullptr;
- }
- bool CustomMaterial::initWithFile(const std::string& validfilename)
- {
- Properties* properties = Properties::createNonRefCounted(validfilename);
- // 解析材质属性
- parseProperties((strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace());
- CC_SAFE_DELETE(properties);
- return true;
- }
- bool CustomMaterial::parseProperties(Properties* materialProperties)
- {
- setName(materialProperties->getId());
- Properties* space = materialProperties->getNextNamespace();
- while (space) { // 遍历属性对象中的命名空间
- const char* name = space->getNamespace();
- if (strcmp(name, "technique") == 0) {
- parseTechnique(space);
- } else if (strcmp(name, "renderState") == 0) {
- parseRenderState(this, space);
- }
- space = materialProperties->getNextNamespace();
- }
- return true;
- }
- bool CustomMaterial::parseTechnique(Properties* techniqueProperties)
- {
- Technique* technique = Technique::create(this);
- _techniques.pushBack(technique);
- if (!_currentTechnique) {
- _currentTechnique = technique;
- }
- technique->setName(techniqueProperties->getId()); // 设置材质名称
- Properties* space = techniqueProperties->getNextNamespace();
- while (space) { // 遍历technique属性对象中的命名空间
- const char* name = space->getNamespace();
- if (strcmp(name, "pass") == 0) {
- parsePass(technique, space);
- } else if (strcmp(name, "renderState") == 0) {
- parseRenderState(this, space);
- }
- space = techniqueProperties->getNextNamespace();
- }
- return true;
- }
- bool CustomMaterial::parsePass(Technique* technique, Properties* passProperties)
- {
- Pass* pass = Pass::create(technique);
- if (pass == nullptr) {
- return false;
- }
- technique->addPass(pass);
- Properties* space = passProperties->getNextNamespace();
- while (space) { // 遍历pass属性对象中的命名空间
- const char* name = space->getNamespace();
- if (strcmp(name, "shader") == 0) {
- parseShader(pass, space);
- } else if (strcmp(name, "renderState") == 0) {
- parseRenderState(pass, space);
- } else if (strcmp(name, "editorUniforms") == 0) {
- _parseEditorUniform(space);
- } else if (strcmp(name, "uniforms") == 0) {
- _parseUniformParams(pass->getGLProgramState(), space);
- } else {
- CCASSERT(false, "Invalid namespace");
- return false;
- }
- space = passProperties->getNextNamespace();
- }
- return true;
- }
- bool CustomMaterial::parseShader(Pass* pass, Properties* shaderProperties)
- {
- // vertexShader
- const char* vertShader = getOptionalString(shaderProperties, "vertexShader", nullptr);
- // fragmentShader
- const char* fragShader = getOptionalString(shaderProperties, "fragmentShader", nullptr);
- // compileTimeDefines
- const char* compileTimeDefines = getOptionalString(shaderProperties, "defines", "");
- if (vertShader && fragShader)
- {
- auto glProgramState = GLProgramState::getOrCreateWithShaders(_relativePath + vertShader, _relativePath + fragShader, compileTimeDefines);
- pass->setGLProgramState(glProgramState);
- // Parse uniforms only if the GLProgramState was created
- auto property = shaderProperties->getNextProperty();
- while (property)
- {
- if (isValidUniform(property))
- {
- parseUniform(glProgramState, shaderProperties, property);
- }
- property = shaderProperties->getNextProperty();
- }
- auto space = shaderProperties->getNextNamespace();
- while (space)
- {
- const char* name = space->getNamespace();
- if (strcmp(name, "sampler") == 0)
- {
- parseSampler(glProgramState, space);
- }
- space = shaderProperties->getNextNamespace();
- }
- }
- return true;
- }
- bool CustomMaterial::parseRenderState(RenderState* renderState, Properties* properties)
- {
- auto state = renderState->getStateBlock();
- auto property = properties->getNextProperty();
- while (property)
- {
- // Parse uniforms only if the GLProgramState was created
- // Render state only can have "strings" or numbers as values. No new namespaces
- state->setState(property, properties->getString(property));
- std::string value = properties->getString(property);
- if (std::string(property).compare("blend") == 0) {
- if (value.compare("true") == 0) {
- _useBlendFunc = true;
- }
- } else if (std::string(property).compare("blendSrc") == 0) {
- _blendFunc.src = _parseBlend(value);
- } else if (std::string(property).compare("blendDst") == 0) {
- _blendFunc.dst = _parseBlend(value);
- }
- property = properties->getNextProperty();
- }
- return true;
- }
- int CustomMaterial::_parseBlend(const std::string& value)
- {
- std::string upper(value);
- std::transform(upper.begin(), upper.end(), upper.begin(), (int(*)(int))toupper);
- if (upper == "ZERO")
- return GL_ZERO;
- else if (upper == "ONE")
- return GL_ONE;
- else if (upper == "SRC_COLOR")
- return GL_SRC_COLOR;
- else if (upper == "ONE_MINUS_SRC_COLOR")
- return GL_ONE_MINUS_SRC_COLOR;
- else if (upper == "DST_COLOR")
- return GL_DST_COLOR;
- else if (upper == "ONE_MINUS_DST_COLOR")
- return GL_ONE_MINUS_DST_COLOR;
- else if (upper == "SRC_ALPHA")
- return GL_SRC_ALPHA;
- else if (upper == "ONE_MINUS_SRC_ALPHA")
- return GL_ONE_MINUS_SRC_ALPHA;
- else if (upper == "DST_ALPHA")
- return GL_DST_ALPHA;
- else if (upper == "ONE_MINUS_DST_ALPHA")
- return GL_ONE_MINUS_DST_ALPHA;
- else if (upper == "SRC_ALPHA_SATURATE")
- return GL_SRC_ALPHA_SATURATE;
- else
- {
- CCLOG("Unsupported blend value (%s). (Will default to BLEND_ONE if errors are treated as warnings)", value.c_str());
- return RenderState::BLEND_ONE;
- }
- }
- bool CustomMaterial::parseSampler(GLProgramState* glProgramState, Properties* samplerProperties)
- {
- CCASSERT(samplerProperties->getId(), "Sampler must have an id. The id is the uniform name");
- if (glProgramState == nullptr || samplerProperties == nullptr) {
- return false;
- }
- // required
- bool canBeEdit = samplerProperties->getBool("editorTexture");
- const char* filename = samplerProperties->getString("path");
- filename = (filename == nullptr) ? "" : filename;
- std::string filePath = (canBeEdit == false) ? _relativePath + filename : filename;
-
- Texture2D* texture = nullptr;
- Vec2 texRectOffset, texRectSize;
- // 先从图集里找
- SpriteFrame *spriteFrame = SpriteFrameCache::getInstance()->getSpriteFrameByName(filename);
-
- if (spriteFrame != nullptr) {
- texture = spriteFrame->getTexture();
- // 计算纹理的偏移和大小
- Rect rect = spriteFrame->getRectInPixels();
- Size atlasSize = spriteFrame->getTexture()->getContentSizeInPixels();
- texRectOffset = Vec2(rect.origin.x / atlasSize.width, rect.origin.y / atlasSize.height);
- texRectSize = Vec2(rect.size.width / atlasSize.width, rect.size.height / atlasSize.height);
- } else {
- texture = Director::getInstance()->getTextureCache()->addImage(filePath);
- texRectOffset = Vec2(0, 0);
- texRectSize = Vec2(1, 1);
- }
-
- Texture2D::TexParams texParams;
- // mipmap
- bool usemipmap = false;
- const char* mipmap = getOptionalString(samplerProperties, "mipmap", "false");
- if (mipmap && strcasecmp(mipmap, "true")==0) {
- usemipmap = true;
- }
- // valid options: REPEAT, CLAMP
- const char* wrapS = getOptionalString(samplerProperties, "wrapS", "CLAMP_TO_EDGE");
- if (strcasecmp(wrapS, "REPEAT")==0)
- texParams.wrapS = GL_REPEAT;
- else if(strcasecmp(wrapS, "CLAMP_TO_EDGE")==0)
- texParams.wrapS = GL_CLAMP_TO_EDGE;
- else
- CCLOG("Invalid wrapS: %s", wrapS);
- // valid options: REPEAT, CLAMP
- const char* wrapT = getOptionalString(samplerProperties, "wrapT", "CLAMP_TO_EDGE");
- if (strcasecmp(wrapT, "REPEAT")==0)
- texParams.wrapT = GL_REPEAT;
- else if(strcasecmp(wrapT, "CLAMP_TO_EDGE")==0)
- texParams.wrapT = GL_CLAMP_TO_EDGE;
- else
- CCLOG("Invalid wrapT: %s", wrapT);
- // valid options: NEAREST, LINEAR, NEAREST_MIPMAP_NEAREST, LINEAR_MIPMAP_NEAREST, NEAREST_MIPMAP_LINEAR, LINEAR_MIPMAP_LINEAR
- const char* minFilter = getOptionalString(samplerProperties, "minFilter", usemipmap ? "LINEAR_MIPMAP_NEAREST" : "LINEAR");
- if (strcasecmp(minFilter, "NEAREST")==0)
- texParams.minFilter = GL_NEAREST;
- else if(strcasecmp(minFilter, "LINEAR")==0)
- texParams.minFilter = GL_LINEAR;
- else if(strcasecmp(minFilter, "NEAREST_MIPMAP_NEAREST")==0)
- texParams.minFilter = GL_NEAREST_MIPMAP_NEAREST;
- else if(strcasecmp(minFilter, "LINEAR_MIPMAP_NEAREST")==0)
- texParams.minFilter = GL_LINEAR_MIPMAP_NEAREST;
- else if(strcasecmp(minFilter, "NEAREST_MIPMAP_LINEAR")==0)
- texParams.minFilter = GL_NEAREST_MIPMAP_LINEAR;
- else if(strcasecmp(minFilter, "LINEAR_MIPMAP_LINEAR")==0)
- texParams.minFilter = GL_LINEAR_MIPMAP_LINEAR;
- else
- CCLOG("Invalid minFilter: %s", minFilter);
- // valid options: NEAREST, LINEAR
- const char* magFilter = getOptionalString(samplerProperties, "magFilter", "LINEAR");
- if (strcasecmp(magFilter, "NEAREST")==0)
- texParams.magFilter = GL_NEAREST;
- else if(strcasecmp(magFilter, "LINEAR")==0)
- texParams.magFilter = GL_LINEAR;
- else
- CCLOG("Invalid magFilter: %s", magFilter);
-
- if (texture) {
- if (usemipmap == true) {
- texture->generateMipmap();
- }
- texture->setTexParameters(texParams);
- glProgramState->setUniformTexture(samplerProperties->getId(), texture);
- glProgramState->setUniformVec2("u_texRectOffset", texRectOffset);
- glProgramState->setUniformVec2("u_texRectSize", texRectSize);
- }
-
- if (canBeEdit) {
- _paramTexture.push_back(UniformParamTexture(samplerProperties->getId(), texParams));
- }
-
- return true;
- }
- bool CustomMaterial::_parseEditorUniform(Properties* paramsProperties)
- {
- const char* property = paramsProperties->getNextProperty();
- while (property) {
- _editorUniforms[property] = paramsProperties->getBool(property);
- property = paramsProperties->getNextProperty();
- }
- return true;
- }
- bool CustomMaterial::_parseUniformParams(GLProgramState* programState, Properties* paramsProperties)
- {
- if (programState == nullptr || paramsProperties == nullptr) {
- return false;
- }
- const char* property = paramsProperties->getNextProperty();
- while (property) { // 遍历所有属性变量
- Properties::Type type = paramsProperties->getType(property);
- switch (type) {
- case Properties::Type::NUMBER: {
- float f = paramsProperties->getFloat(property);
- programState->setUniformFloat(property, f);
- if (_editorUniforms[property] == true) {
- _paramFloat.push_back(UniformParamFloat(property, f));
- }
- break;
- }
-
- case Properties::Type::VECTOR2: {
- Vec2 v2;
- paramsProperties->getVec2(property, &v2);
- programState->setUniformVec2(property, v2);
- if (_editorUniforms[property] == true) {
- _paramVec2.push_back(UniformParamVec2(property, v2));
- }
- break;
- }
-
- case Properties::Type::VECTOR3: {
- Vec3 v3;
- paramsProperties->getVec3(property, &v3);
- programState->setUniformVec3(property, v3);
- if (_editorUniforms[property] == true) {
- _paramVec3.push_back(UniformParamVec3(property, v3));
- }
- break;
- }
-
- case Properties::Type::VECTOR4: {
- Vec4 v4;
- paramsProperties->getVec4(property, &v4);
- programState->setUniformVec4(property, v4);
- if (_editorUniforms[property] == true) {
- _paramVec4.push_back(UniformParamVec4(property, v4));
- }
- break;
- }
-
- case Properties::Type::MATRIX: {
- Mat4 m4;
- paramsProperties->getMat4(property, &m4);
- programState->setUniformMat4(property, m4);
- if (_editorUniforms[property] == true) {
- _paramMat4.push_back(UniformParamMat4(property, m4));
- }
- break;
- }
-
- case Properties::Type::STRING: {
- programState->setParameterAutoBinding(property, paramsProperties->getString());
- if (_editorUniforms[property] == true) {
- _paramString.push_back(UniformParamString(property, paramsProperties->getString()));
- }
- break;
- }
-
- default:
- CCASSERT(false, "未知uniform变量类型");
- break;
- }
- property = paramsProperties->getNextProperty();
- }
- return true;
- }
- void CustomMaterial::updateUniformTime(float delta)
- {
- // 累加time
- _time += delta;
- if (_time >= 10000) {
- _time = 0;
- }
-
- // 对每个pass中包含u_time的uniform进行参数更新
- for (auto technique : getTechniques()) {
- for (auto pass : technique->getPasses()) {
- auto glProgramState = pass->getGLProgramState();
- if (glProgramState != nullptr && glProgramState->getGLProgram()->getUniformLocation("u_time") != -1) {
- glProgramState->setUniformFloat("u_time", _time);
- }
- }
- }
- }
- const std::vector<UniformParamFloat> CustomMaterial::getParamsFloat()
- {
- return _paramFloat;
- }
- const std::vector<UniformParamVec2> CustomMaterial::getParamsVec2()
- {
- return _paramVec2;
- }
- const std::vector<UniformParamVec3> CustomMaterial::getParamsVec3()
- {
- return _paramVec3;
- }
- const std::vector<UniformParamVec4> CustomMaterial::getParamsVec4()
- {
- return _paramVec4;
- }
- const std::vector<UniformParamMat4> CustomMaterial::getParamsMat4()
- {
- return _paramMat4;
- }
- const std::vector<UniformParamString> CustomMaterial::getParamsString()
- {
- return _paramString;
- }
- void CustomMaterial::setParamFloat(std::string name, float value)
- {
- for (auto ¶m : _paramFloat) {
- if (param.name == name) {
- param.value = value;
- }
- }
- GLProgramState* programState = _getGLProgramState();
- if (programState) {
- programState->setUniformFloat(name, value);
- }
- }
- void CustomMaterial::setParamsVec2(std::string name, Vec2 value)
- {
- for (auto ¶m : _paramVec2) {
- if (param.name == name) {
- param.value = value;
- }
- }
- GLProgramState* programState = _getGLProgramState();
- if (programState) {
- programState->setUniformVec2(name, value);
- }
- }
- void CustomMaterial::setParamsVec3(std::string name, Vec3 value)
- {
- for (auto ¶m : _paramVec3) {
- if (param.name == name) {
- param.value = value;
- }
- }
- GLProgramState* programState = _getGLProgramState();
- if (programState) {
- programState->setUniformVec3(name, value);
- }
- }
- void CustomMaterial::setParamsVec4(std::string name, Vec4 value)
- {
- for (auto ¶m : _paramVec4) {
- if (param.name == name) {
- param.value = value;
- }
- }
- GLProgramState* programState = _getGLProgramState();
- if (programState) {
- programState->setUniformVec4(name, value);
- }
- }
- void CustomMaterial::setParamsMat4(std::string name, Mat4 value)
- {
- for (auto ¶m : _paramMat4) {
- if (param.name == name) {
- param.value = value;
- }
- }
- GLProgramState* programState = _getGLProgramState();
- if (programState) {
- programState->setUniformMat4(name, value);
- }
- }
- void CustomMaterial::setParamsString(std::string name, std::string value)
- {
- for (auto ¶m : _paramString) {
- if (param.name == name) {
- param.value = value;
- }
- }
-
- GLProgramState* programState = _getGLProgramState();
- if (programState) {
- programState->setParameterAutoBinding(name, value);
- }
- }
- void CustomMaterial::setParamsTexture(SpriteFrame* spriteFrame)
- {
- GLProgramState* programState = _getGLProgramState();
- if (programState == nullptr || spriteFrame == nullptr) {
- return;
- }
- Texture2D* texture = spriteFrame->getTexture();
- Vec2 texRectOffset, texRectSize;
-
- // 计算纹理的偏移和大小
- Rect rect = spriteFrame->getRectInPixels();
- Size atlasSize = spriteFrame->getTexture()->getContentSizeInPixels();
- texRectOffset = Vec2(rect.origin.x / atlasSize.width, rect.origin.y / atlasSize.height);
- texRectSize = Vec2(rect.size.width / atlasSize.width, rect.size.height / atlasSize.height);
-
- for (auto ¶m : _paramTexture) {
- texture->setTexParameters(param.texParams);
- programState->setUniformTexture(param.name, texture);
- programState->setUniformVec2("u_texRectOffset", texRectOffset);
- programState->setUniformVec2("u_texRectSize", texRectSize);
- }
- }
- GLProgramState* CustomMaterial::_getGLProgramState()
- {
- if (getTechniques().at(0) && getTechniques().at(0)->getPasses().at(0)) {
- return getTechniques().at(0)->getPasses().at(0)->getGLProgramState();
- }
- return nullptr;
- }
- void CustomMaterial::setRelativePath(std::string relativePath)
- {
- auto found = relativePath.find_last_of("/\\");
- if (found != std::string::npos) {
- _relativePath = relativePath.substr(0, found + 1);
- } else {
- _relativePath = "";
- }
- }
- bool CustomMaterial::useBlendFunc()
- {
- return _useBlendFunc;
- }
- BlendFunc CustomMaterial::getBlendFunc()
- {
- return _blendFunc;
- }
- std::string CustomMaterial::getRelativePath()
- {
- return _relativePath;
- }
- void CustomMaterial::setMaterialPath(std::string materialPath)
- {
- _materialPath = materialPath;
- }
- std::string CustomMaterial::getMaterialPath()
- {
- return _materialPath;
- }
- static bool isValidUniform(const char* name)
- {
- return !(strcmp(name, "defines")==0 ||
- strcmp(name, "vertexShader")==0 ||
- strcmp(name, "fragmentShader")==0);
- }
- static const char* getOptionalString(Properties* properties, const char* key, const char* defaultValue)
- {
- const char* ret = properties->getString(key);
- if (!ret)
- ret = defaultValue;
- return ret;
- }
- NS_CC_END
|