This still contained the original message which didn't say the index.
Times changed significantly since then, and the printed index really
proved to be useful.
Also fixing a OOB assertion in the test triggered by the new ArrayView
element access assertions -- the graceful assertion returns the first
element, so we have to have at least one there to return.
This is the first builtin array attribute, with one of the objectives
being an ability to support an arbitrary count of per-vertex weights in
a single contiguous attribute without the complexity of having to go
through several four-component attributes.
On the shader side it still needs to get cut into at most four
components per attribute, but there's no reason for such limitation to
get propagated here as well.
Co-authored-by: Vladimír Vondruš <mosra@centrum.cz>
Finally got an idea how to provide various options store these
efficiently, so it's implemented now. Five different storage variants
times four different type sizes.
These APIs are mostly just for debugging purposes, not widely used, so
it doesn't make sense to have them as constexpr in the header. (Plus the
returned void view is useless in a constexpr context anyway.)
This header size is getting out of hand, so every stripped bit counts.
Also now that they're no longer constexpr, I can go back to using
regular assertions. The reinterpret_cast<> wasn't needed either.
I'm not sure why this restriction was there as nothing was preventing
them from being used. The attribute is only accessible through the
typeless attribute(), which gives back
`Containers::StridedArrayView2D<const char>` with second dimension size
being set to the full stride. And there it doesn't matter if the format
is an array or not.
This will be useful for joint IDs and weights, for example doing crazy
things like packing the IDs into an array of 8 4-bit numbers, saving
half the memory compared to the smallest builtin representation using
UnsignedByte[8].
A lot of pain went into creating owned mesh data even though it was
completely unnecessary in retrospect. Originally I thought "let's not
use any advanced feature" but the verbosity is just not worth it.
In the recent-ish SceneData tests I went with non-owned data already,
and it was much simpler. It's a learning process even for using my own
APIs, huh.
Otherwise it's really, REALLY hard to discover which data are missing in
the output. Especially for files with 1700 meshes, 800 materials, 3600
textures and such.
Which is consistent with about everything else. No idea why I picked
such a strange API name.
Backwards compatibility aliases in place, as these are likely used by a
lot of code already. To ensure I didn't break anything, I'm updating all
code to use the new API in the next commit.
It's four pointers, twice as much as what would be acceptable. Not sure
why this happened, maybe because all those cases used an ArrayView
before and so I just changed the type without considering the difference
in its size?
Unfortunately this change also means a bump in the plugin interface
string, thus all scene converter plugins have to be updated as well.
Of course I used the wrong `CORRADE_FAIL_IF(false, ...)` in a few
places. Yet another confirmation it was too hard to use and a dedicated
macro is needed.
For cases where the whole MaterialAttributeData instance is needed and
calculating the right offset into the array returned by attributeData()
would be too error-prone.
Similar accessor is in MeshData already, so this achieves better feature
parity between the two.
With the following invocation
magnum-sceneconverter --info-importer -I GltfImporter \
-i customSceneFieldTypes/foo=Int
the newly-added option wasn't visible in the configuration printout
because the printer exited right once encountering the Doxygen
[configuration_] snippet marker in the file, and the option got added
after it. Now it's continuing after the marker and the newly-added
option is visible.
Lists features, aliases as well as documented contents of the whole
configuration file. Useful to not need to look up online docs when
working on the command line.
They're each a totally different beast and putting them into the same
test file doesn't really make sense:
- We want to link certain plugins statically on static builds to test
certain code paths in the implementation. However this is
counter-productive for the executable tests because there we are
checking for plugin presence from the test with the assumption that
the executable and the test have the exact same set of plugins
available (or linked statically).
- The executable tests are implemented on Unix only at the moment,
thus it's wasteful to try to build it on any other platforms. Having
it in a separate file makes it much easier to deal with.
Because storing arbitrary data as a string was not good:
- It *never* followed alignment requirements due to the last byte being
used for size. Instead the size is now stored before the data, and
thus the data is always on the 64 byte boundary.
- As it could contain arbitrary binary data, it could cause
magnum-sceneconverter --material-info to print garbage, corrupt the
terminal or, worst case, crash. Not good.
- It stored an implicit \0, which was unnecessary.
Makes a lot of use cases significantly simpler -- apart from the trivial
"convert an OBJ to a glTF" scenario, many processing steps are about
passing most data through but only doing a pass on meshes, or images, or
materials. And this simplifies that use case quite a lot.
This is only "driver" code, with no new interfaces for the plugins. For
them it still looks like all data, their names and related metadata were
added one by one.
Also, a suprisingly large amount of code for this feature.
It was quite a pile, and all of it was written just once, relying only
on hopefully-available model files that would hopefully touch most code
paths. Which means, extremely annoying to make changes in.
I extracted the code to a header that can be tested with a mocked-up
importer and without having to execute the utility itself, deduplicated
the image info printing code, fixed various inconsistencies (such as
data/field flags sometimes denoted with superfluous "flags:" and
sometimes not) and TODOs (such as 2D/3D skins, where there was no format
whatsoever that would have 2D skin support, so the code couldn't get
written).
Now it's finally possible to easily add the remaining missing features,
such as printing camera info.
This happened because I made an early implementation of the batch
AbstractSceneConverter APIs, stashed it away, then implemented image
flags and then continued working on the stash, unaware that it's
outdated.
The enum-to-string conversion was just a private API and we need to use
it in various material filtering code. It was also a private class member
for some reason, even though it has no relation to / dependency on the
MaterialData class. So it's made a free function instead.
Unlike most other options, where a plugin can support 3D but not 2D or
compressed but not uncompressed data, the "levels" option is orthogonal
to the rest -- if a format supports multi-level data, it obviously also
supports a case where there is just a single level, and if it supports
multi-level images, then it likely supports them for 1D, 2D and 3D, not
just some.
I used the same reasoning for the new SceneConverterFeatures interfaces
already, just "backporting" it here as well.
The bit pattern actually followed this already, but for some reason I
still went ahead and stamped out all possible combinations. Because
of that, nothing really changes on the ABI side either and the
deprecated aliases are now exactly as they were before, so no need to
bump the plugin interface version.
And properly test the behavior as well. While it's rare that a batch
and immediate conversions would be mixed on a single converter instance,
if it happens by accident it should not lead to unexpected internal
state.
Initially I thought there was no reason for this to fail, but then
realized AnySceneConverter would need it. And also any other plugin
relying on something external that might fail during initialization --
there's no other moment after plugin instantiation where it could
signalize a failure, and deferring that to the first add() call,
whichever would it be, is really not a sane idea.
Wasn't really possible to split this into multiple commits, so here's
the whole thing including delegation from and to the single-mesh APIs.
What's not done here and postponed for later is:
- an ability to feed the whole importer to it, filtering away data that
aren't supported by the converter
- corresponding changes in AbstractImageConverter, where it would now
primarily accept ImageData to future-proof for arbitrary extra
key/value data
They are required to have the same format already, so flags make sense
as well -- what's the point of saving a multi-level cube map with one of
the levels being just a 2D array, anyway?
With the intention that those will eventually contain also things like
YUp / YDown, PremultipliedAlpha and such.
This commit is mostly just busywork, wiring this into [Compressed]Image,
[Compressed]ImageView and Trade::ImageData and ensuring the flags get
correctly propagated during moves and conversions. Unfortunately in case
of Trade::ImageData it meant deprecating the current set of constructor
in order to insert an ImageFlags parameter before the importer state
pointer.
The only non-trivial piece of logic is when a 2D
[Compressed]ImageView gets converted to a 3D one, then the Array bit is
implicitly dropped, as 2D arrays of 1D images are not really a thing.
Instead, it's now possible to add new flags when doing the conversion --
for example to turn a 2D image to a (single-layer) 2D array image.