func programLoop(window *glfw.Window) { // the linked shader program determines how the data will be rendered shaders := compileShaders() shaderProgram := linkShaders(shaders) // VAO contains all the information about the data to be rendered VAO := createTriangleVAO() for !window.ShouldClose() { // poll events and call their registered callbacks glfw.PollEvents() // perform rendering gl.ClearColor(0.2, 0.5, 0.5, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT) // draw loop gl.UseProgram(shaderProgram) // ensure the right shader program is being used gl.BindVertexArray(VAO) // bind data gl.DrawArrays(gl.TRIANGLES, 0, 3) // perform draw call gl.BindVertexArray(0) // unbind data (so we don't mistakenly use/modify it) // end of draw loop // swap in the rendered buffer window.SwapBuffers() } }
func Run() { if err := glfw.Init(); err != nil { glog.Fatalln("failed to initialize glfw", err) } defer glfw.Terminate() setupWindowOptions() window, err := glfw.CreateWindow(WindowWidth, WindowHeight, "Game", nil, nil) if err != nil { panic(err) } window.MakeContextCurrent() //initilize Glow if err := gl.Init(); err != nil { panic(err) } version := gl.GoStr(gl.GetString(gl.VERSION)) fmt.Println("OpenGL version", version) shaderSource, err := ReadShaders("colorShader") if err != nil { panic(err) } program, err := NewProgram(shaderSource) if err != nil { panic(err) } program.Use() sprite := &SpriteComponent{-.5, -.5, 1, 1} sprite.ReloadGraphics() vertAttrib := uint32(gl.GetAttribLocation(program.program, CStr("vertPosition"))) gl.EnableVertexAttribArray(vertAttrib) gl.VertexAttribPointer(vertAttrib, 3, gl.FLOAT, false, 0, gl.PtrOffset(0)) gl.Enable(gl.DEPTH_TEST) gl.DepthFunc(gl.LESS) gl.ClearColor(1.0, 1.0, 1.0, 1.0) for !window.ShouldClose() { gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) program.Use() gl.BindVertexArray(sprite.vaoID) gl.DrawArrays(gl.TRIANGLES, 0, 2*3) window.SwapBuffers() glfw.PollEvents() } }
// New returns a newly created Screen func New(width int, height int, fullscreen bool, FSAA int, name string) *Screen { window := &Screen{} C.SDL_Init(C.SDL_INIT_VIDEO) C.setGlContextAttributes() C.SDL_GL_SetAttribute(C.SDL_GL_DOUBLEBUFFER, 1) // Force hardware accel C.SDL_GL_SetAttribute(C.SDL_GL_ACCELERATED_VISUAL, 1) if FSAA > 0 { // FSAA (Fullscreen antialiasing) C.SDL_GL_SetAttribute(C.SDL_GL_MULTISAMPLEBUFFERS, 1) C.SDL_GL_SetAttribute(C.SDL_GL_MULTISAMPLESAMPLES, C.int(FSAA)) // 2, 4, 8 } flags := C.SDL_WINDOW_OPENGL | C.SDL_RENDERER_ACCELERATED if fullscreen { flags = flags | C.SDL_WINDOW_FULLSCREEN } C.SDL_CreateWindowAndRenderer(C.int(width), C.int(height), C.Uint32(flags), &window.sdlWindow, &window.renderer) C.SDL_SetWindowTitle(window.sdlWindow, C.CString(name)) C.SDL_GL_CreateContext(window.sdlWindow) if err := gl.Init(); err != nil { panic(err) } version := gl.GoStr(gl.GetString(gl.VERSION)) fmt.Println("OpenGL version", version) // Configure global settings gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.ClearColor(0.0, 0.0, 0.0, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) window.Width = width window.Height = height window.name = name window.shouldClose = false C.SDL_GL_SwapWindow(window.sdlWindow) window.startTime = time.Now() window.frameTime = time.Now() C.SDL_GL_SetSwapInterval(1) window.vsync = true return window }
func draw(w *glfw.Window) { //Get the horizontal split size of the window sizex, sizey := w.GetSize() var eyesize mgl32.Vec2 eyesize[0] = float32(sizex / 2.0) eyesize[1] = float32(sizey) gl.Enable(gl.SCISSOR_TEST) gl.Scissor(0, 0, int32(eyesize[0]), int32(eyesize[1])) gl.ClearColor(1, 0, 0, 1) gl.Clear(gl.COLOR_BUFFER_BIT) gl.Scissor(int32(eyesize[0]), 0, int32(eyesize[0]), int32(eyesize[1])) gl.ClearColor(0, 0, 1, 1) gl.Clear(gl.COLOR_BUFFER_BIT) gl.Disable(gl.SCISSOR_TEST) }
func (me *Core) CreateWin(width, height int, name string) { glfw.WindowHint(glfw.ContextVersionMajor, 4) glfw.WindowHint(glfw.ContextVersionMinor, 5) glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True) glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile) glfw.WindowHint(glfw.Samples, 4) // AA4 glfw.WindowHint(glfw.Resizable, glfw.False) win, err := glfw.CreateWindow(width, height, name, nil, nil) if err != nil { panic(err) } me.Win = win win.MakeContextCurrent() gl.ClearColor(1.0, 1.0, 1.0, 1.0) me.ClearOpt = gl.COLOR_BUFFER_BIT }
func makeWindow() *glfw.Window { win, err := glfw.CreateWindow(windowWidth, windowHeight, "Tutorial #1", nil, nil) if err != nil { panic(err) } if err := gl.Init(); err != nil { panic(err) } win.MakeContextCurrent() gl.ClearColor(1.0, 1.0, 1.0, 1.0) return win }
func (r *Renderer) Draw() { /* Clear screen */ gl.ClearColor(0.9, 0.9, 0.9, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) /* Enable blending */ gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) /* Depth test */ gl.Enable(gl.DEPTH_TEST) gl.DepthFunc(gl.LESS) for _, pass := range r.Passes { pass.DrawPass(r.Scene) } }
func initGL() string { // Initialize Glow if err := gl.Init(); err != nil { panic(err) } version := gl.GoStr(gl.GetString(gl.VERSION)) fmt.Println("OpenGL version", version) fmt.Println("OpenGl shading version", gl.GoStr(gl.GetString(gl.SHADING_LANGUAGE_VERSION))) fmt.Println("OpenGl renderer", gl.GoStr(gl.GetString(gl.RENDERER))) // Configure global settings gl.Enable(gl.DEPTH_TEST) gl.DepthFunc(gl.LESS) gl.ClearColor(0.5, 0.5, 0.5, 1.0) return version }
func (screen *Screen) Init(title string, onCloseHandler func(), chip *chip8.Chip8) { var err error screen.chip = chip err = glfw.Init() if err != nil { panic(err) } window, err := glfw.CreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, title, nil, nil) if err != nil { panic(err) } window.MakeContextCurrent() // Initialize Glow if err := gl.Init(); err != nil { panic(err) } version := gl.GoStr(gl.GetString(gl.VERSION)) fmt.Println("OpenGL version", version) gl.ClearColor(255.0, 0.0, 0.0, 0.0) //Set the cleared screen colour to black gl.Viewport(0, 0, int32(SCREEN_WIDTH), int32(SCREEN_HEIGHT)) //This sets up the viewport so that the coordinates (0, 0) are at the top left of the window for !window.ShouldClose() { // Do OpenGL stuff gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) window.SwapBuffers() glfw.PollEvents() } onCloseHandler() }
func main() { if err := glfw.Init(); err != nil { log.Fatalln("failed to inifitialize glfw:", err) } defer glfw.Terminate() glfw.WindowHint(glfw.Resizable, glfw.False) glfw.WindowHint(glfw.ContextVersionMajor, 4) glfw.WindowHint(glfw.ContextVersionMinor, 1) glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile) glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True) window, err := glfw.CreateWindow(windowWidth, windowHeight, "Hello!", nil, nil) if err != nil { panic(err) } window.MakeContextCurrent() // Initialize Glow (go function bindings) if err := gl.Init(); err != nil { panic(err) } window.SetKeyCallback(keyCallback) // program loop for !window.ShouldClose() { // poll events and call their registered callbacks glfw.PollEvents() // perform rendering gl.ClearColor(0.2, 0.5, 0.5, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT) // swap in the rendered buffer window.SwapBuffers() } }
func programLoop(window *win.Window) error { // the linked shader program determines how the data will be rendered vertShader, err := gfx.NewShaderFromFile("shaders/phong.vert", gl.VERTEX_SHADER) if err != nil { return err } fragShader, err := gfx.NewShaderFromFile("shaders/phong.frag", gl.FRAGMENT_SHADER) if err != nil { return err } program, err := gfx.NewProgram(vertShader, fragShader) if err != nil { return err } defer program.Delete() lightFragShader, err := gfx.NewShaderFromFile("shaders/light.frag", gl.FRAGMENT_SHADER) if err != nil { return err } // special shader program so that lights themselves are not affected by lighting lightProgram, err := gfx.NewProgram(vertShader, lightFragShader) if err != nil { return err } VAO := createVAO(cubeVertices, nil) lightVAO := createVAO(cubeVertices, nil) // ensure that triangles that are "behind" others do not draw over top of them gl.Enable(gl.DEPTH_TEST) camera := cam.NewFpsCamera(mgl32.Vec3{0, 0, 3}, mgl32.Vec3{0, 1, 0}, -90, 0, window.InputManager()) for !window.ShouldClose() { // swaps in last buffer, polls for window events, and generally sets up for a new render frame window.StartFrame() // update camera position and direction from input evevnts camera.Update(window.SinceLastFrame()) // background color gl.ClearColor(0, 0, 0, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) // depth buffer needed for DEPTH_TEST // cube rotation matrices rotateX := (mgl32.Rotate3DX(mgl32.DegToRad(-45 * float32(glfw.GetTime())))) rotateY := (mgl32.Rotate3DY(mgl32.DegToRad(-45 * float32(glfw.GetTime())))) rotateZ := (mgl32.Rotate3DZ(mgl32.DegToRad(-45 * float32(glfw.GetTime())))) // creates perspective fov := float32(60.0) projectTransform := mgl32.Perspective(mgl32.DegToRad(fov), float32(window.Width())/float32(window.Height()), 0.1, 100.0) camTransform := camera.GetTransform() lightPos := mgl32.Vec3{0.6, 1, 0.1} lightTransform := mgl32.Translate3D(lightPos.X(), lightPos.Y(), lightPos.Z()).Mul4( mgl32.Scale3D(0.2, 0.2, 0.2)) program.Use() gl.UniformMatrix4fv(program.GetUniformLocation("view"), 1, false, &camTransform[0]) gl.UniformMatrix4fv(program.GetUniformLocation("project"), 1, false, &projectTransform[0]) gl.BindVertexArray(VAO) // draw each cube after all coordinate system transforms are bound // obj is colored, light is white gl.Uniform3f(program.GetUniformLocation("material.ambient"), 1.0, 0.5, 0.31) gl.Uniform3f(program.GetUniformLocation("material.diffuse"), 1.0, 0.5, 0.31) gl.Uniform3f(program.GetUniformLocation("material.specular"), 0.5, 0.5, 0.5) gl.Uniform1f(program.GetUniformLocation("material.shininess"), 32.0) lightColor := mgl32.Vec3{ float32(math.Sin(glfw.GetTime() * 1)), float32(math.Sin(glfw.GetTime() * 0.35)), float32(math.Sin(glfw.GetTime() * 0.65)), } diffuseColor := mgl32.Vec3{ 0.5 * lightColor[0], 0.5 * lightColor[1], 0.5 * lightColor[2], } ambientColor := mgl32.Vec3{ 0.2 * lightColor[0], 0.2 * lightColor[1], 0.2 * lightColor[2], } gl.Uniform3f(program.GetUniformLocation("light.ambient"), ambientColor[0], ambientColor[1], ambientColor[2]) gl.Uniform3f(program.GetUniformLocation("light.diffuse"), diffuseColor[0], diffuseColor[1], diffuseColor[2]) gl.Uniform3f(program.GetUniformLocation("light.specular"), 1.0, 1.0, 1.0) gl.Uniform3f(program.GetUniformLocation("light.position"), lightPos.X(), lightPos.Y(), lightPos.Z()) for _, pos := range cubePositions { // turn the cubes into rectangular prisms for more fun worldTranslate := mgl32.Translate3D(pos[0], pos[1], pos[2]) worldTransform := worldTranslate.Mul4( rotateX.Mul3(rotateY).Mul3(rotateZ).Mat4(), ) gl.UniformMatrix4fv(program.GetUniformLocation("model"), 1, false, &worldTransform[0]) gl.DrawArrays(gl.TRIANGLES, 0, 36) } gl.BindVertexArray(0) // Draw the light obj after the other boxes using its separate shader program // this means that we must re-bind any uniforms lightProgram.Use() gl.BindVertexArray(lightVAO) gl.UniformMatrix4fv(lightProgram.GetUniformLocation("model"), 1, false, &lightTransform[0]) gl.UniformMatrix4fv(lightProgram.GetUniformLocation("view"), 1, false, &camTransform[0]) gl.UniformMatrix4fv(lightProgram.GetUniformLocation("project"), 1, false, &projectTransform[0]) gl.DrawArrays(gl.TRIANGLES, 0, 36) gl.BindVertexArray(0) // end of draw loop } return nil }
func programLoop(window *glfw.Window) error { // the linked shader program determines how the data will be rendered vertShader, err := gfx.NewShaderFromFile("shaders/basic.vert", gl.VERTEX_SHADER) if err != nil { return err } fragShader, err := gfx.NewShaderFromFile("shaders/basic.frag", gl.FRAGMENT_SHADER) if err != nil { return err } program, err := gfx.NewProgram(vertShader, fragShader) if err != nil { return err } defer program.Delete() vertices := []float32{ // position // texture position -0.5, -0.5, -0.5, 0.0, 0.0, 0.5, -0.5, -0.5, 1.0, 0.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5, 0.5, -0.5, 1.0, 1.0, -0.5, 0.5, -0.5, 0.0, 1.0, -0.5, -0.5, -0.5, 0.0, 0.0, -0.5, -0.5, 0.5, 0.0, 0.0, 0.5, -0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 1.0, 0.5, 0.5, 0.5, 1.0, 1.0, -0.5, 0.5, 0.5, 0.0, 1.0, -0.5, -0.5, 0.5, 0.0, 0.0, -0.5, 0.5, 0.5, 1.0, 0.0, -0.5, 0.5, -0.5, 1.0, 1.0, -0.5, -0.5, -0.5, 0.0, 1.0, -0.5, -0.5, -0.5, 0.0, 1.0, -0.5, -0.5, 0.5, 0.0, 0.0, -0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, 0.5, 0.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, -0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, -0.5, 1.0, 1.0, 0.5, -0.5, 0.5, 1.0, 0.0, 0.5, -0.5, 0.5, 1.0, 0.0, -0.5, -0.5, 0.5, 0.0, 0.0, -0.5, -0.5, -0.5, 0.0, 1.0, -0.5, 0.5, -0.5, 0.0, 1.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, -0.5, 0.5, 0.5, 0.0, 0.0, -0.5, 0.5, -0.5, 0.0, 1.0, } indices := []uint32{} VAO := createVAO(vertices, indices) texture0, err := gfx.NewTextureFromFile("../images/RTS_Crate.png", gl.CLAMP_TO_EDGE, gl.CLAMP_TO_EDGE) if err != nil { panic(err.Error()) } texture1, err := gfx.NewTextureFromFile("../images/trollface-transparent.png", gl.CLAMP_TO_EDGE, gl.CLAMP_TO_EDGE) if err != nil { panic(err.Error()) } cubePositions := [][]float32{ []float32{0.0, 0.0, -3.0}, []float32{2.0, 5.0, -15.0}, []float32{-1.5, -2.2, -2.5}, []float32{-3.8, -2.0, -12.3}, []float32{2.4, -0.4, -3.5}, []float32{-1.7, 3.0, -7.5}, []float32{1.3, -2.0, -2.5}, []float32{1.5, 2.0, -2.5}, []float32{1.5, 0.2, -1.5}, []float32{-1.3, 1.0, -1.5}, } gl.Enable(gl.DEPTH_TEST) for !window.ShouldClose() { // poll events and call their registered callbacks glfw.PollEvents() // background color gl.ClearColor(0.2, 0.5, 0.5, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) // draw vertices program.Use() // set texture0 to uniform0 in the fragment shader texture0.Bind(gl.TEXTURE0) texture0.SetUniform(program.GetUniformLocation("ourTexture0")) // set texture1 to uniform1 in the fragment shader texture1.Bind(gl.TEXTURE1) texture1.SetUniform(program.GetUniformLocation("ourTexture1")) // update shader transform matrices // Create transformation matrices rotateX := (mgl32.Rotate3DX(mgl32.DegToRad(-60 * float32(glfw.GetTime())))) rotateY := (mgl32.Rotate3DY(mgl32.DegToRad(-60 * float32(glfw.GetTime())))) rotateZ := (mgl32.Rotate3DZ(mgl32.DegToRad(-60 * float32(glfw.GetTime())))) viewTransform := mgl32.Translate3D(0, 0, -3) projectTransform := mgl32.Perspective(mgl32.DegToRad(60), windowWidth/windowHeight, 0.1, 100.0) gl.UniformMatrix4fv(program.GetUniformLocation("view"), 1, false, &viewTransform[0]) gl.UniformMatrix4fv(program.GetUniformLocation("project"), 1, false, &projectTransform[0]) gl.UniformMatrix4fv(program.GetUniformLocation("worldRotateX"), 1, false, &rotateX[0]) gl.UniformMatrix4fv(program.GetUniformLocation("worldRotateY"), 1, false, &rotateY[0]) gl.UniformMatrix4fv(program.GetUniformLocation("worldRotateZ"), 1, false, &rotateZ[0]) gl.BindVertexArray(VAO) for _, pos := range cubePositions { worldTranslate := mgl32.Translate3D(pos[0], pos[1], pos[2]) worldTransform := (worldTranslate.Mul4(rotateX.Mul3(rotateY).Mul3(rotateZ).Mat4())) gl.UniformMatrix4fv(program.GetUniformLocation("world"), 1, false, &worldTransform[0]) gl.DrawArrays(gl.TRIANGLES, 0, 36) } // gl.DrawElements(gl.TRIANGLES, 36, gl.UNSIGNED_INT, unsafe.Pointer(nil)) gl.BindVertexArray(0) texture0.UnBind() texture1.UnBind() // end of draw loop // swap in the rendered buffer window.SwapBuffers() } return nil }
// SetClearColor sets the color when the screen is cleared for redrawing func (window *Screen) SetClearColor(r float32, g float32, b float32, a float32) { gl.ClearColor(r, g, b, a) }
func main() { if err := glfw.Init(); err != nil { log.Fatalln("failed to initialize glfw:", err) } defer glfw.Terminate() glfw.WindowHint(glfw.Resizable, glfw.False) glfw.WindowHint(glfw.ContextVersionMajor, 4) glfw.WindowHint(glfw.ContextVersionMinor, 1) glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile) glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True) window, err := glfw.CreateWindow(windowWidth, windowHeight, "Cube", nil, nil) if err != nil { panic(err) } window.MakeContextCurrent() // Initialize Glow if err := gl.Init(); err != nil { panic(err) } version := gl.GoStr(gl.GetString(gl.VERSION)) fmt.Println("OpenGL version", version) // Configure the vertex and fragment shaders program, err := newProgram(vertexShader, fragmentShader) if err != nil { panic(err) } gl.UseProgram(program) projection := mgl32.Perspective(mgl32.DegToRad(45.0), float32(windowWidth)/windowHeight, 0.1, 10.0) projectionUniform := gl.GetUniformLocation(program, gl.Str("projection\x00")) gl.UniformMatrix4fv(projectionUniform, 1, false, &projection[0]) camera := mgl32.LookAtV(mgl32.Vec3{3, 3, 3}, mgl32.Vec3{0, 0, 0}, mgl32.Vec3{0, 1, 0}) cameraUniform := gl.GetUniformLocation(program, gl.Str("camera\x00")) gl.UniformMatrix4fv(cameraUniform, 1, false, &camera[0]) model := mgl32.Ident4() modelUniform := gl.GetUniformLocation(program, gl.Str("model\x00")) gl.UniformMatrix4fv(modelUniform, 1, false, &model[0]) textureUniform := gl.GetUniformLocation(program, gl.Str("tex\x00")) gl.Uniform1i(textureUniform, 0) gl.BindFragDataLocation(program, 0, gl.Str("outputColor\x00")) // Load the texture texture, err := newTexture("square.png") if err != nil { panic(err) } // Configure the vertex data var vao uint32 gl.GenVertexArrays(1, &vao) gl.BindVertexArray(vao) var vbo uint32 gl.GenBuffers(1, &vbo) gl.BindBuffer(gl.ARRAY_BUFFER, vbo) gl.BufferData(gl.ARRAY_BUFFER, len(cubeVertices)*4, gl.Ptr(cubeVertices), gl.STATIC_DRAW) vertAttrib := uint32(gl.GetAttribLocation(program, gl.Str("vert\x00"))) gl.EnableVertexAttribArray(vertAttrib) gl.VertexAttribPointer(vertAttrib, 3, gl.FLOAT, false, 5*4, gl.PtrOffset(0)) texCoordAttrib := uint32(gl.GetAttribLocation(program, gl.Str("vertTexCoord\x00"))) gl.EnableVertexAttribArray(texCoordAttrib) gl.VertexAttribPointer(texCoordAttrib, 2, gl.FLOAT, false, 5*4, gl.PtrOffset(3*4)) // Configure global settings gl.Enable(gl.DEPTH_TEST) gl.DepthFunc(gl.LESS) gl.ClearColor(1.0, 1.0, 1.0, 1.0) angle := 0.0 previousTime := glfw.GetTime() for !window.ShouldClose() { gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) // Update time := glfw.GetTime() elapsed := time - previousTime previousTime = time angle += elapsed model = mgl32.HomogRotate3D(float32(angle), mgl32.Vec3{0, 1, 0}) // Render gl.UseProgram(program) gl.UniformMatrix4fv(modelUniform, 1, false, &model[0]) gl.BindVertexArray(vao) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, texture) gl.DrawArrays(gl.TRIANGLES, 0, 6*2*3) // Maintenance window.SwapBuffers() glfw.PollEvents() } }
func main() { var parser = flags.NewParser(&gOpts, flags.Default) var err error var args []string if args, err = parser.Parse(); err != nil { os.Exit(1) } if len(args) < 1 || len(args) > 2 { panic(fmt.Errorf("Too many or not enough arguments")) } gDiffFlag = len(args) == 2 // make sure that we display any errors that are encountered //glfw.SetErrorCallback(errorCallback) // the GLFW library has to be initialized before any of the methods // can be invoked if err = glfw.Init(); err != nil { panic(err) } // to be tidy, make sure glfw.Terminate() is called at the end of // the program to clean things up by using `defer` defer glfw.Terminate() // hints are the way you configure the features requested for the // window and are required to be set before calling glfw.CreateWindow(). // desired number of samples to use for mulitsampling //glfw.WindowHint(glfw.Samples, 4) // request a OpenGL 4.1 core context if runtime.GOOS == "darwin" { glfw.WindowHint(glfw.ContextVersionMajor, 3) glfw.WindowHint(glfw.ContextVersionMinor, 3) } else { glfw.WindowHint(glfw.ContextVersionMajor, 4) glfw.WindowHint(glfw.ContextVersionMinor, 1) } glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True) glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile) // do the actual window creation var window *glfw.Window window, err = glfw.CreateWindow(1024, 768, "goicmpgl", nil, nil) if err != nil { // we legitimately cannot recover from a failure to create // the window in this sample, so just bail out panic(err) } // set the callback function to get all of the key input from the user window.SetKeyCallback(keyCallback) window.SetMouseButtonCallback(mouseDownCallback) window.SetScrollCallback(mouseWheelCallback) window.SetCursorPosCallback(mouseMoveCallback) // GLFW3 can work with more than one window, so make sure we set our // new window as the current context to operate on window.MakeContextCurrent() // disable v-sync for max FPS if the driver allows it //glfw.SwapInterval(0) // make sure that GLEW initializes all of the GL functions if err = gl.Init(); err != nil { panic(err) } var attribs []string = []string{ "position", "uvs", } // compile our shaders var progTex0 *Program if progTex0, err = LoadShaderProgram(vertShader, fragShaderTex0, attribs); err != nil { panic(err) } defer progTex0.DeleteProgram() var progGrid *Program if progGrid, err = LoadShaderProgram(vertShader, S_FragmentShader_Grid, attribs); err != nil { panic(err) } defer progGrid.DeleteProgram() var diffProg2 *Program if diffProg2, err = LoadShaderProgram(vertShader, sProgram2Src, attribs); err != nil { panic(err) } defer diffProg2.DeleteProgram() var diffProg3 *Program if diffProg3, err = LoadShaderProgram(vertShader, sProgram3Src, attribs); err != nil { panic(err) } defer diffProg3.DeleteProgram() var diffProg4 *Program if diffProg4, err = LoadShaderProgram(vertShader, sProgram4Src, attribs); err != nil { panic(err) } defer diffProg4.DeleteProgram() var diffProg5 *Program if diffProg5, err = LoadShaderProgram(vertShader, sProgram5Src, attribs); err != nil { panic(err) } defer diffProg5.DeleteProgram() var image1_path string = args[0] if strings.HasPrefix(image1_path, "http") { if err, image1_path = downloadImage(image1_path); err != nil { panic(err) } } var texture *Texture if err, texture, gImage1 = NewTexture(image1_path, false); err != nil { panic(err) } defer texture.DeleteTexture() var texture2 *Texture if gDiffFlag { var image2_path string = args[1] if strings.HasPrefix(image2_path, "http") { if err, image2_path = downloadImage(image2_path); err != nil { panic(err) } } if err, texture2, gImage2 = NewTexture(image2_path, false); err != nil { panic(err) } defer texture2.DeleteTexture() if texture.Size.X != texture2.Size.X || texture.Size.Y != texture2.Size.Y { fmt.Println("WARNING: image dimensions differ!") } else { fmt.Printf("image dimensions: %dx%d\n", texture.Size.X, texture.Size.Y) } } else { fmt.Printf("image dimensions: %dx%d\n", texture.Size.X, texture.Size.Y) } var font *Font if err, font = NewFont("Font.png", 16); err != nil { panic(err) } defer font.DeleteFont() var help1 *String = font.NewString("1: show only A") defer help1.DeleteString() var help2 *String = font.NewString("2: show only B") defer help2.DeleteString() var help3 *String = font.NewString("3: show diff A&B") defer help3.DeleteString() var helph *String = font.NewString("h: toggle this help") defer helph.DeleteString() var helparrows *String = font.NewString("<up>,<down>: go from A to B") defer helparrows.DeleteString() var helpzoom *String = font.NewString("[]: zoom in/out (also mouse wheel)") defer helpzoom.DeleteString() var helpclear *String = font.NewString("Z: reset zoom/view") defer helpclear.DeleteString() var helpescape *String = font.NewString("ESC: quit") defer helpescape.DeleteString() var vbo *VBO if vbo, err = NewVBOQuad(0, 0, float32(texture.Size.X), float32(texture.Size.Y)); err != nil { panic(err) } defer vbo.DeleteVBO() var cnt float32 = 0 // while there's no request to close the window for !window.ShouldClose() { cnt += 1 // get the texture of the window because it may have changed since creation width, height := window.GetFramebufferSize() wwidth, _ := window.GetSize() gRetinaScale = float32(width) / float32(wwidth) //fmt.Printf("x=%d y=%d wx=%d wy=%d\n", width, height, wwidth, wheight) if cnt >= float32(width) { cnt = 0 } var matrix Matrix2x3 = IdentityMatrix2x3() matrix = matrix.Translate(-1.0, 1.0) matrix = matrix.Scale(2.0/float32(width), -2.0/float32(height)) // clear it all out gl.Viewport(0, 0, int32(width), int32(height)) gl.ClearColor(0.0, 0.0, 0.0, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) gl.Enable(gl.BLEND) gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) gl.BlendEquation(gl.FUNC_ADD) var matrix3 Matrix2x3 = matrix.Scale(gZoom, gZoom) matrix3 = matrix3.Translate(gOffX, gOffY) // draw the grid if true { vbo.Bind() progGrid.UseProgram() color1 := [4]float32{.4, .4, .4, 1} color2 := [4]float32{.9, .9, .9, 1} grid := [3]float32{float32(texture.Size.X), float32(texture.Size.Y), 8 / gZoom} //fmt.Printf("%.2f %.2f %.2f %.2f\n", grid[0], grid[1], grid[2], grid[3]) progGrid.ProgramUniformMatrix4fv("ModelviewMatrix", matrix3.Array()) progGrid.ProgramUniform4fv("color1", color1) progGrid.ProgramUniform4fv("color2", color2) progGrid.ProgramUniform3fv("grid", grid) if err = progGrid.ValidateProgram(); err != nil { panic(err) } vbo.Draw() vbo.Unbind() progGrid.UnuseProgram() } // draw the texture if !gDiffFlag { vbo.Bind() progTex0.UseProgram() texture.BindTexture(0) progTex0.ProgramUniformMatrix4fv("ModelviewMatrix", matrix3.Array()) progTex0.ProgramUniform1i("tex1", 0) progTex0.ProgramUniform1f("blend", gBlend) if err = progTex0.ValidateProgram(); err != nil { panic(err) } vbo.Draw() vbo.Unbind() progTex0.UnuseProgram() texture.UnbindTexture(0) } else { var diffBlend float32 = gBlend var diffProg *Program if diffBlend < 0.25 { diffBlend *= 4 diffProg = diffProg2 } else if diffBlend < 0.5 { // 0.25 -> 0.5 diffBlend = 4*diffBlend - 1 diffProg = diffProg4 } else if diffBlend < 0.75 { // 0.5 -> 0.75 diffBlend = 4*diffBlend - 2 diffProg = diffProg5 } else { // 0.75 -> 1.0= diffBlend = 4*diffBlend - 3 diffProg = diffProg3 } vbo.Bind() diffProg.UseProgram() texture.BindTexture(0) texture2.BindTexture(1) diffProg.ProgramUniformMatrix4fv("ModelviewMatrix", matrix3.Array()) diffProg.ProgramUniform1i("decalA", 0) diffProg.ProgramUniform1i("decalB", 1) diffProg.ProgramUniform1f("diffBlend", diffBlend) if err = diffProg.ValidateProgram(); err != nil { panic(err) } vbo.Draw() vbo.Unbind() diffProg.UnuseProgram() texture.UnbindTexture(0) texture2.UnbindTexture(1) } // font if gHelp { color := [...]float32{0, 0, 1, 1} bg := [...]float32{0.5, 0.5, 0.5, 0.5} var line float32 = 0 if err = helph.Draw(font, color, bg, matrix, 0.5, 20, 100+line*128); err != nil { panic(err) } line += 1 help1.Draw(font, color, bg, matrix, 0.5, 20, 100+line*128) line += 1 help2.Draw(font, color, bg, matrix, 0.5, 20, 100+line*128) line += 1 help3.Draw(font, color, bg, matrix, 0.5, 20, 100+line*128) line += 1 helparrows.Draw(font, color, bg, matrix, 0.5, 20, 100+line*128) line += 1 helpzoom.Draw(font, color, bg, matrix, 0.5, 20, 100+line*128) line += 1 helpclear.Draw(font, color, bg, matrix, 0.5, 20, 100+line*128) line += 1 helpescape.Draw(font, color, bg, matrix, 0.5, 20, 100+line*128) line += 1 } // swapping OpenGL buffers and polling events has been decoupled // in GLFW3, so make sure to invoke both here window.SwapBuffers() glfw.PollEvents() } }
// BackGroundColor - set background color for the scene func (glRenderer *OpenglRenderer) BackGroundColor(r, g, b, a float32) { gl.ClearColor(r, g, b, a) }
/* Clear the frame buffer. Make sure its bound first */ func (f *FrameBuffer) Clear() { gl.ClearColor(f.ClearColor.R, f.ClearColor.G, f.ClearColor.B, f.ClearColor.A) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); }
func (p *LightPass) DrawPass(scene *Scene) { /* use light pass shader */ p.Material.Use() shader := p.Material.Shader /* compute camera view projection inverse */ vp := scene.Camera.Projection.Mul4(scene.Camera.View) vp_inv := vp.Inv() shader.Matrix4f("cameraInverse", &vp_inv[0]) /* clear */ gl.ClearColor(0.9, 0.9, 0.9, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) /* set blending mode to additive */ gl.DepthMask(false) /* draw lights */ lights := scene.FindLights() last := len(lights) - 1 for i, light := range lights { if i == 1 { /* first light pass we want the shader to restore the depth buffer * then, disable depth masking so that multiple lights can be drawn */ gl.BlendFunc(gl.ONE, gl.ONE) } if i == last { gl.DepthMask(true) } /* draw shadow pass for this light into shadow map */ p.Shadows.DrawPass(scene, &light) /* use light pass shader */ p.Material.Use() /* compute world to lightspace (light view projection) matrix */ lp := light.Projection lv := mgl.LookAtV(light.Position, mgl.Vec3{}, mgl.Vec3{0, 1, 0}) // only for directional light lvp := lp.Mul4(lv) shader.Matrix4f("light_vp", &lvp[0]) /* set light uniform attributes */ shader.Vec3("light.Position", &light.Position) shader.Vec3("light.Color", &light.Color) shader.Int32("light.Type", int32(light.Type)) shader.Float("light.Range", light.Range) shader.Float("light.attenuation.Constant", light.Attenuation.Constant) shader.Float("light.attenuation.Linear", light.Attenuation.Linear) shader.Float("light.attenuation.Quadratic", light.Attenuation.Quadratic) /* render light */ gl.Viewport(0, 0, int32(scene.Camera.Width), int32(scene.Camera.Height)) p.quad.Draw() } /* reset GL state */ gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) }
func Main() { err := glfw.Init() if err != nil { panic(err) } defer glfw.Terminate() glfw.WindowHint(glfw.Resizable, glfw.False) glfw.WindowHint(glfw.ContextVersionMajor, 3) glfw.WindowHint(glfw.ContextVersionMinor, 2) glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile) glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True) window, err := glfw.CreateWindow(WindowWidth, WindowHeight, "Cube", nil, nil) Window = window if err != nil { panic(err) } window.MakeContextCurrent() // Initialize Glow if err := gl.Init(); err != nil { panic(err) } version := gl.GoStr(gl.GetString(gl.VERSION)) fmt.Println("OpenGL version", version) // Configure the vertex and fragment shaders program, err := newProgram("SimpleVertexShader.vertexshader", "SimpleFragmentShader.fragmentshader") if err != nil { panic(err) } gl.UseProgram(program) projection := mgl32.Perspective(mgl32.DegToRad(45.0), float32(WindowWidth)/WindowHeight, 0.1, 10.0) projectionUniform := gl.GetUniformLocation(program, gl.Str("projection\x00")) gl.UniformMatrix4fv(projectionUniform, 1, false, &projection[0]) camera := mgl32.LookAtV(mgl32.Vec3{3, 3, 3}, mgl32.Vec3{0, 0, 0}, mgl32.Vec3{0, 1, 0}) cameraUniform := gl.GetUniformLocation(program, gl.Str("camera\x00")) gl.UniformMatrix4fv(cameraUniform, 1, false, &camera[0]) model := mgl32.Ident4() modelUniform := gl.GetUniformLocation(program, gl.Str("model\x00")) gl.UniformMatrix4fv(modelUniform, 1, false, &model[0]) textureUniform := gl.GetUniformLocation(program, gl.Str("tex\x00")) gl.Uniform1i(textureUniform, 0) gl.BindFragDataLocation(program, 0, gl.Str("outputColor\x00")) // Configure global settings gl.Enable(gl.DEPTH_TEST) gl.DepthFunc(gl.LESS) gl.ClearColor(1.0, 1.0, 1.0, 1.0) angle := 0.0 previousTime := glfw.GetTime() width, height := window.GetSize() window.SetCursorPos(float64(width/2), float64(height/2)) window.SetKeyCallback(input.OnKey) window.SetCursorPosCallback(input.OnCursor) window.SetMouseButtonCallback(input.OnMouse) meshes.LoadColladaCube("cube.dae") for !player.ShouldClose { gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) // Update time := glfw.GetTime() elapsed := time - previousTime previousTime = time angle += elapsed model = mgl32.HomogRotate3D(float32(angle), mgl32.Vec3{0, 1, 0}) // Render gl.UseProgram(program) // gl.UniformMatrix4fv(modelUniform, 1, false, &model[0]) player.MainPlayer.Draw(program) for _, element := range game.Universe { (element).Draw(program) } // Maintenance window.SwapBuffers() glfw.PollEvents() } }
func (context *Context) SetBackgroundColor(color *Colorf) { gl.ClearColor(color[0], color[1], color[2], color[3]) }
func programLoop(window *glfw.Window) { // the linked shader program determines how the data will be rendered vertexShader := compileShader(vertexShaderSource, gl.VERTEX_SHADER) fragmentShaderBlue := compileShader(fragmentShaderBlueSource, gl.FRAGMENT_SHADER) shaderProgramBlue := linkShaders([]uint32{vertexShader, fragmentShaderBlue}) fragmentShaderRed := compileShader(fragmentShaderRedSource, gl.FRAGMENT_SHADER) shaderProgramRed := linkShaders([]uint32{vertexShader, fragmentShaderRed}) // shader objects are not needed after they are linked into a program object gl.DeleteShader(vertexShader) gl.DeleteShader(fragmentShaderBlue) gl.DeleteShader(fragmentShaderRed) vertices1 := []float32{ 0.2, 0.2, 0.0, // top right 0.2, -0.8, 0.0, // bottom right -0.8, -0.8, 0.0, // bottom left -0.8, 0.2, 0.0, // top left } indices1 := []uint32{ 0, 1, 3, // first triangle 1, 2, 3, // second triangle } VAO1 := createTriangleVAO(vertices1, indices1) vertices2 := []float32{ 0.2, 0.6, 0.0, // top 0.6, -0.2, 0.0, // bottom right -0.2, -0.2, 0.0, // bottom left } indices2 := []uint32{ 0, 1, 2, // only triangle } VAO2 := createTriangleVAO(vertices2, indices2) for !window.ShouldClose() { // poll events and call their registered callbacks glfw.PollEvents() // perform rendering gl.ClearColor(0.2, 0.5, 0.5, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT) // draw loop // draw rectangle gl.PolygonMode(gl.FRONT_AND_BACK, gl.LINE) gl.UseProgram(shaderProgramRed) gl.BindVertexArray(VAO1) gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, unsafe.Pointer(nil)) gl.BindVertexArray(0) // draw triangle gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL) gl.UseProgram(shaderProgramBlue) gl.BindVertexArray(VAO2) gl.DrawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, unsafe.Pointer(nil)) gl.BindVertexArray(0) // end of draw loop // swap in the rendered buffer window.SwapBuffers() } }
func programLoop(window *glfw.Window) error { // the linked shader program determines how the data will be rendered vertShader, err := gfx.NewShaderFromFile("shaders/basic.vert", gl.VERTEX_SHADER) if err != nil { return err } fragShader, err := gfx.NewShaderFromFile("shaders/basic.frag", gl.FRAGMENT_SHADER) if err != nil { return err } shaderProgram, err := gfx.NewProgram(vertShader, fragShader) if err != nil { return err } defer shaderProgram.Delete() vertices := []float32{ // top 0.0, 0.5, 0.0, // position 1.0, 0.0, 0.0, // Color // bottom right 0.5, -0.5, 0.0, 0.0, 1.0, 0.0, // bottom left -0.5, -0.5, 0.0, 0.0, 0.0, 1.0, } indices := []uint32{ 0, 1, 2, // only triangle } VAO := createTriangleVAO(vertices, indices) for !window.ShouldClose() { // poll events and call their registered callbacks glfw.PollEvents() // perform rendering gl.ClearColor(0.2, 0.5, 0.5, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT) // draw loop // draw triangle shaderProgram.Use() gl.BindVertexArray(VAO) gl.DrawElements(gl.TRIANGLES, 3, gl.UNSIGNED_INT, unsafe.Pointer(nil)) gl.BindVertexArray(0) // end of draw loop // swap in the rendered buffer window.SwapBuffers() } return nil }
func programLoop(window *glfw.Window) error { // the linked shader program determines how the data will be rendered vertShader, err := gfx.NewShaderFromFile("shaders/basic.vert", gl.VERTEX_SHADER) if err != nil { return err } fragShader, err := gfx.NewShaderFromFile("shaders/basic.frag", gl.FRAGMENT_SHADER) if err != nil { return err } shaderProgram, err := gfx.NewProgram(vertShader, fragShader) if err != nil { return err } defer shaderProgram.Delete() vertices := []float32{ // top left -0.75, 0.75, 0.0, // position 1.0, 0.0, 0.0, // Color 1.0, 0.0, // texture coordinates // top right 0.75, 0.75, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, // bottom right 0.75, -0.75, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, // bottom left -0.75, -0.75, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, } indices := []uint32{ // rectangle 0, 1, 2, // top triangle 0, 2, 3, // bottom triangle } VAO := createVAO(vertices, indices) texture0, err := gfx.NewTextureFromFile("../images/RTS_Crate.png", gl.CLAMP_TO_EDGE, gl.CLAMP_TO_EDGE) if err != nil { panic(err.Error()) } texture1, err := gfx.NewTextureFromFile("../images/trollface.png", gl.CLAMP_TO_EDGE, gl.CLAMP_TO_EDGE) if err != nil { panic(err.Error()) } for !window.ShouldClose() { // poll events and call their registered callbacks glfw.PollEvents() // background color gl.ClearColor(0.2, 0.5, 0.5, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT) // draw vertices shaderProgram.Use() // set texture0 to uniform0 in the fragment shader texture0.Bind(gl.TEXTURE0) texture0.SetUniform(shaderProgram.GetUniformLocation("ourTexture0")) // set texture1 to uniform1 in the fragment shader texture1.Bind(gl.TEXTURE1) texture1.SetUniform(shaderProgram.GetUniformLocation("ourTexture1")) gl.BindVertexArray(VAO) gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, unsafe.Pointer(nil)) gl.BindVertexArray(0) texture0.UnBind() texture1.UnBind() // end of draw loop // swap in the rendered buffer window.SwapBuffers() } return nil }
func programLoop(window *win.Window) error { // the linked shader program determines how the data will be rendered vertShader, err := gfx.NewShaderFromFile("shaders/basic.vert", gl.VERTEX_SHADER) if err != nil { return err } fragShader, err := gfx.NewShaderFromFile("shaders/basic.frag", gl.FRAGMENT_SHADER) if err != nil { return err } program, err := gfx.NewProgram(vertShader, fragShader) if err != nil { return err } defer program.Delete() VAO := createVAO(cubeVertices, nil) texture0, err := gfx.NewTextureFromFile("../images/RTS_Crate.png", gl.CLAMP_TO_EDGE, gl.CLAMP_TO_EDGE) if err != nil { panic(err.Error()) } texture1, err := gfx.NewTextureFromFile("../images/trollface-transparent.png", gl.CLAMP_TO_EDGE, gl.CLAMP_TO_EDGE) if err != nil { panic(err.Error()) } // ensure that triangles that are "behind" others do not draw over top of them gl.Enable(gl.DEPTH_TEST) camera := cam.NewFpsCamera(mgl32.Vec3{0, 0, 3}, mgl32.Vec3{0, 1, 0}, -90, 0, window.InputManager()) for !window.ShouldClose() { // swaps in last buffer, polls for window events, and generally sets up for a new render frame window.StartFrame() // update camera position and direction from input evevnts camera.Update(window.SinceLastFrame()) // background color gl.ClearColor(0.2, 0.5, 0.5, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) // depth buffer needed for DEPTH_TEST program.Use() // bind textures texture0.Bind(gl.TEXTURE0) texture0.SetUniform(program.GetUniformLocation("ourTexture0")) texture1.Bind(gl.TEXTURE1) texture1.SetUniform(program.GetUniformLocation("ourTexture1")) // cube rotation matrices rotateX := (mgl32.Rotate3DX(mgl32.DegToRad(-60 * float32(glfw.GetTime())))) rotateY := (mgl32.Rotate3DY(mgl32.DegToRad(-60 * float32(glfw.GetTime())))) rotateZ := (mgl32.Rotate3DZ(mgl32.DegToRad(-60 * float32(glfw.GetTime())))) // creates perspective fov := float32(60.0) projectTransform := mgl32.Perspective(mgl32.DegToRad(fov), float32(window.Width())/float32(window.Height()), 0.1, 100.0) camTransform := camera.GetTransform() gl.UniformMatrix4fv(program.GetUniformLocation("camera"), 1, false, &camTransform[0]) gl.UniformMatrix4fv(program.GetUniformLocation("project"), 1, false, &projectTransform[0]) gl.BindVertexArray(VAO) // draw each cube after all coordinate system transforms are bound for _, pos := range cubePositions { worldTranslate := mgl32.Translate3D(pos[0], pos[1], pos[2]) worldTransform := (worldTranslate.Mul4(rotateX.Mul3(rotateY).Mul3(rotateZ).Mat4())) gl.UniformMatrix4fv(program.GetUniformLocation("world"), 1, false, &worldTransform[0]) gl.DrawArrays(gl.TRIANGLES, 0, 36) } gl.BindVertexArray(0) texture0.UnBind() texture1.UnBind() // end of draw loop } return nil }