Skip to content
Antonie Blom edited this page Oct 23, 2013 · 2 revisions

Pencil.Gaming differs from OpenTK mainly in this area: it implements GLFW as its windowing/input system. This will be a quick overview of the GLFW windowing/input system, going over some of the basic functionality. More information about GLFW can be found at their website (www.glfw.org).

There are two supported version of GLFW: GLFW 2 and GLFW 3. GLFW 2 is very stable, and is the current stable version of Pencil.Gaming. GLFW 3, however, is still under development, and usage in large projects is therefore discouraged (unless experimental). This is the reference page for GLFW 2.

Initializing/terminating GLFW

GLFW is accessed through a managed class: Pencil.Gaming.Glfw, so you should probably add using Pencil.Gaming; to files using GLFW.

To use GLFW you will first have initialize it, and at the end of the application, you will have to terminate it. The function used for initialing is Glfw.Init(), and the function used for terminating is Glfw.Terminate(). This is how you use these functions:

try {
    if (!Glfw.Init()) {
        Console.Error.WriteLine("Failed to initialize GLFW!");
        Environment.Exit(1);
    }

    // ...
    // ...
} finally {
    Glfw.Terminate();
}

The try-finally blocks are optional, but it is advised to do so. That way GLFW will terminate properly, even if an exception occurs.

You can see that Glfw.Init() returns a bool. This value indicates whether GLFW succeeded in initializing, and if it returns false, you should close the application, since further use of any other GLFW functions in that application will have undefined effects.

Opening Windows

When you make a game, it's probably useful to have a window for it first, which is something you can do with GLFW. When opening a window with GLFW, it will also automatically set the OpenGL context to the window. Opening a window is done through the function Glfw.OpenWindow(int, int, int, int, int, int, int, int, WindowMode), and closing is done through the function Glfw.CloseWindow(). You use them like this (after GLFW has been intialized):

try {
    Glfw.OpenWindow(800, 600, 8, 8, 8, 8, 24, 0, WindowMode.Window);
    
    // ...
    // ...
} finally {
    Glfw.CloseWindow();
}

Let's examine some of the parameters passed to Glfw.OpenWindow. The first two parameters specify the width and height of the window, respectively. The next three parameters are for specifying the red, green and blue bits that the window will use, respectively. The sixth parameter indicates the number of alpha bits that will be used by the window. The seventh parameter specifies the number of depth bits that the window will use, and the eighth parameter specifies the number of bits in the depth buffer. The next parameter is used for the stencil buffer bits, and is usually left zero. The last parameter specifies whether this window is fullscreen or windowed (windowed in this example).

After you've opened the window, it's time to check whether the window has actually been opened, and exit if this isn't the case.

if (Glfw.GetWindowParam(WindowParam.Opened) == 0) {
    Console.Error.WriteLine("Failed to open a GLFW window!");
    Environment.Exit(1);
}

Further Info About Windows

After that call, some other window properties can be set (title, vsync, etc), and after a close is requested by the user, you need to close the window. This is once again done in a finally block, to close the window no matter what goes wrong.

To specify the window title, you need to make a call to Glfw.SetWindowTitle(string), after the window has been opened:

Glfw.SetWindowTitle("This is a GLFW window!");

You can also specify whether the window should use vsync or not. By default, vsync is on, but you can switch between states like so:

Glfw.SwapInterval(false); // Turn vsync off
Glfw.SwapInterval(true);  // Turn vsync on

You can also make use of what are called window hints, these specify how the window should be opened, and are therefore called before Glfw.OpenWindow. Some examples:

Glfw.OpenWindowHint(OpenWindowHint.FSAASamples, 4); // Turns on 4× mutlisampling
Glfw.OpenWindowHint(OpenWindowHint.NoResize, 1);    // Turns off window resizing

You can play around with some other hints, I won't go into great detail on this wiki.

During run time, you will need to know whether a close was requested by the user, and if so, close the window and clean up. For this, you should have a game loop, call Glfw.PollEvents() and then call Glfw.GetWindowParam(WindowParam):

Glfw.PollEvents(); // Get events
while (Glfw.GetWindowParam(WindowParam.Opened) != 0) { // leave loop if requested

    Glfw.PollEvents(); // Get events
}

There are some other widow parameters that you can check. Play around with them for a bit to find out more about them.

Time Management

In games, you often need the time that has passed since the last frame. There are many ways to do this in GLFW, we'll go over one of them. In this method, we:

  • Set the time to zero
  • Enter the game loop
  • Get the time that has passed
  • Reset the time to zero

So the code will look like this:

Glfw.PollEvents();
Glfw.SetTime(0.0);                                     // Set time to zero
while (Glfw.GetWindowParam(WindowParam.Opened) == 0) { // Enter game loop
    float timeDelta = (float) Glfw.GetTime();          // Get the time that has passed
    Glfw.SetTime(0.0);                                 // Reset the time

    // Do rendering and stuff

    Glfw.PollEvents();
}

User Input

GLFW is also an input system capable of locating the mouse cursor, getting mouse button states and get keyboard input. Touch input is planned for GLFW3.

Getting the mouse position is very easy. You simply make a call to Glfw.GetMousePos:

int mousePosX, mousePosY;
Glfw.GetMousePos(out mousePosX, out mousePosY);

Input methods will only work after a call to Glfw.PollEvents().

To get the state of a mouse button, you make a call to Glfw.GetMouseButton:

if (Glfw.GetMouseButton(MouseButton.LeftButton)) {
    Console.WriteLine("The left mouse button was pressed.");
}

You can similarly check for MouseButton.RightButton, MouseButton.MiddleButton and on some mice, MouseButton.Button0 to MouseButton.Button8.

You can check the state of the mouse wheel by calling Glfw.GetMouseWheel().

Keyboard input is also as easy as a function call, you have to call Glfw.GetKey(char) or Glfw.GetKey(Key), the latter for checking control characters:

if (Glfw.GetKey('A')) {
    Console.WriteLine("The A key was pressed.");
}
if (Glfw.GetKey(Key.LeftShift)) {
    Console.WriteLine("The left shift key was pressed.");
}

A Basic GLFW Application

So now that we've got all that out of the way, we can make a simple GLFW application. Here it is:

using Pencil.Gaming;

class Program {
    private static void Main(string[] args) {
        try {
            Glfw.Init();

            try {
                Glfw.OpenWindowHint(OpenWindowHint.NoResize, 1);
                Glfw.OpenWindow(800, 600, 8, 8, 8, 8, 24, 0, WindowMode.Window);
                Glfw.SetWindowTitle("Hello GLFW!");
                Glfw.SwapInterval(false);

                Glfw.SetTime(0.0);
                while (Glfw.GetWindowParam(WindowParam.Opened) != 0) {
                    float deltaT = (float) Glfw.GetTime();
                    Glfw.SetTime(0.0);

                    // Do your rendering/updating here

                    Glfw.SwapBuffers(); // Not covered on this wiki, swaps buffers
                    Glfw.PollEvents();
                }
            } finally {
                Glfw.CloseWindow();
            }
        } finally {
            Glfw.Terminate();
        }
    }
}