Skip to content
OpenGL Next: functional programming and DSL
Kotlin Java
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


Build Status License Release Slack Status

OpenGL Next, functional programming

A wrapper around OpenGL aimed to improve the dev experience by making gl code compact, easier (also allocation-wise) and type-safe (by converting those gl int constants into enums).

To show you a practical example, you can take a look at the different code snippets on the gli README

Intensive usage of inline classes and enums.. use them as a class or an enum, compiled as Ints


A buffer in means of OpenGL can be used for vertex attributes, indices, uniform data, atomic counters, texture data, and shader storage data.


    arrayBufferName = glGenBuffers()
    glBindBuffer(GL_ARRAY_BUFFER, arrayBufferName)
    glBufferData(GL_ARRAY_BUFFER, positionData, GL_STATIC_DRAW)
    glBindBuffer(GL_ARRAY_BUFFER, 0)

    elementBufferName = glGenBuffers()
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferName)
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementData, GL_STATIC_DRAW)
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)

We can see a lot of redundancy here, starting from the word "Buffer".

Second, we can enclose in a lambda whatever we want to execute when a buffer gets bound.

Next, we can get rid of the target repetition, it can be specified just once, at the begin of the scoping.

All successive calls will refer to that target.

All of this, turns out as

    val arrayBuffer = glGenBuffers()
    arrayBuffer.bound(ARRAY) {
        data(positionData, STATIC_DRAW)

We can push even further and specify the buffer name just once, and leave out the usage (default to STATIC_DRAW) and have everything as

glGenBuffers(::elementBuffer).bound(ELEMENT_ARRAY) { data(elementData) }

Thanks to the inline function, the compiler will take the burden to take our code and automatically transform it as you see on top, the verbose traditional version

Object-oriented design offers also to a much comfortable way to get and set parameters.

Let's say we want to retrieve the size of a buffer. The old-school way would require you to write something like:

glBindBuffer(GL_ARRAY_BUFFER, buffer)
val bufferSize /* : Int */ = glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE)
glBindBuffer(GL_ARRAY_BUFFER, 0)

Again, syntax redundancy can be avoided, so with gln you can simply type

val bufferSize = buffer.bound(ARRAY) { size }

The nice thing is that we do know the type of request, so we can deliver it directly as it should be logically. For example, since GL_BUFFER_IMMUTABLE_STORAGE returns either GL_FALSE or GL_TRUE

glBindBuffer(GL_ARRAY_BUFFER, buffer)
val bufferImmutability /* : Boolean */ = glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_IMMUTABLE_STORAGE) == GL_TRUE
glBindBuffer(GL_ARRAY_BUFFER, 0)

it makes sense to return directly a Boolean

val bufferImmutability /* : Boolean */ = buffer.bound(ARRAY) { immutableStorage }

This of course applies also for other variable types, such as the inlined enum BufferAccess or the typealiased integer MapBufferFlags.



You can’t perform that action at this time.