Building a mesh from scratch makes the test much easier to grasp and
allows me to test more corner cases together instead of having to add
special cases for offset-only, array and implementation-specific
attributes.
The test now also uncovers a potential optimization opportunity where a
copy of the attribute metadata could be avoided in some cases. Not
implementing it right now, just adding a TODO and an XFAIL.
A bit sad it took me three years to invent the right name for this
utility, heh. Also moving it together with others to a new
MeshTools/Copy.h header because *this* is the mainly useful API, not
reference() / mutableReference().
MaterialTools and SceneTools will get similar copy() APIs doing the same
thing.
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.
Instead of saying "which is not supported" in each assert, which is
vague and might imply that "it eventually will be supported", document
the actual reason in a single place, which is the MeshAttributeData docs.
This is unfortunately a breaking change to compileLines(), which now
takes the output of generateLines() instead of a line mesh. There's a
new assertion that'll blow up if the code is used the previous way,
sorry for the breakage.
What's however very useful about this change is that now it's possible
to take those generated line meshes and concatenate() them together,
achieving what's otherwise not implemented yet, such as drawing several
disconnected line strips or loops together.
It's all still partially private (the custom mesh attribute names are)
and I'm marking both APIs as experimental now to hint that it's not in
the final form/functionality yet. In particular, the data layout
optimizations described in the shader docs aren't used by these tools
yet, and if/once the line-specific vertex attributes become builtin,
compileLines() will not need to exist anymore as compile() will handle
that directly.
Currently just the bare minimum, more features such as handling
multiple contiguous strips and loops inside a single mesh or an
overlapping layout will come later.
Otherwise it may be hard to guess which of them is failing. *Ideally*
the assert would also contain the stride vs type size, maybe I do
that next time I spend that much time investigating why it asserts.
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.
Before it was checked only inside generate*IndicesInto() the function
delegates to, which was too late as the arrays would be allocated with
an insanely high size at that point.
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.
And also add a compiledPerVertexJointCount() helper which returns the
amount of components used in the primary and secondary joint IDs /
weights slots.
Co-authored-by: Squareys <squareys@googlemail.com>
Which is currently the case for any two attributes of the same name
(such as two texture coordinate sets), or bitangents and object ID used
together.
Plus extending the check for matrix attributes (such as instanced
transformation conflicting with secondary joint IDs and weights).
None of these attributes are builtin though, so the check can't be
verified at the moment.
And also documenting the behavior, for some reason the comment was
apparently not updated since the MeshData2D/MeshData3D days!
To be clear -- it would work even without, as it'd fall back to
calculating the range of the weights attribute and choosing an epsilon
based on that, but now it takes a shortcut as Weights are known to be in
a [0, 1] range.
What's especially nice is that the code snippets no longer need to
describe that there's "2 lights, 3 materials and 5 draws" because now
it's self-documenting.
Consistently with checkLink(), this avoids having to explicitly include
both Iterable and Reference in shader code. Alsod allowing people to
have direct arrays of shaders, runtime-sized lists of shaders etc.
A compat include is provided on a deprecated build to avoid breaking
existing code.
There's no reason for those to exist anymore -- origiinally they were
added in a hopeful attempt to make use of parallel shader compilation,
but in practice that meant compiling at most two or three shaders at
once and still stalling until that was done, so not that great at all.
The new APIs provide much better opportunities for parallelism.
Fun fact:
CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile() && frag.compile());
is actually one character shorter than
CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag}));
so not even typing convenience would be a reason to keep these.
This allows people to directly pass Containers::Array<Trade::MeshData>
there, without having to put them to an annoying temporary
Containers::Array<Containers::Reference<const Trade::MeshData>.
The Iterable header is included for backwards compatibility, apart from
that there should be no breaking change.