Such an unnecessary footgun -- I was already checking the other case,
having attribute data too short, but this I thought is fine because it's
not leading to any crash. Well it's leading to needless pain and
suffering, that's what it is doing!
And of course already found FIVE such bugs in just Magnum tests alone.
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.
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.
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.
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.
Logic mostly the same as with MaterialAttribute::*TextureCoordinates --
attribute not present is treated the same way as if the layer was 0
(since that's what a 2D non-array texture is, a single-slice array), and
conversely if the attribute is 0 it's the same as if it would be not
present at all. Plus it also gets checked in queries for packed
textures, if everything is the same but the layer is different, then
it's not a packed texture.
The rest of the commit is just busywork for convenience APIs.
Again not publicly documented because I don't like the naming and I
don't have the full behavior and interactions figured out yet -- i.e.,
an array of VertexFormats would be printed with Debug::packed as a long
string of characters without any whitespace. Not good, thus this
feature probably needs to be split in two, with this being named
"compact" or something else.
With really huge materials it's kinda useless to not know which layer
the error happened in -- and usually it's exactly because the layer
indices were specified wrong.
It was a clever harmless trick. Well, it was way more harmless than it
was clever, but even then it caused UBSan to complain. And that's Not A
Good Thing for various reasons, so let's just comply.
The main bad effect of this change is a *slightly* larger list of
exported symbols but until we actually get rid of the major bloats like
<iostream>, <string> and the like, this is not going to have any
measurable impact.
Reason is that Assimp custom material attribute names are also prefixed
with $ and other weird characters, which could lead to them appearing
before $LayerName, causing a layer to falsely appear unnamed. A space,
instead, is before all printable characters so it's guaranteed to be
always first.
Some things you just don't realize at first. Fortunately the binary
layout isn't pinned yet for the serialization format so this change is
mostly fine.
Hah, so many overloads. Not providing mutable access to keys or layer
offsets as that would break the invariant of the internal array always
being sorted.
This is a bit huge because of all the new overloads that take a
MaterialLayer instead of a string, but all that is just boring
boilerplate. Additionally this:
* exposes glTF clear coat parameters (which, interestingly enough,
reuse existing attributes and don't introduce any new)
* provides a convenience wrapper in PbrClearCoatMaterialData
* and a convenience base for material layer wrappers that redirect
all APIs with implicit layer argument to desired layer instead of the
base material
Well, "basic". Practically mirrors glTF PBR materials:
- builtin metallic/roughness
- the KHR_materials_pbrSpecularGlossiness extension
- extra normal/occlusion/emission maps
- exposes the implicit metallic/roughness and specular/glossiness
packing, but also allows separate maps with arbitrary packings as
well as two-channel normal maps (instead of three-channel)
- provides convenience checks for the most common packing schemes
including MSFT_packing_normalRoughnessMetallic and the three variants
of MSFT_packing_occlusionRoughnessMetallic
- teaches PhongMaterialData to recognize packed specular/glossiness
maps as well
Next up is exposing at least one layer extension, and then I'm done
here.
Because We Can. No, actually, this will be used for upcoming material
layers, it's not a bloat. However, this means you can do things like
Trade::MaterialData weDoCssHere{{}, {
{"color", "navy"},
{"highlight", "rgba(35, 255, 78, 0.75)"},
{"dropShadow", "var(--shadow-color)"}
}};
Suited mainly for custom app-specific material properties (e.g., actual
texture pointers and handles), not really planning on using this in
Magnum itself.
AbstractMaterialData is now just a typedef to MaterialData, with all
existing public APIs moved to (and marked as deprecated, if they don't
make sense anymore). The new class doesn't have a virtual destructor as
that's not the desired use anymore -- and AbstractImporter::material()
APIs will be returning an Optional instead of a Pointer, which means any
potential subclasses will be sliced away.
PhongMaterialData is reimplemented using the new key/value store,
with no own members anymore -- thus having the same size as
MaterialData, and safe to be casted from it to access the helper APIs.
Compared to previous AbstractMaterialData, which was always just a
single type, the new data can describe several different materials at
once. This is the case for example with glTF, where a material can be
metallic/roughness but also have an alternative description using
specular/glossiness.
Currently the usage is undocumented, but when everything is in place, if
a material advertises given type, it can be then cast to one of
its convenience subclasses.