| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- //
- // helper.cxx
- // graphics
- //
- // Created by Sam Jaffe on 5/18/19.
- // Copyright © 2019 Sam Jaffe. All rights reserved.
- //
- #include "helper.hpp"
- #include "opengl_renderer.h"
- #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/exception.h"
- #include "game/graphics/material.hpp"
- #include "game/graphics/shader.hpp"
- #include "game/graphics/shader_program.hpp"
- #include "game/graphics/texture.hpp"
- #include "game/util/env.hpp"
- #include "game/util/files.hpp"
- #include "game/util/time.hpp"
- namespace graphics {
- extern void print_shader_error(GLuint, std::string const &);
- extern void print_shader_program_error(GLuint, std::string const &,
- std::string const &);
- struct compilation_error : std::runtime_error {
- using std::runtime_error::runtime_error;
- };
- struct linker_error : std::runtime_error {
- using std::runtime_error::runtime_error;
- };
- }
- using namespace graphics;
- namespace {
- int glfmt(textures::format color_fmt) {
- switch (color_fmt) {
- case textures::format::RGB:
- return GL_RGB;
- case textures::format::RGBA:
- return GL_RGBA;
- }
- }
- int gltype(shaders::type tp) {
- switch (tp) {
- case shaders::type::FRAGMENT:
- return GL_FRAGMENT_SHADER;
- case shaders::type::VERTEX:
- return GL_VERTEX_SHADER;
- }
- }
- }
- texture opengl_manager::compile(textures::format color, math::vec2i size,
- void const * buffer) const {
- // textures::external_data data(env::resource_file(path));
- // 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);
- // 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, size.x(), size.y(), 0,
- bufferFormat, GL_UNSIGNED_BYTE, buffer);
- 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 texture{id, size};
- }
- shader opengl_manager::compile(shaders::type tp,
- std::string const & path) const {
- 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("shader", 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, NULL);
- // 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) {
- print_shader_error(id, abs_path);
- throw compilation_error("Could not compile the shader file");
- }
- return shader{id, tp, path};
- }
- shader_program opengl_manager::compile(identity<shader> fragmentShader,
- identity<shader> vertexShader) const {
- // 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) {
- // print_shader_program_error(id, fragmentShader.actual().path,
- // vertexShader.actual().path);
- throw linker_error("Could not link shader program");
- }
- return shader_program{id, fragmentShader, vertexShader};
- }
- opengl_uniform_data & opengl_manager::data(identity<shader_program> program) {
- auto & data = data_[program];
- // TODO: perform this in compile()
- if (data.uniform_id.empty()) {
- glUseProgram(program.id);
- using materials::uniform;
- data.uniform_id = {
- {uniform::NORMAL, glGetUniformLocation(program.id, "u_normalMap")},
- {uniform::DIFFUSE, glGetUniformLocation(program.id, "u_diffuseMap")},
- {uniform::SPECULAR, glGetUniformLocation(program.id, "u_specularMap")}};
- }
- return data;
- }
|