mirror of https://github.com/mosra/magnum.git
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
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()}, 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()}, 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()}; |
|
} |
|
|
|
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()}; |
|
} |
|
|
|
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()}, 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()}, 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()}; |
|
} |
|
|
|
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()}; |
|
} |
|
|
|
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()}, 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()}, 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()}; |
|
} |
|
|
|
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()}; |
|
} |
|
|
|
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}); |
|
} |
|
|
|
}}
|
|
|