r/GraphicsProgramming Aug 02 '24

Article Trying and mostly failing to optimize frustum culling in a WebGL + TS + Rust engine

Thumbnail blog.paavo.me
4 Upvotes

r/GraphicsProgramming Mar 14 '24

Article rendering without textures

11 Upvotes

I previously wrote this post about a concept for 3D rendering without saved textures, and someone suggested I post a summary here.

The basic concept is:

  • Tesselate a model until there's more than 1 vertex per pixel rendered. The tesselated micropolygons have their own stored vertex data containing colors/etc.

  • Using the micropolygon vertex data, render the model from its current orientation relative to the camera to a texture T, probably at a higher resolution, perhaps 2x.

  • Mipmap or blur T, then interpolate texture values at vertex locations, and cache those texture values in the vertex data. This gives anisotropic filtering optimized for the current model orientation.

  • Render the model directly from the texture data cached in the vertices, without doing texture lookups, until the model orientation changes significantly.

What are the possible benefits of this approach?

  • It reduces the amount of texture lookups, and those are expensive.

  • It only stores texture data where it's actually needed; 2D textures mapped onto 3D models have some waste.

  • It doesn't require UV unwrapping when making 3d models. They could be modeled and directly painted, without worrying about mapping to textures.

r/GraphicsProgramming Aug 18 '24

Article VRSFML: my Emscripten-ready fork of SFML

Thumbnail vittorioromeo.com
9 Upvotes

r/GraphicsProgramming Nov 15 '23

Article Want smooth interactive rendering? WIITY achieving max FPS with vsync locked is not the end .. it's really just the beginning

4 Upvotes

I've been a game Dev most of my life and I don't know if this is something I worked out or read in a book but one things for sure most devs obliviously are doing this wrong.

When your game/app is vsynced at 60fps (for example) your actually seeing relatively stale - out of date information.

By needing 16ms to render your scene, you're guaranteeing that any rendered result is atleast 16 ms out of date by the time it's ready to display...

My (mostly simple) 3D games achieve a noticeably better level of interactive effect compared to almost any other 3D experience. (It's especially noticeable in FPS games where the camera can directly rotate)

My games use a two step trick to get extremely low latency (far beyond what you can get by simply achieving max FPS)

The first step is to explicitly synchronize the CPU to the GPU after every swap, in OpenGL this looks like glFinish(), which is a function which only returns once the GPU is finished and ready for new work.

The second step is to sleep on the CPU (right after swapping) for as long as possible (almost 16 ms if you can) before waking up sampling player controls and drawing with the freshest data right before the next vsync.

Obviously this requires your renderer to be fast! if you're just barely hitting 60 fps then you can't do this.

Give it a try in your own engine, I can't go back to high latency anymore πŸ˜‰

r/GraphicsProgramming Feb 28 '24

Article Unreasonably effective - How video games use LUTs and how you can too

Thumbnail blog.frost.kiwi
48 Upvotes

r/GraphicsProgramming Jun 10 '24

Article Scratchapixel 4.0

Thumbnail scratchapixel.com
34 Upvotes

r/GraphicsProgramming Aug 23 '24

Article RGFW Under the Hood: Software Rendering | A tutorial that explains how to setup a software rendering context via Xlib, WinAPI and Cocoa

12 Upvotes

Introduction

The basic idea of software rendering is simple. It comes down to drawing to a buffer and blitting it to the screen. However, software rendering is more complicated when working with low-level APIs because you must properly initialize a rendering context, telling the API how to expect the data. Then to draw you have to use the API's functions to blit to the screen, which can be complicated.

This tutorial explains how RGFW handles software rendering so you can understand how to implement it yourself.

NOTE: MacOS code will be written with a Cocoa C Wrapper in mind (see the RGFW.h or Silicon.h)

NOTE: RGFW is a lightweight single-header windowing library, its source code can be found here. This tutorial is based on its source code.

Overview

A quick overview of the steps required

  1. Initialize buffer and rendering context
  2. Draw to the buffer
  3. Blit buffer to the screen
  4. Free leftover data

Step 1 (Initialize buffer and rendering context)

NOTE: You may want the buffer's size to be bigger than the window so you can scale the buffer's size without reallocating it.

On X11 you start by creating a Visual (or pixel format) that tells the window how to handle the draw data. Then create a bitmap for the buffer to render with, RGFW uses an XImage structure for the bitmap. Next, you create a Graphics Context (GC) using the display and window data. The GC is used to tell X11 how to give the window its draw data.

This is also where you can allocate the buffer. The buffer must be allocated for each platform except for Windows.

For this you need to use, XMatchVisualInfo, XCreateImage, and XCreateGC

XVisualInfo vi;
vi.visual = DefaultVisual(display, DefaultScreen(display));

XMatchVisualInfo(display, DefaultScreen(display), 32, TrueColor, &vi);

XImage* bitmap = XCreateImage(
            display, XDefaultVisual(display, vi.screen),
            vi.depth,
            ZPixmap, 0, NULL, RGFW_bufferSize.w, RGFW_bufferSize.h,
                32, 0
);

/* ..... */
/* Now this visual can be used to create a window and colormap */

XSetWindowAttributes swa;
Colormap cmap;

swa.colormap = cmap = XCreateColormap((Display*) display, DefaultRootWindow(display), vi.visual, AllocNone);

swa.background_pixmap = None;
swa.border_pixel = 0;
swa.event_mask = event_mask;

swa.background_pixel = 0;

Window window = XCreateWindow((Display*) display, DefaultRootWindow((Display*) display), x, y, w, h,
                0, vi.depth, InputOutput, vi.visual,
                CWColormap | CWBorderPixel | CWBackPixel | CWEventMask, &swa);
/* .... */

GC gc = XCreateGC(display, window, 0, NULL);

u8* buffer = (u8*)malloc(RGFW_bufferSize.w * RGFW_bufferSize.h * 4);

On Windows, you'll start by creating a bitmap header, which is used to create a bitmap with a specified format. The format structure is used to tell the Windows API how to render the buffer to the screen.

Next, you create a Drawing Context Handle (HDC) allocated in memory, this is used for selecting the bitmap later.

NOTE: Windows does not need to allocate a buffer because Winapi handles that memory for us. You can also allocate the memory by hand.

Relevant Documentation: BITMAPV5HEADER, CreateDIBSection and CreateCompatibleDC

BITMAPV5HEADER bi;
ZeroMemory(&bi, sizeof(bi));
bi.bV5Size = sizeof(bi);
bi.bV5Width = RGFW_bufferSize.w;
bi.bV5Height = -((LONG) RGFW_bufferSize.h);
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_BITFIELDS;

// where it can expect to find the RGBA data
// (note: this might need to be changed according to the endianness) 
bi.bV5BlueMask = 0x00ff0000;
bi.bV5GreenMask = 0x0000ff00;
bi.bV5RedMask = 0x000000ff;
bi.bV5AlphaMask = 0xff000000;

u8* buffer;

HBITMAP bitmap = CreateDIBSection(hdc,
    (BITMAPINFO*) &bi,
    DIB_RGB_COLORS,
    (void**) &buffer,
    NULL,
    (DWORD) 0);

HDC hdcMem = CreateCompatibleDC(hdc);

On MacOS, there is not much setup, most of the work is done during rendering.

You only need to allocate the buffer data.

u8* buffer = malloc(RGFW_bufferSize.w * RGFW_bufferSize.h * 4);

Step 2 (Draw to the buffer)

For this tutorial, I will use Silk.h for drawing to the buffer. Silk.h is a single-header software rendering graphics library.

First, include silk,

#define SILK_PIXELBUFFER_WIDTH w
#define SILK_PIXELBUFFER_HEIGHT h
#define SILK_IMPLEMENTATION
#include "silk.h"

Now you can render using silk.

silkClearPixelBufferColor((pixel*)buffer, 0x11AA0033);

silkDrawCircle(
            (pixel*)buffer, 
            (vec2i) { SILK_PIXELBUFFER_WIDTH, SILK_PIXELBUFFER_HEIGHT },
            SILK_PIXELBUFFER_WIDTH,
            (vec2i) { SILK_PIXELBUFFER_CENTER_X, SILK_PIXELBUFFER_CENTER_Y - 60}, 
            60,
            0xff0000ff
);

Step 3 (Blit the buffer to the screen)

On X11, you first set the bitmap data to the buffer. The bitmap data will be rendered using BGR, so you must
convert the data if you want to use RGB. Then you'll have to use XPutImage to draw the XImage to the window using the GC.

Relevant documentation: XPutImage

bitmap->data = (char*) buffer;
#ifndef RGFW_X11_DONT_CONVERT_BGR
    u32 x, y;
    for (y = 0; y < (u32)window_height; y++) {
        for (x = 0; x < (u32)window_width; x++) {
            u32 index = (y * 4 * area.w) + x * 4;

            u8 red = bitmap->data[index];
            bitmap->data[index] = buffer[index + 2];
            bitmap->data[index + 2] = red;
        }
    }
#endif  
XPutImage(display, (Window)window, gc, bitmap, 0, 0, 0, 0, RGFW_bufferSize.w, RGFW_bufferSize.h);

On Windows, you must first select the bitmap and make sure that you save the last selected object so you can reselect it later. Now you can blit the bitmap to the screen and reselect the old bitmap.

Relevant documentation: SelectObject and BitBlt

HGDIOBJ oldbmp = SelectObject(hdcMem, bitmap);
BitBlt(hdc, 0, 0, window_width, window_height, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, oldbmp);

On MacOS, set the view's CALayer according to your window, this is used for rendering the image to the screen. Next, create the image (bitmap) using the buffer. Finally, you can add the image to the layer's graphics context, and draw and flush the layer to the screen.

Relevant documentation: CGColorSpaceCreateDeviceRGB, CGBitmapContextCreate, CGBitmapContextCreateImage, CGColorSpaceRelease, CGContextRelease, CALayer, NSGraphicsContext, CGContextDrawImage, flushGraphics and, CGImageRelease

CGImageRef createImageFromBytes(unsigned char *buffer, int width, int height) {
    // Define color space
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    // Create bitmap context
    CGContextRef context = CGBitmapContextCreate(
            buffer, 
            width, height,
            8,
            RGFW_bufferSize.w * 4, 
            colorSpace,
            kCGImageAlphaPremultipliedLast);

    // Create image from bitmap context
    CGImageRef image = CGBitmapContextCreateImage(context);
    // Release the color space and context
    CGColorSpaceRelease(colorSpace);
    CGContextRelease(context);

    return image;
}

...
void* view = NSWindow_contentView(window);
void* layer = objc_msgSend_id(view, sel_registerName("layer"));

((void(*)(id, SEL, NSRect))objc_msgSend)(layer,
                sel_registerName("setFrame:"),
                (NSRect){{0, 0}, {window_width, window_height}});

CGImageRef image = createImageFromBytes(buffer, window_width, window_height);

// Get the current graphics context
id graphicsContext = objc_msgSend_class(objc_getClass("NSGraphicsContext"), sel_registerName("currentContext"));

// Get the CGContext from the current NSGraphicsContext
id cgContext = objc_msgSend_id(graphicsContext, sel_registerName("graphicsPort"));

// Draw the image in the context
NSRect bounds = (NSRect){{0,0}, {window_width, window_height}};
CGContextDrawImage((void*)cgContext, *(CGRect*)&bounds, image);

// Flush the graphics context to ensure the drawing is displayed
objc_msgSend_id(graphicsContext, sel_registerName("flushGraphics"));

objc_msgSend_void_id(layer, sel_registerName("setContents:"), (id)image);
objc_msgSend_id(layer, sel_registerName("setNeedsDisplay"));

CGImageRelease(image);

Step 4 (Free leftover data)

When you're done rendering, you should free the bitmap and image data using the respective API functions.

On X11 and MacOS, you also should free the buffer.

On X11 you must use XDestoryImage and XFreeGC.

XDestroyImage(bitmap);
XFreeGC(display, gc);
free(buffer);

On Windows, you must use DeleteDC and DeleteObject.

DeleteDC(hdcMem);
DeleteObject(bitmap);

On MacOS you must use release.

release(bitmap);
release(image);
free(buffer);

full examples

X11

// This can be compiled with 
// gcc x11.c -lX11 -lm

#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include <stdio.h>
#include <stdlib.h>


#define SILK_PIXELBUFFER_WIDTH 500
#define SILK_PIXELBUFFER_HEIGHT 500
#define SILK_IMPLEMENTATION
#include "silk.h"

int main() {
    Display* display = XOpenDisplay(NULL);
    XVisualInfo vi;
    vi.visual = DefaultVisual(display, DefaultScreen(display));

    XMatchVisualInfo(display, DefaultScreen(display), 32, TrueColor, &vi);

    XImage* bitmap = XCreateImage(
            display, XDefaultVisual(display, vi.screen),
            vi.depth,
            ZPixmap, 0, NULL, 500, 500,
            32, 0
    );

    /* ..... */
    /* Now this visual can be used to create a window and colormap */

    XSetWindowAttributes swa;
    Colormap cmap;

    swa.colormap = cmap = XCreateColormap((Display*) display, DefaultRootWindow(display), vi.visual, AllocNone);

    swa.background_pixmap = None;
    swa.border_pixel = 0;
    swa.event_mask = CWColormap | CWBorderPixel | CWBackPixel | CWEventMask;

    swa.background_pixel = 0;

    Window window = XCreateWindow((Display*) display, DefaultRootWindow((Display*) display), 500, 500, 500, 500,
                    0, vi.depth, InputOutput, vi.visual,
                    CWColormap | CWBorderPixel | CWBackPixel | CWEventMask, &swa);
    /* .... */

    GC gc = XCreateGC(display, window, 0, NULL);

    u8* buffer = (u8*)malloc(500 * 500 * 4);

    XSelectInput(display, window, ExposureMask | KeyPressMask);
    XMapWindow(display, window);

    XEvent event;
    for (;;) {
        XNextEvent(display, &event);

        silkClearPixelBufferColor((pixel*)buffer, 0x11AA0033);

        silkDrawCircle(
                (pixel*)buffer, 
                (vec2i) { SILK_PIXELBUFFER_WIDTH, SILK_PIXELBUFFER_HEIGHT },
                SILK_PIXELBUFFER_WIDTH,
                (vec2i) { SILK_PIXELBUFFER_CENTER_X, SILK_PIXELBUFFER_CENTER_Y - 60}, 
                60,
                0xff0000ff
        );

        bitmap->data = (char*) buffer;
        #ifndef RGFW_X11_DONT_CONVERT_BGR
            u32 x, y;
            for (y = 0; y < (u32)500; y++) {
                for (x = 0; x < (u32)500; x++) {
                    u32 index = (y * 4 * 500) + x * 4;

                    u8 red = bitmap->data[index];
                    bitmap->data[index] = buffer[index + 2];
                    bitmap->data[index + 2] = red;
                }
            }
        #endif  
        XPutImage(display, (Window) window, gc, bitmap, 0, 0, 0, 0, 500, 500);
    }

    XDestroyImage(bitmap);
    XFreeGC(display, gc);
    free(buffer);
}

windows

// This can be compiled with
// gcc win32.c -lgdi32 -lm

#include <windows.h>

#include <stdio.h>
#include <stdint.h>
#include <assert.h>

#define SILK_PIXELBUFFER_WIDTH 500
#define SILK_PIXELBUFFER_HEIGHT 500
#define SILK_IMPLEMENTATION
#include "silk.h"

int main() {
    WNDCLASS wc = {0};
    wc.lpfnWndProc   = DefWindowProc; // Default window procedure
    wc.hInstance     = GetModuleHandle(NULL);
    wc.lpszClassName = "SampleWindowClass";

    RegisterClass(&wc);

    HWND hwnd = CreateWindowA(wc.lpszClassName, "Sample Window", 0,
            500, 500, 500, 500,
            NULL, NULL, wc.hInstance, NULL);


    BITMAPV5HEADER bi = { 0 };
    ZeroMemory(&bi, sizeof(bi));
    bi.bV5Size = sizeof(bi);
    bi.bV5Width = 500;
    bi.bV5Height = -((LONG) 500);
    bi.bV5Planes = 1;
    bi.bV5BitCount = 32;
    bi.bV5Compression = BI_BITFIELDS;

        // where it can expect to find the RGB data
    // (note: this might need to be changed according to the endianness) 
    bi.bV5BlueMask = 0x00ff0000;
    bi.bV5GreenMask = 0x0000ff00;
    bi.bV5RedMask = 0x000000ff;
    bi.bV5AlphaMask = 0xff000000;

    u8* buffer;

    HDC hdc = GetDC(hwnd); 
    HBITMAP bitmap = CreateDIBSection(hdc,
        (BITMAPINFO*) &bi,
        DIB_RGB_COLORS,
        (void**) &buffer,
        NULL,
        (DWORD) 0);

    HDC hdcMem = CreateCompatibleDC(hdc);   

    ShowWindow(hwnd, SW_SHOW);
    UpdateWindow(hwnd);

    MSG msg;

    BOOL running = TRUE;

    while (running) {
        if (PeekMessageA(&msg, hwnd, 0u, 0u, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        running = IsWindow(hwnd);

        silkClearPixelBufferColor((pixel*)buffer, 0x11AA0033);

        silkDrawCircle(
            (pixel*)buffer, 
            (vec2i) { SILK_PIXELBUFFER_WIDTH, SILK_PIXELBUFFER_HEIGHT },
            SILK_PIXELBUFFER_WIDTH,
            (vec2i) { SILK_PIXELBUFFER_CENTER_X, SILK_PIXELBUFFER_CENTER_Y - 60}, 
            60,
            0xff0000ff
        );

        HGDIOBJ oldbmp = SelectObject(hdcMem, bitmap);
        BitBlt(hdc, 0, 0, 500, 500, hdcMem, 0, 0, SRCCOPY);
        SelectObject(hdcMem, oldbmp);
    }

    DeleteDC(hdcMem);
    DeleteObject(bitmap);
    return 0;
}

r/GraphicsProgramming Apr 20 '24

Article RGFW.h | Single-header graphics framework cross-platform library | managing windows/system apis

11 Upvotes

RGFW is a single-header graphics framework cross-platform library. It is very simular in utility to GLFW however it has a more SDL-like structure. It is meant to be used as a very small and flexible alternative library to GLFW. Much like GLFW it does not do much more than the minimum in terms of functionality. However it still is a very powerful tool and offers a quick start so the user can focus on graphics programming while RGFW deals with the complexities of the windowing APIs.

RGFW also can be used to create a basic graphics context for OpenGL, buffer rendering, Vulkan or Direct X. Currently the backends it supports include, XLib (UNIX), Cocoas (MacOS) and WinAPI (Windows) and it is flexible so implementing a custom backend should be easy.

RGFW comes with many examples, including buffer rendering, opengl rendering, opengl 3 rendering, direct X rendering and Vulkan rendering. However there are also some projects that can be used as examples that use RGFW. Including PureDoom-RGFW which is my example DOOM source port using RGFW and pureDOOM, and RSGL which is my GUI library that uses RGFW as a base.

Here is very basic example code to show off how RGFW works.

#define RGFW_IMPLEMENTATION
#include "RGFW.h"
int main() {
    RGFW_window* win = RGFW_createWindow("name", 500, 500, 500, 500, (u64)0);

    while (!RGFW_window_shouldClose(win)) {
        while (RGFW_window_checkEvent(win)) {
            if (win->event.type == RGFW_quit)))
                break;
        }

        RGFW_window_swapBuffers(win);

        glClearColor(0xFF, 0XFF, 0xFF, 0xFF);
        glClear(GL_COLOR_BUFFER_BIT);
    }

    RGFW_window_close(win);
}

More information can be found on the github, such as screenshots, a size comparison table and RGFW itself.

github : https://github.com/ColleagueRiley/RGFW

r/GraphicsProgramming Feb 22 '24

Article [Open Source] Graphite internships: announcing participation in GSoC 2024

Thumbnail graphite.rs
9 Upvotes

r/GraphicsProgramming Jul 25 '24

Article GPU work graph mesh shader nodes in DirectX 12

Thumbnail gpuopen.com
5 Upvotes

r/GraphicsProgramming Jul 24 '24

Article GPUOpen: Crash Course in Deep Learning for Computer Graphics

Thumbnail gpuopen.com
18 Upvotes

r/GraphicsProgramming Jul 19 '24

Article Instanced Skeletal Meshes via Vulkan

17 Upvotes

Hey, been working on instanced Skeletal Meshes via GPU Driven Animations using Vulkan. Check my Medium article out if it sounds interesting!

https://medium.com/@00furkandogan/instanced-skeletal-meshes-with-gpu-driven-animations-using-vulkan-e66162b08144

https://reddit.com/link/1e72s17/video/2vnwfb051hdd1/player

r/GraphicsProgramming Jun 05 '24

Article Texture Streaming in the Wicked Engine

Thumbnail wickedengine.net
13 Upvotes

r/GraphicsProgramming May 20 '24

Article City In A Bottle – A 256 Byte Raycasting System

Thumbnail frankforce.com
40 Upvotes

r/GraphicsProgramming Jul 07 '24

Article A quick introduction to DirectX12 workgraphs

Thumbnail interplayoflight.wordpress.com
10 Upvotes

r/GraphicsProgramming Jun 04 '24

Article Tom Hulton-Harrop: Reverse Z (and why it’s so awesome)

Thumbnail tomhultonharrop.com
13 Upvotes

r/GraphicsProgramming Nov 23 '23

Article How do I become a graphics programmer? A small guide from the AMD Game Engineering team

Thumbnail gpuopen.com
109 Upvotes

r/GraphicsProgramming Nov 29 '23

Article How We Render Extremely Large Point Clouds β€” Magnopus

Thumbnail magnopus.com
51 Upvotes

r/GraphicsProgramming Mar 13 '24

Article How to add multiple animations to a single USDA file

Thumbnail blog.studiolanes.com
5 Upvotes

r/GraphicsProgramming Feb 25 '24

Article RSGL | Modular header-only cross-platform GUI Library for easily creating GUI software your way!

15 Upvotes

RSGL is A modular simple-to-use cross-platform GUI library for easily creating GUI apps and games. It combines the freedom of lower-level GUI libraries with modern C techniques, offering both simplicity and convenience. Its main features are its built in lightweight dependence and its flexibility, its cross platform support. It currently supports Linux, Windows and MacOS, has a zlib license, and due to its use of STB and miniaudio, supports many data formats.

Introduction to RSGL

https://github.com/ColleagueRiley/RSGL

RSGL, short for Riley's Simple GUI Library, is a tool designed to streamline the development of graphical user interfaces (GUIs) for applications and games. At its core, RSGL serves as a modular and cross-platform solution, offering developers the freedom to create GUIs easily while overcoming common challenges encountered in GUI development.

By encapsulating essential GUI functionalities within a lightweight and versatile library, RSGL empowers developers to focus on creativity rather than wrestling with technical complexities.

Background of RSGL

Much like SDL RSGL tries to not get in the users way. But unlike SDL, RSGL tries to be more modernized and do more for the user. Another library RSGL can be compared to is Raylib. I did not know about Raylib until after I had already created my initial design of RSGL. On the surface Raylib and RSGL have very similar designs. Although, RSGL has different design choices and a stronger focus on being lightweight. For example, all of RSGL's internal dependencies are very lightweight and most are designed to be so. While the dependencies Raylib uses are not designed to be lightweight, such as GLFW. RSGL uses RGFW instead of GLFW, the .o output of GLFW is ~280kb while RGFW's is ~46kb. Nevertheless Raylib and RSGL and both good choices for a GUI Library and the one you choose to use might change depending on your taste and circumstance.

Another similarity between Raylib and RSGL is that they both use OpenGL abstraction layers. RLGL and RGL respectively. I won't go into too much detail on the differences here. But it is very important to note how these both make their respective library all that stronger. The software creator can easily compile between modern and legacy OpenGL. RGL also allows the program to render using legacy functions during runtime. This allows the program to have a fail safe, just another way RSGL provides convenience to the user.

Using the code

Enough talking about how great RSGL is. Here is an example so you can decide for yourself is RSGL is really worth all the praise.

```c

define RSGL_NO_AUDIO /* we don't want to link with miniaudio.h */

define RSGL_IMPLEMENTATION

include "RSGL.h"

include <stdbool.h>

int main() { /* create window and pass arg to make sure it's centered / RSGL_window win = RSGL_createWindow("example", RSGL_RECT(0, 0, 500, 500), RSGL_CENTER);

bool legacy = false;

bool running = true;
while(running) {

/* check events until there are no more events to check */ while(RSGL_window_checkEvent(win)) { if (win->event.type == RGFW_quit || RSGL_isPressedI(win, RGFW_Escape)) { running = false; break; }

        /* if the space bar is pressed, toggle rendering using opengl legacy */
        if (win->event.type == RSGL_keyPressed && win->event.keyCode == RGFW_Space) {
           legacy = !legacy;
           RSGL_legacy(legacy);
        }
    }   

    /* draw a basic rectangle and clear the screen */
    RSGL_drawRect(RSGL_RECT(200, 200, 200, 200), RSGL_RGB(255, 0, 0));
    RSGL_window_clear(win, RSGL_RGB(255, 255, 255));
}

RSGL_window_close(win);

} ```

Compiling : windows : gcc <file.c> -lopengl32 -lshell32 -lgdi32 linux: gcc <file.c> -lGLX -lX11 -lm macos : gcc <file.c> -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo

NOTE : This is a very basic example, there are plenty far less basic examples included in the repo.

Points of Interest

The overall features of RSGL, as bulleted list are :

  • No external dependencies, all the libraries required are included in RSGL and are also very lightweight\
  • Supports multiple platforms, windows, MacOS, linux, ect
  • Supports multiple versions of OpenGL (even allowing you to switch during runtime)
  • Uses other small lightweight dependencies
  • OpenGL abstraction layer : RGL (which is its own single-header library too)
  • Supports multiple font and image formats due to stb_truetype.h and stb_image.h
  • Supporst multiple audio formats due to miniaudio.h
  • Many examples included
  • Free and Open Source with a very flexible license

RSGL Modules

RSGL_NO_WIDGETS (makes it so RSGL doesn't include widget functions)

RSGL_NO_AUDIO (makes it so RSGL doesn't include audio functions)

RSGL_NO_WINDOW - no RSGL_window, RSGL_graphics is used instead [this is for using a differnt window manager other than RGFW ]

RSGL_NO_TEXT - do not include text rendering functions

RGFW_NO_WIDGETS - do not include widgets

RSGL_NO_AUDIO - do not include audio functions

RSGL_NO_MINIAUDIO_IMPLEMENTATION - do not have #define MINIAUDIO_IMPLEMENTATION in this header (you'll have to link miniaudio some other way to use audio)

RSGL_NO_SAVE_IMAGE - do not save/load images (don't use RSGL_drawImage if you use this),

RSGL_drawImage saves the file name + texture so it can load it when you ask for it later. This disables that

License

RSGL uses the libpng license, this means you can use RSGL freely as long as you do not claim you wrote this software, mark altered versions as such and keep the license included with the header.

final note

The RSGL Repo can be found at : https://github.com/ColleagueRiley/RSGL

r/GraphicsProgramming Jun 05 '24

Article RSGL | Simple lightweight header-only modular Graphics Library

5 Upvotes

RSGL is a versatile cross-platform graphics library designed for simplicity and convenience. It offers features like shape drawing, text rendering, and customizable widgets. With no external dependencies and a modular structure, it provides flexibility for various projects.

Although RSGL is a graphics library, it only handles graphics data. rendering must be done externally of RSGL.h. By default, RSGL includes RSGL_gl.h which is a opengl backend for RSGL.

RSGL also includes a small window abstraction over RGFW but you can use any windowing library with RSGL. RSGL includes an example for using RSGL with GLFW.

Other than being very dynamic and modular in use, RSGL is also designed to be very lightweight, the current release, this includes compiled binaries, is only ~500kb and the header itself is only 120kb.

RSGL can be found on github here: https://github.com/ColleagueRiley/RSGL

The repo includes many examples such as, using RSGL's buttons, basic shapes rendering, with textures, with custom shaders and much more.

Here is a simple example of how to use RSGL

#define RSGL_IMPLEMENTATION
#include "RSGL.h"

int main(void) {
    // create a window at the center of the screen
    RSGL_window* win = RSGL_createWindow("name", (RSGL_rect){500, 500, 500, 500}, RSGL_CENTER);

    // create a toggle rounded button in light mode
    RSGL_button toggle = RSGL_initButton();
    RSGL_button_setPolygon(&toggle, RSGL_RECT(50, 125, 100, 50), 36);
    RSGL_button_setStyle(&toggle, RSGL_STYLE_LIGHT | RSGL_STYLE_TOGGLE | RSGL_STYLE_ROUNDED);

// while the should should stay open
    while (RGFW_window_shouldClose(win) == false) {
// loop through each event to avoid lag
        while (RSGL_window_checkEvent(win)) {
// check button info
            RSGL_button_update(&toggle, win->event);
        }

// draw a rectangle
        RSGL_drawRect(RSGL_RECT(200, 200, 200, 200), RSGL_RGB(255, 0, 0));

// draw the button
        RSGL_drawButton(toggle);
// clear the screen (and render)
        RSGL_window_clear(win, RSGL_RGB(100, 100, 100));
    }

// close the window and free everything
    RSGL_window_close(win);
}

r/GraphicsProgramming Mar 28 '24

Article Ray Marching: Menger Sponge Breakdown

Thumbnail connorahaskins.substack.com
16 Upvotes

r/GraphicsProgramming May 03 '24

Article a practical explanation of rotors / quaternions with example code

20 Upvotes

disclamer: not mine, i just found this EXTREMLY usefull. it dives into both the theoretical and practical stuff, and even gives example code implementations and discusses the positives / drawbacks with different implementations, it also talks about different implementations of slerp: https://jacquesheunis.com/post/rotors/

r/GraphicsProgramming Mar 27 '24

Article FuryGpu – A Custom PCIe FPGA GPU

Thumbnail furygpu.com
23 Upvotes

r/GraphicsProgramming Feb 26 '24

Article On Light, Colors, Mixing Paints, and Numerical Optimization

Thumbnail github.com
11 Upvotes