I run into the following problem.I load my shaders from files.The shader program ,when trying to compile, throws these errors for the vertex and fragment shaders:
Vertex info
0(12) : error C0000: syntax error, unexpected $undefined at token ""
Fragment info
0(10) : error C0000: syntax error, unexpected $undefined at token ""
When inspecting the loaded content of the files I can see all kinds of garbage text is attached at the beginnings and the ends of the shader files.Like this one:
#version 330
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 color;
smooth out vec4 theColor;
void main()
{
gl_Position = position;
theColor = color;
}ýýýý««««««««þîþîþîþ
The methods loading the shaders look as follows:
void ShaderLoader::loadShaders(char * vertexShaderFile,char *fragmentShaderFile){
vs = loadFile(vertexShaderFile,vlen);
fs = loadFile(fragmentShaderFile,flen);
}
char *ShaderLoader::loadFile(char *fname,GLint &fSize){
ifstream::pos_type size;
char * memblock;
string text;
// file read based on example in cplusplus.com tutorial
ifstream file (fname, ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
fSize = (GLuint) size;
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
cout << "file " << fname << " loaded" << endl;
text.assign(memblock);
}
else
{
cout << "Unable to open file " << fname << endl;
exit(1);
}
return memblock;
}
I tried to change the encoding from UTF-8 top ANSI ,also tried to edit outside the visual studio but the problem still persists .Any help on this will be greatly appreciated.
You're using C++, so I suggest you leverage that. Instead of reading into a self allocated char array I suggest you read into a std::string:
#include <string>
#include <fstream>
std::string loadFileToString(char const * const fname)
{
std::ifstream ifile(fname);
std::string filetext;
while( ifile.good() ) {
std::string line;
std::getline(ifile, line);
filetext.append(line + "\n");
}
return filetext;
}
That automatically takes care of all memory allocation and proper delimiting -- the keyword is RAII: Resource Allocation Is Initialization. Later on you can upload the shader source with something like
void glcppShaderSource(GLuint shader, std::string const &shader_string)
{
GLchar const *shader_source = shader_string.c_str();
GLint const shader_length = shader_string.size();
glShaderSource(shader, 1, &shader_source, &shader_length);
}
void load_shader(GLuint shaderobject, char * const shadersourcefilename)
{
glcppShaderSource(shaderobject, loadFileToString(shadersourcefilename));
}
It looks like all you have to do is allocate one more byte of memory in which you can place a null ('\0'):
...
memblock = new char[1 + fSize];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
memblock[size] = '\0';
...
edit
I changed my code to use fSize in the array rather than size, since it is a GLint, which is just a typedef over an integer. Also, I tried this fix on my machine, and it works as far as I can tell - no junk at the beginning, and none at the end.
Related
So the question above pretty much explains my problem, I have a program that prints the code size of my fragment shader and vertex shader, it is part of my Game engine project I have been working on for the past few days as a learning experience to get more knowledge of low-level c++ programming, but the problem is when I list where both shaders are placed in the project, my program proceeds to crash with a memory leak, the answer I need is exactly why this is happening
PipeLine.h:
#include <iostream>
#include <vector>
namespace G_piplne
{
class EdtrPipeLine
{
public:
//grabs the file path to the frag file of the glsl shader file
EdtrPipeLine(const std::string& vertFilePath, const std::string& fragFilePath);
private:
//gets the file path of both the frag file and vert file
static std::vector<char> readFile(const std::string& filepath);
//grabs the file path to the vert file of the glsl shader file
void createGraphicsPipeLine(const std::string& vertFilePath, const std::string& fragFilePath);
};
}
PipeLine.cpp used for initiating the functions in the PipeLine header file
#include "shaders_h/PipeLine.h"
#include <fstream>
#include <stdexcept>
namespace G_piplne
{
EdtrPipeLine::EdtrPipeLine(const std::string& vertFilePath, const std::string& fragFilePath)
{
createGraphicsPipeLine(vertFilePath, fragFilePath);
}
std::vector<char> EdtrPipeLine::readFile(const std::string& filepath)
{
std::ifstream file(filepath, std::ios::ate | std::ios::binary);
if (!file.is_open())
{
throw std::runtime_error("failed to open file: " + filepath);
}
size_t filesize = static_cast<size_t>(file.tellg());
std::vector<char> buffer(filesize);
file.seekg(0);
file.read(buffer.data(), filesize);
file.close();
return buffer;
}
void EdtrPipeLine::createGraphicsPipeLine(const std::string& vertFilePath, const std::string& fragFilePath)
{
//Reads Frag and Vert Code Size
auto vertCode = readFile(vertFilePath);
auto fragCode = readFile(fragFilePath);
//Prints Frag and Vert Code Size
std::cout << "Vertex Shader Code Size: " << vertCode.size() << "\n";
std::cout << "Frag Shader Code Size: " << fragCode.size() << "\n";
}
}
and finally, the EditorConfigWindow header file which uses the function to display my vert and frag code size
#pragma once
#include "EditorWindow.h"
#include "../shaders_h/PipeLine.h"
namespace G_editor
{
class EditorWindowConfig
{
public:
//Init Varibles for the size of the Editor Window
static constexpr int WIDTH = 800;
static constexpr int HEIGHT = 600;
void run();
private:
//init Window with name GPRPG
EditorWindow editorWindow{ WIDTH, HEIGHT, "GPRPG" };
//Display vert and frag code size
G_piplne::EdtrPipeLine edtrPipeLine{"../../Shaders/simpleShader.vert.spv ", "../../Shaders/simpleShader.frag.spv"};
};
}
All shader files are in the right place and listed correctly, I double-checked the names and they are correct as well, the error is as listed below
Unhandled exception at 0x00007FF8F0154F69 in GPRPG.exe: Microsoft C++ exception: std::runtime_error at memory location 0x00000064240FEEA8.
this error is hit at the breakpoint right when the createGraphicsPipeLine function is called from the EditorWindowConfig Header file, I've tried moving the shader files around in the project but it leads to the same problem, thank you in advance for any assistance given that may point me in the right direction to solve this problem
In researching, I found that adding the absolute path to my shader file actually outputs the size as expected, the program didn't like the short path I was inputting for some reason
I am trying to compile a simple colored triangle example with OpenGL 3 (GLSL 130) but my fragment shader never compiles. The error reported is always
syntax error unexpected $end
My vertex shader compiles and shows the geometry but the fragment shader fails.
Here are the sources (very simple one):
Vertex.vs:
attribute vec3 vertex_position;
attribute vec3 vertex_color;
varying vec4 out_color;
void main(void)
{
gl_Position = vec4(vertex_position, 1.0);
out_color = vec4(vertex_color, 1.0);
}
And fragment.fs:
varying vec4 out_color;
void main(void)
{
gl_FragColor = out_color;
}
[EDIT] Here is my shader compile code:
char *loadShader(const char *fname)
{
FILE* fp = fopen(fname, "rb");
long size = 0;
if (!fp)
return NULL;
fseek(fp, 0, SEEK_END);
size = ftell(fp) + 1;
fseek(fp, 0, SEEK_SET);
char* data = (char*) malloc((sizeof(char) * size));
::fread(data, 1, size, fp);
data[size-1] = '\0';
fclose(fp);
return data;
}
Shader::Shader(const char *fname)
: m_data(NULL),
ID(0)
{
if (fname)
m_data = ilian::loadShader(fname);
}
Shader::Shader(const char *data, size_t size)
{
if (data && size >0)
{
m_data = (char*) malloc(sizeof(char) * size);
::memmove(m_data, data, size);
}
}
Shader::~Shader()
{
if (m_data)
{
free(m_data);
m_data = NULL;
}
glDeleteShader(ID);
std::cout << "~Shader()\n";
}
std::string Shader::data()
{
std::string s((char*)m_data);
return s;
}
GLuint &Shader::getID()
{
return ID;
}
void Shader::createShader(ShaderType type)
{
GLint res = -1;
switch (type)
{
case VERTEX:
ID = glCreateShader(GL_VERTEX_SHADER);
break;
case FRAGMENT:
ID = glCreateShader(GL_FRAGMENT_SHADER);
break;
default:
break;
}
const GLchar* source = (const GLchar*) data().c_str();
int shader_len = data().length();
glShaderSource(ID, 1, &source, &shader_len);
glCompileShader(ID);
glGetShaderiv(ID, GL_COMPILE_STATUS, &res);
if (res == GL_TRUE)
{
std::cout << "Shader Compile OK!\n";
}
else
{
std::cout << "Shader Compile FAIL!\n";
GLint maxLength = 0;
glGetShaderiv(ID, GL_INFO_LOG_LENGTH, &maxLength);
//The maxLength includes the NULL character
std::vector<GLchar> infoLog(maxLength);
glGetShaderInfoLog(ID, maxLength, &maxLength, &infoLog[0]);
std::cout << (char*)infoLog.data() << "\n";
//We don't need the shader anymore.
glDeleteShader(ID);
}
}
GLProgram::GLProgram(const char *vs_source, const char *fs_source)
: ID(0), vs(nullptr), fs(nullptr)
{
vs = new Shader(vs_source);
fs = new Shader(fs_source);
vs->createShader(VERTEX);
fs->createShader(FRAGMENT);
}
GLProgram::~GLProgram()
{
if (vs)
delete vs;
if (fs)
delete fs;
}
VAO &GLProgram::getVertexArrayObject()
{
return vao;
}
bool GLProgram::createProgram()
{
static GLint msg;
ID = glCreateProgram();
glAttachShader(ID, vs->getID());
glAttachShader(ID, fs->getID());
glLinkProgram(ID);
glGetProgramiv(ID, GL_LINK_STATUS, &msg);
std::cout << "Link status: (" <<msg
<< ")"<< std::endl;
if (!msg)
{
GLint infoLen = 0;
glGetProgramiv(ID, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen > 1)
{
char* infoLog = new char[infoLen];
glGetProgramInfoLog(ID, infoLen, NULL, infoLog);
printf("Error linking program:\n%s\n", infoLog);
delete [] infoLog;
}
}
}
void GLProgram::bind(int location, const char *attribyte)
{
glBindAttribLocation(ID, location, attribyte);
}
void GLProgram::useProgram()
{
glUseProgram(ID);
glBindVertexArray(vao.ID());
}
You are passing a pointer to an invalid memory address to glShaderSource. This happens because you try to get the c_str() pointer from a temporary string object in this line:
const GLchar* source = (const GLchar*) data().c_str();
Right after this line, the temporary string returned by data() gets deleted and the source pointer points to an invalid memory address.
The shortest (but ugly) fix to your code is to make sure that the string object still lives when you use the pointer by storing it:
auto data_str = data();
const GLchar* source = (const GLchar*)data_str.c_str();
But since the construction of the whole string object is completely useless in your code (and actually hurts performance because the string object creates a copy of the underlying char array), the better way is to return the char* instead of a new std::string in the data() function:
const char* Shader::data()
{
return m_data;
}
and use it with:
const GLchar* source = data();
Or even better: Do not use a char* with malloc in the first place and use the proper C++ methods to directly load a std::string from the file.
When i try to create my shader with CreateVertexShader(), I get COM error 'The paremeter is incorrect.'.
struct ShaderData
{
LPVOID ShaderCode;
size_t ShaderSize;
};
This function works but it leaks. When delete[] buffer is uncommented I get the error.
Shader::ShaderData Shader::LoadShader(const std::string& file)
{
std::ifstream ifs(file, std::ios::in | std::ios::binary);
if (!ifs) return;
ifs.seekg(0, std::ios::end);
size_t size = static_cast<std::size_t>(ifs.tellg());
ifs.seekg(0, std::ios::beg);
char* buffer = new char[size];
ifs.read(buffer, len);
ShaderData data = { buffer, size };
//delete[] buffer;
return data;
}
Another version of the same function but using std::vector, I still get the same error.
Shader::ShaderData Shader::LoadShader(const std::string& file)
{
std::ifstream ifs(file, std::ios::in | std::ios::binary);
if (!ifs) return;
ifs.seekg(0, std::ios::end);
size_t size = static_cast<std::size_t>(ifs.tellg());
ifs.seekg(0, std::ios::beg);
std::vector<char> buffer(size);
ifs.read(buffer.data(), size);
ShaderData data = { static_cast<void*>(buffer.data()), size };
return data;
}
Function creating the shaders. m_vertex_data and m_pixel_data are both member variables of class Shader, and holds the data returned from LoadShader().
void Shader::CreateShaders(ID3D11Device* device)
{
device->CreateVertexShader(m_vertex_data.ShaderCode,
m_vertex_data.ShaderSize,
nullptr,
m_vertex_shader.GetAddressOf()));
device->CreatePixelShader(m_pixel_data.ShaderCode,
m_pixel_data.ShaderSize,
nullptr,
m_pixel_shader.GetAddressOf()));
}
You need to keep the buffer pointed to by ShaderData::ShaderCode; valid until you create a shader. To avoid leaks just replace it with ::std::vector< char > ShaderCode; so the buffer will be kept safe. Actually you don't need ShaderData struct at all, just return a vector containing shader code.
Well this is a bit of an embarrasing problem, I can't seem to load any sort of file through a program I made. My program fails everytime regardless of the file i try to load, so I'm not quite sure what's going on. Specifically, the program is supposed to be loading GLSL shaders, and it hasn't been working. Here is my code:
static inline GLuint GetProgram(const char* vert,const char* frag)
{
GLuint vertex,fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
std::string vCode,fCode;
std::ifstream vss(vert);
std::ifstream fss(frag);
if(vss.is_open())
{
std::string line;
while(std::getline(vss,line))
{
vCode += line + '\n';
}
}
else
{
OutputDebugStringA("ERROR READING VERTEX SHADER\n");
}
if(fss.is_open())
{
std::string line;
while(std::getline(fss,line))
{
fCode += line + '\n';
}
}
else
{
OutputDebugStringA("ERROR READING FRAGMENT SHADER\n");
}
vss.close();
fss.close();
char const* vsp = vCode.c_str();
char const* fsp = fCode.c_str();
glShaderSource(vertex,1,&vsp,NULL);
glShaderSource(fragment,1,&fsp,NULL);
OutputDebugStringA("Vertex Source:\n");
OutputDebugStringA(vsp + '\n');
OutputDebugStringA("Fragment Source:\n");
OutputDebugStringA(fsp + '\n');
glCompileShader(vertex);
glCompileShader(fragment);
GLuint prog = glCreateProgram();
glAttachShader(prog,vertex);
glAttachShader(prog,fragment);
glLinkProgram(prog);
char errbuf[1024];
GLsizei len;
glGetProgramInfoLog(prog,sizeof(errbuf),&len,errbuf);
OutputDebugStringA(errbuf);
glUseProgram(prog);
return prog;
}
vss.is_open() and fss.is_open() return false everytime. This problem only occurs with this program too, I have another that runs the exact same function listed and it works just fine.
How I am calling it:
GLuint program = Shader::GetProgram("v.vert","f.frag");
The directory:
Finally got it! Just had to use _getcwd(), move my files to that location and append the file names of the two shaders. Here is my code now:
static inline GLuint GetProgram(const char* vert,const char* frag)
{
GLuint vertex,fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
const char* dir = _getcwd(NULL,0);
std::string var1 = dir;
std::string vCode,fCode;
std::fstream vss;
std::fstream fss;
char* var2 = "/";
std::string vertpath = var1;
std::string fragpath = var1;
vertpath.append(var2);
fragpath.append(var2);
fragpath.append(frag);
vertpath.append(vert);
vss.open(vertpath);
fss.open(fragpath);
I'm having a bit of a problem with my code for compiling shaders, namely they both register as failed compiles and no log is received.
This is the shader compiling code:
/* Make the shader */
Uint size;
GLchar* file;
loadFileRaw(filePath, file, &size);
const char * pFile = file;
const GLint pSize = size;
newCashe.shader = glCreateShader(shaderType);
glShaderSource(newCashe.shader, 1, &pFile, &pSize);
glCompileShader(newCashe.shader);
GLint shaderCompiled;
glGetShaderiv(newCashe.shader, GL_COMPILE_STATUS, &shaderCompiled);
if(shaderCompiled == GL_FALSE)
{
ReportFiler->makeReport("ShaderCasher.cpp", "loadShader()", "Shader did not compile", "The shader " + filePath + " failed to compile, reporting the error - " + OpenGLServices::getShaderLog(newCashe.shader));
}
And these are the support functions:
bool loadFileRaw(string fileName, char* data, Uint* size)
{
if (fileName != "")
{
FILE *file = fopen(fileName.c_str(), "rt");
if (file != NULL)
{
fseek(file, 0, SEEK_END);
*size = ftell(file);
rewind(file);
if (*size > 0)
{
data = (char*)malloc(sizeof(char) * (*size + 1));
*size = fread(data, sizeof(char), *size, file);
data[*size] = '\0';
}
fclose(file);
}
}
return data;
}
string OpenGLServices::getShaderLog(GLuint obj)
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;
glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
string log = infoLog;
free(infoLog);
return log;
}
return "<Blank Log>";
}
and the shaders I'm loading:
void main(void)
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
void main(void)
{
gl_Position = ftransform();
}
In short I get
From: ShaderCasher.cpp, In: loadShader(), Subject: Shader did not compile
Message: The shader Data/Shaders/Standard/standard.vs failed to compile, reporting the error - <Blank Log>
for every shader I compile.
I've tried replacing the file reading with just a hard coded string but I get the same error so there must be something wrong with how I'm compiling them. I have run and compiled example programs with shaders, so I doubt my drivers are the issue, but in any case I'm on a Nvidia 8600m GT.
Can anyone help?
In loadFileRaw, you pass char *data by value. Then you assign to it:
data = (char*)malloc(sizeof(char) * (*size + 1));
so your call
loadFileRaw(filePath, file, &size);
does not change the value of file! To change file, pass it in by pointer:
loadFileRaw(filePath, &file, &size);
and then change your function to
bool loadFileRaw(string fileName, char** data, Uint* size) { ... }
and in it,
*data = (char*)malloc(sizeof(char) * (*size + 1));
etc. (for the remaining references to data).
That said, since you're using C++, look into using std::vector<char> or std::string for your memory management. To get you started,
{
std::vector<char> data;
data.resize(100); // now it has 100 entries, initialized to zero
silly_C_function_that_takes_a_char_pointer_and_a_size(&data[0], 100); // OK
} // presto, memory freed
Also, you can look into using std::ifstream for reading files, instead of using FILE *.
Try with:
glShaderSource(newCashe.shader, 1, &pFile, NULL);
Which is the most commonly used call to load shader sources.