Skip to content

Instantly share code, notes, and snippets.

@demotomohiro
Created February 4, 2020 16:17
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save demotomohiro/64050496bb615c50fa608d7105509a53 to your computer and use it in GitHub Desktop.
Save demotomohiro/64050496bb615c50fa608d7105509a53 to your computer and use it in GitHub Desktop.
Nim's hot code reloading with GLFW sample
import nimgl/opengl
proc createShader(source:cstring, shaderType: GLEnum): GLuint =
result = glCreateShader(shaderType)
assert result != 0
glShaderSource(result, 1, unsafeAddr 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 compiler:"
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*(
shaderSrc0: string;
shaderType0: GLEnum;
shaderSrc1: string;
shaderType1: GLEnum): GLuint =
let vso = createShader(shaderSrc0, shaderType0)
let fso = createShader(shaderSrc1, shaderType1)
result = glCreateProgram()
glAttachShader(result, vso)
glAttachShader(result, fso)
result.linkProgramObj()
glDeleteShader(vso)
glDeleteShader(fso)
proc newProgObj*(vertShaderSrc, fragShaderSrc: string): GLuint =
newProgObj(vertShaderSrc, GL_VERTEX_SHADER, fragShaderSrc, GL_FRAGMENT_SHADER)

Tested this sample with Nim 1.0.6 on Windows 8.1

  1. Install Nim Game Library
nimble install nimgl
  1. Get glfw3.dll Go to GLFW web site, go to Download page and download Windows pre-compiled binaries. Unzip it and copy glfw3.dll to where you run sample program.

  2. Copy & paste or git clone sample code

  3. Build testgl.nim

nim c --hotcodereloading:on -d:glfwDLL testgl.nim
  1. Run testgl.exe
testgl.exe
  1. Change code in logic.nim For example:
	color = vec4(0.0, 0.0, 1.0, 0.0);

to

	color = vec4(1.0, 0.0, 0.0, 0.0);

When you write this chage to the file, logic.nim is automatically rebuild and you will see a triangle with new color.

import std/[hotcodereloading, os, times]
import nimgl/opengl
import glcommon
var
progObj: GLuint
lastMod = getLastModificationTime(currentSourcePath())
proc init* =
const triangleVSSrc = """
#version 450
uniform float iTime;
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(0.5 + 0.5 * sin(iTime), 0.0, 0.0, 1.0);
}
}
"""
const triangleFSSrc = """
#version 420
out vec4 color;
void main()
{
color = vec4(0.0, 0.0, 1.0, 0.0);
}
"""
progObj = newProgObj(triangleVSSrc, triangleFSSrc)
glUseProgram(progObj)
beforeCodeReload:
glUseProgram(0)
glDeleteProgram(progObj)
afterCodeReload:
init()
proc update*(time: float32): bool =
let t = getLastModificationTime(currentSourcePath())
if t > lastMod:
if execShellCmd("nim c --hotcodereloading:on -d:glfwDLL testgl.nim") == 0:
lastMod = t
performCodeReload()
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
glUniform1f(glGetUniformLocation(progObj, "iTime"), time)
glDrawArrays(GL_TRIANGLES, 0, 3)
return true
import nimgl/[glfw, opengl]
import logic
proc main() =
doAssert glfwInit()
glfwWindowHint(GLFWContextVersionMajor, 4)
glfwWindowHint(GLFWContextVersionMinor, 5)
glfwWindowHint(GLFWOpenglForwardCompat, GLFW_TRUE)
glfwWindowHint(GLFWOpenglProfile, GLFW_OPENGL_CORE_PROFILE)
glfwWindowHint(GLFWResizable, GLFW_FALSE)
let w = glfwCreateWindow(800, 600)
assert w != nil
w.makeContextCurrent
doAssert glInit()
#OpenGL functions are available now
echo cast[cstring](glGetString(GL_VERSION))
echo cast[cstring](glGetString(GL_RENDERER))
var vao: GLuint
glGenVertexArrays(1, addr vao)
glBindVertexArray(vao)
var
width: int32
height: int32
w.getFramebufferSize(addr width, addr height)
glViewport(0, 0, GLsizei(width), GLsizei(height))
logic.init()
var iframe = 0
let fps = 60.0'f32
while logic.update(float32(iframe) / fps) and not w.windowShouldClose:
w.swapBuffers()
glfwPollEvents()
inc iframe
w.destroyWindow
glfwTerminate()
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment