C++ and SDL2 will get you a window, events, sound and other low level stuff, and you can get support for PNGs and fonts easier by including some of nothings/stb libraries[0] (rather than the equivalent SDL libs.) Maybe toss in Lua/LuaJIT for good measure. That will scratch a lot of itches.
But IMHO it's better in the long run to just pick up Godot and save yourself months of unnecessary effort. Otherwise if you're like me you'll wind up in the weeds with nothing to show for it but a tilemap class you've rewritten a dozen times.
https://github.com/nothings/stb
> Why not C99? stdint.h, declare-anywhere, etc.
> I still use MSVC 6 (1998) as my IDE because it has better human factors for me than later versions of MSVC.
>zlib is 23k lines
It's not needed to make a PNG reader/writer. zlib is massive overkill for only making a PNG reader or writer. Here's a tiny deflate/inflate code [2] under 1k lines (and could be much smaller if needed).
stb[0] has single headers of ~7k lines total including all of the formats PNG, JPG, BMP,. PSD, GIF, HDR, and PIC. Here's [1] a 3k lines single file PNG version with tons if #ifdefs for all sorts of platforms. Removing those and I'd not be surprised if you could not do it in ~1k lines (which I'd consider quite simple compared to most of todays' media formats).
>Of course they're not common formats so you're stuck with complex formats like PNG
BMP is super common and easy to use anywhere.
I use flat image files all the time for quick and dirty stuff. They quickly saturate disk speeds and networking speeds (say recording a few decent speed cameras), and I've found PNG compression to alleviate those saturate CPU speeds (some libs are super slow, some are vastly faster). I've many times made custom compression formats to balance these for high performance tools when neither things like BMPs or things like PNG would suffice.
[0] https://github.com/nothings/stb
[1] https://github.com/richgel999/fpng/blob/main/src/fpng.cpp
https://github.com/nothings/stb
Important difference to typical C++ header-only libs: STB style libs don't use the inline keyword, but instead place the implementation into an ifdef/endif block.
It's really just for easier distribution and integration, and the difference to a single .h/.c pair isn't all that big.
Definitely not big enough to get all riled up about it - the actual problem are libraries that come in dozens of source and header files and with their own build system files, or C++ libraries which put the implementation into inline code, like most C++ stdlib headers (because this increases compilation time for every file which includes such a header).
Further: https://github.com/oz123/awesome-c as another example of the many many C libraries you could find.
By traditional reckoning, you’re almost correct, but this is an exception.
Unlike many other languages (including TypeScript AFAIK), C and C++ compilers are defined to process a self-contained piece of text (the “compilation unit”), which must declare the type of everything it uses from the outside; those are then linked together into an executable with external references bound by name, with the types blindly assumed to be correct. (The linker works at the assembly level, not the C level, the types are already gone.) The usual workaround is to have the preprocessor, which puts together said piece of text[1], pull in the declarations from a common source, the “headers”, just plain insert the declaration text into the source file. Thus the headers play a similar role to .d.ts files, but the toolchain does not impose any convention on how things are arranged in files, unlike in TypeScript, Go, or Java.
There are two downsides for this: first, the declarations go through the compiler once for every source file that uses them, yielding slower compiles; second, if you want to consume a library in source form you’ll have to marry the build system for the library with the build system for your consumer. (The “build system” is the conceptual thing that knows how to set up the header search paths, which files to compile, and how to link or otherwise package the results into build artifacts.)
An alternative to this traditional organization is the “header-only library”; it mostly eliminates the second downside at the cost of exacerbating the first.
- In the C++ world, the dumb linker model I described above is something of a lie: a lot of C++ things (vtables, inline functions, template instances, etc.) do not actually have a well-defined compilation unit they belong to (“vague linkage”), so in the simplest approach the compiler generates a definition for every compilation unit and the linker has to (know enough to be able to) throw away all of these except one. (You see where the notoriously long C++ compile times come from.) A header-only library then just bites the bullet, defines everything inline, and has the linker sort them out. These have become fairly common over the last decade. (This does not help the compile times.)
- In the C or C-ish-C++ gamedev world, there’s a practical need to get prototypes or good-enough preliminary versions out the door quickly, so the library that is easiest to integrate across as much build systems as possible has an advantage. A different variety of header-only libraries has gained traction there. These have the header contain both declarations and implementation, but the implementation is guarded by a preprocessor macro; the user of the library defines that macro in a single compilation unit that they designate as owning that implementation. (This has worse “tree-shaking” characteristics than a well-organized static library, but if the library isn’t large that’s probably not a big deal, and in any case many common libraries, such as libjpeg and libtiff, are not well organized in this sense.)
The QOI reference implementation comes from the second tradition and is probably influenced by the popular stb libraries[2].
[1] Actually a token stream.
[1] https://en.wikipedia.org/wiki/Wavefront_.obj_file
[2] https://en.wikipedia.org/wiki/Netpbm#PPM_example
[3] https://github.com/nothings/stb
See for example:
It seems like this would be an interesting approach to a lot of security programming where it involves data structures, since those have typically been a source of issues. Having a memory-safe ASN.1 parser would be really nice, considering how much difficulty that has caused in the security space.
With a lot of security programming there's a reliance on constant-time algorithms, which this may not be well-suited to, however.
Might you have a write-up or link for these, and if so might you be willing to share it?
I have been using Sean Barrett's libraries [0], as well as his curated list of other people's single-header libraries [1], and, like you, I am always on the lookout for new things to add to the collection :)
Also I would love to have a nice c++ lib for uuids. It's in boost of course.. but well that's boost. Outside of that there is one, but it requires GSL.
A few examples: https://handmadehero.org/ https://ourmachinery.com/post/physical-design/
Simple libs widely used in game dev circles: https://github.com/nothings/stb
This one is a full game engine with tools made for educational purpose: https://www.raylib.com/
I do write games and game engine code and tools in C++ without using any of the OOP features.
I know quite a few of other professional, experienced and talented developers doing the same, even full AA studios with up to 50 employees.
Some of them are going back to procedural C after a few years of disappointment with OOP madness.
I'll publish articles about this later, but for now, all I have to say is that it just works.
Newbies are often afraid of manual memory management and pointers, but there are simple ways to avoid shooting yourself in the feet with those.
(I'm not the author and don't know them, I'm just a happy user.)
The same idea can also be used for C++ headers (unless it's all template interfaces).
With such stb-style headers, you can even get better compile times, because you can include all header-libs into a single implementation source file, giving the same advantages as unity-builds (merging all sources into one file).
PS: origin of the name "stb-style": https://github.com/nothings/stb (although I guess the general idea existed before)
Its 3rd-party libraries also tend to be closer to C/C++'s "drop-in" solutions like STB[1] than the enormous JS ecosystem which often requires extra tools like Node and/or extra packages like JQuery.
Admittedly, Lua's ecosystem is much smaller than Javascript's, but in my experience Lua is vastly easier to maintain. You can certainly write bad Lua, but it's one of the only languages where I don't implicitly dread reading other people's code.
It is sort of annoying that tables which are treated like arrays are 1-indexed by convention, though.
The basic concept of these is they use macros to specify the type/size of the elements so you can have generic containers in C.
For hash's, you can also look at klib's khash [5]
[1] https://github.com/nothings/stb
[2] https://github.com/attractivechaos/klib
[3] https://github.com/nothings/stb/blob/master/stretchy_buffer....
[4] https://github.com/attractivechaos/klib/blob/master/kvec.h
[5] http://attractivechaos.github.io/klib/#Khash%3A%20generic%20...
I get some of the reasons that you would initially start out with a header-only implementation, but when your library grows, you probably want to split it at some point. For me personally, that point would be some time before the header reached 25k (!!) lines.
https://attractivechaos.wordpress.com/2008/08/28/comparison-...
(Also provides kbtree.h, ksort.h, kstream.h, kvec.h)
[3] https://attractivechaos.wordpress.com/programs/
Also there are the stb header-only libraries. There is a hash table implementation buried inside stb.h
Tiny Tcl implementations are fun in general and perhaps easier to produce than tiny Scheme implementations — as long as you are willing to concede that everything really is a string. :-) (I.e., no caching binary representations; you have to parse from scratch each time.) In a similar vein as TH1 but with a little more functionality there are Picol (https://tcl.wiki/Picol) and LIL (http://runtimeterror.com/tech/lil/).
Disclosure: I maintain an expanded fork of Picol. The original version of it written by antirez was only ~550 LOC but with suchenwi's additions and mine it is now around 3100. There is a link to it on the wiki page. The change that I am most fond of is making it an stb-style (https://github.com/nothings/stb/) header library.
A random collection of anecdotal stuff and opinions that comes to my head:
For common utilities for game development stb libraries are fantastic: https://github.com/nothings/stb
For general idea how to structure code you could google "data oriented design c++".
Try not to structure your solution around class hierarchies but prefer data pipelines.
Write your code so that it's easy to debug.
Prefer to structure your solutions around stl containers and stl algorithms.
Avoid using inheritance as long as it does not reduce code complexity. If you use inheritance prefer to use only abstract base classes. Do not use template metaprogramming unless you are absolutely sure it's the most simple way to solve your problem. Avoid multiple inheritance like the plague. Ignore my advice if your problem is such that they don't make sense.
Try not to solve any other problem than the one you have immediately in front of you, and solve it as fast and simply as possible. Do not try to create some "framework" to solve your problems but prefer simple code. Refactor your code as your program progresses. This point might be obvious - but for me personally has been the most difficult thing to learn - writing agressively simple code is the best thing I've learned. This does not mean that the abstractions that are implemented are necessarily simple - just that the implementation is as easy to read, easy to debug and easy to reason about it's dependencies, as possible.
If you can trade off complexity of dependency with a little bit more code, prefer little bit more code. I.e. if you have an itch to include a library because you need a single function, think hard about implementing or copy pasting the function to your codebase. Once you are confident enough that you know you need something, only then include it.
Learn some OCaml :) - really, I feel like much better C++ programmer after I understood how a properly designed language with a static type system works. (I hear "Real world OCaml" is a good book).
I've never seen a C or C++ codebase that does this. Maybe you can rely on link-time deduplication, but it will still cause duplicate compilation, and thus increased compile times. I haven't thought it about it lately, but I thought the common wisdom was not to depend on the linker to dedupe or strip unused symbols. Actually it should cause link-time errors, not just duplicated cause.
The justification is also somewhat ridiculous: Why single-file headers?
Windows doesn't have standard directories where libraries live. That makes deploying libraries in Windows a lot more painful than open source developers on Unix-derivates generally realize. (It also makes library dependencies a lot worse in Windows.)
Really? Why not just lay out your source normally, and then munge it with a simple script into something Windows can handle (similar to sqlite)? Because writing trivial scripts on Windows is also a pain?
[1] https://github.com/nothings/stb
[2] https://github.com/nothings/stb/blob/master/stb_c_lexer.h
>Why single-file headers?
>Windows doesn't have standard directories where libraries live. That makes deploying libraries in Windows a lot more painful than open source developers on Unix-derivates generally realize. (It also makes library dependencies a lot worse in Windows.)
>There's also a common problem in Windows where a library was built against a different version of the runtime library, which causes link conflicts and confusion. Shipping the libs as headers means you normally just compile them straight into your project without making libraries, thus sidestepping that problem.
>Making them a single file makes it very easy to just drop them into a project that needs them. (Of course you can still put them in a proper shared library tree if you want.)
>Why not two files, one a header and one an implementation? The difference between 10 files and 9 files is not a big deal, but the difference between 2 files and 1 file is a big deal. You don't need to zip or tar the files up, you don't have to remember to attach two files, etc.
To quote Sean Barrett:
Opus' non-public-domain code as spec is terrible.\n Independent implementation requires "clean room" = writing\n own specification!\n
\nSean is famous among the game developer community for providing a useful variety of public domain code (i'd call them libraries, but almost all are written to be used as a single-header file include):- glm for math (http://glm.g-truc.net/0.9.5/index.html)
- gli for texture loading (http://gli.g-truc.net/0.5.1/index.html)
- assimp for general asset loading: http://assimp.sourceforge.net/index.html
- the STB headers (not OpenGL specific): https://github.com/nothings/stb
- GLFW as window system glue and input wrapper
- ...and more which I am not aware of or forgot to list
GPU vendors also have SDKs and especially debugging tools (e.g. NVIDIA nSight which integrates into VStudio). It's not in one place like in DirectX, but on the other hand, the OpenGL world has a lot more platforms and usage scenarios to cover then D3D or the various new-style APIs like Metal or Mantle (these are the actual motivation for OpenGL-Next, reducing overhead even when this means a lower-level API which is even more focuses and harder to use then before).