func compileShader(source string, shaderType uint32) (uint32, error) { shader := gl.CreateShader(shaderType) csource := gl.Str(source) gl.ShaderSource(shader, 1, &csource, nil) if e := gl.GetError(); e != gl.NO_ERROR { panic(fmt.Sprintf("before resizing: %d", e)) } gl.CompileShader(shader) if e := gl.GetError(); e != gl.NO_ERROR { panic(fmt.Sprintf("before resizing: %d", e)) } var status int32 gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status) if status == gl.FALSE { var logLength int32 gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength) log := strings.Repeat("\x00", int(logLength+1)) gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log)) return 0, fmt.Errorf("failed to compile %v: %v", source, log) } return shader, nil }
// // Build Shader // Creates and compiles a shader // // @param source (string) the path to the shader file // @param shaderType (uint32) the shader type // // @return shader (uint32) the pointer to the shader // @return error (error) the error (if any) // func BuildShader(source string, shaderType uint32) (uint32, error) { // Creates the Shader Object shader := gl.CreateShader(shaderType) // Reads the File fileContents := FileToString(source) // Converts the file contents into a valid C String csource := gl.Str(fileContents) // Loads the Shader's Source gl.ShaderSource(shader, 1, &csource, nil) // Compiles the Shader gl.CompileShader(shader) // Gets any errors that happened when building the Shader var status int32 gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status) // If there was an error, parse the C Error into a Go Error and return it if status == gl.FALSE { var logLength int32 gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength) log := strings.Repeat("\x00", int(logLength+1)) gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log)) return 0, fmt.Errorf("failed to compile %v: %v", source, log) } // Returns the shader if everything is OK return shader, nil }
func newProgram(vertexShaderSource, fragmentShaderSource string) (uint32, error) { vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER) if err != nil { return 0, err } fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER) if err != nil { return 0, err } program := gl.CreateProgram() gl.AttachShader(program, vertexShader) gl.AttachShader(program, fragmentShader) gl.LinkProgram(program) var status int32 gl.GetProgramiv(program, gl.LINK_STATUS, &status) if status == gl.FALSE { var logLength int32 gl.GetProgramiv(program, gl.INFO_LOG_LENGTH, &logLength) log := strings.Repeat("\x00", int(logLength+1)) gl.GetProgramInfoLog(program, logLength, nil, gl.Str(log)) return 0, fmt.Errorf("failed to link program: %v", log) } gl.DeleteShader(vertexShader) gl.DeleteShader(fragmentShader) return program, nil }
func (glr *GlRenderer) initScreen() { var err error glr.program, err = createScreenShader() if err != nil { panic(err) } gl.UseProgram(glr.program) projection := mgl32.Ortho2D(-1, 1, 1, -1) projectionUniform := gl.GetUniformLocation(glr.program, gl.Str("projection\x00")) gl.UniformMatrix4fv(projectionUniform, 1, false, &projection[0]) textureUniform := gl.GetUniformLocation(glr.program, gl.Str("tex\x00")) gl.Uniform1i(textureUniform, 0) glr.texture = createScreenTexture(glr.width, glr.height) gl.GenVertexArrays(1, &glr.vao) gl.BindVertexArray(glr.vao) var quadVertices = []float32{ // X, Y, Z, U, V 1.0, -1.0, 0.0, 1.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 0.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, } var vbo uint32 gl.GenBuffers(1, &vbo) gl.BindBuffer(gl.ARRAY_BUFFER, vbo) gl.BufferData(gl.ARRAY_BUFFER, len(quadVertices)*4, gl.Ptr(quadVertices), gl.STATIC_DRAW) vertAttrib := uint32(gl.GetAttribLocation(glr.program, gl.Str("vert\x00"))) gl.EnableVertexAttribArray(vertAttrib) gl.VertexAttribPointer(vertAttrib, 3, gl.FLOAT, false, 5*4, gl.PtrOffset(0)) texCoordAttrib := uint32(gl.GetAttribLocation(glr.program, gl.Str("vertTexCoord\x00"))) gl.EnableVertexAttribArray(texCoordAttrib) gl.VertexAttribPointer(texCoordAttrib, 2, gl.FLOAT, false, 5*4, gl.PtrOffset(3*4)) gl.Enable(gl.DEPTH_TEST) gl.ClearColor(1.0, 1.0, 1.0, 1.0) }
// // Init App // This function initializes the variables and sets up the environment. // // @param wrapper (*wrapper.Glw) the window wrapper // func InitApp(glw *wrapper.Glw) { /* Set the object transformation controls to their initial values */ x = 0.05 y = 0 z = 0 angle_x = 0 angle_y = 0 angle_z = 0 angle_inc_x = 0 angle_inc_y = 0 angle_inc_z = 0 scale = 1.0 aspect_ratio = 1.3333 colourmode = objects.COLOR_SOLID var numLats uint32 = 20 // Number of latitudes in our sphere var numLongs uint32 = 20 // Number of longitudes in our sphere // Generate index (name) for one vertex array object gl.GenVertexArrays(1, &vertexArrayObject) // Create the vertex array object and make it current gl.BindVertexArray(vertexArrayObject) // Create the Cube Object cube = objects.NewCube(&vertexPositions, &vertexColours, &normals) cube.MakeVBO() // create the sphere object sphere = objects.NewSphere(numLats, numLongs) sphere.MakeSphereVBO() // Creates the Shader Program var err error shaderProgram, err = wrapper.LoadShader("./shaders/basic.vert", "./shaders/basic.frag") // If there is any error loading the shaders, it panics if err != nil { panic(err) } // Define uniforms to send to vertex shader modelUniform = gl.GetUniformLocation(shaderProgram, gl.Str("model\x00")) colourmodeUniform = gl.GetUniformLocation(shaderProgram, gl.Str("colourmode\x00")) viewUniform = gl.GetUniformLocation(shaderProgram, gl.Str("view\x00")) projectionUniform = gl.GetUniformLocation(shaderProgram, gl.Str("projection\x00")) }
func makeResources() *gResources { r := gResources{ vertexBuffer: makeBuffer(gl.ARRAY_BUFFER, gl.Ptr(gVertexBufferData), 4*len(gVertexBufferData)), elementBuffer: makeBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Ptr(gElementBufferData), 4*len(gElementBufferData)), } r.textures[0] = makeTexture("hello1.png") r.textures[1] = makeTexture("hello2.png") r.vertexShader = makeShader(gl.VERTEX_SHADER, vertex_glsl) r.fragmentShader = makeShader(gl.FRAGMENT_SHADER, fragment_glsl) r.program = makeProgram(r.vertexShader, r.fragmentShader) r.uniforms.fadeFactor = gl.GetUniformLocation(r.program, gl.Str("fade_factor\x00")) r.uniforms.textures[0] = gl.GetUniformLocation(r.program, gl.Str("textures[0]\x00")) r.uniforms.textures[1] = gl.GetUniformLocation(r.program, gl.Str("textures[1]\x00")) r.attributes.position = gl.GetAttribLocation(r.program, gl.Str("position\x00")) return &r }
func makeShader(shaderType uint32, source string) uint32 { shader := gl.CreateShader(shaderType) csource := gl.Str(source) gl.ShaderSource(shader, 1, &csource, nil) gl.CompileShader(shader) var status int32 gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status) if status == gl.FALSE { var logLength int32 gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength) log := strings.Repeat("\x00", int(logLength+1)) gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log)) x(fmt.Errorf("failed to compile %v: %v", source, log)) } return shader }
func (r *Renderer) Render() { // defer glfw.Terminate() shader := r.Shaders.textureFlat program := shader.program // gl.UseProgram(program) // 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 += elapsed // r.Mesh.modelView = mgl32.HomogRotate3D(float32(angle), mgl32.Vec3{0, 1, 0}) // Render // gl.UniformMatrix4fv(shader.uniforms["modelView"], 1, false, &r.Mesh.modelView[0]) time := glfw.GetTime() _ = time - r.PreviousTime r.PreviousTime = time // fmt.Println(elapsed * 100) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) gl.UniformMatrix4fv(shader.uniforms["projection"], 1, false, &r.Projection[0]) gl.UniformMatrix4fv(shader.uniforms["camera"], 1, false, &r.Camera[0]) // TODO : batch triangles and use multiple textures for _, mesh := range r.Meshes { gl.UniformMatrix4fv(shader.uniforms["modelView"], 1, false, &mesh.modelView[0]) gl.Uniform1i(shader.uniforms["tex"], 0) gl.BindVertexArray(mesh.vao) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, mesh.textures[0]) gl.DrawArrays(gl.TRIANGLES, 0, int32(len(mesh.verticies)/5)) } // Maintenance r.Window.SwapBuffers() glfw.PollEvents() if r.Ready == false { r.Ready = true } }
// // Load Shader // Load vertex and fragment shader and return the compiled program. // // @param vertexShaderSource (string) path to the vertex shader file // @param fragmentShaderSource (string) path to the fragment shader file // // @return program (uint32) a pointer to the shader program // @return error (error) the error (if any) // func LoadShader(vertexShaderSource, fragmentShaderSource string) (uint32, error) { // Loads the Vertex shader file vertexShader, err := BuildShader(vertexShaderSource, gl.VERTEX_SHADER) if err != nil { return 0, err } // Loads the fragment shader file fragmentShader, err := BuildShader(fragmentShaderSource, gl.FRAGMENT_SHADER) if err != nil { return 0, err } // Creates the Program program := gl.CreateProgram() // Attaches the Shaders to the program gl.AttachShader(program, vertexShader) gl.AttachShader(program, fragmentShader) // Links the program gl.LinkProgram(program) // Gets any error that happened when linking the program var status int32 gl.GetProgramiv(program, gl.LINK_STATUS, &status) // If there was any error, parse the C error and return it as a Go error if status == gl.FALSE { var logLength int32 gl.GetProgramiv(program, gl.INFO_LOG_LENGTH, &logLength) log := strings.Repeat("\x00", int(logLength+1)) gl.GetProgramInfoLog(program, logLength, nil, gl.Str(log)) return 0, fmt.Errorf("failed to link program: %v", log) } // Deletes the shaders gl.DeleteShader(vertexShader) gl.DeleteShader(fragmentShader) // returns the program return program, nil }
func makeResources() *gResources { r := gResources{ vertexBuffer1: makeBuffer(gl.ARRAY_BUFFER, gl.Ptr(gVertexBufferData1), 4*len(gVertexBufferData1)), elementBuffer1: makeBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Ptr(gElementBufferData1), 4*len(gElementBufferData1)), vertexBuffer2: makeBuffer(gl.ARRAY_BUFFER, gl.Ptr(gVertexBufferData2), 4*len(gVertexBufferData2)), elementBuffer2: makeBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Ptr(gElementBufferData2), 4*len(gElementBufferData2)), colorBuffer2: makeBuffer(gl.ARRAY_BUFFER, gl.Ptr(gColorBufferData2), 4*len(gColorBufferData2)), } r.vertexShader1 = makeShader(gl.VERTEX_SHADER, vertex_glsl1) r.fragmentShader1 = makeShader(gl.FRAGMENT_SHADER, fragment_glsl1) r.program1 = makeProgram(r.vertexShader1, r.fragmentShader1) r.vertexShader2 = makeShader(gl.VERTEX_SHADER, vertex_glsl2) r.fragmentShader2 = makeShader(gl.FRAGMENT_SHADER, fragment_glsl2) r.program2 = makeProgram(r.vertexShader2, r.fragmentShader2) r.uniforms2.xmul = gl.GetUniformLocation(r.program2, gl.Str("xmul\x00")) r.uniforms2.ymul = gl.GetUniformLocation(r.program2, gl.Str("ymul\x00")) r.uniforms2.sin = gl.GetUniformLocation(r.program2, gl.Str("sin\x00")) r.uniforms2.cos = gl.GetUniformLocation(r.program2, gl.Str("cos\x00")) r.attributes1.position = gl.GetAttribLocation(r.program1, gl.Str("position\x00")) r.attributes2.position = gl.GetAttribLocation(r.program2, gl.Str("position\x00")) r.attributes2.color = gl.GetAttribLocation(r.program2, gl.Str("vertexColor\x00")) // circle gColorBufferData3 := make([]float32, 0, 126*3) gVertexBufferData3 := make([]float32, 0, 126*2) gElementBufferData3 := make([]uint32, 0, 126) r.len3 = 0 for i := float64(0); i < 2*math.Pi; i += .05 { rd, g, b := hsb2rgb(float32(i/(2*math.Pi)), 1, 1) gColorBufferData3 = append(gColorBufferData3, rd, g, b) gVertexBufferData3 = append(gVertexBufferData3, float32(math.Sin(i)), float32(math.Cos(i))) gElementBufferData3 = append(gElementBufferData3, uint32(r.len3)) r.len3++ } r.vertexBuffer3 = makeBuffer(gl.ARRAY_BUFFER, gl.Ptr(gVertexBufferData3), 4*len(gVertexBufferData3)) r.elementBuffer3 = makeBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Ptr(gElementBufferData3), 4*len(gElementBufferData3)) r.colorBuffer3 = makeBuffer(gl.ARRAY_BUFFER, gl.Ptr(gColorBufferData3), 4*len(gColorBufferData3)) return &r }
func makeProgram(vertexShader uint32, fragmentShader uint32) uint32 { program := gl.CreateProgram() gl.AttachShader(program, vertexShader) gl.AttachShader(program, fragmentShader) gl.LinkProgram(program) var status int32 gl.GetProgramiv(program, gl.LINK_STATUS, &status) if status == gl.FALSE { var logLength int32 gl.GetProgramiv(program, gl.INFO_LOG_LENGTH, &logLength) log := strings.Repeat("\x00", int(logLength+1)) gl.GetProgramInfoLog(program, logLength, nil, gl.Str(log)) x(errors.New(fmt.Sprintf("failed to link program: %v", log))) } return program }
func (shaderManager *ShaderManager) CreateUniform(shaderName, uniformName string) { shaderManager.Shaders[shaderName].Uniforms[uniformName] = gl.GetUniformLocation(shaderManager.Shaders[shaderName].Shader, gl.Str(uniformName+"\x00")) }
func (objectLoader *WavefrontObject) DrawObject(shaderProgram uint32) { for _, object := range objectLoader.Objects { // Reads the uniform Locations modelUniform := gl.GetUniformLocation(shaderProgram, gl.Str("model\x00")) ambientUniform := gl.GetUniformLocation(shaderProgram, gl.Str("ambient\x00")) diffuseUniform := gl.GetUniformLocation(shaderProgram, gl.Str("diffuse\x00")) specularUniform := gl.GetUniformLocation(shaderProgram, gl.Str("specular\x00")) emissiveUniform := gl.GetUniformLocation(shaderProgram, gl.Str("emissive\x00")) // Send our uniforms variables to the currently bound shader if object.Material != nil { gl.Uniform4f(ambientUniform, object.Material.KaR, object.Material.KaG, object.Material.KaB, object.Material.Tr) // Ambient colour. gl.Uniform4f(diffuseUniform, object.Material.KdR, object.Material.KdG, object.Material.KdB, object.Material.Tr) // Diffuse colour. gl.Uniform4f(specularUniform, object.Material.KsR, object.Material.KsG, object.Material.KsB, object.Material.Tr) // Specular colour. gl.Uniform4f(emissiveUniform, object.Material.KeR, object.Material.KeG, object.Material.KeB, object.Material.Tr) // Emissive colour. if object.Material.Texture != 0 { textureUniform := gl.GetUniformLocation(shaderProgram, gl.Str("DiffuseTextureSampler\x00")) gl.Uniform1i(textureUniform, 0) normalTextureUniform := gl.GetUniformLocation(shaderProgram, gl.Str("NormalTextureSampler\x00")) gl.Uniform1i(normalTextureUniform, 1) specularTextureUniform := gl.GetUniformLocation(shaderProgram, gl.Str("SpecularTextureSampler\x00")) gl.Uniform1i(specularTextureUniform, 2) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, object.Material.Texture) gl.ActiveTexture(gl.TEXTURE1) gl.BindTexture(gl.TEXTURE_2D, object.Material.NormalMap) gl.ActiveTexture(gl.TEXTURE2) gl.BindTexture(gl.TEXTURE_2D, object.Material.SpecularMap) } if object.Material.Tr < 1.0 { // Enables Transparencies gl.Enable(gl.BLEND) // gl.BlendFunc(gl.SRC_COLOR, gl.ONE) // gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) } } // Geometry var size int32 // Used to get the byte size of the element (vertex index) array gl.UniformMatrix4fv(modelUniform, 1, false, &object.Model[0]) // Get the vertices uniform position verticesUniform := uint32(gl.GetAttribLocation(shaderProgram, gl.Str("position\x00"))) normalsUniform := uint32(gl.GetAttribLocation(shaderProgram, gl.Str("normal\x00"))) textureCoordinatesUniform := uint32(gl.GetAttribLocation(shaderProgram, gl.Str("texcoord\x00"))) // Describe our vertices array to OpenGL (it can't guess its format automatically) gl.BindBuffer(gl.ARRAY_BUFFER, object.VertexBufferObjectVertices) gl.VertexAttribPointer( verticesUniform, // attribute index 3, // number of elements per vertex, here (x,y,z) gl.FLOAT, // the type of each element false, // take our values as-is 0, // no extra data between each position nil, // offset of first element ) gl.EnableVertexAttribArray(normalsUniform) gl.BindBuffer(gl.ARRAY_BUFFER, object.VertexBufferObjectNormals) gl.VertexAttribPointer( normalsUniform, // attribute 3, // number of elements per vertex, here (x,y,z) gl.FLOAT, // the type of each element false, // take our values as-is 0, // no extra data between each position nil, // offset of first element ) gl.EnableVertexAttribArray(textureCoordinatesUniform) gl.BindBuffer(gl.ARRAY_BUFFER, object.VertexBufferObjectTextureCoords) gl.VertexAttribPointer( textureCoordinatesUniform, // attribute 2, // number of elements per vertex, here (u,v) gl.FLOAT, // the type of each element false, // take our values as-is 0, // no extra data between each position nil, // offset of first element ) size = int32(len(object.Vertex)) gl.PointSize(3.0) // Enable this line to show model in wireframe switch objectLoader.DrawMode { case 1: gl.PolygonMode(gl.FRONT_AND_BACK, gl.LINE) default: gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL) } gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, object.VertexBufferObjectFaces) gl.GetBufferParameteriv(gl.ELEMENT_ARRAY_BUFFER, gl.BUFFER_SIZE, &size) gl.DrawElements(gl.TRIANGLES, int32(len(object.Faces)), gl.UNSIGNED_SHORT, nil) // gl.DrawElements(gl.POINTS, int32(len(object.Faces)), gl.UNSIGNED_SHORT, nil) // Disables transparencies gl.Disable(gl.BLEND) } }
/* Enable vertex attributes and draw object Could improve efficiency by moving the vertex attribute pointer functions to the create object but this method is more general This code is almost untouched fomr the tutorial code except that I changed the number of elements per vertex from 4 to 3*/ func (terrain *Terrain) DrawObject(shaderProgram uint32) { toneUniform := gl.GetAttribLocation(shaderProgram, gl.Str("tone\x00")) gl.Uniform4f(toneUniform, terrain.ColorTone.X(), terrain.ColorTone.Y(), terrain.ColorTone.Z(), terrain.ColorTone.W()) // gl.Uniform4f(toneUniform, 0.0, 1.0, 0.5, 1.0) // gl.Uniform4fv(toneUniform, 1, &terrain.ColorTone[0]) // Reads the uniform Locations modelUniform := gl.GetUniformLocation(shaderProgram, gl.Str("model\x00")) // Send our uniforms variables to the currently bound shader gl.UniformMatrix4fv(modelUniform, 1, false, &terrain.Model[0]) // Get the vertices uniform position verticesUniform := uint32(gl.GetAttribLocation(shaderProgram, gl.Str("position\x00"))) normalsUniform := uint32(gl.GetAttribLocation(shaderProgram, gl.Str("normal\x00"))) colorsUniform := uint32(gl.GetAttribLocation(shaderProgram, gl.Str("colour\x00"))) // Describe our vertices array to OpenGL (it can't guess its format automatically) gl.EnableVertexAttribArray(verticesUniform) gl.BindBuffer(gl.ARRAY_BUFFER, terrain.VBOVertices) gl.VertexAttribPointer( verticesUniform, // attribute index 3, // number of elements per vertex, here (x,y,z) gl.FLOAT, // the type of each element false, // take our values as-is 0, // no extra data between each position nil, // offset of first element ) gl.EnableVertexAttribArray(normalsUniform) gl.BindBuffer(gl.ARRAY_BUFFER, terrain.VBONormals) gl.VertexAttribPointer( normalsUniform, // attribute 3, // number of elements per vertex, here (x,y,z) gl.FLOAT, // the type of each element false, // take our values as-is 0, // no extra data between each position nil, // offset of first element ) gl.EnableVertexAttribArray(colorsUniform) gl.BindBuffer(gl.ARRAY_BUFFER, terrain.VBOColors) gl.VertexAttribPointer( colorsUniform, // attribute 3, // number of elements per vertex, here (x,y,z) gl.FLOAT, // the type of each element false, // take our values as-is 0, // no extra data between each position nil, // offset of first element ) size := int32(len(terrain.Indices)) gl.PointSize(3.0) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, terrain.VBOIndices) gl.GetBufferParameteriv(gl.ELEMENT_ARRAY_BUFFER, gl.BUFFER_SIZE, &size) // Enable this line to show model in wireframe switch terrain.DrawMode { case 1: gl.PolygonMode(gl.FRONT_AND_BACK, gl.LINE) case 2: gl.DrawArrays(gl.POINTS, 0, int32(len(terrain.Vertices))) // gl.DrawElements(gl.POINTS, int32(len(terrain.Indices)), gl.UNSIGNED_SHORT, nil) return default: gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL) } var location int = 0 /* Draw the triangle strips */ for i := uint32(0); i < terrain.XSize-1; i++ { location = SizeOfUint16 * int(i*terrain.ZSize*2) gl.DrawElements(gl.TRIANGLE_STRIP, int32(terrain.ZSize*2), gl.UNSIGNED_SHORT, gl.PtrOffset(location)) } // gl.DrawElements( // gl.TRIANGLE_STRIP, // len(terrain.Indices), // gl.UNSIGNED_SHORT, // nil, // ) }
func createProgram(vertexShaderFile, fragmentShaderFile string, uniforms, attributes []string) (*Shader, error) { // Configure the vertex and fragment shaders vertexShaderSource, err := ioutil.ReadFile(vertexShaderFile) vertexShaderSource = append(vertexShaderSource, 0x00) fragmentShaderSource, err := ioutil.ReadFile(fragmentShaderFile) fragmentShaderSource = append(fragmentShaderSource, 0x00) vertexShader, err := compileShader(string(vertexShaderSource), gl.VERTEX_SHADER) if err != nil { return nil, err } fragmentShader, err := compileShader(string(fragmentShaderSource), gl.FRAGMENT_SHADER) if err != nil { return nil, err } program := gl.CreateProgram() gl.AttachShader(program, vertexShader) gl.AttachShader(program, fragmentShader) gl.LinkProgram(program) var status int32 gl.GetProgramiv(program, gl.LINK_STATUS, &status) if status == gl.FALSE { var logLength int32 gl.GetProgramiv(program, gl.INFO_LOG_LENGTH, &logLength) log := strings.Repeat("\x00", int(logLength+1)) gl.GetProgramInfoLog(program, logLength, nil, gl.Str(log)) return nil, fmt.Errorf("failed to link program: %v", log) } gl.DeleteShader(vertexShader) gl.DeleteShader(fragmentShader) gl.UseProgram(program) programUniforms := make(map[string]int32) for _, uniformName := range uniforms { if uniformName != "" { glstr := gl.Str(uniformName + "\x00") programUniforms[uniformName] = gl.GetUniformLocation(program, glstr) } } programAttributes := make(map[string]uint32) for _, attribName := range attributes { if attribName != "" { glstr := gl.Str(attribName + "\x00") programAttributes[attribName] = uint32(gl.GetAttribLocation(program, glstr)) } } return &Shader{ program: program, uniforms: programUniforms, attributes: programAttributes, }, nil }