Welcome, Guest. Please login or register. Did you miss your activation email?

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - binary1248

Pages: [1] 2
1
After running a few of the current project highlights through AMD GPU PerfStudio, I noticed something really interesting with the way Cendric causes OpenGL operations to be submitted to the driver.



Basically, for really huge vertex arrays, a disproportionately large amount of the time spent calling OpenGL is spent in the actual draw calls themselves. This is in stark contrast to what many might believe is the source of all the time spent using OpenGL.

The time spent in those draw calls isn't actually the time the GPU needs to render anything. Commands are still queued and submitted to the GPU to be executed asynchronously. This also isn't the time that "just has to be spent" doing what any draw call would do, otherwise the draw calls that process only 4 vertices should take just as much time.

Keeping the definitions of gl*Pointer and glDrawArray functions in mind, the spent time almost certainly has to come from the copying of the vertex data from the address space of the application into the address space of the driver for asynchronous DMA transfer to the GPU.

In this case, 19600 sf::Vertex worth of data had to be copied on every draw call (this is assuming the driver is smart and combines copying the 3 memory blocks specified by the pointers into a single copy). Since each sf::Vertex is 20 bytes big, this memory block is 392 KB. For reasons the author will know, it is submitted 8 times per frame for a total of 3136 KB and assuming we want to run at a minimum of 60 FPS, 188.16 MB per second.

Yes... 188.16 MB/s is still a long way from the GB/s memory bandwidth that we have within system RAM and between CPU and GPU, but still... If you consider that in this example, 50% of the CPU time the application needs per frame is spent merely copying data around it makes you wonder if there are any better alternatives.

(Again, this was all assuming the driver isn't stupid and making 3 copies per draw which would make it 564.48 MB/s)

I wouldn't call this a bandwidth bottleneck as is. The FPS in this game is still probably bottlenecked more by some GPU-specific factors e.g. fillrate etc. This is about letting the CPU do more useful things at the same time the GPU is eating through those commands.

Which leads me to the question: Would it make sense to introduce something like sf::VertexBuffer?

sf::VertexBuffer would be something in between sf::VertexArray and sf::Texture. Just like sf::Texture, sf::VertexBuffer would live in the GPU while it is alive, and like sf::VertexArray, it would contain an array of sf::Vertex data. Unlike sf::VertexArray, reading from an sf::VertexBuffer would be just as expensive as reading from an sf::Texture since it would incur a GPU-CPU readback. However, considering it is a very common use case to only submit data without having to read it back this wouldn't be that big of a problem.

The main advantage of sf::VertexBuffer over sf::VertexArray would be that because it lives on the GPU, it won't have to be copied every draw call. Again, this isn't just about saving memory bandwidth. In all games I measured it was never a bottleneck, although one must consider I have a pretty high end system so it might become a bottleneck on crappier systems. What is guaranteed is that the drawing thread (in Cendric's case there is only a single thread) is free to do other useful things more often during a single frame instead of spending a lot of time waiting for memory to be copied. This can be things like AI, physics, sound etc. Even if the final FPS of the current games would not increase, it would leave the authors with more room to do other interesting CPU-side things that might not have been possible because the game became CPU-bound. In the case that one day games do become memory bandwidth-bound, keeping as much data in GPU memory as possible will also help to reduce the bottleneck.

So, what I want to ask is: Is there anybody out there who would actually, at the current time, benefit from keeping vertex data on the GPU using an sf::VertexBuffer? I have a feeling that Cendric would, but until there is an implementation to test with, it is just a theory.

2
Feature requests / sf::RenderTarget::setActive
« on: October 06, 2016, 01:49:59 am »
Continuing from this discussion:

It seems like an inconsistency or at least weirdness that all the subclasses of sf::RenderTarget themselves do expose a setActive method, however sf::RenderTarget does not expose the same itself. This makes it harder to write generic code that is agnostic to the concrete sf::RenderTarget implementation but still has to be interleaved in a reliable way with raw OpenGL rendering.

Conceptually, a render target that can be used for sfml-graphics drawing should also provide the possibility for non-sfml-graphics rendering i.e. OpenGL. Support for this is already partially provided via sf::RenderTarget::pushGLStates, sf::RenderTarget::popGLStates and sf::RenderTarget::resetGLStates, however if one wants to take state management into ones own hands, there is no way to activate the sf::RenderTarget's context otherwise.

What I suggest is exposing a completely identical setActive() method as the subclasses and simply forwarding the call through to whatever concrete class lies underneath via activate() which is already available.

3
SFML development / How should SFML handle non-legacy shaders?
« on: August 27, 2016, 05:29:53 pm »
One of the roadblocks on the way to providing newer, more "modern" and less "legacy" rendering implementations is the way shaders would be used.

The problem is that Khronos decided to make a clean cut when jumping from the legacy to the modern pipeline in regards to shader usage. There is no backwards compatible way to cover both implementations.

For those who don't understand what I mean, let me demonstrate.

This is what legacy GLSL (the kind SFML currently uses) would look like:
uniform float wave_phase;
uniform vec2 wave_amplitude;

void main()
{
    vec4 vertex = gl_Vertex;
    vertex.x += cos(gl_Vertex.y * 0.02 + wave_phase * 3.8) * wave_amplitude.x
              + sin(gl_Vertex.y * 0.02 + wave_phase * 6.3) * wave_amplitude.x * 0.3;
    vertex.y += sin(gl_Vertex.x * 0.02 + wave_phase * 2.4) * wave_amplitude.y
              + cos(gl_Vertex.x * 0.02 + wave_phase * 5.2) * wave_amplitude.y * 0.3;

    gl_Position = gl_ModelViewProjectionMatrix * vertex;
    gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
    gl_FrontColor = gl_Color;
}

This is what the non-legacy variant would look like:
#version 130

uniform mat4 sf_ModelViewMatrix;
uniform mat4 sf_ProjectionMatrix;
uniform mat4 sf_TextureMatrix;

in vec4 sf_Vertex;
in vec4 sf_Color;
in vec4 sf_MultiTexCoord;

out vec4 sf_FrontColor;
out vec2 sf_TexCoord;

uniform float wave_phase;
uniform vec2 wave_amplitude;

void main()
{
    vec4 vertex = sf_Vertex;
    vertex.x += cos(sf_Vertex.y * 0.02 + wave_phase * 3.8) * wave_amplitude.x
              + sin(sf_Vertex.y * 0.02 + wave_phase * 6.3) * wave_amplitude.x * 0.3;
    vertex.y += sin(sf_Vertex.x * 0.02 + wave_phase * 2.4) * wave_amplitude.y
              + cos(sf_Vertex.x * 0.02 + wave_phase * 5.2) * wave_amplitude.y * 0.3;

    gl_Position = sf_ProjectionMatrix * sf_ModelViewMatrix * vertex;
    sf_TexCoord = sf_TextureMatrix * sf_MultiTexCoord;
    sf_FrontColor = sf_Color;
}

Almost all the built-in variables have been removed. The only one remaining which is relevant to us is gl_Position.

Because all the built-ins were removed, this means that SFML would have to explicitly transfer the uniform data as well as specify the attribute bindings using the in and out attribute names as can be seen in the second snippet. For demonstration purposes, I just replaced the gl_ prefix with sf_ to make the changes clearer and obvious that they are no longer GL built-ins.

The question now is:

Should SFML just provide a fixed table of legacy replacements so that the user can write GLSL like they used to even using the non-legacy pipeline? This would force the user to follow the given convention and if they don't, errors will occur and drawing will simply not produce the expected output.

Or should SFML allow the user to specify what they are going to name all of the required uniforms and attributes in their GLSL using some global/static function once at the start of their application? If the user doesn't follow what they specify, drawing will also not produce the expected output.

Maybe a mixed solution containing both of the options is the best. SFML would use the pre-specified table of replacements as default values and allow the user to override entries as they wish.

The next question would be: How does SFML guarantee that the GLSL the user provides will work no matter what the target platform supports? The problem is that the user might not know whether the target platform can support non-legacy shaders beforehand. In order to handle both scenarios, the user would have to specify 2 sets of shader source: 1 for the legacy shader implementation and 1 for the non-legacy shader implementation. They could always opt to reject using the non-legacy implementation and stick to legacy for maximum compatibility and not having to write GLSL twice, however this prevents them from using the non-legacy pipeline which might be the better choice if available. On the mobile platforms, this isn't an issue since legacy shaders don't exist.

Once these questions are answered, SFML might be able to move on and provide a few newer rendering backends and finally offer support for shaders on mobile platforms.

So, what would you, the community, like to see/use?

4
Feature requests / Get rid of the state cache inside RenderTarget
« on: December 04, 2015, 11:26:23 pm »
I never really liked the idea of this state cache. It makes interoperation between sfml-graphics and other libraries painful, and just complicates RenderTarget code.

I did some testing, and it seems that whether or not the cache is used, the performance stays identical, in both high and low graphics load situations. On first glance, it would seem like saving 1 matrix upload and having to manipulate a few more GL states every frame might have some form of impact. The fact that it doesn't, seems to me like an indication that we just move the work from the calls into GL to constantly having to pre-transform the vertex data on the CPU instead of leaving it to the shader units which are more suited for the job anyway.

Finally getting rid of the cache would make current maintenance of RenderTarget and future extension much easier. I'm already having a hard time figuring out how to support custom shader attributes with this cache around, and it also seems to have an effect on #1015 as well.

For reference, this is the code I used to generate a synthetic load that would actually trigger the state caching:
#include <SFML/Graphics.hpp>
#include <algorithm>
#include <sstream>

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 600, 32), "Test");

    sf::Clock clock;
    sf::Event event;
    std::stringstream sstr;

    sf::Texture texture;
    texture.loadFromFile("resources/texture.jpg");
    sf::Sprite sprites[4096];

    for (int i = 0; i < 4096; i++)
        sprites[i].setTexture(texture);

    float deltas[256];
    int index = 0;

    while (window.isOpen())
    {
        deltas[index = ((index + 1) % 256)] = clock.restart().asSeconds();

        if (!index)
        {
            float avg = std::accumulate(deltas, deltas + 256, 0.f) / 256.f;
            sstr.str("");
            sstr << "Frame Time: " << avg << "s -- " << (1.f / avg) << " FPS";
            window.setTitle(sstr.str());
        }

        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                return EXIT_SUCCESS;
        }

        window.clear();

        for (int i = 0; i < 4096; i++)
            window.draw(sprites[i]);

        window.display();
    }
}
You can test the performance with and without caching enabled by temporarily hardcoding this line to false.

5
General discussions / Experimental internal-context-less branch
« on: October 09, 2015, 04:10:26 am »
Hi guys, I recently came up with a way to completely get rid of the need for those infamous "internal contexts" that have plagued SFML for so long. This solves many problems/annoyances without actually changing the behaviour of the library for anybody who follows the official usage guidelines/documentation and doesn't rely on undocumented/undefined behaviour.

With internal contexts gone, you might have guessed, SFML has to deal with less contexts. Currently, even if you are working with a single window, SFML will create and hold on to at least 3 contexts although only one of them is really ever used. This branch gets rid of one of the unused contexts, the other one is another story. Less contexts means smaller memory footprint and less work for the OS/driver if that means anything.

The biggest change however, would be that people can actually start creating RenderTextures and other OpenGL resources in threads without having to worry about their system blowing up at some point. The only reason this was an issue previously was because of the whole internal context story.

For the time being I've pushed the branch to my own repository. After enough people have tested it and made sure I didn't utterly break too much stuff, I'll push it to the main repository and open a formal pull request. It might get merged one day.

Here it is for your testing pleasure: https://github.com/SFML/SFML/tree/feature/no_internal_context

6
SFML projects / Looping Sound
« on: March 29, 2015, 04:01:25 pm »
Since not everybody is automatically notified of wiki changes:

I implemented a proof-of-concept Looping Music class that provides the same interface as the one proposed in pull request 629.

It can be found here.

If you want to test it out without too much effort, just replace the code from the SFML sound example with it, build and run it.

7
General discussions / How to help test SFML
« on: March 28, 2015, 09:05:36 pm »
Since Glocke was interested in testing SFML and asked me how he could help, I decided instead of replying to his message, I'd make the information public in case anybody else is interested.

If you are keen on helping test the latest and greatest that SFML has to offer, start out by watching the GitHub repository.

Go to https://github.com/SFML/SFML and at the top, you see a button labelled "Watch". Click on that and you will be watching the repository, meaning you will be automatically notified of any commits that are made.

Now... SFML development happens in branches. Nothing is ever directly pushed to the master branch any more. If code ends up in the master branch, it would have gone through a dedicated pull request meaning code review and thorough testing. For every issue that is currently being worked on, there is normally an associated branch and pull request.

You can find a detailed list of all branches here: https://github.com/SFML/SFML/branches/all. If you click on the #number at the right, it will take you to its associated pull request, where you can provide feedback about e.g. whether it fixes the issue for you or even breaks something that previously worked. The pull request is the "main hub" for discussions regarding that work item, and any future changes will typically be announced in it by the author as well.

After browsing through the branches, you might have found something that you think you are able to meaningfully test, you have 2 options at this point, either clone the repository using git or download the zip archive of the corresponding branch.

To download the zip archive of the branch, simply click on the branch name in the list of branches. Once you are at the file list index just click on the "Download ZIP" button to the right and unzip the archive somewhere.

You will have to do this again every time you want to try out another branch or even another version of the same branch deleting the previous files first. This is why I recommend the git method.

To clone the repository using git, either use the tool you might have installed to do it, or install git and run
Code: [Select]
git clone https://github.com/SFML/SFML.gitat any command line that is able to run the git executable. Once the repository is cloned, you can review the remote branches that exist using the command
Code: [Select]
git branch -rvThis will output the branch name, HEAD of the branch and commit message of HEAD. You can make sure you are testing the right stuff by checking whether the HEAD message is what you expect. To checkout/switch to a branch, simply run the command
Code: [Select]
git checkout -f <HEAD commit hash here>The -f is there just in case you accidentally modify a tracked file, it will discard the change automatically.

Cloning the repository has the advantage that you don't have to re-download a new zip every time you want to test another branch, or even a newer version of the branch.

At this point, just build SFML using the standard procedure. Configure using CMake, build it however you want and conduct your tests however you feel like testing the code ;). Nothing prevents you from using WIP branches in your own projects as well, in case you just can't wait for that next release ;).

8
Feature requests / Facility to load dynamic libraries
« on: January 08, 2015, 08:22:00 pm »
It is not uncommon for applications these days to require loading optional libraries at runtime.

Probably the most common example of this would be to automatically load optional plug-ins/add-ons that the user wants the program to load during runtime.

Currently, the developer would need to resort to OS-specific code to achieve this, which can become annoying if you have to do this in many projects.

SFML would allow the developer to load libraries (possibly appending the correct filename suffix depending on the OS) and check for and load specific functions from those libraries.

9
Feature requests / Facility to get standard paths
« on: January 08, 2015, 08:16:09 pm »
Currently there is no way for the user to retrieve the paths of standard locations in a cross-platform way.

One can check the environment variables using std::getenv() but often times you wouldn't be able to use their values directly without a bit more information about the target system.

As an example: On Linux systems, it might be typical to store user data in the HOME location, on Windows, there is also a HOME path, but that is not where user data is usually stored (APPDATA is used for this).

If an SFML application is installed by a user with administrative privileges and is to be used by unprivileged users, there would be no place to store per-user data since the binary directory would be read-only.

Other examples of useful paths might be: The current working directory, a directory where temporary data can be stored, the location where fonts are installed (yes... currently if you wanted to use installed fonts you would have a lot of pre-processor in your code).

10
General discussions / SFML 2.2 - Next-Gen Multimedia Capability Today
« on: December 11, 2014, 10:49:10 am »
Here are a few reasons why SFML 2.2 will be the best release of SFML yet.
These comparisons are based on screenshots of in-game footage. One can clearly see the improvements that SFML 2.2 provides over SFML 2.1.

Side by side comparison

If you have more examples of other games/software that takes advantage of SFML 2.2, feel free to post them here as well :D.

For those who still don't get it... This was supposed to parody certain other... API releases.

11
SFML development / SFML Context Management
« on: October 02, 2014, 04:06:50 am »
Hello awesome SFML forum! :D

Today, I (We? Can't speak for the other team members..) approach all of you to ask for your opinion on the matter of:

SFML Context Management

This has been an issue that I have personally been involved in for a long time, and I can imagine many others, including Laurent himself of course, have expressed their concern in regards to this matter time and again.

With the SFML 3 vision thread up in full swing for just over 5 months, there is no doubt that we are going to start work on SFML 3 sooner or later.

As you all know one of the biggest uses of SFML, is in the area of 2D graphics. To realize this, SFML builds on top of the cross-platform graphics API OpenGL. As with any hardware accelerated API, there needs to be some form handle to identify the accelerator device in question, whether it is really the physical device or a virtual device that is emulated by the driver. DirectX names their handles, devices, fittingly, and OpenGL decided to name their handles contexts. OpenGL has had a long history, much longer than DirectX, and needless to say, the concept of contexts as a container for GL state has existed since the beginnings of OpenGL.

For those familiar with OpenGL, you know that calls to the OpenGL API will only have an effect if a context is currently active, to keep it simple for now. Any state modifying calls will modify the state of the currently active context and no other. Since OpenGL used to do most of its work via bindings (i.e. state variables), understanding how contexts work is essential if you plan on using multiple of them, and that is where the difficulties arise.

There are a certain set of constraints that have to be met when dealing with contexts. Many of them are probably the result of operating system constraints from the time when the first specifications were written, but they haven't changed much since then. I will try to list most of the important ones here so that you can understand what I mention later better.
  • Contexts are containers for OpenGL objects, identifiers to resources that live somewhere, either in the driver or on the GPU itself.
  • Contexts are containers for OpenGL state. OpenGL can be seen as one huge state machine, and you manipulate this state to alter what you see on your screen.
  • OpenGL operations operate either on state, or objects. If the container (i.e. context) for these does not exist, naturally, OpenGL operations will have no effect.
  • Almost all OpenGL objects can be shared between contexts. This simply means that they share the same identifier space, meaning that an identifier generated in one context can be used in another. In previous versions of OpenGL, one did not even have to generate objects and could manage the identifiers without the help of the driver. This however has been deprecated and will cause an error in newer OpenGL. The most prominent examples of objects that cannot be shared between contexts are framebuffer objects, the underlying object of an sf::RenderTexture and vertex array objects, containers for vertex attribute binding state in modern OpenGL.
  • Context resource sharing works on a peer-to-peer basis. Sharing is associative. Once contexts are shared with any context that is part of a chain of other contexts, it cannot be "unshared".
  • Every context has its own default framebuffer, basically a surface on which all draw operations have an effect. This cannot be suppressed, even if one does not intend on ever drawing to that framebuffer.
  • Contexts can be activated and deactivated. The currently active context is the one that OpenGL operations have an effect on.
  • Contexts can only be activated in a single thread at a time. It is an error to activate a context in a different thread than one that it is currently already activated in. In order to switch the thread in which a context is active in, the previous thread has to deactivate it and only after that has been done can the new thread activate it.
  • What follows from the previous points is that only a single context can be active in a thread at any given time. Activating another context than the one already active will automatically deactivate the currently active one first. Multiple contexts can simultaneously be active, but each in their respective threads. Unless you know that your application causes a lot of work in the driver (not on the GPU!) and that you have a multi-threaded driver, splitting OpenGL work up among multiple contexts in multiple threads will provide absolutely no gain in regards to OpenGL performance. Developers who know how to get a hold of that information will probably also understand how to exploit multi-threaded GL, but most of the time, this is simply not the case. With future OpenGL versions, reduction of driver overhead is also part of the plan, so multi-threaded OpenGL usage will keep losing significance as well.

SFML makes extensive use of OpenGL for drawing throughout its graphics module, and marginal use of OpenGL in its window module in order to provide context support for developers who aim to use OpenGL directly.

The technical details come now.

Due to historical reasons, Laurent chose to have a single context that serves no other purpose than to be shared with any context that is created after it. In SFML code, this context is referred to as the "shared context". The shared context is the first context to be created in an SFML application, due to the fact that any future contexts have to be shared with it. It is created as part of the global GL context initialization which happens as soon as the first sf::GlResource is created. It relies on reference counting in order to track how many objects there are that still rely on having an active context. Once the last sf::GlResource is destroyed, the global GL context cleanup is performed, which gets rid of the shared context as well. In addition to that, the cleanup function also gets rid of all "internal contexts".

SFML sets up a sort of "invariant" that states that as soon as a sf::GlResource has to perform any operation within any thread that thread will have to constantly have a context active at all times, even when not required. Maybe this was done for performance reasons? I do not know (only Laurent knows :P), and the difference was barely measurable in my tests. As opposed to "standard practice" of deactivating contexts when required, SFML "deactivates" contexts on the current thread by activating a so called "internal context", a thread local context that makes sure that the invariant of having a context active at all times is upheld. These internal contexts are created the first time they are required (i.e. a context was activated and requested to deactivate) and due to the way the context management works, they cannot be destroyed until global cleanup, which typically happens when the application closes. This results in what is now known as the "context leak" that has been discussed on the forum and tracker often enough. Applications spawning temporary threads to perform sfml-graphics operations will notice a constant rise in memory usage due to this, and at some point, the driver will also give up in trying to manage the excessive number of contexts.

Are these internal contexts ever used when (and if) they are active? Not very often in typical code. If an application doesn't make use of sfml-graphics in secondary threads without an explicit context object and never explicitly calls .setActive(false) from within the main thread (the one that deals with the main window) or creates sfml-graphics objects before the main window is created, it will likely never be used. Nonetheless, it is created, all the time. If you are proficient in OpenGL debugging tools, you will notice that even the simplest SFML application, such as those found in the beginner tutorials will end up creating 3 OpenGL contexts, although the shared context is unnecessary (according to my tests) and the internal context is rarely ever used.

Additionally, because framebuffer objects cannot be shared between contexts as stated above, in order for SFML to guarantee that a sf::RenderTexture can be used in any thread after it is created, it has to contain its own context that is activated solely when something is to be done on the sf::RenderTexture and deactivated thereafter. This means that in a single-threaded application with a "large" number of sf::RenderTextures, the same number of additional contexts will have to be created, one for each sf::RenderTexture. The alternative implementation of sf::RenderTexture using a secondary context's default framebuffer on systems that don't support framebuffer objects is more justified, but the systems that cause this to be the case are getting less and less common.

The reasoning behind the current design stems from the fact that SFML tries to hide context management from its users. The assumption is that context management shouldn't be something that beginners have to struggle with when they already have so much to learn. This is true, and maybe it should be something that is kept for understanding at a later time, but I personally find that learning that a context has to be active in order to play with sfml-graphics is something that shouldn't be too hard to grasp. The problem is that I, Laurent and many others already have a lot of experience with graphics programming, so what might seem easy for us might seem like a nightmare for beginners. Conversely, what might seem like a boon to beginners is a nightmare to advanced users (e.g. threaded sfml-graphics).

SFML 3 will probably bring with it a lot of changes, and Laurent has already proposed his ideas on separating the sf::RenderTarget concept from the window and offscreen rendering surface objects (currently sf::RenderTexture). Conceptually, a sf::RenderTarget is nothing other than a context that is used to target a surface to render to, so in that respect a change in regards to context management wouldn't be as drastic as some might expect.

I would have provided mockup examples of what explicit context management might look like, but I decided against it since it is only one of many possible ways of exposing it through the API and I don't want to influence the outcome of the poll because of that.

We really need community feedback on this matter. Should SFML make context management more explicit? Or do you think that it should stay implicit since this is what makes SFML different from (and better than?) all other multimedia libraries?

Please try to be honest and give the poll a bit of thought before voting. In the case you retrospectively change your mind, please try to factor in the gut feeling you had when you voted previously. We want the API to feel good and easy to use, yet powerful at the same time, and there is no better way to judge the "feel" of the API than relying on your gut feeling. Also, since I hope to get a representative opinion on this matter, it is important to motivate as many of SFML's users to vote as possible, especially those that don't visit the forum very often. SFML will always try to be beginner friendly and thus their opinions are worth just as much (if not more) than those of us who have been using SFML for years, and yet they are probably the ones who are the hardest to get a hold of for these kinds of polls.

For those who are afraid/shy of exposing yourself, keep in mind that voting is anonymous (posting is not mandatory), and only those with database access (i.e. those who really don't care ;D) can check what you voted for, if they even invest the amount of effort required to do that.

I would be happy for your feedback on this matter :).

12
SFML projects / 3DEE
« on: April 02, 2014, 04:24:46 am »
3DEE - 3D Extrapolated Extension for SFML

Yes... some people might have expected this from me, and this was in the planning for quite a while and since Tank preferred that I work on this rather than SFGUI how could I say no? ;D

General Idea
I've been using SFML for quite a while now, and it sort of fulfilled my needs in the beginning. But as I wrote more and more things, I always had to resort to using raw OpenGL to get 3D rendering done because well... SFML doesn't support 3D rendering through its drawable API. It got quite annoying that all my applications had basically the same OpenGL boilerplate code that SFML happily takes care of... for 2D. I thought: there must be a common subset of functionality that all 3D applications rely on that everybody has to code, but nobody truly likes to code. That is basically what this extension is for. It takes all the concepts that make rapid prototyping and coding graphical applications with SFML so simple and fast, and applies them to the 3D domain as well. Moreover, it was designed to be as general as possible to fit as many use cases as possible while still adhering to the SFML architecture... somewhat.

As for the name... no I initially had no idea that it could be pronounced like that. I tend to name my projects after what they are since I am such a creative person. It is just a working title after all. I couldn't name it SFML, I already had a directory named SFML ;).

The idea is simple. Take all SFML classes that are bound to the 2D plane and extrapolate them into the next dimension (I know, it sounds awesome if you say it like that). 2D objects are furthermore still compatible with 3D rendering. They will simply have their z coordinate set to 0 appropriately.

Features
3D Primitives
Analog to RectangleShape and CircleShape, there are the 3D counterparts named Cuboid and SphericalPolyhedron respectively. They are based on Polyhedron which is the analog to Shape. For constructing one's own polyhedra, there is the ConvexPolyhedron class as an analog to ConvexShape (don't ask me why it is named ConvexPolyhedron, I don't understand either ::)).

3D Models
You might be asking: OK great, we have primitives, but what about models? After all they represent the bulk of geometry in a typical 3D application. That is true, and that is why there is a very light interface class called Model which provides a few methods that might be helpful when building your own application specific 3D model classes. Since model loading, storage and representation is a science in itself, one isn't limited to using Model at all costs. Even a simple VertexArray can be used to represent model data if you want more control. Model was one of the classes for which I genuinely had no idea how to design. The requirements differ so much per application so instead of trying to implement a solution for every possible scenario, I figured just make it as light as possible and purely optional to use. I didn't implement model data loading because that would have introduced another dependency (which I don't like), and it ends up in a lot of code that the application would not make use of in the end. Model loading is done by the application specific class. Feedback would be appreciated on what other useful features could be added to Model.

Billboards
Although so simple, billboards are so common in 3D applications, as a replacement for complex geometry at lower levels of detail, as the representation of particles and many other things. Billboards are implemented as Sprites which are automatically rotated to always face the camera they were set to track. Nothing more, nothing less.

Cameras
What 3D application would be complete without Cameras? They are indeed the analog to a View and derive from View just to keep things simple (I could have derived the other way around or made a common parent interface but I wanted to minimize the needed changes). They can be used anywhere a normal View would be able to be used. As inspiration for its API I took the newly added/changed Listener API with its position and directions so combining a Listener and Camera becomes quite trivial and the only natural thing to do :).

Lights
This is the first controversial feature. There is a Light class, and it bases its functionality on the fixed-function lighting of OpenGL with all its limitations. This could also be done using shaders, which I also recommend doing if you can afford it. However, sticking with SFML philosophy I felt that I had to provide an alternative for those unlucky people without programmable graphics hardware. Light can also be used for rapid prototyping and replaced later on with something more... flexible, but short of copying and pasting shader code along with its handling code, this is the fastest you will get lighting up and running which is absolutely necessary in many 3D applications.

Shadows
This is the second controversial (non-)feature. Yes... it is a non-feature because I didn't implement shadowing. There simply isn't any fixed-function support for shadows and writing a custom shadow implementation
  • Is guaranteed to have worse performance than the equivalent shader/modern variant
  • Is not guaranteed to be optimal given the scene for which it is to be used, meaning that I would have to write multiple implementations for each scenario which would all be inferior to writing an application specific implementation
  • Is still a science in itself. There is no consensus on "how to do it right", just general techniques that still need to be adapted to each application
For those reasons I thought it be better to let the application developer implement their own shadows which suits their needs the best.

Minor Features
4x4 Transforms
This was a given, considering we are working in 3D now. This could be considered a major feature, however I don't directly use Transforms all that much and I don't think many others do as well ;).

Stencil attachment for RenderTextures
I figured when rendering in 3D, it is going to be necessary to have an optional stencil attachment for RenderTextures, after all, many advanced techniques rely on use of stencil data (this includes shadowing techniques). This also sparks the question of whether the format of RenderTextures should be even more flexible to e.g. prevent the creation of a color buffer in cases where one isn't required.

2D Drawable Winding
I altered all 2D drawable classes to specify vertex data with counter-clockwise winding. This was a requirement because I enabled backface culling in RenderTarget by default, get used to it ;D.

OK, enough with the features, where's the...
Yes... the repository can be found at GitHub: https://github.com/binary1248/SFML

The branch consists of additions/changes to the SFML master branch in order to make integration as seamless as possible. Because I consider this to be a strict superset of SFML's features, this extension should be able to be dropped in place of the standard SFML implementation and it should work out of the box. If it doesn't, either it is a bug (not unlikely at all ;)) or have something to do with the caveats that I am going to list.

The change set should stay more or less compatible with future changes to mainline SFML if not too much is changed. As such it should be easily rebased to the current SFML master when anything happens there.

Caveats
Winding
If you make use of your own geometry specification using VertexArray or a custom ConvexShape/Shape, make sure the face winding matches with what is expected (counter-clockwise). Culling is enabled by default in this implementation and any clockwise faces will not be rendered. Make it into a good habit and one day you will thank me because of the performance boost you might observe ;).

Vertex Normals
By default, vertex normals should be set correctly for all 2D drawables, facing in the positive z direction. When specifying your own vertex data, do not forget to specify them if the default doesn't cut it and you want to light your geometry.

View Matrix
Contrary to popular belief, you in fact don't move the view around by manipulating the projection matrix. The projection matrix is there for one purpose, and as its name implies that is the projection from eye/view space coordinates into normalized device coordinates. The reason why the architects of OpenGL chose the term modelview matrix is because the modelview matrix combines the Model and the View matrix into a single matrix. With the help of pushing and popping the stack it isn't hard to understand the theoretical concept. This is how a vertex is transformed:

vertex_out = projection * view * model * vertex_in

The model matrix transforms the vertex into world space, the view matrix into eye space and the projection matrix into normalized device space which is fed into the rasterizer. The reason why combining the view matrix into the projection matrix is possible is simple to understand from the equation. However, this brings problems with it, especially when lighting and normals come into play. Vertex normals are transformed just like normal vertex data, however they are not multiplied with the projection matrix. This means if you have your view matrix combined with the projection matrix as opposed to the modelview matrix the normals will not be transformed properly, and lighting will produce unexpected results.

The proper way to move the view around is to instead "move the world around the view". This is done using the inverse of what would normally be considered the rotation and translation of the camera.

This is less of a problem when rendering in 2D without lighting because... well... there are no normals to worry about. There are other strange side-effects that are the result of this mistake. For more information refer to this. If you have some obscure code that relies on the vanilla "non-standard" matrix implementation then maybe it's time to consider fixing it up.

Frequently Asked Questions
Q: Where are the pre-compiled libraries for XYZ compiler?
A: You know me... No pre-compiled libraries here.

Q: I can't see anything I draw!
A: Read documentation? Read caveats? Did everything right? Report bug.

Q: Why are there no copyright notices in the newly added files?
A: I can't just copy them from the standard SFML files can I? Until I figure out what best to do, the source is available under the same license as SFML, zlib.

Q: Do you plan on ....
A: Yes I have plans for a lot of things, and they will be implemented when I have a general idea of how to implement them. Don't be afraid of asking for features, if they are simple enough and are general enough to be useful to people besides you as well, I might implement them. However I will not take the route of implementing every possible variation of a certain feature to cater to every possible use case like certain individuals try and fail to do.

Q: I know this isn't a question but I found a bug and I am sure it isn't intended behaviour described in a footnote of the documentation, and it wasn't in your caveat list.
A: Ask here or GitHub tracker.

Q: Where is the documentation?
A: doxygen inside the doc directory, or just generate the doc target in CMake. Same as SFML.

Q: What? No screenshots? What kind of presentation is this?!
A: The only thing to see would be the example I added, and that is not the focus as it is there purely for code demonstration purposes. And besides... building the example and running it yourself isn't really hard is it?

Q: This is too complicated for me. Is there a simpler way?
A: What? This is supposed to make your life simpler, and your development... faster. If you prefer writing 500 lines of OpenGL code to get a rotating lit cube up and running, be my guest.

Q: I don't understand OpenGL! That's the reason I use SFML. Why does this look a lot like OpenGL?
A: Like everything in the universe, there is a reason why OpenGL looks like what it is. Indeed you will find that many 3D APIs that don't get too high level have similar interfaces. Nothing else makes much sense. This is no exception. It helps to understand OpenGL concepts but most of the time it should not be needed when using this (my opinion, very subjective). In the case where a bit more knowledge is required, I have tried to write documentation explaining everything that is required.

Q: ... this engine ...
A: This is not an engine. SFML is not an engine. If you want an engine, you will have to look elsewhere.

Q: I want XYZ to look like ABC and when I click UVW it should become IJK. Please help.
A: Look for code slaves elsewhere.

Q: Will parts of this become part of SFML?
A: That is not for me to decide. If Laurent wants to grab bits and pieces, he is very welcome to. I am fine if all of this gets merged and I end up relinquishing my rights to the code. Anything that increases the number of 3D projects in this subforum... I'm getting quite bored... Teapot Defence anyone?

Q: Man that interface is completely moronic. How did you even come up with such a monstrosity?!
A: Constructive criticism welcome. I know this is a sensitive (and quite complicated) topic. And I guess nobody (not even Laurent) tried anything like this before from what I can tell. One learns from their mistakes, and mistakes have to be made to learn.

Q: Are those the only questions in the FAQ?
A: Nope, more will be added if needed.

Q: Why does this thread look like the SFNUL one?
A: Because I am a truly creative individual.

13
SFML projects / SFNUL
« on: November 30, 2013, 04:32:03 am »
SFNUL - Simple and Fast Network Utility Library

I originally intended it to just be called NUL, but go figure why I couldn't name it that... I guess the SF is fitting because if you ask me, it sticks with the SF philosophy somewhat :).

Background History
SFNUL was envisioned a veeeery long time ago, while I was still actively working on my super awesome project Wyrm before even touching SFGUI because Wyrm needed a UI :). Back then I already considered making the networking more reusable because I tended to have to rewrite the exact same code in every networked game I coded, and it got quite annoying. Time passed, and I had more interesting things to do than actively work on Wyrm so that idea kind of went with it for a while.

It wasn't until helping Jungletoe debug his network related problems earlier this year that I realized SFML networking had a lot of shortcomings that I also found annoying, not only because I found that it didn't provide a level of abstraction of networking that was high enough, but because in certain situations it sacrifices standards conformance for a bit of usability. Being a computer science student for so long, I've come to revere standards which is why SFNUL aims to warn the developer about non-standard behaviour that they might cause.

General Idea
The main goal of SFNUL is to cut down on the network boilerplate code that can be seen in most multiplayer games. I already experienced this first hand while working on Wyrm, and browsing through the SFML network forum reviewing code and problems many have, I've gotten a feeling for what multiplayer game developers might need to spend less time writing "the same old annoying code that has to be written in every single project". SFNUL's sole purpose is to give developers more time to work on the code that makes their project unique from all others instead of code that is common among all projects. I want to see less code/problems and more playable multiplayer games ;).

Features
Fully asynchronous socket API.
Process data according to your own pace, it will trickle into an internal buffer but this doesn't mean you need to dedicate a thread to a blocking call or resort to selectors to check if any data is available. If data is available, you will be able to retrieve it and process it, if not then do something else.

Fully asynchronous TCP connection establishment/accept.
TCP connections will continue trying to connect and will automatically transmit/receive queued data when it is established. Incoming TCP connection requests are also queued into an internal buffer for you to process when you are ready.

TLS/SSL support.
You can set up a TLS transport and use it like you would use a TCP connection. All TLS specific features are added on top of the ReliableTransport interface which a normal TCP socket also implements.

HTTP/HTTPS client support.
Send arbitrarily constructed HTTP requests through the HTTPClient and it will receive and parse the reply sent back from the server which you can pick up from the HTTPClient, as with everything else, when you feel like it. HTTPClient supports HTTP/1.1 chunked transfers, persistent connections and request pipelining for efficient throughput utilization.

sfn::Message
Those familiar with sf::Packet will understand how sfn::Message works. It is the SFNUL version of sf::Packet that can do a lot more useful things ;). Let's use some code to demonstrate the differences:
sf::Packet packet;
sfn::Message message;

std::vector<int> vec = { 1, 2, 3, 4 };

packet << vec; // Doesn't compile, no operator<<( const std::vector<int>& )
message << vec; // Compiles, all objects that conform to the STL container interface are supported.

// Nesting containers works as well.
std::vector<std::list<std::deque<std::string>>> something;
// Insert some data here...

message << something; // Works fine.
message >> something; // Works fine as well.

int i = 42;

packet.prepend( &i, sizeof( i ) ); // Doesn't exist. No easy way to prepend data to a packet.
i >> message; // Intuitively insert data into the front of the message to prepend.

struct A {
        int a, b, c;
        float d, e, f;
        char g[16];
};

A a;

packet << a; // What?? How could this possibly be implemented?
message << a; // Yes... this works... any trivial data type is supported for insertion and extraction.
message >> a; // Just to complete the cycle.

Links
Did you ever wonder how you can separate multiple different networking concerns from each other when communicating between hosts? Say you need to transmit data every time the player hits a key to move, that is one concern, then you need to transmit object states, that is another concern, and on top of that the players want to chat with each other, yet another concern. A typical approach would be to label each of these with a separate packet type ID to properly identify their payload, or the worse solution that many big games go for: open up multiple connections between the same pair of hosts. With the sfn::Link, that is taken care of automatically. sfn::Link multiplexes multiple distinct streams into a single network connection and demultiplexes them at the other end. All you need to do is assign each concern a stream ID and send/receive over that stream when dealing with that concern.

Object Synchronization
The centrepiece of SFNUL, seeking to solve the most annoying part of multiplayer coding. When you have multiple hosts which share the same world state with each other, performing the proper synchronization between them can become quite a tedious task. You need to assign IDs, perform required serialization/deserialization, object lifetime management, connection management and many other annoying things that have nothing to do with your vision of the game. This is where the sfn::Synchronizer comes in. Simply put: The sfn::Synchronizer makes sure that state changes to objects that it manages are propagated to synchronized remote hosts automatically without any extra coding effort from the developer. A simple example with a lot of things omitted for demonstration purposes:
class Blob : public sfn::SyncedObject {
public:
        // ... type id / constructors omitted ...
        sfn::SyncedInt32 x;
        sfn::SyncedInt32 y;
        sfn::SyncedType<sf::Color> c;
};

sfn::SynchronizerServer synchronizer_server;
auto blob = synchronizer.CreateObject<Blob>();

sfn::SynchronizerClient synchronizer_client;
// We assume the blob is already created on the client for brevity sake.

// On the server we do:
blob.x = 10;
blob.y = 20;
blob.c = sf::Color::Green;

// On the client we do.... absolutely nothing. The changes are performed automatically.
No more wasted time on getting the synchronization up and running and even more wasted time debugging it when it doesn't work. Do what you would do for a single player game and get multiplayer for free... in some sense :).

Here is a diagram showing how the SFNUL facilities and dependencies can interact with each other:


These were very brief examples/descriptions of the ideas behind SFNUL. If you want more demonstrations (that also work) look in the examples directory.

OK, enough with the features, where's the...
Yes... the repository can be found at GitHub: https://github.com/binary1248/SFNUL

If it isn't already apparent, SFNUL makes very heavy use of C++11 features. This means that you not only need a compiler that can compile C++11 code somewhat, but one that is feature complete and more importantly conforms to the standard. This already rules out Visual Studio 2012 and earlier, so if you haven't hopped on the Visual Studio 2013 train, well this could be another reason to consider if you want to try SFNUL.

SFNUL is licensed under the Mozilla Public License Version 2.0. Put simply, it is a file-based license, as long as you don't modify any of SFNUL's files you are free to do/distribute whatever/however you want, all subject to the terms of the MPL of course. If you distribute software using modified MPL code, you need to make available the modifications under the MPL as well. See this as a contribution back to the open source community for all of its efforts you have taken advantage of in the past ;). As with any other license, read through the MPL text if you want to understand what you can/cannot/have to do.

Frequently Asked Questions
Q: Where are the pre-compiled libraries for XYZ compiler?
A: Learn to compile something yourself, it isn't as hard as you think.

Q: I downloaded the zip archive off GitHub but it's complaining about missing headers during compile. Why?
A: zip archive won't work. Clone via git and initialize all submodules. Explained in the README.

Q: But I don't have git, surely there must be another way?
A: There is another way, it's called install git and use it.

Q: Wait... so what has this got to do with SFML?
A: Initially, it interacted a lot with SFML's classes, but then I realized that it would be easier for me to implement my own take on SFML's classes with many more features I found were missing and were feasible with C++11. So right now, it has very little to do with SFML. It can even be used independently of SFML. But you will recognize a bit of SFML's interface design still left in SFNUL.

Q: Do you plan on ....
A: Yes I have plans for a lot of things, and they will be implemented when I have a general idea of how to implement them. Either that, or I run into a dead end in one of my other projects and know that it is something SFNUL should be able to solve, so I implement it into SFNUL to be able to use it in the project and share it with the world at the same time.

Q: I know this isn't a question but I found a bug and I am sure it isn't intended behaviour described in a footnote of the documentation.
A: GitHub tracker.

Q: Where is the documentation?
A: doxygen inside the doc directory, or just generate the doc target in CMake.

Q: This is too complicated for me. Is there a simpler way?
A: What? This is supposed to make your life simpler. Write a few games with decent network support and come back here so that you can realize how that question doesn't make much sense.

Q: Are those the only questions in the FAQ?
A: Nope, more will be added if needed.

14
SFML projects / SFML Installer
« on: November 30, 2013, 02:12:43 am »
Since so many people tend to have problems/fear building SFML for themselves instead of relying on pre-built versions which are outdated relatively fast and going through the headache of trying to get incompatible versions running on a totally different compiler version, I thought this would be a good opportunity to put SFGUI and SFNUL through a bit of testing.

That, and I was completely bored :P.

So any ways... I present... SFML Installer.

What is SFML Installer you might ask? Well, it's not like any other installer you have encountered before. This one actually builds the files it installs on the fly on the target system using your development toolchain. This rules out any possible incompatibilities and since it grabs the latest SFML master, a "reinstall" should automatically update your library to the latest version available on GitHub (in case Laurent was nice and fixed the bug you might have discovered ^^). And... the dialog windows are all driven by OpenGL :D.

Under the hood, SFML Installer is basically just a download client (which supports HTTPS with certificate verification through SFNUL for GitHub downloading) and a command executor. All it does is grab SFML from GitHub, looks for CMake and your toolchain and configures/compiles SFML so that it can install it to a directory of your choosing. This is simple for some people to do on their own, however the installer does it all automatically for those who can't or don't want to.

Right now, it has support for Code::Blocks and Visual Studio detection, meaning it will find make/nmake if you have a typical install of one of those on your system. If you have MinGW or nmake installed by themselves, they will only be found if they are executable through the PATH environment variable, but I assume they would have been added to PATH anyway in that case. If you are unlucky enough to have multiple Visual Studio installations on your system, SFML Installer will automatically use the latest version that is installed, if you don't like it and think it can be done better... repository details further down :P.

The default settings compile all possible configurations of dynamic/static and debug/release, so you won't be missing your favourite library when developing.

Since using pre-compiled libraries is mostly popular on Windows, I only coded in support for Windows for now. Anyone who thinks Linux/OS X might need support can fill in the empty functions that are already in the repository and try your luck. Whoever has more ambitious plans for the installer framework is free to realize them since the code is released under the WTFPL... because I was bored.

Like most open source code I write, the repository can be found over at GitHub: https://github.com/binary1248/SFMLInstaller

If you don't care about the code and just want the statically linked executable: SFMLInstaller.exe

If you don't trust me and think my win32 code will format your drive... well you're out of luck for now ;D.

15
Network / Broken HTTPS code stub
« on: September 09, 2013, 09:05:34 am »
I already had a feeling that SFML didn't support HTTPS due to the fact that it doesn't link in any SSL libraries, so I checked the source just for fun. I found some code that parses https:// URIs and connects to the server on port 443 to send a "normal" HTTP request. Is this really necessary? I don't think it's a good idea to pretend to the user that SFML has invisible HTTPS support and just fail every connection attempt after sending potentially sensitive data (yes... this might be a security risk). An error/warning message on the console should be enough when trying to do this.

Until you decide on real HTTPS support can't you just prevent that needless connection establishment from taking place and tell the user HTTPS support doesn't exist yet? You said yourself here that you would think about removing the code but until now it still exists.

Pages: [1] 2