You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1278 lines
55 KiB

/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "AbstractSceneConverter.h"
#include <Corrade/Containers/AnyReference.h>
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/EnumSet.hpp>
#include <Corrade/Containers/Iterable.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/ScopeGuard.h>
#include <Corrade/Containers/String.h>
#include <Corrade/PluginManager/Manager.hpp>
#include <Corrade/Utility/Path.h>
#include "Magnum/ImageView.h"
#include "Magnum/PixelFormat.h"
#include "Magnum/Trade/AbstractImporter.h"
#include "Magnum/Trade/ArrayAllocator.h"
#include "Magnum/Trade/ImageData.h"
#include "Magnum/Trade/MeshData.h"
#include "Magnum/Trade/SceneData.h"
#ifdef MAGNUM_BUILD_DEPRECATED
/* needed by deprecated convertToFile() that takes a std::string */
#include <Corrade/Containers/StringStl.h>
#endif
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
#include "Magnum/Trade/configure.h"
#endif
namespace Corrade { namespace PluginManager {
template class MAGNUM_TRADE_EXPORT Manager<Magnum::Trade::AbstractSceneConverter>;
}}
namespace Magnum { namespace Trade {
using namespace Containers::Literals;
/* Gets allocated in begin*() and deallocated in end*() or abort(). The direct
conversion functions such as convert(const MeshData&) don't directly need
this state, but can indirectly delegate to it, such as when
convert(const MeshData&) is emulated with a sequence of begin(),
add(const MeshData&) and end(). */
struct AbstractSceneConverter::State {
enum class Type {
Convert,
ConvertToData,
ConvertToFile
};
explicit State(Type type): type{type} {
if(type == Type::Convert)
new(&converted.mesh) Containers::Optional<MeshData>{};
else if(type == Type::ConvertToData)
new(&converted.meshToData) Containers::Optional<Containers::Array<char>>{};
else if(type == Type::ConvertToFile)
new(&converted.meshToFile) bool{};
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
~State() {
if(type == Type::Convert)
converted.mesh.~Optional();
else if(type == Type::ConvertToData)
converted.meshToData.~Optional();
else if(type == Type::ConvertToFile)
;
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
Type type;
UnsignedInt sceneCount = 0;
UnsignedInt animationCount = 0;
UnsignedInt lightCount = 0;
UnsignedInt cameraCount = 0;
UnsignedInt skin2DCount = 0;
UnsignedInt skin3DCount = 0;
UnsignedInt meshCount = 0;
UnsignedInt materialCount = 0;
UnsignedInt textureCount = 0;
UnsignedInt image1DCount = 0;
UnsignedInt image2DCount = 0;
UnsignedInt image3DCount = 0;
/* Used if type == Type::ConvertToFile. Could theoretically be in the same
allocation as State (ArrayTuple?), or at least reusing the space in
`converted`, but I don't think a single allocation matters that much. */
Containers::String filename;
union Converted {
/* C++, FUCK OFF, what's the point of requiring me to create an
explicit constructor and destructor if I have no way to store or
know the information about the active field at this point?! */
Converted() noexcept {}
~Converted() {}
Containers::Optional<MeshData> mesh;
Containers::Optional<Containers::Array<char>> meshToData;
bool meshToFile;
} converted;
};
Containers::StringView AbstractSceneConverter::pluginInterface() {
return
/* [interface] */
"cz.mosra.magnum.Trade.AbstractSceneConverter/0.2"_s
/* [interface] */
;
}
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
Containers::Array<Containers::String> AbstractSceneConverter::pluginSearchPaths() {
const Containers::Optional<Containers::String> libraryLocation = Utility::Path::libraryLocation(&pluginInterface);
return PluginManager::implicitPluginSearchPaths(
#ifndef MAGNUM_BUILD_STATIC
libraryLocation ? *libraryLocation : Containers::String{},
#else
{},
#endif
#ifdef CORRADE_IS_DEBUG_BUILD
MAGNUM_PLUGINS_SCENECONVERTER_DEBUG_DIR,
#else
MAGNUM_PLUGINS_SCENECONVERTER_DIR,
#endif
#ifdef CORRADE_IS_DEBUG_BUILD
"magnum-d/"
#else
"magnum/"
#endif
"sceneconverters"_s);
}
#endif
AbstractSceneConverter::AbstractSceneConverter() = default;
AbstractSceneConverter::AbstractSceneConverter(PluginManager::Manager<AbstractSceneConverter>& manager): PluginManager::AbstractManagingPlugin<AbstractSceneConverter>{manager} {}
AbstractSceneConverter::AbstractSceneConverter(PluginManager::AbstractManager& manager, const Containers::StringView& plugin): PluginManager::AbstractManagingPlugin<AbstractSceneConverter>{manager, plugin} {}
AbstractSceneConverter::~AbstractSceneConverter() = default;
SceneConverterFeatures AbstractSceneConverter::features() const {
const SceneConverterFeatures features = doFeatures();
CORRADE_ASSERT(features, "Trade::AbstractSceneConverter::features(): implementation reported no features", {});
return features;
}
void AbstractSceneConverter::setFlags(SceneConverterFlags flags) {
_flags = flags;
doSetFlags(flags);
}
void AbstractSceneConverter::doSetFlags(SceneConverterFlags) {}
void AbstractSceneConverter::addFlags(SceneConverterFlags flags) {
setFlags(_flags|flags);
}
void AbstractSceneConverter::clearFlags(SceneConverterFlags flags) {
setFlags(_flags & ~flags);
}
Containers::Optional<MeshData> AbstractSceneConverter::convert(const MeshData& mesh) {
abort();
CORRADE_ASSERT(features() & SceneConverterFeature::ConvertMesh,
"Trade::AbstractSceneConverter::convert(): mesh conversion not supported", {});
Containers::Optional<MeshData> out = doConvert(mesh);
CORRADE_ASSERT(!out || (
(!out->_indexData.deleter() || out->_indexData.deleter() == static_cast<void(*)(char*, std::size_t)>(Implementation::nonOwnedArrayDeleter) || out->_indexData.deleter() == ArrayAllocator<char>::deleter) &&
(!out->_vertexData.deleter() || out->_vertexData.deleter() == static_cast<void(*)(char*, std::size_t)>(Implementation::nonOwnedArrayDeleter) || out->_vertexData.deleter() == ArrayAllocator<char>::deleter) &&
(!out->_attributes.deleter() || out->_attributes.deleter() == static_cast<void(*)(MeshAttributeData*, std::size_t)>(Implementation::nonOwnedArrayDeleter))),
"Trade::AbstractSceneConverter::convert(): implementation is not allowed to use a custom Array deleter", {});
return out;
}
Containers::Optional<MeshData> AbstractSceneConverter::doConvert(const MeshData&) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::convert(): mesh conversion advertised but not implemented", {});
}
bool AbstractSceneConverter::convertInPlace(MeshData& mesh) {
abort();
CORRADE_ASSERT(features() & SceneConverterFeature::ConvertMeshInPlace,
"Trade::AbstractSceneConverter::convertInPlace(): mesh conversion not supported", {});
return doConvertInPlace(mesh);
}
bool AbstractSceneConverter::doConvertInPlace(MeshData&) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::convertInPlace(): mesh conversion advertised but not implemented", {});
}
#ifndef MAGNUM_BUILD_DEPRECATED
Containers::Optional<Containers::Array<char>>
#else
Implementation::SceneConverterOptionalButAlsoArray<char>
#endif
AbstractSceneConverter::convertToData(const MeshData& mesh) {
abort();
if(features() >= SceneConverterFeature::ConvertMeshToData) {
Containers::Optional<Containers::Array<char>> out = doConvertToData(mesh);
CORRADE_ASSERT(!out || !out->deleter() || out->deleter() == static_cast<void(*)(char*, std::size_t)>(Implementation::nonOwnedArrayDeleter) || out->deleter() == ArrayAllocator<char>::deleter,
"Trade::AbstractSceneConverter::convertToData(): implementation is not allowed to use a custom Array deleter", {});
/* GCC 4.8 needs an explicit conversion here */
#ifdef MAGNUM_BUILD_DEPRECATED
return Implementation::SceneConverterOptionalButAlsoArray<char>{std::move(out)};
#else
return out;
#endif
} else if(features() >= (SceneConverterFeature::ConvertMultipleToData|SceneConverterFeature::AddMeshes)) {
beginData();
if(add(mesh)) return endData();
/* Finish the conversion even if add() fails -- this API shouldn't
leave it in an in-progress state */
abort();
return {};
} else CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::convertToData(): mesh conversion not supported", {});
}
Containers::Optional<Containers::Array<char>> AbstractSceneConverter::doConvertToData(const MeshData&) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::convertToData(): mesh conversion advertised but not implemented", {});
}
bool AbstractSceneConverter::convertToFile(const MeshData& mesh, const Containers::StringView filename) {
abort();
if(features() >= SceneConverterFeature::ConvertMeshToFile) {
return doConvertToFile(mesh, filename);
} else if(features() & (SceneConverterFeature::ConvertMultipleToFile|SceneConverterFeature::AddMeshes)) {
beginFile(filename);
if(add(mesh)) return endFile();
/* Finish the conversion even if add() fails -- this API shouldn't
leave it in an in-progress state */
abort();
return false;
} else CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::convertToFile(): mesh conversion not supported", {});
}
#ifdef MAGNUM_BUILD_DEPRECATED
bool AbstractSceneConverter::convertToFile(const std::string& filename, const MeshData& mesh) {
return convertToFile(mesh, filename);
}
#endif
bool AbstractSceneConverter::doConvertToFile(const MeshData& mesh, const Containers::StringView filename) {
CORRADE_ASSERT(features() >= SceneConverterFeature::ConvertMeshToData, "Trade::AbstractSceneConverter::convertToFile(): mesh conversion advertised but not implemented", false);
const Containers::Optional<Containers::Array<char>> out = doConvertToData(mesh);
/* No deleter checks as it doesn't matter here */
if(!out) return false;
if(!Utility::Path::write(filename, *out)) {
Error() << "Trade::AbstractSceneConverter::convertToFile(): cannot write to file" << filename;
return false;
}
return true;
}
bool AbstractSceneConverter::isConverting() const {
return !!_state;
}
void AbstractSceneConverter::abort() {
if(!_state) return;
doAbort();
_state = {};
}
void AbstractSceneConverter::doAbort() {}
bool AbstractSceneConverter::begin() {
abort();
_state.emplace(State::Type::Convert);
if(features() >= SceneConverterFeature::ConvertMultiple) {
if(!doBegin()) {
_state = {};
return false;
}
return true;
} else if(features() & SceneConverterFeature::ConvertMesh) {
/* Actual operation performed in doAdd(const MeshData&) */
return true;
} else CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::begin(): feature not supported", {});
}
bool AbstractSceneConverter::doBegin() {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::begin(): feature advertised but not implemented", {});
}
Containers::Pointer<AbstractImporter> AbstractSceneConverter::end() {
CORRADE_ASSERT(_state && _state->type == State::Type::Convert,
"Trade::AbstractSceneConverter::end(): no conversion in progress", {});
Containers::ScopeGuard deleteState{this, [](AbstractSceneConverter* self) {
self->_state = {};
}};
if(features() & SceneConverterFeature::ConvertMesh) {
if(_state->meshCount != 1) {
Error{} << "Trade::AbstractSceneConverter::end(): the converter requires exactly one mesh";
return {};
}
struct SingleMeshImporter: AbstractImporter {
explicit SingleMeshImporter(Containers::Optional<Trade::MeshData>&& mesh) noexcept: _mesh{std::move(mesh)} {}
ImporterFeatures doFeatures() const override { return {}; }
bool doIsOpened() const override { return _opened; }
void doClose() override {
_opened = false;
_mesh = {};
}
UnsignedInt doMeshCount() const override { return 1; }
Containers::Optional<MeshData> doMesh(UnsignedInt, UnsignedInt) override {
/* To avoid complicated logic (such as returning non-owned
data and then having to specify the lifetime guarantees),
the mesh can be retrieved only once. Second time it's an
error. Another option would be to behave like if the
importer is closed afterwards, but that would result in
assertions which isn't nice. */
if(!_mesh) {
Error{} << "Trade::AbstractSceneConverter::end(): mesh can be retrieved only once from a converter with just Trade::SceneConverterFeature::ConvertMesh";
return {};
}
Containers::Optional<Trade::MeshData> out = std::move(_mesh);
_mesh = {};
return out;
}
private:
bool _opened = true;
Containers::Optional<Trade::MeshData> _mesh;
};
return Containers::Pointer<AbstractImporter>(new SingleMeshImporter{std::move(_state->converted.mesh)});
} else if(features() & SceneConverterFeature::ConvertMultiple) {
return doEnd();
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
Containers::Pointer<AbstractImporter> AbstractSceneConverter::doEnd() {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::end(): feature advertised but not implemented", {});
}
bool AbstractSceneConverter::beginData() {
abort();
_state.emplace(State::Type::ConvertToData);
if(features() >= SceneConverterFeature::ConvertMultipleToData) {
if(!doBeginData()) {
_state = {};
return false;
}
return true;
} else if(features() >= SceneConverterFeature::ConvertMeshToData) {
/* Actual operation performed in doAdd(const MeshData&) */
return true;
} else CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::beginData(): feature not supported", {});
}
bool AbstractSceneConverter::doBeginData() {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::beginData(): feature advertised but not implemented", {});
}
Containers::Optional<Containers::Array<char>> AbstractSceneConverter::endData() {
CORRADE_ASSERT(_state && _state->type == State::Type::ConvertToData,
"Trade::AbstractSceneConverter::endData(): no data conversion in progress", {});
Containers::ScopeGuard deleteState{this, [](AbstractSceneConverter* self) {
self->_state = {};
}};
if(features() >= SceneConverterFeature::ConvertMultipleToData) {
Containers::Optional<Containers::Array<char>> out = doEndData();
CORRADE_ASSERT(!out || !out->deleter() || out->deleter() == static_cast<void(*)(char*, std::size_t)>(Implementation::nonOwnedArrayDeleter) || out->deleter() == ArrayAllocator<char>::deleter,
"Trade::AbstractSceneConverter::endData(): implementation is not allowed to use a custom Array deleter", {});
return out;
} else if(features() >= SceneConverterFeature::ConvertMeshToData) {
if(_state->meshCount != 1) {
Error{} << "Trade::AbstractSceneConverter::endData(): the converter requires exactly one mesh";
return {};
}
/* No deleter validity checks here, those were performed in
convertToData(const MeshData&) already */
return std::move(_state->converted.meshToData);
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
Containers::Optional<Containers::Array<char>> AbstractSceneConverter::doEndData() {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::endData(): feature advertised but not implemented", {});
}
bool AbstractSceneConverter::beginFile(const Containers::StringView filename) {
abort();
_state.emplace(State::Type::ConvertToFile);
_state->filename = Containers::String::nullTerminatedGlobalView(filename);
if(features() >= SceneConverterFeature::ConvertMultipleToFile) {
if(!doBeginFile(_state->filename)) {
_state = {};
return false;
}
return true;
} else if(features() >= SceneConverterFeature::ConvertMeshToFile) {
/* Actual operation performed in doAdd(const MeshData&) */
return true;
} else CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::beginFile(): feature not supported", {});
}
bool AbstractSceneConverter::doBeginFile(Containers::StringView) {
CORRADE_ASSERT(features() >= SceneConverterFeature::ConvertMultipleToData,
"Trade::AbstractSceneConverter::beginFile(): feature advertised but not implemented", {});
return doBeginData();
}
bool AbstractSceneConverter::endFile() {
CORRADE_ASSERT(_state && _state->type == State::Type::ConvertToFile,
"Trade::AbstractSceneConverter::endFile(): no file conversion in progress", {});
Containers::ScopeGuard deleteState{this, [](AbstractSceneConverter* self) {
self->_state = {};
}};
if(features() >= SceneConverterFeature::ConvertMultipleToFile) {
return doEndFile(_state->filename);
} else if(features() & SceneConverterFeature::ConvertMeshToFile) {
if(_state->meshCount != 1) {
Error{} << "Trade::AbstractSceneConverter::endFile(): the converter requires exactly one mesh, got" << _state->meshCount;
return {};
}
return _state->converted.meshToFile;
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
bool AbstractSceneConverter::doEndFile(const Containers::StringView filename) {
CORRADE_ASSERT(features() >= SceneConverterFeature::ConvertMultipleToData,
"Trade::AbstractSceneConverter::endFile(): feature advertised but not implemented", {});
const Containers::Optional<Containers::Array<char>> data = doEndData();
/* No deleter checks as it doesn't matter here */
if(!data) return false;
if(!Utility::Path::write(filename, *data)) {
Error{} << "Trade::AbstractSceneConverter::endFile(): cannot write to file" << filename;
return false;
}
return true;
}
UnsignedInt AbstractSceneConverter::sceneCount() const {
CORRADE_ASSERT(_state, "Trade::AbstractSceneConverter::sceneCount(): no conversion in progress", {});
return _state->sceneCount;
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const SceneData& scene, const Containers::StringView name) {
CORRADE_ASSERT(features() & SceneConverterFeature::AddScenes,
"Trade::AbstractSceneConverter::add(): scene conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
if(doAdd(_state->sceneCount, scene, name))
return _state->sceneCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const SceneData& scene) {
return add(scene, {});
}
bool AbstractSceneConverter::doAdd(UnsignedInt, const SceneData&, Containers::StringView) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::add(): scene conversion advertised but not implemented", {});
}
void AbstractSceneConverter::setSceneFieldName(const SceneField field, const Containers::StringView name) {
CORRADE_ASSERT(features() & SceneConverterFeature::AddScenes,
"Trade::AbstractSceneConverter::setSceneFieldName(): feature not supported", );
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::setSceneFieldName(): no conversion in progress", );
CORRADE_ASSERT(isSceneFieldCustom(field),
"Trade::AbstractSceneConverter::setSceneFieldName():" << field << "is not custom", );
doSetSceneFieldName(sceneFieldCustom(field), name);
}
void AbstractSceneConverter::doSetSceneFieldName(UnsignedInt, Containers::StringView) {}
void AbstractSceneConverter::setObjectName(const UnsignedLong object, const Containers::StringView name) {
CORRADE_ASSERT(features() & SceneConverterFeature::AddScenes,
"Trade::AbstractSceneConverter::setObjectName(): feature not supported", );
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::setObjectName(): no conversion in progress", );
doSetObjectName(object, name);
}
void AbstractSceneConverter::doSetObjectName(UnsignedLong, Containers::StringView) {}
void AbstractSceneConverter::setDefaultScene(const UnsignedInt id) {
CORRADE_ASSERT(features() & SceneConverterFeature::AddScenes,
"Trade::AbstractSceneConverter::setDefaultScene(): feature not supported", );
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::setDefaultScene(): no conversion in progress", );
CORRADE_ASSERT(id < _state->sceneCount,
"Trade::AbstractSceneConverter::setDefaultScene(): index" << id << "out of range for" << _state->sceneCount << "scenes", );
doSetDefaultScene(id);
}
void AbstractSceneConverter::doSetDefaultScene(UnsignedInt) {}
UnsignedInt AbstractSceneConverter::animationCount() const {
CORRADE_ASSERT(_state, "Trade::AbstractSceneConverter::animationCount(): no conversion in progress", {});
return _state->animationCount;
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const AnimationData& animation, const Containers::StringView name) {
CORRADE_ASSERT(features() & SceneConverterFeature::AddAnimations,
"Trade::AbstractSceneConverter::add(): animation conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
if(doAdd(_state->animationCount, animation, name))
return _state->animationCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const AnimationData& animation) {
return add(animation, {});
}
bool AbstractSceneConverter::doAdd(UnsignedInt, const AnimationData&, Containers::StringView) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::add(): animation conversion advertised but not implemented", {});
}
UnsignedInt AbstractSceneConverter::lightCount() const {
CORRADE_ASSERT(_state, "Trade::AbstractSceneConverter::lightCount(): no conversion in progress", {});
return _state->lightCount;
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const LightData& light, const Containers::StringView name) {
CORRADE_ASSERT(features() & SceneConverterFeature::AddLights,
"Trade::AbstractSceneConverter::add(): light conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
if(doAdd(_state->lightCount, light, name))
return _state->lightCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const LightData& light) {
return add(light, {});
}
bool AbstractSceneConverter::doAdd(UnsignedInt, const LightData&, Containers::StringView) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::add(): light conversion advertised but not implemented", {});
}
UnsignedInt AbstractSceneConverter::cameraCount() const {
CORRADE_ASSERT(_state, "Trade::AbstractSceneConverter::cameraCount(): no conversion in progress", {});
return _state->cameraCount;
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const CameraData& camera, const Containers::StringView name) {
CORRADE_ASSERT(features() & SceneConverterFeature::AddCameras,
"Trade::AbstractSceneConverter::add(): camera conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
if(doAdd(_state->cameraCount, camera, name))
return _state->cameraCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const CameraData& camera) {
return add(camera, {});
}
bool AbstractSceneConverter::doAdd(UnsignedInt, const CameraData&, Containers::StringView) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::add(): camera conversion advertised but not implemented", {});
}
UnsignedInt AbstractSceneConverter::skin2DCount() const {
CORRADE_ASSERT(_state, "Trade::AbstractSceneConverter::skin2DCount(): no conversion in progress", {});
return _state->skin2DCount;
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const SkinData2D& skin, const Containers::StringView name) {
CORRADE_ASSERT(features() & SceneConverterFeature::AddSkins2D,
"Trade::AbstractSceneConverter::add(): 2D skin conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
if(doAdd(_state->skin2DCount, skin, name))
return _state->skin2DCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const SkinData2D& skin) {
return add(skin, {});
}
bool AbstractSceneConverter::doAdd(UnsignedInt, const SkinData2D&, Containers::StringView) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::add(): 2D skin conversion advertised but not implemented", {});
}
UnsignedInt AbstractSceneConverter::skin3DCount() const {
CORRADE_ASSERT(_state, "Trade::AbstractSceneConverter::skin3DCount(): no conversion in progress", {});
return _state->skin3DCount;
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const SkinData3D& skin, const Containers::StringView name) {
CORRADE_ASSERT(features() & SceneConverterFeature::AddSkins3D,
"Trade::AbstractSceneConverter::add(): 3D skin conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
if(doAdd(_state->skin3DCount, skin, name))
return _state->skin3DCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const SkinData3D& skin) {
return add(skin, {});
}
bool AbstractSceneConverter::doAdd(UnsignedInt, const SkinData3D&, Containers::StringView) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::add(): 3D skin conversion advertised but not implemented", {});
}
UnsignedInt AbstractSceneConverter::meshCount() const {
CORRADE_ASSERT(_state, "Trade::AbstractSceneConverter::meshCount(): no conversion in progress", {});
return _state->meshCount;
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const MeshData& mesh, const Containers::StringView name) {
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
if(features() >= SceneConverterFeature::AddMeshes) {
if(!doAdd(_state->meshCount, mesh, name)) return {};
} else if(features() & (SceneConverterFeature::ConvertMesh|
SceneConverterFeature::ConvertMeshToData|
SceneConverterFeature::ConvertMeshToFile)) {
if(_state->meshCount != 0) {
Error{} << "Trade::AbstractSceneConverter::add(): the converter requires exactly one mesh, got" << _state->meshCount + 1;
return {};
}
if(_state->type == State::Type::Convert) {
CORRADE_INTERNAL_ASSERT(features() & SceneConverterFeature::ConvertMesh);
if(!(_state->converted.mesh = doConvert(mesh)))
return {};
} else if(_state->type == State::Type::ConvertToData) {
CORRADE_INTERNAL_ASSERT(features() >= SceneConverterFeature::ConvertMeshToData);
if(!(_state->converted.meshToData = doConvertToData(mesh)))
return {};
} else if(_state->type == State::Type::ConvertToFile) {
CORRADE_INTERNAL_ASSERT(features() & SceneConverterFeature::ConvertMeshToFile);
if(!(_state->converted.meshToFile = doConvertToFile(mesh, _state->filename)))
return {};
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
} else CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::add(): mesh conversion not supported", {});
return _state->meshCount++;
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const MeshData& mesh) {
return add(mesh, {});
}
bool AbstractSceneConverter::doAdd(const UnsignedInt id, const MeshData& mesh, const Containers::StringView name) {
CORRADE_ASSERT(features() >= SceneConverterFeature::MeshLevels, "Trade::AbstractSceneConverter::add(): mesh conversion advertised but not implemented", {});
return doAdd(id, Containers::Iterable<const MeshData>{mesh}, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const MeshData> meshLevels, const Containers::StringView name) {
CORRADE_ASSERT(features() >= (SceneConverterFeature::AddMeshes|SceneConverterFeature::MeshLevels),
"Trade::AbstractSceneConverter::add(): multi-level mesh conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
CORRADE_ASSERT(!meshLevels.isEmpty(),
"Trade::AbstractSceneConverter::add(): at least one mesh level has to be specified", false);
if(doAdd(_state->meshCount, meshLevels, name))
return _state->meshCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const MeshData> meshLevels) {
return add(meshLevels, {});
}
bool AbstractSceneConverter::doAdd(UnsignedInt, Containers::Iterable<const MeshData>, Containers::StringView) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::add(): multi-level mesh conversion advertised but not implemented", {});
}
void AbstractSceneConverter::setMeshAttributeName(const MeshAttribute attribute, const Containers::StringView name) {
CORRADE_ASSERT(features() & SceneConverterFeature::AddMeshes,
"Trade::AbstractSceneConverter::setMeshAttributeName(): feature not supported", );
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::setMeshAttributeName(): no conversion in progress", );
CORRADE_ASSERT(isMeshAttributeCustom(attribute),
"Trade::AbstractSceneConverter::setMeshAttributeName():" << attribute << "is not custom", );
doSetMeshAttributeName(meshAttributeCustom(attribute), name);
}
void AbstractSceneConverter::doSetMeshAttributeName(UnsignedShort, Containers::StringView) {}
UnsignedInt AbstractSceneConverter::materialCount() const {
CORRADE_ASSERT(_state, "Trade::AbstractSceneConverter::materialCount(): no conversion in progress", {});
return _state->materialCount;
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const MaterialData& material, const Containers::StringView name) {
CORRADE_ASSERT(features() & SceneConverterFeature::AddMaterials,
"Trade::AbstractSceneConverter::add(): material conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
if(doAdd(_state->materialCount, material, name))
return _state->materialCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const MaterialData& material) {
return add(material, {});
}
bool AbstractSceneConverter::doAdd(UnsignedInt, const MaterialData&, Containers::StringView) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::add(): material conversion advertised but not implemented", {});
}
UnsignedInt AbstractSceneConverter::textureCount() const {
CORRADE_ASSERT(_state, "Trade::AbstractSceneConverter::textureCount(): no conversion in progress", {});
return _state->textureCount;
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const TextureData& texture, const Containers::StringView name) {
CORRADE_ASSERT(features() & SceneConverterFeature::AddTextures,
"Trade::AbstractSceneConverter::add(): texture conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
if(doAdd(_state->textureCount, texture, name))
return _state->textureCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const TextureData& texture) {
return add(texture, {});
}
bool AbstractSceneConverter::doAdd(UnsignedInt, const TextureData&, Containers::StringView) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::add(): texture conversion advertised but not implemented", {});
}
#ifndef CORRADE_NO_ASSERT
namespace {
template<UnsignedInt dimensions> bool checkImageValidity(const char* const messagePrefix, const ImageData<dimensions>& image) {
/* At some point there might be a file format that allows zero-sized
images, but so far I don't know about any. When such format appears,
this check will get moved to plugin implementations that can't work with
zero-sized images.
Also note that this check isn't done for the Image->Image conversion
above, there zero-sized images and nullptr *could* make sense. */
CORRADE_ASSERT(image.size().product(),
messagePrefix << "can't add image with a zero size:" << image.size(), false);
CORRADE_ASSERT(image.data(),
messagePrefix << "can't add image with a nullptr view", false);
return true;
}
template<UnsignedInt dimensions> bool checkImageValidity(const char* const messagePrefix, const Containers::Iterable<const ImageData<dimensions>> imageLevels) {
CORRADE_ASSERT(!imageLevels.isEmpty(),
messagePrefix << "at least one image level has to be specified", false);
const bool isCompressed = imageLevels[0].isCompressed();
const PixelFormat format = isCompressed ? PixelFormat{} : imageLevels[0].format();
const UnsignedInt formatExtra = isCompressed ? 0 : imageLevels[0].formatExtra();
const CompressedPixelFormat compressedFormat = isCompressed ? imageLevels[0].compressedFormat() : CompressedPixelFormat{};
const ImageFlags<dimensions> flags = imageLevels[0].flags();
/* Going through *all* levels although the format assertion is never fired
in the first iteration in order to properly check also the first one for
zero size / nullptr. */
for(std::size_t i = 0; i != imageLevels.size(); ++i) {
CORRADE_ASSERT(imageLevels[i].size().product(),
messagePrefix << "can't add image level" << i << "with a zero size:" << imageLevels[i].size(), false);
CORRADE_ASSERT(imageLevels[i].data(),
messagePrefix << "can't add image level" << i << "with a nullptr view", false);
CORRADE_ASSERT(imageLevels[i].isCompressed() == isCompressed,
messagePrefix << "image level" << i << (isCompressed ? "is not" : "is") << "compressed but previous" << (isCompressed ? "are" : "aren't"), false);
if(!isCompressed) {
CORRADE_ASSERT(imageLevels[i].format() == format,
messagePrefix << "image levels don't have the same format, expected" << format << "but got" << imageLevels[i].format() << "for level" << i, false);
CORRADE_ASSERT(imageLevels[i].formatExtra() == formatExtra,
messagePrefix << "image levels don't have the same extra format field, expected" << formatExtra << "but got" << imageLevels[i].formatExtra() << "for level" << i, false);
} else {
CORRADE_ASSERT(imageLevels[i].compressedFormat() == compressedFormat,
messagePrefix << "image levels don't have the same format, expected" << compressedFormat << "but got" << imageLevels[i].compressedFormat() << "for level" << i, false);
}
CORRADE_ASSERT(imageLevels[i].flags() == flags,
messagePrefix << "image levels don't have the same flags, expected" << flags << "but got" << imageLevels[i].flags() << "for level" << i, false);
}
return true;
}
}
#endif
UnsignedInt AbstractSceneConverter::image1DCount() const {
CORRADE_ASSERT(_state, "Trade::AbstractSceneConverter::image1DCount(): no conversion in progress", {});
return _state->image1DCount;
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const ImageData1D& image, const Containers::StringView name) {
CORRADE_ASSERT(features() & (image.isCompressed() ? SceneConverterFeature::AddCompressedImages1D : SceneConverterFeature::AddImages1D),
"Trade::AbstractSceneConverter::add():" << (image.isCompressed() ? "compressed 1D" : "1D") << "image conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
#ifndef CORRADE_NO_ASSERT
/* Explicitly return if checks fail for CORRADE_GRACEFUL_ASSERT builds */
if(!checkImageValidity("Trade::AbstractSceneConverter::add():", image))
return {};
#endif
if(doAdd(_state->image1DCount, image, name))
return _state->image1DCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const ImageData1D& image) {
return add(image, {});
}
bool AbstractSceneConverter::doAdd(const UnsignedInt id, const ImageData1D& image, const Containers::StringView name) {
CORRADE_ASSERT(features() >= SceneConverterFeature::ImageLevels, "Trade::AbstractSceneConverter::add(): 1D image conversion advertised but not implemented", {});
return doAdd(id, Containers::Iterable<const ImageData1D>{image}, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const ImageView1D& image, const Containers::StringView name) {
return add(ImageData1D{image.storage(), image.format(), image.formatExtra(), image.pixelSize(), image.size(), DataFlags{}, image.data(), image.flags()}, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const ImageView1D& image) {
return add(image, {});
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const CompressedImageView1D& image, const Containers::StringView name) {
return add(ImageData1D{image.storage(), image.format(), image.size(), DataFlags{}, image.data(), image.flags()}, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const CompressedImageView1D& image) {
return add(image, {});
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const ImageData1D> imageLevels, const Containers::StringView name) {
#ifndef CORRADE_NO_ASSERT
/* Explicitly return if checks fail for CORRADE_GRACEFUL_ASSERT builds.
Has to be first so we can safely ask for the first item in asserts
below. */
if(!checkImageValidity("Trade::AbstractSceneConverter::add():", imageLevels))
return {};
#endif
CORRADE_ASSERT(features() >= ((imageLevels.front().isCompressed() ? SceneConverterFeature::AddCompressedImages1D : SceneConverterFeature::AddImages1D)|SceneConverterFeature::ImageLevels),
"Trade::AbstractSceneConverter::add(): multi-level" << (imageLevels.front().isCompressed() ? "compressed 1D" : "1D") << "image conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
if(doAdd(_state->image1DCount, imageLevels, name))
return _state->image1DCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const ImageData1D> imageLevels) {
return add(imageLevels, {});
}
bool AbstractSceneConverter::doAdd(UnsignedInt, Containers::Iterable<const ImageData1D>, Containers::StringView) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::add(): multi-level 1D image conversion advertised but not implemented", {});
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const ImageView1D> imageLevels, const Containers::StringView name) {
Containers::Array<ImageData1D> data{NoInit, imageLevels.size()};
for(std::size_t i = 0; i != imageLevels.size(); ++i) {
const ImageView1D& image = imageLevels[i];
new(&data[i]) ImageData1D{image.storage(), image.format(), image.formatExtra(), image.pixelSize(), image.size(), DataFlags{}, image.data(), image.flags()};
}
return add(data, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const ImageView1D> imageLevels) {
return add(imageLevels, {});
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const CompressedImageView1D> imageLevels, const Containers::StringView name) {
Containers::Array<ImageData1D> data{NoInit, imageLevels.size()};
for(std::size_t i = 0; i != imageLevels.size(); ++i) {
const CompressedImageView1D& image = imageLevels[i];
new(&data[i]) ImageData1D{image.storage(), image.format(), image.size(), DataFlags{}, image.data(), image.flags()};
}
return add(data, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const CompressedImageView1D> imageLevels) {
return add(imageLevels, {});
}
UnsignedInt AbstractSceneConverter::image2DCount() const {
CORRADE_ASSERT(_state, "Trade::AbstractSceneConverter::image2DCount(): no conversion in progress", {});
return _state->image2DCount;
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const ImageData2D& image, const Containers::StringView name) {
CORRADE_ASSERT(features() & (image.isCompressed() ? SceneConverterFeature::AddCompressedImages2D : SceneConverterFeature::AddImages2D),
"Trade::AbstractSceneConverter::add():" << (image.isCompressed() ? "compressed 2D" : "2D") << "image conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
#ifndef CORRADE_NO_ASSERT
/* Explicitly return if checks fail for CORRADE_GRACEFUL_ASSERT builds */
if(!checkImageValidity("Trade::AbstractSceneConverter::add():", image))
return {};
#endif
if(doAdd(_state->image2DCount, image, name))
return _state->image2DCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const ImageData2D& image) {
return add(image, {});
}
bool AbstractSceneConverter::doAdd(const UnsignedInt id, const ImageData2D& image, const Containers::StringView name) {
CORRADE_ASSERT(features() >= SceneConverterFeature::ImageLevels, "Trade::AbstractSceneConverter::add(): 2D image conversion advertised but not implemented", {});
return doAdd(id, Containers::Iterable<const ImageData2D>{image}, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const ImageView2D& image, const Containers::StringView name) {
return add(ImageData2D{image.storage(), image.format(), image.formatExtra(), image.pixelSize(), image.size(), DataFlags{}, image.data(), image.flags()}, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const ImageView2D& image) {
return add(image, {});
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const CompressedImageView2D& image, const Containers::StringView name) {
return add(ImageData2D{image.storage(), image.format(), image.size(), DataFlags{}, image.data(), image.flags()}, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const CompressedImageView2D& image) {
return add(image, {});
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const ImageData2D> imageLevels, const Containers::StringView name) {
#ifndef CORRADE_NO_ASSERT
/* Explicitly return if checks fail for CORRADE_GRACEFUL_ASSERT builds.
Has to be first so we can safely ask for the first item in asserts
below. */
if(!checkImageValidity("Trade::AbstractSceneConverter::add():", imageLevels))
return {};
#endif
CORRADE_ASSERT(features() >= ((imageLevels.front().isCompressed() ? SceneConverterFeature::AddCompressedImages2D : SceneConverterFeature::AddImages2D)|SceneConverterFeature::ImageLevels),
"Trade::AbstractSceneConverter::add(): multi-level" << (imageLevels.front().isCompressed() ? "compressed 2D" : "2D") << "image conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
if(doAdd(_state->image2DCount, imageLevels, name))
return _state->image2DCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const ImageData2D> imageLevels) {
return add(imageLevels, {});
}
bool AbstractSceneConverter::doAdd(UnsignedInt, Containers::Iterable<const ImageData2D>, Containers::StringView) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::add(): multi-level 2D image conversion advertised but not implemented", {});
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const ImageView2D> imageLevels, const Containers::StringView name) {
Containers::Array<ImageData2D> data{NoInit, imageLevels.size()};
for(std::size_t i = 0; i != imageLevels.size(); ++i) {
const ImageView2D& image = imageLevels[i];
new(&data[i]) ImageData2D{image.storage(), image.format(), image.formatExtra(), image.pixelSize(), image.size(), DataFlags{}, image.data(), image.flags()};
}
return add(data, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const ImageView2D> imageLevels) {
return add(imageLevels, {});
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const CompressedImageView2D> imageLevels, const Containers::StringView name) {
Containers::Array<ImageData2D> data{NoInit, imageLevels.size()};
for(std::size_t i = 0; i != imageLevels.size(); ++i) {
const CompressedImageView2D& image = imageLevels[i];
new(&data[i]) ImageData2D{image.storage(), image.format(), image.size(), DataFlags{}, image.data(), image.flags()};
}
return add(data, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const CompressedImageView2D> imageLevels) {
return add(imageLevels, {});
}
UnsignedInt AbstractSceneConverter::image3DCount() const {
CORRADE_ASSERT(_state, "Trade::AbstractSceneConverter::image3DCount(): no conversion in progress", {});
return _state->image3DCount;
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const ImageData3D& image, const Containers::StringView name) {
CORRADE_ASSERT(features() & (image.isCompressed() ? SceneConverterFeature::AddCompressedImages3D : SceneConverterFeature::AddImages3D),
"Trade::AbstractSceneConverter::add():" << (image.isCompressed() ? "compressed 3D" : "3D") << "image conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
#ifndef CORRADE_NO_ASSERT
/* Explicitly return if checks fail for CORRADE_GRACEFUL_ASSERT builds */
if(!checkImageValidity("Trade::AbstractSceneConverter::add():", image))
return {};
#endif
if(doAdd(_state->image3DCount, image, name))
return _state->image3DCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const ImageData3D& image) {
return add(image, {});
}
bool AbstractSceneConverter::doAdd(const UnsignedInt id, const ImageData3D& image, const Containers::StringView name) {
CORRADE_ASSERT(features() >= SceneConverterFeature::ImageLevels, "Trade::AbstractSceneConverter::add(): 3D image conversion advertised but not implemented", {});
return doAdd(id, Containers::Iterable<const ImageData3D>{image}, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const ImageView3D& image, const Containers::StringView name) {
return add(ImageData3D{image.storage(), image.format(), image.formatExtra(), image.pixelSize(), image.size(), DataFlags{}, image.data(), image.flags()}, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const ImageView3D& image) {
return add(image, {});
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const CompressedImageView3D& image, const Containers::StringView name) {
return add(ImageData3D{image.storage(), image.format(), image.size(), DataFlags{}, image.data(), image.flags()}, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const CompressedImageView3D& image) {
return add(image, {});
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const ImageData3D> imageLevels, const Containers::StringView name) {
#ifndef CORRADE_NO_ASSERT
/* Explicitly return if checks fail for CORRADE_GRACEFUL_ASSERT builds.
Has to be first so we can safely ask for the first item in asserts
below. */
if(!checkImageValidity("Trade::AbstractSceneConverter::add():", imageLevels))
return {};
#endif
CORRADE_ASSERT(features() >= ((imageLevels.front().isCompressed() ? SceneConverterFeature::AddCompressedImages3D : SceneConverterFeature::AddImages3D)|SceneConverterFeature::ImageLevels),
"Trade::AbstractSceneConverter::add(): multi-level" << (imageLevels.front().isCompressed() ? "compressed 3D" : "3D") << "image conversion not supported", {});
CORRADE_ASSERT(_state,
"Trade::AbstractSceneConverter::add(): no conversion in progress", {});
if(doAdd(_state->image3DCount, imageLevels, name))
return _state->image3DCount++;
return {};
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const ImageData3D> imageLevels) {
return add(imageLevels, {});
}
bool AbstractSceneConverter::doAdd(UnsignedInt, Containers::Iterable<const ImageData3D>, Containers::StringView) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractSceneConverter::add(): multi-level 3D image conversion advertised but not implemented", {});
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const ImageView3D> imageLevels, const Containers::StringView name) {
Containers::Array<ImageData3D> data{NoInit, imageLevels.size()};
for(std::size_t i = 0; i != imageLevels.size(); ++i) {
const ImageView3D& image = imageLevels[i];
new(&data[i]) ImageData3D{image.storage(), image.format(), image.formatExtra(), image.pixelSize(), image.size(), DataFlags{}, image.data(), image.flags()};
}
return add(data, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const ImageView3D> imageLevels) {
return add(imageLevels, {});
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const CompressedImageView3D> imageLevels, const Containers::StringView name) {
Containers::Array<ImageData3D> data{NoInit, imageLevels.size()};
for(std::size_t i = 0; i != imageLevels.size(); ++i) {
const CompressedImageView3D& image = imageLevels[i];
new(&data[i]) ImageData3D{image.storage(), image.format(), image.size(), DataFlags{}, image.data(), image.flags()};
}
return add(data, name);
}
Containers::Optional<UnsignedInt> AbstractSceneConverter::add(const Containers::Iterable<const CompressedImageView3D> imageLevels) {
return add(imageLevels, {});
}
Debug& operator<<(Debug& debug, const SceneConverterFeature value) {
const bool packed = debug.immediateFlags() >= Debug::Flag::Packed;
if(!packed)
debug << "Trade::SceneConverterFeature" << Debug::nospace;
switch(value) {
/* LCOV_EXCL_START */
#define _c(v) case SceneConverterFeature::v: return debug << (packed ? "" : "::") << Debug::nospace << #v;
_c(ConvertMesh)
_c(ConvertMeshInPlace)
_c(ConvertMeshToData)
_c(ConvertMeshToFile)
_c(ConvertMultiple)
_c(ConvertMultipleToData)
_c(ConvertMultipleToFile)
_c(AddScenes)
_c(AddAnimations)
_c(AddLights)
_c(AddCameras)
_c(AddSkins2D)
_c(AddSkins3D)
_c(AddMeshes)
_c(AddMaterials)
_c(AddTextures)
_c(AddImages1D)
_c(AddImages2D)
_c(AddImages3D)
_c(AddCompressedImages1D)
_c(AddCompressedImages2D)
_c(AddCompressedImages3D)
_c(MeshLevels)
_c(ImageLevels)
#undef _c
/* LCOV_EXCL_STOP */
}
return debug << (packed ? "" : "(") << Debug::nospace << reinterpret_cast<void*>(UnsignedInt(value)) << Debug::nospace << (packed ? "" : ")");
}
Debug& operator<<(Debug& debug, const SceneConverterFeatures value) {
return Containers::enumSetDebugOutput(debug, value, debug.immediateFlags() >= Debug::Flag::Packed ? "{}" : "Trade::SceneConverterFeatures{}", {
SceneConverterFeature::ConvertMesh,
SceneConverterFeature::ConvertMeshInPlace,
SceneConverterFeature::ConvertMeshToData,
/* Implied by ConvertMeshToData, has to be after */
SceneConverterFeature::ConvertMeshToFile,
SceneConverterFeature::ConvertMultiple,
SceneConverterFeature::ConvertMultipleToData,
/* Implied by ConvertMultipleToData, has to be after */
SceneConverterFeature::ConvertMultipleToFile,
SceneConverterFeature::AddScenes,
SceneConverterFeature::AddAnimations,
SceneConverterFeature::AddLights,
SceneConverterFeature::AddCameras,
SceneConverterFeature::AddSkins2D,
SceneConverterFeature::AddSkins3D,
SceneConverterFeature::AddMeshes,
SceneConverterFeature::AddMaterials,
SceneConverterFeature::AddTextures,
SceneConverterFeature::AddImages1D,
SceneConverterFeature::AddImages2D,
SceneConverterFeature::AddImages3D,
SceneConverterFeature::AddCompressedImages1D,
SceneConverterFeature::AddCompressedImages2D,
SceneConverterFeature::AddCompressedImages3D,
SceneConverterFeature::MeshLevels,
SceneConverterFeature::ImageLevels});
}
Debug& operator<<(Debug& debug, const SceneConverterFlag value) {
debug << "Trade::SceneConverterFlag" << Debug::nospace;
switch(value) {
/* LCOV_EXCL_START */
#define _c(v) case SceneConverterFlag::v: return debug << "::" #v;
_c(Verbose)
#undef _c
/* LCOV_EXCL_STOP */
}
return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedByte(value)) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, const SceneConverterFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Trade::SceneConverterFlags{}", {
SceneConverterFlag::Verbose});
}
}}