mirror of https://github.com/mosra/magnum.git
Browse Source
It was quite a pile, and all of it was written just once, relying only on hopefully-available model files that would hopefully touch most code paths. Which means, extremely annoying to make changes in. I extracted the code to a header that can be tested with a mocked-up importer and without having to execute the utility itself, deduplicated the image info printing code, fixed various inconsistencies (such as data/field flags sometimes denoted with superfluous "flags:" and sometimes not) and TODOs (such as 2D/3D skins, where there was no format whatsoever that would have 2D skin support, so the code couldn't get written). Now it's finally possible to easily add the remaining missing features, such as printing camera info.pull/580/head
23 changed files with 2699 additions and 984 deletions
@ -0,0 +1,966 @@
|
||||
#ifndef Magnum_SceneTools_Implementation_sceneConverterUtilities_h |
||||
#define Magnum_SceneTools_Implementation_sceneConverterUtilities_h |
||||
/*
|
||||
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 <cctype> /* std::isupper() */ |
||||
#include <unordered_map> /* sceneFieldNames */ |
||||
#include <Corrade/Containers/Optional.h> |
||||
#include <Corrade/Containers/Pair.h> |
||||
#include <Corrade/Utility/Arguments.h> |
||||
|
||||
#include "Magnum/Math/FunctionsBatch.h" |
||||
#include "Magnum/Trade/AnimationData.h" |
||||
#include "Magnum/Trade/LightData.h" |
||||
#include "Magnum/Trade/MaterialData.h" |
||||
#include "Magnum/Trade/MeshData.h" |
||||
#include "Magnum/Trade/SceneData.h" |
||||
#include "Magnum/Trade/SkinData.h" |
||||
#include "Magnum/Trade/TextureData.h" |
||||
|
||||
#include "Magnum/Trade/Implementation/converterUtilities.h" |
||||
|
||||
namespace Magnum { namespace SceneTools { namespace Implementation { |
||||
|
||||
using namespace Containers::Literals; |
||||
|
||||
/* Used only in executables where we don't want it to be exported -- in
|
||||
particular magnum-sceneconverter and its tests */ |
||||
namespace { |
||||
|
||||
/** @todo const Array& doesn't work, minmax() would fail to match */ |
||||
template<class T> Containers::String calculateBounds(Containers::Array<T>&& attribute) { |
||||
/** @todo clean up when Debug::toString() exists */ |
||||
std::ostringstream out; |
||||
Debug{&out, Debug::Flag::NoNewlineAtTheEnd} << Debug::packed << Math::minmax(attribute); |
||||
return out.str(); |
||||
} |
||||
|
||||
/* Named attribute index from a global index */ |
||||
/** @todo some helper for this directly on the MeshData class? */ |
||||
UnsignedInt namedAttributeId(const Trade::MeshData& mesh, UnsignedInt id) { |
||||
const Trade::MeshAttribute name = mesh.attributeName(id); |
||||
for(UnsignedInt i = 0; i != mesh.attributeCount(name); ++i) |
||||
if(mesh.attributeId(name, i) == id) return i; |
||||
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ |
||||
} |
||||
|
||||
bool printInfo(const Debug::Flags useColor, const bool useColor24, const Utility::Arguments& args, Trade::AbstractImporter& importer, std::chrono::high_resolution_clock::duration& importTime) { |
||||
struct AnimationInfo { |
||||
UnsignedInt animation; |
||||
Trade::AnimationData data{{}, {}}; |
||||
Containers::String name; |
||||
}; |
||||
|
||||
struct SkinInfo { |
||||
bool twoDimensions; |
||||
UnsignedInt skin; |
||||
UnsignedInt jointCount; |
||||
Containers::String name; |
||||
}; |
||||
|
||||
struct LightInfo { |
||||
UnsignedInt light; |
||||
Trade::LightData data{{}, {}, {}}; |
||||
Containers::String name; |
||||
}; |
||||
|
||||
struct MaterialInfo { |
||||
UnsignedInt material; |
||||
Trade::MaterialData data{{}, {}}; |
||||
Containers::String name; |
||||
}; |
||||
|
||||
struct TextureInfo { |
||||
UnsignedInt texture; |
||||
Trade::TextureData data{{}, {}, {}, {}, {}, {}}; |
||||
Containers::String name; |
||||
}; |
||||
|
||||
struct MeshAttributeInfo { |
||||
std::size_t offset; |
||||
Int stride; |
||||
UnsignedInt arraySize; |
||||
Trade::MeshAttribute name; |
||||
Containers::String customName; |
||||
VertexFormat format; |
||||
Containers::String bounds; |
||||
}; |
||||
|
||||
struct MeshInfo { |
||||
UnsignedInt mesh, level; |
||||
MeshPrimitive primitive; |
||||
UnsignedInt indexCount, vertexCount; |
||||
std::size_t indexOffset; |
||||
Int indexStride; |
||||
Containers::String indexBounds; |
||||
MeshIndexType indexType; |
||||
Containers::Array<MeshAttributeInfo> attributes; |
||||
std::size_t indexDataSize, vertexDataSize; |
||||
Trade::DataFlags indexDataFlags, vertexDataFlags; |
||||
Containers::String name; |
||||
}; |
||||
|
||||
struct SceneFieldInfo { |
||||
Trade::SceneField name; |
||||
Trade::SceneFieldFlags flags; |
||||
Trade::SceneFieldType type; |
||||
UnsignedInt arraySize; |
||||
std::size_t size; |
||||
}; |
||||
|
||||
struct SceneInfo { |
||||
UnsignedInt scene; |
||||
Trade::SceneMappingType mappingType; |
||||
UnsignedLong mappingBound; |
||||
Containers::Array<SceneFieldInfo> fields; |
||||
std::size_t dataSize; |
||||
Trade::DataFlags dataFlags; |
||||
Containers::String name; |
||||
}; |
||||
|
||||
struct ObjectInfo { |
||||
UnsignedLong object; |
||||
/* A bitfield, assuming no more than 32 scenes */ |
||||
/** @todo might be too little? */ |
||||
UnsignedInt scenes; |
||||
Containers::Array<Containers::Pair<Trade::SceneField, UnsignedInt>> fields; |
||||
Containers::String name; |
||||
}; |
||||
|
||||
/* Parse everything first to avoid errors interleaved with output */ |
||||
bool error = false; |
||||
|
||||
/* Object properties */ |
||||
Containers::Array<ObjectInfo> objectInfos; |
||||
if(args.isSet("info") || args.isSet("info-objects")) { |
||||
objectInfos = Containers::Array<ObjectInfo>{std::size_t(importer.objectCount())}; |
||||
|
||||
for(UnsignedLong i = 0; i != importer.objectCount(); ++i) { |
||||
objectInfos[i].object = i; |
||||
objectInfos[i].name = importer.objectName(i); |
||||
} |
||||
} |
||||
|
||||
/* Scene properties, together with counting how much is each mesh / light /
|
||||
material / skin / object referenced (which gets used only if both |
||||
--info-scenes and --info-{lights,materials,skins,objects} is passed and |
||||
the file has at least one scene). Texture reference count is calculated |
||||
when parsing materials. */ |
||||
Containers::Array<SceneInfo> sceneInfos; |
||||
/* Only the very latest GCC seems to support enum classes as keys and I
|
||||
can't be bothered to write a std::hash specialization, so just making |
||||
the key typeless */ |
||||
std::unordered_map<UnsignedInt, Containers::String> sceneFieldNames; |
||||
Containers::Array<UnsignedInt> materialReferenceCount; |
||||
Containers::Array<UnsignedInt> lightReferenceCount; |
||||
Containers::Array<UnsignedInt> meshReferenceCount; |
||||
Containers::Array<UnsignedInt> skin2DReferenceCount; |
||||
Containers::Array<UnsignedInt> skin3DReferenceCount; |
||||
if((args.isSet("info") || args.isSet("info-scenes")) && importer.sceneCount()) { |
||||
materialReferenceCount = Containers::Array<UnsignedInt>{importer.materialCount()}; |
||||
lightReferenceCount = Containers::Array<UnsignedInt>{importer.lightCount()}; |
||||
meshReferenceCount = Containers::Array<UnsignedInt>{importer.meshCount()}; |
||||
skin2DReferenceCount = Containers::Array<UnsignedInt>{importer.skin2DCount()}; |
||||
skin3DReferenceCount = Containers::Array<UnsignedInt>{importer.skin3DCount()}; |
||||
|
||||
for(UnsignedInt i = 0; i != importer.sceneCount(); ++i) { |
||||
Containers::Optional<Trade::SceneData> scene = importer.scene(i); |
||||
if(!scene) { |
||||
error = true; |
||||
continue; |
||||
} |
||||
|
||||
SceneInfo info{}; |
||||
info.scene = i; |
||||
info.mappingType = scene->mappingType(); |
||||
info.mappingBound = scene->mappingBound(); |
||||
info.dataSize = scene->data().size(); |
||||
info.dataFlags = scene->dataFlags(); |
||||
info.name = importer.sceneName(i); |
||||
for(UnsignedInt j = 0; j != scene->fieldCount(); ++j) { |
||||
const Trade::SceneField name = scene->fieldName(j); |
||||
|
||||
if(name == Trade::SceneField::Mesh) for(const Containers::Pair<UnsignedInt, Containers::Pair<UnsignedInt, Int>>& meshMaterial: scene->meshesMaterialsAsArray()) { |
||||
if(meshMaterial.second().first() < meshReferenceCount.size()) |
||||
++meshReferenceCount[meshMaterial.second().first()]; |
||||
if(UnsignedInt(meshMaterial.second().second()) < materialReferenceCount.size()) |
||||
++materialReferenceCount[meshMaterial.second().second()]; |
||||
} |
||||
|
||||
if(name == Trade::SceneField::Skin) for(const Containers::Pair<UnsignedInt, UnsignedInt> skin: scene->skinsAsArray()) { |
||||
if(scene->is2D() && skin.second() < skin2DReferenceCount.size()) |
||||
++skin2DReferenceCount[skin.second()]; |
||||
if(scene->is3D() && skin.second() < skin3DReferenceCount.size()) |
||||
++skin3DReferenceCount[skin.second()]; |
||||
} |
||||
|
||||
if(name == Trade::SceneField::Light) for(const Containers::Pair<UnsignedInt, UnsignedInt>& light: scene->lightsAsArray()) { |
||||
if(light.second() < lightReferenceCount.size()) |
||||
++lightReferenceCount[light.second()]; |
||||
} |
||||
|
||||
arrayAppend(info.fields, InPlaceInit, |
||||
name, |
||||
scene->fieldFlags(j), |
||||
scene->fieldType(j), |
||||
scene->fieldArraySize(j), |
||||
scene->fieldSize(j)); |
||||
|
||||
/* If the field has a custom name, save it into the map. Not
|
||||
putting it into the fields array as the map is reused by |
||||
object info as well. */ |
||||
if(Trade::isSceneFieldCustom(name)) { |
||||
/* Fetch the name only if it's not already there */ |
||||
const auto inserted = sceneFieldNames.emplace(sceneFieldCustom(name), Containers::String{}); |
||||
if(inserted.second) |
||||
inserted.first->second = importer.sceneFieldName(name); |
||||
} |
||||
|
||||
if(objectInfos) for(const UnsignedInt object: scene->mappingAsArray(j)) { |
||||
if(object >= objectInfos.size()) continue; |
||||
|
||||
objectInfos[object].object = object; |
||||
objectInfos[object].scenes |= 1 << i; |
||||
|
||||
/* If the field is repeated, increase the count instead */ |
||||
if(!objectInfos[object].fields.isEmpty() && objectInfos[object].fields.back().first() == name) |
||||
++objectInfos[object].fields.back().second(); |
||||
else |
||||
arrayAppend(objectInfos[object].fields, InPlaceInit, name, 1u); |
||||
} |
||||
} |
||||
|
||||
arrayAppend(sceneInfos, std::move(info)); |
||||
} |
||||
} |
||||
|
||||
/* Animation properties */ |
||||
Containers::Array<AnimationInfo> animationInfos; |
||||
if(args.isSet("info") || args.isSet("info-animations")) for(UnsignedInt i = 0; i != importer.animationCount(); ++i) { |
||||
Containers::Optional<Trade::AnimationData> animation; |
||||
{ |
||||
Trade::Implementation::Duration d{importTime}; |
||||
if(!(animation = importer.animation(i))) { |
||||
error = true; |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
AnimationInfo info{}; |
||||
info.animation = i; |
||||
info.name = importer.animationName(i); |
||||
info.data = *std::move(animation); |
||||
|
||||
arrayAppend(animationInfos, std::move(info)); |
||||
} |
||||
|
||||
/* Skin properties */ |
||||
Containers::Array<SkinInfo> skinInfos; |
||||
if(args.isSet("info") || args.isSet("info-skins")) { |
||||
for(UnsignedInt i = 0; i != importer.skin2DCount(); ++i) { |
||||
Containers::Optional<Trade::SkinData2D> skin; |
||||
{ |
||||
Trade::Implementation::Duration d{importTime}; |
||||
if(!(skin = importer.skin2D(i))) { |
||||
error = true; |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
SkinInfo info{}; |
||||
info.twoDimensions = true; |
||||
info.skin = i; |
||||
info.name = importer.skin2DName(i); |
||||
info.jointCount = skin->joints().size(); |
||||
|
||||
arrayAppend(skinInfos, std::move(info)); |
||||
} |
||||
|
||||
for(UnsignedInt i = 0; i != importer.skin3DCount(); ++i) { |
||||
Containers::Optional<Trade::SkinData3D> skin; |
||||
{ |
||||
Trade::Implementation::Duration d{importTime}; |
||||
if(!(skin = importer.skin3D(i))) { |
||||
error = true; |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
SkinInfo info{}; |
||||
info.twoDimensions = false; |
||||
info.skin = i; |
||||
info.name = importer.skin3DName(i); |
||||
info.jointCount = skin->joints().size(); |
||||
|
||||
arrayAppend(skinInfos, std::move(info)); |
||||
} |
||||
} |
||||
|
||||
/* Light properties */ |
||||
Containers::Array<LightInfo> lightInfos; |
||||
if(args.isSet("info") || args.isSet("info-lights")) for(UnsignedInt i = 0; i != importer.lightCount(); ++i) { |
||||
Containers::Optional<Trade::LightData> light; |
||||
{ |
||||
Trade::Implementation::Duration d{importTime}; |
||||
if(!(light = importer.light(i))) { |
||||
error = true; |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
LightInfo info{}; |
||||
info.light = i; |
||||
info.name = importer.lightName(i); |
||||
info.data = *std::move(light); |
||||
|
||||
arrayAppend(lightInfos, std::move(info)); |
||||
} |
||||
|
||||
/* Material properties, together with how much is each texture shared
|
||||
(which gets used only if both --info-materials and --info-textures is |
||||
passed and the file has at least one material). */ |
||||
Containers::Array<MaterialInfo> materialInfos; |
||||
Containers::Array<UnsignedInt> textureReferenceCount; |
||||
if((args.isSet("info") || args.isSet("info-materials")) && importer.materialCount()) { |
||||
textureReferenceCount = Containers::Array<UnsignedInt>{importer.textureCount()}; |
||||
|
||||
for(UnsignedInt i = 0; i != importer.materialCount(); ++i) { |
||||
Containers::Optional<Trade::MaterialData> material; |
||||
{ |
||||
Trade::Implementation::Duration d{importTime}; |
||||
if(!(material = importer.material(i))) { |
||||
error = true; |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
/* Calculate texture reference count for all properties that look
|
||||
like a texture */ |
||||
for(UnsignedInt j = 0; j != material->layerCount(); ++j) { |
||||
for(UnsignedInt k = 0; k != material->attributeCount(j); ++k) { |
||||
if(material->attributeType(j, k) != Trade::MaterialAttributeType::UnsignedInt || !material->attributeName(j, k).hasSuffix("Texture"_s)) |
||||
continue; |
||||
|
||||
const UnsignedInt texture = material->attribute<UnsignedInt>(j, k); |
||||
/** @todo once StridedBitArrayView2D exists, fix this to
|
||||
count each material only once by having one bit for |
||||
every material and texture */ |
||||
if(texture < textureReferenceCount.size()) |
||||
++textureReferenceCount[texture]; |
||||
} |
||||
} |
||||
|
||||
MaterialInfo info{}; |
||||
info.material = i; |
||||
info.name = importer.materialName(i); |
||||
info.data = *std::move(material); |
||||
|
||||
arrayAppend(materialInfos, std::move(info)); |
||||
} |
||||
} |
||||
|
||||
/* Mesh properties */ |
||||
Containers::Array<MeshInfo> meshInfos; |
||||
if(args.isSet("info") || args.isSet("info-meshes")) for(UnsignedInt i = 0; i != importer.meshCount(); ++i) { |
||||
for(UnsignedInt j = 0; j != importer.meshLevelCount(i); ++j) { |
||||
Containers::Optional<Trade::MeshData> mesh; |
||||
{ |
||||
Trade::Implementation::Duration d{importTime}; |
||||
if(!(mesh = importer.mesh(i, j))) { |
||||
error = true; |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
MeshInfo info{}; |
||||
info.mesh = i; |
||||
info.level = j; |
||||
info.primitive = mesh->primitive(); |
||||
info.vertexCount = mesh->vertexCount(); |
||||
info.vertexDataSize = mesh->vertexData().size(); |
||||
info.vertexDataFlags = mesh->vertexDataFlags(); |
||||
if(!j) { |
||||
info.name = importer.meshName(i); |
||||
} |
||||
if(mesh->isIndexed()) { |
||||
info.indexCount = mesh->indexCount(); |
||||
info.indexType = mesh->indexType(); |
||||
info.indexOffset = mesh->indexOffset(); |
||||
info.indexStride = mesh->indexStride(); |
||||
info.indexDataSize = mesh->indexData().size(); |
||||
info.indexDataFlags = mesh->indexDataFlags(); |
||||
if(args.isSet("bounds")) |
||||
info.indexBounds = calculateBounds(mesh->indicesAsArray()); |
||||
} |
||||
for(UnsignedInt k = 0; k != mesh->attributeCount(); ++k) { |
||||
const Trade::MeshAttribute name = mesh->attributeName(k); |
||||
|
||||
/* Calculate bounds, if requested, if this is not an
|
||||
implementation-specific format and if it's not a custom |
||||
attribute */ |
||||
Containers::String bounds; |
||||
if(args.isSet("bounds") && !isVertexFormatImplementationSpecific(mesh->attributeFormat(k))) switch(name) { |
||||
case Trade::MeshAttribute::Position: |
||||
bounds = calculateBounds(mesh->positions3DAsArray(namedAttributeId(*mesh, k))); |
||||
break; |
||||
case Trade::MeshAttribute::Tangent: |
||||
bounds = calculateBounds(mesh->tangentsAsArray(namedAttributeId(*mesh, k))); |
||||
break; |
||||
case Trade::MeshAttribute::Bitangent: |
||||
bounds = calculateBounds(mesh->bitangentsAsArray(namedAttributeId(*mesh, k))); |
||||
break; |
||||
case Trade::MeshAttribute::Normal: |
||||
bounds = calculateBounds(mesh->normalsAsArray(namedAttributeId(*mesh, k))); |
||||
break; |
||||
case Trade::MeshAttribute::TextureCoordinates: |
||||
bounds = calculateBounds(mesh->textureCoordinates2DAsArray(namedAttributeId(*mesh, k))); |
||||
break; |
||||
case Trade::MeshAttribute::Color: |
||||
bounds = calculateBounds(mesh->colorsAsArray(namedAttributeId(*mesh, k))); |
||||
break; |
||||
case Trade::MeshAttribute::ObjectId: |
||||
bounds = calculateBounds(mesh->objectIdsAsArray(namedAttributeId(*mesh, k))); |
||||
break; |
||||
} |
||||
|
||||
arrayAppend(info.attributes, InPlaceInit, |
||||
mesh->attributeOffset(k), |
||||
mesh->attributeStride(k), |
||||
mesh->attributeArraySize(k), |
||||
name, Trade::isMeshAttributeCustom(name) ? |
||||
importer.meshAttributeName(name) : "", |
||||
mesh->attributeFormat(k), |
||||
bounds); |
||||
} |
||||
|
||||
arrayAppend(meshInfos, std::move(info)); |
||||
} |
||||
} |
||||
|
||||
/* Texture properties, together with how much is each image shared (which
|
||||
gets used only if both --info-textures and --info-images is passed and |
||||
the file has at least one texture). */ |
||||
Containers::Array<TextureInfo> textureInfos; |
||||
Containers::Array<UnsignedInt> image1DReferenceCount; |
||||
Containers::Array<UnsignedInt> image2DReferenceCount; |
||||
Containers::Array<UnsignedInt> image3DReferenceCount; |
||||
if((args.isSet("info") || args.isSet("info-textures")) && importer.textureCount()) { |
||||
image1DReferenceCount = Containers::Array<UnsignedInt>{importer.image1DCount()}; |
||||
image2DReferenceCount = Containers::Array<UnsignedInt>{importer.image2DCount()}; |
||||
image3DReferenceCount = Containers::Array<UnsignedInt>{importer.image3DCount()}; |
||||
for(UnsignedInt i = 0; i != importer.textureCount(); ++i) { |
||||
Containers::Optional<Trade::TextureData> texture; |
||||
{ |
||||
Trade::Implementation::Duration d{importTime}; |
||||
if(!(texture = importer.texture(i))) { |
||||
error = true; |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
switch(texture->type()) { |
||||
case Trade::TextureType::Texture1D: |
||||
if(texture->image() < image1DReferenceCount.size()) |
||||
++image1DReferenceCount[texture->image()]; |
||||
break; |
||||
case Trade::TextureType::Texture1DArray: |
||||
case Trade::TextureType::Texture2D: |
||||
if(texture->image() < image2DReferenceCount.size()) |
||||
++image2DReferenceCount[texture->image()]; |
||||
break; |
||||
case Trade::TextureType::CubeMap: |
||||
case Trade::TextureType::CubeMapArray: |
||||
case Trade::TextureType::Texture2DArray: |
||||
case Trade::TextureType::Texture3D: |
||||
if(texture->image() < image3DReferenceCount.size()) |
||||
++image3DReferenceCount[texture->image()]; |
||||
break; |
||||
} |
||||
|
||||
TextureInfo info{}; |
||||
info.texture = i; |
||||
info.name = importer.textureName(i); |
||||
info.data = *std::move(texture); |
||||
|
||||
arrayAppend(textureInfos, std::move(info)); |
||||
} |
||||
} |
||||
|
||||
Containers::Array<Trade::Implementation::ImageInfo> imageInfos; |
||||
if(args.isSet("info") || args.isSet("info-images")) { |
||||
imageInfos = Trade::Implementation::imageInfo(importer, error, importTime); |
||||
} |
||||
|
||||
std::size_t totalSceneDataSize = 0; |
||||
for(const SceneInfo& info: sceneInfos) { |
||||
Debug d{useColor}; |
||||
d << Debug::boldColor(Debug::Color::Default) << "Scene" << info.scene << Debug::nospace << ":" << Debug::resetColor; |
||||
if(info.name) d << Debug::boldColor(Debug::Color::Yellow) << info.name << Debug::resetColor; |
||||
d << Debug::newline; |
||||
d << " Bound:" << info.mappingBound << "objects" |
||||
<< Debug::color(Debug::Color::Blue) << "@" << Debug::packed |
||||
<< Debug::color(Debug::Color::Cyan) << info.mappingType |
||||
<< Debug::resetColor << "(" << Debug::nospace |
||||
<< Utility::format("{:.1f}", info.dataSize/1024.0f) << "kB"; |
||||
if(info.dataFlags != (Trade::DataFlag::Owned|Trade::DataFlag::Mutable)) |
||||
d << Debug::nospace << "," << Debug::packed |
||||
<< Debug::color(Debug::Color::Green) << info.dataFlags |
||||
<< Debug::resetColor; |
||||
d << Debug::nospace << ")"; |
||||
|
||||
d << Debug::newline << " Fields:"; |
||||
for(const SceneFieldInfo& field: info.fields) { |
||||
d << Debug::newline << " " |
||||
<< Debug::boldColor(Debug::Color::Default); |
||||
if(Trade::isSceneFieldCustom(field.name)) { |
||||
d << "Custom(" << Debug::nospace |
||||
<< Trade::sceneFieldCustom(field.name) |
||||
<< Debug::nospace << ":" << Debug::nospace |
||||
<< Debug::color(Debug::Color::Yellow) |
||||
<< sceneFieldNames[sceneFieldCustom(field.name)] |
||||
<< Debug::nospace |
||||
<< Debug::boldColor(Debug::Color::Default) << ")"; |
||||
} else d << Debug::packed << field.name; |
||||
|
||||
d << Debug::color(Debug::Color::Blue) << "@" << Debug::packed << Debug::color(Debug::Color::Cyan) << field.type; |
||||
if(field.arraySize) |
||||
d << Debug::nospace << Utility::format("[{}]", field.arraySize); |
||||
d << Debug::resetColor; |
||||
if(field.flags) d << Debug::nospace << "," |
||||
<< Debug::packed << Debug::color(Debug::Color::Green) |
||||
<< field.flags << Debug::resetColor; |
||||
d << Debug::nospace << "," << field.size << "entries"; |
||||
} |
||||
|
||||
totalSceneDataSize += info.dataSize; |
||||
} |
||||
if(!sceneInfos.isEmpty()) |
||||
Debug{} << "Total scene data size:" << Utility::format("{:.1f}", totalSceneDataSize/1024.0f) << "kB"; |
||||
|
||||
for(const ObjectInfo& info: objectInfos) { |
||||
/* Objects without a name and not referenced by any scenes are useless,
|
||||
ignore */ |
||||
if(!info.name && !info.scenes) continue; |
||||
|
||||
Debug d{useColor}; |
||||
d << Debug::boldColor(Debug::Color::Default) << "Object" << info.object << Debug::resetColor; |
||||
|
||||
if(sceneInfos) { |
||||
const UnsignedInt count = Math::popcount(info.scenes); |
||||
if(!count) d << Debug::color(Debug::Color::Red); |
||||
d << "(referenced by" << count << "scenes)"; |
||||
if(!count) d << Debug::resetColor; |
||||
} |
||||
|
||||
d << Debug::boldColor(Debug::Color::Default) << Debug::nospace << ":" |
||||
<< Debug::resetColor; |
||||
if(info.name) d << Debug::boldColor(Debug::Color::Yellow) |
||||
<< info.name << Debug::resetColor; |
||||
if(info.scenes) { |
||||
d << Debug::newline << " Fields:"; |
||||
|
||||
for(std::size_t i = 0; i != info.fields.size(); ++i) { |
||||
if(i) d << Debug::nospace << ","; |
||||
const Containers::Pair<Trade::SceneField, UnsignedInt> nameCount = info.fields[i]; |
||||
d << Debug::color(Debug::Color::Cyan); |
||||
if(Trade::isSceneFieldCustom(nameCount.first())) { |
||||
d << "Custom(" << Debug::nospace |
||||
<< Trade::sceneFieldCustom(nameCount.first()) |
||||
<< Debug::nospace << ":" << Debug::nospace |
||||
<< Debug::color(Debug::Color::Yellow) |
||||
<< sceneFieldNames[sceneFieldCustom(nameCount.first())] |
||||
<< Debug::nospace |
||||
<< Debug::color(Debug::Color::Cyan) << ")"; |
||||
} else d << Debug::packed << nameCount.first(); |
||||
if(nameCount.second() != 1) |
||||
d << Debug::nospace << Utility::format("[{}]", nameCount.second()); |
||||
d << Debug::resetColor; |
||||
} |
||||
} |
||||
} |
||||
|
||||
std::size_t totalAnimationDataSize = 0; |
||||
for(const AnimationInfo& info: animationInfos) { |
||||
Debug d{useColor}; |
||||
d << Debug::boldColor(Debug::Color::Default) << "Animation" << info.animation << Debug::nospace << ":" << Debug::resetColor; |
||||
if(info.name) d << Debug::boldColor(Debug::Color::Yellow) << info.name << Debug::resetColor; |
||||
|
||||
d << Debug::newline << " Duration: {" << Debug::nospace |
||||
/** @todo have a nice packed printing for Range instead */ |
||||
<< info.data.duration().min() << Debug::nospace << "," |
||||
<< info.data.duration().max() << Debug::nospace << "} (" |
||||
<< Debug::nospace << Utility::format("{:.1f}", info.data.data().size()/1024.0f) << "kB"; |
||||
if(info.data.dataFlags() != (Trade::DataFlag::Owned|Trade::DataFlag::Mutable)) |
||||
d << Debug::nospace << "," << Debug::packed |
||||
<< Debug::color(Debug::Color::Green) |
||||
<< info.data.dataFlags() << Debug::resetColor; |
||||
d << Debug::nospace << ")"; |
||||
|
||||
for(UnsignedInt i = 0; i != info.data.trackCount(); ++i) { |
||||
d << Debug::newline << " Track" << i << Debug::nospace << ":" |
||||
<< Debug::packed << Debug::boldColor(Debug::Color::Default) |
||||
<< info.data.trackTargetType(i) |
||||
<< Debug::color(Debug::Color::Blue) << "@" |
||||
<< Debug::packed << Debug::color(Debug::Color::Cyan) |
||||
<< info.data.trackType(i) << Debug::resetColor; |
||||
if(info.data.trackType(i) != info.data.trackResultType(i)) |
||||
d << Debug::color(Debug::Color::Blue) << "->" |
||||
<< Debug::packed << Debug::color(Debug::Color::Cyan) |
||||
<< info.data.trackResultType(i) << Debug::resetColor; |
||||
d << Debug::nospace << "," << info.data.track(i).size() |
||||
<< "keyframes"; |
||||
if(info.data.track(i).duration() != info.data.duration()) |
||||
d << Debug::newline << " Duration: {" << Debug::nospace |
||||
/** @todo have a nice packed printing for Range instead */ |
||||
<< info.data.track(i).duration().min() << Debug::nospace |
||||
<< "," << info.data.track(i).duration().max() |
||||
<< Debug::nospace << "}"; |
||||
d << Debug::newline |
||||
<< " Interpolation:" |
||||
<< Debug::packed << Debug::color(info.data.track(i).interpolation() == Animation::Interpolation::Custom ? Debug::Color::Yellow : Debug::Color::Cyan) |
||||
<< info.data.track(i).interpolation() << Debug::resetColor |
||||
<< Debug::nospace << "," << Debug::packed |
||||
<< Debug::color(Debug::Color::Cyan) |
||||
<< info.data.track(i).before() << Debug::resetColor |
||||
<< Debug::nospace << "," << Debug::packed |
||||
<< Debug::color(Debug::Color::Cyan) |
||||
<< info.data.track(i).after() << Debug::resetColor; |
||||
/** @todo might be useful to show bounds here as well, though not
|
||||
so much for things like complex numbers or quats */ |
||||
} |
||||
|
||||
totalAnimationDataSize += info.data.data().size(); |
||||
} |
||||
if(!animationInfos.isEmpty()) |
||||
Debug{} << "Total animation data size:" << Utility::format("{:.1f}", totalAnimationDataSize/1024.0f) << "kB"; |
||||
|
||||
for(const SkinInfo& info: skinInfos) { |
||||
Debug d{useColor}; |
||||
d << Debug::boldColor(Debug::Color::Default) << (info.twoDimensions ? "2D skin" : "3D skin") << info.skin |
||||
<< Debug::resetColor; |
||||
|
||||
/* Print reference count only if there actually are scenes and they
|
||||
were parsed, otherwise this information is useless */ |
||||
if((info.twoDimensions && skin2DReferenceCount) || |
||||
(!info.twoDimensions && skin3DReferenceCount)) |
||||
{ |
||||
const UnsignedInt count = info.twoDimensions ? skin2DReferenceCount[info.skin] : skin3DReferenceCount[info.skin]; |
||||
if(!count) d << Debug::color(Debug::Color::Red); |
||||
d << "(referenced by" << count << "objects)"; |
||||
if(!count) d << Debug::resetColor; |
||||
} |
||||
|
||||
d << Debug::boldColor(Debug::Color::Default) << Debug::nospace << ":" |
||||
<< Debug::resetColor; |
||||
if(info.name) d << Debug::boldColor(Debug::Color::Yellow) |
||||
<< info.name << Debug::resetColor; |
||||
|
||||
d << Debug::newline << " " << info.jointCount << "joints"; |
||||
} |
||||
|
||||
for(const LightInfo& info: lightInfos) { |
||||
Debug d{useColor}; |
||||
d << Debug::boldColor(Debug::Color::Default) << "Light" << info.light << Debug::resetColor; |
||||
|
||||
/* Print reference count only if there actually are scenes and they
|
||||
were parsed, otherwise this information is useless */ |
||||
if(lightReferenceCount) { |
||||
const UnsignedInt count = lightReferenceCount[info.light]; |
||||
if(!count) d << Debug::color(Debug::Color::Red); |
||||
d << "(referenced by" << count << "objects)"; |
||||
if(!count) d << Debug::resetColor; |
||||
} |
||||
|
||||
d << Debug::boldColor(Debug::Color::Default) << Debug::nospace << ":" |
||||
<< Debug::resetColor; |
||||
if(info.name) d << Debug::boldColor(Debug::Color::Yellow) |
||||
<< info.name << Debug::resetColor; |
||||
|
||||
d << Debug::newline << " Type:" << Debug::packed |
||||
<< Debug::color(Debug::Color::Cyan) |
||||
<< info.data.type() << Debug::resetColor; |
||||
if(info.data.type() == Trade::LightData::Type::Spot) |
||||
d << Debug::nospace << "," << Debug::packed |
||||
<< Deg(info.data.innerConeAngle()) << Debug::nospace |
||||
<< "° -" << Debug::packed << Deg(info.data.outerConeAngle()) |
||||
<< Debug::nospace << "°"; |
||||
d << Debug::newline << " Color:"; |
||||
if(useColor24) d << Debug::color |
||||
<< Math::pack<Color3ub>(info.data.color()); |
||||
d << Debug::packed << info.data.color(); |
||||
if(!Math::equal(info.data.intensity(), 1.0f)) |
||||
d << "*" << info.data.intensity(); |
||||
if(info.data.type() != Trade::LightData::Type::Ambient && |
||||
info.data.type() != Trade::LightData::Type::Directional) |
||||
d << Debug::newline << " Attenuation:" << Debug::packed |
||||
<< info.data.attenuation(); |
||||
if(info.data.range() != Constants::inf()) |
||||
d << Debug::newline << " Range:" << Debug::packed |
||||
<< info.data.range(); |
||||
} |
||||
|
||||
for(const MaterialInfo& info: materialInfos) { |
||||
Debug d{useColor}; |
||||
d << Debug::boldColor(Debug::Color::Default) << "Material" << info.material << Debug::resetColor; |
||||
|
||||
/* Print reference count only if there actually are scenes and they
|
||||
were parsed, otherwise this information is useless */ |
||||
if(materialReferenceCount) { |
||||
const UnsignedInt count = materialReferenceCount[info.material]; |
||||
if(!count) d << Debug::color(Debug::Color::Red); |
||||
d << "(referenced by" << count << "objects)"; |
||||
if(!count) d << Debug::resetColor; |
||||
} |
||||
|
||||
d << Debug::boldColor(Debug::Color::Default) << Debug::nospace << ":" |
||||
<< Debug::resetColor; |
||||
if(info.name) d << Debug::boldColor(Debug::Color::Yellow) << info.name << Debug::resetColor; |
||||
|
||||
d << Debug::newline << " Type:" << Debug::packed << Debug::color(Debug::Color::Cyan) << info.data.types() << Debug::resetColor; |
||||
|
||||
for(UnsignedInt i = 0; i != info.data.layerCount(); ++i) { |
||||
/* Print extra layers with extra indent */ |
||||
const char* indent; |
||||
if(info.data.layerCount() != 1 && i != 0) { |
||||
d << Debug::newline << " Layer" << i << Debug::nospace << ":"; |
||||
if(!info.data.layerName(i).isEmpty()) { |
||||
if(std::isupper(info.data.layerName(i)[0])) |
||||
d << Debug::boldColor(Debug::Color::Default); |
||||
else |
||||
d << Debug::color(Debug::Color::Yellow); |
||||
d << info.data.layerName(i) << Debug::resetColor; |
||||
} |
||||
indent = " "; |
||||
} else { |
||||
d << Debug::newline << " Base layer:"; |
||||
indent = " "; |
||||
} |
||||
|
||||
for(UnsignedInt j = 0; j != info.data.attributeCount(i); ++j) { |
||||
/* Ignore layer name (which is always first) unless it's in the
|
||||
base material, in which case we print it as it wouldn't |
||||
otherwise be shown anywhere */ |
||||
if(i && !j && info.data.attributeName(i, j) == " LayerName") |
||||
continue; |
||||
|
||||
d << Debug::newline << indent; |
||||
if(std::isupper(info.data.attributeName(i, j)[0])) |
||||
d << Debug::boldColor(Debug::Color::Default); |
||||
else |
||||
d << Debug::color(Debug::Color::Yellow); |
||||
d << info.data.attributeName(i, j) << Debug::color(Debug::Color::Blue) << "@" << Debug::packed << Debug::color(Debug::Color::Cyan) |
||||
<< info.data.attributeType(i, j) << Debug::resetColor << Debug::nospace |
||||
<< ":"; |
||||
switch(info.data.attributeType(i, j)) { |
||||
#define _c(type) case Trade::MaterialAttributeType::type: \ |
||||
d << Debug::packed << info.data.attribute<type>(i, j); \
|
||||
break; |
||||
/* LCOV_EXCL_START */ |
||||
_c(Float) |
||||
_c(Deg) |
||||
_c(Rad) |
||||
_c(UnsignedInt) |
||||
_c(Int) |
||||
_c(UnsignedLong) |
||||
_c(Long) |
||||
_c(Vector2) |
||||
_c(Vector2ui) |
||||
_c(Vector2i) |
||||
/* Vector3 handled below */ |
||||
_c(Vector3ui) |
||||
_c(Vector3i) |
||||
/* Vector4 handled below */ |
||||
_c(Vector4ui) |
||||
_c(Vector4i) |
||||
_c(Matrix2x2) |
||||
_c(Matrix2x3) |
||||
_c(Matrix2x4) |
||||
_c(Matrix3x2) |
||||
_c(Matrix3x3) |
||||
_c(Matrix3x4) |
||||
_c(Matrix4x2) |
||||
_c(Matrix4x3) |
||||
/* LCOV_EXCL_STOP */ |
||||
#undef _c |
||||
case Trade::MaterialAttributeType::Bool: |
||||
d << info.data.attribute<bool>(i, j); |
||||
break; |
||||
case Trade::MaterialAttributeType::Vector3: |
||||
/** @todo hasSuffix() might be more robust against
|
||||
false positives, but KHR_materials_specular in glTF |
||||
uses ColorFactor :/ */ |
||||
if(useColor24 && info.data.attributeName(i, j).contains("Color"_s)) |
||||
d << Debug::color << Math::pack<Color3ub>(info.data.attribute<Vector3>(i, j)); |
||||
d << Debug::packed << info.data.attribute<Vector3>(i, j); |
||||
break; |
||||
case Trade::MaterialAttributeType::Vector4: |
||||
/** @todo hasSuffix() might be more robust against
|
||||
false positives, but KHR_materials_specular in glTF |
||||
uses ColorFactor :/ */ |
||||
if(useColor24 && info.data.attributeName(i, j).contains("Color"_s)) |
||||
d << Debug::color << Math::pack<Color3ub>(info.data.attribute<Vector4>(i, j).rgb()); |
||||
d << Debug::packed << info.data.attribute<Vector4>(i, j); |
||||
break; |
||||
case Trade::MaterialAttributeType::Pointer: |
||||
d << info.data.attribute<const void*>(i, j); |
||||
break; |
||||
case Trade::MaterialAttributeType::MutablePointer: |
||||
d << info.data.attribute<void*>(i, j); |
||||
break; |
||||
case Trade::MaterialAttributeType::String: |
||||
d << info.data.attribute<Containers::StringView>(i, j); |
||||
break; |
||||
case Trade::MaterialAttributeType::TextureSwizzle: |
||||
d << Debug::packed << info.data.attribute<Trade::MaterialTextureSwizzle>(i, j); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
std::size_t totalMeshDataSize = 0; |
||||
for(const MeshInfo& info: meshInfos) { |
||||
Debug d{useColor}; |
||||
if(info.level == 0) { |
||||
d << Debug::boldColor(Debug::Color::Default) << "Mesh" << info.mesh << Debug::resetColor; |
||||
|
||||
/* Print reference count only if there actually are scenes and they
|
||||
were parsed, otherwise this information is useless */ |
||||
if(meshReferenceCount) { |
||||
const UnsignedInt count = meshReferenceCount[info.mesh]; |
||||
if(!count) d << Debug::color(Debug::Color::Red); |
||||
d << "(referenced by" << count << "objects)"; |
||||
if(!count) d << Debug::resetColor; |
||||
} |
||||
|
||||
d << Debug::boldColor(Debug::Color::Default) << Debug::nospace << ":" |
||||
<< Debug::resetColor; |
||||
if(info.name) d << Debug::boldColor(Debug::Color::Yellow) << info.name << Debug::resetColor; |
||||
d << Debug::newline; |
||||
} |
||||
d << " Level" << info.level << Debug::nospace << ":" |
||||
<< info.vertexCount << "vertices" << Debug::color(Debug::Color::Blue) << "@" << Debug::packed << Debug::color(Debug::Color::Cyan) << info.primitive << Debug::resetColor << "(" << Debug::nospace |
||||
<< Utility::format("{:.1f}", info.vertexDataSize/1024.0f) |
||||
<< "kB"; |
||||
if(info.vertexDataFlags != (Trade::DataFlag::Owned|Trade::DataFlag::Mutable)) |
||||
d << Debug::nospace << "," << Debug::packed |
||||
<< Debug::color(Debug::Color::Green) |
||||
<< info.vertexDataFlags << Debug::resetColor; |
||||
d << Debug::nospace << ")"; |
||||
|
||||
for(const MeshAttributeInfo& attribute: info.attributes) { |
||||
d << Debug::newline << " " |
||||
<< Debug::boldColor(Debug::Color::Default); |
||||
if(Trade::isMeshAttributeCustom(attribute.name)) { |
||||
d << "Custom(" << Debug::nospace |
||||
<< Trade::meshAttributeCustom(attribute.name) |
||||
<< Debug::nospace << ":" << Debug::nospace |
||||
<< Debug::color(Debug::Color::Yellow) |
||||
<< attribute.customName << Debug::nospace |
||||
<< Debug::boldColor(Debug::Color::Default) << ")"; |
||||
} else d << Debug::packed << attribute.name; |
||||
|
||||
d << Debug::color(Debug::Color::Blue) << "@" << Debug::packed << Debug::color(Debug::Color::Cyan) << attribute.format; |
||||
if(attribute.arraySize) |
||||
d << Debug::nospace << Utility::format("[{}]", attribute.arraySize); |
||||
d << Debug::resetColor; |
||||
d << Debug::nospace << ", offset" << attribute.offset; |
||||
d << Debug::nospace << ", stride" |
||||
<< attribute.stride; |
||||
if(attribute.bounds) |
||||
d << Debug::newline << " Bounds:" << attribute.bounds; |
||||
} |
||||
|
||||
if(info.indexType != MeshIndexType{}) { |
||||
d << Debug::newline << " " << info.indexCount << "indices" << Debug::color(Debug::Color::Blue) << "@" |
||||
<< Debug::packed << Debug::color(Debug::Color::Cyan) << info.indexType << Debug::resetColor << Debug::nospace << ", offset" << info.indexOffset << Debug::nospace << ", stride" << info.indexStride << "(" << Debug::nospace |
||||
<< Utility::format("{:.1f}", info.indexDataSize/1024.0f) |
||||
<< "kB"; |
||||
if(info.indexDataFlags != (Trade::DataFlag::Owned|Trade::DataFlag::Mutable)) |
||||
d << Debug::nospace << "," << Debug::packed |
||||
<< Debug::color(Debug::Color::Green) << info.indexDataFlags << Debug::resetColor; |
||||
d << Debug::nospace << ")"; |
||||
if(info.indexBounds) |
||||
d << Debug::newline << " Bounds:" << info.indexBounds; |
||||
} |
||||
|
||||
totalMeshDataSize += info.vertexDataSize + info.indexDataSize; |
||||
} |
||||
if(!meshInfos.isEmpty()) |
||||
Debug{} << "Total mesh data size:" << Utility::format("{:.1f}", totalMeshDataSize/1024.0f) << "kB"; |
||||
|
||||
for(const TextureInfo& info: textureInfos) { |
||||
Debug d{useColor}; |
||||
d << Debug::boldColor(Debug::Color::Default) << "Texture" << info.texture << Debug::resetColor; |
||||
|
||||
/* Print reference count only if there actually are materials and they
|
||||
were parsed, otherwise this information is useless */ |
||||
if(textureReferenceCount) { |
||||
const UnsignedInt count = textureReferenceCount[info.texture]; |
||||
if(!count) d << Debug::color(Debug::Color::Red); |
||||
d << "(referenced by" << count << "material attributes)"; |
||||
if(!count) d << Debug::resetColor; |
||||
} |
||||
|
||||
d << Debug::boldColor(Debug::Color::Default) << Debug::nospace << ":" |
||||
<< Debug::resetColor; |
||||
if(info.name) d << Debug::boldColor(Debug::Color::Yellow) |
||||
<< info.name << Debug::resetColor; |
||||
d << Debug::newline; |
||||
d << " Type:" |
||||
<< Debug::packed |
||||
<< Debug::color(Debug::Color::Cyan) << info.data.type() |
||||
<< Debug::resetColor << Debug::nospace << ", image" |
||||
<< info.data.image(); |
||||
d << Debug::newline << " Minification, mipmap and magnification:" |
||||
<< Debug::packed << Debug::color(Debug::Color::Cyan) |
||||
<< info.data.minificationFilter() << Debug::nospace << "," |
||||
<< Debug::packed << Debug::color(Debug::Color::Cyan) |
||||
<< info.data.mipmapFilter() << Debug::nospace << "," |
||||
<< Debug::packed << Debug::color(Debug::Color::Cyan) |
||||
<< info.data.magnificationFilter() << Debug::resetColor; |
||||
/** @todo show only the dimensions that matter for a particular texture
|
||||
type */ |
||||
d << Debug::newline << " Wrapping:" << Debug::resetColor << "{" << Debug::nospace |
||||
<< Debug::packed << Debug::color(Debug::Color::Cyan) |
||||
<< info.data.wrapping()[0] << Debug::resetColor |
||||
<< Debug::nospace << "," << Debug::packed |
||||
<< Debug::color(Debug::Color::Cyan) << info.data.wrapping()[1] |
||||
<< Debug::resetColor << Debug::nospace << "," << Debug::packed |
||||
<< Debug::color(Debug::Color::Cyan) << info.data.wrapping()[1] |
||||
<< Debug::resetColor << Debug::nospace << "}"; |
||||
} |
||||
|
||||
Trade::Implementation::printImageInfo(useColor, imageInfos, image1DReferenceCount, image2DReferenceCount, image3DReferenceCount); |
||||
|
||||
return error; |
||||
} |
||||
|
||||
} |
||||
|
||||
}}} |
||||
|
||||
#endif |
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,12 @@
|
||||
Animation 0: |
||||
Duration: {0.5, 1.25} (0.1 kB) |
||||
Track 0: Translation2D @ Vector2, 3 keyframes |
||||
Interpolation: Linear, DefaultConstructed, Constant |
||||
Track 1: Rotation2D @ CubicHermite2D -> Vector2, 3 keyframes |
||||
Interpolation: Constant, Extrapolated, Extrapolated |
||||
Animation 1: Custom track duration and interpolator function |
||||
Duration: {0.1, 1.3} (0.1 kB, ExternallyOwned) |
||||
Track 0: Scaling3D @ Vector3, 5 keyframes |
||||
Duration: {0.75, 1.25} |
||||
Interpolation: Custom, DefaultConstructed, Constant |
||||
Total animation data size: 0.2 kB |
||||
@ -0,0 +1,3 @@
|
||||
1D image 0: |
||||
Level 0: {1024} @ R32F (4.0 kB) |
||||
Total image data size: 4.0 kB |
||||
@ -0,0 +1,8 @@
|
||||
Light 0: |
||||
Type: Spot, 55° - 85° |
||||
Color: {0.203922, 0.341176, 1} * 15 |
||||
Attenuation: {1.2, 0.3, 0.04} |
||||
Range: 100 |
||||
Light 1: Directional light with always-implicit attenuation and range |
||||
Type: Directional |
||||
Color: {1, 0.341176, 0.203922} * 5 |
||||
@ -0,0 +1,28 @@
|
||||
Material 0: |
||||
Type: PbrMetallicRoughness |
||||
Base layer: |
||||
BaseColor @ Vector4: {0.231373, 0.823529, 0.403922, 0.6} |
||||
DoubleSided @ Bool: true |
||||
EmissiveColor @ Vector3: {0.054902, 0.619608, 0.792157} |
||||
RoughnessTexture @ UnsignedInt: 67 |
||||
RoughnessTextureMatrix @ Matrix3x3: {1, 0, 0.25, |
||||
0, 1, 0.75, |
||||
0, 0, 1} |
||||
RoughnessTextureSwizzle @ TextureSwizzle: B |
||||
deadBeef @ Pointer: 0xdeadbeef |
||||
notAColour3 @ Vector3: {0.2, 0.3, 0.4} |
||||
notAColour4 @ Vector4: {0.1, 0.2, 0.3, 0.4} |
||||
reflectionAngle @ Deg: 35 |
||||
undeadBeef @ MutablePointer: 0xbeefbeef |
||||
Material 1: Lots o' laierz |
||||
Type: Phong|PbrClearCoat |
||||
Base layer: |
||||
DiffuseColor @ Vector4: {0.780392, 0.811765, 0.184314, 0.6} |
||||
Layer 1: ClearCoat |
||||
LayerFactor @ Float: 0.5 |
||||
LayerFactorTexture @ UnsignedInt: 3 |
||||
Layer 2: anEmptyLayer |
||||
Layer 3: |
||||
LayerFactor @ Float: 0.25 |
||||
LayerFactorTexture @ UnsignedInt: 2 |
||||
yes @ String: a string |
||||
@ -0,0 +1,21 @@
|
||||
Mesh 0: |
||||
Level 0: 2 vertices @ Lines (0.2 kB, {}) |
||||
Position @ Vector3, offset 0, stride 12 |
||||
Bounds: ({0.1, -0.1, -0.2}, {0.2, 0, 0.2}) |
||||
Tangent @ Vector3, offset 24, stride 12 |
||||
Bounds: ({0.2, -0.2, 0.2}, {0.3, 0.8, 0.8}) |
||||
Bitangent @ Vector3, offset 48, stride 12 |
||||
Bounds: ({0.3, 0.2, 0}, {0.4, 0.9, 1}) |
||||
ObjectId @ UnsignedShort, offset 72, stride 2 |
||||
Bounds: (12, 155) |
||||
Normal @ Vector3, offset 76, stride 12 |
||||
Bounds: ({0, 0, 0}, {1, 1, 1}) |
||||
TextureCoordinates @ Vector2, offset 100, stride 8 |
||||
Bounds: ({0.5, 0.5}, {1.5, 0.5}) |
||||
Color @ Vector4, offset 116, stride 16 |
||||
Bounds: ({0.6, 0.2, 0.2, 0}, {1, 0.4, 0.4, 0.2}) |
||||
ObjectId @ UnsignedInt, offset 148, stride 4 |
||||
Bounds: (15, 337) |
||||
3 indices @ UnsignedByte, offset 0, stride 1 (0.0 kB, {}) |
||||
Bounds: (3, 176) |
||||
Total mesh data size: 0.2 kB |
||||
@ -0,0 +1,16 @@
|
||||
Mesh 0: |
||||
Level 0: 50 vertices @ Points (0.6 kB, ExternallyOwned|Mutable) |
||||
Position @ Vector3, offset 0, stride 12 |
||||
70 indices @ UnsignedShort, offset 0, stride 2 (0.1 kB, ExternallyOwned) |
||||
Mesh 1: LODs? No, meshets. |
||||
Level 0: 250 vertices @ Triangles (6.8 kB) |
||||
Position @ Vector3, offset 0, stride 12 |
||||
Tangent @ Vector4, offset 3000, stride 16 |
||||
Level 1: 135 vertices @ Meshlets (83.8 kB) |
||||
Custom(25:vertices) @ UnsignedInt[64], offset 0, stride 256 |
||||
Custom(26:triangles) @ Vector3ub[126], offset 34560, stride 378 |
||||
Custom(37:) @ UnsignedByte, offset 85590, stride 1 |
||||
Custom(116:vertexCount) @ UnsignedByte, offset 85725, stride 1 |
||||
Mesh 2: |
||||
Level 0: 15 vertices @ Instances (0.0 kB) |
||||
Total mesh data size: 91.4 kB |
||||
@ -0,0 +1,5 @@
|
||||
Object 0: Parent-less mesh |
||||
Object 2: Two meshes, shared among two scenes |
||||
Object 4: Two custom arrays |
||||
Object 6: Only in the second scene, but no fields, thus same as unreferenced |
||||
Object 8: Not in any scene |
||||
@ -0,0 +1,98 @@
|
||||
Scene 0: |
||||
Bound: 2 objects @ UnsignedInt (0.1 kB, {}) |
||||
Fields: |
||||
Transformation @ Matrix4x4, 0 entries |
||||
Mesh @ UnsignedInt, 4 entries |
||||
MeshMaterial @ Int, 4 entries |
||||
Light @ UnsignedInt, 4 entries |
||||
Skin @ UnsignedInt, 4 entries |
||||
Scene 1: |
||||
Bound: 4 objects @ UnsignedInt (0.0 kB, {}) |
||||
Fields: |
||||
Transformation @ Matrix3x3, 0 entries |
||||
Mesh @ UnsignedInt, 3 entries |
||||
Skin @ UnsignedInt, 3 entries |
||||
Total scene data size: 0.1 kB |
||||
Object 0 (referenced by 1 scenes): |
||||
Fields: Mesh, MeshMaterial, Light, Skin |
||||
Object 1 (referenced by 2 scenes): |
||||
Fields: Mesh[2], MeshMaterial[2], Light[2], Skin[2], Mesh, Skin |
||||
Object 2 (referenced by 0 scenes): Not referenced |
||||
Object 3 (referenced by 1 scenes): |
||||
Fields: Mesh, Skin |
||||
2D skin 0 (referenced by 1 objects): |
||||
2 joints |
||||
2D skin 1 (referenced by 1 objects): |
||||
3 joints |
||||
2D skin 2 (referenced by 0 objects): Not referenced |
||||
1 joints |
||||
3D skin 0 (referenced by 0 objects): Not referenced |
||||
2 joints |
||||
3D skin 1 (referenced by 2 objects): |
||||
1 joints |
||||
3D skin 2 (referenced by 1 objects): |
||||
3 joints |
||||
Light 0 (referenced by 2 objects): |
||||
Type: Directional |
||||
Color: {0.341176, 1, 0.203922} * 5 |
||||
Light 1 (referenced by 0 objects): Not referenced |
||||
Type: Ambient |
||||
Color: {1, 0.341176, 0.203922} * 0.1 |
||||
Light 2 (referenced by 1 objects): |
||||
Type: Directional |
||||
Color: {0.203922, 0.341176, 1} |
||||
Material 0 (referenced by 2 objects): |
||||
Type: {} |
||||
Base layer: |
||||
BaseColorTexture @ UnsignedInt: 2 |
||||
DiffuseTexture @ UnsignedInt: 2 |
||||
Material 1 (referenced by 1 objects): |
||||
Type: {} |
||||
Base layer: |
||||
EmissiveTexture @ UnsignedInt: 4 |
||||
NormalTexture @ UnsignedInt: 17 |
||||
lookupTexture @ UnsignedInt: 0 |
||||
volumeTexture @ UnsignedInt: 3 |
||||
Material 2 (referenced by 0 objects): Not referenced |
||||
Type: {} |
||||
Base layer: |
||||
Mesh 0 (referenced by 2 objects): |
||||
Level 0: 5 vertices @ Points (0.0 kB) |
||||
Mesh 1 (referenced by 0 objects): Not referenced |
||||
Level 0: 4 vertices @ Lines (0.0 kB) |
||||
Mesh 2 (referenced by 3 objects): |
||||
Level 0: 4 vertices @ TriangleFan (0.0 kB) |
||||
Total mesh data size: 0.0 kB |
||||
Texture 0 (referenced by 1 material attributes): |
||||
Type: Texture1D, image 1 |
||||
Minification, mipmap and magnification: Nearest, Nearest, Linear |
||||
Wrapping: {Repeat, Repeat, Repeat} |
||||
Texture 1 (referenced by 0 material attributes): Not referenced |
||||
Type: Texture1DArray, image 225 |
||||
Minification, mipmap and magnification: Nearest, Nearest, Linear |
||||
Wrapping: {Repeat, Repeat, Repeat} |
||||
Texture 2 (referenced by 2 material attributes): |
||||
Type: Texture2D, image 0 |
||||
Minification, mipmap and magnification: Nearest, Nearest, Linear |
||||
Wrapping: {Repeat, Repeat, Repeat} |
||||
Texture 3 (referenced by 1 material attributes): |
||||
Type: Texture3D, image 1 |
||||
Minification, mipmap and magnification: Nearest, Nearest, Linear |
||||
Wrapping: {Repeat, Repeat, Repeat} |
||||
Texture 4 (referenced by 1 material attributes): |
||||
Type: Texture2D, image 0 |
||||
Minification, mipmap and magnification: Nearest, Nearest, Linear |
||||
Wrapping: {Repeat, Repeat, Repeat} |
||||
1D image 0 (referenced by 0 textures): Not referenced |
||||
Level 0: {1} @ RGBA8I (0.0 kB) |
||||
1D image 1 (referenced by 1 textures): |
||||
Level 0: {4} @ R8I (0.0 kB) |
||||
2D image 0 (referenced by 2 textures): |
||||
Level 0: {1, 2} @ RGBA8I (0.0 kB) |
||||
2D image 1 (referenced by 0 textures): Not referenced |
||||
Level 0: {4, 1} @ R8I (0.0 kB) |
||||
3D image 0 (referenced by 0 textures): Not referenced |
||||
Level 0: {1, 2, 1} @ RGBA8I (0.0 kB) |
||||
3D image 1 (referenced by 1 textures): |
||||
Level 0: {4, 1, 1} @ R8I (0.0 kB) |
||||
Total image data size: 0.0 kB |
||||
@ -0,0 +1,25 @@
|
||||
Scene 0: A simple scene |
||||
Bound: 4 objects @ UnsignedInt (0.1 kB) |
||||
Fields: |
||||
Parent @ Int, 3 entries |
||||
Mesh @ UnsignedInt, OrderedMapping, 4 entries |
||||
Scene 1: |
||||
Bound: 8 objects @ UnsignedByte (0.0 kB, ExternallyOwned|Mutable) |
||||
Fields: |
||||
Custom(42:) @ Double, 2 entries |
||||
Custom(1337:DirectionVector) @ Short[3], 3 entries |
||||
Total scene data size: 0.1 kB |
||||
Object 0 (referenced by 1 scenes): Parent-less mesh |
||||
Fields: Mesh |
||||
Object 1 (referenced by 1 scenes): |
||||
Fields: Parent, Mesh |
||||
Object 2 (referenced by 2 scenes): Two meshes, shared among two scenes |
||||
Fields: Parent, Mesh[2], Custom(1337:DirectionVector) |
||||
Object 3 (referenced by 2 scenes): |
||||
Fields: Parent, Custom(42:) |
||||
Object 4 (referenced by 1 scenes): Two custom arrays |
||||
Fields: Custom(1337:DirectionVector)[2] |
||||
Object 6 (referenced by 0 scenes): Only in the second scene, but no fields, thus same as unreferenced |
||||
Object 7 (referenced by 1 scenes): |
||||
Fields: Custom(42:) |
||||
Object 8 (referenced by 0 scenes): Not in any scene |
||||
@ -0,0 +1,11 @@
|
||||
Scene 0: A simple scene |
||||
Bound: 4 objects @ UnsignedInt (0.1 kB) |
||||
Fields: |
||||
Parent @ Int, 3 entries |
||||
Mesh @ UnsignedInt, OrderedMapping, 4 entries |
||||
Scene 1: |
||||
Bound: 8 objects @ UnsignedByte (0.0 kB, ExternallyOwned|Mutable) |
||||
Fields: |
||||
Custom(42:) @ Double, 2 entries |
||||
Custom(1337:DirectionVector) @ Short[3], 3 entries |
||||
Total scene data size: 0.1 kB |
||||
@ -0,0 +1,10 @@
|
||||
2D skin 0: |
||||
5 joints |
||||
2D skin 1: Second 2D skin, external data |
||||
15 joints |
||||
3D skin 0: First 3D skin, external data |
||||
12 joints |
||||
3D skin 1: |
||||
2 joints |
||||
3D skin 2: |
||||
1 joints |
||||
@ -0,0 +1,8 @@
|
||||
Texture 0: |
||||
Type: Texture1D, image 666 |
||||
Minification, mipmap and magnification: Nearest, Nearest, Linear |
||||
Wrapping: {Repeat, Repeat, Repeat} |
||||
Texture 1: Name! |
||||
Type: Texture2DArray, image 3 |
||||
Minification, mipmap and magnification: Linear, Linear, Nearest |
||||
Wrapping: {MirroredRepeat, ClampToEdge, ClampToEdge} |
||||
@ -0,0 +1,26 @@
|
||||
/* |
||||
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. |
||||
*/ |
||||
|
||||
#define SCENETOOLS_TEST_DIR "${SCENETOOLS_TEST_DIR}" |
||||
@ -0,0 +1,192 @@
|
||||
/*
|
||||
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 <sstream> |
||||
#include <Corrade/Containers/StringStl.h> /** @todo remove once Debug is stream-free */ |
||||
#include <Corrade/TestSuite/Tester.h> |
||||
#include <Corrade/TestSuite/Compare/StringToFile.h> |
||||
#include <Corrade/Utility/DebugStl.h> /** @todo remove once Debug is stream-free */ |
||||
#include <Corrade/Utility/Path.h> |
||||
|
||||
#include "Magnum/Trade/Implementation/converterUtilities.h" |
||||
|
||||
#include "configure.h" |
||||
|
||||
namespace Magnum { namespace Trade { namespace Test { namespace { |
||||
|
||||
struct ImageConverterTest: TestSuite::Tester { |
||||
explicit ImageConverterTest(); |
||||
|
||||
void infoImplementation(); |
||||
void infoImplementationError(); |
||||
}; |
||||
|
||||
ImageConverterTest::ImageConverterTest() { |
||||
addTests({&ImageConverterTest::infoImplementation, |
||||
&ImageConverterTest::infoImplementationError}); |
||||
} |
||||
|
||||
void ImageConverterTest::infoImplementation() { |
||||
struct Importer: Trade::AbstractImporter { |
||||
Trade::ImporterFeatures doFeatures() const override { return {}; } |
||||
bool doIsOpened() const override { return true; } |
||||
void doClose() override {} |
||||
|
||||
/* Three 1D images, one with two levels and named, one compressed,
|
||||
one just to not have two of everything */ |
||||
UnsignedInt doImage1DCount() const override { return 3; } |
||||
UnsignedInt doImage1DLevelCount(UnsignedInt id) override { |
||||
return id == 1 ? 2 : 1; |
||||
} |
||||
Containers::String doImage1DName(UnsignedInt id) override { |
||||
return id == 2 ? "Third 1D image just so there aren't two" : ""; |
||||
} |
||||
Containers::Optional<Trade::ImageData1D> doImage1D(UnsignedInt id, UnsignedInt level) override { |
||||
if(id == 0 && level == 0) |
||||
return Trade::ImageData1D{CompressedPixelFormat::Astc10x10RGBAF, 1024, Containers::Array<char>{NoInit, 4096}}; |
||||
if(id == 1 && level == 0) |
||||
return Trade::ImageData1D{PixelFormat::RGBA8Snorm, 16, Containers::Array<char>{NoInit, 64}}; |
||||
if(id == 1 && level == 1) |
||||
return Trade::ImageData1D{PixelFormat::RGBA8Snorm, 8, Containers::Array<char>{NoInit, 32}}; |
||||
if(id == 2 && level == 0) |
||||
return Trade::ImageData1D{PixelFormat::Depth16Unorm, 4, Containers::Array<char>{NoInit, 8}}; |
||||
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
||||
} |
||||
|
||||
/* Two 2D images, one with three levels and named, the other compressed
|
||||
and array */ |
||||
UnsignedInt doImage2DCount() const override { return 2; } |
||||
UnsignedInt doImage2DLevelCount(UnsignedInt id) override { |
||||
return id == 0 ? 3 : 1; |
||||
} |
||||
Containers::String doImage2DName(UnsignedInt id) override { |
||||
return id == 0 ? "A very nice mipmapped 2D image" : ""; |
||||
} |
||||
Containers::Optional<Trade::ImageData2D> doImage2D(UnsignedInt id, UnsignedInt level) override { |
||||
if(id == 0 && level == 0) |
||||
return Trade::ImageData2D{PixelFormat::RG16F, {256, 128}, Containers::Array<char>{NoInit, 131072}}; |
||||
if(id == 0 && level == 1) |
||||
return Trade::ImageData2D{PixelFormat::RG16F, {128, 64}, Containers::Array<char>{NoInit, 32768}}; |
||||
if(id == 0 && level == 2) |
||||
return Trade::ImageData2D{PixelFormat::RG16F, {64, 32}, Containers::Array<char>{NoInit, 8192}}; |
||||
if(id == 1) |
||||
return Trade::ImageData2D{CompressedPixelFormat::PvrtcRGB2bppUnorm, {4, 8}, Containers::Array<char>{NoInit, 32}, ImageFlag2D::Array}; |
||||
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
||||
} |
||||
|
||||
/* One 2D cube map array image, one 3D mipmapped & named and two 2D
|
||||
array; with one externally owned */ |
||||
UnsignedInt doImage3DCount() const override { return 4; } |
||||
UnsignedInt doImage3DLevelCount(UnsignedInt id) override { |
||||
return id == 1 ? 2 : 1; |
||||
} |
||||
Containers::String doImage3DName(UnsignedInt id) override { |
||||
return id == 1 ? "Volume kills!" : ""; |
||||
} |
||||
Containers::Optional<Trade::ImageData3D> doImage3D(UnsignedInt id, UnsignedInt level) override { |
||||
if(id == 0 && level == 0) |
||||
return Trade::ImageData3D{PixelFormat::R8Unorm, {16, 16, 12}, Containers::Array<char>{NoInit, 3072}, ImageFlag3D::CubeMap|ImageFlag3D::Array}; |
||||
if(id == 1 && level == 0) |
||||
return Trade::ImageData3D{PixelFormat::R8Unorm, {16, 16, 16}, Containers::Array<char>{NoInit, 4096}}; |
||||
if(id == 1 && level == 1) |
||||
return Trade::ImageData3D{PixelFormat::R8Unorm, {8, 8, 6}, Containers::Array<char>{NoInit, 2048}}; |
||||
if(id == 2 && level == 0) |
||||
return Trade::ImageData3D{CompressedPixelFormat::Bc1RGBSrgb, {4, 1, 1}, Containers::Array<char>{NoInit, 16}, ImageFlag3D::Array}; |
||||
if(id == 3 && level == 0) |
||||
return Trade::ImageData3D{PixelFormat::R32F, {1, 4, 1}, Trade::DataFlag::ExternallyOwned|Trade::DataFlag::Mutable, data, ImageFlag3D::Array}; |
||||
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
||||
} |
||||
|
||||
char data[16]; |
||||
} importer; |
||||
|
||||
bool error = false; |
||||
std::chrono::high_resolution_clock::duration time; |
||||
Containers::Array<Implementation::ImageInfo> infos = Implementation::imageInfo(importer, error, time); |
||||
CORRADE_VERIFY(!error); |
||||
CORRADE_COMPARE(infos.size(), 13); |
||||
|
||||
/* Print to visually verify coloring */ |
||||
{ |
||||
Debug{} << "======================== visual color verification start ======================="; |
||||
Implementation::printImageInfo(Debug::isTty() ? Debug::Flags{} : Debug::Flag::DisableColors, infos, nullptr, nullptr, nullptr); |
||||
Debug{} << "======================== visual color verification end ========================="; |
||||
} |
||||
|
||||
std::ostringstream out; |
||||
Debug redirectOutput{&out}; |
||||
Implementation::printImageInfo(Debug::Flag::DisableColors, infos, nullptr, nullptr, nullptr); |
||||
CORRADE_COMPARE_AS(out.str(), |
||||
Utility::Path::join(TRADE_TEST_DIR, "ImageConverterTestFiles/info.txt"), |
||||
TestSuite::Compare::StringToFile); |
||||
} |
||||
|
||||
void ImageConverterTest::infoImplementationError() { |
||||
struct Importer: Trade::AbstractImporter { |
||||
Trade::ImporterFeatures doFeatures() const override { return {}; } |
||||
bool doIsOpened() const override { return true; } |
||||
void doClose() override {} |
||||
|
||||
UnsignedInt doImage1DCount() const override { return 2; } |
||||
Containers::Optional<Trade::ImageData1D> doImage1D(UnsignedInt id, UnsignedInt) override { |
||||
Error{} << "1D image" << id << "error!"; |
||||
return {}; |
||||
} |
||||
|
||||
UnsignedInt doImage2DCount() const override { return 2; } |
||||
Containers::Optional<Trade::ImageData2D> doImage2D(UnsignedInt id, UnsignedInt) override { |
||||
Error{} << "2D image" << id << "error!"; |
||||
return {}; |
||||
} |
||||
|
||||
UnsignedInt doImage3DCount() const override { return 2; } |
||||
Containers::Optional<Trade::ImageData3D> doImage3D(UnsignedInt id, UnsignedInt) override { |
||||
Error{} << "3D image" << id << "error!"; |
||||
return {}; |
||||
} |
||||
} importer; |
||||
|
||||
bool error = false; |
||||
std::chrono::high_resolution_clock::duration time; |
||||
std::ostringstream out; |
||||
Debug redirectOutput{&out}; |
||||
Error redirectError{&out}; |
||||
Containers::Array<Implementation::ImageInfo> infos = Implementation::imageInfo(importer, error, time); |
||||
/* It should return a failure and no output */ |
||||
CORRADE_VERIFY(error); |
||||
CORRADE_VERIFY(infos.isEmpty()); |
||||
/* But it should not exit after first error */ |
||||
CORRADE_COMPARE(out.str(), |
||||
"1D image 0 error!\n" |
||||
"1D image 1 error!\n" |
||||
"2D image 0 error!\n" |
||||
"2D image 1 error!\n" |
||||
"3D image 0 error!\n" |
||||
"3D image 1 error!\n"); |
||||
} |
||||
|
||||
}}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Trade::Test::ImageConverterTest) |
||||
@ -0,0 +1,23 @@
|
||||
1D image 0: |
||||
Level 0: {1024} @ Astc10x10RGBAF (4.0 kB) |
||||
1D image 1: |
||||
Level 0: {16} @ RGBA8Snorm (0.1 kB) |
||||
Level 1: {8} @ RGBA8Snorm (0.0 kB) |
||||
1D image 2: Third 1D image just so there aren't two |
||||
Level 0: {4} @ Depth16Unorm (0.0 kB) |
||||
2D image 0: A very nice mipmapped 2D image |
||||
Level 0: {256, 128} @ RG16F (128.0 kB) |
||||
Level 1: {128, 64} @ RG16F (32.0 kB) |
||||
Level 2: {64, 32} @ RG16F (8.0 kB) |
||||
2D image 1: |
||||
Level 0: Array {4, 8} @ PvrtcRGB2bppUnorm (0.0 kB) |
||||
3D image 0: |
||||
Level 0: Array|CubeMap {16, 16, 12} @ R8Unorm (3.0 kB) |
||||
3D image 1: Volume kills! |
||||
Level 0: {16, 16, 16} @ R8Unorm (4.0 kB) |
||||
Level 1: {8, 8, 6} @ R8Unorm (2.0 kB) |
||||
3D image 2: |
||||
Level 0: Array {4, 1, 1} @ Bc1RGBSrgb (0.0 kB) |
||||
3D image 3: |
||||
Level 0: Array {1, 4, 1} @ R32F (0.0 kB, ExternallyOwned|Mutable) |
||||
Total image data size: 181.2 kB |
||||
Loading…
Reference in new issue