Skip to content

Instantly share code, notes, and snippets.

@hurricanerix
Last active August 29, 2015 14:05
Show Gist options
  • Save hurricanerix/8c6906dc0e0f9431e38f to your computer and use it in GitHub Desktop.
Save hurricanerix/8c6906dc0e0f9431e38f to your computer and use it in GitHub Desktop.
Simple Go app setting up SDL2 & OpenGL.
// The MIT License (MIT)
//
// Copyright (c) 2014 Richard Hawkins
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package main
import (
"fmt"
"github.com/go-gl/gl"
"github.com/veandco/go-sdl2/sdl"
"os"
)
const windowWidth int = 1024
const windowHeight int = 768
const vertSource string = `
#version 330
uniform mat4 model_matrix;
uniform mat4 view_matrix;
uniform mat4 proj_matrix;
in vec4 mc_vertex;
void main()
{
mat4 mv_matrix = view_matrix * model_matrix;
vec4 cc_vertex = mv_matrix * mc_vertex;
gl_Position = proj_matrix * cc_vertex;
}`
const fragSource string = `
#version 330
out vec4 frag_color;
void main()
{
frag_color = vec4(1.0, 0.0, 0.0, 1.0);
}`
var vertices = []float32{
0.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, 1.0,
1.0, 1.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 0.0, 1.0,
1.0, 1.0, 0.0, 1.0}
// Transform the from local coordinates to world coordinates.
func get4x4Transform(scaleX float32, scaleY float32, transX float32, transY float32, transZ float32) [16]float32 {
return [16]float32{
scaleX, 0.0, 0.0, transX,
0.0, scaleY, 0.0, transY,
0.0, 0.0, 1.0, transZ,
0.0, 0.0, 0.0, 1.0}
}
// Create a orthographic projection matrix.
func getProjectionMatrix(left float32, right float32, bottom float32, top float32) [16]float32 {
zNear := -25.0
zFar := 25.0
invZ := 1.0 / (zFar - zNear)
invY := 1.0 / (top - bottom)
invX := 1.0 / (right - left)
return [16]float32{
(2.0 * invX), 0.0, 0.0, (-(right + left) * invX),
0.0, (2.0 * invY), 0.0, (-(top + bottom) * invY),
0.0, 0.0, float32(-2.0 * invZ), float32(-(zFar + zNear) * invZ),
0.0, 0.0, 0.0, 1.0}
}
func getViewMatrix(x float32, y float32) [16]float32 {
scaleX := float32(1.0)
scaleY := float32(1.0)
transX := x
transY := y
transZ := float32(1.0)
return get4x4Transform(scaleX, scaleY, transX, transY, transZ)
}
func checkGLError(name string) {
e := gl.GetError()
if e != gl.NO_ERROR {
fmt.Print(fmt.Sprintf("%s: ", name))
switch e {
case gl.INVALID_VALUE:
fmt.Println("INVALID_VALUE")
case gl.INVALID_ENUM:
fmt.Println("INVALID_ENUM")
case gl.INVALID_OPERATION:
fmt.Println("INVALID_OPERATION")
case gl.INVALID_FRAMEBUFFER_OPERATION:
fmt.Println("INVALID_FRAMEBUFFER_OPERATION")
case gl.OUT_OF_MEMORY:
fmt.Println("OUT_OF_MEMORY")
case gl.STACK_UNDERFLOW:
fmt.Println("STACK_UNDERFLOW")
case gl.STACK_OVERFLOW:
fmt.Println("STACK_OVERFLOW")
default:
fmt.Print(fmt.Sprintf("Unknown(%d)", e))
}
os.Exit(4)
}
}
func main() {
// Init
sdl.Init(sdl.INIT_EVERYTHING)
sdl.GL_SetAttribute(sdl.GL_CONTEXT_MAJOR_VERSION, 3)
sdl.GL_SetAttribute(sdl.GL_CONTEXT_MINOR_VERSION, 2)
sdl.GL_SetAttribute(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_CORE)
sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1)
sdl.GL_SetAttribute(sdl.GL_DEPTH_SIZE, 24)
sdl.GL_SetSwapInterval(1)
window := sdl.CreateWindow("Go/SDL2/OpenGL", sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED, windowWidth, windowHeight, sdl.WINDOW_OPENGL|sdl.WINDOW_SHOWN)
if window == nil {
fmt.Fprintf(os.Stderr, "Error: Could not create window\n")
os.Exit(1)
}
sdl.GL_CreateContext(window)
if gl.Init() != 0 {
fmt.Fprintf(os.Stderr, "Failed to init GL")
os.Exit(1)
}
gl.GetError() // 1280
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
gl.Enable(gl.DEPTH_TEST)
gl.Enable(gl.CULL_FACE)
gl.Enable(gl.BLEND)
gl.ClearColor(0.3, 0.3, 0.3, 1.0)
// Load Shader
attribLocs := map[string]gl.AttribLocation{
"mc_vertex": -1,
}
uniformLocs := map[string]gl.UniformLocation{
"model_matrix": -1,
"view_matrix": -1,
"proj_matrix": -1,
}
vertShader := gl.CreateShader(gl.VERTEX_SHADER)
checkGLError("gl.CreateShader")
vertShader.Source(vertSource)
checkGLError("vertShader.Source")
vertShader.Compile()
checkGLError("vertShader.Compile")
if vertShader.Get(gl.COMPILE_STATUS) != gl.TRUE {
fmt.Fprintf(os.Stderr, fmt.Sprintf("vertex shader error: %s\n", vertShader.GetInfoLog()))
os.Exit(1)
}
fragShader := gl.CreateShader(gl.FRAGMENT_SHADER)
checkGLError("gl.CreateShader")
fragShader.Source(fragSource)
fragShader.Compile()
if fragShader.Get(gl.COMPILE_STATUS) != gl.TRUE {
fmt.Fprintf(os.Stderr, fmt.Sprintf("frag shader error: %s\n", fragShader.GetInfoLog()))
os.Exit(1)
}
shader := gl.CreateProgram()
shader.AttachShader(vertShader)
shader.AttachShader(fragShader)
shader.Link()
if shader.Get(gl.LINK_STATUS) != gl.TRUE {
fmt.Fprintf(os.Stderr, fmt.Sprintf("linker error: %s\n", shader.GetInfoLog()))
os.Exit(1)
}
for k := range attribLocs {
attribLocs[k] = shader.GetAttribLocation(k)
}
for k := range uniformLocs {
uniformLocs[k] = shader.GetUniformLocation(k)
}
// Load Object
vao := gl.GenVertexArray()
checkGLError("gl.GenVertexArray")
vao.Bind()
checkGLError("vao.Bind")
//gl.EnableClientState(gl.VERTEX_ARRAY)
vertexBuffer := gl.GenBuffer()
checkGLError("gl.GenBuffer")
vertexBuffer.Bind(gl.ARRAY_BUFFER)
checkGLError("vertexBuffer.Bind")
gl.BufferData(gl.ARRAY_BUFFER, len(vertices)*4, vertices, gl.STATIC_DRAW)
checkGLError("vertexBuffer.Bind")
//gl.VertexPointer(4, gl.FLOAT, 0, uintptr(0))
attribLocs["mc_vertex"].AttribPointer(4, gl.FLOAT, false, 0, nil)
checkGLError("gl.VertexPointer")
vertexBuffer.Unbind(gl.ARRAY_BUFFER)
checkGLError("vertexBuffer.Unbind")
vao.Unbind()
checkGLError("vao.Unbind")
// Loop
running := true
var event sdl.Event
for running {
for event = sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
switch t := event.(type) {
case *sdl.QuitEvent:
running = false
case *sdl.MouseMotionEvent:
fmt.Printf("[%d ms] MouseMotion\ttype:%d\tid:%d\tx:%d\ty:%d\txrel:%d\tyrel:%d\n", t.Timestamp, t.Type, t.Which, t.X, t.Y, t.XRel, t.YRel)
case *sdl.MouseButtonEvent:
fmt.Printf("[%d ms] MouseButton\ttype:%d\tid:%d\tx:%d\ty:%d\tbutton:%d\tstate:%d\n", t.Timestamp, t.Type, t.Which, t.X, t.Y, t.Button, t.State)
case *sdl.MouseWheelEvent:
fmt.Printf("[%d ms] MouseWheel\ttype:%d\tid:%d\tx:%d\ty:%d\n", t.Timestamp, t.Type, t.Which, t.X, t.Y)
case *sdl.KeyUpEvent:
fmt.Printf("[%d ms] Keyboard\ttype:%d\tsym:%c\tmodifiers:%d\tstate:%d\trepeat:%d\n", t.Timestamp, t.Type, t.Keysym.Sym, t.Keysym.Mod, t.State, t.Repeat)
if t.Keysym.Sym == sdl.K_ESCAPE {
running = false
}
case *sdl.UserEvent:
fmt.Printf("[%d ms] UserEvent\tcode:%d\n", t.Timestamp, t.Code)
}
// Update model_matrix
objectW := float32(100)
objectH := float32(100)
objectX := float32(float32(windowWidth)/2.0 - float32(objectW)/2.0)
objectY := float32(float32(windowHeight)/2.0 - float32(objectH)/2.0)
modelMatrix := get4x4Transform(objectW, objectH, objectX, objectY, 1.0)
// Update proj_matrix
projMatrix := getProjectionMatrix(0.0, float32(windowWidth), 0.0, float32(windowHeight))
// Update view_matrix
viewMatrix := getViewMatrix(1.0, 1.0)
// Start Rendering
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
shader.Use()
checkGLError("shader.Use")
// Draw object
vao.Bind()
checkGLError("vao.Bind")
uniformLocs["model_matrix"].UniformMatrix4fv(true, modelMatrix)
checkGLError("uniformLocs[model_matrix].Uniform4fm")
uniformLocs["view_matrix"].UniformMatrix4fv(true, viewMatrix)
checkGLError("uniformLocs[view_matrix].Uniform4fm")
uniformLocs["proj_matrix"].UniformMatrix4fv(true, projMatrix)
checkGLError("uniformLocs[proj_matrix].Uniform4fm")
attribLocs["mc_vertex"].EnableArray()
checkGLError("attribLocs[mc_vertex].EnableArray")
gl.DrawArrays(gl.TRIANGLES, 0, int(len(vertices)/4))
checkGLError("gl.DrawArrays")
vao.Unbind()
checkGLError("vao.Unbind")
// Stop Rendering
shader.Unuse()
sdl.GL_SwapWindow(window)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment