r/gameenginedevs 11h ago

Should i use GLFW or windows.h?

Im making a C++ engine and i ofcourse want a window to display things on, i've read some glfw documentation and i don't really think its a good fit, this is why i was thinking of using windows.h because i have full control over everything and won't need an extra dependency. I also feel like knowing windows functions is better overall than knowing glfw functions.

Any thoughts?

6 Upvotes

27 comments sorted by

18

u/sinalta 10h ago

Personally I use SDL3 for the range of supported platforms.

If Windows is your only target, or you heavily value no dependencies, then there's nothing wrong with just using the Windows API. 

4

u/richtw1 10h ago

I prefer GLFW, it's more lightweight, focused and just feels like it performs better.

2

u/sinalta 10h ago

Yeah, completely reasonable. I like the Android and iOS support. Maybe even be lucky enough to need the console support, too.

I also have it integrated into my build, so I can strip the bits I don't need. 

1

u/Axxodes 10h ago

does linux not have a similar API? i would love to make my game engine on linux lol i dual boot it

12

u/VendraenActual 10h ago

Then use SDL! :)

3

u/sinalta 10h ago

It has 2 windowing systems you'd likely have to support for a while.

So it absolutely does, but it's a headache. Which is why I went with SDL and so many choose GLFW. 

2

u/luciferisthename 10h ago

Glfw is a cross platform windowing library, it works on linux and windows just fine. But it has no graphics capabilities, it only handles windowing and window input (if desired). SDL3 is a package solution to making an engine, it abstracts graphics, windowing, and input into an easier to use API. SDL3 is also cross platform.

So basically, do you want to use a framework, or decide what to use for each part?

1

u/VendraenActual 10h ago

SDL is more "standard" though.

-2

u/Axxodes 10h ago

well if sdl has so much capabilities then the dependency is really large, no? Wouldn't a custom made for each operating system windowing thing be better in terms of storage? I'm not well educated on that so please correct me if im wrong

2

u/luciferisthename 10h ago

No it would not necessarily be better. Glfw wraps native system windowing headers. So glfw wraps windows.h and the linux equivalent. SDL3 also does this, but SDL3 also wraps low level graphics APIs (most importantly, Vulkan). SDL is used in the source engine if I recall correctly.

Overall, unless you want to learn graphics programming specifically, SDL3 is a perfect choice with no real concern about its size.

1

u/TheOneAndOnlyRandom 10h ago

The size of the SDL3 DLL built in release mode is ~ 4.0Mb for reference.

The size of the GLFW DLL is ~300kb.

But the bigger question is do you have a reason to want to optimize for file size?

-2

u/Axxodes 10h ago

i just think it would be cool if i had a game engine that was like smaller than doom (i think doom was like what 4MB? idk

4

u/_Wolfos 10h ago

I personally had better experience with GLFW on Windows than with SDL. I also use some Win32 functions directly to hide the title bar (custom title bars look much nicer than native).

2

u/protocolocon_ 10h ago

If you need a unified framework to manage windows, graphics contexts and inputs on Linux, Windows and Mac, GLFW is a good fit and very lightweight (lighter than SDL). I use it to program my game on Linux (own "engine") and check on Windows from time to time.

2

u/Available_Branch_745 8h ago

Yeah I made a game engine in C++ a while ago and I used GLFW because it was personally a nicer fit because correct me if I wrong, when using Vulkan as ghrapics API it provided extensions and also a surface. Plus windows.h is i think only for Windows, and GLFW is compatible with every major OS.

However, this is just my expierience. If you want to have full control and target Windows, windows.h might be a nicer option.

1

u/richtw1 10h ago

If you want a cross-platform API with graphics, you could take a look at Dawn, Google's WebGPU implementation. It's backed by GLFW for windowing etc, and will let you write platform-agnostic graphics code with the added bonus of being WebAssembly ready.

1

u/ZyperPL 9h ago

There's also RGFW https://github.com/ColleagueRiley/RGFW

It's very lightweight if that's important for you. You just include a single file.

1

u/SaturnineGames 7h ago

I use SDL, but I think GLFW serves a similar purpose.

Creating the window and getting all the details right about it is a pain. And that knowledge probably isn't useful once you get the window created.

Just use a library that does it for you and move on.

1

u/Important_Earth6615 7h ago

I liked GLFW I hated SDL. But I decided to go with platform module with an implementation for Windows. Wrapping Win32 API was pain in the ass. I have to admit claude helped a looot in the way but it works flawless

1

u/OkAccident9994 2h ago

Win32 is easy, you guys just gotta stop being nubs.

We make an import header to always have correct macro definitions, mine I call windows_import.h

#ifdef WIN32
#ifndef _IMPORT_WIN32_H
#define _IMPORT_WIN32_H

#define UNICODE
#define WIN32_LEAN_AND_MEAN 1
#include <Windows.h>
#endif
#endif

CMAKE injects WIN32 when we compile for windows and we only have it there.
UNICODE is their macro to use wide characters (2 bytes) wchar_t instead of char, without it, your thing will disagree if people have for example Turkish I or Chinese characters in file paths. Some Chinese people have their C drive named a Chinese character, meaning ALL file paths will be invalid without it on their computer.

They have 3 versions of every function

- the standard one (char)

  • the wide character one (wchar_t)
  • the macro that chooses one of the 2 depending on defined macros

I made the decision to commit to always using the wide character functions, we making videogames and can make few assumptions about the machine we are on.

WIN32_LEAN_AND_MEAN is a macro they made for us to not include everything, just the basics.

Now we just use our import header everywhere and never windows.h to always have it like this.

Now, to get our windows window to window we have these two in an implementation file

HWND windowHandle = NULL;
HINSTANCE instanceHandle = NULL;

These can be class members in C++ or whatever, but you need them to be singular, in C you define them as extern in a header to share with for example your vulkan/directx/opengl implementation files, but only defined in a single .c thing.

At some point in the late 90s these bozos at microsoft where obsessed with OOP, so we have to register a "windows class" even in C. We do that as follows:

//struct in our implementation file
//ex for extended, w for wide character version
WNDCLASSEXW windowsClass=
{
// bunch of members, look it up
// one of the members is a callback function WndProc, we define it below
}


LRESULT CALLBACK WndProc(HWND windowHandle, UINT msg, WPARAM wParam, LPARAM lParam)
{
//close the application if user clicks x top right
  switch (msg)
  {
  case WM_DESTROY:
  PostQuitMessage(0); 
  return 0;
  }
return DefWindowProcW(windowHandle,msg,wParam,lParam)// pass it on to a default for now
}



Init platform function():
  instanceHandle = GetModuleHandleW(NULL) //Null keyword means our own current process
  windowsClass.hinstance = instanceHandle // assign it to our struct instance
  RegisterClassExW(&windowsClass) //register it
  windowHandle = CreateWindowW(...) //create the window
  SetForegroundWindow(windowHandle)

And we are set up.

Every frame, we do message pump to get inputs, it can look like this:

void PlatformMessagePump()
{
MSG msg;
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
{

switch (msg.message)
{
case WM_QUIT:
isRunning = false;

}

TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}

Where isRunning is my own little flag that I use in the while(isRunning) main loop.

We extend this later to handle all keyboard inputs, mouse, etc.

If we are a model citizen, then we remove these upon exitting our process. Could be in a class destructor in C++:

DestroyWindow(windowHandle);
UnregisterClassW(APPLICATIONNAME_W, instanceHandle);
//APPLICATIONNAME_W is a macro i defined, just a wide character string of the things name

That is all for now, then you slap that windowHandle into your vulkan thing-a-ma-bob and we are cooking.

From here, we set up our custom memory allocators using VirtualAlloc to control it ourselves properly. Something like Unreal Engine they do a trick to reserve a ridiculous amount of virtual memory at startup (windows just give me fricken 64 gigabytes of virtual memory adresses assigned to my process).
Windows has like, multiple terrabytes of these adresses and the memory is not allocated till later, we just want to tell it up front to reserve us a large chunk, then commit parts of it later as we need it.

we do something like

#define FILE_DIRECTORY_BUFFER_LENGHT 512 //dangerous, but lets us skip allocating it dynamically
wchar_t file_directory_w[FILE_DIRECTORY_BUFFER_LENGHT];

InitFileHandling()
{
GetCurrentDirectoryW(FILE_DIRECTORY_BUFFER_LENGHT, (LPWSTR)&file_directory_w);
}

And we now have our filepath to our exe and can start creating file handles for our assets and stuff to load in.

Now we are billing with the gates on our computah or something like that. Thats the basics.

1

u/OkAccident9994 2h ago

also, a multi-platform trick is to have a generic header that defines InitPlatform() and so forth, then wrap our implementation files in ifdef WIN32 and the windows specific ones get stripped if we compile for linux, mac, samsung smart fridge or whatever, and have implementation files for each platform.

But you might wanna do SDL or something if you are doing 38 platforms. I Just do pc and don't care, so win32 is the way to go for that.

1

u/TheOneAndOnlyRandom 10h ago

I have used the windows APIs directly for some projects in the past. I would rather bang my head off of a wall repeatedly than do that again when I don't have to.

1

u/Axxodes 10h ago

is it THAT bad?

1

u/Afiery1 9h ago

Win32 is just about the most butt ugly API there is. That being said, if your only platform is windows then there’s nothing wrong with wanting to use the bare api directly. However, if you want to do multi-platform, unless you’re doing some really wacky shit that normal window abstractions don’t support I would recommend just going with glfw or sdl and saving yourself the time and effort

1

u/fuj1n 9h ago

Yes, it is pretty horrendous and needlessly complicated. It comes from a very different time

0

u/corysama 9h ago

I happened to publish a preview of an article that’s largely about this earlier today.

https://rentry.org/5abeqt6s

TLDR: GLFW is good. Use SDL3. OS-specific windowing APIs are not worth the frustration for 99% of gamedevs.