Exemplo n.º 1
0
func main() {
	if err := glfw.Init(); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}
	defer glfw.Terminate()

	glfw.OpenWindowHint(glfw.FsaaSamples, 4)
	glfw.OpenWindowHint(glfw.OpenGLVersionMajor, 3)
	glfw.OpenWindowHint(glfw.OpenGLVersionMinor, 3)
	glfw.OpenWindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)

	if err := glfw.OpenWindow(1024, 768, 0, 0, 0, 0, 32, 0, glfw.Windowed); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}

	gl.Init()
	gl.GetError() // Ignore error

	glfw.SetWindowTitle("Tutorial 01")
	glfw.Enable(glfw.StickyKeys)

	gl.ClearColor(0., 0., 0.4, 0.)
	// Equivalent to a do... while
	for ok := true; ok; ok = (glfw.Key(glfw.KeyEsc) != glfw.KeyPress && glfw.WindowParam(glfw.Opened) == gl.TRUE) {
		glfw.SwapBuffers()
	}

}
Exemplo n.º 2
0
func main() {
	if err := glfw.Init(); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}

	defer glfw.Terminate()

	glfw.OpenWindowHint(glfw.FsaaSamples, 4)
	glfw.OpenWindowHint(glfw.OpenGLVersionMajor, 3)
	glfw.OpenWindowHint(glfw.OpenGLVersionMinor, 3)
	glfw.OpenWindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)

	if err := glfw.OpenWindow(1024, 768, 0, 0, 0, 0, 32, 0, glfw.Windowed); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}

	gl.Init()     // Can't find gl.GLEW_OK or any variation, not sure how to check if this worked
	gl.GetError() // Ignore error

	glfw.SetWindowTitle("Tutorial 02")

	glfw.Enable(glfw.StickyKeys)
	gl.ClearColor(0., 0., 0.4, 0.)

	prog := helper.MakeProgram("SimpleVertexShader.vertexshader", "SimpleFragmentShader.fragmentshader")

	vBufferData := [...]float32{
		-1., -1., 0.,
		1., -1., 0.,
		0., 1., 0.}

	vertexArray := gl.GenVertexArray()
	vertexArray.Bind()
	buffer := gl.GenBuffer()
	buffer.Bind(gl.ARRAY_BUFFER)
	gl.BufferData(gl.ARRAY_BUFFER, len(vBufferData)*4, &vBufferData, gl.STATIC_DRAW)

	// Equivalent to a do... while
	for ok := true; ok; ok = (glfw.Key(glfw.KeyEsc) != glfw.KeyPress && glfw.WindowParam(glfw.Opened) == gl.TRUE) {
		gl.Clear(gl.COLOR_BUFFER_BIT)

		prog.Use()

		attribLoc := gl.AttribLocation(0)
		attribLoc.EnableArray()
		buffer.Bind(gl.ARRAY_BUFFER)
		attribLoc.AttribPointer(3, gl.FLOAT, false, 0, nil)

		gl.DrawArrays(gl.TRIANGLES, 0, 3)

		attribLoc.DisableArray()

		glfw.SwapBuffers()
	}

}
Exemplo n.º 3
0
func main() {
	var err error
	if err = glfw.Init(); err != nil {
		fmt.Fprintf(os.Stderr, "[e] %v\n", err)
		return
	}

	// Ensure glfw is cleanly terminated on exit.
	defer glfw.Terminate()

	if err = glfw.OpenWindow(256, 256, 8, 8, 8, 0, 0, 0, glfw.Windowed); err != nil {
		fmt.Fprintf(os.Stderr, "[e] %v\n", err)
		return
	}

	// Ensure window is cleanly closed on exit.
	defer glfw.CloseWindow()

	// Enable vertical sync on cards that support it.
	glfw.SetSwapInterval(1)

	// Set window title
	glfw.SetWindowTitle("Simple GLFW window")

	// Hook some events to demonstrate use of callbacks.
	// These are not necessary if you don't need them.
	glfw.SetWindowSizeCallback(onResize)
	glfw.SetWindowCloseCallback(onClose)
	glfw.SetMouseButtonCallback(onMouseBtn)
	glfw.SetMouseWheelCallback(onMouseWheel)
	glfw.SetKeyCallback(onKey)
	glfw.SetCharCallback(onChar)

	// Start loop
	running := true
	for running {
		// OpenGL rendering goes here.

		// Swap front and back rendering buffers. This also implicitly calls
		// glfw.PollEvents(), so we have valid key/mouse/joystick states after
		// this. This behavior can be disabled by calling glfw.Disable with the
		// argument glfw.AutoPollEvents. You must be sure to manually call
		// PollEvents() or WaitEvents() in this case.
		glfw.SwapBuffers()

		// Break out of loop when Escape key is pressed, or window is closed.
		running = glfw.Key(glfw.KeyEsc) == 0 && glfw.WindowParam(glfw.Opened) == 1
	}
}
Exemplo n.º 4
0
func Run() {

	running = true

	for running {

		start := time.Now()

		escPressed := glfw.Key(glfw.KeyEsc)
		windowOpen := glfw.WindowParam(glfw.Opened)

		running = escPressed == 0 && windowOpen == 1

		select {
		case data := <-ScreenOutputChan:

			drawFrame(data.Pixels)
			drawInfoBox(3, 3, 12, data.IterNr, data.NThreads, data.ExecTime)
			glfw.SwapBuffers()

		default: // Non blocking!
			glfw.PollEvents()

		}

		// Limit to 60hz

		elapsed := time.Since(start)

		timeToSleep := 16*time.Millisecond - elapsed

		if timeToSleep > 0 {
			time.Sleep(timeToSleep)
		}

	}
}
Exemplo n.º 5
0
func main() {
	var err error
	var looping = true
	defer fmt.Println("EXIT")
	if err = glfw.Init(); err != nil {
		panic(err)
	}
	defer glfw.Terminate()
	glfw.OpenWindowHint(glfw.FsaaSamples, 0)
	if useStrictCoreProfile {
		glfw.OpenWindowHint(glfw.OpenGLVersionMajor, 3)
		glfw.OpenWindowHint(glfw.OpenGLVersionMinor, 2)
		glfw.OpenWindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	}

	if err = glfw.OpenWindow(1280, 720, 8, 8, 8, 0, 24, 8, glfw.Windowed); err != nil {
		panic(err)
	}
	defer glfw.CloseWindow()
	glfw.Enable(glfw.StickyKeys)
	if !gl.Util.Init() {
		panic("Failed to initialize at least OpenGL 3.2 or higher.")
	}
	defer logLastGlError("(post loop)")
	gl.ClearColor(0.3, 0.1, 0.0, 1.0)
	gl.Enable(gl.DEPTH_TEST)
	gl.FrontFace(gl.CCW)
	gl.CullFace(gl.BACK)
	gl.Disable(gl.CULL_FACE)
	if err = compileShaders(); err != nil {
		panic(err)
	}
	setupGeometry()
	defer deleteGeometry()
	logLastGlError("(pre loop)")

	for looping {
		gl.UseProgram(shaderProg)
		if isFirstLoop {
			logLastGlError("gl.UseProgram")
		}

		gl.Viewport(0, 0, 1280, 720)
		if isFirstLoop {
			logLastGlError("gl.ViewPort")
		}

		gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
		if isFirstLoop {
			logLastGlError("gl.Clear")
		}

		renderGeometry(faceTri)
		if isFirstLoop {
			logLastGlError("renderGeometry(faceTri)")
		}

		renderGeometry(faceQuad)
		if isFirstLoop {
			logLastGlError("renderGeometry(faceQuad)")
		}

		if (glfw.WindowParam(glfw.Opened) != 1) || (glfw.Key(glfw.KeyEsc) == glfw.KeyPress) {
			looping = false
		} else {
			glfw.SwapBuffers()
		}
		isFirstLoop = false
	}
	logLastGlError("post-loop")
}
Exemplo n.º 6
0
func main() {
	if err := glfw.Init(); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}

	defer glfw.Terminate()

	glfw.OpenWindowHint(glfw.FsaaSamples, 4)
	glfw.OpenWindowHint(glfw.OpenGLVersionMajor, 3)
	glfw.OpenWindowHint(glfw.OpenGLVersionMinor, 3)
	glfw.OpenWindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)

	if err := glfw.OpenWindow(1024, 768, 0, 0, 0, 0, 32, 0, glfw.Windowed); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}

	glfw.SetSwapInterval(0)

	//gl.GlewExperimental(true)
	gl.Init()     // Can't find gl.GLEW_OK or any variation, not sure how to check if this worked
	gl.GetError() // ignore error, since we're telling it to use CoreProfile above, we get "invalid enumerant" (GLError 1280) which freaks the OpenGLSentinel out

	glfw.SetWindowTitle("Tutorial 07")

	glfw.Enable(glfw.StickyKeys)
	glfw.Disable(glfw.MouseCursor) // Not in the original tutorial, but IMO it SHOULD be there
	glfw.SetMousePos(1024.0/2.0, 768.0/2.0)

	gl.ClearColor(0., 0., 0.4, 0.)

	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LESS)

	gl.Enable(gl.CULL_FACE)

	camera := input.NewCamera()

	vertexArray := gl.GenVertexArray()
	defer vertexArray.Delete()
	vertexArray.Bind()

	prog := helper.MakeProgram("TransformVertexShader.vertexshader", "TextureFragmentShader.fragmentshader")
	defer prog.Delete()

	matrixID := prog.GetUniformLocation("MVP")

	texture := helper.MakeTextureFromTGA("uvmap.tga") // Had to convert to tga, go-gl is missing the texture method for DDS right now
	defer texture.Delete()
	texSampler := prog.GetUniformLocation("myTextureSampler")

	meshObj := objloader.LoadObject("cube.obj")
	vertices, uvs := meshObj.Vertices, meshObj.UVs

	vertexBuffer := gl.GenBuffer()
	defer vertexBuffer.Delete()
	vertexBuffer.Bind(gl.ARRAY_BUFFER)
	gl.BufferData(gl.ARRAY_BUFFER, len(vertices)*3*4, vertices, gl.STATIC_DRAW)

	uvBuffer := gl.GenBuffer()
	defer uvBuffer.Delete()
	uvBuffer.Bind(gl.ARRAY_BUFFER)
	// UV doesn't seem to care
	gl.BufferData(gl.ARRAY_BUFFER, len(uvs)*2*4, uvs, gl.STATIC_DRAW)

	// Equivalent to a do... while
	for ok := true; ok; ok = (glfw.Key(glfw.KeyEsc) != glfw.KeyPress && glfw.WindowParam(glfw.Opened) == gl.TRUE && glfw.Key('Q') != glfw.KeyPress) {
		func() {
			gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

			prog.Use()
			defer gl.ProgramUnuse()

			view, proj := camera.ComputeViewPerspective()
			model := mathgl.Ident4f()

			MVP := proj.Mul4(view).Mul4(model)

			matrixID.UniformMatrix4fv(false, MVP)

			gl.ActiveTexture(gl.TEXTURE0)
			texture.Bind(gl.TEXTURE_2D)
			defer texture.Unbind(gl.TEXTURE_2D)
			texSampler.Uniform1i(0)

			vertexAttrib := gl.AttribLocation(0)
			vertexAttrib.EnableArray()
			defer vertexAttrib.DisableArray()
			vertexBuffer.Bind(gl.ARRAY_BUFFER)
			defer vertexBuffer.Unbind(gl.ARRAY_BUFFER)
			vertexAttrib.AttribPointer(3, gl.FLOAT, false, 0, nil)

			uvAttrib := gl.AttribLocation(1)
			uvAttrib.EnableArray()
			defer uvAttrib.DisableArray()
			uvBuffer.Bind(gl.ARRAY_BUFFER)
			defer uvBuffer.Unbind(gl.ARRAY_BUFFER)
			uvAttrib.AttribPointer(2, gl.FLOAT, false, 0, nil)

			gl.DrawArrays(gl.TRIANGLES, 0, len(vertices))

			glfw.SwapBuffers()
		}() // Defers unbinds and disables to here, end of the loop
	}

}
Exemplo n.º 7
0
// Check whether a key is pressed.
func (c *Controller) Key(key int) int {
	return glfw.Key(key)
}
Exemplo n.º 8
0
func New(width int, height int, title string) *Window {
	var err error
	window := &Window{width: width, height: height, title: title}
	// initialize logger
	logf, err := os.OpenFile("window.log", os.O_WRONLY|os.O_CREATE, 0640)
	logger := log.New(logf, "", log.Ldate|log.Ltime)

	if err = glfw.Init(); err != nil {
		fmt.Fprintf(os.Stderr, "[e] %v\n", err)
		return nil
	}

	// width, hieght, r,g,b,a (color depth bits), depth, stencil, mode
	if err = glfw.OpenWindow(window.width, window.height, 8, 8, 8, 0, 0, 0, glfw.Windowed); err != nil {
		fmt.Fprintf(os.Stderr, "[e] %v\n", err)
		return nil
	}

	onResize := func(w, h int) {
		logger.Printf("resized: %dx%d\n", w, h)
	}

	onClose := func() int {
		logger.Println("window closed\n")
		return 1 // return 0 to keep window open.
	}

	// list callback generators
	createBtnList := func(btnNext func() interface{}, device string) func(button, state int) {
		btnList := list.New()
		btnNext = func() interface{} { return btnList.Remove(btnList.Back()) }
		return func(button, state int) {
			btnList.PushFront(btnEvent{button: button, state: state})
			logger.Printf("%s button: %d, %d\n", device, button, state)
		}
	}

	createPosList := func(posNext func() interface{}, device string) func(x, y int) {
		posList := list.New()
		posNext = func() interface{} { return posList.Remove(posList.Back()) }
		return func(x, y int) {
			posList.PushFront(posEvent{x: x, y: y})
			logger.Printf("%s pos: %d, %d\n", device, x, y)
		}
	}

	createDeltaList := func(deltaNext func() interface{}, device string) func(delta int) {
		deltaList := list.New()
		deltaNext = func() interface{} { return deltaList.Remove(deltaList.Back()) }
		return func(delta int) {
			deltaList.PushFront(deltaEvent{delta: delta})
			logger.Printf("%s delta: %d\n", device, delta)
		}
	}

	glfw.SetSwapInterval(1)
	glfw.SetWindowTitle(title)

	glfw.SetWindowSizeCallback(onResize)
	glfw.SetWindowCloseCallback(onClose)
	glfw.SetMousePosCallback(createPosList(window.MousePos, "mouse pos"))
	glfw.SetMouseButtonCallback(createBtnList(window.MouseBtn, "mouse"))
	glfw.SetMouseWheelCallback(createDeltaList(window.MouseWheel, "mouse wheel"))
	glfw.SetKeyCallback(createBtnList(window.KeyEvt, "keyboard"))
	glfw.SetCharCallback(createBtnList(window.CharEvt, "char"))

	window.Start = func() {
		defer glfw.Terminate()
		defer glfw.CloseWindow()
		running := true
		for running {
			window.Render()
			glfw.SwapBuffers()
			// Break out of loop when Escape key is pressed, or window is closed.
			running = glfw.Key(glfw.KeyEsc) == 0 && glfw.WindowParam(glfw.Opened) == 1
		}
	}

	return window
}
Exemplo n.º 9
0
func main() {
	if err := glfw.Init(); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}

	defer glfw.Terminate()

	glfw.OpenWindowHint(glfw.FsaaSamples, 4)
	glfw.OpenWindowHint(glfw.OpenGLVersionMajor, 3)
	glfw.OpenWindowHint(glfw.OpenGLVersionMinor, 3)
	glfw.OpenWindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)

	if err := glfw.OpenWindow(1024, 768, 0, 0, 0, 0, 32, 0, glfw.Windowed); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}

	gl.Init()
	gl.GetError() // Ignore error

	glfw.SetWindowTitle("Tutorial 04")

	glfw.Enable(glfw.StickyKeys)
	gl.ClearColor(0., 0., 0.4, 0.)

	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LESS)

	vertexArray := gl.GenVertexArray()
	defer vertexArray.Delete()
	vertexArray.Bind()

	prog := helper.MakeProgram("TransformVertexShader.vertexshader", "ColorFragmentShader.fragmentshader")
	defer prog.Delete()

	matrixID := prog.GetUniformLocation("MVP")

	Projection := mathgl.Perspective(45.0, 4.0/3.0, 0.1, 100.0)

	View := mathgl.LookAt(4.0, 3.0, -3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)

	Model := mathgl.Ident4f()

	MVP := Projection.Mul4(View).Mul4(Model) // Remember, transform multiplication order is "backwards"

	vBufferData := [...]float32{
		-1.0, -1.0, -1.0,
		-1.0, -1.0, 1.0,
		-1.0, 1.0, 1.0,
		1.0, 1.0, -1.0,
		-1.0, -1.0, -1.0,
		-1.0, 1.0, -1.0,
		1.0, -1.0, 1.0,
		-1.0, -1.0, -1.0,
		1.0, -1.0, -1.0,
		1.0, 1.0, -1.0,
		1.0, -1.0, -1.0,
		-1.0, -1.0, -1.0,
		-1.0, -1.0, -1.0,
		-1.0, 1.0, 1.0,
		-1.0, 1.0, -1.0,
		1.0, -1.0, 1.0,
		-1.0, -1.0, 1.0,
		-1.0, -1.0, -1.0,
		-1.0, 1.0, 1.0,
		-1.0, -1.0, 1.0,
		1.0, -1.0, 1.0,
		1.0, 1.0, 1.0,
		1.0, -1.0, -1.0,
		1.0, 1.0, -1.0,
		1.0, -1.0, -1.0,
		1.0, 1.0, 1.0,
		1.0, -1.0, 1.0,
		1.0, 1.0, 1.0,
		1.0, 1.0, -1.0,
		-1.0, 1.0, -1.0,
		1.0, 1.0, 1.0,
		-1.0, 1.0, -1.0,
		-1.0, 1.0, 1.0,
		1.0, 1.0, 1.0,
		-1.0, 1.0, 1.0,
		1.0, -1.0, 1.0}

	colorBufferData := [...]float32{
		0.583, 0.771, 0.014,
		0.609, 0.115, 0.436,
		0.327, 0.483, 0.844,
		0.822, 0.569, 0.201,
		0.435, 0.602, 0.223,
		0.310, 0.747, 0.185,
		0.597, 0.770, 0.761,
		0.559, 0.436, 0.730,
		0.359, 0.583, 0.152,
		0.483, 0.596, 0.789,
		0.559, 0.861, 0.639,
		0.195, 0.548, 0.859,
		0.014, 0.184, 0.576,
		0.771, 0.328, 0.970,
		0.406, 0.615, 0.116,
		0.676, 0.977, 0.133,
		0.971, 0.572, 0.833,
		0.140, 0.616, 0.489,
		0.997, 0.513, 0.064,
		0.945, 0.719, 0.592,
		0.543, 0.021, 0.978,
		0.279, 0.317, 0.505,
		0.167, 0.620, 0.077,
		0.347, 0.857, 0.137,
		0.055, 0.953, 0.042,
		0.714, 0.505, 0.345,
		0.783, 0.290, 0.734,
		0.722, 0.645, 0.174,
		0.302, 0.455, 0.848,
		0.225, 0.587, 0.040,
		0.517, 0.713, 0.338,
		0.053, 0.959, 0.120,
		0.393, 0.621, 0.362,
		0.673, 0.211, 0.457,
		0.820, 0.883, 0.371,
		0.982, 0.099, 0.879}

	//elBufferData := [...]uint8{0, 1, 2} // Not sure why this is here

	vertexBuffer := gl.GenBuffer()
	defer vertexBuffer.Delete()
	vertexBuffer.Bind(gl.ARRAY_BUFFER)
	gl.BufferData(gl.ARRAY_BUFFER, len(vBufferData)*4, &vBufferData, gl.STATIC_DRAW)

	colorBuffer := gl.GenBuffer()
	defer colorBuffer.Delete()
	colorBuffer.Bind(gl.ARRAY_BUFFER)
	gl.BufferData(gl.ARRAY_BUFFER, len(colorBufferData)*4, &colorBufferData, gl.STATIC_DRAW)

	// Equivalent to a do... while
	for ok := true; ok; ok = (glfw.Key(glfw.KeyEsc) != glfw.KeyPress && glfw.WindowParam(glfw.Opened) == gl.TRUE) {
		gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

		prog.Use()

		matrixID.UniformMatrix4fv(false, MVP)

		vertexAttrib := gl.AttribLocation(0)
		vertexAttrib.EnableArray()
		vertexBuffer.Bind(gl.ARRAY_BUFFER)
		vertexAttrib.AttribPointer(3, gl.FLOAT, false, 0, nil)

		colorAttrib := gl.AttribLocation(1)
		colorAttrib.EnableArray()
		colorBuffer.Bind(gl.ARRAY_BUFFER)
		colorAttrib.AttribPointer(3, gl.FLOAT, false, 0, nil)

		gl.DrawArrays(gl.TRIANGLES, 0, 12*3)

		vertexAttrib.DisableArray()
		colorAttrib.DisableArray()

		glfw.SwapBuffers()
	}

}
Exemplo n.º 10
0
//	Returns true if the specified key is pressed.
func (_ *NgUserIO) KeyPressed(key int) bool {
	return glfw.Key(key) == glfw.KeyPress
}
Exemplo n.º 11
0
func main() {
	if err := glfw.Init(); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}

	defer glfw.Terminate()

	glfw.OpenWindowHint(glfw.FsaaSamples, 4)
	glfw.OpenWindowHint(glfw.OpenGLVersionMajor, 3)
	glfw.OpenWindowHint(glfw.OpenGLVersionMinor, 3)
	glfw.OpenWindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)

	if err := glfw.OpenWindow(1024, 768, 0, 0, 0, 0, 32, 0, glfw.Windowed); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}

	//gl.GlewExperimental(true)
	gl.Init()     // Can't find gl.GLEW_OK or any variation, not sure how to check if this worked
	gl.GetError() // ignore error, since we're telling it to use CoreProfile above, we get "invalid enumerant" (GLError 1280) which freaks the OpenGLSentinel out
	// With go-gl we also apparently can't set glewExperimental

	glfw.SetWindowTitle("Tutorial 05")

	glfw.Enable(glfw.StickyKeys)
	gl.ClearColor(0., 0., 0.4, 0.)

	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LESS)

	vertexArray := gl.GenVertexArray()
	defer vertexArray.Delete()
	vertexArray.Bind()

	prog := helper.MakeProgram("TransformVertexShader.vertexshader", "TextureFragmentShader.fragmentshader")
	defer prog.Delete()

	matrixID := prog.GetUniformLocation("MVP")

	Projection := mathgl.Perspective(45.0, 4.0/3.0, 0.1, 100.0)

	View := mathgl.LookAt(4.0, 3.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)

	Model := mathgl.Ident4f()

	MVP := Projection.Mul4(View).Mul4(Model) // Remember, transform multiplication order is "backwards"

	texture := helper.MakeTextureFromTGA("uvtemplate.tga")
	defer texture.Delete()
	texSampler := prog.GetUniformLocation("myTextureSampler")

	vBufferData := [...]float32{
		-1.0, -1.0, -1.0,
		-1.0, -1.0, 1.0,
		-1.0, 1.0, 1.0,
		1.0, 1.0, -1.0,
		-1.0, -1.0, -1.0,
		-1.0, 1.0, -1.0,
		1.0, -1.0, 1.0,
		-1.0, -1.0, -1.0,
		1.0, -1.0, -1.0,
		1.0, 1.0, -1.0,
		1.0, -1.0, -1.0,
		-1.0, -1.0, -1.0,
		-1.0, -1.0, -1.0,
		-1.0, 1.0, 1.0,
		-1.0, 1.0, -1.0,
		1.0, -1.0, 1.0,
		-1.0, -1.0, 1.0,
		-1.0, -1.0, -1.0,
		-1.0, 1.0, 1.0,
		-1.0, -1.0, 1.0,
		1.0, -1.0, 1.0,
		1.0, 1.0, 1.0,
		1.0, -1.0, -1.0,
		1.0, 1.0, -1.0,
		1.0, -1.0, -1.0,
		1.0, 1.0, 1.0,
		1.0, -1.0, 1.0,
		1.0, 1.0, 1.0,
		1.0, 1.0, -1.0,
		-1.0, 1.0, -1.0,
		1.0, 1.0, 1.0,
		-1.0, 1.0, -1.0,
		-1.0, 1.0, 1.0,
		1.0, 1.0, 1.0,
		-1.0, 1.0, 1.0,
		1.0, -1.0, 1.0}

	uvBufferData := [...]float32{
		0.000059, 1.0 - 0.000004,
		0.000103, 1.0 - 0.336048,
		0.335973, 1.0 - 0.335903,
		1.000023, 1.0 - 0.000013,
		0.667979, 1.0 - 0.335851,
		0.999958, 1.0 - 0.336064,
		0.667979, 1.0 - 0.335851,
		0.336024, 1.0 - 0.671877,
		0.667969, 1.0 - 0.671889,
		1.000023, 1.0 - 0.000013,
		0.668104, 1.0 - 0.000013,
		0.667979, 1.0 - 0.335851,
		0.000059, 1.0 - 0.000004,
		0.335973, 1.0 - 0.335903,
		0.336098, 1.0 - 0.000071,
		0.667979, 1.0 - 0.335851,
		0.335973, 1.0 - 0.335903,
		0.336024, 1.0 - 0.671877,
		1.000004, 1.0 - 0.671847,
		0.999958, 1.0 - 0.336064,
		0.667979, 1.0 - 0.335851,
		0.668104, 1.0 - 0.000013,
		0.335973, 1.0 - 0.335903,
		0.667979, 1.0 - 0.335851,
		0.335973, 1.0 - 0.335903,
		0.668104, 1.0 - 0.000013,
		0.336098, 1.0 - 0.000071,
		0.000103, 1.0 - 0.336048,
		0.000004, 1.0 - 0.671870,
		0.336024, 1.0 - 0.671877,
		0.000103, 1.0 - 0.336048,
		0.336024, 1.0 - 0.671877,
		0.335973, 1.0 - 0.335903,
		0.667969, 1.0 - 0.671889,
		1.000004, 1.0 - 0.671847,
		0.667979, 1.0 - 0.335851}

	vertexBuffer := gl.GenBuffer()
	defer vertexBuffer.Delete()
	vertexBuffer.Bind(gl.ARRAY_BUFFER)
	gl.BufferData(gl.ARRAY_BUFFER, len(vBufferData)*4, &vBufferData, gl.STATIC_DRAW)

	uvBuffer := gl.GenBuffer()
	defer uvBuffer.Delete()
	uvBuffer.Bind(gl.ARRAY_BUFFER)
	gl.BufferData(gl.ARRAY_BUFFER, len(uvBufferData)*4, &uvBufferData, gl.STATIC_DRAW)

	// Equivalent to a do... while
	for ok := true; ok; ok = (glfw.Key(glfw.KeyEsc) != glfw.KeyPress && glfw.WindowParam(glfw.Opened) == gl.TRUE) {
		func() {
			gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

			prog.Use()
			defer gl.ProgramUnuse()

			matrixID.UniformMatrix4fv(false, MVP)

			gl.ActiveTexture(gl.TEXTURE0)
			texture.Bind(gl.TEXTURE_2D)
			defer texture.Unbind(gl.TEXTURE_2D)
			texSampler.Uniform1i(0)

			vertexAttrib := gl.AttribLocation(0)
			vertexAttrib.EnableArray()
			defer vertexAttrib.DisableArray()
			vertexBuffer.Bind(gl.ARRAY_BUFFER)
			defer vertexBuffer.Unbind(gl.ARRAY_BUFFER)
			vertexAttrib.AttribPointer(3, gl.FLOAT, false, 0, nil)

			uvAttrib := gl.AttribLocation(1)
			uvAttrib.EnableArray()
			defer uvAttrib.DisableArray()
			uvBuffer.Bind(gl.ARRAY_BUFFER)
			defer uvBuffer.Unbind(gl.ARRAY_BUFFER)
			uvAttrib.AttribPointer(2, gl.FLOAT, false, 0, nil)

			gl.DrawArrays(gl.TRIANGLES, 0, 12*3)

			glfw.SwapBuffers()
		}() // Defers unbinds and disables to here, end of the loop
	}

}
Exemplo n.º 12
0
func (me *window) Key(key int) int {
	return glfw.Key(key)
}
Exemplo n.º 13
0
func (s *System) CheckExitMainLoop() bool {
	return (glfw.Key(glfw.KeyEsc) != glfw.KeyPress && glfw.WindowParam(glfw.Opened) == gl.TRUE)
}
Exemplo n.º 14
0
func IsKeyDown(key int) bool {
	return glfw.Key(key) == glfw.KeyPress
}
Exemplo n.º 15
0
func main() {
	if err := glfw.Init(); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}

	defer glfw.Terminate()

	glfw.OpenWindowHint(glfw.FsaaSamples, 4)
	glfw.OpenWindowHint(glfw.OpenGLVersionMajor, 3)
	glfw.OpenWindowHint(glfw.OpenGLVersionMinor, 3)
	glfw.OpenWindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)

	if err := glfw.OpenWindow(1024, 768, 0, 0, 0, 0, 32, 0, glfw.Windowed); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}

	gl.Init()     // Can't find gl.GLEW_OK or any variation, not sure how to check if this worked
	gl.GetError() // Ignore error

	glfw.SetWindowTitle("Tutorial 03")

	glfw.Enable(glfw.StickyKeys)
	gl.ClearColor(0., 0., 0.4, 0.)

	vertexArray := gl.GenVertexArray()
	defer vertexArray.Delete()
	vertexArray.Bind()

	prog := helper.MakeProgram("SimpleTransform.vertexshader", "SingleColor.fragmentshader")
	defer prog.Delete()

	matrixID := prog.GetUniformLocation("MVP")

	Projection := mathgl.Perspective(45.0, 4.0/3.0, 0.1, 100.0)
	//Projection := mathgl.Identity(4,mathgl.FLOAT64)
	//Projection := mathgl.Ortho2D(-5,5,-5,5)
	View := mathgl.LookAt(4.0, 3.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
	//View := mathgl.Identity(4,mathgl.FLOAT64)

	Model := mathgl.Ident4f()
	//Model := mathgl.Scale3D(2.,2.,2.).Mul(mathgl.HomogRotate3DX(25.0)).Mul(mathgl.Translate3D(.5,.2,-.7))
	MVP := Projection.Mul4(View).Mul4(Model) // Remember, transform multiplication order is "backwards"

	vBufferData := [...]float32{
		-1., -1., 0.,
		1., -1., 0.,
		0., 1., 0.}
	//elBufferData := [...]uint8{0, 1, 2} // Not sure why this is here

	buffer := gl.GenBuffer()
	defer buffer.Delete()
	buffer.Bind(gl.ARRAY_BUFFER)
	gl.BufferData(gl.ARRAY_BUFFER, len(vBufferData)*4, &vBufferData, gl.STATIC_DRAW)

	// Equivalent to a do... while
	for ok := true; ok; ok = (glfw.Key(glfw.KeyEsc) != glfw.KeyPress && glfw.WindowParam(glfw.Opened) == gl.TRUE) {
		gl.Clear(gl.COLOR_BUFFER_BIT)

		prog.Use()

		matrixID.UniformMatrix4fv(false, MVP)

		attribLoc := gl.AttribLocation(0)
		attribLoc.EnableArray()
		buffer.Bind(gl.ARRAY_BUFFER)
		attribLoc.AttribPointer(3, gl.FLOAT, false, 0, nil)

		gl.DrawArrays(gl.TRIANGLES, 0, 3)

		attribLoc.DisableArray()

		glfw.SwapBuffers()
	}

}
Exemplo n.º 16
0
func (s *Sys) stepCycle() error {

	// TODO(nictuku): Show CPU tracer on video.
	draw := false
	// pc points to next opcode.
	opcode := uint16(s.mem[s.PC])<<8 | uint16(s.mem[s.PC+1])
	// defer log.Printf("opcode 0x%04x", opcode)
	// defer log.Printf("cycle result:\n%v", s.String())

	x := byte((opcode & 0x0F00) >> 8)
	y := byte((opcode & 0x00F0) >> 4)

	switch opcode & 0xF000 {
	case 0x0000:
		if opcode&0xFF00 != 0x0000 {
			// 0NNN	Calls RCA 1802 program at address NNN.
			//  => Only used by the original computers that implemented CHIP-8.
			goto NOTIMPLEMENTED
		}

		switch opcode & 0x000F {
		case 0x0000:
			// 00E0	Clears the screen.
			s.gfx = make([]byte, screenWidth*screenHeight)
			draw = true
		default:
			// 00EE	Returns from a subroutine.
			if s.SP <= 0 {
				return fmt.Errorf("stack bottom")
			}
			s.PC = s.stack[s.SP]
			s.SP--
		}

	case 0x1000:
		// 1NNN	Jumps to address NNN.
		s.PC = opcode & 0x0FFF
		goto SKIPINC

	case 0x2000:
		// 2NNN	Calls subroutine at NNN.
		if s.SP >= 15 {
			return fmt.Errorf("stack exhausted")
		}
		s.SP++
		s.stack[s.SP] = s.PC
		s.PC = opcode & 0x0FFF
		goto SKIPINC

	case 0x3000:
		// 3XNN	Skips the next instruction if VX equals NN.
		// Weird type mistmatch. Expected?
		if uint16(s.V[x]) == opcode&0xFF {
			s.PC += 2
		}

	case 0x4000:
		// 4XNN	Skips the next instruction if VX doesn't equal NN.
		if s.V[x] != byte(opcode&0xFF) {
			// Skip next.
			s.PC += 2
		}
	case 0x5000:
		// 5XY0	Skips the next instruction if VX equals VY.
		if s.V[x] == s.V[y] {
			s.PC += 2
		}

	case 0x6000:
		// 6XNN	Sets VX to NN.
		s.V[x] = byte(opcode & 0x00FF)
	case 0x7000:
		// 7XNN	Adds NN to VX.
		s.V[x] += byte(opcode & 0x00FF)

	case 0x8000:
		switch opcode & 0x000F {
		case 0x0000:
			// 8XY0	Sets VX to the value of VY.
			s.V[x] = s.V[y]
		case 0x0001:
			// 8XY1	Sets VX to VX or VY.
			s.V[x] = s.V[x] | s.V[y]

		case 0x0002:
			// 8XY2	Sets VX to VX and VY.
			s.V[x] = s.V[x] & s.V[y]
		case 0x0003:
			// 8XY3	Sets VX to VX xor VY.
			s.V[x] = s.V[x] ^ s.V[y]
		case 0x0004:
			// 8XY4	Adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't.
			add := s.V[x] + s.V[y]
			s.V[x] = add & 0xFF
			s.V[0xF] = (add >> 8) & 0x1
		case 0x0005:
			// 8XY5	VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
			sub := s.V[x] - s.V[y]
			if sub < 0 {
				sub = 0
				s.V[0xF] = 0
			} else {
				s.V[0xF] = 1
			}
			s.V[x] = sub
		default:
			goto NOTIMPLEMENTED
		}
	// 8XY6	Shifts VX right by one. VF is set to the value of the least significant bit of VX before the shift.[2]
	// 8XY7	Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
	// 8XYE	Shifts VX left by one. VF is set to the value of the most significant bit of VX before the shift.[2]

	case 0x9000:
		// 9XY0	Skips the next instruction if VX doesn't equal VY.
		if s.V[x] != s.V[y] {
			s.PC += 2
		}

	case 0xA000:
		// ANNN	Sets I to the address NNN.
		s.I = opcode & 0x0FFF

	// BNNN	Jumps to the address NNN plus V0.
	case 0xC000:
		// CXNN	Sets VX to a random number and NN.
		s.V[x] = byte(uint16(rand.Int()) & opcode & 0x0FF)

	case 0xD000:
		// DXYN	Draws a sprite at coordinate (VX, VY) that has a width of 8
		// pixels and a height of N pixels. Each row of 8 pixels is read as
		// bit-coded (with the most significant bit of each byte displayed on
		// the left) starting from memory location I; I value doesn't change
		// after the execution of this instruction.

		// Based on the implementation from:
		// http://www.multigesture.net
		var pixel byte
		x := uint16(s.V[(opcode&0x0F00)>>8])
		y := uint16(s.V[(opcode&0x00F0)>>4])
		height := uint16(opcode & 0x000F)
		s.V[0xF] = 0

		// yline+y < screenHeight was added later, to prevent out of range offsets.
		for yline := uint16(0); yline < height && yline+y < screenHeight; yline++ {
			pixel = s.mem[s.I+yline]
			for xline := uint16(0); xline < 8; xline++ {
				if (pixel & (0x80 >> xline)) != 0 {
					offset := (x + xline + ((y + yline) * screenWidth))
					if s.gfx[offset] == 1 {
						// VF is set to 1 if any screen pixels are flipped from
						// set to unset when the sprite is drawn, and to 0 if
						// that doesn't happen.
						s.V[0xF] = 1
					}
					s.gfx[offset] ^= 1
				}
			}
		}
		draw = true

	case 0xE000:
		switch opcode & 0x00FF {
		case 0x00A1:
			// EXA1	Skips the next instruction if the key stored in VX isn't pressed.
			// TODO(nictuku): Implement keyboard events.
			if (s.key[s.V[x]]) == false {
				s.PC += 2
			}
			// goto NOTIMPLEMENTED
		case 0x009E:
			// EX9E Skips the next instruction if the key stored in VX is pressed.
			// TODO(nictuku): Implement keyboard events.
			// goto NOTIMPLEMENTED
			// s.PC += 2
			if (s.key[s.V[x]]) == true {
				s.PC += 2
			}

		default:
			goto NOTIMPLEMENTED
		}
	case 0xF000:
		switch opcode & 0x00FF {
		case 0x000A:
			// FX0A	A key press is awaited, and then stored in VX.
			// notifyKeyEvent.
		L:
			for {

				glfw.WaitEvents()
				for i, k := range keyMap {
					panic(fmt.Sprintf("resulting value %x", k))

					if glfw.Key(int(k)) == glfw.KeyPress {

						s.key[i] = true
						s.V[x] = k
						break L
					}
					s.key[i] = false
				}
			}

		case 0x0007:
			// FX07	Sets VX to the value of the delay timer.
			s.V[x] = s.DelayTimer
		case 0x0015:
			// FX15	Sets the delay timer to VX.
			s.DelayTimer = s.V[x]

		case 0x0018:
			// FX18	Sets the sound timer to VX.
			s.SoundTimer = s.V[x]

		case 0x001E:
			// FX1E	Adds VX to I.
			// VF is set to 1 when range overflow (I+VX>0xFFF), and 0 when
			// there isn't. This is undocumented feature of the Chip-8 and used
			// by Spacefight 2019! game.
			add := s.I + uint16(s.V[x])
			if add > s.I {
				s.V[0xF] = 0x0
			} else {
				s.V[0xF] = 0x1
			}
			s.I = add

		case 0x0029:
			// FX29	Sets I to the location of the sprite for the character in VX. Characters 0-F (in hexadecimal) are represented by a 4x5 font.
			s.I = 0x50 + uint16(s.V[x])*4 // XXX assuming fontset at the beginning of memory.

		case 0x0033:
			// FX33	Stores the Binary-coded decimal representation of VX, with
			// the most significant of three digits at the address in I, the
			// middle digit at I plus 1, and the least significant digit at I
			// plus 2.
			s.mem[s.I] = byte(s.V[x] / 100 % 10)
			s.mem[s.I+1] = byte(s.V[x] / 10 % 10)
			s.mem[s.I+2] = byte(s.V[x] % 10)

		case 0x0055:
			// FX55	Stores V0 to VX in memory starting at address I.
			// On the original interpreter, when the operation is done, I=I+X+1
			for i, reg := range s.V[0:x] {
				m := s.I + uint16(i)
				s.mem[m] = reg
			}
			s.I = +uint16(x + 1)

		case 0x0065:
			// FX65	Fills V0 to VX with values from memory starting at address I.
			for i := uint16(0); i <= uint16(x); i++ {
				s.V[i] = s.mem[s.I+i]

			}
			/*
				// Debugging.
				for i, b := range s.mem {
					fmt.Printf("%2x ", b)
					if i > 1 && i % 20 == 0 {
						fmt.Printf("\n%x\n", i)
					}
				}
			*/

		default:
			goto NOTIMPLEMENTED
		}

	default:
		goto NOTIMPLEMENTED
	}
	// Common case.
	s.PC += 2
SKIPINC:
	if s.DelayTimer > 0 {
		s.DelayTimer -= 1
	}
	if s.SoundTimer > 0 {
		if s.SoundTimer == 1 {
			log.Println("BEEP!")
		}
		s.SoundTimer -= 1
	}

	if draw {
		s.video.draw(s.gfx)
	}
	return nil
NOTIMPLEMENTED:
	return fmt.Errorf("opcode not implemented: %x", opcode)
}
Exemplo n.º 17
0
// Since go has multiple return values, I just went ahead and made it return the view and perspective matrices (in that order) rather than messing with getter methods
func (c *Camera) ComputeViewPerspective() (mathgl.Mat4f, mathgl.Mat4f) {
	if mathgl.FloatEqual(-1.0, c.time) {
		c.time = glfw.Time()
	}

	currTime := glfw.Time()
	deltaT := currTime - c.time

	xPos, yPos := glfw.MousePos()
	glfw.SetMousePos(width/2.0, height/2.0)

	c.hAngle += mouseSpeed * ((width / 2.0) - float64(xPos))
	c.vAngle += mouseSpeed * ((height / 2.0) - float64(yPos))

	dir := mathgl.Vec3f{
		float32(math.Cos(c.vAngle) * math.Sin(c.hAngle)),
		float32(math.Sin(c.vAngle)),
		float32(math.Cos(c.vAngle) * math.Cos(c.hAngle))}

	right := mathgl.Vec3f{
		float32(math.Sin(c.hAngle - math.Pi/2.0)),
		0.0,
		float32(math.Cos(c.hAngle - math.Pi/2.0))}

	up := right.Cross(dir)

	if glfw.Key(glfw.KeyUp) == glfw.KeyPress || glfw.Key('W') == glfw.KeyPress {
		c.pos = c.pos.Add(dir.Mul(float32(deltaT * speed)))
	}

	if glfw.Key(glfw.KeyDown) == glfw.KeyPress || glfw.Key('S') == glfw.KeyPress {
		c.pos = c.pos.Sub(dir.Mul(float32(deltaT * speed)))
	}

	if glfw.Key(glfw.KeyRight) == glfw.KeyPress || glfw.Key('D') == glfw.KeyPress {
		c.pos = c.pos.Add(right.Mul(float32(deltaT * speed)))
	}

	if glfw.Key(glfw.KeyLeft) == glfw.KeyPress || glfw.Key('A') == glfw.KeyPress {
		c.pos = c.pos.Sub(right.Mul(float32(deltaT * speed)))
	}

	// Adding to the original tutorial, Space goes up
	if glfw.Key(glfw.KeySpace) == glfw.KeyPress {
		c.pos = c.pos.Add(up.Mul(float32(deltaT * speed)))
	}

	// Adding to the original tutorial, left control goes down
	if glfw.Key(glfw.KeyLctrl) == glfw.KeyPress {
		c.pos = c.pos.Sub(up.Mul(float32(deltaT * speed)))
	}

	fov := initialFOV - 5.0*float64(glfw.MouseWheel())

	proj := mathgl.Perspective(fov, 4.0/3.0, 0.1, 100.0)
	view := mathgl.LookAtV(c.pos, c.pos.Add(dir), up)

	c.time = currTime

	return view, proj
}
Exemplo n.º 18
0
func main() {
	if err := glfw.Init(); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}

	defer glfw.Terminate()

	glfw.OpenWindowHint(glfw.FsaaSamples, 4)
	glfw.OpenWindowHint(glfw.OpenGLVersionMajor, 3)
	glfw.OpenWindowHint(glfw.OpenGLVersionMinor, 3)
	glfw.OpenWindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)

	if err := glfw.OpenWindow(1024, 768, 0, 0, 0, 0, 32, 0, glfw.Windowed); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		return
	}

	glfw.SetSwapInterval(0)

	//gl.GlewExperimental(true)
	gl.Init()     // Can't find gl.GLEW_OK or any variation, not sure how to check if this worked
	gl.GetError() // ignore error, since we're telling it to use CoreProfile above, we get "invalid enumerant" (GLError 1280) which freaks the OpenGLSentinel out

	glfw.SetWindowTitle("Tutorial 09")

	glfw.Enable(glfw.StickyKeys)
	glfw.Disable(glfw.MouseCursor) // Not in the original tutorial, but IMO it SHOULD be there
	glfw.SetMousePos(1024.0/2.0, 768.0/2.0)

	gl.ClearColor(0., 0., 0.4, 0.)

	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LESS)

	gl.Enable(gl.CULL_FACE)

	camera := input.NewCamera()

	vertexArray := gl.GenVertexArray()
	defer vertexArray.Delete()
	vertexArray.Bind()

	prog := helper.MakeProgram("StandardShading.vertexshader", "StandardShading.fragmentshader")
	defer prog.Delete()

	matrixID := prog.GetUniformLocation("MVP")
	viewMatrixID := prog.GetUniformLocation("V")
	modelMatrixID := prog.GetUniformLocation("M")

	texture := helper.MakeTextureFromTGA("uvmap.tga") // Had to convert to tga, go-gl is missing the texture method for DDS right now
	defer texture.Delete()
	texSampler := prog.GetUniformLocation("myTextureSampler")

	meshObj := objloader.LoadObject("suzanne.obj")

	indices, indexedVertices, indexedUVs, indexedNormals := indexer.IndexVBO(meshObj.Vertices, meshObj.UVs, meshObj.Normals)

	vertexBuffer := gl.GenBuffer()
	defer vertexBuffer.Delete()
	vertexBuffer.Bind(gl.ARRAY_BUFFER)
	gl.BufferData(gl.ARRAY_BUFFER, len(indexedVertices)*3*4, indexedVertices, gl.STATIC_DRAW)

	uvBuffer := gl.GenBuffer()
	defer uvBuffer.Delete()
	uvBuffer.Bind(gl.ARRAY_BUFFER)
	// And yet, the weird length stuff doesn't seem to matter for UV or normal
	gl.BufferData(gl.ARRAY_BUFFER, len(indexedUVs)*2*4, indexedUVs, gl.STATIC_DRAW)

	normBuffer := gl.GenBuffer()
	defer normBuffer.Delete()
	normBuffer.Bind(gl.ARRAY_BUFFER)
	gl.BufferData(gl.ARRAY_BUFFER, len(indexedNormals)*3*4, indexedNormals, gl.STATIC_DRAW)

	elementBuffer := gl.GenBuffer()
	defer elementBuffer.Delete()
	elementBuffer.Bind(gl.ELEMENT_ARRAY_BUFFER)
	gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(indices)*2, indices, gl.STATIC_DRAW) // NOTE: a GL_UNSIGNED_SHORT is 16-bits

	lightID := prog.GetUniformLocation("LightPosition_worldspace")
	lastTime := glfw.Time()
	nbFrames := 0
	// Equivalent to a do... while
	for ok := true; ok; ok = (glfw.Key(glfw.KeyEsc) != glfw.KeyPress && glfw.WindowParam(glfw.Opened) == gl.TRUE && glfw.Key('Q') != glfw.KeyPress) {

		currTime := glfw.Time()
		nbFrames++
		if currTime-lastTime >= 1.0 {
			fmt.Printf("%f ms/frame\n", 1000.0/float64(nbFrames))
			nbFrames = 0
			lastTime += 1.0
		}

		func() {
			gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

			prog.Use()
			defer gl.ProgramUnuse()

			view, proj := camera.ComputeViewPerspective()
			model := mathgl.Ident4f()

			MVP := proj.Mul4(view).Mul4(model)
			//mvpArray := mvp.AsCMOArray(mathgl.FLOAT32).([16]float32)
			//vArray := view.AsCMOArray(mathgl.FLOAT32).([16]float32)
			//mArray := model.AsCMOArray(mathgl.FLOAT32).([16]float32)

			matrixID.UniformMatrix4fv(false, MVP)
			viewMatrixID.UniformMatrix4fv(false, view)
			modelMatrixID.UniformMatrix4fv(false, model)

			lightID.Uniform3f(4., 4., 4.)

			gl.ActiveTexture(gl.TEXTURE0)
			texture.Bind(gl.TEXTURE_2D)
			defer texture.Unbind(gl.TEXTURE_2D)
			texSampler.Uniform1i(0)

			vertexAttrib := gl.AttribLocation(0)
			vertexAttrib.EnableArray()
			defer vertexAttrib.DisableArray()
			vertexBuffer.Bind(gl.ARRAY_BUFFER)
			defer vertexBuffer.Unbind(gl.ARRAY_BUFFER)
			vertexAttrib.AttribPointer(3, gl.FLOAT, false, 0, nil)

			uvAttrib := gl.AttribLocation(1)
			uvAttrib.EnableArray()
			defer uvAttrib.DisableArray()
			uvBuffer.Bind(gl.ARRAY_BUFFER)
			defer uvBuffer.Unbind(gl.ARRAY_BUFFER)
			uvAttrib.AttribPointer(2, gl.FLOAT, false, 0, nil)

			normAttrib := gl.AttribLocation(2)
			normAttrib.EnableArray()
			defer normAttrib.DisableArray()
			normBuffer.Bind(gl.ARRAY_BUFFER)
			defer normBuffer.Unbind(gl.ARRAY_BUFFER)
			normAttrib.AttribPointer(3, gl.FLOAT, false, 0, nil)

			elementBuffer.Bind(gl.ELEMENT_ARRAY_BUFFER)
			defer elementBuffer.Unbind(gl.ELEMENT_ARRAY_BUFFER)

			gl.DrawElements(gl.TRIANGLES, len(indices), gl.UNSIGNED_SHORT, nil)

			glfw.SwapBuffers()
		}() // Defers unbinds and disables to here, end of the loop
	}

}