void256/nifty-gui — pull request #197 by 3xp0n3nt (2014-01-14 22:11:44+00:00)
Title: Major batch rendering system overhaul.

Note: Everything compiles, all tests are passing, and I have tested the rendering system via the nifty-examples in JOGL, LWJGL, and LibGDX, for non-core-profile batch renderers, as I do not have the hardware to test the core profile rendering system, although it compiles and passes the tests as well.

Non-atlas textures:

- A non-atlas texture is a texture that is not within atlas tolerance,
meaning that it takes up too much a percentage of space in the atlas (or
it's width or height or both won't physically fit in the atlas), and
since all atlases and currently the same size, if it is not within atlas
tolerance, it won't fit in any atlas, no matter how empty or full it
might be. The atlas tolerance is separate from the fullness or emptiness
of an atlas.

- Sometimes we need to be able to create large background images that we
don't want consuming an entire atlas, or even high-res images that won't
even "physically" fit in an atlas even if we wanted them to. For these,
it is convenient to render them as a separate, individual, non-atlas
texture in order to allow the use of such large images.

- The performance penalty for having several of these non-atlas textures
is actually very minor. They are simply assigned to their own batch,
since each batch can only have one texture id. You can see it as a
performance benefit actually because you free up so much space in your
atlas.

- Non-atlas textures are managed completely automatically based on the
atlas tolerance.

Multiple texture atlases:

- When an atlas gets too full, we don't want to render every texture
individually. The GPU is actually very good at handling multiple texture
atlases for us with very little performance penalty most of the time.

- The beautiful part is when an atlas gets too full, the next atlas will
be attempted to add the image to, and so on, until, if there are no more
created atlases, a new atlas will be created. And because the image is
within atlas tolerance, it is guaranteed to fit in a newly created,
empty atlas in a worst case scenario =).

- The other beautiful part is that for every image we go back to the
first atlas to attempt upload even if the last image didn't fit
because images are different sizes and there is always more room
available, especially for very small images. This way the atlas space is
not wasted because we don't start every time on the "latest" atlas, we
always rewind back to the beginning. This only happens relatively rarely
during image upload, so the performance penalty is once again moot, and
we gain a lot of performance by utilizing multiple atlases rather than
having the overflow images all be rendered in separate textures.

OpenGL Non-Core-Profile Batch Rendering Changes:

- Create Batch interface, whose begin() method takes not only a
BlendMode parameter as usual, but also a texture id, since each batch
is now going to potentially (not necessarily) be a different texture.

- Create OpenGlBatch, an abstract Batch implementation to provide
default behavior for OpenGL-based Batch implementations, to avoid code
duplication.

- Create LwjglBatch, JoglBatch, & GdxBatch concrete Batch
implementations that extend OpenGlBatch. This gets rid of the static
inner Batch classes that were nasty and had a ton of code duplication.

- Create OpenGlBatchRenderBackend, an abstract BatchRenderBackend
implementation to provide a ton of default behavior for OpenGL-based
Batch implementations, to avoid code duplication. In fact, the
BatchRenderBackend implementations are so similar that most of the real
code is in here.

- Make OpenGlBatchRenderBackend use abstract OpenGL calls, since the
only real difference between the BatchRenderBackend implementations is
the way in which OpenGL calls are invoked.

- Make LwjglBatchRenderBackend, JoglBatchRenderBackend, &
GdxBatchRenderBackend extend OpenGlBatchRenderBackend, and implement
the abstract OpenGL methods from openGlBatchRenderBackend by simply
forwarding the actual OpenGL calls from either LWGJL, JOGL, or LibGDX
libraries. Only the OpenGL constants and methods that are actually used
are implemented, not the entire collection, although that will become
useful in the future for Nifty to have it's own complete OpenGL
abstraction (can't do everything in one commit ;).

- Make OpenGlBatchRenderBackend fully OpenGL ES compatible. It only uses
calls that are available in OpenGL ES, which also works fine with
regular "desktop" OpenGL. OpenGlBatchRenderBackend is a compatibility
class; it seeks to provide the broadest application for classes which
extend it. It does not use any core-profile functionality - that is a
separate project.

- Refactor duplicated fillRemovedTexture system property into
BatchRenderConfiguration, and rename it fillRemovedImagesInAtlas
because that is way clearer. Create fillRemovedImagesInAtlas method in
BatchRenderBackend interface, so that BatchRenderDevice can inject the
BatchRenderConfiguration value into the BatchRenderBackend
implementation.

OpenGL Core Profile Batch Rendering Changes:

- Core Profile BatchRenderBackend's do not yet support multiple texture
atlases or non-atlas textures in this commit, although that will be
following shortly. The methods and framework are present, just not
implemented yet. This won't cause any problems as long as all your stuff
fits in one atlas. If it's a problem, you can temporarily use the
parallel non-core profile BatchRenderBackend.

- Core Profile classes are as lightly refactored as possible while still
adapting to the new framework. This is a work in progress, so there is
still a lot of code duplication here, and a lot of potential for future
refactoring.

- Create LwjglBatchCoreProfile, JoglBatchCoreProfile, &
GdxBatchCoreProfile, which implement the Batch interface. These
classes are simply extracted almost exactly from their original
BatchRenderBackendCoreProfile counterpart.

BatchRenderConfiguration:

- Simple class that uses "LibGDX-style" preferences to cleanly pass
user-options to BatchRenderDevice without the need for a million
telescoping constructors or complex Builder patterns.

- Allow easy configuration of old & new parameters: atlas size, atlas
padding, atlas tolerance, initial number of atlases, whether to
unload / dispose images between screens (requiring reupload) or not,
whether to use high quality texture filtering, and whether to fill in
removed image gaps in the atlas or not.

- These configurations are all very well documents and have nice, sane,
tested defaults so that you don't even have to configure any of these
options unless you really want to.

BatchRenderDevice:
- Create additional constructor to receive a BatchRenderConfiguration
instance
- Make original constructor use BatchRenderConfiguration defaults
- Refactor clipping code into inner Clipping class - increases clarity
and prepares it for moving into its own class eventually
- Overall refactoring and cleanup
- Add textureId parameter to a lot of methods, such as addQuad, since
we can't assume quads are part of a specific texture anymore.
Everything is refactored to remove the assumption about everything being
rendered to the same texture. Everything in this class passes around a
texture id as necessary.
- Add a ton of documentation to the top of the class explaining everything.
- Implement image caching for when the BatchRenderConfiguration option
is set for not disposing of images between screens. When this option is
set to false (don't dispose / unload between screens), screen
re-transitions are lightning fast and buttery smooth because after
visiting a screen once, the images are permanently uploaded, and you
can't run out of atlas space ;).
- Add even more debugging log messages.
- Each atlas has an accompanying TextureAtlasGenerator.
- Much of the changes in this class are changing methods that used to
assume acting on a single atlas to work with multiple atlases
instead, including passing around a texture id.

BatchRenderImage:

- This class was badly in need of an overhaul, and it sure got one -
almost a complete rewrite. Because the upload() method is internal to
the BatchRenderImage itself, much of the multiple texture atlas logic
and non-atlas texture logic is in this class.
- Add a reupload method that takes a texture id and
TextureAtlasGenerator. It is necessary for when the image fails to
upload to the original atlas, then it must be able to reupload to a
different atlas with it's accompanying TextureAtlasGenerator.
- Add a lot of commentary to this class.
- Add a lot of very useful debugging log messages so you can see what's
happening with multiple texture atlases and non-atlas textures
easily.

TextureAtlasGenerator:

- Add 28 tests for TextureAtlasGenerator
- Create new method shouldAddImage that checks whether an image is
within atlas tolerance
- Delete unused TextureAtlasGeneratorException class
- Result is now "Nullable", meaning that you can get a null Result
returned when attempting to add an image to an atlas. That just means
that the iamge was not within atlas tolerance. Anyway, the null Result's
are handled perfectly by BatchRenderImage, and by the
TextureAtlasGenerator tests.
- Add a ton of documentation to this class.

BatchRenderBackend:

- Add a ton of documentation
- Add some new methods for managing non-atlas textures
- Modify atlas methods to take a texture id
- Add a couple new methods for configuring settings from
BatchRenderConfiguration
- Add a createBatch factory method to return the specific concrete Batch
implementation for use with OpenGlBatchRenderBackend - polymorphic
Batch's
- Add a generic type specifier to the class to specify the type of
concrete Batch implementation, mainly for use with the createBatch
method.

Image IO:

- Delete nasty duplicate ImageData interfaces in nifty-renderer-lwjl &
nifty-renderer-jogl2

- Delete nasty duplicate ImageData implementations, TGAImageData &
ImageIOImageData in nifty-renderer-lwjl & nifty-renderer-jogl2

- Rename ImageData interface to ImageLoader, since that's what it is.

- Rename ImageIOImageData & TGAImageData to ImageIOImageLoader &
TGAImageLoader, respectively.

- Create ImageLoaderFactory for creating concrete ImageLoader instances
based on the image filename extension. This code was duplicated all
over the place.

- Move ImageLoader interface, ImageLoaderFactory, TGAImageLoader, &
ImageIOImageLoader to nifty-core/render/io where it belongs

Mouse cursors:

- Add enable() & disable() methods to MouseCursor interface for polymorphic mouse
cursor handling (no more casting or instanceof checks, yay!)
- MouseCursor implementations now take a filename & NiftyResourceLoader in
their constructors to keep messy image loading code internal

Faux changes:

There are some files that appear to have every line changed but that is
not the case at all; it is just git stripping out the evil CRLF
characters.