Skip to content

Instantly share code, notes, and snippets.

@Grief
Last active July 26, 2017 10:05
Show Gist options
  • Save Grief/93dffffe0aaeba1af75c621c7a20b801 to your computer and use it in GitHub Desktop.
Save Grief/93dffffe0aaeba1af75c621c7a20b801 to your computer and use it in GitHub Desktop.
package main
import (
"github.com/go-gl/gl/v4.5-core/gl"
"github.com/go-gl/glfw/v3.2/glfw"
"github.com/go-gl/mathgl/mgl32"
"golang.org/x/image/draw"
"image"
_ "image/png"
"io"
"os"
p "path"
"runtime"
)
func main() {
StartEngine(func() {
//texture = LoadTexture("square.png") // TEXTURE LOADS HERE WITHOUT AN ISSUE
CreateWindow(WindowCfg{
Init: func() {
var vao uint32
gl.GenVertexArrays(1, &vao)
gl.BindVertexArray(vao)
gl.GenBuffers(1, &vbo)
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
gl.BufferData(gl.ARRAY_BUFFER, len(cubeVertices)*4, gl.Ptr(cubeVertices), gl.STATIC_DRAW)
},
}, func() {
renderCube()
})
texture = LoadTexture("square.png") // TEXTURE LOADED HERE CAUSES BLACK BORDER
program = NewProgram(vertexShader, fragmentShader)
transform = mgl32.Perspective(mgl32.DegToRad(45.0), float32(800)/600, 0.1, 10.0)
transform = transform.Mul4(mgl32.LookAtV(mgl32.Vec3{3, 3, 3}, mgl32.Vec3{0, 0, 0}, mgl32.Vec3{0, 1, 0}))
transform = transform.Mul4(mgl32.HomogRotate3D(float32(2.0), mgl32.Vec3{0, 1, 0}))
transformUniform = gl.GetUniformLocation(program, gl.Str("transform\x00"))
textureUniform = gl.GetUniformLocation(program, gl.Str("tex\x00"))
vertAttrib = uint32(gl.GetAttribLocation(program, gl.Str("vert\x00")))
texCoordAttrib = uint32(gl.GetAttribLocation(program, gl.Str("vertTexCoord\x00")))
})
}
type task struct {
fn func()
notify chan bool
}
type Pipe chan task
type Window struct {
native *glfw.Window
threadContext Pipe
renderHandler func()
}
type WindowCfg struct {
Init func()
}
type file struct {
path string
}
type ReadStream io.Reader
var rootDirectory string
var vbo uint32
var transformUniform int32
var textureUniform int32
var texture uint32
var vertAttrib uint32
var texCoordAttrib uint32
var program uint32
var transform = mgl32.Ident4()
var shareContext *glfw.Window
var mainThreadContext = CreatePipe()
func renderCube() {
gl.ClearColor(0, 0.1, 0, 0)
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
if vbo == 0 {
return
}
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
gl.UseProgram(program)
gl.Enable(gl.DEPTH_TEST)
gl.DepthFunc(gl.LESS)
gl.Uniform1i(textureUniform, 0)
gl.EnableVertexAttribArray(vertAttrib)
gl.EnableVertexAttribArray(texCoordAttrib)
gl.VertexAttribPointer(vertAttrib, 3, gl.FLOAT, false, 5*4, gl.PtrOffset(0))
gl.VertexAttribPointer(texCoordAttrib, 2, gl.FLOAT, false, 5*4, gl.PtrOffset(3*4))
gl.UniformMatrix4fv(transformUniform, 1, false, &transform[0])
gl.ActiveTexture(gl.TEXTURE0)
gl.BindTexture(gl.TEXTURE_2D, texture)
gl.DrawArrays(gl.TRIANGLES, 0, 6*2*3)
}
func runInMainThread(fn func()) {
mainThreadContext.Run(fn, glfw.PostEmptyEvent)
}
func StartEngine(fnLoad func()) {
runtime.LockOSThread()
var err error
if err = glfw.Init(); err != nil {
panic(err)
}
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
glfw.WindowHint(glfw.ContextVersionMajor, 4)
glfw.WindowHint(glfw.ContextVersionMinor, 5)
glfw.WindowHint(glfw.Visible, glfw.False)
shareContext, err = glfw.CreateWindow(100, 100, "", nil, nil)
glfw.WindowHint(glfw.Visible, glfw.True)
shareContext.MakeContextCurrent()
gl.Init()
go func() {
runInMainThread(func() {
fnLoad()
})
}()
for {
mainThreadContext.ExecuteReceivedTasks()
glfw.WaitEvents()
}
glfw.Terminate()
}
func NewProgram(vertexShaderSource, fragmentShaderSource string) uint32 {
vertexShader, fragmentShader := compileShader(vertexShaderSource, gl.VERTEX_SHADER), compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
program := gl.CreateProgram()
gl.AttachShader(program, vertexShader)
gl.AttachShader(program, fragmentShader)
gl.LinkProgram(program)
return program
}
func CreateWindow(cfg WindowCfg, renderHandler func()) Window {
var window Window
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
glfw.WindowHint(glfw.ContextVersionMajor, 4)
glfw.WindowHint(glfw.ContextVersionMinor, 5)
//shareContext.MakeContextCurrent()
nativeWindow, err := glfw.CreateWindow(800, 600, "", nil, shareContext)
if err != nil {
panic(err)
}
window = Window{
native: nativeWindow,
renderHandler: renderHandler,
threadContext: CreatePipe(),
}
go func() {
runtime.LockOSThread()
window.native.MakeContextCurrent()
glfw.SwapInterval(1)
cfg.Init()
for !window.native.ShouldClose() {
window.threadContext.ExecuteReceivedTasks()
window.renderHandler()
window.native.SwapBuffers()
}
}()
return window
}
func compileShader(source string, shaderType uint32) uint32 {
shader := gl.CreateShader(shaderType)
csources, free := gl.Strs(source)
gl.ShaderSource(shader, 1, csources, nil)
free()
gl.CompileShader(shader)
var status int32
gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
return shader
}
func LoadTexture(path ...string) uint32 {
var id uint32
File(path...).Read(func(stream ReadStream) {
img, _, _ := image.Decode(stream)
rgba := image.NewRGBA(img.Bounds())
draw.Draw(rgba, rgba.Bounds(), img, image.Point{0, 0}, draw.Src)
gl.GenTextures(1, &id)
gl.ActiveTexture(gl.TEXTURE0)
gl.BindTexture(gl.TEXTURE_2D, id)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(rgba.Rect.Size().X), int32(rgba.Rect.Size().Y), 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(rgba.Pix))
})
return id
}
func CreatePipe() Pipe {
return make(Pipe, 1)
}
func (p Pipe) Run(fn func(), notify func()) {
resume := make(chan bool)
task := task{fn: fn, notify: resume}
p <- task
if notify != nil {
notify()
}
_ = <-resume
}
func (p Pipe) ExecuteReceivedTasks() {
select {
case task := <-p:
task.fn()
close(task.notify)
default:
}
}
func init() {
ex, err := os.Executable()
if err != nil {
panic(err)
}
rootDirectory = p.Dir(ex)
}
func File(path ...string) file {
return file{path: p.Join(append([]string{rootDirectory}, path...)...)}
}
func (f file) Read(fn func(stream ReadStream)) {
file, err := os.Open(f.path)
if err != nil {
panic(err)
}
fn(file)
defer file.Close()
}
var vertexShader = `
#version 330
uniform mat4 transform;
in vec3 vert;
in vec2 vertTexCoord;
out vec2 fragTexCoord;
void main() {
fragTexCoord = vertTexCoord;
gl_Position = transform * vec4(vert, 1);
}
` + "\x00"
var fragmentShader = `
#version 330
uniform sampler2D tex;
in vec2 fragTexCoord;
out vec4 outputColor;
void main() {
outputColor = texture(tex, fragTexCoord);
}
` + "\x00"
var cubeVertices = []float32{
// X, Y, Z, U, V
// Bottom
-1.0, -1.0, -1.0, 0.0, 0.0,
1.0, -1.0, -1.0, 1.0, 0.0,
-1.0, -1.0, 1.0, 0.0, 1.0,
1.0, -1.0, -1.0, 1.0, 0.0,
1.0, -1.0, 1.0, 1.0, 1.0,
-1.0, -1.0, 1.0, 0.0, 1.0,
// Top
-1.0, 1.0, -1.0, 0.0, 0.0,
-1.0, 1.0, 1.0, 0.0, 1.0,
1.0, 1.0, -1.0, 1.0, 0.0,
1.0, 1.0, -1.0, 1.0, 0.0,
-1.0, 1.0, 1.0, 0.0, 1.0,
1.0, 1.0, 1.0, 1.0, 1.0,
// Front
-1.0, -1.0, 1.0, 1.0, 0.0,
1.0, -1.0, 1.0, 0.0, 0.0,
-1.0, 1.0, 1.0, 1.0, 1.0,
1.0, -1.0, 1.0, 0.0, 0.0,
1.0, 1.0, 1.0, 0.0, 1.0,
-1.0, 1.0, 1.0, 1.0, 1.0,
// Back
-1.0, -1.0, -1.0, 0.0, 0.0,
-1.0, 1.0, -1.0, 0.0, 1.0,
1.0, -1.0, -1.0, 1.0, 0.0,
1.0, -1.0, -1.0, 1.0, 0.0,
-1.0, 1.0, -1.0, 0.0, 1.0,
1.0, 1.0, -1.0, 1.0, 1.0,
// Left
-1.0, -1.0, 1.0, 0.0, 1.0,
-1.0, 1.0, -1.0, 1.0, 0.0,
-1.0, -1.0, -1.0, 0.0, 0.0,
-1.0, -1.0, 1.0, 0.0, 1.0,
-1.0, 1.0, 1.0, 1.0, 1.0,
-1.0, 1.0, -1.0, 1.0, 0.0,
// Right
1.0, -1.0, 1.0, 1.0, 1.0,
1.0, -1.0, -1.0, 1.0, 0.0,
1.0, 1.0, -1.0, 0.0, 0.0,
1.0, -1.0, 1.0, 1.0, 1.0,
1.0, 1.0, -1.0, 0.0, 0.0,
1.0, 1.0, 1.0, 0.0, 1.0,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment