[HN Gopher] RGFW: Single-header C99 window abstraction library
       ___________________________________________________________________
        
       RGFW: Single-header C99 window abstraction library
        
       Author : klaussilveira
       Score  : 144 points
       Date   : 2024-11-22 21:31 UTC (1 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | colleagueRiley wrote:
       | Thanks :)
        
       | CyberDildonics wrote:
       | I love single header libraries and I like the idea here of taking
       | care of one necessity well. It seems like good modularity all
       | around.
       | 
       | A quick heads up, the micro UI emscripten example doesn't work on
       | chrome or firefox. The error is: _DrawElements doesn 't actually
       | prepareClientAttributes properly._
        
         | colleagueRiley wrote:
         | I'm aware of the errors for the micro UI (on the web), it's
         | something I plan on looking into soon!
        
         | ranger_danger wrote:
         | The one big downside I see is that if you want to actually work
         | on the library itself, it's a pain to have to re-compile the
         | entire thing every time you change something.
         | 
         | Nuklear (https://github.com/Immediate-Mode-UI/Nuklear) uses
         | separate files with a deploy script that combines them all into
         | a single header; I think that approach is quicker for iterating
         | on the code.
        
           | colleagueRiley wrote:
           | Sure, but the library is also relatively small, so it
           | compiles quickly. Although if you want to you can compile it
           | on its own.
           | 
           | It's also possible to compile it on its own using `gcc -c -x
           | c -D RGFW_IMPLEMENTATION RGFW.h`
           | 
           | Nuklear is not a true single-header style library, it only
           | uses that as a format. The difference is that the design is
           | far less compact and lightweight than a stb-style library.
           | 
           | I'm pretty sure GLFW has some files that are nearly the same
           | size as RGFW, for example.
        
             | ranger_danger wrote:
             | Why do you claim Nuklear is not a "true single-header style
             | library"? And who gets to say what that even means?
        
               | colleagueRiley wrote:
               | It is a single-header library in terms of the format,
               | yes. But it is also not designed to be a single-header
               | library, unlike an STB-style library.
               | 
               | Nuklear is a full-sized library that can be compiled into
               | and used as one file. However, RGFW and STB are designed
               | to be lightweight and minimalistic. That's the
               | distinctive part of single-header libraries, also known
               | as STB-style libraries.
               | 
               | To be clear, I don't mean this to hate on Nuklear, it's a
               | cool UI library, but its design doesn't match the single-
               | header format.
        
               | ranger_danger wrote:
               | How is it not designed to be a single-header library? The
               | README even directly states "Single-header library".
               | 
               | How is it not designed to be lightweight and
               | minimalistic?
               | 
               | How do you think the design differs from your idea (which
               | is what exactly?) of a "single-header format"?
        
               | colleagueRiley wrote:
               | https://github.com/SasLuca/glfw-single-
               | header/blob/master/ex...
        
               | ranger_danger wrote:
               | What is this supposed to be telling me? This also looks
               | like it was multiple files concatenated together because
               | there are multiple different header guards throughout the
               | file.
        
           | CyberDildonics wrote:
           | Have you actually tried? This is 287 KB of C. MSVC on
           | computers from 15 years ago will compile C at about 60 MB/s.
           | I'm skeptical this is actually a problem.
           | 
           | SQLite is distributed as a single 6 MB .c file and compiles
           | in ... 0.1 seconds.
        
             | jstimpfle wrote:
             | That may be true for extremely simple source code, but it's
             | almost too good to be true. Your number sounded so
             | impressive that I tried with gcc (12.2) on my Linux VM.
             | With -O0, it takes around 27s, with -O2 it's 1m07s.
             | 
             | With -E (only preprocess) we are at around 0.320s for the
             | 260K lines of sqlite3.c. Which makes sense, 1M lines/s for
             | the preprocessor and maybe also the AST should be doable
             | (that may be where you got your 60MB/s number from). But
             | compiling is something else.
             | 
             | MSVC may be faster here or not, I haven't tested it.
             | 
             | A more modern machine (mine is a i5-7600K from 2018) may be
             | 2x or more faster, and running on multiple threads will
             | speed up the build as well.
        
               | mandarax8 wrote:
               | What exactly did you try to compile and how?
               | $ time gcc -x c  -c RGFW.h -D RGFW_IMPLEMENTATION -fPIC
               | -D RGFW_EXPORT       0.42s user 0.03s system 93% cpu
               | 0.485 total
        
               | jstimpfle wrote:
               | sqlite3, if you read carefully again.
        
               | CyberDildonics wrote:
               | _(that may be where you got your 60MB /s number from)_
               | 
               | It's not that. I think I messed up and the 0.1 seconds
               | was tcc and msvc was 1 or 2 seconds. Nothing was 27
               | seconds. Try tcc, even though you are in a VM it should
               | be very fast as a baseline for what's possible.
               | 
               | The point is that some people talk about single header
               | files being slow are really saying "what if". C is
               | incredibly fast to compile and the slow parts are the
               | overhead from each compilation unit and the optimizers.
               | 
               | 287 KB of source code added to a compilation unit is
               | nothing in the modern era. Not only that, but you can
               | just choose to put a lot of them in the same compilation
               | unit and not touch it again.
               | 
               | Every time I've used single file header libraries it
               | makes things simple and fast. I'm not going to change
               | them so dumping them all into a single compilation unit
               | is fine.
        
       | felipefar wrote:
       | You could support mobile platforms as well. IIRC, even if Android
       | allows creating only one window per activity, this behavior can
       | be easily mapped on the abstraction that you provide.
        
         | colleagueRiley wrote:
         | That's something I plan on looking into at some point. I'm
         | unsure if I want that in the main version or a separate branch
         | for embedded devices.
         | 
         | It's low priority though because my main focus is desktop
         | applications.
        
         | slmjkdbtl wrote:
         | sokol_app.h has mobile support
        
       | dmitrygr wrote:
       | > Wayland support is very experimental and broken
       | 
       | You and everyone else, RGFW, you and everyone else.
        
         | colleagueRiley wrote:
         | X11 needs a real alternative :(
        
           | themerone wrote:
           | What do you expect from an alternative?
        
             | colleagueRiley wrote:
             | - Better API design - Not being experimental after 11 years
             | 
             | I think that Wayland actually has some steps in the right
             | direction, but overall I don't think it's actually a very
             | good alternative. It's way more low-level than X11 and a
             | lot of higher level features, like window decorations, are
             | not even officially supported.
        
           | akira2501 wrote:
           | X11 is fine. It's mostly just Video Games that need an
           | alternative. It'd be nice if there was a "pause X11 video
           | card control and give exclusive access to a single
           | application." Then there's no need to care.
        
             | ori_b wrote:
             | You just described X11's DRI (direct rendering
             | infrastructure).
             | 
             | https://en.m.wikipedia.org/wiki/Direct_Rendering_Infrastruc
             | t...
        
             | Longhanks wrote:
             | X11 is utterly broken for multi-monitor setups with
             | different resolutions at different scales (e. g. builtin
             | laptop screen @1.25x, external display at 1x or some
             | variation of that). With high resolution screens (e g. 4k
             | at only 27"), that setup is not uncommon anymore.
             | 
             | (Wayland is broken in very many other ways, though, so you
             | trade one evil for... 5 others).
        
               | alwayslikethis wrote:
               | Wayland's scaling for 1.25x and even 1.5x is not so great
               | either, though it is slowly going in the right direction
               | with wp-fractional-scale-v1
        
               | uecker wrote:
               | X was a very well designed system IMHO that could be
               | evolved via extensions (e.g. how compositing was added
               | etc.). It is sad that few people work on it anymore to
               | fix such issues.
        
             | freeone3000 wrote:
             | This actually doesn't work with modern expectations.
             | 
             | Modern games are expected to work in multi-monitor setups
             | and render in "borderless windowed" mode, so you can alt-
             | tab out to multitask, or have a comms overlay. Single
             | monitor single process gaming still _happens_ , but a good
             | 85% of setups (according to the Steam Hardware Survey) are
             | not that. There are five games I know or that actually
             | handle multimonitor natively of the hundreds I've played.
             | So we need some form of cooperative multitasking for
             | graphics with the window manager.
        
               | 1oooqooq wrote:
               | Modern good games are not expected to "render in
               | "borderless windowed" mode, so you can alt-tab out to
               | multitask"
               | 
               | Really bad games with slow multiplayer match making lobby
               | and tiresome repetitive gameplay and bad UX where you
               | need to look most of the actual game information on a fan
               | wiki, or triple A games where you have to login and enter
               | credit card information on a "launcher"... those are the
               | ones you expect to "render in "borderless windowed" mode,
               | so you can alt-tab out to multitask". Good riddance.
        
           | jll29 wrote:
           | Are you kidding? I started reading the X11 handbook series in
           | the 1980s and now it's 2024 and I'm nearly finished, and you
           | want to replace it? ;-)
        
         | amjoshuamichael wrote:
         | Yeah, I've been looking for a minimal SDL alternative for a
         | long time and I was really excited reading through this as that
         | solution, but the lack of Wayland support is a huge dealbreaker
         | for me.
         | 
         | Are there any good minimal windowing utilities that support
         | Wayland? SDL does a _lot_ I don 't need and I try to maintain
         | minimal dependencies. I suppose I could just use glfw &
         | libsoundio, haven't tried that yet.
        
           | colleagueRiley wrote:
           | As far as I know, RGFW is the only minimal windowing of its
           | kind. I guess I would suggest either targeting XWayland or
           | using GLFW.
           | 
           | The Wayland API itself also really sucks to work with, even
           | more so than Xlib....
           | 
           | But, RGFW's Wayland support will probably be improved in the
           | future. :)
        
           | PittleyDunkin wrote:
           | GLFW has worked well for me.
        
           | marcthe12 wrote:
           | Waylands problem is that to use it, you need code generation
           | so the wayland backend kinda hard to design for a header only
           | lib.
        
             | colleagueRiley wrote:
             | I just have the Makefile do the code generation, it would
             | be annoying for the user, but they can complain to Wayland
             | if they don't like it.
        
             | amjoshuamichael wrote:
             | I've seen some interesting work in doing Wayland by hand:
             | 
             | https://gaultier.github.io/blog/wayland_from_scratch.html
             | 
             | I'd also look at the work done on minimal wayland projects
             | like [foot](https://codeberg.org/dnkl/foot), which supports
             | wayland well and seems to be written by hand (see:
             | https://codeberg.org/dnkl/foot/src/branch/master/wayland.c)
        
           | vkazanov wrote:
           | Isn't SDL itself is quite minimal already? I mean, it is
           | definitely not high-level in any sense of the word.
        
             | Sharlin wrote:
             | Not minimal in the sense of "just give me a window, a
             | minimal event loop, and a GPU context/swapbuffers
             | function".
        
               | colleagueRiley wrote:
               | Even then, that's what GLFW is designed to do, and it's
               | entire source code is still far larger than RGFW's.
        
             | slimsag wrote:
             | SDL provides..
             | 
             | ..an image decoding library.
             | 
             | ..an audio input/output library.
             | 
             | ..a multi-channel audio mixer.
             | 
             | ..ttf and rtf font rendering.
             | 
             | ..networking.
             | 
             | ..runtime shader cross-compilation
             | 
             | ..its own entire graphics abstraction layer / API.
             | 
             | ..its own shader language, shader compiler, and shader
             | bytecode format.
             | 
             | I don't know at which point something becomes 'high level',
             | but SDL is only 'minimal' if you use a subset of its
             | functionality.
        
           | nextaccountic wrote:
           | Rust has a lot of those small libs, my favorite is miniquad
           | 
           | https://crates.io/crates/miniquad
        
             | Sharlin wrote:
             | Other alternatives: pixels, minifb, softbuffer.
        
               | colleagueRiley wrote:
               | Sure, but none of these are true alternatives because
               | they are missing a lot of features that libraries like
               | GLFW or RGFW have.
               | 
               | (They may be good alternatives for certain use-cases)
        
               | Sharlin wrote:
               | Oh, just based on the README I assumed RGFW was more
               | minimal than it actually is.
        
               | colleagueRiley wrote:
               | Minimal refers to the code itself.
               | 
               | GLFW's codebase is ~10MB while RGFW's is about ~300kb.
               | But RGFW tries to support nearly everything that GLFW
               | supports.
        
               | Sharlin wrote:
               | Yeah, my bad :)
        
       | garbagepatch wrote:
       | This was added to raylib as a backend recently:
       | https://github.com/raysan5/raylib/releases#:~:text=RGFW
        
       | eqvinox wrote:
       | Every time I see a "single-header C library", I wonder to myself
       | where we'd be if only Windows had a proper package manager.
       | 
       | (Especially since that'd force the POSIX world to de-fracture
       | itself too.)
        
         | perching_aix wrote:
         | > a proper package manager
         | 
         | Those are a thing? Wasn't aware.
        
           | raymond_goo wrote:
           | Isn't the one from Rust pretty good?
        
             | perching_aix wrote:
             | Haven't worked with it much yet, not really my point
             | either. They were talking about OS package managers, most
             | likely the typical Linux package managers, and so did I.
        
         | linkdd wrote:
         | scoop? chocolatey? pacman in msys2? winget?
        
           | eqvinox wrote:
           | Remind me please, which of these is shipped with a default
           | Windows install?
        
             | wis wrote:
             | I realize you asked sarcastically, but as of relatively
             | recently WinGet is shipped by default with the latest
             | versions of Windows 10 and in Windows 11. [1]
             | 
             | But why is being installed by default important?
             | 
             | [1] https://www.petergirnus.com/blog/how-to-use-windows-
             | package-...
        
               | kreetx wrote:
               | It's an adoption barrier.
        
               | 1oooqooq wrote:
               | meh. it's not.
               | 
               | If you are convincing people to run commands to install
               | packages:
               | 
               | - they care about trust, they will already have their
               | package manager from the ecosystem they trust (which
               | should be msys+pacman on windows, btw)
               | 
               | - they couldn't care less and will trust your `curl |
               | bash` or `Invoke-RestMethod -Uri
               | http://hacker.com/totallysafe.exe`
               | 
               | on both cases, not having a default package manager
               | shipped caused zero adoption attrition, I mean, besides
               | the attrition of needing a non-standard package to begin
               | with.
        
               | frizlab wrote:
               | IMHO it is though. I have a windows VM I rarely use and
               | tried using a package manager at some point, but end up
               | not succeeding until winget was part of the system and
               | was a no-brainer.
               | 
               | Too many possibilities made me choose none.
        
               | Conscat wrote:
               | I know very non-technical people who use Chocolatey for
               | acquiring ffmpeg.
        
               | eqvinox wrote:
               | It was only partially sarcastic (yeah that didn't
               | communicate at all, bad habit on my end), I had googled
               | them but didn't quite understand the winget situation at
               | glance. Thanks for the answer, actually appreciated!
        
           | flohofwoe wrote:
           | Most of those are for installing applications, not system-
           | wide C library source distributions (e.g. you'll need to
           | figure out the path of the source and header files in build
           | scripts since there's no standard location for that on
           | Windows).
           | 
           | The closest thing to a C/C++ package manager standard on
           | Windows is probably vcpkg: https://vcpkg.io/en/
        
         | colleagueRiley wrote:
         | We'd be at the same spot, single-header files are still useful.
         | 
         | A single-header file is not a 'full-sized' library compressed
         | into one file it's codebase is designed to actually be
         | minimalist. Many libraries have single files that are the same
         | size as their alternative single-header.
        
         | Philpax wrote:
         | I wonder where we'd be if we'd stopped relying on system
         | packages to provide dependencies for C / C++. It is positively
         | miserable to have to pollute your system when a codebase
         | written in Go / Rust / your favourite modern language Just
         | Works out of the box.
        
           | linkdd wrote:
           | With a central, curated, audited package repository where
           | publishing rights are given to absolutely everyone then
           | supply chain attacks in C and C++ would be even easier.
        
         | IshKebab wrote:
         | We'd be in exactly the same place because nobody wants to use
         | an OS-dependent package manager for an OS-agnostic project.
         | 
         | I don't know if you noticed but no modern languages use Linux
         | packages to provide dependencies, because that obviously sucks
         | balls for many reasons.
        
       | eska wrote:
       | Not sure whether this is tested on Windows at all. I opened the
       | header and immediately found this `typedef signed long i64`, i.e.
       | i64 is actually i32.
        
         | Conscat wrote:
         | I'm not sure that issue would be caught by ordinary testing. It
         | will implicitly cast into long long, so it might make little or
         | no difference in this case.
        
           | eska wrote:
           | A lot of people use i64 in the global namespace, so this will
           | affect later code. It's basically `#define true false`. When
           | I consider a library I will do a quick sniff test to look for
           | very obvious mistakes, at which point I won't look further.
        
             | colleagueRiley wrote:
             | :( That's disappointing, but I understand.
        
         | colleagueRiley wrote:
         | I test Windows mainly with MINGW, that might be an issue with
         | MSVC. Feel free to report the issue on the github repository.
         | 
         | I'm pretty sure windows uses "long" for 64 bit but linux uses
         | "long long" for 64 bit
        
           | tredre3 wrote:
           | > I'm pretty sure windows uses "long" for 64 bit but linux
           | uses "long long" for 64 bit
           | 
           | Windows long is 32bit even on 64bit CPUs.
           | 
           | Linux long is arch dependent and is 64bit on x64, 32bit on
           | x86.
           | 
           | long long is always 64bit on both platforms.
        
             | colleagueRiley wrote:
             | Okay, thank you.
        
           | eska wrote:
           | It's just that the #if checks for the MSVC compiler, not for
           | Windows as a platform. And on that compiler you will never
           | have LP64, but LLP64: https://en.wikipedia.org/wiki/64-bit_co
           | mputing#64-bit_data_m...
           | 
           | I just roll my own for this because I don't need all the
           | functionality, and generally find such cross-platform
           | libraries to only really test on Linux, and it's too much of
           | a hassle.
        
             | colleagueRiley wrote:
             | Yes, because MSVC may or may not have stdint.h
        
           | flohofwoe wrote:
           | Since you're using C99 as the base C version, why not use the
           | fixed-width types from stdint.h (int32_t, int64_t, ...)?
           | 
           | You can still typedef those to i32, i64 shortcuts etc, but I
           | would try to avoid this in libraries since it might collide
           | with user typedefs of the same name - or at least try to
           | avoid it in the public API declarations.
        
             | colleagueRiley wrote:
             | I use those by default although I read that MSVC's support
             | for those are iffy. I'm pretty sure STB does the same thing
             | for the same reason.
             | 
             | Source: https://handmade.network/forums/articles/t/7138-how
             | _to_write...
        
               | flohofwoe wrote:
               | Since around Visual Studio 2015 you're fine.
               | 
               | AFAIK the STB headers are on C89 mainly because nothings
               | likes to use VC6 as C IDE.
               | 
               | E.g. if you depend on other C99 features anyway,
               | including stdint.h is fine, also on MSVC.
               | 
               | PS: FWIW I use stdint.h types in the Sokol headers since
               | around 2017 and never heard complaints from users, with
               | the supported compilers being MSVC, GCC and Clang.
        
               | colleagueRiley wrote:
               | Oh, I wasn't sure if that was you :)
               | 
               | Thanks for the advice, I'm a little worried about
               | breaking compatibility with compilers that don't support
               | stdint. But if it's standard for C99 thing then sure.
        
               | eska wrote:
               | _Since around Visual Studio 2015 you 're fine._
               | 
               | I personally use `_MSC_VER >= 1600`, so it's since Visual
               | Studio 2010 from April 2010. Built-in types like __int32
               | from before then may be used as well.
        
         | InfiniteRand wrote:
         | It depends whether you're compiling in 32-bit or 64-bit mode,
         | MSVC has two different modes and there are different versions
         | of MinGW for 32-bit and 64-bit
        
           | tom_ wrote:
           | For MSVC, long is 4 bytes: https://learn.microsoft.com/en-
           | us/cpp/cpp/fundamental-types-...
        
         | bluecalm wrote:
         | This is strange because C99 has stdint.h so we don't need to
         | use "short/long/long long/long long long" nonsense anymore.
        
       | uecker wrote:
       | I like simple code written in C, but when does this "single-
       | header" nonsense stop? C has super nice and simple modularization
       | via the classical .h/.c split which ensures fast compilation,
       | proper encapsulation, no instruction bloat via creating multiple
       | instances for all functions.
        
         | colleagueRiley wrote:
         | Try putting GLFW's source code into one file and then compile
         | it. That will take at least a few seconds, RGFW compiles in
         | less than a second.
         | 
         | Where's the bloat? :)
         | 
         | https://github.com/SasLuca/glfw-single-header/blob/master/ex...
        
           | uecker wrote:
           | The issue if if you have many such libraries and any change
           | to the implementation forces recompilation of everything.
           | Maybe not such a big deal for such small libraries, but an
           | annoying trend IMHO.
        
         | tredre3 wrote:
         | > no instruction bloat via creating multiple instances for all
         | functions.
         | 
         | This makes me think that you're using single-header libraries
         | wrong. These kind of libraries usually require you to do
         | something special prior to including it to get the actual code
         | and you must do it only in ONE file.
         | 
         | For example, you'd #define RGFW_IMPLEMENTATION before #include
         | rgfw.h in exactly ONE .c. If you need the header in other
         | files, you do NOT define RGFW_IMPLEMENTATION and no code will
         | be produced.
        
           | uecker wrote:
           | Well, I do not use them at all. But I agree that this
           | mechanism would avoid the additional copies. I have seen
           | other single-header libraries though...
           | 
           | In any case, forcing me to figure out the specific
           | XYZ_IMPLEMENTATION for each library is less user friendly
           | that just proving a .c and .h file.
        
         | CyberDildonics wrote:
         | I can't figure out why anyone would call it 'nonsense'. The
         | definitions and functions have to be together, they may as well
         | be a single file separated by a preprocessor definition.
         | 
         | Include the header where you want the definitions. Include the
         | header and use the preproccesor definition in the compilation
         | unit you want the functions in. Done.
         | 
         | There is no speed issue here. It would take 100x the C to make
         | a difference and it's actually going to be much faster and
         | simpler to put a lot of single file libraries into one
         | compilation unit. I always wonder if the downsides are
         | theoretical or if people are really doing what I've been doing
         | and still have a problem with it.
        
       ___________________________________________________________________
       (page generated 2024-11-23 23:00 UTC)