/gln

OpenGL Next: functional programming and DSL

Primary LanguageKotlinApache License 2.0Apache-2.0

gln

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

Buffer

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

This

    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 world "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

    arrayBufferName = glGenBuffers()
    arrayBufferName.bound(ARRAY_BUFFER) {
        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(::elementBufferName).bound(ELEMENT_ARRAY_BUFFER) { 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_BUFFER) { 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_BUFFER) { immutableStorage }

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

Manual

here