From d0e18bdb7924c71cdca8dd983711171d87ef28be Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Mon, 17 Jan 2022 23:12:32 -0500 Subject: glplanet, an OpenGL-based planetary renderer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit glplanet draws Earth like it currently appears from space, putting nighttime areas in shadow and daytime areas in light. It’s modeled after Xplanet (http://xplanet.sourceforge.net/), but whereas Xplanet is entirely a CPU-resident program, glplanet draws using OpenGL. It’s thus much less resource-intensive, particularly when using high-resolution textures. --- src/gl/shader.h | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 src/gl/shader.h (limited to 'src/gl/shader.h') diff --git a/src/gl/shader.h b/src/gl/shader.h new file mode 100644 index 0000000..b4cfb63 --- /dev/null +++ b/src/gl/shader.h @@ -0,0 +1,211 @@ +// Copyright 2021 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. + +// Shaders and shader programs. + +#ifndef GLPLANET_SRC_GL_SHADER_H_ +#define GLPLANET_SRC_GL_SHADER_H_ + +#include +#include + +#include "src/gl/error.h" +#include "third_party/abseil/absl/strings/string_view.h" +#include "third_party/glew/include/GL/glew.h" + +namespace gl { + +class FragmentShader; +class VertexShader; + +// An individual shader. +// +// The shader life cycle looks like this: +// +// Shader s; +// s.SetSource(source_location); +// s.Compile(); +// std::cerr << s.compile_log(); +// +// The Compile function throws if errors occur during compilation, but warnings +// are merely saved. You must retrieve the compilation log if you wish to report +// warnings. +class Shader { + public: + Shader(Shader&&) noexcept = default; + Shader& operator=(Shader&&) noexcept = default; + + virtual ~Shader() noexcept(!(gl_internal::kThreadSafetyChecks || + gl_internal::kAggressiveErrorChecking)) { + gl_internal::CheckThreadSafety(); + glDeleteShader(shader_); + gl_internal::UnnecessaryErrorCheck(); + } + + // Loads the shader source. This function copies the source buffer, so the + // source buffer need not stay valid after this call. + // + // You may call this function repeatedly. Doing so invalidates the shader, and + // you must recompile it with Compile before using it. + void SetSource(absl::string_view source); + + // Compiles the shader. Throws a std::runtime_error including the compilation + // log if compilation fails. If compilation succeeds but generates warnings, + // this function silently returns; check the compile_log member to see what + // the warnings were. + // + // You must call SetSource before calling this function. + // + // You may call this function repeatedly. + void Compile(); + + // Fetches the shader compilation log. If this is empty, there were no + // warnings during the compilation. + // + // You must call Compile before calling this function. + // + // You may call this function repeatedly. + const std::string& compile_log() const; + + // The GL identifier for this shader. + unsigned int id() const noexcept { return shader_; } + + protected: + GLuint shader_; + bool source_set_; + bool compile_attempted_; + std::string compile_log_; + + private: + friend class FragmentShader; + friend class VertexShader; + + explicit Shader(GLenum type); +}; + +// A fragment shader. +class FragmentShader final : public Shader { + public: + explicit FragmentShader() : Shader(GL_FRAGMENT_SHADER) {} +}; + +// A vertex shader. +class VertexShader final : public Shader { + public: + explicit VertexShader() : Shader(GL_VERTEX_SHADER) {} +}; + +// A shader program consisting of multiple shaders. +// +// The shader program life cycle looks like this: +// +// ShaderProgram p; +// p.attach(s); +// p.SetFragmentDataLocation("output_color", framebuffer_id); +// p.Link(); +// std::cerr << s.link_log(); +// DoSomethingWith(p.active_vertex_attribute("whatever")); +// +// Analogously to Shader::Compile, Link throws if errors occur during linking, +// but warnings are merely saved. You must retrieve the link log if you wish to +// report warnings. +class ShaderProgram final { + public: + explicit ShaderProgram(); + + ShaderProgram(ShaderProgram&&) noexcept = default; + ShaderProgram& operator=(ShaderProgram&&) noexcept = default; + + ~ShaderProgram() noexcept(!(gl_internal::kThreadSafetyChecks || + gl_internal::kAggressiveErrorChecking)) { + gl_internal::CheckThreadSafety(); + glDeleteProgram(program_); + gl_internal::UnnecessaryErrorCheck(); + } + + // Attach shaders to the program. The shaders need not be compiled, but you + // must compile them before calling Link. + // + // You may call these functions repeatedly, so long as you never pass the same + // shader twice. In any case, calling these functions invalidates the program, + // and you must relink it with Link before using it. + void Attach(const VertexShader& shader) { AttachShader(shader); } + void Attach(const FragmentShader& shader) { + AttachShader(shader); + has_fragment_shader_ = true; + } + + // Associates a fragment shader output variable with an output framebuffer. + // The variable name must not start with "gl_". The default framebuffer has ID + // 0. + // + // You must have a fragment shader attached to this program to call this + // function. + // + // You may call this function repeatedly. Doing so invalidates the program, + // and you must relink it with Link before using it. + void SetFragmentDataLocation(const char* name, int framebuffer_id); + + // Links the shader program. Throws a std::runtime_error including the link + // log if linking fails. If linking succeeds but generates warnings, this + // function silently returns; check the link_log member to see what the + // warnings were. + // + // You may call this function repeatedly. + void Link(); + + // Fetches the program link log. If this is empty, there were no warnings + // during the link. + // + // You must call Link before calling this function. + // + // You may call this function repeatedly. + const std::string& link_log() const; + + // The index of the specified active vertex attribute. The variable name must + // not start with "gl_". + // + // Throws std::invalid_argument if the specified name is reserved, inactive, + // or nonexistent. Throws std::logic_error if the program has not been linked. + int active_vertex_attribute(const char* name) const; + + // The index of the specified active uniform variable. The variable name must + // not start with "gl_". + // + // Throws std::invalid_argument if the specified name is reserved, inactive, + // or nonexistent. Throws std::logic_error if the program has not been linked. + int active_uniform(const char* name) const; + + // The GL identifier for this program. + unsigned int id() const noexcept { return program_; } + + private: + void AttachShader(const Shader& shader) { + gl_internal::CheckThreadSafety(); + glAttachShader(program_, shader.id()); + // This error check is necessary because the user might have passed in the + // same shader twice. + gl_internal::ErrorCheck(); + link_attempted_ = false; + } + + GLuint program_; + bool has_fragment_shader_; + bool link_attempted_; + std::string link_log_; +}; + +} // namespace gl + +#endif // GLPLANET_SRC_GL_SHADER_H_ -- cgit v1.2.3