| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- //
- // helper.cxx
- // graphics
- //
- // Created by Sam Jaffe on 5/18/19.
- // Copyright © 2019 Sam Jaffe. All rights reserved.
- //
- #include "helper.hpp"
- #include <iostream>
- #include <memory>
- #include <sstream>
- #ifdef __APPLE__
- #include <OpenGL/gl3.h>
- #endif
- #include "scope_guard/scope_guard.hpp"
- #include "vector/vector.hpp"
- #include "game/graphics/shader.hpp"
- #include "game/util/env.hpp"
- #include "game/util/files.hpp"
- namespace {
- typedef void (*GLGetIntFor)(GLuint, GLenum, GLint *);
- typedef void (*GLGetLog)(GLuint, GLsizei, GLsizei *, GLchar *);
- struct opengl_error_formatter {
- void operator()() const;
- static void shader_error(GLuint id, std::string const & path);
- GLuint obj;
- std::string fileName, path, eNoticeMessage, eFileMessage, eWindowTitle;
- GLGetIntFor getIntv;
- GLGetLog getInfoLog;
- };
- void opengl_error_formatter::operator()() const {
- std::stringstream errorString;
- std::string errorLineNumber;
- int infologLength = 0;
- int maxLength = 0;
- getIntv(obj, GL_INFO_LOG_LENGTH, &maxLength);
- errorString << eNoticeMessage << "\n";
- std::unique_ptr<char[]> infoLog(new char[maxLength + 1]);
- getInfoLog(obj, maxLength, &infologLength, infoLog.get());
- std::string errorLog(infoLog.get());
- infoLog.reset();
- if (infologLength <= 0) return;
- std::size_t openParen = errorLog.find('(');
- std::size_t closeParen = errorLog.find(')');
- errorLineNumber =
- errorLog.substr(openParen + 1, closeParen - openParen - 1);
- errorString << fileName << " , "
- << "line " << errorLineNumber << ":\n";
- std::string errorStart = errorLog.find("error") != std::string::npos
- ? errorLog.substr(errorLog.find("error"))
- : errorLog;
- errorString << errorLog << "\n";
- errorString << "OpenGL Version: " << glGetString(GL_VERSION) << "\n";
- errorString << "GLSL Shading Version: "
- << glGetString(GL_SHADING_LANGUAGE_VERSION) << "\n";
- errorString << eFileMessage << "\n";
- errorString << "RAW ERROR LOG: " << errorLog;
- std::stringstream consoleOutput;
- consoleOutput << "1>" << path << '(' << errorLineNumber << ')' << ": "
- << errorStart
- << "in OpenGL version: " << glGetString(GL_VERSION) << " and "
- << "GLSL Shading Version: "
- << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
- #ifdef _WIN32
- OutputDebugStringA(consoleOutput.str().c_str());
- MessageBoxA(nullptr, errorString.str().c_str(), eWindowTitle.c_str(),
- MB_OK);
- #else
- std::cerr << consoleOutput.str() << std::endl;
- std::cerr << errorString.str() << std::endl;
- #endif
- }
- void opengl_error_formatter::shader_error(GLuint id,
- std::string const & path) {
- std::string fileName = path.substr(path.find_last_of("/"));
- opengl_error_formatter{id,
- fileName,
- path,
- "GLSL shader compile error!",
- "File location" + path,
- "GLSL Compile Error in " + fileName,
- glGetShaderiv,
- glGetShaderInfoLog}();
- }
- }
- namespace graphics { namespace textures {
- static int glfmt(format color_fmt) {
- switch (color_fmt) {
- case format::RGB:
- return GL_RGB;
- case format::RGBA:
- return GL_RGBA;
- }
- }
- unsigned int init(format color_fmt, math::vec2i dimension,
- void const * data) {
- unsigned int id;
- // Enable texturings
- // glEnable( GL_TEXTURE_2D );
- // Tell OpenGL that our pixel data is single-byte aligned
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- // Ask OpenGL for an unused texName (ID number) to use for this texture
- glGenTextures(1, &id);
- // Tell OpenGL to bind (set) this as the currently active texture
- glBindTexture(GL_TEXTURE_2D, id);
- // Set texture clamp vs. wrap (repeat)
- // one of: GL_CLAMP_TO_EDGE, GL_REPEAT, GL_MIRRORED_REPEAT,
- // GL_MIRROR_CLAMP_TO_EDGE, ...
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- // the format our source pixel data is currently in; any of: GL_RGB,
- // GL_RGBA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, ...
- int bufferFormat = glfmt(color_fmt);
- // the format we want the texture to me on the card; allows us to translate
- // into a different texture format as we upload to OpenGL
- int internalFormat = bufferFormat;
- /* glTexImage2D: Load a 2d texture image
- * target: Creating this as a 2d texture.
- * level: Which mipmap level to use as the "root" (0 = the highest-quality,
- * full-res image), if mipmaps are enabled.
- * internalFormat: Type of texel format we want OpenGL to use for this
- * texture internally on the video card.
- * width: Texel-width of image; for maximum compatibility, use 2^N + 2^B,
- * where N is some integer in the range [3,10], and B is the border
- * thickness [0,1]
- * height: Texel-height of image; for maximum compatibility, use 2^M + 2^B,
- * where M is some integer in the range [3,10], and B is the border
- * thickness [0,1]
- * border: Border size, in texels (must be 0 or 1)
- * format: Pixel format describing the composition of the pixel data in
- * buffer
- * type: Pixel color components are unsigned bytes (one byte per color/alpha
- * channel)
- * pixels: Location of the actual pixel data bytes/buffer
- */
- glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, dimension.x(), dimension.y(),
- 0, bufferFormat, GL_UNSIGNED_BYTE, data);
- glGenerateMipmap(GL_TEXTURE_2D);
- // Set magnification (texel > pixel) and minification (texel < pixel)
- // filters one of: GL_NEAREST, GL_LINEAR
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- // one of: GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST,
- // GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST,
- // GL_LINEAR_MIPMAP_LINEAR
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- GL_NEAREST_MIPMAP_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5);
- return id;
- }
- }}
- namespace graphics { namespace shaders {
- struct file_read_error : std::runtime_error {
- using std::runtime_error::runtime_error;
- };
- struct compilation_error : std::runtime_error {
- using std::runtime_error::runtime_error;
- };
- struct linker_error : std::runtime_error {
- using std::runtime_error::runtime_error;
- };
- static int gltype(type tp) {
- switch (tp) {
- case type::FRAGMENT:
- return GL_FRAGMENT_SHADER;
- case type::VERTEX:
- return GL_VERTEX_SHADER;
- }
- }
- unsigned int init(type tp, std::string const & path) {
- std::unique_ptr<char const[]> buffer;
- // 1. Load the vertex shader code (text file) to a new memory buffer
- std::string const abs_path = env::resource_file(path);
- if ((buffer = files::load(abs_path))) {
- throw file_read_error("Could not load shader file " + abs_path);
- }
- // 2. Create a new shader ID
- // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
- unsigned int id = glCreateShader(gltype(tp));
- // 3. Associate the shader code with the new shader ID
- char const * buffer_ptr = buffer.get();
- glShaderSource(id, 1, &buffer_ptr, nullptr);
- // 4. Compile the shader (the shader compiler is built in to your graphics
- // card driver)
- glCompileShader(id);
- // 5. Check for compile errors
- int return_code;
- glGetShaderiv(id, GL_COMPILE_STATUS, &return_code);
- if (return_code != GL_TRUE) {
- opengl_error_formatter::shader_error(id, abs_path);
- throw compilation_error("Could not compile the shader file");
- }
- return id;
- }
- unsigned int init_program(shader const & fragmentShader,
- shader const & vertexShader) {
- // 9. Create a new shader program ID
- unsigned int id = glCreateProgram();
- // 10. Attach the vertex and fragment shaders to the new shader program
- glAttachShader(id, vertexShader.id);
- glAttachShader(id, fragmentShader.id);
- // 11. Do some other advanced stuff we'll do later on (like setting generic
- // vertex attrib locations)
- glBindAttribLocation(id, 0, "a_position");
- glBindAttribLocation(id, 1, "a_color");
- glBindAttribLocation(id, 2, "a_texCoords");
- glBindAttribLocation(id, 3, "a_normal");
- // 12. Link the program
- glLinkProgram(id);
- // 13. Check for link errors
- int return_code;
- glGetProgramiv(id, GL_LINK_STATUS, &return_code);
- if (return_code != GL_TRUE) {
- // LogShaderProgramError(*id, vertPath, fragPath);
- throw linker_error("Could not link shader program");
- }
- return id;
- }
- void activate(unsigned int id) {
- // 100. Use the shader program ID to "turn it on" for all subsequent drawing
- glUseProgram(id);
- /*
- // 101. Enable texturing and Bind texture(s) to GPU texture units
- glActiveTexture(GL_TEXTURE3);
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, emissiveTextureID);
- glActiveTexture(GL_TEXTURE2);
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, specularTextureID);
- glActiveTexture(GL_TEXTURE1);
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, normalTextureID);
- glActiveTexture(GL_TEXTURE0);
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, diffuseTextureID);
- */
- // 102. Get the location # of each named uniform you wish to pass in to the
- // shader
- int timeUniformLocation = glGetUniformLocation(id, "u_time");
- int scale = glGetUniformLocation(id, "Scale");
- int diffuseMapUniformLocation = glGetUniformLocation(id, "u_diffuseMap");
- int normalMapUniformLocation = glGetUniformLocation(id, "u_normalMap");
- int specularMapUniformLocation = glGetUniformLocation(id, "u_specularMap");
- int emissiveMapUniformLocation = glGetUniformLocation(id, "u_emissiveMap");
- int debugWave = glGetUniformLocation(id, "g_debugWave");
- // 103. Set the uniform values, including the texture unit numbers for
- // texture (sampler) uniforms
- // Env::GetCurrentTimeSeconds()
- glUniform1f(timeUniformLocation, (float)time(NULL));
- glUniform1f(scale, 2.f);
- glUniform1i(debugWave, 1); // TODO: m_waveEffectOn in ShaderProgram??
- // for GL_TEXTURE0, texture unit 0
- glUniform1i(diffuseMapUniformLocation, 0);
- // for GL_TEXTURE1, texture unit 1
- glUniform1i(normalMapUniformLocation, 1);
- // for GL_TEXTURE2, texture unit 2
- glUniform1i(specularMapUniformLocation, 2);
- // for GL_TEXTURE3, texture unit 3
- glUniform1i(emissiveMapUniformLocation, 3);
- }
- }}
|