Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SceneData rework #525

Merged
merged 49 commits into from
Dec 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
b54a60f
Trade: initial redesign of the SceneData class.
mosra Jul 10, 2021
d1dda87
Trade: add SceneField string mapping APIs to AbstractImporter.
mosra Sep 2, 2021
a7f4851
Trade: MSVC 2017, what are you doing.
mosra Sep 3, 2021
73b32de
Trade: hi, MSVC 2015, you ancient curse.
mosra Sep 3, 2021
1505d43
Trade: it's probably good to have these switches guarded.
mosra Sep 8, 2021
59d6709
Trade: avoid double lookup in SceneData::fooAsArray().
mosra Sep 9, 2021
4e8fa9d
Trade: add SceneData::fooInto() overloads for subranges.
mosra Sep 10, 2021
56047b0
Trade: make SceneField::MeshMaterial signed.
mosra Sep 11, 2021
7192517
Trade: combine mesh and material SceneData convenience APIs together.
mosra Sep 16, 2021
c61ed94
Trade: SceneData TRS components can each have different type, test that.
mosra Sep 18, 2021
be36c8a
Trade: convenience access to separate TRS components in SceneData.
mosra Sep 18, 2021
140e60a
Trade: convenience per-object field access in SceneData.
mosra Sep 18, 2021
409b493
Trade: add a parentFor() object-oriented accessor as well.
mosra Sep 24, 2021
f734094
Trade: support storing pointers (and thus importer state) in SceneData.
mosra Sep 26, 2021
c9ac4d6
Trade: introduce SceneData::is2D() and is3D().
mosra Oct 4, 2021
67900c7
Trade: SceneField::Skin now requires a transformation to be present.
mosra Oct 4, 2021
4da64d6
Trade: reintroduce original deprecated SceneData APIs.
mosra Sep 2, 2021
e858ab2
Trade: add scene{Object,Field}TypeAlignment().
mosra Oct 11, 2021
618fbec
Trade: adapt AbstractImporter for the new SceneData workflow.
mosra Sep 22, 2021
505538d
Trade: add an explicitly defaulted deinlined SkinData destructor.
mosra Sep 22, 2021
4602248
Trade: ensure the deprecated SceneData constructor uses default delet…
mosra Sep 22, 2021
b9cb395
AnySceneImporter: adapt to SceneData redesign.
mosra Sep 24, 2021
26d2f3e
sceneconverter: print contents of the new SceneData.
mosra Sep 29, 2021
b192c4c
Trade: internal tool for creating SceneData out of loose views.
mosra Oct 13, 2021
6e1bb5f
Trade: add public SceneData APIs for finding fields and objects.
mosra Dec 3, 2021
54042da
Trade: this doesn't need to be exported.
mosra Oct 13, 2021
9cdc5f0
Trade: internal tool for making SceneData with single-function objects.
mosra Oct 13, 2021
640fe8f
Trade: process SceneData to single-function-objects for backwards com…
mosra Oct 13, 2021
cb3070f
Trade: ensure newly added object IDs don't overlap each other.
mosra Dec 7, 2021
8ef35d4
Trade: the compatibility default for transformless scenes should be TRS.
mosra Oct 14, 2021
4adabf9
Trade: warn in deprecated SceneData::children*D() if there's no parent.
mosra Nov 1, 2021
e056ad3
Trade: allow SceneField::Transformation to be a 3x2 or a 4x3 matrix.
mosra Nov 1, 2021
0366919
Trade: test SceneData::{parentFor,childrenFor}() with trivial parents.
mosra Nov 1, 2021
605d72c
Trade: fix SceneData object view retrieval & test it more thoroughly.
mosra Nov 1, 2021
6fe0dd1
Trade: report at least some *D object count if everything fails.
mosra Nov 9, 2021
e0893f8
Trade: another case for the deprecated path not being 100% compatible.
mosra Nov 9, 2021
98e023b
Trade: GCC 4.8, hello!
mosra Nov 13, 2021
2b409ee
Trade: drop assertions for 64-bit object/parent values from SceneData.
mosra Nov 22, 2021
efd3b9c
Trade: SceneData::*AsArray() and *Into() now return object IDs as well.
mosra Nov 22, 2021
19c055d
Trade: remove the useless indirection from SceneField::Parent.
mosra Nov 26, 2021
5df37d2
Trade: rename SceneData "objects" to "mapping".
mosra Dec 3, 2021
1fbb87e
Trade: high-level documentation for SceneData.
mosra Sep 2, 2021
3f38ab1
Trade: flags for annotating SceneData field object mappings.
mosra Dec 4, 2021
78b71e1
Trade: preserve field flags in the scene combining tools.
mosra Dec 6, 2021
43c70d8
sceneconverter: print scene field flags in --info, if present.
mosra Dec 6, 2021
dd9f474
Trade: use 64-bit values in object-oriented SceneData APIs.
mosra Dec 7, 2021
7dc2dea
Trade: make AnimationData object reference 64-bit.
mosra Dec 7, 2021
b6200d0
Trade: correctly copy skins alongside duplicated multi-mesh objects.
mosra Dec 7, 2021
4418bec
Trade: bump AbstractImporter interface version.
mosra Sep 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,610 changes: 1,610 additions & 0 deletions doc/artwork/scenedata-dod.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1,290 changes: 1,290 additions & 0 deletions doc/artwork/scenedata-tree.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions doc/changelog.dox
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,9 @@ See also:
@ref Trade::PhongMaterialData::normalTextureScale() and
@ref Trade::PhongMaterialData::normalTextureSwizzle() to make new features
added for PBR materials recognizable also in classic Phong workflows.
- A completely redesigned @ref Trade::SceneData class that stores data of
the whole scene in a data-oriented way, allowing for storing custom fields
as well. See [mosra/magnum#525](https://github.com/mosra/magnum/pull/525).
- New @ref Trade::SkinData class and @ref Trade::AbstractImporter::skin2D() /
@ref Trade::AbstractImporter::skin3D() family of APIs for skin import, as
well as support in @ref Trade::AnySceneImporter "AnySceneImporter"
Expand Down Expand Up @@ -629,6 +632,27 @@ See also:
directly but rather generated on-the-fly from attribute data, which makes
them less efficient than calling @ref Trade::MaterialData::hasAttribute()
etc.
- @ref Trade::SceneData constructor taking a @ref std::vector of 2D and 3D
children is deprecated in favor of the new scene representation. Use
@ref Trade::SceneData::SceneData(SceneMappingType, UnsignedLong, Containers::Array<char>&&, Containers::Array<SceneFieldData>&&, const void*)
instead.
- @cpp Trade::SceneData::children2D() @ce and
@cpp Trade::SceneData::children3D() @ce are deprecated in favor of the
new scene representation. Use @ref Trade::SceneData::childrenFor() with
@cpp -1 @ce passed as the @p object argument to get a list of top-level
objects.
- @cpp Trade::ObjectData*D @ce, @cpp Trade::MeshObjectData*D @ce classes,
@cpp Trade::ObjectInstanceType*D @ce, @cpp Trade::ObjectFlag*D @ce,
@cpp Trade::ObjectFlags*D @ce enums and the corresponding
@cpp Trade::AbstractImporter::object*DCount() @ce,
@cpp Trade::AbstractImporter::object*DForName() @ce,
@cpp Trade::AbstractImporter::object*DName() @ce and
@cpp Trade::AbstractImporter::object*D() @ce accessor APIs are deprecated
in favor of the unified representation in @ref Trade::SceneData and the
@ref Trade::AbstractImporter::objectCount(),
@relativeref{Trade::AbstractImporter,objectForName()} and
@relativeref{Trade::AbstractImporter,objectName()} accessors that are
shared for 2D and 3D.
- @ref Trade::AbstractImporter::material() now returns
@ref Corrade::Containers::Optional instead of a @ref Corrade::Containers::Pointer,
as the new @ref Trade::MaterialData class isn't polymorphic anymore. If
Expand Down Expand Up @@ -802,6 +826,23 @@ See also:
@cpp Trade::AbstractMaterialData @ce aliases to, doesn't have a
@cpp virtual @ce destructor as subclasses with extra data members aren't a
desired use case anymore.
- @ref Trade::SceneData constructor taking a @ref std::vector of 2D and 3D
children that got deprecated in favor of
@ref Trade::SceneData::SceneData(SceneMappingType, UnsignedLong, Containers::Array<char>&&, Containers::Array<SceneFieldData>&&, const void*)
no longer accepts a scene that has both 2D and 3D children.
- The deprecated @cpp Trade::AbstractImporter::object*DCount() @ce,
@cpp Trade::AbstractImporter::object*DForName() @ce,
@cpp Trade::AbstractImporter::object*DName() @ce and
@cpp Trade::AbstractImporter::object*D() @ce accessors now behave different
for objects with multiple mesh assignments. This handling was originally
present in importer plugins themselves, but as the new
@ref Trade::SceneData representation supports multiple mesh/camera/...
assignments to a single object natively, the handling was moved to a single
place in the compatibility layer. Because the compatibility layer cannot
renumber object IDs, the newly added objects are not immediately following
the original ID but instead allocated at the end of the object ID range
reported by the importer. While the newly added objects have different IDs,
they retain the parent name like before.
- @ref Trade::AbstractImporter::doDefaultScene() is now @cpp const @ce ---
since the function is not expected to fail, no kind of complex lazy
population can be done anyway. This is now consistent with `do*Count()`
Expand Down
257 changes: 237 additions & 20 deletions doc/snippets/MagnumTrade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@
*/

#include <unordered_map>
#include <Corrade/Containers/ArrayTuple.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/Pair.h>
#include <Corrade/Utility/Algorithms.h>
#include <Corrade/Utility/DebugStl.h>
#include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/Resource.h>

Expand All @@ -47,12 +50,15 @@
#include "Magnum/Trade/LightData.h"
#include "Magnum/Trade/MaterialData.h"
#include "Magnum/Trade/MeshData.h"
#include "Magnum/Trade/ObjectData2D.h"
#include "Magnum/Trade/MeshObjectData3D.h"
#include "Magnum/Trade/PbrClearCoatMaterialData.h"
#include "Magnum/Trade/PbrSpecularGlossinessMaterialData.h"
#include "Magnum/Trade/PbrMetallicRoughnessMaterialData.h"
#include "Magnum/Trade/PhongMaterialData.h"
#include "Magnum/Trade/SceneData.h"
#include "Magnum/SceneGraph/Drawable.h"
#include "Magnum/SceneGraph/Scene.h"
#include "Magnum/SceneGraph/Object.h"
#include "Magnum/SceneGraph/MatrixTransformation3D.h"
#ifdef MAGNUM_TARGET_GL
#include "Magnum/GL/Texture.h"
#include "Magnum/GL/TextureFormat.h"
Expand All @@ -66,12 +72,16 @@

#ifdef MAGNUM_BUILD_DEPRECATED
#define _MAGNUM_NO_DEPRECATED_MESHDATA /* So it doesn't yell here */
#define _MAGNUM_NO_DEPRECATED_OBJECTDATA /* So it doesn't yell here */

#include "Magnum/Trade/MeshData2D.h"
#include "Magnum/Trade/MeshData3D.h"
#include "Magnum/Trade/MeshObjectData3D.h"
#include "Magnum/Trade/ObjectData2D.h"
#endif

#define DOXYGEN_ELLIPSIS(...) __VA_ARGS__
#define DOXYGEN_IGNORE(...) __VA_ARGS__

using namespace Magnum;
using namespace Magnum::Math::Literals;
Expand Down Expand Up @@ -180,21 +190,6 @@ importer->openFile("scene.gltf"); // memory-maps all files
}
#endif

{
Containers::Pointer<Trade::AbstractImporter> importer;
Int materialIndex;
/* [AbstractImporter-usage-cast] */
Containers::Pointer<Trade::ObjectData3D> data = importer->object3D(12);
if(data && data->instanceType() == Trade::ObjectInstanceType3D::Mesh) {
auto& mesh = static_cast<Trade::MeshObjectData3D&>(*data);

materialIndex = mesh.material();
// ...
}
/* [AbstractImporter-usage-cast] */
static_cast<void>(materialIndex);
}

{
Containers::Pointer<Trade::AbstractImporter> importer;
/* [AbstractImporter-setFileCallback] */
Expand Down Expand Up @@ -844,9 +839,9 @@ MeshTools::transformPointsInPlace(transformation, data.positions(0));
/* [MeshData2D-transform] */
CORRADE_IGNORE_DEPRECATED_POP
}
#endif

{
CORRADE_IGNORE_DEPRECATED_PUSH
Trade::ObjectData2D& baz();
Trade::ObjectData2D& data = baz();
/* [ObjectData2D-transformation] */
Expand All @@ -855,9 +850,9 @@ Matrix3 transformation =
Matrix3::scaling(data.scaling());
/* [ObjectData2D-transformation] */
static_cast<void>(transformation);
CORRADE_IGNORE_DEPRECATED_POP
}

#ifdef MAGNUM_BUILD_DEPRECATED
{
CORRADE_IGNORE_DEPRECATED_PUSH
Trade::MeshData3D& bar();
Expand All @@ -871,9 +866,9 @@ MeshTools::transformVectorsInPlace(transformation, data.normals(0));
/* [MeshData3D-transform] */
CORRADE_IGNORE_DEPRECATED_POP
}
#endif

{
CORRADE_IGNORE_DEPRECATED_PUSH
Trade::ObjectData3D& fizz();
Trade::ObjectData3D& data = fizz();
/* [ObjectData3D-transformation] */
Expand All @@ -882,6 +877,228 @@ Matrix4 transformation =
Matrix4::scaling(data.scaling());
/* [ObjectData3D-transformation] */
static_cast<void>(transformation);
CORRADE_IGNORE_DEPRECATED_POP
}
#endif

{
/* [SceneFieldData-usage] */
Containers::StridedArrayView1D<UnsignedInt> transformationMapping = DOXYGEN_ELLIPSIS({});
Containers::StridedArrayView1D<Matrix4> transformations = DOXYGEN_ELLIPSIS({});

Trade::SceneFieldData field{Trade::SceneField::Transformation,
transformationMapping, transformations};
/* [SceneFieldData-usage] */
}

{
/* [SceneFieldData-usage-offset-only] */
struct Node {
UnsignedInt object;
Int parent;
Matrix4 transform;
};

/* Layout defined statically, 120 objects in total */
constexpr Trade::SceneFieldData parents{Trade::SceneField::Parent, 120,
Trade::SceneMappingType::UnsignedInt, offsetof(Node, object), sizeof(Node),
Trade::SceneFieldType::Int, offsetof(Node, parent), sizeof(Node)};
constexpr Trade::SceneFieldData transforms{Trade::SceneField::Transformation, 120,
Trade::SceneMappingType::UnsignedInt, offsetof(Node, object), sizeof(Node),
Trade::SceneFieldType::Matrix4x4, offsetof(Node, transform), sizeof(Node)};

/* Actual data populated later */
Containers::Array<char> data{120*sizeof(Node)};
DOXYGEN_ELLIPSIS()
Trade::SceneData{Trade::SceneMappingType::UnsignedInt, 120, std::move(data),
{parents, transforms}};
/* [SceneFieldData-usage-offset-only] */
}

{
typedef SceneGraph::Scene<SceneGraph::MatrixTransformation3D> Scene3D;
typedef SceneGraph::Object<SceneGraph::MatrixTransformation3D> Object3D;
/* [SceneData-usage1] */
Trade::SceneData data = DOXYGEN_ELLIPSIS(Trade::SceneData{{}, 0, nullptr, nullptr});
if(!data.is3D() ||
!data.hasField(Trade::SceneField::Parent) ||
!data.hasField(Trade::SceneField::Mesh))
Fatal{} << "Oh noes!";

Scene3D scene;
Containers::Array<Object3D*> objects{std::size_t(data.mappingBound())};
/* [SceneData-usage1] */

/* [SceneData-usage2] */
auto parents = data.parentsAsArray();
for(Containers::Pair<UnsignedInt, Int>& parent: parents)
objects[parent.first()] = new Object3D{};
/* [SceneData-usage2] */

/* [SceneData-usage3] */
for(Containers::Pair<UnsignedInt, Int>& parent: parents)
objects[parent.first()]->setParent(
parent.second() == -1 ? &scene : objects[parent.second()]
);
/* [SceneData-usage3] */

/* [SceneData-usage4] */
for(Containers::Pair<UnsignedInt, Matrix4>& transformation:
data.transformations3DAsArray())
{
if(Object3D* const object = objects[transformation.first()])
object->setTransformation(transformation.second());
}
/* [SceneData-usage4] */

/* [SceneData-usage5] */
class Drawable: public SceneGraph::Drawable3D {
public:
explicit Drawable(Object3D& object, UnsignedInt mesh, Int material, DOXYGEN_ELLIPSIS(int))DOXYGEN_IGNORE(: SceneGraph::Drawable3D{object} {
static_cast<void>(mesh);
static_cast<void>(material);
} int foo);

DOXYGEN_ELLIPSIS(void draw(const Matrix4&, SceneGraph::Camera3D&) override {})
};

for(const Containers::Pair<UnsignedInt, Containers::Pair<UnsignedInt, Int>>&
meshMaterial: data.meshesMaterialsAsArray())
{
if(Object3D* const object = objects[meshMaterial.first()])
new Drawable{*object, meshMaterial.second().first(),
meshMaterial.second().second(), DOXYGEN_ELLIPSIS(0)};
}
/* [SceneData-usage5] */

/* [SceneData-usage-advanced] */
Containers::StridedArrayView1D<const UnsignedInt> transformationMapping =
data.mapping<UnsignedInt>(Trade::SceneField::Transformation);
Containers::StridedArrayView1D<const Matrix4> transformations =
data.field<Matrix4>(Trade::SceneField::Transformation);
for(std::size_t i = 0; i != transformationMapping.size(); ++i) {
if(Object3D* const object = objects[transformationMapping[i]])
object->setTransformation(transformations[i]);
}
/* [SceneData-usage-advanced] */
}

{
Trade::SceneData data{{}, 0, nullptr, nullptr};
/* [SceneData-per-object] */
Containers::Pointer<Trade::AbstractImporter> importer = DOXYGEN_ELLIPSIS({});

for(const Containers::Pair<UnsignedInt, Int>& meshMaterial:
data.meshesMaterialsFor(importer->objectForName("Chair")))
{
Debug{} << "Mesh:" << importer->meshName(meshMaterial.first());
if(meshMaterial.second() != -1)
Debug{} << "With a material:" << importer->materialName(meshMaterial.second());
}
/* [SceneData-per-object] */
}

{
Trade::SceneData data{{}, 0, nullptr, nullptr};
typedef SceneGraph::Object<SceneGraph::MatrixTransformation3D> Object3D;
Containers::Array<Object3D*> objects;
/* [SceneData-usage-mutable] */
Containers::StridedArrayView1D<const UnsignedInt> transformationMapping =
data.mapping<UnsignedInt>(Trade::SceneField::Transformation);
Containers::StridedArrayView1D<Matrix4> mutableTransformations =
data.mutableField<Matrix4>(Trade::SceneField::Transformation);
for(std::size_t i = 0; i != transformationMapping.size(); ++i) {
if(Object3D* const object = objects[transformationMapping[i]])
mutableTransformations[i] = object->transformation();
}
/* [SceneData-usage-mutable] */
}

{
const std::size_t nodeCount{}, meshAssignmentCount{};
/* [SceneData-populating] */
struct Common {
UnsignedShort object;
Short parent;
Matrix4 transformation;
};

Containers::StridedArrayView1D<Common> common;
Containers::ArrayView<UnsignedShort> meshMaterialMapping;
Containers::ArrayView<UnsignedShort> meshes;
Containers::ArrayView<UnsignedShort> meshMaterials;
Containers::Array<char> data = Containers::ArrayTuple{
{nodeCount, common},
{meshAssignmentCount, meshMaterialMapping},
{meshAssignmentCount, meshes},
{meshAssignmentCount, meshMaterials}
};

// populate the views ...

Trade::SceneData scene{
Trade::SceneMappingType::UnsignedShort, nodeCount,
std::move(data), {
Trade::SceneFieldData{Trade::SceneField::Parent,
common.slice(&Common::object), common.slice(&Common::parent)},
Trade::SceneFieldData{Trade::SceneField::Transformation,
common.slice(&Common::object), common.slice(&Common::transformation)},
Trade::SceneFieldData{Trade::SceneField::Mesh,
meshMaterialMapping, meshes},
Trade::SceneFieldData{Trade::SceneField::MeshMaterial,
meshMaterialMapping, meshMaterials}
}};
/* [SceneData-populating] */
}

{
std::size_t nodeCount{};
/* [SceneData-populating-custom1] */
DOXYGEN_ELLIPSIS()
Containers::ArrayView<UnsignedShort> cellMapping;
Containers::ArrayView<Matrix4> cellFrustums;
Containers::StridedArrayView2D<Int> cellLights;
Containers::Array<char> data = Containers::ArrayTuple{
DOXYGEN_ELLIPSIS()
{32*24, cellMapping},
{32*24, cellFrustums},
{{32*24, 8}, cellLights},
};

for(std::size_t i = 0; i != cellMapping.size(); ++i) {
cellMapping[i] = nodeCount + i;
cellFrustums[i] = DOXYGEN_ELLIPSIS({});
for(std::size_t j = 0; j != cellLights[i].size(); ++j)
cellLights[i][j] = DOXYGEN_ELLIPSIS({});
}
/* [SceneData-populating-custom1] */

/* [SceneData-populating-custom2] */
constexpr Trade::SceneField CellFrustum = Trade::sceneFieldCustom(0x00);
constexpr Trade::SceneField CellLights = Trade::sceneFieldCustom(0x01);

Trade::SceneData scene{
Trade::SceneMappingType::UnsignedShort, nodeCount + cellMapping.size(),
std::move(data), {
DOXYGEN_ELLIPSIS()
Trade::SceneFieldData{CellFrustum, cellMapping, cellFrustums},
Trade::SceneFieldData{CellLights, cellMapping, cellLights},
}};
/* [SceneData-populating-custom2] */
}

{
constexpr Trade::SceneField CellFrustum = Trade::sceneFieldCustom(0);
constexpr Trade::SceneField CellLights = Trade::sceneFieldCustom(1);
Trade::SceneData scene{{}, 0, nullptr, nullptr};
/* [SceneData-populating-custom-retrieve] */
Containers::StridedArrayView1D<const Matrix4> cellFrustums =
scene.field<Matrix4>(CellFrustum);
Containers::StridedArrayView2D<const Int> cellLights =
scene.field<Int[]>(CellLights);
/* [SceneData-populating-custom-retrieve] */
static_cast<void>(cellFrustums);
static_cast<void>(cellLights);
}

}
Loading