* Improvements to the 3D library (both C++ and Storm)

** Texture wrapping etc.

There are a number of different ways in which to handle texture wraparound (e.g. clip to edge, wrap,
mirror, etc.). These are not currently supported.

- Overview:
  - Need to be able to set texture options on the Texture object.
  - Respect them in the shader code (and in the C++ version, for debugging).

** Texture filtering (and mip-mapping)

Currently, we only provide a single "sample" function to sample textures. This does not allow for
texture filtering techniques to make textures look less jittery when they are further away.

- Overview:
  - We need versions of the "sample" function that accepts more parameters. For example, for
    mip-mapping, it often accepts a "distance" parameter to determine how much the text should be
    "blurred". There may be other versions that are relevant as well.
  - For mip-mapping, we need to be able to tell the Texture object to generate mip levels (or if we
    rather provide them ourselves) in a suitable fashion.
  - We need some options to tell the texture how it should behave in a shader (i.e. the sampler state).
  - Also some plumbing to make everything work together.

** Anti-aliasing

There are many approaches for anti-aliasing in 3D rendering (e.g. MSAA). It would be relevant to
support at least some of the most common ones when rendering to the screen.

** Manipulating the depth buffer

Some techniques utilize the fact that the pixel shader can (read and) write to the depth buffer.
There is some infrastructure for this already (a depth annotation, for example), but it is not
functional.

** Stencil buffers

The rendering code currently sets up a stencil buffer for use by shaders etc. However, it is not
possible to use it currently.

One use case seems to be "shadow volume", which can be used as an example for how to implement the
feature: https://en.wikipedia.org/wiki/Shadow_volume

** Proper handling of alpha

The two backends currently handle alpha differently. For example, D3D has an alpha channel in its
output buffer, but not OpenGL. This only makes a difference when rendering to textures.

** Arrays in Pipelines (as uniforms)

It is convenient to be able to work with arrays in shaders. For example, when applying lightning
while respecting many different light sources. For this reason it would be nice to support arrays of
vertices (or entire vertex types).

One limitation in shader programming is that (I think) most shader languages only support static
arrays. However, with some cleverness we can bridge the gap a bit.

If we define arrays in Pipelines with a maximum upper limit (e.g. "<type> array[<max-size>];"), we
can represent the array internally as a static sized array and an unsigned integer that holds the
size of the array. That way we can emulate "array.count" in the shader code, and still read all
members. We can simply throw an exception on the CPU side if the user attempts to put too many
elements in the array.

- Overview:
  - Add support to arrays to the pipeline logic.
  - Add partial support for the array type in the shaders.
  - Fix layout code for array types (position in shaders and in vertex buffers).

** Vertex types in Pipelines (and in other Vertex types)

It is currently not possible to add a vertex type as a uniform to a pipeline. This should be
possible.

- Overview:
  - Implement the missing functions in Pipeline/PipelineDecl. They are currently marked "fail ...".
  - Verify that the layout code for shader uniforms work properly. This may be the case, since the
    functionality is partially shared with input/output parameters.

** Ability to render to textures (or similar).

This is a requirement for more advanced techniques, such as shadow mapping.

- Overvoew:
  - Modifying the Texture class to allow us to create GPU-writable textures of specific sizes.
  - Allowing Pipelines to render to one (or more) textures. This can be done by providing an
    additional 'render' method that also accepts a texture, for example. Alternatively, we mark
    the outputs as "texture0", "texture1", etc. to indicate that we want to use the pipeline
    to render to texture(s) instead of rendering to the screeen.
  - Some plumbing to actually make the rendering happen.
  - Note: it would be interesting to support textures with fewer than 4 channels (e.g. back buffers).

- Examples that can be used to guide the implementation are:
  - https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping
  - https://medium.com/@martinRenou/real-time-rendering-of-water-caustics-59cda1d74aa


** Allow using Graphics2D and Graphics3D without attaching them to a window

Using a Graphics2D to render to an Image would, for example, allow rendering fonts to a texture and
then drawing them in 3D. A large part of the infrastructure for this is already there. One simply
needs to create a suitable rendering surface (potentially software rendered) and use the existing
code to render to an Image.

** Interop between 2D and 3D

It would be nice to be able to attach a painter to a texture (in the 3D world) or a Bitmap (in the
2D world), so that one can use the 2D rendering pipeline to render to a texture and then use it in
the 3D world. Vice versa with 3D - that would for example allow embedding 3D stuff inside
presentations.

This does not necessarily have to be in textures. For example, rendering 3D into a 2D surface might
work more or less natively (at least when both backends are based on D3D or OpenGL, respectively).

To some degree this would already be possible with "Allow using Graphics2D and 3D without attaching
them to a window". However, that would require a round-trip to CPU memory, which is probably too
expensive for complex scenes.

As a bonus, if we can use a 3D painter inside another 3D painter (which we ought to get for free if
we use BasicPainter), we could implement multipass techniques. However, we would duplicate some
resources due to how everything is structured.

** Rendering sometimes freezes/stutters

In some cases, rendering freezes on Linux, even in continuous mode. This is most likely due to a
timing issue between the rendering code and Gtk. My guess is that the rendering code asks Gtk to
schedule a new frame at the wrong time, so Gtk discards this request. I am not sure exactly when
this "incorrect time" is, however.

** Automatic type casts of literals in the shader language

The shader language is currently more strict than Basic Storm when working with literal values. For
example Vector(1, 2, 3) is not allowed. Instead, one has to write Vector(1.0, 2.0, 3.0).

In the simple case, this can be achieved much in the same way as the "Literal" class in Basic Storm.
