diff -r 2a156cb51479 -r 4cbd9c0beb4c Shark.cpp --- a/Shark.cpp Tue Dec 26 15:41:07 2023 +0100 +++ b/Shark.cpp Tue Dec 26 23:46:45 2023 +0100 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,7 @@ GLint uView = -2; GLint uProjection = -2; GLint uTexture = -2; + GLint uTextureScale = -2; } ProgAttr; struct { @@ -185,7 +187,8 @@ void parametrizeTexture(std::shared_ptr tex); bool reloadTexture(const std::string& fileName); void loadTextures(); - std::shared_ptr loadShaders(); + void loadShaders(); + void updateVariableLocations(); bool reloadShader(const std::string& fileName); void setTitle(const std::string& suffix = ""); static const std::string getDefaultFile(const std::string& relativePath); @@ -269,7 +272,7 @@ // Load GLSL shaders: - shaderProgram = loadShaders(); + loadShaders(); loadTextures(); loadVertices(); @@ -468,6 +471,9 @@ glm::mat4 model = glm::mat4(1.0f); // identity matrix glUniformMatrix4fv(ProgAttr.uModel, 1, GL_FALSE, &model[0][0]); + // TODO: draw a rectangle for each texture + glUniform1f(ProgAttr.uTextureScale, textures[0]->getScale()); + glDrawArrays(GL_TRIANGLES, 0, 2 * 3); // see loadVertices() std::cerr << "GLSL: glDrawArrays()" << std::endl; } @@ -546,8 +552,7 @@ XAttrs xa(tex->getFileName()); std::string magf = xa["shader-shark.texture.mag-filter"]; std::string minf = xa["shader-shark.texture.min-filter"]; - // TODO: std::string scale = xa["shader-shark.texture.scale"]; - // TODO: keep MappedFile locked until we read the attributes + std::string scale = xa["shader-shark.texture.scale"]; auto GLT2D = GL_TEXTURE_2D; auto MAG = GL_TEXTURE_MAG_FILTER; @@ -558,6 +563,14 @@ if (minf == "linear") glTexParameteri(GLT2D, MIN, GL_LINEAR); else if (minf == "nearest") glTexParameteri(GLT2D, MIN, GL_NEAREST); + + if (scale.size()) { + float sc; + if (std::from_chars(scale.data(), scale.data() + scale.size(), sc).ec + == std::errc{}) tex->setScale(sc); + else std::cerr << "Invalid texture scale value - expecting float\n"; + // tex->setScale(std::stof(scale)); // locale-dependent (. vs ,) + } } void Shark::Impl::loadTextures() { @@ -595,82 +608,77 @@ return false; } -std::shared_ptr Shark::Impl::loadShaders() { - try { - // Vertex Array Object (VAO) - GLuint vao; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - // VAO - something like context for bound data/variables - // We can switch multiple VAOs. VAO can contain multiple VBOs. - // what-are-vertex-array-objects +void Shark::Impl::loadShaders() { + // Vertex Array Object (VAO) + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + // VAO - something like context for bound data/variables + // We can switch multiple VAOs. VAO can contain multiple VBOs. + // what-are-vertex-array-objects - // Vertex Buffer Object (VBO): - GLuint vbo; - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); + // Vertex Buffer Object (VBO): + GLuint vbo; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); - { - // Load default shaders if there are no configured: - int vc = 0; - int fc = 0; - auto& ss = cfg.shaders; - for (const auto& s : ss) if (s.type == "vertex") vc++; - for (const auto& s : ss) if (s.type == "fragment") fc++; - auto& d = getDefaultFile; - if (vc == 0) ss.push_back({d("shaders/default.vert"), "vertex"}); - if (fc == 0) ss.push_back({d("shaders/default.frag"), "fragment"}); - } + { + // Load default shaders if there are no configured: + int vc = 0; + int fc = 0; + auto& ss = cfg.shaders; + for (const auto& s : ss) if (s.type == "vertex") vc++; + for (const auto& s : ss) if (s.type == "fragment") fc++; + auto& d = getDefaultFile; + if (vc == 0) ss.push_back({d("shaders/default.vert"), "vertex"}); + if (fc == 0) ss.push_back({d("shaders/default.frag"), "fragment"}); + } - std::shared_ptr program = std::make_shared(); + shaderProgram = std::make_shared(); - // glBindFragDataLocation(program, 0, "outColor"); - // glBindAttribLocation(program, LOC.input, "vertices"); + // glBindFragDataLocation(program, 0, "outColor"); + // glBindAttribLocation(program, LOC.input, "vertices"); - for (const Configuration::Shader definition : cfg.shaders) { - Shader::Type type; - std::string fileName = definition.fileName; - if (definition.type == "fragment") type = Shader::Type::FRAGMENT; - else if (definition.type == "vertex") type = Shader::Type::VERTEX; - else throw std::invalid_argument("unsupported shader type"); + for (const Configuration::Shader definition : cfg.shaders) { + Shader::Type type; + std::string fileName = definition.fileName; + if (definition.type == "fragment") type = Shader::Type::FRAGMENT; + else if (definition.type == "vertex") type = Shader::Type::VERTEX; + else throw std::invalid_argument("unsupported shader type"); - MappedFile file(fileName); - std::shared_ptr shader = std::make_shared( - type, file, fileName); + MappedFile file(fileName); + std::shared_ptr shader = std::make_shared( + type, file, fileName); - program->attachShader(*shader.get()); - shaders.push_back(shader); - watchedFiles.push_back(fileMonitor.watch(fileName)); - std::cerr << "GLSL loaded: " << fileName.c_str() << std::endl; - // We may detach and delete shaders, - // but our shaders are small, so we keep them for later reloading. - } + shaderProgram->attachShader(*shader.get()); + shaders.push_back(shader); + watchedFiles.push_back(fileMonitor.watch(fileName)); + std::cerr << "GLSL loaded: " << fileName.c_str() << std::endl; + // We may detach and delete shaders, + // but our shaders are small, so we keep them for later reloading. + } - // GLSL compiler does very efficient / aggressive optimization. - // Attributes and uniforms that are not used in the shader are deleted. - // And even if we e.g. read color from a texture and overwrite it, - // the variable is still deleted and considered „inactive“. - // Functions glGetAttribLocation() and glGetUniformLocation() return -1. - - program->link(); + shaderProgram->link(); + updateVariableLocations(); + // listVariables(program); + std::cerr << "GLSL shader count: " << shaders.size() << std::endl; +} - ProgAttr.aVertexXYZ = program->getAttribLocation("aVertexXYZ"); - ProgAttr.aTextureXY = program->getAttribLocation("aTextureXY"); - ProgAttr.uModel = program->getUniformLocation("uModel"); - ProgAttr.uView = program->getUniformLocation("uView"); - ProgAttr.uProjection = program->getUniformLocation("uProjection"); - ProgAttr.uTexture = program->getUniformLocation("uTexture"); - ProgAttr.fColor = program->getFragDataLocation("fColor"); - program->bindFragDataLocation("fColor", ProgAttr.fColor); - // listVariables(program); - std::cerr << "GLSL shader count: " << shaders.size() << std::endl; - return program; - } catch (const std::exception& e) { - std::cerr << "Error while loading shaders: " << e.what() << std::endl; - } catch (...) { - std::cerr << "Error while loading shaders: unknown" << std::endl; - } - throw std::logic_error("GLSL: loadShaders() failed"); +void Shark::Impl::updateVariableLocations() { + // GLSL compiler does very efficient / aggressive optimization. + // Attributes and uniforms that are not used in the shader are deleted. + // And even if we e.g. read color from a texture and overwrite it, + // the variable is still deleted and considered „inactive“. + // Functions glGetAttribLocation() and glGetUniformLocation() return -1. + ProgAttr.aVertexXYZ = shaderProgram->getAttribLocation("aVertexXYZ"); + ProgAttr.aTextureXY = shaderProgram->getAttribLocation("aTextureXY"); + ProgAttr.uModel = shaderProgram->getUniformLocation("uModel"); + ProgAttr.uView = shaderProgram->getUniformLocation("uView"); + ProgAttr.uProjection = shaderProgram->getUniformLocation("uProjection"); + ProgAttr.uTexture = shaderProgram->getUniformLocation("uTexture"); + ProgAttr.uTextureScale = shaderProgram->getUniformLocation("uTextureScale"); + ProgAttr.fColor = shaderProgram->getFragDataLocation("fColor"); + shaderProgram->bindFragDataLocation("fColor", ProgAttr.fColor); } bool Shark::Impl::reloadShader(const std::string& fileName) { @@ -678,6 +686,7 @@ if (shader->getFileName() == fileName) { shader->update(MappedFile(fileName)); shaderProgram->link(); + updateVariableLocations(); return true; } }