#ifndefSHADER_H#defineSHADER_H#include<string>#include<glad/glad.h>#include<glm/glm.hpp>#include<glm/gtc/type_ptr.hpp>// General purpsoe shader object. Compiles from file, generates// compile/link-time error messages and hosts several utility // functions for easy management.classShader{public:// stateunsignedint ID;// constructorShader();// sets the current shader as active
Shader&Use();// compiles the shader from given source codevoidCompile(constchar* vertexSource,constchar* fragmentSource,constchar* geometrySource =nullptr);// note: geometry source code is optional // utility functionsvoidSetFloat(constchar* name,float value,bool useShader =false);voidSetInteger(constchar* name,int value,bool useShader =false);voidSetVector2f(constchar* name,float x,float y,bool useShader =false);voidSetVector2f(constchar* name,const glm::vec2& value,bool useShader =false);voidSetVector3f(constchar* name,float x,float y,float z,bool useShader =false);voidSetVector3f(constchar* name,const glm::vec3& value,bool useShader =false);voidSetVector4f(constchar* name,float x,float y,float z,float w,bool useShader =false);voidSetVector4f(constchar* name,const glm::vec4& value,bool useShader =false);voidSetMatrix4(constchar* name,const glm::mat4& matrix,bool useShader =false);private:// checks if compilation or linking failed and if so, print the error logsvoidcheckCompileErrors(unsignedint object, std::string type);};#endif#include"shader.h"#include<iostream>// constructorinlineShader::Shader(){}
Shader&Shader::Use(){glUseProgram(this->ID);return*this;}voidShader::Compile(constchar* vertexSource,constchar* fragmentSource,constchar* geometrySource){unsignedint sVertex, sFragment, gShader;// vertex Shader
sVertex =glCreateShader(GL_VERTEX_SHADER);glShaderSource(sVertex,1,&vertexSource,NULL);glCompileShader(sVertex);checkCompileErrors(sVertex,"VERTEX");// fragment Shader
sFragment =glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(sFragment,1,&fragmentSource,NULL);glCompileShader(sFragment);checkCompileErrors(sFragment,"FRAGMENT");// if geometry shader source code is given, also compile geometry shaderif(geometrySource !=nullptr){
gShader =glCreateShader(GL_GEOMETRY_SHADER);glShaderSource(gShader,1,&geometrySource,NULL);glCompileShader(gShader);checkCompileErrors(gShader,"GEOMETRY");}// shader programthis->ID =glCreateProgram();glAttachShader(this->ID, sVertex);glAttachShader(this->ID, sFragment);if(geometrySource !=nullptr)glAttachShader(this->ID, gShader);glLinkProgram(this->ID);checkCompileErrors(this->ID,"PROGRAM");// delete the shaders as they're linked into our program now and no longer necessaryglDeleteShader(sVertex);glDeleteShader(sFragment);if(geometrySource !=nullptr)glDeleteShader(gShader);}voidShader::SetFloat(constchar* name,float value,bool useShader){if(useShader)this->Use();glUniform1f(glGetUniformLocation(this->ID, name), value);}voidShader::SetInteger(constchar* name,int value,bool useShader){if(useShader)this->Use();glUniform1i(glGetUniformLocation(this->ID, name), value);}voidShader::SetVector2f(constchar* name,float x,float y,bool useShader){if(useShader)this->Use();glUniform2f(glGetUniformLocation(this->ID, name), x, y);}voidShader::SetVector2f(constchar* name,const glm::vec2& value,bool useShader){if(useShader)this->Use();glUniform2f(glGetUniformLocation(this->ID, name), value.x, value.y);}voidShader::SetVector3f(constchar* name,float x,float y,float z,bool useShader){if(useShader)this->Use();glUniform3f(glGetUniformLocation(this->ID, name), x, y, z);}voidShader::SetVector3f(constchar* name,const glm::vec3& value,bool useShader){if(useShader)this->Use();glUniform3f(glGetUniformLocation(this->ID, name), value.x, value.y, value.z);}voidShader::SetVector4f(constchar* name,float x,float y,float z,float w,bool useShader){if(useShader)this->Use();glUniform4f(glGetUniformLocation(this->ID, name), x, y, z, w);}voidShader::SetVector4f(constchar* name,const glm::vec4& value,bool useShader){if(useShader)this->Use();glUniform4f(glGetUniformLocation(this->ID, name), value.x, value.y, value.z, value.w);}voidShader::SetMatrix4(constchar* name,const glm::mat4& matrix,bool useShader){if(useShader)this->Use();glUniformMatrix4fv(glGetUniformLocation(this->ID, name),1,false, glm::value_ptr(matrix));}voidShader::checkCompileErrors(unsignedint object, std::string type){int success;char infoLog[1024];if(type !="PROGRAM"){glGetShaderiv(object, GL_COMPILE_STATUS,&success);if(!success){glGetShaderInfoLog(object,1024,NULL, infoLog);
std::cout <<"| ERROR::SHADER: Compile-time error: Type: "<< type <<"\n"<< infoLog <<"\n -- --------------------------------------------------- -- "<< std::endl;}}else{glGetProgramiv(object, GL_LINK_STATUS,&success);if(!success){glGetProgramInfoLog(object,1024,NULL, infoLog);
std::cout <<"| ERROR::Shader: Link-time error: Type: "<< type <<"\n"<< infoLog <<"\n -- --------------------------------------------------- -- "<< std::endl;}}}
Texture类
#ifndefTEXTURE_H#defineTEXTURE_H#include<glad/glad.h>// Texture2D is able to store and configure a texture in OpenGL.// It also hosts utility functions for easy management.classTexture2D{public:// holds the ID of the texture object, used for all texture operations to reference to this particlar textureunsignedint ID;// texture image dimensionsunsignedint Width, Height;// width and height of loaded image in pixels// texture Formatunsignedint Internal_Format;// format of texture objectunsignedint Image_Format;// format of loaded image// texture configurationunsignedint Wrap_S;// wrapping mode on S axisunsignedint Wrap_T;// wrapping mode on T axisunsignedint Filter_Min;// filtering mode if texture pixels < screen pixelsunsignedint Filter_Max;// filtering mode if texture pixels > screen pixels// constructor (sets default texture modes)Texture2D();// generates texture from image datavoidGenerate(unsignedint width,unsignedint height,unsignedchar* data);// binds the texture as the current active GL_TEXTURE_2D texture objectvoidBind()const;};#endif#include<iostream>#include"Texture.h"Texture2D::Texture2D():Width(0),Height(0),Internal_Format(GL_RGB),Image_Format(GL_RGB),Wrap_S(GL_REPEAT),Wrap_T(GL_REPEAT),Filter_Min(GL_LINEAR),Filter_Max(GL_LINEAR){glGenTextures(1,&this->ID);}voidTexture2D::Generate(unsignedint width,unsignedint height,unsignedchar* data){this->Width = width;this->Height = height;// create TextureglBindTexture(GL_TEXTURE_2D,this->ID);glTexImage2D(GL_TEXTURE_2D,0,this->Internal_Format, width, height,0,this->Image_Format, GL_UNSIGNED_BYTE, data);// set Texture wrap and filter modesglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,this->Wrap_S);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,this->Wrap_T);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,this->Filter_Min);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,this->Filter_Max);// unbind textureglBindTexture(GL_TEXTURE_2D,0);}voidTexture2D::Bind()const{glBindTexture(GL_TEXTURE_2D,this->ID);}
ResourceManager类
#ifndefRESOURCE_MANAGER_H#defineRESOURCE_MANAGER_H#include<map>#include<string>#include<glad/glad.h>#include"Texture.h"#include"Shader.h"// A static singleton ResourceManager class that hosts several// functions to load Textures and Shaders. Each loaded texture// and/or shader is also stored for future reference by string// handles. All functions and resources are static and no // public constructor is defined.classResourceManager{public:// resource storagestatic std::map<std::string, Shader> Shaders;static std::map<std::string, Texture2D> Textures;// loads (and generates) a shader program from file loading vertex, fragment (and geometry) shader's source code. If gShaderFile is not nullptr, it also loads a geometry shaderstatic Shader LoadShader(constchar* vShaderFile,constchar* fShaderFile,constchar* gShaderFile, std::string name);// retrieves a stored saderstatic Shader GetShader(std::string name);// loads (and generates) a texture from filestatic Texture2D LoadTexture(constchar* file,bool alpha, std::string name);// retrieves a stored texturestatic Texture2D GetTexture(std::string name);// properly de-allocates all loaded resourcesstaticvoidClear();private:// private constructor, that is we do not want any actual resource manager objects. Its members and functions should be publicly available (static).ResourceManager(){}// loads and generates a shader from filestatic Shader loadShaderFromFile(constchar* vShaderFile,constchar* fShaderFile,constchar* gShaderFile =nullptr);// loads a single texture from filestatic Texture2D loadTextureFromFile(constchar* file,bool alpha);};#endif#include"ResourceManager.h"#include<iostream>#include<sstream>#include<fstream>#include"stb_image.h"// Instantiate static variables
std::map<std::string, Texture2D> ResourceManager::Textures;
std::map<std::string, Shader> ResourceManager::Shaders;
Shader ResourceManager::LoadShader(constchar* vShaderFile,constchar* fShaderFile,constchar* gShaderFile, std::string name){
Shaders[name]=loadShaderFromFile(vShaderFile, fShaderFile, gShaderFile);return Shaders[name];}
Shader ResourceManager::GetShader(std::string name){return Shaders[name];}
Texture2D ResourceManager::LoadTexture(constchar* file,bool alpha, std::string name){
Textures[name]=loadTextureFromFile(file, alpha);return Textures[name];}
Texture2D ResourceManager::GetTexture(std::string name){return Textures[name];}voidResourceManager::Clear(){// (properly) delete all shaders for(auto iter : Shaders)glDeleteProgram(iter.second.ID);// (properly) delete all texturesfor(auto iter : Textures)glDeleteTextures(1,&iter.second.ID);}
Shader ResourceManager::loadShaderFromFile(constchar* vShaderFile,constchar* fShaderFile,constchar* gShaderFile){// 1. retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::string geometryCode;try{// open files
std::ifstream vertexShaderFile(vShaderFile);
std::ifstream fragmentShaderFile(fShaderFile);
std::stringstream vShaderStream, fShaderStream;// read file's buffer contents into streams
vShaderStream << vertexShaderFile.rdbuf();
fShaderStream << fragmentShaderFile.rdbuf();// close file handlers
vertexShaderFile.close();
fragmentShaderFile.close();// convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();// if geometry shader path is present, also load a geometry shaderif(gShaderFile !=nullptr){
std::ifstream geometryShaderFile(gShaderFile);
std::stringstream gShaderStream;
gShaderStream << geometryShaderFile.rdbuf();
geometryShaderFile.close();
geometryCode = gShaderStream.str();}}catch(std::exception e){
std::cout <<"ERROR::SHADER: Failed to read shader files"<< std::endl;}constchar* vShaderCode = vertexCode.c_str();constchar* fShaderCode = fragmentCode.c_str();constchar* gShaderCode = geometryCode.c_str();// 2. now create shader object from source code
Shader shader;
shader.Compile(vShaderCode, fShaderCode, gShaderFile !=nullptr? gShaderCode :nullptr);return shader;}
Texture2D ResourceManager::loadTextureFromFile(constchar* file,bool alpha){// create texture object
Texture2D texture;if(alpha){
texture.Internal_Format = GL_RGBA;
texture.Image_Format = GL_RGBA;}// load imageint width, height, nrChannels;unsignedchar* data =stbi_load(file,&width,&height,&nrChannels,0);// now generate texture
texture.Generate(width, height, data);// and finally free image datastbi_image_free(data);return texture;}