diff options
Diffstat (limited to 'src/gl/draw.h')
-rw-r--r-- | src/gl/draw.h | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/src/gl/draw.h b/src/gl/draw.h new file mode 100644 index 0000000..13deb43 --- /dev/null +++ b/src/gl/draw.h @@ -0,0 +1,217 @@ +// Copyright 2021, 2022 Benjamin Barenblat +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +// Drawing to the framebuffer. + +#ifndef GLPLANET_SRC_GL_DRAW_H_ +#define GLPLANET_SRC_GL_DRAW_H_ + +#include <Eigen/Core> +#include <initializer_list> +#include <stdexcept> + +#include "src/gl/buffer.h" +#include "src/gl/error.h" +#include "src/gl/shader.h" +#include "src/gl/texture.h" +#include "src/gl/vertex_array.h" +#include "third_party/glew/include/GL/glew.h" + +namespace gl { + +// Makes the specified shader program active. +inline void SetActiveShaderProgram(ShaderProgram& program) { + gl_internal::CheckThreadSafety(); + glUseProgram(program.id()); + // This error check is necessary because glUseProgram can fail. + gl_internal::ErrorCheck(); +} + +// RAII version of the above: While live, makes the specified shader program +// active. +class ActiveShaderProgram final { + public: + explicit ActiveShaderProgram(ShaderProgram& program) { + gl_internal::CheckThreadSafety(); + glGetIntegerv(GL_CURRENT_PROGRAM, &old_); + gl_internal::UnnecessaryErrorCheck(); + SetActiveShaderProgram(program); + } + + ActiveShaderProgram(const ActiveShaderProgram&) = delete; + ActiveShaderProgram& operator=(const ActiveShaderProgram&) = delete; + + ~ActiveShaderProgram() { + gl_internal::CheckThreadSafety(); + glUseProgram(old_); + // This error check is necessary because glUseProgram can fail. + gl_internal::ErrorCheck(); + } + + private: + GLint old_; +}; + +// Sets the specified uniform in the active shader. Throws std::logic_error in +// the event of a type error (e.g., you set a mat4 uniform to a single integer). +inline void SetActiveShaderUniform(int index, int v0) { + gl_internal::CheckThreadSafety(); + glUniform1i(index, v0); + // This error check is necessary because the shader variable might have a + // different type than was passed in. + gl_internal::ErrorCheck(); +} +inline void SetActiveShaderUniform(int index, const Eigen::Vector2f& value) { + gl_internal::CheckThreadSafety(); + glUniform2fv(index, /*count=*/1, value.data()); + // This error check is necessary because the shader variable might have a + // different type than was passed in. + gl_internal::ErrorCheck(); +} +inline void SetActiveShaderUniform(int index, const Eigen::Vector3f& value) { + gl_internal::CheckThreadSafety(); + glUniform3fv(index, /*count=*/1, value.data()); + // This error check is necessary because the shader variable might have a + // different type than was passed in. + gl_internal::ErrorCheck(); +} +inline void SetActiveShaderUniform(int index, const Eigen::Matrix4f& value) { + gl_internal::CheckThreadSafety(); + glUniformMatrix4fv(index, /*count=*/1, /*transpose=*/GL_FALSE, value.data()); + // This error check is necessary because the shader variable might have a + // different type than was passed in. + gl_internal::ErrorCheck(); +} + +// Binds the specified VAO. +inline void BindVertexArray(const VertexArray& vao) noexcept( + !(gl_internal::kThreadSafetyChecks || + gl_internal::kAggressiveErrorChecking)) { + gl_internal::CheckThreadSafety(); + glBindVertexArray(vao.id()); + gl_internal::UnnecessaryErrorCheck(); +} + +// RAII version of the above: While live, binds the specified VAO. +class BoundVertexArray final { + public: + explicit BoundVertexArray(const VertexArray& vao) noexcept( + !(gl_internal::kThreadSafetyChecks || + gl_internal::kAggressiveErrorChecking)) { + gl_internal::CheckThreadSafety(); + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_); + gl_internal::UnnecessaryErrorCheck(); + BindVertexArray(vao); + } + + BoundVertexArray(const BoundVertexArray&) = delete; + BoundVertexArray& operator=(const BoundVertexArray&) = delete; + + ~BoundVertexArray() noexcept(!(gl_internal::kThreadSafetyChecks || + gl_internal::kAggressiveErrorChecking)) { + gl_internal::CheckThreadSafety(); + glBindVertexArray(old_); + gl_internal::UnnecessaryErrorCheck(); + } + + private: + GLint old_; +}; + +// Sets the current texture unit. +inline void UseTextureUnit(int unit) { + gl_internal::CheckThreadSafety(); + glActiveTexture(GL_TEXTURE0 + unit); + // This error check is necessary because the user might have passed in a + // too-large index for the texture unit. + gl_internal::ErrorCheck(); +} + +// Binds the specified 2D texture. +inline void BindTexture2d(const Texture2d& tex) noexcept( + !(gl_internal::kThreadSafetyChecks || + gl_internal::kAggressiveErrorChecking)) { + gl_internal::CheckThreadSafety(); + glBindTexture(GL_TEXTURE_2D, tex.id()); + gl_internal::UnnecessaryErrorCheck(); +} + +// RAII version of the above: While live, binds the specified 2D texture. +class BoundTexture2d final { + public: + explicit BoundTexture2d(const Texture2d& tex) noexcept( + !(gl_internal::kThreadSafetyChecks || + gl_internal::kAggressiveErrorChecking)) { + gl_internal::CheckThreadSafety(); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_); + gl_internal::UnnecessaryErrorCheck(); + BindTexture2d(tex); + } + + BoundTexture2d(const BoundTexture2d&) = delete; + BoundTexture2d& operator=(const BoundTexture2d&) = delete; + + ~BoundTexture2d() noexcept(!(gl_internal::kThreadSafetyChecks || + gl_internal::kAggressiveErrorChecking)) { + gl_internal::CheckThreadSafety(); + glBindTexture(GL_TEXTURE_2D, old_); + gl_internal::UnnecessaryErrorCheck(); + } + + private: + GLint old_; +}; + +enum class GlBuffer : GLenum { + kColor = GL_COLOR_BUFFER_BIT, + kDepth = GL_DEPTH_BUFFER_BIT, + kStencil = GL_STENCIL_BUFFER_BIT, +}; + +inline void Clear(const std::initializer_list<GlBuffer>& buffers) noexcept( + !(gl_internal::kThreadSafetyChecks || + gl_internal::kAggressiveErrorChecking)) { + gl_internal::CheckThreadSafety(); + + GLenum mask = 0; + for (GlBuffer b : buffers) { + mask |= FromEnum(b); + } + glClear(mask); + gl_internal::UnnecessaryErrorCheck(); +} + +enum class Primitive : GLenum { + kPoints = GL_POINTS, + kLineStrip = GL_LINE_STRIP, + kLineLoop = GL_LINE_LOOP, + kLines = GL_LINES, + kLineStripAdjacency = GL_LINE_STRIP_ADJACENCY, + kLinesAdjacency = GL_LINES_ADJACENCY, + kTriangleStrip = GL_TRIANGLE_STRIP, + kTriangleFan = GL_TRIANGLE_FAN, + kTriangles = GL_TRIANGLES, + kTriangleStripAdjacency = GL_TRIANGLE_STRIP_ADJACENCY, + kTrianglesAdjacency = GL_TRIANGLES_ADJACENCY, + kPatches = GL_PATCHES, +}; + +// Draws the elements from the specified VAO. The VAO must already be bound. +void DrawElements(const gl::VertexArray&, Primitive); + +void SetViewport(int x, int y, int width, int height); + +} // namespace gl + +#endif // GLPLANET_SRC_GL_DRAW_H_ |