├── include ├── gl.h ├── get_seconds.h ├── STR.h ├── print_opengl_info.h ├── print_program_info_log.h ├── load_shader.h ├── find_and_replace_all.h ├── mesh_to_vao.h ├── last_modification_time.h ├── icosahedron.h ├── print_shader_info_log.h ├── REDRUM.h ├── read_json.h ├── report_gl_error.h └── create_shader_program_from_files.h ├── src ├── PI.glsl ├── pass-through.vs ├── version410.glsl ├── pass-through.fs ├── pass-through.tes ├── identity.glsl ├── translate.glsl ├── blue_and_gray.fs ├── pass-through.tcs ├── uniform_scale.glsl ├── tangent.glsl ├── rotate_about_y.glsl ├── smooth_heaviside.glsl ├── interpolate.glsl ├── perlin_noise.glsl ├── improved_perlin_noise.glsl ├── random_direction.glsl ├── bump_height.glsl ├── model.glsl ├── random2.glsl ├── lit.fs ├── procedural_color.fs ├── smooth_step.glsl ├── bump_position.glsl ├── 5.tcs ├── blinn_phong.glsl ├── improved_smooth_step.glsl ├── bump.fs ├── planet.fs ├── model_view_projection.vs └── snap_to_sphere.tes ├── images ├── earth.gif ├── test-01.png ├── test-02.gif ├── test-04.gif ├── test-05.gif ├── test-06.gif ├── test-07.gif ├── test-08.gif ├── bool-debug.png ├── normal-debug.png ├── distance-debug.png ├── position-debug.png ├── test-02-wireframe.gif └── test-03-wireframe.gif ├── .gitmodules ├── glad ├── CMakeLists.txt └── include │ └── KHR │ └── khrplatform.h ├── data ├── test-01.json ├── test-04.json ├── test-03.json ├── test-02.json ├── test-05.json ├── test-06.json ├── test-07.json └── test-08.json ├── .gitignore ├── file_watcher.cpp ├── CMakeLists.txt ├── tex ├── 02f380174e367c8935a57f86907fc7da.svg ├── b56595d2a30a0af329086562ca12d521.svg ├── ff44d867a998c08241beb49b30148782.svg ├── 1926c401973f24b4db4f35dca2eb381d.svg ├── 980fcd4213d7b5d2ffcc82ec78c27ead.svg ├── df092db5465f28cad5cd98f89fa50dd9.svg ├── 2ad9d098b937e46f9f58968551adac57.svg ├── 509fb6a370666a6736bbb7ab34494d6f.svg ├── b83d238e84b2e2204d33e3b6bbeecc2f.svg ├── e9b7c44ac040760328d11f2e7d436527.svg ├── 599a5166ad0520501c5d389abb0f34b8.svg ├── 6fd1684d4ead55dc193d5263233c0a57.svg ├── 3f9da50841370c429266d54ea7e41469.svg ├── ef68da33e858695fb6fa1867bc04cd31.svg ├── 15fe178ff3c20f9ccaf122aa40408229.svg ├── 2dbb3b571269b3589a2967f510e6ecbb.svg ├── 3dc6bff3f146e4a70a9167b7adfb75d0.svg └── 3e7a34f47d2caa11d496d74347a18799.svg ├── markdown └── header.md ├── css ├── style.css └── github-markdown.css └── main.cpp /include/gl.h: -------------------------------------------------------------------------------- 1 | #ifndef GL_H 2 | #define GL_H 3 | #include 4 | #endif 5 | -------------------------------------------------------------------------------- /src/PI.glsl: -------------------------------------------------------------------------------- 1 | // Half the circumference of a unit circle 2 | #define M_PI 3.1415926535897932384626433 3 | -------------------------------------------------------------------------------- /images/earth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/earth.gif -------------------------------------------------------------------------------- /images/test-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/test-01.png -------------------------------------------------------------------------------- /images/test-02.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/test-02.gif -------------------------------------------------------------------------------- /images/test-04.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/test-04.gif -------------------------------------------------------------------------------- /images/test-05.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/test-05.gif -------------------------------------------------------------------------------- /images/test-06.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/test-06.gif -------------------------------------------------------------------------------- /images/test-07.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/test-07.gif -------------------------------------------------------------------------------- /images/test-08.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/test-08.gif -------------------------------------------------------------------------------- /src/pass-through.vs: -------------------------------------------------------------------------------- 1 | in vec4 pos_vs_in; 2 | out vec4 pos_cs_in; 3 | void main() 4 | { 5 | pos_cs_in = pos_vs_in; 6 | } 7 | -------------------------------------------------------------------------------- /images/bool-debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/bool-debug.png -------------------------------------------------------------------------------- /images/normal-debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/normal-debug.png -------------------------------------------------------------------------------- /images/distance-debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/distance-debug.png -------------------------------------------------------------------------------- /images/position-debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/position-debug.png -------------------------------------------------------------------------------- /images/test-02-wireframe.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/test-02-wireframe.gif -------------------------------------------------------------------------------- /images/test-03-wireframe.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alecjacobson/computer-graphics-shader-pipeline/HEAD/images/test-03-wireframe.gif -------------------------------------------------------------------------------- /src/version410.glsl: -------------------------------------------------------------------------------- 1 | #version 410 core 2 | // We're using version 4.10. This should always be the first file listed and no 3 | // other files should attempt to specify a version. 4 | -------------------------------------------------------------------------------- /src/pass-through.fs: -------------------------------------------------------------------------------- 1 | in vec4 pos_fs_in; 2 | out vec3 color; 3 | void main() 4 | { 5 | // Set color to screen position to show something 6 | color = 0.5+0.5*pos_fs_in.xyz; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "eigen"] 2 | path = eigen 3 | url = https://github.com/eigenteam/eigen-git-mirror 4 | [submodule "glfw"] 5 | path = glfw 6 | url = https://github.com/glfw/glfw.git 7 | -------------------------------------------------------------------------------- /glad/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(glad) 3 | 4 | add_library(glad src/glad.c) 5 | target_include_directories(glad PUBLIC include) 6 | 7 | if(NOT WIN32) 8 | target_link_libraries(glad PUBLIC ${CMAKE_DL_LIBS}) 9 | endif() 10 | -------------------------------------------------------------------------------- /src/pass-through.tes: -------------------------------------------------------------------------------- 1 | layout(triangles, equal_spacing, ccw) in; 2 | in vec4 pos_es_in[]; 3 | out vec4 pos_fs_in; 4 | // expects: interpolate 5 | void main() 6 | { 7 | pos_fs_in = interpolate(gl_TessCoord,pos_es_in[0], pos_es_in[1], pos_es_in[2]); 8 | gl_Position = pos_fs_in; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /data/test-01.json: -------------------------------------------------------------------------------- 1 | { 2 | "vertex": [ "../src/version410.glsl","../src/pass-through.vs"], 3 | "tess_control": [ "../src/version410.glsl","../src/pass-through.tcs"], 4 | "tess_evaluation": [ "../src/version410.glsl","../src/interpolate.glsl","../src/pass-through.tes"], 5 | "fragment": [ "../src/version410.glsl","../src/pass-through.fs"] 6 | } 7 | -------------------------------------------------------------------------------- /include/get_seconds.h: -------------------------------------------------------------------------------- 1 | #ifndef GET_SECONDS_H 2 | #define GET_SECONDS_H 3 | // Return current epoch time in seconds 4 | double get_seconds(); 5 | 6 | // Implementation 7 | #include 8 | double get_seconds() 9 | { 10 | return 11 | std::chrono::duration( 12 | std::chrono::system_clock::now().time_since_epoch()).count(); 13 | } 14 | #endif 15 | -------------------------------------------------------------------------------- /src/identity.glsl: -------------------------------------------------------------------------------- 1 | // Return a 4x4 identity matrix 2 | mat4 identity() 3 | { 4 | ///////////////////////////////////////////////////////////////////////////// 5 | // Replace with your code 6 | return mat4( 7 | 0,0,0,0, 8 | 0,0,0,0, 9 | 0,0,0,0, 10 | 0,0,0,0); 11 | ///////////////////////////////////////////////////////////////////////////// 12 | } 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/translate.glsl: -------------------------------------------------------------------------------- 1 | // Inputs: 2 | // t 3D vector by which to translate 3 | // Return a 4x4 matrix that translates and 3D point by the given 3D vector 4 | mat4 translate(vec3 t) 5 | { 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // Replace with your code 8 | return identity(); 9 | ///////////////////////////////////////////////////////////////////////////// 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/blue_and_gray.fs: -------------------------------------------------------------------------------- 1 | // Set the pixel color to blue or gray depending on is_moon. 2 | // 3 | // Uniforms: 4 | uniform bool is_moon; 5 | // Outputs: 6 | out vec3 color; 7 | void main() 8 | { 9 | ///////////////////////////////////////////////////////////////////////////// 10 | // Replace with your code: 11 | color = vec3(1,1,1); 12 | ///////////////////////////////////////////////////////////////////////////// 13 | } 14 | -------------------------------------------------------------------------------- /src/pass-through.tcs: -------------------------------------------------------------------------------- 1 | layout (vertices = 3) out; 2 | 3 | in vec4 pos_cs_in[]; 4 | out vec4 pos_es_in[]; 5 | 6 | void main() 7 | { 8 | // Calculate the tess levels 9 | if(gl_InvocationID == 0) 10 | { 11 | gl_TessLevelOuter[0] = 1; 12 | gl_TessLevelOuter[1] = 1; 13 | gl_TessLevelOuter[2] = 1; 14 | gl_TessLevelInner[0] = 1; 15 | } 16 | pos_es_in[gl_InvocationID] = pos_cs_in[gl_InvocationID]; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/uniform_scale.glsl: -------------------------------------------------------------------------------- 1 | // Inputs: 2 | // s amount to scale in all directions 3 | // Return a 4x4 matrix that scales and input 3D position/vector by s in all 3 4 | // directions. 5 | mat4 uniform_scale(float s) 6 | { 7 | ///////////////////////////////////////////////////////////////////////////// 8 | // Replace with your code 9 | return identity(); 10 | ///////////////////////////////////////////////////////////////////////////// 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/tangent.glsl: -------------------------------------------------------------------------------- 1 | // Input: 2 | // N 3D unit normal vector 3 | // Outputs: 4 | // T 3D unit tangent vector 5 | // B 3D unit bitangent vector 6 | void tangent(in vec3 N, out vec3 T, out vec3 B) 7 | { 8 | ///////////////////////////////////////////////////////////////////////////// 9 | // Replace with your code 10 | T = vec3(1,0,0); 11 | B = vec3(0,1,0); 12 | ///////////////////////////////////////////////////////////////////////////// 13 | } 14 | -------------------------------------------------------------------------------- /data/test-04.json: -------------------------------------------------------------------------------- 1 | { 2 | "vertex": [ "../src/version410.glsl","../src/pass-through.vs"], 3 | "tess_control": [ "../src/version410.glsl","../src/5.tcs"], 4 | "tess_evaluation": [ "../src/version410.glsl","../src/PI.glsl","../src/identity.glsl","../src/uniform_scale.glsl","../src/translate.glsl","../src/rotate_about_y.glsl","../src/interpolate.glsl","../src/model.glsl","../src/snap_to_sphere.tes"], 5 | "fragment": [ "../src/version410.glsl","../src/blue_and_gray.fs"] 6 | } 7 | 8 | -------------------------------------------------------------------------------- /data/test-03.json: -------------------------------------------------------------------------------- 1 | { 2 | "vertex": [ "../src/version410.glsl","../src/PI.glsl","../src/identity.glsl","../src/uniform_scale.glsl","../src/translate.glsl","../src/rotate_about_y.glsl","../src/model.glsl","../src/model_view_projection.vs"], 3 | "tess_control": [ "../src/version410.glsl","../src/5.tcs"], 4 | "tess_evaluation": [ "../src/version410.glsl","../src/interpolate.glsl","../src/pass-through.tes"], 5 | "fragment": [ "../src/version410.glsl","../src/blue_and_gray.fs"] 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/rotate_about_y.glsl: -------------------------------------------------------------------------------- 1 | // Inputs: 2 | // theta amount y which to rotate (in radians) 3 | // Return a 4x4 matrix that rotates a given 3D point/vector about the y-axis by 4 | // the given amount. 5 | mat4 rotate_about_y(float theta) 6 | { 7 | ///////////////////////////////////////////////////////////////////////////// 8 | // Replace with your code 9 | return identity(); 10 | ///////////////////////////////////////////////////////////////////////////// 11 | } 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | 31 | *.un~ 32 | *.swo 33 | *.swp 34 | build/* 35 | *.DS_Store 36 | file_watcher 37 | solution/* 38 | -------------------------------------------------------------------------------- /data/test-02.json: -------------------------------------------------------------------------------- 1 | { 2 | "vertex": [ "../src/version410.glsl","../src/PI.glsl","../src/identity.glsl","../src/uniform_scale.glsl","../src/translate.glsl","../src/rotate_about_y.glsl","../src/model.glsl","../src/model_view_projection.vs"], 3 | "tess_control": [ "../src/version410.glsl","../src/pass-through.tcs"], 4 | "tess_evaluation": [ "../src/version410.glsl","../src/interpolate.glsl","../src/pass-through.tes"], 5 | "fragment": [ "../src/version410.glsl","../src/blue_and_gray.fs"] 6 | } 7 | -------------------------------------------------------------------------------- /data/test-05.json: -------------------------------------------------------------------------------- 1 | { 2 | "vertex": [ "../src/version410.glsl","../src/pass-through.vs"], 3 | "tess_control": [ "../src/version410.glsl","../src/5.tcs"], 4 | "tess_evaluation": [ "../src/version410.glsl","../src/PI.glsl","../src/identity.glsl","../src/uniform_scale.glsl","../src/translate.glsl","../src/rotate_about_y.glsl","../src/interpolate.glsl","../src/model.glsl","../src/snap_to_sphere.tes"], 5 | "fragment": [ "../src/version410.glsl","../src/PI.glsl","../src/blinn_phong.glsl","../src/lit.fs"] 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/smooth_heaviside.glsl: -------------------------------------------------------------------------------- 1 | // A useful filter, behaves like a smoothly parameterized smooth Heaviside 2 | // function. 3 | // 4 | // Inputs: 5 | // x input scalar (-inf, inf) 6 | // t control steepness of step function: --> 0 more linear, --> inf more like 7 | // Heaviside function (piecewise constant function x<0--> -1 , x>0 --> 1) 8 | // Returns scalar value 9 | float smooth_heaviside( float x, float t) 10 | { 11 | return (1./(1.+exp(-2.*t*(x)))-1./2.)/(1./(1.+exp(-2.*t*1.))-1./2.); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/interpolate.glsl: -------------------------------------------------------------------------------- 1 | // Using gl_TessCoord interpolate between values stored at three corners of a 2 | // triangle. 3 | // 4 | // Inputs: 5 | // v0 value at corner 0 6 | // v1 value at corner 1 7 | // v2 value at corner 2 8 | // Return linearly interpolated value based on gl_TessCoord. 9 | vec3 interpolate(vec3 bary, vec3 v0, vec3 v1, vec3 v2) 10 | { 11 | return bary.x * v0 + bary.y * v1 + bary.z * v2; 12 | } 13 | vec4 interpolate(vec3 bary, vec4 v0, vec4 v1, vec4 v2) 14 | { 15 | return bary.x * v0 + bary.y * v1 + bary.z * v2; 16 | } 17 | -------------------------------------------------------------------------------- /src/perlin_noise.glsl: -------------------------------------------------------------------------------- 1 | // Given a 3d position as a seed, compute a smooth procedural noise 2 | // value: "Perlin Noise", also known as "Gradient noise". 3 | // 4 | // Inputs: 5 | // st 3D seed 6 | // Returns a smooth value between (-1,1) 7 | // 8 | // expects: random_direction, smooth_step 9 | float perlin_noise( vec3 st) 10 | { 11 | ///////////////////////////////////////////////////////////////////////////// 12 | // Replace with your code 13 | return 0; 14 | ///////////////////////////////////////////////////////////////////////////// 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/improved_perlin_noise.glsl: -------------------------------------------------------------------------------- 1 | // Given a 3d position as a seed, compute an even smoother procedural noise 2 | // value. "Improving Noise" [Perlin 2002]. 3 | // 4 | // Inputs: 5 | // st 3D seed 6 | // Values between -½ and ½ ? 7 | // 8 | // expects: random_direction, improved_smooth_step 9 | float improved_perlin_noise( vec3 st) 10 | { 11 | ///////////////////////////////////////////////////////////////////////////// 12 | // Replace with your code 13 | return 0; 14 | ///////////////////////////////////////////////////////////////////////////// 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/random_direction.glsl: -------------------------------------------------------------------------------- 1 | // Generate a pseudorandom unit 3D vector 2 | // 3 | // Inputs: 4 | // seed 3D seed 5 | // Returns psuedorandom, unit 3D vector drawn from uniform distribution over 6 | // the unit sphere (assuming random2 is uniform over [0,1]²). 7 | // 8 | // expects: random2.glsl, PI.glsl 9 | vec3 random_direction( vec3 seed) 10 | { 11 | ///////////////////////////////////////////////////////////////////////////// 12 | // Replace with your code 13 | return vec3(1,0,0); 14 | ///////////////////////////////////////////////////////////////////////////// 15 | } 16 | -------------------------------------------------------------------------------- /data/test-06.json: -------------------------------------------------------------------------------- 1 | { 2 | "vertex": [ "../src/version410.glsl","../src/pass-through.vs"], 3 | "tess_control": [ "../src/version410.glsl","../src/5.tcs"], 4 | "tess_evaluation": [ "../src/version410.glsl","../src/PI.glsl","../src/identity.glsl","../src/uniform_scale.glsl","../src/translate.glsl","../src/rotate_about_y.glsl","../src/model.glsl","../src/interpolate.glsl","../src/snap_to_sphere.tes"], 5 | "fragment": [ "../src/version410.glsl","../src/PI.glsl","../src/random2.glsl","../src/random_direction.glsl","../src/smooth_step.glsl","../src/perlin_noise.glsl","../src/blinn_phong.glsl","../src/procedural_color.fs"] 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/bump_height.glsl: -------------------------------------------------------------------------------- 1 | // Create a bumpy surface by using procedural noise to generate a height ( 2 | // displacement in normal direction). 3 | // 4 | // Inputs: 5 | // is_moon whether we're looking at the moon or centre planet 6 | // s 3D position of seed for noise generation 7 | // Returns elevation adjust along normal (values between -0.1 and 0.1 are 8 | // reasonable. 9 | float bump_height( bool is_moon, vec3 s) 10 | { 11 | ///////////////////////////////////////////////////////////////////////////// 12 | // Replace with your code 13 | return 0 ; 14 | ///////////////////////////////////////////////////////////////////////////// 15 | } 16 | -------------------------------------------------------------------------------- /src/model.glsl: -------------------------------------------------------------------------------- 1 | // Construct the model transformation matrix. The moon should orbit around the 2 | // origin. The other object should stay still. 3 | // 4 | // Inputs: 5 | // is_moon whether we're considering the moon 6 | // time seconds on animation clock 7 | // Returns affine model transformation as 4x4 matrix 8 | // 9 | // expects: identity, rotate_about_y, translate, PI 10 | mat4 model(bool is_moon, float time) 11 | { 12 | ///////////////////////////////////////////////////////////////////////////// 13 | // Replace with your code 14 | return identity(); 15 | ///////////////////////////////////////////////////////////////////////////// 16 | } 17 | -------------------------------------------------------------------------------- /src/random2.glsl: -------------------------------------------------------------------------------- 1 | // Generate a pseudorandom 2D vector based on a 2D or 3D seed. 2 | // 3 | // https://thebookofshaders.com/edit.php#11/2d-gnoise.frag 4 | // 5 | // Inputs: 6 | // st 2D seed 7 | // Returns 2D random point in [0,1]² 8 | vec2 random2(vec2 st){ 9 | st = vec2( dot(st,vec2(127.1,311.7)), 10 | dot(st,vec2(269.5,183.3)) ); 11 | return fract(sin(st)*43758.5453123); 12 | } 13 | // Inputs: 14 | // st 3D seed 15 | // Returns 2D random point in [0,1]² 16 | vec2 random2(vec3 st){ 17 | vec2 S = vec2( dot(st,vec3(127.1,311.7,783.089)), 18 | dot(st,vec3(269.5,183.3,173.542)) ); 19 | return fract(sin(S)*43758.5453123); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /file_watcher.cpp: -------------------------------------------------------------------------------- 1 | // g++ -o file_watcher file_watcher.cpp -I include -std=c++11 2 | // 3 | // Appears to work correctly on mac and linux. Haven't tested on windows. 4 | 5 | #include "last_modification_time.h" 6 | #include "get_seconds.h" 7 | #include 8 | #include 9 | 10 | int main(int argc, char * argv []) 11 | { 12 | double time_since_last_load = 0; 13 | while(true) 14 | { 15 | if(last_modification_time(argv[1]) > time_since_last_load) 16 | { 17 | std::cout< 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public License 6 | // v. 2.0. If a copy of the MPL was not distributed with this file, You can 7 | // obtain one at http://mozilla.org/MPL/2.0/. 8 | #ifndef IGL_STR_H 9 | #define IGL_STR_H 10 | // http://stackoverflow.com/a/2433143/148668 11 | #include 12 | #include 13 | // Suppose you have a function: 14 | // void func(std::string c); 15 | // Then you can write: 16 | // func(STR("foo"<<1<<"bar")); 17 | #define STR(X) static_cast(std::ostringstream().flush() << X).str() 18 | #endif 19 | -------------------------------------------------------------------------------- /src/smooth_step.glsl: -------------------------------------------------------------------------------- 1 | // Filter an input value to perform a smooth step. This function should be a 2 | // cubic polynomial with smooth_step(0) = 0, smooth_step(1) = 1, and zero first 3 | // derivatives at f=0 and f=1. 4 | // 5 | // Inputs: 6 | // f input value 7 | // Returns filtered output value 8 | float smooth_step( float f) 9 | { 10 | ///////////////////////////////////////////////////////////////////////////// 11 | // Replace with your code 12 | return f; 13 | ///////////////////////////////////////////////////////////////////////////// 14 | } 15 | 16 | vec3 smooth_step( vec3 f) 17 | { 18 | ///////////////////////////////////////////////////////////////////////////// 19 | // Replace with your code 20 | return f; 21 | ///////////////////////////////////////////////////////////////////////////// 22 | } 23 | -------------------------------------------------------------------------------- /src/bump_position.glsl: -------------------------------------------------------------------------------- 1 | // Create a bumpy surface by using procedural noise to generate a new 3D position 2 | // via displacement in normal direction. 3 | // 4 | // Inputs: 5 | // is_moon whether we're looking at the moon or centre planet 6 | // s 3D position of seed for noise generation, also assumed to be surface 7 | // point on the unit spher (and thus also equal to its normal) 8 | // Returns 3D position of p adjusted along n by bump amount 9 | // 10 | // Hint: for a unit sphere object, you might use s=p=n 11 | // 12 | // expects: bump_height 13 | vec3 bump_position(bool is_moon , vec3 s) 14 | { 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // Replace with your code 17 | return s; 18 | ///////////////////////////////////////////////////////////////////////////// 19 | } 20 | -------------------------------------------------------------------------------- /data/test-07.json: -------------------------------------------------------------------------------- 1 | { 2 | "vertex": [ "../src/version410.glsl","../src/pass-through.vs"], 3 | "tess_control": [ "../src/version410.glsl","../src/5.tcs"], 4 | "tess_evaluation": [ "../src/version410.glsl","../src/PI.glsl","../src/identity.glsl","../src/uniform_scale.glsl","../src/translate.glsl","../src/rotate_about_y.glsl","../src/model.glsl","../src/interpolate.glsl","../src/snap_to_sphere.tes"], 5 | "fragment": [ "../src/version410.glsl","../src/PI.glsl","../src/identity.glsl","../src/uniform_scale.glsl","../src/translate.glsl","../src/rotate_about_y.glsl","../src/model.glsl","../src/random2.glsl","../src/random_direction.glsl","../src/improved_smooth_step.glsl","../src/improved_perlin_noise.glsl","../src/blinn_phong.glsl","../src/smooth_heaviside.glsl","../src/bump_height.glsl","../src/bump_position.glsl","../src/tangent.glsl","../src/bump.fs"] 6 | } 7 | 8 | -------------------------------------------------------------------------------- /data/test-08.json: -------------------------------------------------------------------------------- 1 | { 2 | "vertex": [ "../src/version410.glsl","../src/pass-through.vs"], 3 | "tess_control": [ "../src/version410.glsl","../src/5.tcs"], 4 | "tess_evaluation": [ "../src/version410.glsl","../src/PI.glsl","../src/identity.glsl","../src/uniform_scale.glsl","../src/translate.glsl","../src/rotate_about_y.glsl","../src/model.glsl","../src/interpolate.glsl","../src/snap_to_sphere.tes"], 5 | "fragment": [ "../src/version410.glsl","../src/PI.glsl","../src/identity.glsl","../src/uniform_scale.glsl","../src/translate.glsl","../src/rotate_about_y.glsl","../src/model.glsl","../src/random2.glsl","../src/random_direction.glsl","../src/improved_smooth_step.glsl","../src/improved_perlin_noise.glsl","../src/blinn_phong.glsl","../src/smooth_heaviside.glsl","../src/bump_height.glsl","../src/bump_position.glsl","../src/tangent.glsl","../src/planet.fs"] 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/5.tcs: -------------------------------------------------------------------------------- 1 | // Hard-code each tessellation level to 5. 2 | // 3 | // Layout: 4 | // indicate that we're dealing with 3 vertices 5 | // (triangles) as output 6 | layout (vertices = 3) out; 7 | // Inputs: 8 | // 3-long array of this triangle's corners' 3D vertex 9 | // positions 10 | in vec4 pos_cs_in[]; 11 | // Outputs: 12 | // 3-long array of this triangle's corners' 3D vertex 13 | // positions (should be set to input using gl_InvocationID) 14 | out vec4 pos_es_in[]; 15 | void main() 16 | { 17 | ///////////////////////////////////////////////////////////////////////////// 18 | // Replace with your code: 19 | pos_es_in[gl_InvocationID] = pos_cs_in[gl_InvocationID]; 20 | ///////////////////////////////////////////////////////////////////////////// 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/blinn_phong.glsl: -------------------------------------------------------------------------------- 1 | // Compute Blinn-Phong Shading given a material specification, a point on a 2 | // surface and a light direction. Assume the light is white and has a low 3 | // ambient intensity. 4 | // 5 | // Inputs: 6 | // ka rgb ambient color 7 | // kd rgb diffuse color 8 | // ks rgb specular color 9 | // p specular exponent (shininess) 10 | // n unit surface normal direction 11 | // v unit direction from point on object to eye 12 | // l unit light direction 13 | // Returns rgb color 14 | vec3 blinn_phong( 15 | vec3 ka, 16 | vec3 kd, 17 | vec3 ks, 18 | float p, 19 | vec3 n, 20 | vec3 v, 21 | vec3 l) 22 | { 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // Replace with your code 25 | return vec3(1,1,1); 26 | ///////////////////////////////////////////////////////////////////////////// 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/improved_smooth_step.glsl: -------------------------------------------------------------------------------- 1 | // Filter an input value to perform an even smoother step. This function should 2 | // be a quintic polynomial with improved_smooth_step(0) = 0, 3 | // improved_smooth_step(1) = 1, and zero first _and_ second derivatives at f=0 4 | // and f=1. "Improving Noise" [Perlin 2002]. 5 | // 6 | // Inputs: 7 | // f input value 8 | // Returns filtered output value 9 | float improved_smooth_step( float f) 10 | { 11 | ///////////////////////////////////////////////////////////////////////////// 12 | // Replace with your code 13 | return f; 14 | ///////////////////////////////////////////////////////////////////////////// 15 | } 16 | vec3 improved_smooth_step( vec3 f) 17 | { 18 | ///////////////////////////////////////////////////////////////////////////// 19 | // Replace with your code 20 | return f; 21 | ///////////////////////////////////////////////////////////////////////////// 22 | } 23 | -------------------------------------------------------------------------------- /src/bump.fs: -------------------------------------------------------------------------------- 1 | // Set the pixel color using Blinn-Phong shading (e.g., with constant blue and 2 | // gray material color) with a bumpy texture. 3 | // 4 | // Uniforms: 5 | uniform mat4 view; 6 | uniform mat4 proj; 7 | uniform float animation_seconds; 8 | uniform bool is_moon; 9 | // Inputs: 10 | // linearly interpolated from tessellation evaluation shader 11 | // output 12 | in vec3 sphere_fs_in; 13 | in vec3 normal_fs_in; 14 | in vec4 pos_fs_in; 15 | in vec4 view_pos_fs_in; 16 | // Outputs: 17 | // rgb color of this pixel 18 | out vec3 color; 19 | // expects: model, blinn_phong, bump_height, bump_position, 20 | // improved_perlin_noise, tangent 21 | void main() 22 | { 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // Replace with your code 25 | color = vec3(1,1,1); 26 | ///////////////////////////////////////////////////////////////////////////// 27 | } 28 | -------------------------------------------------------------------------------- /include/print_opengl_info.h: -------------------------------------------------------------------------------- 1 | #ifndef PRINT_OPENGL_INFO_H 2 | #define PRINT_OPENGL_INFO_H 3 | #include "gl.h" 4 | #define __gl_h_ 5 | #define GLFW_INCLUDE_GLU 6 | #include 7 | 8 | // Use glfw to print information about the current opengl context 9 | // Should be called after glfwMakeContextCurrent(...) 10 | void print_opengl_info(GLFWwindow * window); 11 | 12 | // Implementation 13 | #include 14 | void print_opengl_info(GLFWwindow * window) 15 | { 16 | int major, minor, rev; 17 | major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR); 18 | minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR); 19 | rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION); 20 | printf("OpenGL version recieved: %d.%d.%d\n", major, minor, rev); 21 | printf("Supported OpenGL is %s\n", (const char*)glGetString(GL_VERSION)); 22 | printf("Supported GLSL is %s\n", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)); 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/planet.fs: -------------------------------------------------------------------------------- 1 | // Generate a procedural planet and orbiting moon. Use layers of (improved) 2 | // Perlin noise to generate planetary features such as vegetation, gaseous 3 | // clouds, mountains, valleys, ice caps, rivers, oceans. Don't forget about the 4 | // moon. Use `animation_seconds` in your noise input to create (periodic) 5 | // temporal effects. 6 | // 7 | // Uniforms: 8 | uniform mat4 view; 9 | uniform mat4 proj; 10 | uniform float animation_seconds; 11 | uniform bool is_moon; 12 | // Inputs: 13 | in vec3 sphere_fs_in; 14 | in vec3 normal_fs_in; 15 | in vec4 pos_fs_in; 16 | in vec4 view_pos_fs_in; 17 | // Outputs: 18 | out vec3 color; 19 | // expects: model, blinn_phong, bump_height, bump_position, 20 | // improved_perlin_noise, tangent 21 | void main() 22 | { 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // Replace with your code 25 | color = vec3(1,1,1); 26 | ///////////////////////////////////////////////////////////////////////////// 27 | } 28 | -------------------------------------------------------------------------------- /include/print_program_info_log.h: -------------------------------------------------------------------------------- 1 | #ifndef PRINT_PROGRAM_INFO_LOG_H 2 | #define PRINT_PROGRAM_INFO_LOG_H 3 | 4 | #include "gl.h" 5 | #include 6 | 7 | // Print information about a given glsl shader program. 8 | // 9 | // Inputs: 10 | // obj id of object we're querying 11 | // Returns true if printed anything. 12 | bool print_program_info_log(const GLuint obj); 13 | 14 | // Implementation 15 | #include "REDRUM.h" 16 | #include "STR.h" 17 | #include "find_and_replace_all.h" 18 | 19 | bool print_program_info_log(const GLuint obj) 20 | { 21 | GLint infologLength = 0; 22 | GLint charsWritten = 0; 23 | 24 | glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength); 25 | 26 | if (infologLength > 0) 27 | { 28 | char * infoLog = new char[infologLength]; 29 | glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog); 30 | std::string log(infoLog); 31 | find_and_replace_all("ERROR",STR(REDRUM("ERROR")),log); 32 | find_and_replace_all("WARNING",STR(YELLOWRUM("WARNING")),log); 33 | std::cerr< 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public License 6 | // v. 2.0. If a copy of the MPL was not distributed with this file, You can 7 | // obtain one at http://mozilla.org/MPL/2.0/. 8 | #ifndef IGL_OPENGL_LOAD_SHADER_H 9 | #define IGL_OPENGL_LOAD_SHADER_H 10 | #include "../igl_inline.h" 11 | #include "gl.h" 12 | #include 13 | 14 | namespace igl 15 | { 16 | namespace opengl 17 | { 18 | // Creates and compiles a shader from a given string 19 | // 20 | // Inputs: 21 | // src string containing GLSL shader code 22 | // type GLSL type of shader, one of: 23 | // GL_VERTEX_SHADER 24 | // GL_FRAGMENT_SHADER 25 | // GL_GEOMETRY_SHADER 26 | // Returns index id of the newly created shader, 0 on error 27 | // 28 | // Will immediately return 0 if src is empty. 29 | IGL_INLINE GLuint load_shader( 30 | const std::string & src,const GLenum type); 31 | } 32 | } 33 | 34 | // Implementation 35 | 36 | 37 | #endif 38 | 39 | -------------------------------------------------------------------------------- /include/find_and_replace_all.h: -------------------------------------------------------------------------------- 1 | #ifndef FIND_AND_REPLACE_ALL_H 2 | #define FIND_AND_REPLACE_ALL_H 3 | #include 4 | 5 | // Find and replace all (exact) occurances of a string with something else. 6 | // 7 | // Inputs: 8 | // toSearch string to find 9 | // replaceStr string to replace 10 | // data string to look in and change in place 11 | // Outputs: 12 | // data (see input) 13 | // Returns number of replacements made 14 | inline int find_and_replace_all( 15 | const std::string & toSearch, 16 | const std::string & replaceStr, 17 | std::string & data); 18 | 19 | // Implementation 20 | 21 | inline int find_and_replace_all( 22 | const std::string & toSearch, 23 | const std::string & replaceStr, 24 | std::string & data) 25 | { 26 | // https://thispointer.com/find-and-replace-all-occurrences-of-a-sub-string-in-c/ 27 | int count = 0; 28 | // Get the first occurrence 29 | size_t pos = data.find(toSearch); 30 | // Repeat till end is reached 31 | while( pos != std::string::npos) 32 | { 33 | count++; 34 | // Replace this occurrence of Sub String 35 | data.replace(pos, toSearch.size(), replaceStr); 36 | // Get the next occurrence from the current position 37 | pos =data.find(toSearch, pos + replaceStr.size()); 38 | } 39 | return count; 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/model_view_projection.vs: -------------------------------------------------------------------------------- 1 | // Determine the perspective projection (do not conduct division) in homogenous 2 | // coordinates. If is_moon is true, then shrink the model by 70%, shift away 3 | // from the origin by 2 units and rotate around the origin at a frequency of 1 4 | // revolution per 4 seconds. 5 | // 6 | // Uniforms: 7 | // 4x4 view transformation matrix: transforms "world 8 | // coordinates" into camera coordinates. 9 | uniform mat4 view; 10 | // 4x4 perspective projection matrix: transforms 11 | uniform mat4 proj; 12 | // number of seconds animation has been running 13 | uniform float animation_seconds; 14 | // whether we're rendering the moon or the other object 15 | uniform bool is_moon; 16 | // Inputs: 17 | // 3D position of mesh vertex 18 | in vec3 pos_vs_in; 19 | // Ouputs: 20 | // transformed and projected position in homogeneous 21 | // coordinates 22 | out vec4 pos_cs_in; 23 | // expects: PI, model 24 | void main() 25 | { 26 | ///////////////////////////////////////////////////////////////////////////// 27 | // Replace with your code 28 | pos_cs_in = vec4(pos_vs_in,1.0); 29 | ///////////////////////////////////////////////////////////////////////////// 30 | } 31 | -------------------------------------------------------------------------------- /src/snap_to_sphere.tes: -------------------------------------------------------------------------------- 1 | // Hint: Crib from your model_view_projection.vs 2 | // Layout: 3 | // Indicate that we're dealing with 4 | // triangles in CCW order and using a 5 | // sane spacing. 6 | layout(triangles, equal_spacing, ccw) in; 7 | // Uniforms 8 | uniform mat4 view; 9 | uniform mat4 proj; 10 | uniform float animation_seconds; 11 | uniform bool is_moon; 12 | // Inputs: 13 | // array of 3 3D patch corner positions 14 | in vec4 pos_es_in[]; 15 | // Outputs: 16 | // projected, view, and model transformed 3D position 17 | out vec4 pos_fs_in; 18 | // view and model transformed 3D position 19 | out vec4 view_pos_fs_in; 20 | // view and model transformed 3D normal 21 | out vec3 normal_fs_in; 22 | // 3D position _before_ applying model, view or projection 23 | // transformations (e.g., point on unit sphere) 24 | out vec3 sphere_fs_in; 25 | // expects: interpolat, model, 26 | void main() 27 | { 28 | ///////////////////////////////////////////////////////////////////////////// 29 | // Replace with your code 30 | pos_fs_in = interpolate(gl_TessCoord, pos_es_in[0], pos_es_in[1], pos_es_in[2]); 31 | gl_Position = pos_fs_in; 32 | ///////////////////////////////////////////////////////////////////////////// 33 | } 34 | 35 | 36 | -------------------------------------------------------------------------------- /include/mesh_to_vao.h: -------------------------------------------------------------------------------- 1 | #ifndef MESH_TO_VAO_H 2 | #define MESH_TO_VAO_H 3 | #include "gl.h" 4 | #include 5 | 6 | // Send a triangle mesh to the GPU using a vertex array object. 7 | // 8 | // Inputs: 9 | // V #V by 3 list of 3D mesh vertex positions 10 | // F #F by 3 list of triangle indices into V 11 | // Outputs: 12 | // VAO identifier of compiled vertex array object. 13 | inline void mesh_to_vao( 14 | const Eigen::Matrix< float,Eigen::Dynamic,3,Eigen::RowMajor> & V, 15 | const Eigen::Matrix & F, 16 | GLuint & VAO); 17 | 18 | // Implementation 19 | 20 | inline void mesh_to_vao( 21 | const Eigen::Matrix< float,Eigen::Dynamic,3,Eigen::RowMajor> & V, 22 | const Eigen::Matrix & F, 23 | GLuint & VAO) 24 | { 25 | // Generate and attach buffers to vertex array 26 | glGenVertexArrays(1, &VAO); 27 | GLuint VBO, EBO; 28 | glGenBuffers(1, &VBO); 29 | glGenBuffers(1, &EBO); 30 | glBindVertexArray(VAO); 31 | glBindBuffer(GL_ARRAY_BUFFER, VBO); 32 | glBufferData(GL_ARRAY_BUFFER, sizeof(float)*V.size(), V.data(), GL_STATIC_DRAW); 33 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); 34 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*F.size(), F.data(), GL_STATIC_DRAW); 35 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); 36 | glEnableVertexAttribArray(0); 37 | glBindBuffer(GL_ARRAY_BUFFER, 0); 38 | glBindVertexArray(0); 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | set(ROOT "${CMAKE_CURRENT_LIST_DIR}") 3 | project(shaderpipeline) 4 | option(USE_SOLUTION "Use solution" OFF) 5 | # Add your project files 6 | include_directories("include/") 7 | # create executable 8 | include(CheckCXXCompilerFlag) 9 | CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) 10 | CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) 11 | if(COMPILER_SUPPORTS_CXX11) 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 13 | elseif(COMPILER_SUPPORTS_CXX0X) 14 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") 15 | else() 16 | message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") 17 | endif() 18 | 19 | # OpenGL library 20 | if (NOT CMAKE_VERSION VERSION_LESS "3.11") 21 | cmake_policy(SET CMP0072 NEW) 22 | endif() 23 | find_package(OpenGL REQUIRED) 24 | 25 | if(USE_SOLUTION) 26 | add_definitions("-DUSE_SOLUTION") 27 | endif() 28 | 29 | if(NOT TARGET glfw) 30 | set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL " " FORCE) 31 | set(GLFW_BUILD_TESTS OFF CACHE BOOL " " FORCE) 32 | set(GLFW_BUILD_DOCS OFF CACHE BOOL " " FORCE) 33 | set(GLFW_INSTALL OFF CACHE BOOL " " FORCE) 34 | add_subdirectory(${ROOT}/glfw glfw) 35 | endif() 36 | 37 | add_subdirectory(${ROOT}/glad glad) 38 | 39 | add_executable(${PROJECT_NAME} main.cpp) 40 | target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${OPENGL_INCLUDE_DIR}) 41 | target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${ROOT}/eigen/) 42 | target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${ROOT}/glfw/include) 43 | target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${ROOT}/glad/include) 44 | target_link_libraries(${PROJECT_NAME} glfw ${OPENGL_gl_LIBRARY} glad) 45 | -------------------------------------------------------------------------------- /include/last_modification_time.h: -------------------------------------------------------------------------------- 1 | #ifndef LAST_MODIFICATION_TIME_H 2 | #define LAST_MODIFICATION_TIME_H 3 | #include 4 | // Inputs: 5 | // path path to file in question 6 | // Returns the last time this file has been modified in seconds. 7 | double last_modification_time(const std::string & path); 8 | 9 | // Implementation 10 | 11 | #if WIN32 12 | 13 | // Shot in the dark... I don't even know if this compiles 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | double last_modification_time(const std::string & path) 21 | { 22 | // https://www.rosettacode.org/wiki/File_modification_time#Windows 23 | FILETIME modtime; 24 | //SYSTEMTIME st; 25 | HANDLE fh; 26 | std::wstring w_path = std::wstring(path.begin(), path.end()); 27 | fh = CreateFileW(w_path.c_str(), GENERIC_READ | FILE_WRITE_ATTRIBUTES, 28 | 0, NULL, OPEN_EXISTING, 0, NULL); 29 | if(fh == INVALID_HANDLE_VALUE) 30 | { 31 | return -1; 32 | } 33 | if(GetFileTime(fh, NULL, NULL, &modtime) == 0) 34 | { 35 | return -1; 36 | } 37 | CloseHandle(fh); 38 | // https://stackoverflow.com/a/19709740/148668 39 | __int64* val = (__int64*) &modtime; 40 | return static_cast(*val) / 10000000.0 - 11644473600.0; 41 | } 42 | #else 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | double last_modification_time(const std::string & path) 50 | { 51 | struct stat s; 52 | struct timespec t = {0,0}; 53 | if (stat(path.c_str(), &s) < 0) { return -1; } 54 | #ifdef __APPLE__ 55 | t = s.st_mtimespec; 56 | #else // Linux? 57 | t = s.st_mtim; 58 | #endif 59 | return double(t.tv_sec) + double(t.tv_nsec)*1e-9; 60 | } 61 | 62 | #endif 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /include/icosahedron.h: -------------------------------------------------------------------------------- 1 | #ifndef ICOSAHEDRON_H 2 | #define ICOSAHEDRON_H 3 | #include 4 | 5 | // Construct a triangle mesh of an icosahedron. 6 | // 7 | // Outputs: 8 | // V 12 by 3 list of 3D mesh vertex positions 9 | // F 20 by 3 list of triangle indices into V 10 | template < 11 | typename DerivedV, 12 | typename DerivedF 13 | > 14 | inline void icosahedron( 15 | Eigen::PlainObjectBase & V, 16 | Eigen::PlainObjectBase & F); 17 | 18 | // Implementation 19 | 20 | template < 21 | typename DerivedV, 22 | typename DerivedF 23 | > 24 | inline void icosahedron( 25 | Eigen::PlainObjectBase & V, 26 | Eigen::PlainObjectBase & F) 27 | { 28 | V = (DerivedV(12,3) << 29 | 0,0,1, 30 | 0.72360679774997894,-0.52573111211913359,0.44721359549995793, 31 | 0.72360679774997894,0.52573111211913359,0.44721359549995793, 32 | -0.27639320225002095,0.85065080835203999,0.44721359549995793, 33 | -0.89442719099991586,1.0953573965284052e-16,0.44721359549995793, 34 | -0.27639320225002112,-0.85065080835203988,0.44721359549995793, 35 | 0.89442719099991586,0,-0.44721359549995793, 36 | 0.27639320225002106,0.85065080835203988,-0.44721359549995793, 37 | -0.72360679774997883,0.5257311121191337,-0.44721359549995793, 38 | -0.72360679774997894,-0.52573111211913348,-0.44721359549995793, 39 | 0.27639320225002084,-0.85065080835203999,-0.44721359549995793, 40 | 0,0,-1).finished(); 41 | F = (DerivedF(20,3)<< 42 | 0,1,2, 43 | 0,2,3, 44 | 0,3,4, 45 | 0,4,5, 46 | 0,5,1, 47 | 1,6,2, 48 | 2,7,3, 49 | 3,8,4, 50 | 4,9,5, 51 | 5,10,1, 52 | 6,7,2, 53 | 7,8,3, 54 | 8,9,4, 55 | 9,10,5, 56 | 10,6,1, 57 | 6,11,7, 58 | 7,11,8, 59 | 8,11,9, 60 | 9,11,10, 61 | 10,11,6).finished(); 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /include/print_shader_info_log.h: -------------------------------------------------------------------------------- 1 | #ifndef PRINT_SHADER_INFO_LOG_H 2 | #define PRINT_SHADER_INFO_LOG_H 3 | 4 | #include "gl.h" 5 | #include 6 | #include 7 | 8 | // Print information (e.g., compilation errors and warnings) about a give glsl 9 | // shader. 10 | // 11 | // Inputs: 12 | // type_str string identifying which kind of shader we're asking about (just 13 | // a prefix to print) 14 | // obj id of object we're querying 15 | // paths list of file paths containing corresponding shader source code 16 | // (assumings `#line ...` directive has been inserted between files). 17 | // Returns true if printed anything. 18 | bool print_shader_info_log( 19 | const std::string & type_str, 20 | const GLuint obj, 21 | const std::vector & paths); 22 | 23 | // Implementation 24 | #include "REDRUM.h" 25 | #include "STR.h" 26 | #include "find_and_replace_all.h" 27 | 28 | #include 29 | 30 | bool print_shader_info_log( 31 | const std::string & type_str, 32 | const GLuint obj, 33 | const std::vector & paths) 34 | { 35 | GLint infologLength = 0; 36 | GLint charsWritten = 0; 37 | 38 | glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength); 39 | 40 | if (infologLength > 0) 41 | { 42 | char * infoLog = new char[infologLength]; 43 | std::cerr< 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public License 6 | // v. 2.0. If a copy of the MPL was not distributed with this file, You can 7 | // obtain one at http://mozilla.org/MPL/2.0/. 8 | #ifndef IGL_REDRUM_H 9 | #define IGL_REDRUM_H 10 | 11 | // Q: These should probably be inside the igl namespace. What's the correct 12 | // way to do that? 13 | // A: I guess the right way is to not use a macro but a proper function with 14 | // streams as input and output. 15 | 16 | // ANSI color codes for formatting iostream style output 17 | 18 | #ifdef WIN32 19 | 20 | // Bold Red, etc. 21 | #define NORUM(X) X 22 | #define BOLD(X) X 23 | #define REDRUM(X) X 24 | #define GREENRUM(X) X 25 | #define YELLOWRUM(X) X 26 | #define BLUERUM(X) X 27 | #define MAGENTARUM(X) X 28 | #define CYANRUM(X) X 29 | // Regular Red, etc. 30 | #define REDGIN(X) X 31 | #define GREENGIN(X) X 32 | #define YELLOWGIN(X) X 33 | #define BLUEGIN(X) X 34 | #define MAGENTAGIN(X) X 35 | #define CYANGIN(X) X 36 | 37 | #else 38 | 39 | // Bold Red, etc. 40 | #define NORUM(X) ""< 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /include/read_json.h: -------------------------------------------------------------------------------- 1 | #ifndef READ_JSON_H 2 | #define READ_JSON_H 3 | 4 | #include 5 | #include 6 | 7 | // Read a shader specification from a .json file 8 | // 9 | // Input: 10 | // filename path to .json file 11 | // Outputs: 12 | // vertex_shader_path paths to files containing source of vertex 13 | // shader 14 | // tess_control_shader_path paths to files containing source of tessellation 15 | // control shader 16 | // tess_evaluation_shader_path paths to files containing source of tessellation 17 | // evaluation shader 18 | // fragment_shader_path paths to files containing source of fragment 19 | // shader 20 | bool read_json( 21 | const std::string & filename, 22 | std::vector & vertex_shader_paths, 23 | std::vector & tess_control_shader_paths, 24 | std::vector & tess_evaluation_shader_paths, 25 | std::vector & fragment_shader_paths); 26 | 27 | // Implementation 28 | 29 | #include 30 | #include 31 | 32 | bool read_json( 33 | const std::string & filename, 34 | std::vector & vertex_shader_paths, 35 | std::vector & tess_control_shader_paths, 36 | std::vector & tess_evaluation_shader_paths, 37 | std::vector & fragment_shader_paths) 38 | { 39 | // Heavily borrowing from 40 | // https://github.com/yig/graphics101-raycasting/blob/master/parser.cpp 41 | using json = nlohmann::json; 42 | 43 | std::ifstream infile( filename ); 44 | if( !infile ) return false; 45 | json j; 46 | infile >> j; 47 | 48 | vertex_shader_paths.clear(); 49 | tess_control_shader_paths.clear(); 50 | tess_evaluation_shader_paths.clear(); 51 | fragment_shader_paths.clear(); 52 | for(const auto & jstr : j["vertex"]) { vertex_shader_paths.push_back(jstr); } 53 | for(const auto & jstr : j["tess_control"]) { tess_control_shader_paths.push_back(jstr); } 54 | for(const auto & jstr : j["tess_evaluation"]) { tess_evaluation_shader_paths.push_back(jstr); } 55 | for(const auto & jstr : j["fragment"]) { fragment_shader_paths.push_back(jstr); } 56 | 57 | return true; 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /tex/b56595d2a30a0af329086562ca12d521.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tex/ff44d867a998c08241beb49b30148782.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /markdown/header.md: -------------------------------------------------------------------------------- 1 | css: css/github-markdown.css 2 | html header: 3 | 18 |
19 | 20 | 21 | 24 | 25 | 26 |
27 | $\newcommand{\A}{\mat{A}}$ 28 | $\newcommand{\B}{\mat{B}}$ 29 | $\newcommand{\C}{\mat{C}}$ 30 | $\newcommand{\D}{\mat{D}}$ 31 | $\newcommand{\E}{\mat{E}}$ 32 | $\newcommand{\F}{\mat{F}}$ 33 | $\newcommand{\G}{\mat{G}}$ 34 | $\newcommand{\H}{\mat{H}}$ 35 | $\newcommand{\I}{\mat{I}}$ 36 | $\newcommand{\K}{\mat{K}}$ 37 | $\newcommand{\L}{\mat{L}}$ 38 | $\newcommand{\M}{\mat{M}}$ 39 | $\newcommand{\N}{\mat{N}}$ 40 | $\newcommand{\One}{\mathbf{1}}$ 41 | $\newcommand{\P}{\mat{P}}$ 42 | $\newcommand{\Q}{\mat{Q}}$ 43 | $\newcommand{\Rot}{\mat{R}}$ 44 | $\newcommand{\R}{\mathbb{R}}$ 45 | $\newcommand{\S}{\mathcal{S}}$ 46 | $\newcommand{\T}{\mat{T}}$ 47 | $\newcommand{\U}{\mat{U}}$ 48 | $\newcommand{\V}{\mat{V}}$ 49 | $\newcommand{\W}{\mat{W}}$ 50 | $\newcommand{\X}{\mat{X}}$ 51 | $\newcommand{\Y}{\mat{Y}}$ 52 | $\newcommand{\argmax}{\mathop{\text{argmax}}}$ 53 | $\newcommand{\argmin}{\mathop{\text{argmin}}}$ 54 | $\newcommand{\c}{\vec{c}}$ 55 | $\newcommand{\d}{\vec{d}}$ 56 | $\newcommand{\e}{\vec{e}}$ 57 | $\newcommand{\f}{\vec{f}}$ 58 | $\newcommand{\g}{\vec{g}}$ 59 | $\newcommand{\mat}[1]{\mathbf{#1}}$ 60 | $\newcommand{\min}{\mathop{\text{min}}}$ 61 | $\newcommand{\n}{\vec{n}}$ 62 | $\newcommand{\p}{\vec{p}}$ 63 | $\newcommand{\q}{\vec{q}}$ 64 | $\newcommand{\r}{\vec{r}}$ 65 | $\newcommand{\transpose}{{\mathsf T}}$ 66 | $\newcommand{\tr}[1]{\mathop{\text{tr}}{\left(#1\right)}}$ 67 | $\newcommand{\t}{\vec{t}}$ 68 | $\newcommand{\u}{\vec{u}}$ 69 | $\newcommand{\vec}[1]{\mathbf{#1}}$ 70 | $\newcommand{\x}{\vec{x}}$ 71 | $\newcommand{\y}{\vec{y}}$ 72 | $\newcommand{\z}{\vec{z}}$ 73 | $\renewcommand{\v}{\vec{v}}$ 74 |
75 | -------------------------------------------------------------------------------- /tex/1926c401973f24b4db4f35dca2eb381d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tex/980fcd4213d7b5d2ffcc82ec78c27ead.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /include/report_gl_error.h: -------------------------------------------------------------------------------- 1 | // This file is part of libigl, a simple c++ geometry processing library. 2 | // 3 | // Copyright (C) 2013 Alec Jacobson 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public License 6 | // v. 2.0. If a copy of the MPL was not distributed with this file, You can 7 | // obtain one at http://mozilla.org/MPL/2.0/. 8 | #ifndef IGL_OPENGL_REPORT_GL_ERROR_H 9 | #define IGL_OPENGL_REPORT_GL_ERROR_H 10 | #define IGL_INLINE inline 11 | 12 | // Hack to allow both opengl/ and opengl2 to use this (we shouldn't allow this) 13 | #ifndef __gl_h_ 14 | # include "gl.h" 15 | #endif 16 | #include 17 | 18 | namespace igl 19 | { 20 | namespace opengl 21 | { 22 | // Print last OpenGL error to stderr prefixed by specified id string 23 | // Inputs: 24 | // id string to appear before any error msgs 25 | // Returns result of glGetError() 26 | IGL_INLINE GLenum report_gl_error(const std::string id); 27 | // No prefix 28 | IGL_INLINE GLenum report_gl_error(); 29 | } 30 | } 31 | 32 | // Implementation 33 | 34 | // This file is part of libigl, a simple c++ geometry processing library. 35 | // 36 | // Copyright (C) 2013 Alec Jacobson 37 | // 38 | // This Source Code Form is subject to the terms of the Mozilla Public License 39 | // v. 2.0. If a copy of the MPL was not distributed with this file, You can 40 | // obtain one at http://mozilla.org/MPL/2.0/. 41 | #include "report_gl_error.h" 42 | #include 43 | 44 | IGL_INLINE GLenum igl::opengl::report_gl_error(const std::string id) 45 | { 46 | // http://stackoverflow.com/q/28485180/148668 47 | 48 | // gluErrorString was deprecated 49 | const auto gluErrorString = [](GLenum errorCode)->const char * 50 | { 51 | switch(errorCode) 52 | { 53 | default: 54 | return "unknown error code"; 55 | case GL_NO_ERROR: 56 | return "no error"; 57 | case GL_INVALID_ENUM: 58 | return "invalid enumerant"; 59 | case GL_INVALID_VALUE: 60 | return "invalid value"; 61 | case GL_INVALID_OPERATION: 62 | return "invalid operation"; 63 | #ifndef GL_VERSION_3_0 64 | case GL_STACK_OVERFLOW: 65 | return "stack overflow"; 66 | case GL_STACK_UNDERFLOW: 67 | return "stack underflow"; 68 | case GL_TABLE_TOO_LARGE: 69 | return "table too large"; 70 | #endif 71 | case GL_OUT_OF_MEMORY: 72 | return "out of memory"; 73 | #ifdef GL_EXT_framebuffer_object 74 | case GL_INVALID_FRAMEBUFFER_OPERATION_EXT: 75 | return "invalid framebuffer operation"; 76 | #endif 77 | } 78 | }; 79 | 80 | GLenum err = glGetError(); 81 | if(GL_NO_ERROR != err) 82 | { 83 | fprintf(stderr,"GL_ERROR: %s%s\n",id.c_str(),gluErrorString(err)); 84 | } 85 | return err; 86 | } 87 | 88 | IGL_INLINE GLenum igl::opengl::report_gl_error() 89 | { 90 | return igl::opengl::report_gl_error(std::string("")); 91 | } 92 | 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /tex/df092db5465f28cad5cd98f89fa50dd9.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /tex/2ad9d098b937e46f9f58968551adac57.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tex/509fb6a370666a6736bbb7ab34494d6f.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tex/b83d238e84b2e2204d33e3b6bbeecc2f.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /include/create_shader_program_from_files.h: -------------------------------------------------------------------------------- 1 | #ifndef CREATE_SHADER_PROGRAM_FROM_FILES_H 2 | #define CREATE_SHADER_PROGRAM_FROM_FILES_H 3 | #include "gl.h" 4 | #include 5 | #include 6 | 7 | // Create a GLSL shader program given a list of paths containing shader code for 8 | // each shader in the vertex-tessellation-fragment shader pipeline. Prints error 9 | // messages on failure. 10 | // 11 | // Inputs: 12 | // vertex_shader_paths ordered list of paths to files containing glsl vertex 13 | // shader code. 14 | // tess_control_shader_paths ordered list of paths to files containing glsl 15 | // tessellation control shader code. 16 | // tess_evaluation_shader_paths ordered list of paths to files containing glsl 17 | // tessellation evaluation shader code. 18 | // fragment_shader_paths ordered list of paths to files containing glsl fragment 19 | // shader code. 20 | // Outputs: 21 | // id identifier of compiled shader program 22 | // Returns true iff success 23 | inline bool create_shader_program_from_files( 24 | const std::vector & vertex_shader_paths, 25 | const std::vector & tess_control_shader_paths, 26 | const std::vector & tess_evaluation_shader_paths, 27 | const std::vector & fragment_shader_paths, 28 | GLuint & id); 29 | 30 | // Implementation 31 | 32 | #include 33 | #include 34 | #include "REDRUM.h" 35 | #include "STR.h" 36 | #include "print_shader_info_log.h" 37 | #include "print_program_info_log.h" 38 | 39 | inline bool create_shader_program_from_files( 40 | const std::vector & vertex_shader_paths, 41 | const std::vector & tess_control_shader_paths, 42 | const std::vector & tess_evaluation_shader_paths, 43 | const std::vector & fragment_shader_paths, 44 | GLuint & id) 45 | { 46 | const auto create_compile_attach = []( 47 | const std::vector & paths, 48 | const GLenum type, 49 | const GLuint prog_id, 50 | GLuint & s) -> bool 51 | { 52 | const std::string type_str = 53 | (type == GL_VERTEX_SHADER ? STR(BOLD("vertex shader")) : 54 | (type == GL_FRAGMENT_SHADER ? STR(BOLD("fragment shader")) : 55 | (type == GL_TESS_CONTROL_SHADER ? STR(BOLD("tessellation control shader")) : 56 | (type == GL_TESS_EVALUATION_SHADER ? STR(BOLD("tessellation evaluation shader")) : 57 | "unknown shader")))); 58 | int total_length = 0; 59 | std::vector strs; 60 | { 61 | for(int p = 0;p cstrs; 81 | for(const auto & str : strs) 82 | { 83 | cstrs.emplace_back(str.c_str()); 84 | } 85 | if(total_length == 0) 86 | { 87 | std::cerr< 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | /* https://gist.github.com/tuzz/3331384 2 | */ 3 | html 4 | { 5 | background-color: #aaa; 6 | margin: 0; 7 | } 8 | 9 | body { 10 | width: 1000px; 11 | margin-top: 0; 12 | margin-bottom: 30px; 13 | margin-left: auto; 14 | margin-right: auto; 15 | font-family: Helvetica, arial, sans-serif; 16 | font-size: 14px; 17 | line-height: 1.6; 18 | padding: 0px; 19 | background-color: white; 20 | padding-left: 30px; 21 | padding-right: 30px; 22 | padding-bottom: 10px; 23 | color: #333; 24 | } 25 | 26 | a { 27 | color: #4183C4; 28 | text-decoration: none; 29 | } 30 | 31 | a.absent { 32 | color: #cc0000; 33 | } 34 | 35 | a.anchor { 36 | display: block; 37 | padding-left: 30px; 38 | margin-left: -30px; 39 | cursor: pointer; 40 | position: absolute; 41 | top: 0; 42 | left: 0; 43 | bottom: 0; 44 | } 45 | 46 | h1 { 47 | font-size: 28px; 48 | color: black; 49 | } 50 | 51 | h1, h2, h3, h4, h5, h6 { 52 | margin: 20px 0 10px; 53 | padding: 0; 54 | font-weight: bold; 55 | -webkit-font-smoothing: antialiased; 56 | cursor: text; 57 | position: relative; 58 | } 59 | 60 | h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { 61 | text-decoration: none; 62 | } 63 | 64 | h1 tt, h1 code { 65 | font-size: inherit; 66 | } 67 | 68 | h2 tt, h2 code { 69 | font-size: inherit; 70 | } 71 | 72 | h3 tt, h3 code { 73 | font-size: inherit; 74 | } 75 | 76 | h4 tt, h4 code { 77 | font-size: inherit; 78 | } 79 | 80 | h5 tt, h5 code { 81 | font-size: inherit; 82 | } 83 | 84 | h6 tt, h6 code { 85 | font-size: inherit; 86 | } 87 | 88 | h2 { 89 | font-size: 24px; 90 | border-bottom: 1px solid #cccccc; 91 | color: black; 92 | } 93 | 94 | h3 { 95 | font-size: 18px; 96 | } 97 | 98 | h4 { 99 | font-size: 16px; 100 | } 101 | 102 | h5 { 103 | font-size: 14px; 104 | } 105 | 106 | h6 { 107 | color: #777777; 108 | font-size: 14px; 109 | } 110 | 111 | p, blockquote, ul, ol, dl, li, table, pre { 112 | margin: 15px 0; 113 | } 114 | 115 | hr { 116 | border: 0 none; 117 | background-color: #cccccc; 118 | height: 4px; 119 | padding: 0; 120 | } 121 | 122 | h1{ 123 | margin-top: 0; 124 | padding-top: 0; 125 | } 126 | 127 | h1 p, h2 p, h3 p, h4 p, h5 p, h6 p { 128 | margin-top: 0; 129 | } 130 | 131 | li p.first { 132 | display: inline-block; 133 | } 134 | 135 | ul, ol { 136 | padding-left: 30px; 137 | } 138 | 139 | ul :first-child, ol :first-child { 140 | margin-top: 0; 141 | } 142 | 143 | ul :last-child, ol :last-child { 144 | margin-bottom: 0; 145 | } 146 | 147 | dl { 148 | padding: 0; 149 | } 150 | 151 | dl dt { 152 | font-size: 14px; 153 | font-weight: bold; 154 | font-style: italic; 155 | padding: 0; 156 | margin: 15px 0 5px; 157 | } 158 | 159 | dl dt:first-child { 160 | padding: 0; 161 | } 162 | 163 | dl dt > :first-child { 164 | margin-top: 0; 165 | } 166 | 167 | dl dt > :last-child { 168 | margin-bottom: 0; 169 | } 170 | 171 | dl dd { 172 | margin: 0 0 15px; 173 | padding: 0 15px; 174 | } 175 | 176 | dl dd > :first-child { 177 | margin-top: 0; 178 | } 179 | 180 | dl dd > :last-child { 181 | margin-bottom: 0; 182 | } 183 | 184 | blockquote { 185 | border-left: 4px solid #dddddd; 186 | padding: 0 15px; 187 | color: #777777; 188 | } 189 | 190 | blockquote > :first-child { 191 | margin-top: 0; 192 | } 193 | 194 | blockquote > :last-child { 195 | margin-bottom: 0; 196 | } 197 | 198 | blockquote h1, blockquote h2, blockquote h3, blockquote h4 199 | { 200 | color: #777777; 201 | } 202 | 203 | table { 204 | padding: 0; 205 | } 206 | table tr { 207 | border-top: 1px solid #cccccc; 208 | background-color: white; 209 | margin: 0; 210 | padding: 0; 211 | } 212 | 213 | table tr:nth-child(2n) { 214 | background-color: #f8f8f8; 215 | } 216 | 217 | table tr th { 218 | font-weight: bold; 219 | border: 1px solid #cccccc; 220 | text-align: left; 221 | margin: 0; 222 | padding: 6px 13px; 223 | } 224 | 225 | table tr td { 226 | border: 1px solid #cccccc; 227 | text-align: left; 228 | margin: 0; 229 | padding: 6px 13px; 230 | } 231 | 232 | table tr th :first-child, table tr td :first-child { 233 | margin-top: 0; 234 | } 235 | 236 | table tr th :last-child, table tr td :last-child { 237 | margin-bottom: 0; 238 | } 239 | 240 | img { 241 | max-width: 100%; 242 | } 243 | 244 | span.frame { 245 | display: block; 246 | overflow: hidden; 247 | } 248 | 249 | span.frame > span { 250 | border: 1px solid #dddddd; 251 | display: block; 252 | float: left; 253 | overflow: hidden; 254 | margin: 13px 0 0; 255 | padding: 7px; 256 | width: auto; 257 | } 258 | 259 | span.frame span img { 260 | display: block; 261 | float: left; 262 | } 263 | 264 | span.frame span span { 265 | clear: both; 266 | color: #333333; 267 | display: block; 268 | padding: 5px 0 0; 269 | } 270 | 271 | span.align-center { 272 | display: block; 273 | overflow: hidden; 274 | clear: both; 275 | } 276 | 277 | span.align-center > span { 278 | display: block; 279 | overflow: hidden; 280 | margin: 13px auto 0; 281 | text-align: center; 282 | } 283 | 284 | span.align-center span img { 285 | margin: 0 auto; 286 | text-align: center; 287 | } 288 | 289 | span.align-right { 290 | display: block; 291 | overflow: hidden; 292 | clear: both; 293 | } 294 | 295 | span.align-right > span { 296 | display: block; 297 | overflow: hidden; 298 | margin: 13px 0 0; 299 | text-align: right; 300 | } 301 | 302 | span.align-right span img { 303 | margin: 0; 304 | text-align: right; 305 | } 306 | 307 | span.float-left { 308 | display: block; 309 | margin-right: 13px; 310 | overflow: hidden; 311 | float: left; 312 | } 313 | 314 | span.float-left span { 315 | margin: 13px 0 0; 316 | } 317 | 318 | span.float-right { 319 | display: block; 320 | margin-left: 13px; 321 | overflow: hidden; 322 | float: right; 323 | } 324 | 325 | span.float-right > span { 326 | display: block; 327 | overflow: hidden; 328 | margin: 13px auto 0; 329 | text-align: right; 330 | } 331 | 332 | pre code { 333 | margin: 0; 334 | padding: 0; 335 | white-space: pre; 336 | border: none; 337 | background: transparent; 338 | } 339 | 340 | pre { 341 | background-color: #f8f8f8; 342 | border: 1px solid #cccccc; 343 | font-size: 13px; 344 | line-height: 19px; 345 | overflow: auto; 346 | padding: 6px 10px; 347 | border-radius: 3px; 348 | } 349 | 350 | figure 351 | { 352 | font-style: italic; 353 | } 354 | 355 | li 356 | { 357 | margin: 0.1em; 358 | } 359 | -------------------------------------------------------------------------------- /tex/599a5166ad0520501c5d389abb0f34b8.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /tex/6fd1684d4ead55dc193d5263233c0a57.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tex/3f9da50841370c429266d54ea7e41469.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tex/ef68da33e858695fb6fa1867bc04cd31.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tex/15fe178ff3c20f9ccaf122aa40408229.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /tex/2dbb3b571269b3589a2967f510e6ecbb.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tex/3dc6bff3f146e4a70a9167b7adfb75d0.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /glad/include/KHR/khrplatform.h: -------------------------------------------------------------------------------- 1 | #ifndef __khrplatform_h_ 2 | #define __khrplatform_h_ 3 | 4 | /* 5 | ** Copyright (c) 2008-2018 The Khronos Group Inc. 6 | ** 7 | ** Permission is hereby granted, free of charge, to any person obtaining a 8 | ** copy of this software and/or associated documentation files (the 9 | ** "Materials"), to deal in the Materials without restriction, including 10 | ** without limitation the rights to use, copy, modify, merge, publish, 11 | ** distribute, sublicense, and/or sell copies of the Materials, and to 12 | ** permit persons to whom the Materials are furnished to do so, subject to 13 | ** the following conditions: 14 | ** 15 | ** The above copyright notice and this permission notice shall be included 16 | ** in all copies or substantial portions of the Materials. 17 | ** 18 | ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. 25 | */ 26 | 27 | /* Khronos platform-specific types and definitions. 28 | * 29 | * The master copy of khrplatform.h is maintained in the Khronos EGL 30 | * Registry repository at https://github.com/KhronosGroup/EGL-Registry 31 | * The last semantic modification to khrplatform.h was at commit ID: 32 | * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 33 | * 34 | * Adopters may modify this file to suit their platform. Adopters are 35 | * encouraged to submit platform specific modifications to the Khronos 36 | * group so that they can be included in future versions of this file. 37 | * Please submit changes by filing pull requests or issues on 38 | * the EGL Registry repository linked above. 39 | * 40 | * 41 | * See the Implementer's Guidelines for information about where this file 42 | * should be located on your system and for more details of its use: 43 | * http://www.khronos.org/registry/implementers_guide.pdf 44 | * 45 | * This file should be included as 46 | * #include 47 | * by Khronos client API header files that use its types and defines. 48 | * 49 | * The types in khrplatform.h should only be used to define API-specific types. 50 | * 51 | * Types defined in khrplatform.h: 52 | * khronos_int8_t signed 8 bit 53 | * khronos_uint8_t unsigned 8 bit 54 | * khronos_int16_t signed 16 bit 55 | * khronos_uint16_t unsigned 16 bit 56 | * khronos_int32_t signed 32 bit 57 | * khronos_uint32_t unsigned 32 bit 58 | * khronos_int64_t signed 64 bit 59 | * khronos_uint64_t unsigned 64 bit 60 | * khronos_intptr_t signed same number of bits as a pointer 61 | * khronos_uintptr_t unsigned same number of bits as a pointer 62 | * khronos_ssize_t signed size 63 | * khronos_usize_t unsigned size 64 | * khronos_float_t signed 32 bit floating point 65 | * khronos_time_ns_t unsigned 64 bit time in nanoseconds 66 | * khronos_utime_nanoseconds_t unsigned time interval or absolute time in 67 | * nanoseconds 68 | * khronos_stime_nanoseconds_t signed time interval in nanoseconds 69 | * khronos_boolean_enum_t enumerated boolean type. This should 70 | * only be used as a base type when a client API's boolean type is 71 | * an enum. Client APIs which use an integer or other type for 72 | * booleans cannot use this as the base type for their boolean. 73 | * 74 | * Tokens defined in khrplatform.h: 75 | * 76 | * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. 77 | * 78 | * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. 79 | * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. 80 | * 81 | * Calling convention macros defined in this file: 82 | * KHRONOS_APICALL 83 | * KHRONOS_APIENTRY 84 | * KHRONOS_APIATTRIBUTES 85 | * 86 | * These may be used in function prototypes as: 87 | * 88 | * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( 89 | * int arg1, 90 | * int arg2) KHRONOS_APIATTRIBUTES; 91 | */ 92 | 93 | /*------------------------------------------------------------------------- 94 | * Definition of KHRONOS_APICALL 95 | *------------------------------------------------------------------------- 96 | * This precedes the return type of the function in the function prototype. 97 | */ 98 | #if defined(_WIN32) && !defined(__SCITECH_SNAP__) 99 | # define KHRONOS_APICALL __declspec(dllimport) 100 | #elif defined (__SYMBIAN32__) 101 | # define KHRONOS_APICALL IMPORT_C 102 | #elif defined(__ANDROID__) 103 | # define KHRONOS_APICALL __attribute__((visibility("default"))) 104 | #else 105 | # define KHRONOS_APICALL 106 | #endif 107 | 108 | /*------------------------------------------------------------------------- 109 | * Definition of KHRONOS_APIENTRY 110 | *------------------------------------------------------------------------- 111 | * This follows the return type of the function and precedes the function 112 | * name in the function prototype. 113 | */ 114 | #if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) 115 | /* Win32 but not WinCE */ 116 | # define KHRONOS_APIENTRY __stdcall 117 | #else 118 | # define KHRONOS_APIENTRY 119 | #endif 120 | 121 | /*------------------------------------------------------------------------- 122 | * Definition of KHRONOS_APIATTRIBUTES 123 | *------------------------------------------------------------------------- 124 | * This follows the closing parenthesis of the function prototype arguments. 125 | */ 126 | #if defined (__ARMCC_2__) 127 | #define KHRONOS_APIATTRIBUTES __softfp 128 | #else 129 | #define KHRONOS_APIATTRIBUTES 130 | #endif 131 | 132 | /*------------------------------------------------------------------------- 133 | * basic type definitions 134 | *-----------------------------------------------------------------------*/ 135 | #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) 136 | 137 | 138 | /* 139 | * Using 140 | */ 141 | #include 142 | typedef int32_t khronos_int32_t; 143 | typedef uint32_t khronos_uint32_t; 144 | typedef int64_t khronos_int64_t; 145 | typedef uint64_t khronos_uint64_t; 146 | #define KHRONOS_SUPPORT_INT64 1 147 | #define KHRONOS_SUPPORT_FLOAT 1 148 | 149 | #elif defined(__VMS ) || defined(__sgi) 150 | 151 | /* 152 | * Using 153 | */ 154 | #include 155 | typedef int32_t khronos_int32_t; 156 | typedef uint32_t khronos_uint32_t; 157 | typedef int64_t khronos_int64_t; 158 | typedef uint64_t khronos_uint64_t; 159 | #define KHRONOS_SUPPORT_INT64 1 160 | #define KHRONOS_SUPPORT_FLOAT 1 161 | 162 | #elif defined(_WIN32) && !defined(__SCITECH_SNAP__) 163 | 164 | /* 165 | * Win32 166 | */ 167 | typedef __int32 khronos_int32_t; 168 | typedef unsigned __int32 khronos_uint32_t; 169 | typedef __int64 khronos_int64_t; 170 | typedef unsigned __int64 khronos_uint64_t; 171 | #define KHRONOS_SUPPORT_INT64 1 172 | #define KHRONOS_SUPPORT_FLOAT 1 173 | 174 | #elif defined(__sun__) || defined(__digital__) 175 | 176 | /* 177 | * Sun or Digital 178 | */ 179 | typedef int khronos_int32_t; 180 | typedef unsigned int khronos_uint32_t; 181 | #if defined(__arch64__) || defined(_LP64) 182 | typedef long int khronos_int64_t; 183 | typedef unsigned long int khronos_uint64_t; 184 | #else 185 | typedef long long int khronos_int64_t; 186 | typedef unsigned long long int khronos_uint64_t; 187 | #endif /* __arch64__ */ 188 | #define KHRONOS_SUPPORT_INT64 1 189 | #define KHRONOS_SUPPORT_FLOAT 1 190 | 191 | #elif 0 192 | 193 | /* 194 | * Hypothetical platform with no float or int64 support 195 | */ 196 | typedef int khronos_int32_t; 197 | typedef unsigned int khronos_uint32_t; 198 | #define KHRONOS_SUPPORT_INT64 0 199 | #define KHRONOS_SUPPORT_FLOAT 0 200 | 201 | #else 202 | 203 | /* 204 | * Generic fallback 205 | */ 206 | #include 207 | typedef int32_t khronos_int32_t; 208 | typedef uint32_t khronos_uint32_t; 209 | typedef int64_t khronos_int64_t; 210 | typedef uint64_t khronos_uint64_t; 211 | #define KHRONOS_SUPPORT_INT64 1 212 | #define KHRONOS_SUPPORT_FLOAT 1 213 | 214 | #endif 215 | 216 | 217 | /* 218 | * Types that are (so far) the same on all platforms 219 | */ 220 | typedef signed char khronos_int8_t; 221 | typedef unsigned char khronos_uint8_t; 222 | typedef signed short int khronos_int16_t; 223 | typedef unsigned short int khronos_uint16_t; 224 | 225 | /* 226 | * Types that differ between LLP64 and LP64 architectures - in LLP64, 227 | * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears 228 | * to be the only LLP64 architecture in current use. 229 | */ 230 | #ifdef _WIN64 231 | typedef signed long long int khronos_intptr_t; 232 | typedef unsigned long long int khronos_uintptr_t; 233 | typedef signed long long int khronos_ssize_t; 234 | typedef unsigned long long int khronos_usize_t; 235 | #else 236 | typedef signed long int khronos_intptr_t; 237 | typedef unsigned long int khronos_uintptr_t; 238 | typedef signed long int khronos_ssize_t; 239 | typedef unsigned long int khronos_usize_t; 240 | #endif 241 | 242 | #if KHRONOS_SUPPORT_FLOAT 243 | /* 244 | * Float type 245 | */ 246 | typedef float khronos_float_t; 247 | #endif 248 | 249 | #if KHRONOS_SUPPORT_INT64 250 | /* Time types 251 | * 252 | * These types can be used to represent a time interval in nanoseconds or 253 | * an absolute Unadjusted System Time. Unadjusted System Time is the number 254 | * of nanoseconds since some arbitrary system event (e.g. since the last 255 | * time the system booted). The Unadjusted System Time is an unsigned 256 | * 64 bit value that wraps back to 0 every 584 years. Time intervals 257 | * may be either signed or unsigned. 258 | */ 259 | typedef khronos_uint64_t khronos_utime_nanoseconds_t; 260 | typedef khronos_int64_t khronos_stime_nanoseconds_t; 261 | #endif 262 | 263 | /* 264 | * Dummy value used to pad enum types to 32 bits. 265 | */ 266 | #ifndef KHRONOS_MAX_ENUM 267 | #define KHRONOS_MAX_ENUM 0x7FFFFFFF 268 | #endif 269 | 270 | /* 271 | * Enumerated boolean type 272 | * 273 | * Values other than zero should be considered to be true. Therefore 274 | * comparisons should not be made against KHRONOS_TRUE. 275 | */ 276 | typedef enum { 277 | KHRONOS_FALSE = 0, 278 | KHRONOS_TRUE = 1, 279 | KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM 280 | } khronos_boolean_enum_t; 281 | 282 | #endif /* __khrplatform_h_ */ 283 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | // clang++ -std=c++11 main.cpp -I include -I $LIBIGL/include -I /usr/local/libigl/external/eigen/ -framework OpenGL -L/usr/local/lib/ -lglfw && ./a.out 2 | // 3 | 4 | // make sure the modern opengl headers are included before any others 5 | #include "gl.h" 6 | #define GLFW_INCLUDE_GLU 7 | #include 8 | 9 | #include "read_json.h" 10 | #include "icosahedron.h" 11 | #include "mesh_to_vao.h" 12 | #include "print_opengl_info.h" 13 | #include "get_seconds.h" 14 | #include "report_gl_error.h" 15 | #include "create_shader_program_from_files.h" 16 | #include "last_modification_time.h" 17 | #ifdef USE_SOLUTION 18 | # include "find_and_replace_all.h" 19 | #endif 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | // Default width and height 32 | bool wire_frame = false; 33 | bool mouse_down = false; 34 | bool is_animating = true; 35 | double last_time = get_seconds(); 36 | double animation_seconds = 0; 37 | int width = 640; 38 | int height = 360; 39 | // Whether display has high dpi (e.g., Mac retinas) 40 | int highdpi = 1; 41 | GLuint prog_id=0; 42 | 43 | Eigen::Affine3f view = 44 | Eigen::Affine3f::Identity() * 45 | Eigen::Translation3f(Eigen::Vector3f(0,0,-10)); 46 | Eigen::Matrix4f proj = Eigen::Matrix4f::Identity(); 47 | 48 | GLuint VAO; 49 | // Mesh data: RowMajor is important to directly use in OpenGL 50 | Eigen::Matrix< float,Eigen::Dynamic,3,Eigen::RowMajor> V; 51 | Eigen::Matrix F; 52 | 53 | int main(int argc, char * argv[]) 54 | { 55 | 56 | std::vector vertex_shader_paths; 57 | std::vector tess_control_shader_paths; 58 | std::vector tess_evaluation_shader_paths; 59 | std::vector fragment_shader_paths; 60 | 61 | // Initialize glfw window 62 | if(!glfwInit()) 63 | { 64 | std::cerr<<"Could not initialize glfw"< &paths, 226 | const double time_of_last_shader_compilation 227 | )->bool 228 | { 229 | for(const auto & path : paths) 230 | { 231 | if(last_modification_time(path) > time_of_last_shader_compilation) 232 | { 233 | std::cout< & paths) 261 | { 262 | for(auto & path : paths) 263 | { 264 | find_and_replace_all("/src/","/solution/",path); 265 | } 266 | }; 267 | replace_all(vertex_shader_paths); 268 | replace_all(tess_control_shader_paths); 269 | replace_all(tess_evaluation_shader_paths); 270 | replace_all(fragment_shader_paths); 271 | } 272 | #endif 273 | // force reload of shaders 274 | time_of_last_shader_compilation = 0; 275 | } 276 | if( 277 | any_changed(vertex_shader_paths ,time_of_last_shader_compilation) || 278 | any_changed(tess_control_shader_paths ,time_of_last_shader_compilation) || 279 | any_changed(tess_evaluation_shader_paths,time_of_last_shader_compilation) || 280 | any_changed(fragment_shader_paths ,time_of_last_shader_compilation)) 281 | { 282 | std::cout<<"-----------------------------------------------"< 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /css/github-markdown.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: octicons-link; 3 | src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAZwABAAAAAACFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEU0lHAAAGaAAAAAgAAAAIAAAAAUdTVUIAAAZcAAAACgAAAAoAAQAAT1MvMgAAAyQAAABJAAAAYFYEU3RjbWFwAAADcAAAAEUAAACAAJThvmN2dCAAAATkAAAABAAAAAQAAAAAZnBnbQAAA7gAAACyAAABCUM+8IhnYXNwAAAGTAAAABAAAAAQABoAI2dseWYAAAFsAAABPAAAAZwcEq9taGVhZAAAAsgAAAA0AAAANgh4a91oaGVhAAADCAAAABoAAAAkCA8DRGhtdHgAAAL8AAAADAAAAAwGAACfbG9jYQAAAsAAAAAIAAAACABiATBtYXhwAAACqAAAABgAAAAgAA8ASm5hbWUAAAToAAABQgAAAlXu73sOcG9zdAAABiwAAAAeAAAAME3QpOBwcmVwAAAEbAAAAHYAAAB/aFGpk3jaTY6xa8JAGMW/O62BDi0tJLYQincXEypYIiGJjSgHniQ6umTsUEyLm5BV6NDBP8Tpts6F0v+k/0an2i+itHDw3v2+9+DBKTzsJNnWJNTgHEy4BgG3EMI9DCEDOGEXzDADU5hBKMIgNPZqoD3SilVaXZCER3/I7AtxEJLtzzuZfI+VVkprxTlXShWKb3TBecG11rwoNlmmn1P2WYcJczl32etSpKnziC7lQyWe1smVPy/Lt7Kc+0vWY/gAgIIEqAN9we0pwKXreiMasxvabDQMM4riO+qxM2ogwDGOZTXxwxDiycQIcoYFBLj5K3EIaSctAq2kTYiw+ymhce7vwM9jSqO8JyVd5RH9gyTt2+J/yUmYlIR0s04n6+7Vm1ozezUeLEaUjhaDSuXHwVRgvLJn1tQ7xiuVv/ocTRF42mNgZGBgYGbwZOBiAAFGJBIMAAizAFoAAABiAGIAznjaY2BkYGAA4in8zwXi+W2+MjCzMIDApSwvXzC97Z4Ig8N/BxYGZgcgl52BCSQKAA3jCV8CAABfAAAAAAQAAEB42mNgZGBg4f3vACQZQABIMjKgAmYAKEgBXgAAeNpjYGY6wTiBgZWBg2kmUxoDA4MPhGZMYzBi1AHygVLYQUCaawqDA4PChxhmh/8ODDEsvAwHgMKMIDnGL0x7gJQCAwMAJd4MFwAAAHjaY2BgYGaA4DAGRgYQkAHyGMF8NgYrIM3JIAGVYYDT+AEjAwuDFpBmA9KMDEwMCh9i/v8H8sH0/4dQc1iAmAkALaUKLgAAAHjaTY9LDsIgEIbtgqHUPpDi3gPoBVyRTmTddOmqTXThEXqrob2gQ1FjwpDvfwCBdmdXC5AVKFu3e5MfNFJ29KTQT48Ob9/lqYwOGZxeUelN2U2R6+cArgtCJpauW7UQBqnFkUsjAY/kOU1cP+DAgvxwn1chZDwUbd6CFimGXwzwF6tPbFIcjEl+vvmM/byA48e6tWrKArm4ZJlCbdsrxksL1AwWn/yBSJKpYbq8AXaaTb8AAHja28jAwOC00ZrBeQNDQOWO//sdBBgYGRiYWYAEELEwMTE4uzo5Zzo5b2BxdnFOcALxNjA6b2ByTswC8jYwg0VlNuoCTWAMqNzMzsoK1rEhNqByEyerg5PMJlYuVueETKcd/89uBpnpvIEVomeHLoMsAAe1Id4AAAAAAAB42oWQT07CQBTGv0JBhagk7HQzKxca2sJCE1hDt4QF+9JOS0nbaaYDCQfwCJ7Au3AHj+LO13FMmm6cl7785vven0kBjHCBhfpYuNa5Ph1c0e2Xu3jEvWG7UdPDLZ4N92nOm+EBXuAbHmIMSRMs+4aUEd4Nd3CHD8NdvOLTsA2GL8M9PODbcL+hD7C1xoaHeLJSEao0FEW14ckxC+TU8TxvsY6X0eLPmRhry2WVioLpkrbp84LLQPGI7c6sOiUzpWIWS5GzlSgUzzLBSikOPFTOXqly7rqx0Z1Q5BAIoZBSFihQYQOOBEdkCOgXTOHA07HAGjGWiIjaPZNW13/+lm6S9FT7rLHFJ6fQbkATOG1j2OFMucKJJsxIVfQORl+9Jyda6Sl1dUYhSCm1dyClfoeDve4qMYdLEbfqHf3O/AdDumsjAAB42mNgYoAAZQYjBmyAGYQZmdhL8zLdDEydARfoAqIAAAABAAMABwAKABMAB///AA8AAQAAAAAAAAAAAAAAAAABAAAAAA==) format('woff'); 4 | } 5 | 6 | .markdown-body { 7 | -ms-text-size-adjust: 100%; 8 | -webkit-text-size-adjust: 100%; 9 | line-height: 1.5; 10 | color: #24292e; 11 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 12 | font-size: 16px; 13 | line-height: 1.5; 14 | word-wrap: break-word; 15 | } 16 | 17 | .markdown-body .pl-c { 18 | color: #6a737d; 19 | } 20 | 21 | .markdown-body .pl-c1, 22 | .markdown-body .pl-s .pl-v { 23 | color: #005cc5; 24 | } 25 | 26 | .markdown-body .pl-e, 27 | .markdown-body .pl-en { 28 | color: #6f42c1; 29 | } 30 | 31 | .markdown-body .pl-smi, 32 | .markdown-body .pl-s .pl-s1 { 33 | color: #24292e; 34 | } 35 | 36 | .markdown-body .pl-ent { 37 | color: #22863a; 38 | } 39 | 40 | .markdown-body .pl-k { 41 | color: #d73a49; 42 | } 43 | 44 | .markdown-body .pl-s, 45 | .markdown-body .pl-pds, 46 | .markdown-body .pl-s .pl-pse .pl-s1, 47 | .markdown-body .pl-sr, 48 | .markdown-body .pl-sr .pl-cce, 49 | .markdown-body .pl-sr .pl-sre, 50 | .markdown-body .pl-sr .pl-sra { 51 | color: #032f62; 52 | } 53 | 54 | .markdown-body .pl-v, 55 | .markdown-body .pl-smw { 56 | color: #e36209; 57 | } 58 | 59 | .markdown-body .pl-bu { 60 | color: #b31d28; 61 | } 62 | 63 | .markdown-body .pl-ii { 64 | color: #fafbfc; 65 | background-color: #b31d28; 66 | } 67 | 68 | .markdown-body .pl-c2 { 69 | color: #fafbfc; 70 | background-color: #d73a49; 71 | } 72 | 73 | .markdown-body .pl-c2::before { 74 | content: "^M"; 75 | } 76 | 77 | .markdown-body .pl-sr .pl-cce { 78 | font-weight: bold; 79 | color: #22863a; 80 | } 81 | 82 | .markdown-body .pl-ml { 83 | color: #735c0f; 84 | } 85 | 86 | .markdown-body .pl-mh, 87 | .markdown-body .pl-mh .pl-en, 88 | .markdown-body .pl-ms { 89 | font-weight: bold; 90 | color: #005cc5; 91 | } 92 | 93 | .markdown-body .pl-mi { 94 | font-style: italic; 95 | color: #24292e; 96 | } 97 | 98 | .markdown-body .pl-mb { 99 | font-weight: bold; 100 | color: #24292e; 101 | } 102 | 103 | .markdown-body .pl-md { 104 | color: #b31d28; 105 | background-color: #ffeef0; 106 | } 107 | 108 | .markdown-body .pl-mi1 { 109 | color: #22863a; 110 | background-color: #f0fff4; 111 | } 112 | 113 | .markdown-body .pl-mc { 114 | color: #e36209; 115 | background-color: #ffebda; 116 | } 117 | 118 | .markdown-body .pl-mi2 { 119 | color: #f6f8fa; 120 | background-color: #005cc5; 121 | } 122 | 123 | .markdown-body .pl-mdr { 124 | font-weight: bold; 125 | color: #6f42c1; 126 | } 127 | 128 | .markdown-body .pl-ba { 129 | color: #586069; 130 | } 131 | 132 | .markdown-body .pl-sg { 133 | color: #959da5; 134 | } 135 | 136 | .markdown-body .pl-corl { 137 | text-decoration: underline; 138 | color: #032f62; 139 | } 140 | 141 | .markdown-body .octicon { 142 | display: inline-block; 143 | vertical-align: text-top; 144 | fill: currentColor; 145 | } 146 | 147 | .markdown-body a { 148 | background-color: transparent; 149 | } 150 | 151 | .markdown-body a:active, 152 | .markdown-body a:hover { 153 | outline-width: 0; 154 | } 155 | 156 | .markdown-body strong { 157 | font-weight: inherit; 158 | } 159 | 160 | .markdown-body strong { 161 | font-weight: bolder; 162 | } 163 | 164 | .markdown-body h1 { 165 | font-size: 2em; 166 | margin: 0.67em 0; 167 | } 168 | 169 | .markdown-body img { 170 | border-style: none; 171 | } 172 | 173 | .markdown-body code, 174 | .markdown-body kbd, 175 | .markdown-body pre { 176 | font-family: monospace, monospace; 177 | font-size: 1em; 178 | } 179 | 180 | .markdown-body hr { 181 | box-sizing: content-box; 182 | height: 0; 183 | overflow: visible; 184 | } 185 | 186 | .markdown-body input { 187 | font: inherit; 188 | margin: 0; 189 | } 190 | 191 | .markdown-body input { 192 | overflow: visible; 193 | } 194 | 195 | .markdown-body [type="checkbox"] { 196 | box-sizing: border-box; 197 | padding: 0; 198 | } 199 | 200 | .markdown-body * { 201 | box-sizing: border-box; 202 | } 203 | 204 | .markdown-body input { 205 | font-family: inherit; 206 | font-size: inherit; 207 | line-height: inherit; 208 | } 209 | 210 | .markdown-body a { 211 | color: #0366d6; 212 | text-decoration: none; 213 | } 214 | 215 | .markdown-body a:hover { 216 | text-decoration: underline; 217 | } 218 | 219 | .markdown-body strong { 220 | font-weight: 600; 221 | } 222 | 223 | .markdown-body hr { 224 | height: 0; 225 | margin: 15px 0; 226 | overflow: hidden; 227 | background: transparent; 228 | border: 0; 229 | border-bottom: 1px solid #dfe2e5; 230 | } 231 | 232 | .markdown-body hr::before { 233 | display: table; 234 | content: ""; 235 | } 236 | 237 | .markdown-body hr::after { 238 | display: table; 239 | clear: both; 240 | content: ""; 241 | } 242 | 243 | .markdown-body table { 244 | border-spacing: 0; 245 | border-collapse: collapse; 246 | } 247 | 248 | .markdown-body td, 249 | .markdown-body th { 250 | padding: 0; 251 | } 252 | 253 | .markdown-body h1, 254 | .markdown-body h2, 255 | .markdown-body h3, 256 | .markdown-body h4, 257 | .markdown-body h5, 258 | .markdown-body h6 { 259 | margin-top: 0; 260 | margin-bottom: 0; 261 | } 262 | 263 | .markdown-body h1 { 264 | font-size: 32px; 265 | font-weight: 600; 266 | } 267 | 268 | .markdown-body h2 { 269 | font-size: 24px; 270 | font-weight: 600; 271 | } 272 | 273 | .markdown-body h3 { 274 | font-size: 20px; 275 | font-weight: 600; 276 | } 277 | 278 | .markdown-body h4 { 279 | font-size: 16px; 280 | font-weight: 600; 281 | } 282 | 283 | .markdown-body h5 { 284 | font-size: 14px; 285 | font-weight: 600; 286 | } 287 | 288 | .markdown-body h6 { 289 | font-size: 12px; 290 | font-weight: 600; 291 | } 292 | 293 | .markdown-body p { 294 | margin-top: 0; 295 | margin-bottom: 10px; 296 | } 297 | 298 | .markdown-body blockquote { 299 | margin: 0; 300 | } 301 | 302 | .markdown-body ul, 303 | .markdown-body ol { 304 | padding-left: 0; 305 | margin-top: 0; 306 | margin-bottom: 0; 307 | } 308 | 309 | .markdown-body ol ol, 310 | .markdown-body ul ol { 311 | list-style-type: lower-roman; 312 | } 313 | 314 | .markdown-body ul ul ol, 315 | .markdown-body ul ol ol, 316 | .markdown-body ol ul ol, 317 | .markdown-body ol ol ol { 318 | list-style-type: lower-alpha; 319 | } 320 | 321 | .markdown-body dd { 322 | margin-left: 0; 323 | } 324 | 325 | .markdown-body code { 326 | font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 327 | font-size: 12px; 328 | } 329 | 330 | .markdown-body pre { 331 | margin-top: 0; 332 | margin-bottom: 0; 333 | font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 334 | font-size: 12px; 335 | } 336 | 337 | .markdown-body .octicon { 338 | vertical-align: text-bottom; 339 | } 340 | 341 | .markdown-body .pl-0 { 342 | padding-left: 0 !important; 343 | } 344 | 345 | .markdown-body .pl-1 { 346 | padding-left: 4px !important; 347 | } 348 | 349 | .markdown-body .pl-2 { 350 | padding-left: 8px !important; 351 | } 352 | 353 | .markdown-body .pl-3 { 354 | padding-left: 16px !important; 355 | } 356 | 357 | .markdown-body .pl-4 { 358 | padding-left: 24px !important; 359 | } 360 | 361 | .markdown-body .pl-5 { 362 | padding-left: 32px !important; 363 | } 364 | 365 | .markdown-body .pl-6 { 366 | padding-left: 40px !important; 367 | } 368 | 369 | .markdown-body::before { 370 | display: table; 371 | content: ""; 372 | } 373 | 374 | .markdown-body::after { 375 | display: table; 376 | clear: both; 377 | content: ""; 378 | } 379 | 380 | .markdown-body>*:first-child { 381 | margin-top: 0 !important; 382 | } 383 | 384 | .markdown-body>*:last-child { 385 | margin-bottom: 0 !important; 386 | } 387 | 388 | .markdown-body a:not([href]) { 389 | color: inherit; 390 | text-decoration: none; 391 | } 392 | 393 | .markdown-body .anchor { 394 | float: left; 395 | padding-right: 4px; 396 | margin-left: -20px; 397 | line-height: 1; 398 | } 399 | 400 | .markdown-body .anchor:focus { 401 | outline: none; 402 | } 403 | 404 | .markdown-body p, 405 | .markdown-body blockquote, 406 | .markdown-body ul, 407 | .markdown-body ol, 408 | .markdown-body dl, 409 | .markdown-body table, 410 | .markdown-body pre { 411 | margin-top: 0; 412 | margin-bottom: 16px; 413 | } 414 | 415 | .markdown-body hr { 416 | height: 0.25em; 417 | padding: 0; 418 | margin: 24px 0; 419 | background-color: #e1e4e8; 420 | border: 0; 421 | } 422 | 423 | .markdown-body blockquote { 424 | padding: 0 1em; 425 | color: #6a737d; 426 | border-left: 0.25em solid #dfe2e5; 427 | } 428 | 429 | .markdown-body blockquote>:first-child { 430 | margin-top: 0; 431 | } 432 | 433 | .markdown-body blockquote>:last-child { 434 | margin-bottom: 0; 435 | } 436 | 437 | .markdown-body kbd { 438 | display: inline-block; 439 | padding: 3px 5px; 440 | font-size: 11px; 441 | line-height: 10px; 442 | color: #444d56; 443 | vertical-align: middle; 444 | background-color: #fafbfc; 445 | border: solid 1px #c6cbd1; 446 | border-bottom-color: #959da5; 447 | border-radius: 3px; 448 | box-shadow: inset 0 -1px 0 #959da5; 449 | } 450 | 451 | .markdown-body h1, 452 | .markdown-body h2, 453 | .markdown-body h3, 454 | .markdown-body h4, 455 | .markdown-body h5, 456 | .markdown-body h6 { 457 | margin-top: 24px; 458 | margin-bottom: 16px; 459 | font-weight: 600; 460 | line-height: 1.25; 461 | } 462 | 463 | .markdown-body h1 .octicon-link, 464 | .markdown-body h2 .octicon-link, 465 | .markdown-body h3 .octicon-link, 466 | .markdown-body h4 .octicon-link, 467 | .markdown-body h5 .octicon-link, 468 | .markdown-body h6 .octicon-link { 469 | color: #1b1f23; 470 | vertical-align: middle; 471 | visibility: hidden; 472 | } 473 | 474 | .markdown-body h1:hover .anchor, 475 | .markdown-body h2:hover .anchor, 476 | .markdown-body h3:hover .anchor, 477 | .markdown-body h4:hover .anchor, 478 | .markdown-body h5:hover .anchor, 479 | .markdown-body h6:hover .anchor { 480 | text-decoration: none; 481 | } 482 | 483 | .markdown-body h1:hover .anchor .octicon-link, 484 | .markdown-body h2:hover .anchor .octicon-link, 485 | .markdown-body h3:hover .anchor .octicon-link, 486 | .markdown-body h4:hover .anchor .octicon-link, 487 | .markdown-body h5:hover .anchor .octicon-link, 488 | .markdown-body h6:hover .anchor .octicon-link { 489 | visibility: visible; 490 | } 491 | 492 | .markdown-body h1 { 493 | padding-bottom: 0.3em; 494 | font-size: 2em; 495 | border-bottom: 1px solid #eaecef; 496 | } 497 | 498 | .markdown-body h2 { 499 | padding-bottom: 0.3em; 500 | font-size: 1.5em; 501 | border-bottom: 1px solid #eaecef; 502 | } 503 | 504 | .markdown-body h3 { 505 | font-size: 1.25em; 506 | } 507 | 508 | .markdown-body h4 { 509 | font-size: 1em; 510 | } 511 | 512 | .markdown-body h5 { 513 | font-size: 0.875em; 514 | } 515 | 516 | .markdown-body h6 { 517 | font-size: 0.85em; 518 | color: #6a737d; 519 | } 520 | 521 | .markdown-body ul, 522 | .markdown-body ol { 523 | padding-left: 2em; 524 | } 525 | 526 | .markdown-body ul ul, 527 | .markdown-body ul ol, 528 | .markdown-body ol ol, 529 | .markdown-body ol ul { 530 | margin-top: 0; 531 | margin-bottom: 0; 532 | } 533 | 534 | .markdown-body li { 535 | word-wrap: break-all; 536 | } 537 | 538 | .markdown-body li>p { 539 | margin-top: 16px; 540 | } 541 | 542 | .markdown-body li+li { 543 | margin-top: 0.25em; 544 | } 545 | 546 | .markdown-body dl { 547 | padding: 0; 548 | } 549 | 550 | .markdown-body dl dt { 551 | padding: 0; 552 | margin-top: 16px; 553 | font-size: 1em; 554 | font-style: italic; 555 | font-weight: 600; 556 | } 557 | 558 | .markdown-body dl dd { 559 | padding: 0 16px; 560 | margin-bottom: 16px; 561 | } 562 | 563 | .markdown-body table { 564 | display: block; 565 | width: 100%; 566 | overflow: auto; 567 | } 568 | 569 | .markdown-body table th { 570 | font-weight: 600; 571 | } 572 | 573 | .markdown-body table th, 574 | .markdown-body table td { 575 | padding: 6px 13px; 576 | border: 1px solid #dfe2e5; 577 | } 578 | 579 | .markdown-body table tr { 580 | background-color: #fff; 581 | border-top: 1px solid #c6cbd1; 582 | } 583 | 584 | .markdown-body table tr:nth-child(2n) { 585 | background-color: #f6f8fa; 586 | } 587 | 588 | .markdown-body img { 589 | max-width: 100%; 590 | box-sizing: content-box; 591 | background-color: #fff; 592 | } 593 | 594 | .markdown-body img[align=right] { 595 | padding-left: 20px; 596 | } 597 | 598 | .markdown-body img[align=left] { 599 | padding-right: 20px; 600 | } 601 | 602 | .markdown-body code { 603 | padding: 0.2em 0.4em; 604 | margin: 0; 605 | font-size: 85%; 606 | background-color: rgba(27,31,35,0.05); 607 | border-radius: 3px; 608 | } 609 | 610 | .markdown-body pre { 611 | word-wrap: normal; 612 | } 613 | 614 | .markdown-body pre>code { 615 | padding: 0; 616 | margin: 0; 617 | font-size: 100%; 618 | word-break: normal; 619 | white-space: pre; 620 | background: transparent; 621 | border: 0; 622 | } 623 | 624 | .markdown-body .highlight { 625 | margin-bottom: 16px; 626 | } 627 | 628 | .markdown-body .highlight pre { 629 | margin-bottom: 0; 630 | word-break: normal; 631 | } 632 | 633 | .markdown-body .highlight pre, 634 | .markdown-body pre { 635 | padding: 16px; 636 | overflow: auto; 637 | font-size: 85%; 638 | line-height: 1.45; 639 | background-color: #f6f8fa; 640 | border-radius: 3px; 641 | } 642 | 643 | .markdown-body pre code { 644 | display: inline; 645 | max-width: auto; 646 | padding: 0; 647 | margin: 0; 648 | overflow: visible; 649 | line-height: inherit; 650 | word-wrap: normal; 651 | background-color: transparent; 652 | border: 0; 653 | } 654 | 655 | .markdown-body .full-commit .btn-outline:not(:disabled):hover { 656 | color: #005cc5; 657 | border-color: #005cc5; 658 | } 659 | 660 | .markdown-body kbd { 661 | display: inline-block; 662 | padding: 3px 5px; 663 | font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 664 | line-height: 10px; 665 | color: #444d56; 666 | vertical-align: middle; 667 | background-color: #fafbfc; 668 | border: solid 1px #d1d5da; 669 | border-bottom-color: #c6cbd1; 670 | border-radius: 3px; 671 | box-shadow: inset 0 -1px 0 #c6cbd1; 672 | } 673 | 674 | .markdown-body :checked+.radio-label { 675 | position: relative; 676 | z-index: 1; 677 | border-color: #0366d6; 678 | } 679 | 680 | .markdown-body .task-list-item { 681 | list-style-type: none; 682 | } 683 | 684 | .markdown-body .task-list-item+.task-list-item { 685 | margin-top: 3px; 686 | } 687 | 688 | .markdown-body .task-list-item input { 689 | margin: 0 0.2em 0.25em -1.6em; 690 | vertical-align: middle; 691 | } 692 | 693 | .markdown-body hr { 694 | border-bottom-color: #eee; 695 | } 696 | --------------------------------------------------------------------------------