Reputation: 13
I'm doing some experiments with OpenGL and I'm trying to load a shader. It needs the source in a const char*, but since i'm doing it on C++ I can use std::strings and then call str.c_str(). That's not the problem - when I try to read a file, it reads perfectly, but the returned value is a corrupted string. Here's the relevant parts of code:
// inline method on engine.hpp
inline void readFile(std::string filePath, std::string* retValue)
{
std::ifstream file;
file.open(filePath);
std::string result;
std::string line;
while (!file.eof())
{
std::getline(file, line);
result.append(line + "\n");
}
memcpy(retValue, &result, sizeof(result));
}
// implemented method on engine.cpp
GLint Engine::createShader(std::string vs, std::string fs)
{
GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
std::string vsSourceStr = "";
std::string fsSourceStr = "";
readFile(vs, &vsSourceStr);
readFile(fs, &fsSourceStr);
const char* vsSource = vsSourceStr.c_str();
const char* fsSource = fsSourceStr.c_str();
//std::string t_vs = readFile(vs);
//const char* vsSource = readFile(vs).c_str();
//const char* fsSource = readFile(fs).c_str();
glShaderSource(vertex, 1, &vsSource, NULL);
glCompileShader(vertex);
glShaderSource(fragment, 1, &fsSource, NULL);
glCompileShader(fragment);
GLint program = glCreateProgram();
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
if (shaderCompiled(program))
{
std::cout << "shader successfully compiled" << std::endl;
}
else
{
std::cout << "shader not compiled" << std::endl;
printShaderError(vertex);
printShaderError(fragment);
std::cout << "Vertex Shader source:" << std::endl;
std::cout << vsSource << std::endl;
std::cout << "Fragment Shader source:" << std::endl;
std::cout << fsSource << std::endl;
}
return program;
}
Here's what Visual Studio says on debug: http://prntscr.com/4qlnx7
It reads the file flawlessly, just crashes the return value. I've tried it returning the result, using references and copying memory, as you can see on my code. Thanks anyway.
Upvotes: 1
Views: 978
Reputation: 1556
When you do memcpy(retValue, &result, sizeof(result));
, you are copying internal std::string structure, not the string data. Assign string instead: *retValue = result
Using a reference for the result string into readFile() will get a more robust version:
void readFile(std::string filePath, std::string& retValue)
{
std::ifstream file(filePath);
retValue.clear();
std::string line;
while (std::getline(file, line))
{
retValue += line;
retValue += '\n';
}
}
GLint Engine::createShader(std::string vs, std::string fs)
{
GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
std::string vsSourceStr;
std::string fsSourceStr;
readFile(vs, vsSourceStr);
readFile(fs, fsSourceStr);
// ...
}
Other way to read a file into a string is to use std::istreambuf_iterator
:
inline std::string readFile(std::string const& filename)
{
std::ifstream file(filename);
std::istreambuf_iterator<char> begin(file), end;
return std::string(begin, end);
}
Upvotes: 0
Reputation: 48605
This will not do what you think:
std::string line;
while (!file.eof())
{
std::getline(file, line);
result.append(line + "\n");
}
Please use:
std::string line;
while (std::getline(file, line))
{
result.append(line + "\n");
}
The reason being that eof()
is not triggered until after the file is read. That means your std::getline()
may have failed (at EOF) and you are using that bad data.
See: C++ FAQ 15.5 regarding eof()
.
Upvotes: 3