169 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "shader.h"
 | |
| 
 | |
| #include <fstream>
 | |
| #include <sstream>
 | |
| #include <vector>
 | |
| 
 | |
| #include "../lib/glew/GL/glew.h"
 | |
| #include "../lib/glfw/glfw3.h"
 | |
| 
 | |
| #include "logger.h"
 | |
| #include "vertex.h"
 | |
| 
 | |
| Shader::Shader(const std::string& vertex_path, const std::string& fragment_path)
 | |
| {
 | |
| 	const uint32_t vshader = compile_shader(GL_VERTEX_SHADER, vertex_path);
 | |
| 	const uint32_t fshader =
 | |
| 	    compile_shader(GL_FRAGMENT_SHADER, fragment_path);
 | |
| 
 | |
| 	if (vshader == 0 || fshader == 0) {
 | |
| 		program_id_ = 0;
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	program_id_ = glCreateProgram();
 | |
| 	glAttachShader(program_id_, vshader);
 | |
| 	glAttachShader(program_id_, fshader);
 | |
| 	glLinkProgram(program_id_);
 | |
| 
 | |
| 	// Error handling
 | |
| 	int ret;
 | |
| 	glGetProgramiv(program_id_, GL_LINK_STATUS, &ret);
 | |
| 	if (ret == GL_FALSE) {
 | |
| 		char buffer[1024];
 | |
| 		glGetProgramInfoLog(program_id_, sizeof(buffer), nullptr,
 | |
| 				    buffer);
 | |
| 		error_ = buffer;
 | |
| 		glDeleteProgram(program_id_);
 | |
| 		program_id_ = 0;
 | |
| 	}
 | |
| 
 | |
| 	glDeleteShader(vshader);
 | |
| 	glDeleteShader(fshader);
 | |
| }
 | |
| 
 | |
| void Shader::use() const
 | |
| {
 | |
| 	if (program_id_ != 0)
 | |
| 		glUseProgram(program_id_);
 | |
| }
 | |
| 
 | |
| void Shader::setup_attribs() const
 | |
| {
 | |
| 	int loc = glGetAttribLocation(program_id_, "vpos");
 | |
| 	if (loc != -1) {
 | |
| 		glEnableVertexAttribArray(loc);
 | |
| 		glVertexAttribPointer(
 | |
| 		    loc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
 | |
| 		    reinterpret_cast<const void*>(offsetof(Vertex, position)));
 | |
| 	}
 | |
| 
 | |
| 	loc = glGetAttribLocation(program_id_, "vcolor");
 | |
| 	if (loc != -1) {
 | |
| 		glEnableVertexAttribArray(loc);
 | |
| 		glVertexAttribPointer(
 | |
| 		    loc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
 | |
| 		    reinterpret_cast<const void*>(offsetof(Vertex, color)));
 | |
| 	}
 | |
| 
 | |
| 	loc = glGetAttribLocation(program_id_, "vtexcoord");
 | |
| 	if (loc != -1) {
 | |
| 		glEnableVertexAttribArray(loc);
 | |
| 		glVertexAttribPointer(
 | |
| 		    loc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
 | |
| 		    reinterpret_cast<const void*>(offsetof(Vertex, tex_coord)));
 | |
| 	}
 | |
| 
 | |
| 	loc = glGetAttribLocation(program_id_, "vnormal");
 | |
| 	if (loc != -1) {
 | |
| 		glEnableVertexAttribArray(loc);
 | |
| 		glVertexAttribPointer(
 | |
| 		    loc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
 | |
| 		    reinterpret_cast<const void*>(offsetof(Vertex, normal)));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int Shader::uniform_location(const char* key) const
 | |
| {
 | |
| 	return glGetUniformLocation(program_id_, key);
 | |
| }
 | |
| 
 | |
| void Shader::set_int(int loc, int value)
 | |
| {
 | |
| 	if (loc != -1)
 | |
| 		glUniform1i(loc, value);
 | |
| }
 | |
| 
 | |
| void Shader::set_float(int loc, float value)
 | |
| {
 | |
| 	if (loc != -1)
 | |
| 		glUniform1f(loc, value);
 | |
| }
 | |
| 
 | |
| void Shader::set_vec3(int loc, const glm::vec3& value)
 | |
| {
 | |
| 	if (loc != -1)
 | |
| 		glUniform3fv(loc, 1, &value[0]);
 | |
| }
 | |
| 
 | |
| void Shader::set_vec4(int loc, const glm::vec4& value)
 | |
| {
 | |
| 	if (loc != -1)
 | |
| 		glUniform4fv(loc, 1, &value[0]);
 | |
| }
 | |
| 
 | |
| void Shader::set_mat4(int loc, const glm::mat4& value)
 | |
| {
 | |
| 	if (loc != -1)
 | |
| 		glUniformMatrix4fv(loc, 1, GL_FALSE, &value[0][0]);
 | |
| }
 | |
| 
 | |
| std::string Shader::read_shader_file(const std::string& filename)
 | |
| {
 | |
| 	std::ifstream file(filename);
 | |
| 	if (!file) {
 | |
| 		error_ = "Failed to open shader file: " + filename;
 | |
| 		Logger::error(sstr("Failed to open shader file: ", filename));
 | |
| 		return std::string{0};
 | |
| 	}
 | |
| 
 | |
| 	std::stringstream buffer;
 | |
| 	buffer << file.rdbuf();
 | |
| 	return buffer.str();
 | |
| }
 | |
| 
 | |
| uint32_t Shader::compile_shader(uint32_t type, const std::string& source_path)
 | |
| {
 | |
| 	const char* shader_type_name =
 | |
| 	    (type == GL_VERTEX_SHADER) ? "vertex" : "fragment";
 | |
| 
 | |
| 	std::string source = read_shader_file(source_path);
 | |
| 	if (source.empty())
 | |
| 		return 0;
 | |
| 
 | |
| 	Logger::info(
 | |
| 	    sstr("Compiling ", shader_type_name, " shader: ", source_path));
 | |
| 
 | |
| 	const uint32_t shader	   = glCreateShader(type);
 | |
| 	const char*    shader_code = source.c_str();
 | |
| 
 | |
| 	glShaderSource(shader, 1, &shader_code, nullptr);
 | |
| 	glCompileShader(shader);
 | |
| 
 | |
| 	// Error handling
 | |
| 	int ret;
 | |
| 	glGetShaderiv(shader, GL_COMPILE_STATUS, &ret);
 | |
| 	if (ret == GL_FALSE) {
 | |
| 		char buffer[1024];
 | |
| 		glGetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer);
 | |
| 		error_ = buffer;
 | |
| 		Logger::error(sstr("Shader compilation failed (",
 | |
| 				   shader_type_name, "): ", buffer));
 | |
| 		glDeleteShader(shader);
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	Logger::info(sstr(shader_type_name, " shader compiled successfully"));
 | |
| 	return shader;
 | |
| }
 |