C++ const char* put variable/DEFINE on init - c++

I have const char* variable with vertex shader code:
const char* FS_source_a =
#include "fs_a.h"
;
in fs_a.h:
"#version 100\n"
"varying lowp vec4 v_color;\n"
"void main(void)\n"
"{\n"
"gl_FragColor = v_color;\n"
"}\n";
Now, I have some defined/static variable, and I want to put it in my shader code, like this[pseudocode]:
"#version "+SHADER_VERSION+"\n"
Well.... Is this possible somehow, or I have to concat them? I want to keep shader source code in separate file.
P.S. This is not opengl question.

You cannot do what you wrote, but you can do this:
code.c
#include "code.h"
const char* FS_source_a = DEFINEDVALUE;
char FS_dest_a[1024] = {0};
sprintf(FS_dest_a, FS_source_a, 100);
code.h
#define DEFINEDVALUE "#version %d\n\
varying lowp vec4 v_color;\n\
void main(void)\n\
{\n\
gl_FragColor = v_color;\n\
}\n"

Related

Why there is no version on Qt shader program?

From https://learnopengl.com/Getting-started/Shaders I read:
Shaders always begin with a version declaration, ...
But on OpenGL Window Example there is no version on shader code. What's the version then?
static const char *vertexShaderSource =
"attribute highp vec4 posAttr;\n"
"attribute lowp vec4 colAttr;\n"
"varying lowp vec4 col;\n"
"uniform highp mat4 matrix;\n"
"void main() {\n"
" col = colAttr;\n"
" gl_Position = matrix * posAttr;\n"
"}\n";
static const char *fragmentShaderSource =
"varying lowp vec4 col;\n"
"void main() {\n"
" gl_FragColor = col;\n"
"}\n";
Following seems to be related: How to Convert GLSL #version 330 core to GLSL ES #version 100?
In qt 5.12.2 source file : qopenglshaderprogram.cpp
LINE 604:
bool QOpenGLShader::compileSourceCode(const char *source){
Q_D(QOpenGLShader);
// This method breaks the shader code into two parts:
// 1. Up to and including an optional #version directive.
// 2. The rest.
// If a #version directive exists, qualifierDefines and redefineHighp
// are inserted after. Otherwise they are inserted right at the start.
// In both cases a #line directive is appended in order to compensate
// for line number changes in case of compiler errors.
if (d->shaderGuard && d->shaderGuard->id() && source) {
const QVersionDirectivePosition versionDirectivePosition = findVersionDirectivePosition(source);
QVarLengthArray<const char *, 5> sourceChunks;
QVarLengthArray<GLint, 5> sourceChunkLengths;
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (versionDirectivePosition.hasPosition()) {
// Append source up to and including the #version directive
sourceChunks.append(source);
sourceChunkLengths.append(GLint(versionDirectivePosition.position));
} else {
// QTBUG-55733: Intel on Windows with Compatibility profile requires a #version always
if (ctx->format().profile() == QSurfaceFormat::CompatibilityProfile) {
const char *vendor = reinterpret_cast<const char *>(ctx->functions()->glGetString(GL_VENDOR));
if (vendor && !strcmp(vendor, "Intel")) {
static const char version110[] = "#version 110\n";
sourceChunks.append(version110);
sourceChunkLengths.append(GLint(sizeof(version110)) - 1);
}
}
}
and
static QVersionDirectivePosition findVersionDirectivePosition(const char *source){
Q_ASSERT(source);
// According to the GLSL spec the #version directive must not be
// preceded by anything but whitespace and comments.
// In order to not get confused by #version directives within a
// multiline comment, we need to do some minimal comment parsing
// while searching for the directive.
If version is not available, "#version 110\n" will be added.
static const char version110[] = "#version 110\n";
sourceChunks.append(version110);

Can you write OpenGL shader in different file and later link it to the program?

Can you write OpenGL shader in a different file and later link it to the program? and if it's possible how? writing OpenGL shader in string makes my code messy.
Here is example code for shaders:
const char* vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aColor;\n"
"\n"
"out vec3 ourColor;\n"
"uniform vec2 angleValues;\n"
"\n"
"void main()\n"
"{\n"
"gl_Position = vec4(aPos.x * angleValues.x - aPos.y * angleValues.y, aPos.y * angleValues.x + aPos.x * angleValues.y , aPos.z, 1.0);\n"
"ourColor = aColor;\n"
"}\n";
const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"
"\n"
"void main()\n"
"{\n"
"FragColor = vec4(ourColor, 1.0);\n"
"}\n";
Yes, you can have files like my_shader.vs or my_fragment.fs and link them like in this Shader class
Just initialize it like this:
shader = Shader("./shaders/my_shader.vs", "./shaders/my_fragment.fs");

GLSL Shader (compilation error)

I've read all recommended posts, I've tried those solutions, but non of them helped.
In short problem lies in the third argument of
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
This code work:
const char *vertexShaderSource = "#version 120 \n"
"attribute vec3 pos;\n"
"attribute vec2 texCoord;\n"
"varying vec2 texCoord0;\n"
"uniform mat4 transform;\n"
"void main()\n"
"{\n"
" gl_Position = transform * vec4(pos, 1.0);\n"
" texCoord0 = texCoord;\n"
"}\0";
But I want to read it from a file, following code works
std::string s= "vertex";
std::ifstream file(s.c_str());
std::stringstream buffer;
buffer << file.rdbuf();
std::string str = buffer.str();
std::cout << str;
And is outputing:
#version 120
attribute vec3 pos;
attribute vec2 texCoord;
varying vec2 texCoord0;
uniform mat4 transform;
void main()
{
gl_Position = transform * vec4(pos, 1.0);
texCoord0 = texCoord;
}
I know that I cannot just simply convert string with code like this:
const char *vertexShaderSource = str.c_str();
And pass it into: glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
So I've used following code to prevent it from ceasing to exist:
char * writable = new char[str.size() + 1];
std::copy(str.begin(), str.end(), writable);
writable[str.size()] = '\0';
Passing glShaderSource(vertexShader, 1, &writable, NULL);does not work also.
I'm getting following error all the time, even with another copy&paste code from tutorials
0:1(4): preprocessor error: syntax error, unexpected HASH_TOKEN
What else I can do?
I've read these posts:
Reading a shader from a .txt file using a structure
read GLSL shaders from file
Here is the code I use to load shader sources:
ifstream iStream(filename);
stringstream buffer;
buffer << iStream.rdbuf();
string source = buffer.str();
const char* sources[] = { source.c_str() };
glShaderSource(handle, 1, sources, 0);
As you can see, the string can be given directly to glShaderSource; there is no need to create a copy of it. Have a look at the spec for c_str() if you're not convinced.
Not sure what the problem is in your case. I have used both \r\n and \n line endings successfully. Maybe you have a U+FEFF BOM character at the start of the file? It could with the the "hash" mentioned in the compilation error.

Why comment glBindFragDataLocation, the GL also works correctly?

const GLchar* vertexSource1 = "#version 330 core\n"
"layout (location = 0) in vec2 position;\n"
"layout (location = 1) in vec3 color;\n"
"out vec3 Color;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position, 0.0, 1.0);\n"
"Color = color;\n"
"}\0";
const GLchar* fragmentSource1 = "#version 330 core\n"
" in vec3 Color;\n"
" out vec4 outColor;\n"
" void main()\n"
" {\n"
" outColor = vec4(Color, 1.0);\n"
" }\n";
GLuint shaderProgram1 = glCreateProgram();
glAttachShader(shaderProgram1, vertexShader1);
glAttachShader(shaderProgram1, fragmentShader1);
// glBindFragDataLocation(shaderProgram1, 0, "Color");
glLinkProgram(shaderProgram1);
Whether I add glBindFragDataLocation or not, the GL works correctly, Why?
Because you're "lucky". The OpenGL specification provides no guarantees about how fragment shader output locations are assigned if you don't assign them. It only says that each one will have a separate location; what locations those are is up to the implementation.
However, considering the sheer volume of code that writes to a single output variable without explicitly assigning it to a location, it's highly unlikely that an OpenGL implementation would ever assign the first FS output location to anything other than 0. So while it isn't a spec guarantee, at this point, it is a de-facto requirement of implementations.
Note: That doesn't mean you shouldn't assign that location manually. It's always best to be on the safe and explicit side.
FYI: layout(location) works for fragment shader outputs too. So you should use that if you're using it on vertex attributes. Then you don't have to worry about doing it from code.

QOpenGLWidget cannot use more than one sampler2D

I've created a very basic shader:
static const char *frag_showImage =
"#version 150\n"
"uniform sampler2D textureSampler;\n"
"in mediump vec2 texc;\n"
"out highp vec4 fragColor;\n"
"void main() {\n"
" fragColor = texture2D(textureSampler, texc.st);\n"
"}\n";
And it works as expected, now a bit more complex one:
"#version 150\n"
"uniform sampler2D textureSampler;\n"
"uniform sampler2D maskSampler;\n"
"in mediump vec2 texc;\n"
"out highp vec4 fragColor;\n"
"void main() {\n"
" fragColor = texture2D(textureSampler, texc.st);\n"
" fragColor.x = texture2D(maskSampler, texc.st).x;\n"
" fragColor.y =0;\n"
"}\n";
It doesn't work but it has no warnings neither errors:
in both cases I bind the first texture as:
QOpenGLFunctions *f =this->context()->functions();
f->glActiveTexture(GL_TEXTURE0);
glBaseTexture->bind();
m_program->setUniformValue("textureSampler", 0);
and the second texture is binded as:
f->glActiveTexture(GL_TEXTURE1);
glMaskTexture->bind();
m_program->setUniformValue("maskSampler", 1);
Notice that if I bind glMaskTexture for the first shader it works ok so the problem is not on that QOpenGlTexture.
Any idea? Thank you in advance!
Goblins: renaming maskSampler to other name it works ok, I have no idea about why this is happening since "maskSampler" is not used in any other part of the code.