The new filterAttributes() API takes a BitArray, which makes the
internals a lot simpler -- no O(n^2) lookup, no growable arrays, and no
need to duplicate the same code in the ID- and name-based variants.
For consistency with MaterialTools and soon MeshTools, the APIs are
moved to a new Filter.h header, with the deprecated variants kept only
in the original FilterAttributes.h.
This is now the preferrable way to set options to plugins that get
delegated to from other plugins, instead of
Until now there wasn't a general command line interface to pass options
to plugins that get delegated to from other plugins, such as image
converters used by scene converters. Due to that limitation, e.g.
GltfSceneConverter had to add an [imageConverter] configuration group
that it then copied over to the chosen image converter. But such
approach obviously doesn't scale -- every converter would have to do the
same, would have to repeat the whole testing process, and basically the
same would need to be done for all importers delegating to image
plugins. Nightmare.
So there's now --set, which allows arbitrary options to be set for
arbitrary plugins, and that's the preferrable way now. To avoid having
to maintain two ways to do the same, the [imageConverter] group will get
removed eventually.
The main use case is being able to specify what concrete plugin gets
used for a particular alias, e.g. to be able to use SpngImporter instead
of PngImporter for faster PNG image loading.
So far the option is implemented only here, as the imageconverter,
shaderconverter and other tools don't really deal with plugins
that delegate to other plugins. Yet.
Useful for creating pixel formats with different channel count,
adding/removing the sRGB bit and such. Counterpart to
vertexFormat(VertexFormat, UnsignedInt, bool) that got added back in
2020.06 already.
The perf cost is just too great for these to be enabled always. The only
place where the assertions are kept always is in the batch APIs -- there
it's assumed the function is called on large enough data to offset this
overhead, plus since it's often dealing with large blocks of data the
memory safety is more important than various FP drifts which were the
usual case why other assertions were firing.
It compiles on GLES2 as well, but there it hits the massive PITA of
being unable to render to LUMINANXCE formats and GL_RED formats not
really being available everywhere.
I don't have the patience to fix that, and almost nobody needs to use
ES2 platforms nowadays, so this isn't really a priority.
So one can directly read it back on GLES without having to wrap the
texture in a framebuffer again.
This change also puts the framebuffer completeness check *before* the
clear() and bind() which makes it no longer emit a GL error. The error
is still silent though, which isn't nice. Gotta fix that eventually as
well.
This means I (and people making their own plugins) don't need to go and
update each and every plugin once the version in the interface string
gets bumped after a (silent) ABI break. Such as when new virtual
functions get added, as those often lead to strange crashes if the
plugins don't get rebuilt after.
The plugins will now use this macro, which means they'll
automatically embed an interface string that was present in the base
class header at build time. However, when the base class updates, the
previous string is still embedded in the plugin binary, which will then
fail to load -- this being automatic doesn't mean the original purpose
is lost. Subsequently rebuilding the plugins from source will make them
pick up the updated interface string again.
The article this API was originally based on assumes a scenario which
just *isn't* matching usual practices here, giving wrong results. Too
bad I didn't spend more time questioning the proof there and just
blindly assumed it's correct because everyone said so.
Won't be typing all that reasoning again in the commit message, see the
changelog entry and the comment in the test for details.
Taking Animation::TrackViewStorage wasn't really a good idea, as it
wasn't solving anything -- in order to create it, there needs to be a
TrackView of a concrete type first anyway, and even then it required a
lot of additional verbose typing.
The new constructors take basically what TrackView takes, plus there's
additionally a constructor that takes a typeless value view together
with explicitly specified value and result types, allowing a truly
type-erased usage. On the other hand, the templated variants directly
deduce the types without any additional typing, making the construction
similarly straightforward to e.g. SceneFieldData.
In case of the type-erased constructors, if the interpolator function
isn't supplied explicitly, an implicit one is picked based on the value
type, result type and interpolation. Not all combinations make sense of
course, so this is a new assertion point, however compared to the
previous way where the interpolator was picked from a *typed* TrackView,
this doesn't add any new restriction -- what asserted there, asserts now
as well, and additionally you can't have e.g. a Quaternion track with a
boolean result. I may also be eventually adding assertions to check that
the target name matches the result type -- so e.g. a rotation isn't
specified as an integer and such. Compared to newer APIs like MeshData,
MaterialData or SceneData the AnimationData API has a significant lack
of sanity asserts like this.
The `Type` was suggesting it'd be some C++ type, definitely not values
like Scaling3D or Translation2D, resulting in a significant "brain
autocompletion error" every time I was using that type.
Unfortunately on AnimationData the trackTargetType() couldn't similarly
get renamed to trackTarget() as there's already trackTarget() that
contains the node ID the target points to, so it's trackTargetName()
instead. Renaming trackTarget() to trackTargetId() wasn't an option as
that would be inconsistent with everything else (TextureTools::image(),
MaterialAttribute::BaseColorTexture, SceneField::Mesh are all IDs but
they don't have an `Id` suffix); renaming to AnimationTrackTargetName
would keep it insanely long and wouldn't make it consistent either
(MeshAttribute, SceneFIeld, MaterialAttribute are all referred to as
"names" yet they don't have a `Name` suffix).
So it has 32k values for custom targets, instead of just 127. This
makes it consistent with MeshAttribute, which also provides 32k values,
while SceneField has a whole 31-bit range to make it possible to store
arbitrary ECS identifiers as well.
Since this is an ABI break, I'm also shifting the values by 1 to have
zero used for an invalid value, consistently with SceneField,
MeshAttribute etc.
To perform conversion of an already-indexed TriangleStrip to Triangles,
for example, without having to perform an expensive deindexing using
duplicate() first.
To be consistent with what the generate*Indices() APIs expect -- it
doesn't make sense for this API to silently round down while the other
would fail for the same input. In particular, the primitiveCount() may
be used to calculate allocation size for an array to pass to
generate*IndicesInto(), and thus it should use the same rules.
The restriction didn't make sense. Disallowing 1 input vertex for lines
or 1/2 input vertices for triangles sure, but 0 vertices should work as
the expected behavior is obvious.
The GL::Renderer::setClearDepth() and setDepthRange() APIs now use the
non-clamping NV entrypoints if available. The float overloads do that
too, to avoid differences in behavior depending on whether these
functions are called with a float or a double type.
I need alpha to coverage for rendering line caps with MSAA, took it as
an opportunity to expose the other related features as well. Fun how I
survived 12+ years without needing those.
"Funny" how this is the only API where I can't use glCreateTextures().
Like, it would have been so easy to just stop teaching glGen*() and
all their quirks and "this ID exists but it's not an object until you
bind it somewhere actually" to people altogether, BUT NO! FFS.
THe remaining elements are zero-filled, consistently with the behavior
with zeroing out attributes that are missing in subsequent meshes. One
use case is concatenating a mesh with 4 JointIds / Weights into a mesh
that has 8 instead.
Right now, copying larger arrays to smaller arrays is still disallowed
to avoid data loss. That is inconsistent with behavior for attributes
(which are silently left out when not present in the first mesh), I'll
need to think about this more and solve the inconsistency somehow.
Either by allowing array slicing or by failing for unhandled attributes
as well, and the latter makes more sense from the perspective of
avoiding data loss.
Every time I think all std::initializer_list APIs already have an
ArrayView counterpart I discover a new one. (And yes, I did this for
Framebuffer, only to later realize that DefaultFramebuffer suffers from
the same.)
Counterparts to the sRGB-converting APIs, for when one doesn't want to
perform sRGB conversion. Or for "wrong sRGB" workflows. Named like this
and not just `fromRgbInt()` to make the calls at least a bit suspicious.
Exposes MaterialTools::phongToPbrMetallicRoughness() that got added some
time ago. Most of the code and tests is scaffolding needed for direct
material import and processing outside of the addImporterContents()
automagic, similar to what was already done for meshes and images.
In particular, adding more material conversion options such as
canonicalization or deduplication will be significantly easier now that
the basics are done and tested.
Because I got tired of having to manually postprocess ground truth files
for shader tests.
A bit strange / funny that the first ever version of my code manages to
produce smaller files than both stb_image and ImageMagick (with
-compress RunTimeLengthEncoded), for some reason both pick some strange
inefficient run combinations in various scenarios, such as "copy 2" +
"repeat 3" where I pick "repeat 5". And the difference is not
insignificant -- when testing with some shader test files, it resulted
in a ~17% smaller size!
The plugin follows the stricter variant of the spec by default (i.e.,
splitting runs across scanline boundaries) -- so that's *not* the
reason for the weird differences between my code and theirs -- but
provides an option to not do that for even smaller files. Which I'm
going to use for shader ground truth test files, because there every
byte counts. This option together with the above difference causes files
to be ~25% smaller, which is quite a lot.