Need help with Pencil.Gaming?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

131 Stars 35 Forks 210 Commits 6 Opened issues


An open-source, cross-platform gaming library for C# with bindings for OpenGL, OpenAL, and GLFW.

Services available


Need anything else?

Contributors list

# 140,279
18 commits
# 594,434
8 commits
# 404,014
2 commits
# 216,273
Common ...
Visual ...
1 commit


Pencil.Gaming is a gaming library for C#, providing support for OpenGL, GLFW, OpenAL and Lua. It's a stable, cross-platform, open-source (some prefer the term "free") alternative to libraries like XNA, which has pretty much died now, OpenTK, which hasn't been updated for about a year, and SharpDX, which is not cross-platform. A feature that Pencil.Gaming has over most other C# gaming libraries, is that users do not need to install any redistributables besides Mono/.NET!

The OpenGL implementation is based on the OpenTK source code.

Functionality and stability


| Platform | OpenGL core | OpenGL extensions | GLFW | OpenAL | | --------------:|:---------------:|:-----------------:|:---------------:|:---------:| | Linux 64-bit | Stable | Stable | Stable | Stable | | Linux 32-bit | Stable | Stable | Stable | Stable | | Windows 64-bit | Stable | Stable | Stable | Stable | | Windows 32-bit | Stable | Stable | Stable | Stable | | Mac OS X | Stable | Stable | Stable | Stable |


| Platform | OpenGL core | OpenGL extensions | GLFW | OpenAL | | --------------:|:---------------:|:-----------------:|:---------------:|:---------:| | Linux 64-bit | Stable | Stable | Stable | Stable | | Linux 32-bit | Stable | Stable | Broken | Stable | | Windows 64-bit | Stable | Stable | Stable | Stable | | Windows 32-bit | Stable | Stable | Presumed Stable | Stable | | Mac OS X | Stable | Stable | Stable* | Stable |

*Both 32 and 64-bit versions provided for Mac OS X, but mono is realistically only available for 32-bit, so those are recommended.

Fixing the

When running a Pencil.Gaming application, it's unfortunately required that you set your .NET working directory to the directory of the application. Not doing so will result in a

. This should probably be the first thing in your main function:
 Environment.CurrentDirectory = Path.GetDirectoryName(typeof(Program).Assembly.Location);

When using Mono, it's also quite important that you have the Pencil.Gaming.dll.config file in the same directory as Pencil.Gaming.dll.

Callback Example

For a quick example of the callbacks, such as the input, see:

Image loading utility

int image = GL.Utils.LoadImage("myfile.png"); // Works with multiple file formats
GL.BindTexture(TextureTarget.Texture2D, image);

GL.Begin(BeginMode.TriangleStrip); GL.TexCoord2(0f, 1f); GL.Vertex2(0.1f, 0.9f); GL.TexCoord2(0f, 0f); GL.Vertex2(0.1f, 0.1f); GL.TexCoord2(1f, 1f); GL.Vertex2(0.9f, 0.9f); GL.TexCoord2(1f, 0f); GL.Vertex2(0.9f, 0.1f); GL.End();

GL.DeleteTextures(1, ref image);

Model loading utility


int modelVbo;
int indexVbo;
int numberOfIndices;

During program initialization


Vector4[] vertices; Vector3[] normals; Vector2[] texCoords; int[] indices; GL.Utils.LoadModel("model.obj", out vertices, out normals, out texCoords, out indices, false);

numberOfIndices = indices.Length;

GL.GenBuffers(1, out modelVbo); GL.BindBuffer(BufferTarget.ArrayBuffer, modelVbo); GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(vertices.Length * 4 * sizeof(float)), vertices, BufferUsageHint.StaticDraw); GL.BindBuffer(BufferTarget.ArrayBuffer, 0);

GL.GenBuffers(1, out indexVbo); GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexVbo); GL.BufferData(BufferTarget.ElementArrayBuffer, new IntPtr(indices.Length * sizeof(int)), indices, BufferUsageHint.StaticDraw); GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);

In the draw function

// NOTE: This uses legacy OpenGL, just to fit in the readme...

GL.BindBuffer(BufferTarget.ArrayBuffer, modelVbo); GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexVbo);

GL.VertexPointer(4, VertexPointerType.Float, 4 * sizeof(float), 0); GL.DrawElements(BeginMode.Triangles, numberOfIndices, DrawElementsType.UnsignedInt, 0);

GL.BindBuffer(BufferTarget.ArrayBuffer, 0); GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);


During cleanup

GL.DeleteBuffers(1, ref modelVbo);
GL.DeleteBuffers(1, ref indexVbo);

Sample usage (OpenAL)

Another utility is the

utility, which is able to load wave files into an OpenAL buffer. Similarly, there's the
utility, allowing Ogg/Vorbis file loading.
uint buffer = AL.Utils.BufferFromWav("MyWaveFile.wav");
uint source;
AL.GenSources(1, out source);

AL.Source(source, ALSourcei.Buffer, (int) buffer); AL.Source(source, ALSourceb.Looping, true);


// ... // ...

// When cleaning up: AL.DeleteSources(1, ref source); AL.DeleteBuffers(1, ref buffer);

Other Resources

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.