Page 1 of 1

Rant

Posted: May 31st, 2020, 11:18 pm
by albinopapa
I've said it before, but I'm gonna say it again, I seem to prefer writing libraries over games and what I've got going on right now is kicking my ass. I now have a new appreciation for the C++ standards committee and other library designers.

If I have my story straight back in 2013-2014 it was suggested that C++ should have some sort of 2D graphics capabilities. The motivation behind this was to make learning C++ more fun for new programmers like what chili has done. Fast forward a few years around 2017-2018 or so and a few people from the committee decided to write up a proposal and possible implementation. It was decided that instead of starting from scratch, the proposal and example implementation would be based on a C library called Cairo.

Normally the standards committee use well established libraries such as boost. The reason for this is the implementors have had a chance to work out as many bugs as possible and it helps establish a user base to determine how desirable the feature or feature set is.

One problem with using Cairo is it's a C library and it would have to be converted to C++ or basically a C++ wrapper around the Cairo library.
Another issue, was a few people were concerned that the scope of what the 2D graphics library using Cairo was too large and the STL should start with the building blocks that lead up to a 2D graphics library.

For instance, we don't even have a standardized type that represents a Point. Std::pair is the closest, but who wants to write:

Code: Select all

if( position.first < radius || position.first >= screen_width - radius )
{
    velocity.first *= -1.f;
}
While .first and .second would have the same meaning as .x and .y, the intention doesn't seem as clear.

I would have to agree with whomever made this point. Right now there are so many libraries out there that have to create their own point or vector representation which means there is little in the way of interoperability aside from creating conversion functions. It would be nice to have a standard point or vector2 type.

Same could be said about matrices as well.

With the position and transformations out of the way, others have mentioned that to make it worth while, a 2D library would need to have font support. SFML for instance uses the FreeFont2 library to render utf 8, 16 and 32 encoded strings. Microsoft could of course use their DirectWrite library for loading fonts and Direct2D for rendering fonts, while Linux users would probably stick with the FreeFont2 library as I think that's what they use right now anyway.

So, positional data, transformations and font loading and rendering out of the way, the remaining parts are rendering to a surface and displaying that surface.

Rendering to a surface could be done in a few ways. One is having it down in hardware and another is like what chili's framework does and render using the CPU then transferring that surface to the GPU for display. Now, the standards committee wouldn't dream of forcing a certain implementation on standard library writers, their job is simply to design the rules that govern the interface and behavior.

One requirement was to be immediate mode rendering instead of state based rendering. This is closer to how the chili framework works. In some graphics libraries, such as Direct2D, you have a brush that you set a color to. You pass this brush to a draw function and Direct2D uses it's color information or bitmap information to draw lines using the color of the ID2D1SolidColorBrush or you can draw patterns using ID2D1BitmapBrush like tiling. This to me would be part of what state based rendering is. I'd much rather pass in a color to the function instead of having to keep around a bunch of solid color brush objects or bitmap brush objects. However, using the Cairo library as a basis for their proposal and design, the immediate mode rendering requirement was lost.

There were some other decisions that made no sense to me as well. For one, their color struct was a struct of doubles. There is no need for that much precision in color representation and some if not most graphics cards don't even process doubles, so they'd have to be converted down anyway. Plus, four doubles is 32 bytes per color, which is a complete waste especially since their surfaces only used std::uint8_t* for it's data, so nothing more than the Color struct in the chili framework.

So basically, a surface to me should be just a read/write 2D container of std::uint32_t elements that should be able to be used as a render target for custom or procedurally generated images. This would differ from a Sprite in my opinion which would be an init only 2D container that the GPU get's to display. This would be what the user controls using physics or input device input. This would allow for flexibility and performance for new users and avid users.

So far we have:
  • point
  • matrix
  • font
  • surface
So what's left? Well, user input such as keyboard, mouse, touch screens, gamepads, etc...

I've been thinking about this for a while and there are some things I'd like to point out.

The chili framework has mouse and keyboard support and the way it's setup is each device has a way of checking it's current state as well as checking for any events pushed into it's queue. I think separating these into their roles would make things simpler in most cases. If you remove the queue, you are left with current state. The current state of these objects can be queried using OS function calls such as finding out if a key is down or mouse position. The nice thing is, by separating the state from the events, getting state could be as simple as having Mouse::GetPosition() instead of passing around a Mouse object. The downside though is getting the mouse position for instance is it's current screen position and not it's current position relative to a specific window ( at least in Windows anyway ).

Now, about the input events. We could have a queue of events for each input device, then have to manage those queues or we could have a callback system where one registers callback functions for certain events like a Mouse::Event::Type::LPress. This to me seems more simple. Nothing to maintain other than registering or unregistering these callbacks. I would imagine this would require less memory also, since only the callbacks are stored and not a queue of events. The STL would need to have some sort of signal/slot API to accomplish this.

So now we have:
  • point
  • matrix
  • font
  • surface
  • input_device_state
  • signal_slot
Now, circling back around to displaying our scenes, we need a window. All GUI operating systems have them, but each handles events differently. However, now that we have a signal_slot type, we can just use it to register handlers ( slots ) for different events. With the standard library being heavily templated, it should be fairly simple to hide OS specific requirements for parameters and what not allowing the standard library to remain pretty general purpose with regards to windowing.

With that our final list is:
  • point: for positional information such as screen coordinates or character position
  • matrix: for transformations of graphics objects
  • fonts: for loading and rendering text to a surface
  • surface: for storing image data that can be modified or displayed
  • input_device_state: for polling input dievices' current state
  • signal_slot: for storing callback functions and forwarding event data to those callback functions after some event
  • windows: for displaying a surface, fonts or other graphics visuals such as lines, curves and the like.
I think this would be the bare minimum that a 2D graphics library would need to be somewhat useful for both learning C++ in a graphics environment as well as making games with enough performance to be relevant.

C++20 is suppose to kick off utf8 support with it's introduction of char8_t type. This will help in regards to fonts.

You could ask: "Where's the sound support or network support?" and I'd have to reply...maybe next time kid.

C++ will be getting networking eventually, so nothing to add on that front.

I'm not sure how a sound interface would look. Seeing as how the STL is suppose to be general purpose what would a sound interface even look like? Would you have a way of generating sound data? Would you have channels? Would it have 3D positional sound or just 2D panning? Personally, I know there are libraries out there that do all this, I just haven't taken a look at any of them to see what an interface would even look like.

Regardless, the topic at hand is the 2D graphics library, not necessarily a game library. That being said, I've been trying to implement the items listed in a way that both hides the operating system details and in such a way that looks like it could be part of the standard library. Kind of a fun learning experience at the moment. The difficult part is going to be trying to make it safe enough for general use. I'll have to come up with tests, static_assert conditions, exceptions, and other sanity checks. When completed, I'll have to get it out there and have it tested in the wild. Maybe if useful and polished, it could be part of the STL...a guy can dream right?

Re: Rant

Posted: June 8th, 2020, 9:07 am
by chili
Networking is planned for C++23 afaik :]

If only M$ would bring decent support for concepts into their IDE (intellisense) already :[

Re: Rant

Posted: June 8th, 2020, 6:05 pm
by albinopapa
Intellisense working with

Code: Select all

	template<typename T>
	concept Copyable = std::conjunction_v<
		std::is_copy_assignable<typename T::value_type>,
		std::is_copy_constructible<typename T::value_type>
	>;

	template<Copyable InIt, Copyable OutIt>
	void Copy( InIt inbeg, InIt inend, OutIt outbeg )
	{
		auto outit = outbeg;
		for( auto it = inbeg; it != inend; ++it, ++outit ) {
			*it = *outit;
		}
	}
In vs2019 16.6.1.

The feature macro __cpp_lib_concepts isn't enabled, so none of the code in <concepts> is enabled even with c++latest is chosen. Apparently, it won't be enabled until Intellisense catches up with the compiler.
Russell Johnston [MSFT] wrote: May 11 at 03:01 PM
This is intentional behavior for now. That "initial support" in IntelliSense is not quite enough to handle the library headers, so the IntelliSense compiler does not advertise that support by defining __cpp_concepts, though it does work for simple cases.

A future release will have full concepts support in IntelliSense and we will start defining the macro then.
__cpp_lib_concepts isn't defined in VS 2019 16.3.0
Well, that's for 16.3, but hasn't been enabled for 16.6 yet either.

Re: Rant

Posted: June 8th, 2020, 6:06 pm
by albinopapa
The shorthand version is going to make SFINAE sooooo much easier and cleaner hopefully.

Code: Select all

#define __cpp_lib_concepts 201907L
#include <concepts>
Defining it manually before including <concepts> seems to make the code in the header available.

Re: Rant

Posted: July 5th, 2020, 3:22 pm
by chili
Interesting... this macro is picked up by the intellisense engine then? I should try it out...