Я следил за руководством LearnOpenGL.com по C++, но, поскольку мне не нравилось вручную жестко закодировать шейдеры в коде, я написал функцию, которая считывает шейдеры из файла:
const char* ReadShader(const char* p_ShaderLocation)
{
std::ifstream ShaderStream;
std::stringstream Buffer;
ShaderStream.open(p_ShaderLocation);
if (!ShaderStream)
{
std::cout << "File: " << p_ShaderLocation << " can't be opened!" << '\n';
return 0;
}
if (ShaderStream.is_open())
{
Buffer << ShaderStream.rdbuf();
ShaderStream.close();
return Buffer.str().c_str();
}
else if (!ShaderStream.is_open())
{
std::cout << "File: " << p_ShaderLocation << " can't be read!" << '\n';
return 0;
}
}
Я попробовал это в первый раз, и это выдало мне следующую ошибку компиляции:
ERROR: Vertex Shader Compilaton Failed
ERROR: 0:2: 'Ç' : unexpected token
ERROR: 0:2: '' : compilation terminated
ERROR: 2 compilation errors. No code generated.
ERROR: Fragment Shader Compilaton Failed
ERROR: 0:2: '' : syntax error, unexpected IDENTIFIER
ERROR: 1 compilation errors. No code generated.
Я понятия не имею, что является причиной этого, но думаю, что это как-то связано с функцией ReadShader. Кроме того, шейдеры точно такие же, как и шейдеры из урока.
Постарайтесь свести к минимуму использование указателей в современном C++. Вы возвращаете висячий указатель (UB), что, очевидно, нехорошо, но если бы это был действительный указатель, все равно оставался бы вопрос, кто за него отвечает. Кому придется снова освободить память. И если вы знаете, что вам нужно сделать это после вызова функции, писать это — дополнительная работа. Возврат std::string
избавит вас от всей этой головной боли.
Хороший компилятор предупредит вас об этом. «ошибка: возврат адреса локального временного объекта»
Проверяем, выглядит ли !ShaderStream.is_open()
после проверки, не выглядит ли ShaderStream.is_open()
лишним.
Вместо
const char* ReadShader(const char* p_ShaderLocation)
{
return Buffer.str().c_str();
}
делать
std::string ReadShader(const char* p_ShaderLocation)
{
return { Buffer.str() };
}
См. также https://en.cppreference.com/w/cpp/io/basic_stringstream/str
Примечания
Копия базовой строки, возвращаемая
str
, является временным объектом, который будет уничтожен в конце выражения, поэтому прямой вызовc_str()
для результатаstr()
(например, вauto *ptr = out.str().c_str();
) приводит к висячему указателю.
Получив код шейдера в виде строкового объекта, вы можете передать его в функцию gl следующим образом:
auto shader_src = ReadShader();
const char *shader_src_str = shader_src.c_str();
GLint shader_src_len = shader_src.length();
glShaderSource(shader, 1, &shader_src_str, &shader_src_len /* or nullptr */);
Buffer
имеет локальную область действия, поэтому вы возвращаете висячий указатель черезreturn Buffer.str().c_str();