pass texture xattr 'shader-shark.texture.scale' to the shaders as 'uTextureScale' + update variable locations on each shader reload
--- 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 <iostream>
#include <iomanip>
#include <string>
+#include <charconv>
#include <memory>
#include <functional>
#include <sstream>
@@ -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<Texture> tex);
bool reloadTexture(const std::string& fileName);
void loadTextures();
- std::shared_ptr<Program> 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<Program> 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> program = std::make_shared<Program>();
+ shaderProgram = std::make_shared<Program>();
- // 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> shader = std::make_shared<Shader>(
- type, file, fileName);
+ MappedFile file(fileName);
+ std::shared_ptr<Shader> shader = std::make_shared<Shader>(
+ 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;
}
}
--- a/Texture.cpp Tue Dec 26 15:41:07 2023 +0100
+++ b/Texture.cpp Tue Dec 26 23:46:45 2023 +0100
@@ -27,6 +27,7 @@
std::string fileName;
int width;
int height;
+ GLfloat scale = 1.;
};
Texture::Texture(
@@ -64,6 +65,14 @@
return (GLfloat) impl->width / (GLfloat) impl->height;
}
+GLfloat Texture::getScale() const {
+ return impl->scale;
+}
+
+void Texture::setScale(GLfloat scale) {
+ impl->scale = scale;
+}
+
void Texture::update(int width, int height, const Buffer& img) {
impl->width = width;
impl->height = height;
--- a/Texture.h Tue Dec 26 15:41:07 2023 +0100
+++ b/Texture.h Tue Dec 26 23:46:45 2023 +0100
@@ -38,6 +38,8 @@
int getWidth() const;
int getHeight() const;
GLfloat getRatio() const;
+ GLfloat getScale() const;
+ void setScale(GLfloat scale);
void update(int width, int height, const Buffer& img);
private:
class Impl;
--- a/shaders/default.frag Tue Dec 26 15:41:07 2023 +0100
+++ b/shaders/default.frag Tue Dec 26 23:46:45 2023 +0100
@@ -1,6 +1,7 @@
#version 330 core
uniform sampler2D uTexture;
+uniform float uTextureScale;
in vec2 vTextureXY;
out vec4 fColor;
--- a/shaders/phosphor-basic.frag Tue Dec 26 15:41:07 2023 +0100
+++ b/shaders/phosphor-basic.frag Tue Dec 26 23:46:45 2023 +0100
@@ -1,6 +1,7 @@
#version 330 core
uniform sampler2D uTexture;
+uniform float uTextureScale;
in vec2 vTextureXY;
out vec4 fColor;
@@ -26,10 +27,10 @@
// fColor = invert(fColor);
fColor = (fColor-rand(vTextureXY)*0.3) * 1.6;
- float lineCount = textureSize(uTexture, 0).y;
+ float lineCount = textureSize(uTexture, 0).y / uTextureScale;
fColor.xyz *= abs(sin(radians(vTextureXY.y * 180. * lineCount)));
- // float columnCount = textureSize(uTexture, 0).x;
+ // float columnCount = textureSize(uTexture, 0).x / uTextureScale;
// fColor.xyz *=
// clamp(abs(sin(radians(vTextureXY.x * 180. * columnCount)))+0.6, 0., 1.);
--- a/shaders/scanlines-basic.frag Tue Dec 26 15:41:07 2023 +0100
+++ b/shaders/scanlines-basic.frag Tue Dec 26 23:46:45 2023 +0100
@@ -1,12 +1,13 @@
#version 330 core
uniform sampler2D uTexture;
+uniform float uTextureScale;
in vec2 vTextureXY;
out vec4 fColor;
void main() {
fColor = texture(uTexture, vTextureXY).rgba;
- float lineCount = textureSize(uTexture, 0).y;
+ float lineCount = textureSize(uTexture, 0).y / uTextureScale;
fColor.xyz *= abs(sin(radians(vTextureXY.y * 180. * lineCount)));
}
--- a/shaders/soften-borders.frag Tue Dec 26 15:41:07 2023 +0100
+++ b/shaders/soften-borders.frag Tue Dec 26 23:46:45 2023 +0100
@@ -1,6 +1,7 @@
#version 330 core
uniform sampler2D uTexture;
+uniform float uTextureScale;
in vec2 vTextureXY;
out vec4 fColor;