Selection of libraries designed to be used with Emu projects. This was originally a Math library only, but has since been changed to hold all Emu libraries to enable consistency in changes to dependencies (such as EmuCore modifications).
Colours may be instantiated with 3 or 4 channels, for RGB or RGBA respectively.
Custom channel types may be used for colours. This means that you can choose higher or lower precisions where necessary.
For example, some use cases may be fine with 0:255 integer range colour channels, whereas others may want more precision such as a normalised 0:1 floating point intensity range.
Colours are not managed by default aside from channel conversions when constructed/assigned with other colours.
It is the user's responsibility to ensure that their colours are in a valid state.
This sticks in line with not paying for what you don't use.
In addition, it doesn't force a certain validation method to be used, which allows users to choose between different methods (such as clamping and wrapping) where each is more suitable.
There is a validation layer template which ensures colours remain valid based on a provided functor.
This template should not be directly used by users, as it is more of an internal EmuMath tool.
This has been used to provide two clearer templates for users to instantiate:
WrappedColour, and its aliases WrappedColourRGB and WrappedColourRGBA, which will automatically wrap colour channels into a valid intensity range.
For example, in a normalised 0:1 range, 1.1 will be wrapped to 0.1, and -0.1 will be wrapped to 0.9.
ClampedColour, and its aliases ClampedColourRGB and ClampedColourRGBA, which will automatically clamp colour channels into a valid intensity range.
For example, in a normalised 0:1 range, 1.1 will be clamped to 1.0 and -0.1 will be clamped to 0.0.
This also means that any base EmuMath::Colour instances - or aliases thereof - taken as arguments should be validated if in a situation where invalid colour data could cause problems and it is possible that invalid data could potentially be provided.
Colours may freely be converted between different types, with conversions automatic and hidden under the hood. The intended view of colours is not with their raw values, but as a ratio of their maximum intensity.
It should be noted that signed integers may be used as well as unsigned integers. The minimum valid intensity for these values will still be 0, and thus signed integers should only be chosen over unsigned integers if reduced accuracy is a desirable effect.
For example, reducing the range of a byte from 255 to 127 by choosing std::int8_t over std::uint8_t.
Gradients may be formed to seamlessly interpolate within an array of colours.
Gradients store separate colour and alpha maps. This serves several purposes:
Reduces memory usage and construction time when emplacing colours since we only need the RGB for a colour.
Allows interpolated colours to be formed separately from alpha, where alpha transitions may have different rates compared to colour transitions.
Maintains the ability for users to have a gradient which includes alpha, although it will be more verbose.
Two function calls instead of 1, as they'll need to call AddColourAnchor(...) and AddAlphaAnchor(...) (note: this is pseudocode).
Allows colours to exist separately from alphas, so colours may be added without needing dummy alphas and vice versa.
This is loosely related to the second point, since the separate existence means easier and technically faster interpolations.
New and existing colours may freely be added and removed from gradients, but they will maintain a state where they contain at least one anchor point for each map.
Colours are validated when received (as per the description for colours above), and users may choose how this validation is performed.
Anchor points are in a normalised 0:1 range. By default, provided points are clamped, but when accessing the user has the option to instead wrap points.
Primarily exists as ease-of-use for gradients that loop on themselves.
Gradients may freely be converted between channel types through construction just like Colours.
Gradients provide an interface which, by default, provides suitable output for its contain channel type.
This interface is made up of template functions, which allow the user to output as any channel type, and in the case of retrieving colours only gives the option to output an RGBA colour with its alpha default-initialised.
Conversions for alternate channel types are performed automatically on output.
Due to the nature of Gradient input (i.e. validating input colours and channels), output colours are guaranteed to be in a valid state without additional operations.
This means validation overhead is purely in creation of anchor points, and calculating interpolated values can be done simply, which allows many access operations to be performed without extra overhead from constant validation.
0:255
integer range colour channels, whereas others may want more precision such as a normalised0:1
floating point intensity range.EmuMath
tool.WrappedColour
, and its aliasesWrappedColourRGB
andWrappedColourRGBA
, which will automatically wrap colour channels into a valid intensity range.0:1
range,1.1
will be wrapped to0.1
, and-0.1
will be wrapped to0.9
.ClampedColour
, and its aliasesClampedColourRGB
andClampedColourRGBA
, which will automatically clamp colour channels into a valid intensity range.0:1
range,1.1
will be clamped to1.0
and-0.1
will be clamped to0.0
.EmuMath::Colour
instances - or aliases thereof - taken as arguments should be validated if in a situation where invalid colour data could cause problems and it is possible that invalid data could potentially be provided.std::int8_t
overstd::uint8_t
.AddColourAnchor(...)
andAddAlphaAnchor(...)
(note: this is pseudocode).0:1
range. By default, provided points are clamped, but when accessing the user has the option to instead wrap points.