Advertisement

Introducing RGFW: A lightweight Single Header Windowing framework & GLFW alternative

Started by July 23, 2024 03:11 PM
0 comments, last by colleagueRiley 2 months ago

Introducing RGFW


RGFW is a cross-platform single-header framework that abstracts creating and managing windows. RGFW is simple to use, letting you focus on programming your game or application rather than dealing with complex low-level windowing APIs, libraries with a lot of overhead, or supporting platform-specific APIs. RGFW handles the low-level APIs for you without getting in your way. It currently supports X11 (Linux), Windows (XP +), Emscripten (HTML5), and MacOS.

While creating a window, RGFW initializes a graphics context of your choosing. The options include OpenGL (including variants), DirectX, direct software rendering, or no graphics API. There is also a separate header for Vulkan support although it's recommended to make your Vulkan context yourself.

RGFW is also flexible by design. For example, you can use an event loop system or an event call-back system. (See more in examples/events/main.c and examples/callbacks/main.c in the RGFW repo).

/* Handling events via an event loop */
while (RGFW_window_checkEvent(win)) {
  switch (win->event.type) {
     case RGFW_quit:
       break;  
     case RGFW_keyPressed:
       break;
     case RGFW_mousePosChanged:
        break;
     ...
  }
}

/* Handling events via event callbacks */

void mouseposfunc(RGFW_window* win, RGFW_point point) {
 
} 
void keyfunc(RGFW_window* win, u32 keycode, char keyName[16], u8 lockState, u8 pressed) {
   
}

void windowquitfunc(RGFW_window* win) {
 
}

RGFW_setMousePosCallback(mouseposfunc);
RGFW_setKeyCallback(keyfunc);
RGFW_setWindowQuitCallback(windowquitfunc);

RGFW vs GLFW


RGFW is designed as an alternative to GLFW. This is because GLFW’s codebase is relatively heavy and is missing some flexibility.

For comparison, there is a GitHub repository that takes all of GLFW’s source code and puts it in one big single-header library. This GLFW.h file is ~10.7 megabytes and cannot be viewed on GitHub. RGFW can be viewed on GitHub because it is ~244 kilobytes and the RGFW binaries are also generally around a third of the size of GLFW’s binaries. RGFW also tends to use less RAM than GLFW.

You might think that since RGFW is significantly smaller than GLFW, it has fewer features. However, RGFW has nearly the same features as GLFW. If you’re interested in knowing the differences, there is a table included in the RGFW repository that compares RGFW to GLFW.

Compiling with RGFW


To use RGFW you need to add this line to one of your source files.

#define RGFW_IMPLEMENTATION

This allows the RGFW source defines to be included. You can also compile RGFW like any other library.

cc -x c -c RGFW.h -D RGFW_IMPLEMENTATION -fPIC -D RGFW_EXPORT

(linux): 
cc -shared RGFW.o -lX11 -lXrandr -lm -lGL

(window mingw): 
cc -shared RGFW.o -lgdi32 -lopengl32 -lwinmm -lm

(macOS)
cc -shared RGFW.o -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo -lm 

A basic example

To create a window and initialize RGFW, if it’s the first window, you use RGFW_createWindow(const char* name, RGFW_rect, u16 args)

For example, to create a window in the center of the screen that cannot be resized

RGFW_window* win = RGFW_createWindow("Window", RGFW_RECT(0, 0, 200, 200) RGFW_CENTER | RGFW_NO_RESIZE);

... // do software stuff

RGFW_window_close(win); // close window now that we're done

After you finish rendering, you need to swap the window buffer.

RGFW_window_swapBuffers(RGFW_window* win);

If you’re using an unsupported API, you’ll need to handle the function yourself.

Now here’s a full RGFW example:

#define RGFW_IMPLEMENTATION
#include "RGFW.h"

u8 icon[4 * 3 * 3] = {0xFF, 0x00, 0x00, 0xFF,    0xFF, 0x00, 0x00, 0xFF,     0xFF, 0x00, 0x00, 0xFF,   0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,     0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF};

void keyfunc(RGFW_window* win, u32 keycode, char keyName[16], u8 lockState, u8 pressed) {
    printf("this is probably early\n");
}

int main() {
    RGFW_window* win = RGFW_createWindow("name", RGFW_RECT(500, 500, 500, 500), (u64)RGFW_CENTER);

    RGFW_window_setIcon(win, icon, RGFW_AREA(3, 3), 4);
    
    RGFW_setKeyCallback(keyfunc); // you can use callbacks like this if you want 

    i32 running = 1;

    while (running) {
        while (RGFW_window_checkEvent(win)) { // or RGFW_window_checkEvents(); if you only want callbacks
            if (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_Escape)) {
                running = 0;
                break;
            }

            if (win->event.type == RGFW_keyPressed) // this is the 'normal' way of handling an event
                printf("This is probably late\n");
        }
        
        glClearColor(0xFF, 0XFF, 0xFF, 0xFF);
        glClear(GL_COLOR_BUFFER_BIT);

        RGFW_window_swapBuffers(win);
    }

    RGFW_window_close(win);
}

To compile this example run:

(linux): 
cc main.c -lX11 -lXrandr -lm -lGL -o example

(window mingw): 
cc main.c -lgdi32 -lopengl32 -lwinmm -lm -o example

(macOS)
cc main.c -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo -lm 
A screenshot of the RGFW examples and PureDoom-RGFW

Final Notes

More example codes and information about RGFW can be found in the repository. The examples can also be run with HTML5 on the RGFW examples site. If RGFW interests you, feel free to check out the RGFW repository, star it, or ask me any questions you have about RGFW. I am also open to any criticism, advice, or feature requests you may have.

None

This topic is closed to new replies.

Advertisement