C++从文件中读取glsl文件中读取着色器字符串代码时遇到的乱码问题

最近在读<<Computer Graphics Programming in OpenGL Using C++>>时,作者给出了一段从glsl文件读源码的程序,再动手做实验后发现了一点小关乎C++底层的stl::string实现机制在string到C字符串的小问题。

源代码是这样写的,它包含在一整个cpp文件中:

而我为了提高后续实验这段代码的复用性,则是将其写入了一个hpp文件,这时候就发生了转换错误:

定义在ReadingGLSLfile.hpp中的pair类型中的经c_str()转换后的C类型字符串在控制台输出的时候还好好的

但是一旦跨文件传输pair值的内容的时候pair的值就变成了乱码(见上图的的vshaderSource和fshaderSource):

我猜测是函数调用产生的中间临时变量在读取值之前就被释放了,故而出现乱码问题,结果不出所料——在修改readerShader的返回类型为&pair后VS直接报了错误。通过在网上查阅pair生命周期的博文之后我明白了问题出现在由STL::string类型转换到C字符串类型的c_str()接口,在Linux中使用Copy-On-Write技术并不会使得c_str()转换后两者的内存地址实际上是相同的,但是现在C语言的编译器经过各大厂商的加工之后Copy-On-Write技术在一些现代编译器已经被替代了,在大多数非Linux环境中都不能确保c_str()使用的安全性。

不同的 stl 标准库实现不同, 比如 CentOS 6.5 默认的 stl::string 实现就是 『Copy-On-Write』, 而 macOS(10.10.5)实现就是『Eager-Copy』。而Windows经过对Visual C++的升级后,对C++编译的用户透明度进一步提高了,难以推知stl::string的实现机制,如果后续在相关资料查到了再来补充。

那么我们应该警惕在跨文件传输经c_str()转换后的C类型字符串,从而我把调用c_str()的过程迁移到了cpp文件下,程序能够成功执行:

 

另外,在glsl文件中书写shader代码的格式也是很有讲究的,这两个shader是我成功运行后两个glsl文件内的内容:

 

而不能像在编译器内部书写C-styled const char*那样:

另附cpp代码:

#include <iostream>
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
#include<vector>
#include"ReadingGLSLfile.hpp"
#define numVAOs 1

GLuint renderingProgram;//GLuint --- shorthand for "unsigned int"
GLuint vao[numVAOs];

GLuint createShaderProgram() {
	pair<string, string> p = readShader("vertShader.glsl", "fragShader.glsl");
	const char* vshaderSource = p.first.c_str();
	cout << "vshaderSource:\n" << vshaderSource << endl;
	const char* fshaderSource = p.second.c_str();
	cout << "fshaderSource:\n" << fshaderSource << endl;
	/*glCreateShader
	creates each shader object
(initially empty), and returns an integer ID for each that is an index for
referencing it later—our code stores this ID in the variables vShader and
fShader*/
	GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
	GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);

	glShaderSource(vShader, 1, &vshaderSource, NULL);
	/* loads the GLSL code
	from the strings into the empty shader objects
	four params :
	a)shader object
	b)the number of strings in the shader source code
	c)an array of pointers to strings containing the source code
	d)an additional parameter we aren't using(explain later)*/
	glShaderSource(fShader, 1, &fshaderSource, NULL);
	glCompileShader(vShader);
	glCompileShader(fShader);
	/*
	glCreateProgram() to create the program object, glAttachShader() to
attach each of the shaders to it, and then glLinkProgram() to request that
the GLSL compiler ensure that they are compatible.
*/
	GLuint vfProgram = glCreateProgram();
	glAttachShader(vfProgram, vShader);
	glAttachShader(vfProgram, fShader);
	glLinkProgram(vfProgram);

	return vfProgram;
}
void init(GLFWwindow* window)
{
	renderingProgram = createShaderProgram();
	glGenVertexArrays(numVAOs, vao);
	glBindVertexArray(vao[0]);
}

void display(GLFWwindow* window, double currentTime) {
	glUseProgram(renderingProgram);//load shaders onto the hardware
	/*glDrawArrays(GLenum mode, Glint first, GLsizei count);
	* The mode is the type of primitive—for triangles we use
	GL_TRIANGLES. The parameter “first” indicates which vertex to start
	with (generally vertex number 0, the first one), and count specifies the total
	number of vertices to be drawn
	*/
	glDrawArrays(GL_TRIANGLES, 0, 3);
	glPointSize(50.0f);
}
int main(void)
{
	if (!glfwInit()) {
		exit(EXIT_FAILURE);
	}
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//use OpenGL version4.3
	GLFWwindow* window = glfwCreateWindow(600, 600, "Chapter2 - program2", NULL, NULL);//the last
	//two parameters allow for full screen mode and resource sharing
	glfwMakeContextCurrent(window);
	if (glewInit() != GLEW_OK) { exit(EXIT_FAILURE); }
	glfwSwapInterval(1);

	init(window);

	while (!glfwWindowShouldClose(window))
	{
		display(window, glfwGetTime());
		glfwSwapBuffers(window);
		glfwPollEvents();//handle other window related  events(such as the user clicking the "X"
		//in the upper right corner,the window module)
	}

	glfwDestroyWindow(window);
	glfwTerminate();
	exit(EXIT_SUCCESS);
	return 0;
}

hpp:

#pragma   once  
#include<utility>
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
/*P56*/
string readShaderSource(const char * filePath)
{
	string content;
	ifstream fileStream(filePath, ios::in);
	string line = "";
	if (fileStream.is_open()) {
		while (!fileStream.eof()) {
			getline(fileStream, line);
			content.append(line + "\n");
		}
		cout << "file opened" << endl;
	}
	else
	{
		cout << "open errors" << endl;
	}
	fileStream.close();
	return content;
}

pair<string, string> readShader(const char*file1,const char* file2)
{
	//(......as before plus)
	string vertShaderStr = readShaderSource(file1);
	string fragShaderStr = readShaderSource(file2);

	pair<string, string> p(vertShaderStr, fragShaderStr);
	cout << "p.first:\n" << p.first<< endl;
	cout << "p.second:\n" << p.second << endl;
	return p;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值