Skip to content

Commit

Permalink
Trade: mutable access to MaterialData attribute values.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mosra committed Oct 7, 2021
1 parent 1fb7074 commit 78cf81b
Show file tree
Hide file tree
Showing 5 changed files with 1,005 additions and 25 deletions.
9 changes: 9 additions & 0 deletions doc/snippets/MagnumTrade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,15 @@ if(data.types() & Trade::MaterialType::PbrClearCoat) {
/* [MaterialData-usage-layers-types] */
}

{
Trade::MaterialData data{{}, {}};
/* [MaterialData-usage-mutable] */
Color4& color = data.mutableAttribute<Color4>(Trade::MaterialAttribute::BaseColor);
ColorHsv hsv = color.toHsv();
color.rgb() = Color3::fromHsv({hsv.hue, hsv.saturation*0.85f, hsv.value});
/* [MaterialData-usage-mutable] */
}

{
/* [MaterialData-populating] */
Trade::MaterialData data{Trade::MaterialType::PbrMetallicRoughness, {
Expand Down
100 changes: 98 additions & 2 deletions src/Magnum/Trade/MaterialData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ template<> MAGNUM_TRADE_EXPORT Containers::StringView MaterialAttributeData::val
}
#endif

MaterialData::MaterialData(const MaterialTypes types, Containers::Array<MaterialAttributeData>&& attributeData, Containers::Array<UnsignedInt>&& layerData, const void* const importerState) noexcept: _data{std::move(attributeData)}, _layerOffsets{std::move(layerData)}, _types{types}, _importerState{importerState} {
MaterialData::MaterialData(const MaterialTypes types, Containers::Array<MaterialAttributeData>&& attributeData, Containers::Array<UnsignedInt>&& layerData, const void* const importerState) noexcept: _data{std::move(attributeData)}, _layerOffsets{std::move(layerData)}, _types{types}, _attributeDataFlags{DataFlag::Owned|DataFlag::Mutable}, _layerDataFlags{DataFlag::Owned|DataFlag::Mutable}, _importerState{importerState} {
#ifndef CORRADE_NO_ASSERT
/* Not checking what's already done in MaterialAttributeData constructor.
Done before sorting so the index refers to the actual input index. */
Expand Down Expand Up @@ -247,7 +247,14 @@ MaterialData::MaterialData(const MaterialTypes types, Containers::Array<Material

MaterialData::MaterialData(const MaterialTypes types, const std::initializer_list<MaterialAttributeData> attributeData, const std::initializer_list<UnsignedInt> layerData, const void* const importerState): MaterialData{types, Implementation::initializerListToArrayWithDefaultDeleter(attributeData), Implementation::initializerListToArrayWithDefaultDeleter(layerData), importerState} {}

MaterialData::MaterialData(const MaterialTypes types, DataFlags, const Containers::ArrayView<const MaterialAttributeData> attributeData, DataFlags, Containers::ArrayView<const UnsignedInt> layerData, const void* const importerState) noexcept: _data{Containers::Array<MaterialAttributeData>{const_cast<MaterialAttributeData*>(attributeData.data()), attributeData.size(), reinterpret_cast<void(*)(MaterialAttributeData*, std::size_t)>(Implementation::nonOwnedArrayDeleter)}}, _layerOffsets{Containers::Array<UnsignedInt>{const_cast<UnsignedInt*>(layerData.data()), layerData.size(), reinterpret_cast<void(*)(UnsignedInt*, std::size_t)>(Implementation::nonOwnedArrayDeleter)}}, _types{types}, _importerState{importerState} {
MaterialData::MaterialData(const MaterialTypes types, const DataFlags attributeDataFlags, const Containers::ArrayView<const MaterialAttributeData> attributeData, const DataFlags layerDataFlags, Containers::ArrayView<const UnsignedInt> layerData, const void* const importerState) noexcept: _data{Containers::Array<MaterialAttributeData>{const_cast<MaterialAttributeData*>(attributeData.data()), attributeData.size(), reinterpret_cast<void(*)(MaterialAttributeData*, std::size_t)>(Implementation::nonOwnedArrayDeleter)}}, _layerOffsets{Containers::Array<UnsignedInt>{const_cast<UnsignedInt*>(layerData.data()), layerData.size(), reinterpret_cast<void(*)(UnsignedInt*, std::size_t)>(Implementation::nonOwnedArrayDeleter)}}, _types{types}, _importerState{importerState} {
CORRADE_ASSERT(!(attributeDataFlags & DataFlag::Owned),
"Trade::MaterialData: can't construct with non-owned attribute data but" << attributeDataFlags, );
CORRADE_ASSERT(!(layerDataFlags & DataFlag::Owned),
"Trade::MaterialData: can't construct with non-owned layer data but" << layerDataFlags, );
_attributeDataFlags = attributeDataFlags;
_layerDataFlags = layerDataFlags;

#ifndef CORRADE_NO_ASSERT
/* Not checking what's already done in MaterialAttributeData constructor */
for(std::size_t i = 0; i != _data.size(); ++i)
Expand Down Expand Up @@ -685,6 +692,16 @@ const void* MaterialData::attribute(const UnsignedInt layer, const UnsignedInt i
return _data[layerOffset(layer) + id].value();
}

void* MaterialData::mutableAttribute(const UnsignedInt layer, const UnsignedInt id) {
CORRADE_ASSERT(_attributeDataFlags & DataFlag::Mutable,
"Trade::MaterialData::mutableAttribute(): attribute data not mutable", {});
CORRADE_ASSERT(layer < layerCount(),
"Trade::MaterialData::mutableAttribute(): index" << layer << "out of range for" << layerCount() << "layers", {});
CORRADE_ASSERT(id < attributeCount(layer),
"Trade::MaterialData::mutableAttribute(): index" << id << "out of range for" << attributeCount(layer) << "attributes in layer" << layer, {});
return const_cast<void*>(_data[layerOffset(layer) + id].value());
}

const void* MaterialData::attribute(const UnsignedInt layer, const Containers::StringView name) const {
CORRADE_ASSERT(layer < layerCount(),
"Trade::MaterialData::attribute(): index" << layer << "out of range for" << layerCount() << "layers", {});
Expand All @@ -694,12 +711,29 @@ const void* MaterialData::attribute(const UnsignedInt layer, const Containers::S
return _data[layerOffset(layer) + id].value();
}

void* MaterialData::mutableAttribute(const UnsignedInt layer, const Containers::StringView name) {
CORRADE_ASSERT(_attributeDataFlags & DataFlag::Mutable,
"Trade::MaterialData::mutableAttribute(): attribute data not mutable", {});
CORRADE_ASSERT(layer < layerCount(),
"Trade::MaterialData::mutableAttribute(): index" << layer << "out of range for" << layerCount() << "layers", {});
const UnsignedInt id = attributeFor(layer, name);
CORRADE_ASSERT(id != ~UnsignedInt{},
"Trade::MaterialData::mutableAttribute(): attribute" << name << "not found in layer" << layer, {});
return const_cast<void*>(_data[layerOffset(layer) + id].value());
}

const void* MaterialData::attribute(const UnsignedInt layer, const MaterialAttribute name) const {
const Containers::StringView string = attributeString(name);
CORRADE_ASSERT(string.data(), "Trade::MaterialData::attribute(): invalid name" << name, {});
return attribute(layer, string);
}

void* MaterialData::mutableAttribute(const UnsignedInt layer, const MaterialAttribute name) {
const Containers::StringView string = attributeString(name);
CORRADE_ASSERT(string.data(), "Trade::MaterialData::mutableAttribute(): invalid name" << name, {});
return mutableAttribute(layer, string);
}

const void* MaterialData::attribute(const Containers::StringView layer, const UnsignedInt id) const {
const UnsignedInt layerId = layerFor(layer);
CORRADE_ASSERT(layerId != ~UnsignedInt{},
Expand All @@ -709,6 +743,17 @@ const void* MaterialData::attribute(const Containers::StringView layer, const Un
return _data[layerOffset(layerId) + id].value();
}

void* MaterialData::mutableAttribute(const Containers::StringView layer, const UnsignedInt id) {
CORRADE_ASSERT(_attributeDataFlags & DataFlag::Mutable,
"Trade::MaterialData::mutableAttribute(): attribute data not mutable", {});
const UnsignedInt layerId = layerFor(layer);
CORRADE_ASSERT(layerId != ~UnsignedInt{},
"Trade::MaterialData::mutableAttribute(): layer" << layer << "not found", {});
CORRADE_ASSERT(id < attributeCount(layer),
"Trade::MaterialData::mutableAttribute(): index" << id << "out of range for" << attributeCount(layer) << "attributes in layer" << layer, {});
return const_cast<void*>(_data[layerOffset(layerId) + id].value());
}

const void* MaterialData::attribute(const Containers::StringView layer, const Containers::StringView name) const {
const UnsignedInt layerId = layerFor(layer);
CORRADE_ASSERT(layerId != ~UnsignedInt{},
Expand All @@ -719,30 +764,66 @@ const void* MaterialData::attribute(const Containers::StringView layer, const Co
return _data[layerOffset(layerId) + id].value();
}

void* MaterialData::mutableAttribute(const Containers::StringView layer, const Containers::StringView name) {
CORRADE_ASSERT(_attributeDataFlags & DataFlag::Mutable,
"Trade::MaterialData::mutableAttribute(): attribute data not mutable", {});
const UnsignedInt layerId = layerFor(layer);
CORRADE_ASSERT(layerId != ~UnsignedInt{},
"Trade::MaterialData::mutableAttribute(): layer" << layer << "not found", {});
const UnsignedInt id = attributeFor(layerId, name);
CORRADE_ASSERT(id != ~UnsignedInt{},
"Trade::MaterialData::mutableAttribute(): attribute" << name << "not found in layer" << layer, {});
return const_cast<void*>(_data[layerOffset(layerId) + id].value());
}

const void* MaterialData::attribute(const Containers::StringView layer, const MaterialAttribute name) const {
const Containers::StringView string = attributeString(name);
CORRADE_ASSERT(string.data(), "Trade::MaterialData::attribute(): invalid name" << name, {});
return attribute(layer, string);
}

void* MaterialData::mutableAttribute(const Containers::StringView layer, const MaterialAttribute name) {
const Containers::StringView string = attributeString(name);
CORRADE_ASSERT(string.data(), "Trade::MaterialData::mutableAttribute(): invalid name" << name, {});
return mutableAttribute(layer, string);
}

const void* MaterialData::attribute(const MaterialLayer layer, const UnsignedInt id) const {
const Containers::StringView string = layerString(layer);
CORRADE_ASSERT(string.data(), "Trade::MaterialData::attribute(): invalid name" << layer, {});
return attribute(string, id);
}

void* MaterialData::mutableAttribute(const MaterialLayer layer, const UnsignedInt id) {
const Containers::StringView string = layerString(layer);
CORRADE_ASSERT(string.data(), "Trade::MaterialData::mutableAttribute(): invalid name" << layer, {});
return mutableAttribute(string, id);
}

const void* MaterialData::attribute(const MaterialLayer layer, const Containers::StringView name) const {
const Containers::StringView string = layerString(layer);
CORRADE_ASSERT(string.data(), "Trade::MaterialData::attribute(): invalid name" << layer, {});
return attribute(string, name);
}

void* MaterialData::mutableAttribute(const MaterialLayer layer, const Containers::StringView name) {
const Containers::StringView string = layerString(layer);
CORRADE_ASSERT(string.data(), "Trade::MaterialData::mutableAttribute(): invalid name" << layer, {});
return mutableAttribute(string, name);
}

const void* MaterialData::attribute(const MaterialLayer layer, const MaterialAttribute name) const {
const Containers::StringView string = layerString(layer);
CORRADE_ASSERT(string.data(), "Trade::MaterialData::attribute(): invalid name" << layer, {});
return attribute(string, name);
}

void* MaterialData::mutableAttribute(const MaterialLayer layer, const MaterialAttribute name) {
const Containers::StringView string = layerString(layer);
CORRADE_ASSERT(string.data(), "Trade::MaterialData::mutableAttribute(): invalid name" << layer, {});
return mutableAttribute(string, name);
}

#ifndef DOXYGEN_GENERATING_OUTPUT
/* On Windows (MSVC, clang-cl and MinGw) it needs an explicit export otherwise
the symbol doesn't get exported. */
Expand All @@ -758,6 +839,21 @@ template<> MAGNUM_TRADE_EXPORT Containers::StringView MaterialData::attribute<Co
"Trade::MaterialData::attribute():" << (data._data.data + 1) << "of" << data._data.type << "can't be retrieved as a string", {});
return {data._data.s.nameValue + Implementation::MaterialAttributeDataSize - data._data.s.size - 3, data._data.s.size, Containers::StringViewFlag::NullTerminated};
}

template<> MAGNUM_TRADE_EXPORT Containers::MutableStringView MaterialData::mutableAttribute<Containers::MutableStringView>(const UnsignedInt layer, const UnsignedInt id) {
CORRADE_ASSERT(_attributeDataFlags & DataFlag::Mutable,
"Trade::MaterialData::mutableAttribute(): attribute data not mutable", {});
/* Can't delegate to mutableAttribute() returning void* because that
doesn't include the size */
CORRADE_ASSERT(layer < layerCount(),
"Trade::MaterialData::mutableAttribute(): index" << layer << "out of range for" << layerCount() << "layers", {});
CORRADE_ASSERT(id < attributeCount(layer),
"Trade::MaterialData::mutableAttribute(): index" << id << "out of range for" << attributeCount(layer) << "attributes in layer" << layer, {});
const Trade::MaterialAttributeData& data = _data[layerOffset(layer) + id];
CORRADE_ASSERT(data._data.type == MaterialAttributeType::String,
"Trade::MaterialData::mutableAttribute():" << (data._data.data + 1) << "of" << data._data.type << "can't be retrieved as a string", {});
return {const_cast<char*>(data._data.s.nameValue) + Implementation::MaterialAttributeDataSize - data._data.s.size - 3, data._data.s.size, Containers::StringViewFlag::NullTerminated};
}
#endif

const void* MaterialData::tryAttribute(const UnsignedInt layer, const Containers::StringView name) const {
Expand Down
Loading

0 comments on commit 78cf81b

Please sign in to comment.