Skip to content

Instantly share code, notes, and snippets.

@demotomohiro
Created November 20, 2024 03:34
Show Gist options
  • Save demotomohiro/a57561a93e088b2a121ef90630c8d1e2 to your computer and use it in GitHub Desktop.
Save demotomohiro/a57561a93e088b2a121ef90630c8d1e2 to your computer and use it in GitHub Desktop.
Minimum example nim-glfw code to draw a triangle using OpenGL
# Minimum example nim-glfw code to draw a triangle using OpenGL.
#
# There are more examples on nim-glfw repo:
# https://github.com/johnnovak/nim-glfw/tree/master/examples
# Get glad/gl.nim from
# https://glad.dav1d.de/#profile=core&language=nim&specification=gl&loader=on&api=gl%3D4.2
import glad/gl
# Install nim-glfw from
# https://github.com/johnnovak/nim-glfw
import glfw
proc createShader(source: cstring; shaderType: GLEnum): GLuint =
result = glCreateShader(shaderType)
assert result != 0
glShaderSource(result, 1, cast[cstringArray](addr source), nil)
glCompileShader(result)
var logLen: GLint
glGetShaderiv(result, GL_INFO_LOG_LENGTH, addr logLen)
if logLen != 0:
var log = newseq[int8](logLen)
glGetShaderInfoLog(result, logLen, nil, cast[cstring](addr log[0]))
echo "Message from OpenGL shader compiler:"
echo cast[cstring](addr log[0])
var compileStatus: GLint
glGetShaderiv(result, GL_COMPILE_STATUS, addr compileStatus)
if compileStatus != cast[GLint](GL_TRUE):
quit "Failed to compile shader"
proc linkProgramObj(progObj: GLuint) =
glLinkProgram(progObj)
var logLen: GLint
glGetProgramiv(progObj, GL_INFO_LOG_LENGTH, addr logLen)
if logLen != 0:
var log = newseq[int8](logLen)
glGetProgramInfoLog(progObj, logLen, nil, cast[cstring](addr log[0]))
echo "Message from OpenGL shader linker:"
echo cast[cstring](addr log[0])
var success: GLint
glGetProgramiv(progObj, GL_LINK_STATUS, addr success)
if success != cast[GLint](GL_TRUE):
quit "Failed to link shader"
proc newProgObj(vertShaderSrc, fragShaderSrc: string): GLuint =
let vso = createShader(vertShaderSrc, GL_VERTEX_SHADER)
let fso = createShader(fragShaderSrc, GL_FRAGMENT_SHADER)
result = glCreateProgram()
glAttachShader(result, vso)
glAttachShader(result, fso)
result.linkProgramObj()
proc windowFramebufferSizeCb(w: Window, size: tuple[w, h: int32]) =
#echo "Window framebuffer size: ", size.w, "x", size.h
glViewport(0, 0, size.w, size.h)
proc keyCb(win: Window, key: Key, scanCode: int32, action: KeyAction,
modKeys: set[ModifierKey]) =
if key == keyEscape and action == kaDown:
win.shouldClose = true
template glslLine(source: static string): string =
## When you put GLSL shader string on a source code as a string literal,
## this template return '#line' directive so that the line number on
## error message from GLSL shader matches line number in the source code.
"#line " & $(instantiationInfo().line + 1) & "\n" & source
proc initGL =
const triangleVSSrc = "#version 420\n" & glslLine"""
void main()
{
if(gl_VertexID == 0)
{
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
}else if(gl_VertexID == 1)
{
gl_Position = vec4(0.0, 1.0, 0.0, 1.0);
}else
{
gl_Position = vec4(1.0, 0.0, 0.0, 1.0);
}
}
"""
const triangleFSSrc = "#version 420\n" & glslLine"""
out vec4 color;
void main()
{
color = vec4(1.0, 0.0, 0.0, 0.0);
}
"""
let progObj = newProgObj(triangleVSSrc, triangleFSSrc)
glUseProgram(progObj)
var vao: GLuint
glGenVertexArrays(1, addr vao)
glBindVertexArray(vao)
proc init: Window =
glfw.initialize()
var cfg = DefaultOpenglWindowConfig
cfg.size = (w: 640, h: 480)
cfg.title = "Simple example"
cfg.resizable = true
cfg.version = glv42
cfg.forwardCompat = true
cfg.profile = opCoreProfile
result = newWindow(cfg)
result.framebufferSizeCb = windowFramebufferSizeCb
result.keyCb = keyCb
if not gladLoadGL(getProcAddress):
quit "Error gladLoadGL"
glfw.swapInterval(1)
initGL()
proc main =
let w = init()
echo "Entering main loop"
while not w.shouldClose:
glClear(GL_COLOR_BUFFER_BIT)
glDrawArrays(GL_TRIANGLES, 0, 3)
glfw.swapBuffers(w)
when false:
# Don't block
glfw.pollEvents()
else:
# Blocks until there is any events.
# Use this one if your program do nothing when there is no user input.
glfw.waitEvents()
glfw.terminate()
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment