├── .gitignore ├── LICENSE ├── README.md ├── SDL2.dll ├── colors.frag ├── easygl.nimble ├── examples ├── advanced_lighting │ ├── advanced_lighting.nim │ ├── gamma_correction.nim │ ├── shaders │ │ ├── advanced_lighting.frag │ │ ├── advanced_lighting.vert │ │ ├── gamma_correction.frag │ │ └── gamma_correction.vert │ └── textures │ │ └── wood.png ├── advanced_opengl │ ├── advanced_glsl.nim │ ├── anti_aliasing.nim │ ├── anti_aliasing_offscreen.nim │ ├── asteroids_instanced.nim │ ├── blending.nim │ ├── cubemaps.nim │ ├── depth_testing.nim │ ├── framebuffers.nim │ ├── geometry_shader.nim │ ├── models │ │ ├── planet │ │ │ ├── planet.mtl │ │ │ ├── planet.obj │ │ │ └── planet_Quom1200.png │ │ └── rock │ │ │ ├── rock.mtl │ │ │ ├── rock.obj │ │ │ └── rock.png │ ├── shaders │ │ ├── aa_post.frag │ │ ├── aa_post.vert │ │ ├── advanced.frag │ │ ├── advanced.vert │ │ ├── advanced_glsl.vert │ │ ├── anti_aliasing.frag │ │ ├── anti_aliasing.vert │ │ ├── asteroids.frag │ │ ├── asteroids.vert │ │ ├── blending.frag │ │ ├── blending.vert │ │ ├── blue.frag │ │ ├── cubemaps.frag │ │ ├── cubemaps.vert │ │ ├── depth_testing.frag │ │ ├── depth_testing.vert │ │ ├── framebuffers.frag │ │ ├── framebuffers.vert │ │ ├── framebuffers_screen.frag │ │ ├── framebuffers_screen.vert │ │ ├── geometry_shader.frag │ │ ├── geometry_shader.geom │ │ ├── geometry_shader.vert │ │ ├── green.frag │ │ ├── planet.frag │ │ ├── planet.vert │ │ ├── red.frag │ │ ├── skybox.frag │ │ ├── skybox.vert │ │ ├── stencil_single_color.frag │ │ ├── stencil_testing.frag │ │ ├── stencil_testing.vert │ │ └── yellow.frag │ ├── stencil_testing.nim │ └── textures │ │ ├── back.jpg │ │ ├── bottom.jpg │ │ ├── container.jpg │ │ ├── front.jpg │ │ ├── left.jpg │ │ ├── marble.jpg │ │ ├── metal.png │ │ ├── right.jpg │ │ ├── top.jpg │ │ └── window.png ├── getting_started │ ├── camera.nim │ ├── coordinate_systems.nim │ ├── hello_triangle.nim │ ├── shaders │ │ ├── camera.frag │ │ ├── camera.vert │ │ ├── coordinate_systems.frag │ │ ├── coordinate_systems.vert │ │ ├── hello_triangle.frag │ │ ├── hello_triangle.vert │ │ ├── shaders.frag │ │ ├── shaders.vert │ │ ├── textures.frag │ │ ├── textures.vert │ │ ├── transformations.frag │ │ └── transformations.vert │ ├── shaderstut.nim │ ├── textures │ │ ├── awesomeface.png │ │ └── container.jpg │ ├── texturestut.nim │ └── transformations.nim ├── lighting │ ├── basic_lighting.nim │ ├── colors.nim │ ├── light_casters.nim │ ├── lighting_maps.nim │ ├── materials.nim │ ├── multiple_lights.nim │ ├── shaders │ │ ├── basic_lighting.frag │ │ ├── basic_lighting.vert │ │ ├── colors.frag │ │ ├── colors.vert │ │ ├── lamp.frag │ │ ├── lamp.vert │ │ ├── light_casters.frag │ │ ├── light_casters.vert │ │ ├── lighting_maps.frag │ │ ├── lighting_maps.vert │ │ ├── materials.frag │ │ ├── materials.vert │ │ ├── multiple_lights.frag │ │ └── multiple_lights.vert │ └── textures │ │ ├── container2.png │ │ └── container2_specular.png ├── model_loading │ ├── model_loading.nim │ ├── models │ │ ├── LICENSE.txt │ │ ├── arm_dif.png │ │ ├── arm_showroom_ddn.png │ │ ├── arm_showroom_spec.png │ │ ├── body_dif.png │ │ ├── body_showroom_ddn.png │ │ ├── body_showroom_spec.png │ │ ├── glass_ddn.png │ │ ├── glass_dif.png │ │ ├── hand_dif.png │ │ ├── hand_showroom_ddn.png │ │ ├── hand_showroom_spec.png │ │ ├── helmet_diff.png │ │ ├── helmet_showroom_ddn.png │ │ ├── helmet_showroom_spec.png │ │ ├── leg_dif.png │ │ ├── leg_showroom_ddn.png │ │ ├── leg_showroom_spec.png │ │ ├── nanosuit.blend │ │ ├── nanosuit.mtl │ │ └── nanosuit.obj │ └── shaders │ │ ├── model_loading.frag │ │ └── model_loading.vert ├── nim.cfg └── utils │ └── camera_util.nim └── src ├── easygl.nim └── easygl ├── assimp.nim ├── mesh.nim ├── model.nim └── utils.nim /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*.* 3 | !*/ 4 | nimcache/ 5 | *.swp 6 | *.exe 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jack Mott 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EasyGL 2 | 3 | A typesafe opengl wrapper for the nim language with no runtime overhead 4 | 5 | Also includes utility functions for working with shaders, model importing (using ASSIMP), and texture loading (using stb_image) 6 | 7 | /examples includes a port (ongoing) of the tutorials on learnopengl.com 8 | 9 | 10 | 11 | # OpenGL ids are made type safe 12 | 13 | OpenGL uses object ids in it's api which are all just unsigned integers. This can cause hard to track down bugs. For instance, if you transposed program and shader on accident, it would compile fine in C or with a normal wrapper, as both are GLuint types. You would need to call glGetError() to find out what was wrong, and you wouldn't know what line of code it was caused by: 14 | 15 | ```c 16 | // void glAttachShader(GLuint program,GLuint shader); 17 | 18 | glAttachShader(shader,program); // no compile time error 19 | 20 | ``` 21 | 22 | With EasyGL I use Nim's `distinct` type alias feature so that this would be a compiler error: 23 | 24 | ```nim 25 | type ShaderId = distinct GLuint 26 | type ShaderProgramId = distinct GLuint 27 | 28 | template AttachShader(program:ShaderProgramId,shader:ShaderId) = 29 | glAttachShader(program.GLuint,shader.GLuint) 30 | 31 | AttachShader(shader,program) # compile error because shader and program are transposed 32 | ``` 33 | 34 | 35 | # Range types prevent invalid input 36 | 37 | Some OpenGL functions only accept a certain range of values as valid, but the type system can't restrict that at compile time. EasyGL uses Nim's range type to constrain input. For instance glVertexAttribPointer can only accept 1..4 as valid input for the size parameter. Using a range type this can be checked at compile time when possible, and a runtime in debug builds. 38 | 39 | ```nim 40 | type VertexAttribSize = range[1..4] 41 | template VertexAttribPointer*(index:uint32, size:VertexAttribSize, attribType:GL_, normalized:bool, stride:int, offset:int) = 42 | glVertexAttribPointer(index.GLuint, size.GLint, attribType.GLenum, normalized.GLboolean,stride.GLsizei, cast[pointer](offset)) 43 | ``` 44 | 45 | # Remove the need for casting and non idiomatic Nim code 46 | 47 | Using the raw OpenGL bindings requries constant casting and non idiomatic code. Such as: 48 | 49 | ```nim 50 | 51 | glBufferData(GL_ARRAY_BUFFER,data.len*T.sizeof().GLsizeiptr,data[0].unsafeAddr,GL_STATIC_DRAW) 52 | 53 | ``` 54 | Here one must pass an unsafe pointer to a `seq` type, and it's size, even though seq already knows it's size. EasyGl abstracts this away, and can accept seq or array types: 55 | 56 | ```nim 57 | BufferData(GL_ARRAY_BUFFER,data,GL_STATIC_DRAW) 58 | ``` 59 | 60 | # Handy utility functions with Nim Generics 61 | 62 | Using Nim's generics features one can drastically reduce the amount of code needed for some common OpenGL patterns, for instance: 63 | 64 | ```c 65 | unsigned int planeVAO, planeVBO; 66 | glGenVertexArrays(1, &planeVAO); 67 | glGenBuffers(1, &planeVBO); 68 | glBindVertexArray(planeVAO); 69 | glBindBuffer(GL_ARRAY_BUFFER, planeVBO); 70 | glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_DRAW); 71 | glEnableVertexAttribArray(0); 72 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); 73 | glEnableVertexAttribArray(1); 74 | glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); 75 | glEnableVertexAttribArray(2); 76 | glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); 77 | glBindVertexArray(0); 78 | ``` 79 | 80 | becomes: 81 | 82 | ```nim 83 | let (planeVAO,planeVBO) = 84 | VertexAttribSetup( 85 | GL_ARRAY_BUFFER, 86 | planeVertices, 87 | GL_STATIC_DRAW, 88 | false, 89 | (0,3),(1,3),(2,2)) 90 | ``` 91 | 92 | -------------------------------------------------------------------------------- /SDL2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackmott/easygl/9a987b48409875ffb0521f3887ae25571ff60347/SDL2.dll -------------------------------------------------------------------------------- /colors.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | out vec4 FragColor; 3 | 4 | uniform vec3 objectColor; 5 | uniform vec3 lightColor; 6 | 7 | void main() 8 | { 9 | FragColor = vec4(lightColor * objectColor, 1.0); 10 | } 11 | -------------------------------------------------------------------------------- /easygl.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "0.1.1" 4 | author = "Jack Mott" 5 | description = "type safe opengl wrapper" 6 | license = "MIT" 7 | 8 | srcDir = "src" 9 | 10 | # Dependencies 11 | 12 | requires "nim >= 0.20.0" 13 | requires "sdl2" 14 | requires "opengl" 15 | requires "stb_image" 16 | requires "glm" 17 | 18 | -------------------------------------------------------------------------------- /examples/advanced_lighting/advanced_lighting.nim: -------------------------------------------------------------------------------- 1 | # OpenGL example using SDL2 2 | 3 | import 4 | sdl2, 5 | opengl, 6 | easygl, 7 | easygl.utils, 8 | stb_image/read as stbi, 9 | glm, 10 | ../utils/camera_util, 11 | times, 12 | os 13 | 14 | discard sdl2.init(INIT_EVERYTHING) 15 | 16 | var screenWidth: cint = 1280 17 | var screenHeight: cint = 720 18 | var gamma = false 19 | var gammaKeyPress = false; 20 | 21 | let window = createWindow("Float", 100, 100, screenWidth, screenHeight, SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE) 22 | discard setRelativeMouseMode(true.Bool32) 23 | discard window.glCreateContext() 24 | 25 | # Initialize OpenGL 26 | loadExtensions() 27 | 28 | 29 | enable(GL_DEPTH_TEST) 30 | enable(GL_BLEND) 31 | blendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) 32 | 33 | 34 | ### Build and compile shader program 35 | let appDir = getAppDir() 36 | let shader = createAndLinkProgram(appDir&"/shaders/advanced_lighting.vert",appDir&"/shaders/advanced_lighting.frag") 37 | 38 | 39 | 40 | # Set up vertex data 41 | let planeVertices : seq[float32] = 42 | @[ 43 | # positions #normals # texcoords 44 | 10.0'f32, -0.5'f32, 10.0'f32, 0.0'f32, 1.0'f32, 0.0'f32, 10.0'f32, 0.0'f32, 45 | -10.0'f32, -0.5'f32, 10.0'f32, 0.0'f32, 1.0'f32, 0.0'f32, 0.0'f32, 0.0'f32, 46 | -10.0'f32, -0.5'f32, -10.0'f32, 0.0'f32, 1.0'f32, 0.0'f32, 0.0'f32, 10.0'f32, 47 | 48 | 10.0'f32, -0.5'f32, 10.0'f32, 0.0'f32, 1.0'f32, 0.0'f32, 10.0'f32, 0.0'f32, 49 | -10.0'f32, -0.5'f32, -10.0'f32, 0.0'f32, 1.0'f32, 0.0'f32, 0.0'f32, 10.0'f32, 50 | 10.0'f32, -0.5'f32, -10.0'f32, 0.0'f32, 1.0'f32, 0.0'f32, 10.0'f32, 10.0'f32] 51 | 52 | let planeVAO = genBindVertexArray() 53 | let planeVBO = genBindBufferData(GL_ARRAY_BUFFER,planeVertices,GL_STATIC_DRAW) 54 | enableVertexAttribArray(0) 55 | vertexAttribPointer(0,3,cGL_FLOAT,false,8*float32.sizeof(),0) 56 | enableVertexAttribArray(1) 57 | vertexAttribPointer(1,3,cGL_FLOAT,false,8*float32.sizeof(),3*float32.sizeof()) 58 | enableVertexAttribArray(2) 59 | vertexAttribPointer(2,2,cGL_FLOAT,false,8*float32.sizeof(),6*float32.sizeof()) 60 | unBindVertexArray() 61 | 62 | let floorTexture = loadTextureWithMips(appDir&"/textures/wood.png") 63 | 64 | var lightPos = vec3(0.0'f32,0.0'f32,0.0'f32) 65 | 66 | shader.use() 67 | shader.setInt("texture1",0) 68 | 69 | var 70 | evt = sdl2.defaultEvent 71 | run = true 72 | 73 | viewport(0, 0, screenWidth, screenHeight) # Set the viewport to cover the new window 74 | let camera = newCamera(vec3(0.0'f32,0.0'f32,3.0'f32)) 75 | 76 | var currentTime,prevTime:float 77 | prevTime=epochTime() 78 | while run: 79 | currentTime = epochTime() 80 | let keyState = getKeyboardState() 81 | let elapsedTime = (currentTime - prevTime).float32*10.0'f32 82 | prevTime = currentTime 83 | while pollEvent(evt): 84 | case evt.kind 85 | of QuitEvent: 86 | run = false 87 | of WindowEvent: 88 | var windowEvent = cast[WindowEventPtr](addr(evt)) 89 | if windowEvent.event == WindowEvent_Resized: 90 | let newWidth = windowEvent.data1 91 | let newHeight = windowEvent.data2 92 | glViewport(0, 0, newWidth, newHeight) # Set the viewport to cover the new window 93 | of MouseWheel: 94 | var wheelEvent = cast[MouseWheelEventPtr](addr(evt)) 95 | camera.processMouseScroll(wheelEvent.y.float32) 96 | of MouseMotion: 97 | var motionEvent = cast[MouseMotionEventPtr](addr(evt)) 98 | camera.processMouseMovement(motionEvent.xrel.float32,motionEvent.yrel.float32) 99 | else: 100 | discard 101 | 102 | 103 | if keyState[SDL_SCANCODE_W.uint8] != 0: 104 | camera.processKeyboard(FORWARD,elapsedTime) 105 | if keyState[SDL_SCANCODE_S.uint8] != 0: 106 | camera.processKeyBoard(BACKWARD,elapsedTime) 107 | if keyState[SDL_SCANCODE_A.uint8] != 0: 108 | camera.processKeyBoard(LEFT,elapsedTime) 109 | if keyState[SDL_SCANCODE_D.uint8] != 0: 110 | camera.processKeyBoard(RIGHT,elapsedTime) 111 | if keyState[SDL_SCANCODE_ESCAPE.uint8] != 0: 112 | break 113 | 114 | 115 | # toggle gamma 116 | if keyState[SDL_SCANCODE_B.uint8] != 0: 117 | gammaKeyPress = true 118 | else: 119 | if gammaKeyPress: 120 | gamma = not gamma 121 | echo "gamma:" & $gamma 122 | gammaKeyPress = false 123 | 124 | 125 | 126 | let error = getGLError() 127 | if error != GL_NO_ERROR: 128 | echo $error.int32 129 | 130 | # Render 131 | clearColor(0.1,0.1,0.1,1.0) 132 | easygl.clear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) 133 | 134 | 135 | 136 | shader.use() 137 | var projection = perspective(radians(camera.Zoom), screenWidth.float32 / screenHeight.float32,0.1'f32,1000.0'f32) 138 | var view = camera.getViewMatrix() 139 | 140 | shader.setMat4("projection",projection) 141 | shader.setMat4("view",view) 142 | # set light uniforms 143 | shader.setVec3("viewPos",camera.Position) 144 | shader.setVec3("lightPos",lightPos) 145 | shader.setInt("gamma", if gamma: 1 else: 0) 146 | 147 | # floor 148 | bindVertexArray(planeVAO) 149 | activeTexture(GL_TEXTURE0) 150 | bindTexture(GL_TEXTURE_2D,floorTexture) 151 | drawArrays(GL_TRIANGLES,0,6) 152 | 153 | 154 | 155 | 156 | window.glSwapWindow() 157 | 158 | 159 | destroy window -------------------------------------------------------------------------------- /examples/advanced_lighting/gamma_correction.nim: -------------------------------------------------------------------------------- 1 | # OpenGL example using SDL2 2 | import 3 | sdl2, 4 | opengl, 5 | easygl, 6 | easygl.utils, 7 | stb_image/read as stbi, 8 | glm, 9 | ../utils/camera_util, 10 | times, 11 | os 12 | 13 | discard sdl2.init(INIT_EVERYTHING) 14 | 15 | var screenWidth: cint = 1280 16 | var screenHeight: cint = 720 17 | var gamma = false 18 | var gammaKeyPress = false; 19 | 20 | let window = createWindow("Float", 100, 100, screenWidth, screenHeight, SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE) 21 | discard setRelativeMouseMode(true.Bool32) 22 | discard window.glCreateContext() 23 | 24 | # Initialize OpenGL 25 | loadExtensions() 26 | 27 | 28 | enable(GL_DEPTH_TEST) 29 | enable(GL_BLEND) 30 | blendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) 31 | 32 | 33 | ### Build and compile shader program 34 | let appDir = getAppDir() 35 | let shader = createAndLinkProgram(appDir&"/shaders/gamma_correction.vert",appDir&"/shaders/gamma_correction.frag") 36 | 37 | 38 | 39 | # Set up vertex data 40 | let planeVertices : seq[float32] = 41 | @[ 42 | # positions #normals # texcoords 43 | 10.0'f32, -0.5'f32, 10.0'f32, 0.0'f32, 1.0'f32, 0.0'f32, 10.0'f32, 0.0'f32, 44 | -10.0'f32, -0.5'f32, 10.0'f32, 0.0'f32, 1.0'f32, 0.0'f32, 0.0'f32, 0.0'f32, 45 | -10.0'f32, -0.5'f32, -10.0'f32, 0.0'f32, 1.0'f32, 0.0'f32, 0.0'f32, 10.0'f32, 46 | 47 | 10.0'f32, -0.5'f32, 10.0'f32, 0.0'f32, 1.0'f32, 0.0'f32, 10.0'f32, 0.0'f32, 48 | -10.0'f32, -0.5'f32, -10.0'f32, 0.0'f32, 1.0'f32, 0.0'f32, 0.0'f32, 10.0'f32, 49 | 10.0'f32, -0.5'f32, -10.0'f32, 0.0'f32, 1.0'f32, 0.0'f32, 10.0'f32, 10.0'f32] 50 | 51 | let (planeVAO,planeVBO) = vertexAttribSetup( 52 | GL_ARRAY_BUFFER, 53 | planeVertices, 54 | GL_STATIC_DRAW, 55 | false, 56 | (0,3),(1,3),(2,2)) 57 | 58 | 59 | let floorTexture = loadTextureWithMips(appDir&"/textures/wood.png",false) 60 | let floorTextureGammaCorrected = loadTextureWithMips(appDir&"/textures/wood.png",true) 61 | 62 | shader.use() 63 | shader.setInt("floorTexture",0) 64 | 65 | var lightPositions = [ 66 | vec3(-3.0'f32,0.0'f32,0.0'f32), 67 | vec3(-1.0'f32,0.0'f32,0.0'f32), 68 | vec3(1.0'f32,0.0'f32,0.0'f32), 69 | vec3(3.0'f32,0.0'f32,0.0'f32) 70 | ] 71 | 72 | var lightColors = [ 73 | vec3(0.25'f32), 74 | vec3(0.50'f32), 75 | vec3(0.75'f32), 76 | vec3(1.0'f32) 77 | ] 78 | 79 | 80 | var 81 | evt = sdl2.defaultEvent 82 | run = true 83 | 84 | glViewport(0, 0, screenWidth, screenHeight) # Set the viewport to cover the new window 85 | let camera = newCamera(vec3(0.0'f32,0.0'f32,3.0'f32)) 86 | 87 | var currentTime,prevTime:float 88 | prevTime=epochTime() 89 | while run: 90 | currentTime = epochTime() 91 | let keyState = getKeyboardState() 92 | let elapsedTime = (currentTime - prevTime).float32*10.0'f32 93 | prevTime = currentTime 94 | while pollEvent(evt): 95 | case evt.kind 96 | of QuitEvent: 97 | run = false 98 | of WindowEvent: 99 | var windowEvent = cast[WindowEventPtr](addr(evt)) 100 | if windowEvent.event == WindowEvent_Resized: 101 | let newWidth = windowEvent.data1 102 | let newHeight = windowEvent.data2 103 | glViewport(0, 0, newWidth, newHeight) # Set the viewport to cover the new window 104 | of MouseWheel: 105 | var wheelEvent = cast[MouseWheelEventPtr](addr(evt)) 106 | camera.processMouseScroll(wheelEvent.y.float32) 107 | of MouseMotion: 108 | var motionEvent = cast[MouseMotionEventPtr](addr(evt)) 109 | camera.processMouseMovement(motionEvent.xrel.float32,motionEvent.yrel.float32) 110 | else: 111 | discard 112 | 113 | 114 | if keyState[SDL_SCANCODE_W.uint8] != 0: 115 | camera.processKeyboard(FORWARD,elapsedTime) 116 | if keyState[SDL_SCANCODE_S.uint8] != 0: 117 | camera.processKeyBoard(BACKWARD,elapsedTime) 118 | if keyState[SDL_SCANCODE_A.uint8] != 0: 119 | camera.processKeyBoard(LEFT,elapsedTime) 120 | if keyState[SDL_SCANCODE_D.uint8] != 0: 121 | camera.processKeyBoard(RIGHT,elapsedTime) 122 | if keyState[SDL_SCANCODE_ESCAPE.uint8] != 0: 123 | break 124 | 125 | 126 | # toggle gamma 127 | if keyState[SDL_SCANCODE_SPACE.uint8] != 0: 128 | gammaKeyPress = true 129 | else: 130 | if gammaKeyPress: 131 | gamma = not gamma 132 | echo "gamma:" & $gamma 133 | gammaKeyPress = false 134 | 135 | 136 | 137 | let error = getGLError() 138 | if error != GL_NO_ERROR: 139 | echo $error.int32 140 | 141 | # Render 142 | clearColor(0.1,0.1,0.1,1.0) 143 | easygl.clear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) 144 | 145 | 146 | 147 | shader.use() 148 | var projection = perspective(radians(camera.Zoom), screenWidth.float32 / screenHeight.float32,0.1'f32,1000.0'f32) 149 | var view = camera.getViewMatrix() 150 | shader.setMat4("projection",projection) 151 | shader.setMat4("view",view) 152 | 153 | # set light uniforms 154 | uniform3fv(getUniformLocation(shader,"lightPositions"),4,lightPositions) 155 | uniform3fv(getUniformLocation(shader,"lightColors"),4,lightColors) 156 | shader.setVec3("viewPos",camera.Position) 157 | shader.setInt("gamma", if gamma: 1 else: 0) 158 | 159 | # floor 160 | bindVertexArray(planeVAO) 161 | activeTexture(GL_TEXTURE0) 162 | bindTexture(GL_TEXTURE_2D,if gamma: floorTextureGammaCorrected else: floorTexture) 163 | drawArrays(GL_TRIANGLES,0,6) 164 | 165 | 166 | 167 | 168 | window.glSwapWindow() 169 | 170 | 171 | destroy window -------------------------------------------------------------------------------- /examples/advanced_lighting/shaders/advanced_lighting.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | out vec4 FragColor; 3 | 4 | in VS_OUT { 5 | vec3 FragPos; 6 | vec3 Normal; 7 | vec2 TexCoords; 8 | } fs_in; 9 | 10 | uniform sampler2D floorTexture; 11 | uniform vec3 lightPos; 12 | uniform vec3 viewPos; 13 | uniform bool blinn; 14 | 15 | void main() 16 | { 17 | vec3 color = texture(floorTexture, fs_in.TexCoords).rgb; 18 | // ambient 19 | vec3 ambient = 0.05 * color; 20 | // diffuse 21 | vec3 lightDir = normalize(lightPos - fs_in.FragPos); 22 | vec3 normal = normalize(fs_in.Normal); 23 | float diff = max(dot(lightDir, normal), 0.0); 24 | vec3 diffuse = diff * color; 25 | // specular 26 | vec3 viewDir = normalize(viewPos - fs_in.FragPos); 27 | vec3 reflectDir = reflect(-lightDir, normal); 28 | float spec = 0.0; 29 | if(blinn) 30 | { 31 | vec3 halfwayDir = normalize(lightDir + viewDir); 32 | spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0); 33 | } 34 | else 35 | { 36 | vec3 reflectDir = reflect(-lightDir, normal); 37 | spec = pow(max(dot(viewDir, reflectDir), 0.0), 8.0); 38 | } 39 | vec3 specular = vec3(0.3) * spec; // assuming bright white light color 40 | FragColor = vec4(ambient + diffuse + specular, 1.0); 41 | } 42 | 43 | -------------------------------------------------------------------------------- /examples/advanced_lighting/shaders/advanced_lighting.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | layout (location = 0) in vec3 aPos; 3 | layout (location = 1) in vec3 aNormal; 4 | layout (location = 2) in vec2 aTexCoords; 5 | 6 | // declare an interface block; see 'Advanced GLSL' for what these are. 7 | out VS_OUT { 8 | vec3 FragPos; 9 | vec3 Normal; 10 | vec2 TexCoords; 11 | } vs_out; 12 | 13 | uniform mat4 projection; 14 | uniform mat4 view; 15 | 16 | void main() 17 | { 18 | vs_out.FragPos = aPos; 19 | vs_out.Normal = aNormal; 20 | vs_out.TexCoords = aTexCoords; 21 | gl_Position = projection * view * vec4(aPos, 1.0); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /examples/advanced_lighting/shaders/gamma_correction.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | out vec4 FragColor; 3 | 4 | in VS_OUT { 5 | vec3 FragPos; 6 | vec3 Normal; 7 | vec2 TexCoords; 8 | } fs_in; 9 | 10 | uniform sampler2D floorTexture; 11 | 12 | uniform vec3 lightPositions[4]; 13 | uniform vec3 lightColors[4]; 14 | uniform vec3 viewPos; 15 | uniform bool gamma; 16 | 17 | vec3 BlinnPhong(vec3 normal, vec3 fragPos, vec3 lightPos, vec3 lightColor) 18 | { 19 | // diffuse 20 | vec3 lightDir = normalize(lightPos - fragPos); 21 | float diff = max(dot(lightDir, normal), 0.0); 22 | vec3 diffuse = diff * lightColor; 23 | // specular 24 | vec3 viewDir = normalize(viewPos - fragPos); 25 | vec3 reflectDir = reflect(-lightDir, normal); 26 | float spec = 0.0; 27 | vec3 halfwayDir = normalize(lightDir + viewDir); 28 | spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0); 29 | vec3 specular = spec * lightColor; 30 | // simple attenuation 31 | float max_distance = 1.5; 32 | float distance = length(lightPos - fragPos); 33 | float attenuation = 1.0 / (gamma ? distance * distance : distance); 34 | 35 | diffuse *= attenuation; 36 | specular *= attenuation; 37 | 38 | return diffuse + specular; 39 | } 40 | 41 | void main() 42 | { 43 | vec3 color = texture(floorTexture, fs_in.TexCoords).rgb; 44 | vec3 lighting = vec3(0.0); 45 | for(int i = 0; i < 4; ++i) 46 | lighting += BlinnPhong(normalize(fs_in.Normal), fs_in.FragPos, lightPositions[i], lightColors[i]); 47 | color *= lighting; 48 | if(gamma) 49 | color = pow(color, vec3(1.0/2.2)); 50 | FragColor = vec4(color, 1.0); 51 | } 52 | 53 | -------------------------------------------------------------------------------- /examples/advanced_lighting/shaders/gamma_correction.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | layout (location = 0) in vec3 aPos; 3 | layout (location = 1) in vec3 aNormal; 4 | layout (location = 2) in vec2 aTexCoords; 5 | 6 | out VS_OUT { 7 | vec3 FragPos; 8 | vec3 Normal; 9 | vec2 TexCoords; 10 | } vs_out; 11 | 12 | uniform mat4 projection; 13 | uniform mat4 view; 14 | 15 | void main() 16 | { 17 | vs_out.FragPos = aPos; 18 | vs_out.Normal = aNormal; 19 | vs_out.TexCoords = aTexCoords; 20 | gl_Position = projection * view * vec4(aPos, 1.0); 21 | } 22 | 23 | -------------------------------------------------------------------------------- /examples/advanced_lighting/textures/wood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackmott/easygl/9a987b48409875ffb0521f3887ae25571ff60347/examples/advanced_lighting/textures/wood.png -------------------------------------------------------------------------------- /examples/advanced_opengl/advanced_glsl.nim: -------------------------------------------------------------------------------- 1 | # OpenGL example using SDL2 2 | 3 | import 4 | sdl2, 5 | opengl, 6 | easygl, 7 | easygl.utils, 8 | stb_image/read as stbi, 9 | glm, 10 | ../utils/camera_util, 11 | times, 12 | os 13 | 14 | discard sdl2.init(INIT_EVERYTHING) 15 | 16 | var screenWidth: cint = 1280 17 | var screenHeight: cint = 720 18 | 19 | let window = createWindow("Float", 100, 100, screenWidth, screenHeight, SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE) 20 | discard setRelativeMouseMode(true.Bool32) 21 | discard window.glCreateContext() 22 | 23 | # Initialize OpenGL 24 | loadExtensions() 25 | 26 | ### Build and compile shader program 27 | let appDir = getAppDir() 28 | let shaderRed = createAndLinkProgram(appDir&"/shaders/advanced_glsl.vert",appDir&"/shaders/red.frag") 29 | let shaderGreen = createAndLinkProgram(appDir&"/shaders/advanced_glsl.vert",appDir&"/shaders/green.frag") 30 | let shaderBlue = createAndLinkProgram(appDir&"/shaders/advanced_glsl.vert",appDir&"/shaders/blue.frag") 31 | let shaderYellow = createAndLinkProgram(appDir&"/shaders/advanced_glsl.vert",appDir&"/shaders/yellow.frag") 32 | 33 | 34 | enable(GL_DEPTH_TEST) 35 | 36 | # Set up vertex data 37 | let cubeVertices : seq[float32] = 38 | @[ 39 | # positions 40 | -0.5'f32, -0.5'f32, -0.5'f32, 41 | 0.5'f32, -0.5'f32, -0.5'f32, 42 | 0.5'f32, 0.5'f32, -0.5'f32, 43 | 0.5'f32, 0.5'f32, -0.5'f32, 44 | -0.5'f32, 0.5'f32, -0.5'f32, 45 | -0.5'f32, -0.5'f32, -0.5'f32, 46 | 47 | -0.5'f32, -0.5'f32, 0.5'f32, 48 | 0.5'f32, -0.5'f32, 0.5'f32, 49 | 0.5'f32, 0.5'f32, 0.5'f32, 50 | 0.5'f32, 0.5'f32, 0.5'f32, 51 | -0.5'f32, 0.5'f32, 0.5'f32, 52 | -0.5'f32, -0.5'f32, 0.5'f32, 53 | 54 | -0.5'f32, 0.5'f32, 0.5'f32, 55 | -0.5'f32, 0.5'f32, -0.5'f32, 56 | -0.5'f32, -0.5'f32, -0.5'f32, 57 | -0.5'f32, -0.5'f32, -0.5'f32, 58 | -0.5'f32, -0.5'f32, 0.5'f32, 59 | -0.5'f32, 0.5'f32, 0.5'f32, 60 | 61 | 0.5'f32, 0.5'f32, 0.5'f32, 62 | 0.5'f32, 0.5'f32, -0.5'f32, 63 | 0.5'f32, -0.5'f32, -0.5'f32, 64 | 0.5'f32, -0.5'f32, -0.5'f32, 65 | 0.5'f32, -0.5'f32, 0.5'f32, 66 | 0.5'f32, 0.5'f32, 0.5'f32, 67 | 68 | -0.5'f32, -0.5'f32, -0.5'f32, 69 | 0.5'f32, -0.5'f32, -0.5'f32, 70 | 0.5'f32, -0.5'f32, 0.5'f32, 71 | 0.5'f32, -0.5'f32, 0.5'f32, 72 | -0.5'f32, -0.5'f32, 0.5'f32, 73 | -0.5'f32, -0.5'f32, -0.5'f32, 74 | 75 | -0.5'f32, 0.5'f32, -0.5'f32, 76 | 0.5'f32, 0.5'f32, -0.5'f32, 77 | 0.5'f32, 0.5'f32, 0.5'f32, 78 | 0.5'f32, 0.5'f32, 0.5'f32, 79 | -0.5'f32, 0.5'f32, 0.5'f32, 80 | -0.5'f32, 0.5'f32, -0.5'f32, ] 81 | 82 | 83 | # cube VAO 84 | let cubeVAO = genBindVertexArray() 85 | let cubeVBO = genBindBufferData(GL_ARRAY_BUFFER,cubeVertices,GL_STATIC_DRAW) 86 | enableVertexAttribArray(0) 87 | vertexAttribPointer(0,3,cGL_FLOAT,false,3*float32.sizeof(),0) 88 | 89 | # configure a uniform buffer object 90 | # --------------------------------- 91 | # first. We get the relevant block indices 92 | let uniformBlockIndexRed = getUniformBlockIndex(shaderRed,"Matrices") 93 | let uniformBlockIndexGreen = getUniformBlockIndex(shaderGreen,"Matrices") 94 | let uniformBlockIndexBlue = getUniformBlockIndex(shaderBlue,"Matrices") 95 | let uniformBlockIndexYellow = getUniformBlockIndex(shaderYellow,"Matrices") 96 | uniformBlockBinding(shaderRed,uniformBlockIndexRed,0) 97 | uniformBlockBinding(shaderGreen,uniformBlockIndexGreen,0) 98 | uniformBlockBinding(shaderBlue,uniformBlockIndexBlue,0) 99 | uniformBlockBinding(shaderYellow,uniformBlockIndexYellow,0) 100 | 101 | # now actually create the buffer 102 | let uboMatrices = genBindBuffer(GL_UNIFORM_BUFFER) 103 | bufferData(GL_UNIFORM_BUFFER,2*Mat4f.sizeof(),GL_STATIC_DRAW) 104 | unbindBuffer(GL_UNIFORM_BUFFER) 105 | # define the range of the buffer that links to a uniform binding point 106 | bindBufferRange(GL_UNIFORM_BUFFER,0,uboMatrices,0,(2*Mat4f.sizeof()).int32) 107 | 108 | # store the projection matrix (we only do this once now) (note: we're not using zoom anymore by changing the FoV) 109 | let projection = perspective(45.0'f32,screenWidth.float32/screenHeight.float32,0.1'f32,100.0'f32) 110 | bindBuffer(GL_UNIFORM_BUFFER,uboMatrices) 111 | bufferSubData(GL_UNIFORM_BUFFER,0,Mat4f.sizeof(),projection.arr) 112 | unbindBuffer(GL_UNIFORM_BUFFER) 113 | 114 | 115 | var 116 | evt = sdl2.defaultEvent 117 | run = true 118 | 119 | glViewport(0, 0, screenWidth, screenHeight) # Set the viewport to cover the new window 120 | let camera = newCamera(vec3(0.0'f32,0.0'f32,3.0'f32)) 121 | 122 | var currentTime,prevTime:float 123 | prevTime=epochTime() 124 | while run: 125 | currentTime = epochTime() 126 | let keyState = getKeyboardState() 127 | let elapsedTime = (currentTime - prevTime).float32*10.0'f32 128 | prevTime = currentTime 129 | while pollEvent(evt): 130 | case evt.kind 131 | of QuitEvent: 132 | run = false 133 | of WindowEvent: 134 | var windowEvent = cast[WindowEventPtr](addr(evt)) 135 | if windowEvent.event == WindowEvent_Resized: 136 | let newWidth = windowEvent.data1 137 | let newHeight = windowEvent.data2 138 | glViewport(0, 0, newWidth, newHeight) # Set the viewport to cover the new window 139 | of MouseWheel: 140 | var wheelEvent = cast[MouseWheelEventPtr](addr(evt)) 141 | camera.processMouseScroll(wheelEvent.y.float32) 142 | of MouseMotion: 143 | var motionEvent = cast[MouseMotionEventPtr](addr(evt)) 144 | camera.processMouseMovement(motionEvent.xrel.float32,motionEvent.yrel.float32) 145 | else: 146 | discard 147 | 148 | 149 | if keyState[SDL_SCANCODE_W.uint8] != 0: 150 | camera.processKeyboard(FORWARD,elapsedTime) 151 | if keyState[SDL_SCANCODE_S.uint8] != 0: 152 | camera.processKeyBoard(BACKWARD,elapsedTime) 153 | if keyState[SDL_SCANCODE_A.uint8] != 0: 154 | camera.processKeyBoard(LEFT,elapsedTime) 155 | if keyState[SDL_SCANCODE_D.uint8] != 0: 156 | camera.processKeyBoard(RIGHT,elapsedTime) 157 | if keyState[SDL_SCANCODE_ESCAPE.uint8] != 0: 158 | break 159 | 160 | let error = getGLError() 161 | if error != GL_NO_ERROR: 162 | echo $error.int32 163 | 164 | # Render 165 | clearColor(0.1,0.1,0.1,1.0) 166 | easygl.clear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) 167 | 168 | let view = camera.getViewMatrix() 169 | bindBuffer(GL_UNIFORM_BUFFER,uboMatrices) 170 | bufferSubData(GL_UNIFORM_BUFFER,Mat4f.sizeof(),Mat4f.sizeof(),view.arr) 171 | unbindBuffer(GL_UNIFORM_BUFFER) 172 | 173 | bindVertexArray(cubeVAO) 174 | shaderRed.use() 175 | var model = mat4(1.0'f32) 176 | model = translate(model,vec3(-0.75'f32,0.75'f32,0.0'f32)) 177 | shaderRed.setMat4("model",model) 178 | drawArrays(GL_TRIANGLES,0,36) 179 | 180 | bindVertexArray(cubeVAO) 181 | shaderGreen.use() 182 | model = mat4(1.0'f32) 183 | model = translate(model,vec3(0.75'f32,0.75'f32,0.0'f32)) 184 | shaderGreen.setMat4("model",model) 185 | drawArrays(GL_TRIANGLES,0,36) 186 | 187 | bindVertexArray(cubeVAO) 188 | shaderYellow.use() 189 | model = mat4(1.0'f32) 190 | model = translate(model,vec3(-0.75'f32,-0.75'f32,0.0'f32)) 191 | shaderYellow.setMat4("model",model) 192 | drawArrays(GL_TRIANGLES,0,36) 193 | 194 | bindVertexArray(cubeVAO) 195 | shaderBlue.use() 196 | model = mat4(1.0'f32) 197 | model = translate(model,vec3(0.75'f32,-0.75'f32,0.0'f32)) 198 | shaderBlue.setMat4("model",model) 199 | drawArrays(GL_TRIANGLES,0,36) 200 | 201 | window.glSwapWindow() 202 | 203 | 204 | destroy window -------------------------------------------------------------------------------- /examples/advanced_opengl/anti_aliasing.nim: -------------------------------------------------------------------------------- 1 | # OpenGL example using SDL2 2 | 3 | import 4 | sdl2, 5 | opengl, 6 | easygl, 7 | easygl.utils, 8 | stb_image/read as stbi, 9 | glm, 10 | ../utils/camera_util, 11 | times, 12 | os 13 | 14 | discard sdl2.init(INIT_EVERYTHING) 15 | 16 | var screenWidth: cint = 1280 17 | var screenHeight: cint = 720 18 | discard glSetAttribute(SDL_GL_MULTISAMPLESAMPLES,4) 19 | let window = createWindow("Float", 100, 100, screenWidth, screenHeight, SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE) 20 | discard setRelativeMouseMode(true.Bool32) 21 | discard window.glCreateContext() 22 | 23 | # Initialize OpenGL 24 | loadExtensions() 25 | 26 | ### Build and compile shader program 27 | let appDir = getAppDir() 28 | let shader = createAndLinkProgram(appDir&"/shaders/anti_aliasing.vert",appDir&"/shaders/anti_aliasing.frag") 29 | 30 | enable(GL_MULTISAMPLE) 31 | enable(GL_DEPTH_TEST) 32 | 33 | # Set up vertex data 34 | let cubeVertices : seq[float32] = 35 | @[ 36 | # positions 37 | -0.5'f32, -0.5'f32, -0.5'f32, 38 | 0.5'f32, -0.5'f32, -0.5'f32, 39 | 0.5'f32, 0.5'f32, -0.5'f32, 40 | 0.5'f32, 0.5'f32, -0.5'f32, 41 | -0.5'f32, 0.5'f32, -0.5'f32, 42 | -0.5'f32, -0.5'f32, -0.5'f32, 43 | 44 | -0.5'f32, -0.5'f32, 0.5'f32, 45 | 0.5'f32, -0.5'f32, 0.5'f32, 46 | 0.5'f32, 0.5'f32, 0.5'f32, 47 | 0.5'f32, 0.5'f32, 0.5'f32, 48 | -0.5'f32, 0.5'f32, 0.5'f32, 49 | -0.5'f32, -0.5'f32, 0.5'f32, 50 | 51 | -0.5'f32, 0.5'f32, 0.5'f32, 52 | -0.5'f32, 0.5'f32, -0.5'f32, 53 | -0.5'f32, -0.5'f32, -0.5'f32, 54 | -0.5'f32, -0.5'f32, -0.5'f32, 55 | -0.5'f32, -0.5'f32, 0.5'f32, 56 | -0.5'f32, 0.5'f32, 0.5'f32, 57 | 58 | 0.5'f32, 0.5'f32, 0.5'f32, 59 | 0.5'f32, 0.5'f32, -0.5'f32, 60 | 0.5'f32, -0.5'f32, -0.5'f32, 61 | 0.5'f32, -0.5'f32, -0.5'f32, 62 | 0.5'f32, -0.5'f32, 0.5'f32, 63 | 0.5'f32, 0.5'f32, 0.5'f32, 64 | 65 | -0.5'f32, -0.5'f32, -0.5'f32, 66 | 0.5'f32, -0.5'f32, -0.5'f32, 67 | 0.5'f32, -0.5'f32, 0.5'f32, 68 | 0.5'f32, -0.5'f32, 0.5'f32, 69 | -0.5'f32, -0.5'f32, 0.5'f32, 70 | -0.5'f32, -0.5'f32, -0.5'f32, 71 | 72 | -0.5'f32, 0.5'f32, -0.5'f32, 73 | 0.5'f32, 0.5'f32, -0.5'f32, 74 | 0.5'f32, 0.5'f32, 0.5'f32, 75 | 0.5'f32, 0.5'f32, 0.5'f32, 76 | -0.5'f32, 0.5'f32, 0.5'f32, 77 | -0.5'f32, 0.5'f32, -0.5'f32, ] 78 | 79 | 80 | 81 | # cube VAO 82 | let cubeVAO = genBindVertexArray() 83 | let cubeVBO = genBindBufferData(GL_ARRAY_BUFFER,cubeVertices,GL_STATIC_DRAW) 84 | enableVertexAttribArray(0) 85 | vertexAttribPointer(0,3,cGL_FLOAT,false,3*float32.sizeof(),0) 86 | unBindVertexArray() 87 | 88 | 89 | var 90 | evt = sdl2.defaultEvent 91 | run = true 92 | 93 | glViewport(0, 0, screenWidth, screenHeight) # Set the viewport to cover the new window 94 | let camera = newCamera(vec3(0.0'f32,0.0'f32,3.0'f32)) 95 | 96 | var currentTime,prevTime:float 97 | prevTime=epochTime() 98 | while run: 99 | currentTime = epochTime() 100 | let keyState = getKeyboardState() 101 | let elapsedTime = (currentTime - prevTime).float32*10.0'f32 102 | prevTime = currentTime 103 | while pollEvent(evt): 104 | case evt.kind 105 | of QuitEvent: 106 | run = false 107 | of WindowEvent: 108 | var windowEvent = cast[WindowEventPtr](addr(evt)) 109 | if windowEvent.event == WindowEvent_Resized: 110 | let newWidth = windowEvent.data1 111 | let newHeight = windowEvent.data2 112 | glViewport(0, 0, newWidth, newHeight) # Set the viewport to cover the new window 113 | of MouseWheel: 114 | var wheelEvent = cast[MouseWheelEventPtr](addr(evt)) 115 | camera.processMouseScroll(wheelEvent.y.float32) 116 | of MouseMotion: 117 | var motionEvent = cast[MouseMotionEventPtr](addr(evt)) 118 | camera.processMouseMovement(motionEvent.xrel.float32,motionEvent.yrel.float32) 119 | else: 120 | discard 121 | 122 | 123 | if keyState[SDL_SCANCODE_W.uint8] != 0: 124 | camera.processKeyboard(FORWARD,elapsedTime) 125 | if keyState[SDL_SCANCODE_S.uint8] != 0: 126 | camera.processKeyBoard(BACKWARD,elapsedTime) 127 | if keyState[SDL_SCANCODE_A.uint8] != 0: 128 | camera.processKeyBoard(LEFT,elapsedTime) 129 | if keyState[SDL_SCANCODE_D.uint8] != 0: 130 | camera.processKeyBoard(RIGHT,elapsedTime) 131 | if keyState[SDL_SCANCODE_ESCAPE.uint8] != 0: 132 | break 133 | 134 | let error = getGLError() 135 | if error != GL_NO_ERROR: 136 | echo $error.int32 137 | 138 | # Render 139 | clearColor(0.1,0.1,0.1,1.0) 140 | easygl.clear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) 141 | 142 | 143 | 144 | shader.use() 145 | var projection = perspective(radians(camera.Zoom), screenWidth.float32 / screenHeight.float32,0.1'f32,1000.0'f32) 146 | var view = camera.getViewMatrix() 147 | var model = mat4(1.0'f32) 148 | shader.setMat4("projection",projection) 149 | shader.setMat4("view",view) 150 | shader.setMat4("model",model) 151 | 152 | bindVertexArray(cubeVAO) 153 | drawArrays(GL_TRIANGLES,0,36) 154 | unBindVertexArray() 155 | 156 | window.glSwapWindow() 157 | 158 | 159 | destroy window -------------------------------------------------------------------------------- /examples/advanced_opengl/anti_aliasing_offscreen.nim: -------------------------------------------------------------------------------- 1 | # OpenGL example using SDL2 2 | ## TODO this one has a bug, whole screen is green. don't know what. 3 | import 4 | sdl2, 5 | opengl, 6 | easygl, 7 | easygl.utils, 8 | stb_image/read as stbi, 9 | glm, 10 | ../utils/camera_util, 11 | times, 12 | os 13 | 14 | discard sdl2.init(INIT_EVERYTHING) 15 | 16 | var screenWidth: cint = 1280 17 | var screenHeight: cint = 720 18 | 19 | let window = createWindow("Float", 100, 100, screenWidth, screenHeight, SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE) 20 | discard setRelativeMouseMode(true.Bool32) 21 | discard window.glCreateContext() 22 | 23 | # Initialize OpenGL 24 | loadExtensions() 25 | 26 | ### Build and compile shader program 27 | let appDir = getAppDir() 28 | let shader = createAndLinkProgram(appDir&"/shaders/anti_aliasing.vert",appDir&"/shaders/anti_aliasing.frag") 29 | let screenShader = createAndLinkProgram(appDir&"/shaders/aa_post.vert",appDir&"/shaders/aa_post.frag") 30 | 31 | 32 | enable(GL_DEPTH_TEST) 33 | 34 | # Set up vertex data 35 | let cubeVertices : seq[float32] = 36 | @[ 37 | # positions 38 | -0.5'f32, -0.5'f32, -0.5'f32, 39 | 0.5'f32, -0.5'f32, -0.5'f32, 40 | 0.5'f32, 0.5'f32, -0.5'f32, 41 | 0.5'f32, 0.5'f32, -0.5'f32, 42 | -0.5'f32, 0.5'f32, -0.5'f32, 43 | -0.5'f32, -0.5'f32, -0.5'f32, 44 | 45 | -0.5'f32, -0.5'f32, 0.5'f32, 46 | 0.5'f32, -0.5'f32, 0.5'f32, 47 | 0.5'f32, 0.5'f32, 0.5'f32, 48 | 0.5'f32, 0.5'f32, 0.5'f32, 49 | -0.5'f32, 0.5'f32, 0.5'f32, 50 | -0.5'f32, -0.5'f32, 0.5'f32, 51 | 52 | -0.5'f32, 0.5'f32, 0.5'f32, 53 | -0.5'f32, 0.5'f32, -0.5'f32, 54 | -0.5'f32, -0.5'f32, -0.5'f32, 55 | -0.5'f32, -0.5'f32, -0.5'f32, 56 | -0.5'f32, -0.5'f32, 0.5'f32, 57 | -0.5'f32, 0.5'f32, 0.5'f32, 58 | 59 | 0.5'f32, 0.5'f32, 0.5'f32, 60 | 0.5'f32, 0.5'f32, -0.5'f32, 61 | 0.5'f32, -0.5'f32, -0.5'f32, 62 | 0.5'f32, -0.5'f32, -0.5'f32, 63 | 0.5'f32, -0.5'f32, 0.5'f32, 64 | 0.5'f32, 0.5'f32, 0.5'f32, 65 | 66 | -0.5'f32, -0.5'f32, -0.5'f32, 67 | 0.5'f32, -0.5'f32, -0.5'f32, 68 | 0.5'f32, -0.5'f32, 0.5'f32, 69 | 0.5'f32, -0.5'f32, 0.5'f32, 70 | -0.5'f32, -0.5'f32, 0.5'f32, 71 | -0.5'f32, -0.5'f32, -0.5'f32, 72 | 73 | -0.5'f32, 0.5'f32, -0.5'f32, 74 | 0.5'f32, 0.5'f32, -0.5'f32, 75 | 0.5'f32, 0.5'f32, 0.5'f32, 76 | 0.5'f32, 0.5'f32, 0.5'f32, 77 | -0.5'f32, 0.5'f32, 0.5'f32, 78 | -0.5'f32, 0.5'f32, -0.5'f32, ] 79 | 80 | 81 | let quadVertices = @[ 82 | # positions # texCoords 83 | -1.0'f32, 1.0'f32, 0.0'f32, 1.0'f32, 84 | -1.0'f32, -1.0'f32, 0.0'f32, 0.0'f32, 85 | 1.0'f32, -1.0'f32, 1.0'f32, 0.0'f32, 86 | 87 | -1.0'f32, 1.0'f32, 0.0'f32, 1.0'f32, 88 | 1.0'f32, -1.0'f32, 1.0'f32, 0.0'f32, 89 | 1.0'f32, 1.0'f32, 1.0'f32, 1.0'f32 90 | ] 91 | 92 | 93 | # cube VAO 94 | let cubeVAO = genBindVertexArray() 95 | let cubeVBO = genBindBufferData(GL_ARRAY_BUFFER,cubeVertices,GL_STATIC_DRAW) 96 | enableVertexAttribArray(0) 97 | vertexAttribPointer(0,3,cGL_FLOAT,false,3*float32.sizeof(),0) 98 | 99 | # screen vao 100 | let quadVAO = genBindVertexArray() 101 | let quadVBO = genBindBufferData(GL_ARRAY_BUFFER, quadVertices,GL_STATIC_DRAW) 102 | enableVertexAttribArray(0) 103 | vertexAttribPointer(0,2,cGL_FLOAT,false,4*float32.sizeof(),0) 104 | enableVertexAttribArray(1) 105 | vertexAttribPointer(1,2,cGL_FLOAT,false,4*float32.sizeof(),2*float32.sizeof()) 106 | 107 | # configure MSAA framebuffer 108 | let framebuffer = genBindFramebuffer(GL_FRAMEBUFFER) 109 | # create a multismaples color attachment texture 110 | let textureColorBufferMultisampled = genBindTexture(GL_TEXTURE_2D_MULTISAMPLE) 111 | texImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,4,GL_RGB,screenWidth,screenHeight,true) 112 | unBindTexture(GL_TEXTURE_2D_MULTISAMPLE) 113 | framebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D_MULTISAMPLE,textureColorBufferMultisampled,0) 114 | # create a (also multisampled) renderbuffer object for depth and stencil attachments 115 | let rbo = genBindRenderbuffer() 116 | renderBufferStorageMultisample(4,GL_DEPTH24_STENCIL8,screenWidth,screenHeight) 117 | unBindRenderBuffer() 118 | framebufferRenderBuffer(GL_FRAMEBUFFER,GL_DEPTH_STENCIL_ATTACHMENT,rbo) 119 | 120 | if checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE: 121 | echo "Framebuffer not complete" 122 | 123 | # configure second post-processing framebuffer 124 | let intermediateFBO = genBindFramebuffer(FrameGL_FRAMEBUFFER) 125 | # create a color attachment texture 126 | let screenTexture = genBindTexture(GL_TEXTURE_2D) 127 | texImage2D(TexImageTarget.TEXTURE_2D,0,TextureInternalFormat.RGB,screenWidth,screenHeight,PixelDataFormat.RGB,PixelDataType.UNSIGNED_BYTE) 128 | texParameteri(GL_TEXTURE_2D,TextureParameter.TEXTURE_MIN_FILTER,GL_LINEAR) 129 | texParameteri(GL_TEXTURE_2D,TextureParameter.TEXTURE_MAG_FILTER,GL_LINEAR) 130 | framebufferTexture2D(FrameGL_FRAMEBUFFER,FrameBufferAttachment.COLOR_ATTACHMENT0,FramebufferGL_TEXTURE_2D,screenTexture,0) 131 | 132 | if checkFramebufferStatus(FrameGL_FRAMEBUFFER) != FramebufferStatus.FRAMEBUFFER_COMPLETE: 133 | echo "Framebuffer not complete" 134 | 135 | unBindFramebuffer(FrameGL_FRAMEBUFFER) 136 | 137 | # shader config 138 | shader.use() 139 | screenShader.setInt("screenTexture",0) 140 | 141 | var 142 | evt = sdl2.defaultEvent 143 | run = true 144 | 145 | glViewport(0, 0, screenWidth, screenHeight) # Set the viewport to cover the new window 146 | let camera = newCamera(vec3(0.0'f32,0.0'f32,3.0'f32)) 147 | 148 | var currentTime,prevTime:float 149 | prevTime=epochTime() 150 | while run: 151 | currentTime = epochTime() 152 | let keyState = getKeyboardState() 153 | let elapsedTime = (currentTime - prevTime).float32*10.0'f32 154 | prevTime = currentTime 155 | while pollEvent(evt): 156 | case evt.kind 157 | of QuitEvent: 158 | run = false 159 | of WindowEvent: 160 | var windowEvent = cast[WindowEventPtr](addr(evt)) 161 | if windowEvent.event == WindowEvent_Resized: 162 | let newWidth = windowEvent.data1 163 | let newHeight = windowEvent.data2 164 | glViewport(0, 0, newWidth, newHeight) # Set the viewport to cover the new window 165 | of MouseWheel: 166 | var wheelEvent = cast[MouseWheelEventPtr](addr(evt)) 167 | camera.processMouseScroll(wheelEvent.y.float32) 168 | of MouseMotion: 169 | var motionEvent = cast[MouseMotionEventPtr](addr(evt)) 170 | camera.processMouseMovement(motionEvent.xrel.float32,motionEvent.yrel.float32) 171 | else: 172 | discard 173 | 174 | 175 | if keyState[SDL_SCANCODE_W.uint8] != 0: 176 | camera.processKeyboard(FORWARD,elapsedTime) 177 | if keyState[SDL_SCANCODE_S.uint8] != 0: 178 | camera.processKeyBoard(BACKWARD,elapsedTime) 179 | if keyState[SDL_SCANCODE_A.uint8] != 0: 180 | camera.processKeyBoard(LEFT,elapsedTime) 181 | if keyState[SDL_SCANCODE_D.uint8] != 0: 182 | camera.processKeyBoard(RIGHT,elapsedTime) 183 | if keyState[SDL_SCANCODE_ESCAPE.uint8] != 0: 184 | break 185 | 186 | let error = getGLError() 187 | if error != GL_NO_ERROR: 188 | echo $error 189 | 190 | # Render 191 | clearColor(0.1,0.1,0.1,1.0) 192 | easygl.clear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) 193 | 194 | # 1. draw scene as normal in multisampled buffers 195 | bindFramebuffer(FrameGL_FRAMEBUFFER,framebuffer) 196 | clearColor(0.1,0.1,0.1,1.0) 197 | easygl.clear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) 198 | enable(GL_DEPTH_TEST) 199 | 200 | shader.use() 201 | var projection = perspective(radians(camera.Zoom), screenWidth.float32 / screenHeight.float32,0.1'f32,1000.0'f32) 202 | var view = camera.getViewMatrix() 203 | var model = mat4(1.0'f32) 204 | shader.setMat4("projection",projection) 205 | shader.setMat4("view",view) 206 | shader.setMat4("model",model) 207 | 208 | bindVertexArray(cubeVAO) 209 | drawArrays(GL_TRIANGLES,0,36) 210 | 211 | # 2. now blit multisampled buffer(s) to normal colorbuffer of intermediate FBO. Image is stored in screenTexture 212 | bindFramebuffer(FrameGL_READ_FRAMEBUFFER,framebuffer) 213 | bindFramebuffer(FrameGL_DRAW_FRAMEBUFFER,intermediateFBO) 214 | blitFramebuffer(0,0,screenWidth,screenHeight,0,0,screenWidth,screenHeight,GL_COLOR_BUFFER_BIT,BlitFilter.NEAREST) 215 | 216 | # 3.now render quad with scene's visuals as its texture image 217 | unBindFramebuffer(FrameGL_FRAMEBUFFER) 218 | clearColor(1.0,1.0,1.0,1.0) 219 | easygl.clear(GL_COLOR_BUFFER_BIT) 220 | disable(GL_DEPTH_TEST) 221 | 222 | # draw Screen quads 223 | screenShader.use() 224 | bindVertexArray(quadVAO) 225 | activeTexture(GL_TEXTURE0) 226 | bindTexture(GL_TEXTURE_2D,screenTexture) 227 | drawArrays(GL_TRIANGLES,0,6) 228 | 229 | 230 | window.glSwapWindow() 231 | 232 | 233 | destroy window -------------------------------------------------------------------------------- /examples/advanced_opengl/asteroids_instanced.nim: -------------------------------------------------------------------------------- 1 | 2 | # OpenGL example using SDL2 3 | 4 | import 5 | sdl2, 6 | opengl, 7 | easygl, 8 | easygl.utils, 9 | easygl.model, 10 | stb_image/read as stbi, 11 | glm, 12 | ../utils/camera_util, 13 | times, 14 | os, 15 | random 16 | 17 | 18 | discard sdl2.init(INIT_EVERYTHING) 19 | 20 | var screenWidth: cint = 800 21 | var screenHeight: cint = 600 22 | 23 | let window = createWindow("Float", 100, 100, screenWidth, screenHeight, SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE) 24 | discard setRelativeMouseMode(true.Bool32) 25 | discard window.glCreateContext() 26 | 27 | # Initialize OpenGL 28 | loadExtensions() 29 | 30 | enable(GL_DEPTH_TEST) 31 | 32 | 33 | ### Build and compile shader program 34 | let appDir = getAppDir() 35 | let asteroidShader = createAndLinkProgram(appDir&"/shaders/asteroids.vert",appDir&"/shaders/asteroids.frag") 36 | let planetShader = createAndLinkProgram(appDir&"/shaders/planet.vert",appDir&"/shaders/planet.frag") 37 | 38 | let rock = loadModel(appDir & "/models/rock/rock.obj") 39 | let planet = loadModel(appDir & "/models/planet/planet.obj") 40 | 41 | let amount = 100_000 42 | var modelMatrices = newSeq[Mat4f](amount) 43 | let radius = 175.0'f32 44 | let offset = 75.0'f32 45 | for i in 0.. 89.0'f32: 63 | camera.Pitch = 89.0'f32 64 | elif camera.Pitch < -89.0'f32: 65 | camera.Pitch = -89.0'f32 66 | 67 | updateCameraVectors(camera) 68 | 69 | proc processMouseScroll*(camera:Camera, yoffset:float32) = 70 | if camera.Zoom >= 1.0'f32 and camera.Zoom <= 45.0'f32: 71 | camera.Zoom = camera.Zoom - yoffset 72 | if camera.Zoom <= 1.0f: 73 | camera.Zoom = 1.0'f32 74 | elif camera.Zoom >= 45.0'f32: 75 | camera.Zoom = 45.0'f32 -------------------------------------------------------------------------------- /src/easygl/mesh.nim: -------------------------------------------------------------------------------- 1 | import 2 | ../easygl, 3 | utils, 4 | opengl, 5 | assimp, 6 | glm 7 | 8 | type TextureType* {.pure.} = enum 9 | TextureDiffuse, 10 | TextureSpecular, 11 | TextureNormal, 12 | TextureHeight 13 | 14 | type Vertex* = object 15 | Position*:Vec3f 16 | Normal*:Vec3f 17 | TexCoords*:Vec2f 18 | Tangent*:Vec3f 19 | Bitangent*:Vec3f 20 | 21 | 22 | type Texture* = object 23 | id*:TextureId 24 | texType*:TextureType 25 | path*:string 26 | 27 | type Mesh* = object 28 | vertices*: seq[Vertex] 29 | indices*: seq[uint32] 30 | textures*: seq[Texture] 31 | VAO*:VertexArrayId 32 | VBO:BufferId 33 | EBO:BufferId 34 | 35 | 36 | proc setupMesh(mesh:var Mesh) = 37 | mesh.VAO = genVertexArray() 38 | mesh.VBO = genBuffer() 39 | mesh.EBO = genBuffer() 40 | bindVertexArray(mesh.VAO) 41 | bindBuffer(GL_ARRAY_BUFFER,mesh.VBO) 42 | 43 | bufferData(GL_ARRAY_BUFFER,mesh.vertices,GL_STATIC_DRAW) 44 | 45 | bindBuffer(GL_ELEMENT_ARRAY_BUFFER,mesh.EBO) 46 | bufferData(GL_ELEMENT_ARRAY_BUFFER,mesh.indices,GL_STATIC_DRAW) 47 | 48 | enableVertexAttribArray(0) 49 | vertexAttribPointer(0,3,cGL_FLOAT,false,Vertex.sizeof().int32,0) 50 | enableVertexAttribArray(1) 51 | vertexAttribPointer(1,3,cGL_FLOAT,false,Vertex.sizeof().int32,offsetof(Vertex,Normal).int32) 52 | enableVertexAttribArray(2) 53 | vertexAttribPointer(2,3,cGL_FLOAT,false,Vertex.sizeof().int32,offsetof(Vertex,TexCoords).int32) 54 | enableVertexAttribArray(3) 55 | vertexAttribPointer(3,3,cGL_FLOAT,false,Vertex.sizeof().int32,offsetof(Vertex,Tangent).int32) 56 | enableVertexAttribArray(4) 57 | vertexAttribPointer(4,3,cGL_FLOAT,false,Vertex.sizeof().int32,offsetof(Vertex,Bitangent).int32) 58 | 59 | unBindVertexArray() 60 | 61 | 62 | proc newMesh*(vertices:seq[Vertex], indices:seq[uint32], textures:seq[Texture]) : Mesh = 63 | result.vertices = vertices 64 | result.indices = indices 65 | result.textures = textures 66 | result.setupMesh() 67 | 68 | proc draw*(mesh:Mesh,shaderProgram:ShaderProgramId) = 69 | var diffuseNr,specularNr,normalNr,heightNr = 0'u32 70 | for i,tex in mesh.textures: 71 | activeTexture((GL_TEXTURE0.ord + i).GLenum) 72 | let texIndex = 73 | case tex.texType: 74 | of TextureType.TextureDiffuse: 75 | diffuseNr.inc() 76 | diffuseNr 77 | of TextureType.TextureSpecular: 78 | specularNr.inc() 79 | specularNr 80 | of TextureType.TextureNormal: 81 | normalNr.inc() 82 | normalNr 83 | of TextureType.TextureHeight: 84 | heightNr.inc() 85 | heightNr 86 | let uniform = $tex.texType & $texIndex 87 | shaderProgram.setInt(uniform,i.int32) 88 | bindTexture(GL_TEXTURE_2D, mesh.textures[i].id) 89 | 90 | bindVertexArray(mesh.VAO) 91 | drawElements(GL_TRIANGLES,mesh.indices.len,GL_UNSIGNED_INT,0) 92 | unBindVertexArray() 93 | activeTexture(GL_TEXTURE0) -------------------------------------------------------------------------------- /src/easygl/model.nim: -------------------------------------------------------------------------------- 1 | import 2 | ../easygl, 3 | utils, 4 | opengl, 5 | assimp, 6 | glm, 7 | mesh, 8 | strutils 9 | 10 | type Model* = object 11 | texturesLoaded* : seq[Texture] 12 | meshes*: seq[Mesh] 13 | directory*:string 14 | gammaCorrection*:bool 15 | 16 | proc draw*(model:Model, shaderProgram:ShaderProgramId) = 17 | 18 | for mesh in model.meshes: 19 | mesh.draw(shaderProgram) 20 | 21 | proc loadMaterialTextures(model: var Model, mat:PMaterial, texType:TTextureType, typeName:TextureType) : seq[Texture] = 22 | var textures = newSeq[Texture]() 23 | let texCount = getTextureCount(mat,texType).int 24 | for i in 0 .. pred(texCount): 25 | var str : AIString 26 | let ret = getTexture(mat,texType,i.cint,addr str) 27 | if ret == ReturnFailure: 28 | echo "failed to get texture" 29 | break; 30 | var skip = false 31 | for j,loadedTex in model.texturesLoaded: 32 | if loadedTex.path == $str: 33 | textures.add(loadedTex) 34 | skip = true; 35 | break; 36 | if not skip: 37 | var texture:Texture 38 | texture.id = loadTextureWithMips(model.directory & $str) 39 | texture.texType = typeName 40 | texture.path = $str 41 | textures.add(texture) 42 | model.texturesLoaded.add(texture) 43 | textures 44 | 45 | 46 | proc processMesh(model:var Model, mesh:PMesh, scene:PScene) : Mesh = 47 | var vertices = newSeq[Vertex]() 48 | var indices = newSeq[uint32]() 49 | var textures = newSeq[Texture]() 50 | 51 | let vertexCount = mesh.vertexCount.int 52 | for i in 0 .. pred(vertexCount): 53 | var vertex:Vertex 54 | var vector:Vec3f 55 | vector.x = mesh.vertices[i].x 56 | vector.y = mesh.vertices[i].y 57 | vector.z = mesh.vertices[i].z 58 | vertex.Position = vector 59 | 60 | vector.x = mesh.normals[i].x 61 | vector.y = mesh.normals[i].y 62 | vector.z = mesh.normals[i].z 63 | vertex.Normal = vector 64 | 65 | # todo - texCoords are a multidimensional array 66 | # will this work?? 67 | if mesh.texCoords[0] != nil: 68 | let m = mesh.texCoords[0] 69 | var vec : Vec2f 70 | vec.x = m[i].x 71 | vec.y = m[i].y 72 | vertex.TexCoords = vec 73 | else: 74 | vertex.TexCoords = vec2(0.0'f32,0.0'f32) 75 | 76 | vector.x = mesh.tangents[i].x 77 | vector.y = mesh.tangents[i].y 78 | vector.z = mesh.tangents[i].z 79 | vertex.Tangent = vector 80 | 81 | vector.x = mesh.bitTangents[i].x 82 | vector.y = mesh.bitTangents[i].y 83 | vector.z = mesh.bitTangents[i].z 84 | vertex.Bitangent = vector 85 | 86 | vertices.add(vertex) 87 | 88 | for i in 0 .. pred(mesh.faceCount).int: 89 | let face = mesh.faces[i] 90 | for j in 0 .. pred(face.indexCount).int: 91 | indices.add(face.indices[j].uint32) 92 | 93 | let material = scene.materials[mesh.materialIndex] 94 | 95 | # we assume a convention for sampler names in the shaders. Each diffuse texture should be named 96 | # as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER. 97 | # Same applies to other texture as the following list summarizes: 98 | # diffuse: texture_diffuseN 99 | # specular: texture_specularN 100 | # normal: texture_normalN 101 | let diffuseMaps = loadMaterialTextures(model,material,TTextureType.TexDiffuse,TextureType.TextureDiffuse) 102 | let specularMaps = loadMaterialTextures(model,material,TTextureType.TexSpecular,TextureType.TextureSpecular) 103 | let normalMaps = loadMaterialTextures(model,material,TTextureType.TexNormals,TextureType.TextureNormal) 104 | let heightMaps = loadMaterialTextures(model,material,TTextureType.TexHeight,TextureType.TextureHeight) 105 | textures = textures & diffuseMaps 106 | textures = textures & specularMaps 107 | textures = textures & normalMaps 108 | textures = textures & heightMaps 109 | newMesh(vertices,indices,textures) 110 | 111 | 112 | 113 | 114 | proc processNode(model:var Model,node:PNode, scene:PScene) = 115 | let meshCount = node.meshCount.int 116 | for i in 0 .. pred(meshCount): 117 | model.meshes.add(processMesh(model,scene.meshes[node.meshes[i]],scene)) 118 | let childrenCount = node.childrenCount.int 119 | for i in 0 .. pred(childrenCount): 120 | processNode(model,node.children[i],scene) 121 | 122 | 123 | proc loadModel*(path:string) : Model = 124 | var model:Model 125 | model.texturesLoaded = newSeq[Texture]() 126 | model.meshes = newSeq[Mesh]() 127 | echo path 128 | let scene = aiImportFile(path,aiProcess_Triangulate or aiProcess_FlipUVs or aiProcess_CalcTangentSpace) 129 | #todo error check 130 | model.directory = path.substr(0,path.rfind("/")) 131 | echo model.directory 132 | processNode(model,scene.rootNode,scene) 133 | model -------------------------------------------------------------------------------- /src/easygl/utils.nim: -------------------------------------------------------------------------------- 1 | import 2 | ../easygl, 3 | stb_image/read as stbi, 4 | opengl, 5 | glm, 6 | options 7 | 8 | 9 | proc compileAndAttachShaderString*(shaderType:GLenum, shaderSrc: string, programId:ShaderProgramId) : ShaderId = 10 | let shaderId = createShader(shaderType) 11 | shaderSource(shaderId,shaderSrc) 12 | compileShader(shaderId) 13 | if not getShaderCompileStatus(shaderId): 14 | echo "Shader Compile Error:" 15 | echo getShaderInfoLog(shaderId) 16 | else: 17 | attachShader(programId,shaderId) 18 | shaderId 19 | 20 | proc createAndLinkProgramString*(vertexSrc:string, fragmentSrc:string, geometrySrc:Option[string] = none(string) ) : ShaderProgramId = 21 | let programId = createProgram() 22 | let vert = compileAndAttachShaderString(GL_VERTEX_SHADER,vertexSrc,programId) 23 | let frag = compileAndAttachShaderString(GL_FRAGMENT_SHADER,fragmentSrc,programId) 24 | let geo = 25 | if geometrySrc.isSome: 26 | compileAndAttachShaderString(GL_GEOMETRY_SHADER,geometrySrc.get(),programId) 27 | else: 28 | 0.ShaderId 29 | 30 | linkProgram(programId) 31 | 32 | if not getProgramLinkStatus(programId): 33 | echo "Link Error:" 34 | echo getProgramInfoLog(programId) 35 | 36 | deleteShader(vert) 37 | deleteShader(frag) 38 | if geometrySrc.isSome: deleteShader(geo) 39 | programId 40 | 41 | # Compiles and attaches in 1 step with error reporting 42 | proc compileAndAttachShader*(shaderType:GLenum, shaderPath: string, programId:ShaderProgramId) : ShaderId = 43 | let shaderId = createShader(shaderType) 44 | shaderSource(shaderId,readFile(shaderPath)) 45 | compileShader(shaderId) 46 | if not getShaderCompileStatus(shaderId): 47 | echo "Shader Compile Error ("&shaderPath&"):" 48 | echo getShaderInfoLog(shaderId) 49 | else: 50 | attachShader(programId,shaderId) 51 | shaderId 52 | 53 | # Handles everything needed to set up a shader, with error reporting 54 | proc createAndLinkProgram*(vertexPath:string, fragmentPath:string, geometryPath:Option[string] = none(string)) : ShaderProgramId = 55 | let programId = createProgram() 56 | let vert = compileAndAttachShader(GL_VERTEX_SHADER,vertexPath,programId) 57 | let frag = compileAndAttachShader(GL_FRAGMENT_SHADER,fragmentPath,programId) 58 | let geo = 59 | if geometryPath.isSome: 60 | compileAndAttachShader(GL_GEOMETRY_SHADER,geometryPath.get(),programId) 61 | else: 62 | 0.ShaderId 63 | 64 | linkProgram(programId) 65 | 66 | if not getProgramLinkStatus(programId): 67 | echo "Link Error:" 68 | echo getProgramInfoLog(programId) 69 | 70 | deleteShader(vert) 71 | deleteShader(frag) 72 | if geometryPath.isSome: deleteShader(geo) 73 | programId 74 | 75 | #handles most image types automatically 76 | proc loadCubemap*(faces:array[6,string]) : TextureId = 77 | let textureId = genBindTexture(GL_TEXTURE_CUBE_MAP) 78 | 79 | stbi.setFlipVerticallyOnLoad(false) 80 | # todo parallelize this 81 | 82 | for i,face in faces: 83 | var width,height,channels:int 84 | let data = stbi.load(face,width,height,channels,stbi.Default) 85 | let target = (GL_TEXTURE_CUBE_MAP_POSITIVE_X.int+i).GLenum 86 | texImage2D(target,0'i32,GL_RGB,width.int32,height.int32,GL_RGB,GL_UNSIGNED_BYTE,data) 87 | 88 | texParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MIN_FILTER,GL_LINEAR) 89 | texParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MAG_FILTER,GL_LINEAR) 90 | texParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE) 91 | texParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE) 92 | texParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE) 93 | textureId 94 | 95 | 96 | proc loadTextureWithMips*(path:string, gammaCorrection:bool = false) : TextureId = 97 | let textureId = genBindTexture(GL_Texture2D) 98 | stbi.setFlipVerticallyOnLoad(true) 99 | var width,height,channels:int 100 | let data = stbi.load(path,width,height,channels,stbi.Default) 101 | let gammaFormat = 102 | if gammaCorrection: 103 | GL_SRGB 104 | else: 105 | GL_RGB 106 | 107 | let (internalFormat,dataFormat,param) = 108 | if channels == 1: 109 | (GL_RED,GL_RED,GL_REPEAT) 110 | elif channels == 3: 111 | (gammaFormat,GL_RGB,GL_REPEAT) 112 | elif channels == 4: 113 | (gammaFormat,GL_RGBA,GL_CLAMP_TO_EDGE) 114 | else: 115 | ( echo "texture unknown, assuming rgb"; 116 | (GL_RGB,GL_RGB,GL_REPEAT) ) 117 | 118 | texImage2D(GL_TEXTURE_2D, 119 | 0'i32, 120 | internalFormat, 121 | width.int32, 122 | height.int32, 123 | dataFormat, 124 | GL_UNSIGNED_BYTE, 125 | data) 126 | 127 | generateMipmap(GL_TEXTURE_2D) 128 | 129 | texParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,param) 130 | texParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,param) 131 | texParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR) 132 | texParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) 133 | textureId 134 | 135 | 136 | # Uniform funcs with easier / shorter names and glm types 137 | template setBool*(program:ShaderProgramId, name: string, value: bool) = 138 | glUniform1i(getUniformLocation(program,name).GLint,value.GLint) 139 | 140 | template setInt*(program:ShaderProgramId, name: string, value: int32) = 141 | glUniform1i(getUniformLocation(program,name).GLint,value.GLint) 142 | 143 | template setFloat*(program:ShaderProgramId, name: string, value: float32) = 144 | glUniform1f(getUniformLocation(program,name).GLint,value.GLfloat) 145 | 146 | template setVec2*(program:ShaderProgramId, name: string, value:var Vec2f) = 147 | glUniform2fv(getUniformLocation(program,name).GLint,1,value.caddr) 148 | 149 | template setVec2*(program:ShaderProgramId, name: string, x:float32, y:float32) = 150 | glUniform2f(getUniformLocation(program,name).GLint,x.GLfloat,y.GLfloat) 151 | 152 | template setVec3*(program:ShaderProgramId, name: string, value:var Vec3f) = 153 | glUniform3fv(getUniformLocation(program,name).GLint,1,value.caddr) 154 | 155 | template setVec3*(program:ShaderProgramId, name: string, x:float32, y:float32, z:float32) = 156 | glUniform3f(getUniformLocation(program,name).GLint,x.GLfloat,y.GLfloat,z.GLfloat) 157 | 158 | template setVec4*(program:ShaderProgramId, name:string, value: var Vec4f) = 159 | glUniform4fv(getUniformLocation(program,name).GLint,1,value.caddr) 160 | 161 | template setVec4*(program:ShaderProgramId, name: string, x:float32, y:float32, z:float32, w:float32) = 162 | glUniform4f(getUniformLocation(program,name).GLint,x.GLfloat,y.GLfloat,z.GLfloat,w.GLfloat) 163 | 164 | template setMat4*(program:ShaderProgramId, name: string, value: var Mat4f ) = 165 | glUniformMatrix4fv(getUniformLocation(program,name).GLint,1,GL_FALSE,value.caddr) 166 | --------------------------------------------------------------------------------