|
|
@@ -1,265 +0,0 @@
|
|
|
-//
|
|
|
-// 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/material.hpp"
|
|
|
-#include "game/graphics/shader.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 &);
|
|
|
-}
|
|
|
-
|
|
|
-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, 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 id;
|
|
|
- }
|
|
|
-
|
|
|
- unsigned int init(identity<shader> const & fragmentShader,
|
|
|
- identity<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) {
|
|
|
- // print_shader_program_error(id, fragmentShader.actual().path,
|
|
|
- // vertexShader.actual().path);
|
|
|
- throw linker_error("Could not link shader program");
|
|
|
- }
|
|
|
- return id;
|
|
|
- }
|
|
|
-
|
|
|
- void activate(identity<shader_program> program) {
|
|
|
- // 100. Use the shader program ID to "turn it on" for all subsequent drawing
|
|
|
- glUseProgram(program.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(program.id, "u_time");
|
|
|
- int scale = glGetUniformLocation(program.id, "Scale");
|
|
|
- int diffuseMap = glGetUniformLocation(program.id, "u_diffuseMap");
|
|
|
- int normalMap = glGetUniformLocation(program.id, "u_normalMap");
|
|
|
- int specularMap = glGetUniformLocation(program.id, "u_specularMap");
|
|
|
- int emissiveMap = glGetUniformLocation(program.id, "u_emissiveMap");
|
|
|
- int debugWave = glGetUniformLocation(program.id, "g_debugWave");
|
|
|
-
|
|
|
- // 103. Set the uniform values, including the texture unit numbers for
|
|
|
- // texture (sampler) uniforms
|
|
|
- // Env::GetCurrentTimeSeconds()
|
|
|
- glUniform1f(timeUniformLocation, env::clock::current_time<float>());
|
|
|
- glUniform1f(scale, 2.f);
|
|
|
- glUniform1i(debugWave, 1); // TODO: m_waveEffectOn in ShaderProgram??
|
|
|
- // for GL_TEXTURE0, texture unit 0
|
|
|
- glUniform1i(diffuseMap, 0);
|
|
|
- // for GL_TEXTURE1, texture unit 1
|
|
|
- glUniform1i(normalMap, 1);
|
|
|
- // for GL_TEXTURE2, texture unit 2
|
|
|
- glUniform1i(specularMap, 2);
|
|
|
- // for GL_TEXTURE3, texture unit 3
|
|
|
- glUniform1i(emissiveMap, 3);
|
|
|
- }
|
|
|
-
|
|
|
- int uniform_location(identity<shader_program> program,
|
|
|
- std::string const & uniform) {
|
|
|
- return glGetUniformLocation(program.id, uniform.c_str());
|
|
|
- }
|
|
|
-}}
|
|
|
-
|
|
|
-namespace graphics { namespace materials {
|
|
|
- void activate(identity<shader_program> program,
|
|
|
- std::vector<uniform> const & uniforms) {
|
|
|
- glUseProgram(program.id);
|
|
|
-
|
|
|
- for (unsigned int i = 0; i < uniforms.size(); i++) {
|
|
|
- const uniform & uniform = uniforms[i];
|
|
|
- glActiveTexture(i + GL_TEXTURE0);
|
|
|
- // glEnable(GL_TEXTURE_2D);
|
|
|
- glBindTexture(GL_TEXTURE_2D, uniform.texture.id);
|
|
|
- glUniform1i(uniform.uniform_id, i);
|
|
|
- }
|
|
|
-
|
|
|
- glActiveTexture(GL_TEXTURE0);
|
|
|
- }
|
|
|
-}}
|