package module
Version: v0.0.0-...-57b2077 Latest Latest

This package is not in the latest version of its module.

Go to latest
Published: Oct 13, 2021 License: MIT Imports: 6 Imported by: 39


glhf GoDoc Report card

openGL Have Fun - A Go package that makes life with OpenGL enjoyable.

go get

Main features

  • Garbage collected OpenGL objects
  • Dynamically sized vertex slices (vertex arrays are boring)
  • Textures, Shaders, Frames (reasonably managed framebuffers)
  • Always possible to use standard OpenGL with glhf


OpenGL is verbose, it's usage patterns are repetitive and it's manual memory management doesn't fit Go's design. When making a game development library, it's usually desirable to create some higher-level abstractions around OpenGL. This library is a take on that.


The library is young and many features are still missing. If you find a bug, have a proposal or a feature request, do an issue!. If you know how to implement something that's missing, do a pull request.


The following are parts of the demo program, which can be found in the examples.

// ... GLFW window creation and stuff ...

// vertex shader source
var vertexShader = `
#version 330 core

in vec2 position;
in vec2 texture;

out vec2 Texture;

void main() {
	gl_Position = vec4(position, 0.0, 1.0);
	Texture = texture;

// fragment shader source
var fragmentShader = `
#version 330 core

in vec2 Texture;

out vec4 color;

uniform sampler2D tex;

void main() {
	color = texture(tex, Texture);

var (
        // Here we define a vertex format of our vertex slice. It's actually a basic slice
        // literal.
        // The vertex format consists of names and types of the attributes. The name is the
        // name that the attribute is referenced by inside a shader.
        vertexFormat = glhf.AttrFormat{
                {Name: "position", Type: glhf.Vec2},
                {Name: "texture", Type: glhf.Vec2},

        // Here we declare some variables for later use.
        shader  *glhf.Shader
        texture *glhf.Texture
        slice   *glhf.VertexSlice

// Here we load an image from a file. The loadImage function is not within the library, it
// just loads and returns a image.NRGBA.
gopherImage, err := loadImage("celebrate.png")
if err != nil {

// Every OpenGL call needs to be done inside the main thread.
mainthread.Call(func() {
        var err error

        // Here we create a shader. The second argument is the format of the uniform
        // attributes. Since our shader has no uniform attributes, the format is empty.
        shader, err = glhf.NewShader(vertexFormat, glhf.AttrFormat{}, vertexShader, fragmentShader)

        // If the shader compilation did not go successfully, an error with a full
        // description is returned.
        if err != nil {

        // We create a texture from the loaded image.
        texture = glhf.NewTexture(

        // And finally, we make a vertex slice, which is basically a dynamically sized
        // vertex array. The length of the slice is 6 and the capacity is the same.
        // The slice inherits the vertex format of the supplied shader. Also, it should
        // only be used with that shader.
        slice = glhf.MakeVertexSlice(shader, 6, 6)

        // Before we use a slice, we need to Begin it. The same holds for all objects in
        // GLHF.

        // We assign data to the vertex slice. The values are in the order as in the vertex
        // format of the slice (shader). Each two floats correspond to an attribute of type
        // glhf.Vec2.
                -1, -1, 0, 1,
                +1, -1, 1, 1,
                +1, +1, 1, 0,

                -1, -1, 0, 1,
                +1, +1, 1, 0,
                -1, +1, 0, 0,

        // When we're done with the slice, we End it.

shouldQuit := false
for !shouldQuit {
        mainthread.Call(func() {
                // ... GLFW stuff ...

                // Clear the window.
                glhf.Clear(1, 1, 1, 1)

                // Here we Begin/End all necessary objects and finally draw the vertex
                // slice.

                // ... GLFW stuff ...


Which version of OpenGL does GLHF use?

It uses OpenGL 3.3 and uses

Why do I have to use package with GLHF?

First of all, OpenGL has to be done from one thread and many operating systems require, that the one thread will be the main thread of your application.

But why that specific package? GLHF uses the mainthread package to do the garbage collection of OpenGL objects, which is super convenient. So in order for it to work correctly, you have to initialize the mainthread package through mainthread.Run. However, once you call this function there is no way to run functions on the main thread, except for through the mainthread package.

Why is the important XY feature not included?

I probably didn't need it yet. If you want that features, create an issue or implement it and do a pull request.

Does GLHF create windows for me?

No. You have to use another library for windowing, e.g.

Why no tests?

If you find a way to automatically test OpenGL, I may add tests.



Package glhf provides abstractions around the basic OpenGL primitives and operations.

All calls should be done from the main thread using "" package.

This package deliberately does not handle nor report trivial OpenGL errors, it's up to you to cause none. It does of course report errors like shader compilation error and such.



View Source
const (
	One              = BlendFactor(gl.ONE)
	Zero             = BlendFactor(gl.ZERO)
	SrcAlpha         = BlendFactor(gl.SRC_ALPHA)
	DstAlpha         = BlendFactor(gl.DST_ALPHA)
	OneMinusSrcAlpha = BlendFactor(gl.ONE_MINUS_SRC_ALPHA)
	OneMinusDstAlpha = BlendFactor(gl.ONE_MINUS_DST_ALPHA)

Here's the list of all blend factors.


This section is empty.


func BlendFunc

func BlendFunc(src, dst BlendFactor)

BlendFunc sets the source and destination blend factor.

func Bounds

func Bounds(x, y, w, h int)

Bounds sets the drawing bounds in pixels. Drawing outside bounds is always discarted.

Calling this function is equivalent to setting viewport and scissor in OpenGL.

func Clear

func Clear(r, g, b, a float32)

Clear clears the current framebuffer or window with the given color.

func Init

func Init()

Init initializes OpenGL by loading function pointers from the active OpenGL context. This function must be manually run inside the main thread (using "" package).

It must be called under the presence of an active OpenGL context, e.g., always after calling window.MakeContextCurrent(). Also, always call this function when switching contexts.


type Attr

type Attr struct {
	Name string
	Type AttrType

Attr represents an arbitrary OpenGL attribute, such as a vertex attribute or a shader uniform attribute.

type AttrFormat

type AttrFormat []Attr

AttrFormat defines names and types of OpenGL attributes (vertex format, uniform format, etc.).


AttrFormat{{"position", Vec2}, {"color", Vec4}, {"texCoord": Vec2}}

func (AttrFormat) Size

func (af AttrFormat) Size() int

Size returns the total size of all attributes of the AttrFormat.

type AttrType

type AttrType int

AttrType represents the type of an OpenGL attribute.

const (
	Int AttrType = iota

List of all possible attribute types.

func (AttrType) Size

func (at AttrType) Size() int

Size returns the size of a type in bytes.

type BeginEnder

type BeginEnder interface {

BeginEnder is an interface for manipulating OpenGL state.

OpenGL is a state machine. Every object can 'enter' it's state and 'leave' it's state. For example, you can bind a buffer and unbind a buffer, bind a texture and unbind it, use shader and unuse it, and so on.

type BlendFactor

type BlendFactor int

BlendFactor represents a source or destination blend factor.

type Frame

type Frame struct {
	// contains filtered or unexported fields

Frame is a fixed resolution texture that you can draw on.

func NewFrame

func NewFrame(width, height int, smooth bool) *Frame

NewFrame creates a new fully transparent Frame with given dimensions in pixels.

func (*Frame) Begin

func (f *Frame) Begin()

Begin binds the Frame. All draw operations will target this Frame until End is called.

func (*Frame) Blit

func (f *Frame) Blit(dst *Frame, sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1 int)

Blit copies rectangle (sx0, sy0, sx1, sy1) in this Frame onto rectangle (dx0, dy0, dx1, dy1) in dst Frame.

If the dst Frame is nil, the destination will be the framebuffer 0, which is the screen.

If the sizes of the rectangles don't match, the source will be stretched to fit the destination rectangle. The stretch will be either smooth or pixely according to the source Frame's smoothness.

func (*Frame) End

func (f *Frame) End()

End unbinds the Frame. All draw operations will go to whatever was bound before this Frame.

func (*Frame) ID

func (f *Frame) ID() uint32

ID returns the OpenGL framebuffer ID of this Frame.

func (*Frame) Texture

func (f *Frame) Texture() *Texture

Texture returns the Frame's underlying Texture that the Frame draws on.

type Shader

type Shader struct {
	// contains filtered or unexported fields

Shader is an OpenGL shader program.

func NewShader

func NewShader(vertexFmt, uniformFmt AttrFormat, vertexShader, fragmentShader string) (*Shader, error)

NewShader creates a new shader program from the specified vertex shader and fragment shader sources.

Note that vertexShader and fragmentShader parameters must contain the source code, they're not filenames.

func (*Shader) Begin

func (s *Shader) Begin()

Begin binds the Shader program. This is necessary before using the Shader.

func (*Shader) End

func (s *Shader) End()

End unbinds the Shader program and restores the previous one.

func (*Shader) ID

func (s *Shader) ID() uint32

ID returns the OpenGL ID of this Shader.

func (*Shader) SetUniformAttr

func (s *Shader) SetUniformAttr(uniform int, value interface{}) (ok bool)

SetUniformAttr sets the value of a uniform attribute of this Shader. The attribute is specified by the index in the Shader's uniform format.

If the uniform attribute does not exist in the Shader, this method returns false.

Supplied value must correspond to the type of the attribute. Correct types are these (right-hand is the type of the value):

Attr{Type: Int}:   int32
Attr{Type: Float}: float32
Attr{Type: Vec2}:  mgl32.Vec2
Attr{Type: Vec3}:  mgl32.Vec3
Attr{Type: Vec4}:  mgl32.Vec4
Attr{Type: Mat2}:  mgl32.Mat2
Attr{Type: Mat23}: mgl32.Mat2x3
Attr{Type: Mat24}: mgl32.Mat2x4
Attr{Type: Mat3}:  mgl32.Mat3
Attr{Type: Mat32}: mgl32.Mat3x2
Attr{Type: Mat34}: mgl32.Mat3x4
Attr{Type: Mat4}:  mgl32.Mat4
Attr{Type: Mat42}: mgl32.Mat4x2
Attr{Type: Mat43}: mgl32.Mat4x3

No other types are supported.

The Shader must be bound before calling this method.

func (*Shader) UniformFormat

func (s *Shader) UniformFormat() AttrFormat

UniformFormat returns the uniform attribute format of this Shader. Do not change it.

func (*Shader) VertexFormat

func (s *Shader) VertexFormat() AttrFormat

VertexFormat returns the vertex attribute format of this Shader. Do not change it.

type Texture

type Texture struct {
	// contains filtered or unexported fields

Texture is an OpenGL texture.

func NewTexture

func NewTexture(width, height int, smooth bool, pixels []uint8) *Texture

NewTexture creates a new texture with the specified width and height with some initial pixel values. The pixels must be a sequence of RGBA values (one byte per component).

func (*Texture) Begin

func (t *Texture) Begin()

Begin binds the Texture. This is necessary before using the Texture.

func (*Texture) End

func (t *Texture) End()

End unbinds the Texture and restores the previous one.

func (*Texture) Height

func (t *Texture) Height() int

Height returns the height of the Texture in pixels.

func (*Texture) ID

func (t *Texture) ID() uint32

ID returns the OpenGL ID of this Texture.

func (*Texture) Pixels

func (t *Texture) Pixels(x, y, w, h int) []uint8

Pixels returns the content of a sub-region of the Texture as an RGBA byte sequence.

func (*Texture) SetPixels

func (t *Texture) SetPixels(x, y, w, h int, pixels []uint8)

SetPixels sets the content of a sub-region of the Texture. Pixels must be an RGBA byte sequence.

func (*Texture) SetSmooth

func (t *Texture) SetSmooth(smooth bool)

SetSmooth sets whether the Texture should be drawn "smoothly" or "pixely".

It affects how the Texture is drawn when zoomed. Smooth interpolates between the neighbour pixels, while pixely always chooses the nearest pixel.

func (*Texture) Smooth

func (t *Texture) Smooth() bool

Smooth returns whether the Texture is set to be drawn "smooth" or "pixely".

func (*Texture) Width

func (t *Texture) Width() int

Width returns the width of the Texture in pixels.

type VertexSlice

type VertexSlice struct {
	// contains filtered or unexported fields

VertexSlice points to a portion of (or possibly whole) vertex array. It is used as a pointer, contrary to Go's builtin slices. This is, so that append can be 'in-place'. That's for the good, because Begin/End-ing a VertexSlice would become super confusing, if append returned a new VertexSlice.

It also implements all basic slice-like operations: appending, sub-slicing, etc.

Note that you need to Begin a VertexSlice before getting or updating it's elements or drawing it. After you're done with it, you need to End it.

func MakeVertexSlice

func MakeVertexSlice(shader *Shader, len, cap int) *VertexSlice

MakeVertexSlice allocates a new vertex array with specified capacity and returns a VertexSlice that points to it's first len elements.

Note, that a vertex array is specialized for a specific shader and can't be used with another shader.

func (*VertexSlice) Begin

func (vs *VertexSlice) Begin()

Begin binds the underlying vertex array. Calling this method is necessary before using the VertexSlice.

func (*VertexSlice) Cap

func (vs *VertexSlice) Cap() int

Cap returns the capacity of an underlying vertex array.

func (*VertexSlice) Draw

func (vs *VertexSlice) Draw()

Draw draws the content of the VertexSlice.

func (*VertexSlice) End

func (vs *VertexSlice) End()

End unbinds the underlying vertex array. Call this method when you're done with VertexSlice.

func (*VertexSlice) Len

func (vs *VertexSlice) Len() int

Len returns the length of the VertexSlice (number of vertices).

func (*VertexSlice) SetLen

func (vs *VertexSlice) SetLen(len int)

SetLen resizes the VertexSlice to length len.

func (*VertexSlice) SetVertexData

func (vs *VertexSlice) SetVertexData(data []float32)

SetVertexData sets the contents of the VertexSlice.

The data is a slice of float32's, where each vertex attribute occupies a certain number of elements. Namely, Float occupies 1, Vec2 occupies 2, Vec3 occupies 3 and Vec4 occupies 4. The attribues in the data slice must be in the same order as in the vertex format of this Vertex Slice.

If the length of vertices does not match the length of the VertexSlice, this methdo panics.

func (*VertexSlice) Slice

func (vs *VertexSlice) Slice(i, j int) *VertexSlice

Slice returns a sub-slice of this VertexSlice covering the range [i, j) (relative to this VertexSlice).

Note, that the returned VertexSlice shares an underlying vertex array with the original VertexSlice. Modifying the contents of one modifies corresponding contents of the other.

func (*VertexSlice) Stride

func (vs *VertexSlice) Stride() int

Stride returns the number of float32 elements occupied by one vertex.

func (*VertexSlice) VertexData

func (vs *VertexSlice) VertexData() []float32

VertexData returns the contents of the VertexSlice.

The data is in the same format as with SetVertexData.

func (*VertexSlice) VertexFormat

func (vs *VertexSlice) VertexFormat() AttrFormat

VertexFormat returns the format of vertex attributes inside the underlying vertex array of this VertexSlice.


Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL