Skip to content

Commit 709d651

Browse files
committed
Changed mesh API to callback
1 parent ff3de6e commit 709d651

File tree

6 files changed

+147
-103
lines changed

6 files changed

+147
-103
lines changed

library/private/scene_impl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ class scene_impl : public scene
3434
scene& add(const std::filesystem::path& filePath) override;
3535
scene& add(const std::vector<std::filesystem::path>& filePath) override;
3636
scene& add(const std::vector<std::string>& filePathStrings) override;
37-
scene& add(const mesh_t& mesh, const double timeStamp = 0) override;
37+
scene& add(const mesh_t& mesh) override;
38+
scene& add(const double startTime, const double endTime, MeshCallback&& Callback) override;
3839
scene& clear() override;
3940
int addLight(const light_state_t& lightState) const override;
4041
int getLightCount() const override;

library/public/scene.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
/// @cond
99
#include <filesystem>
10+
#include <functional>
1011
#include <string>
1112
#include <vector>
1213
/// @endcond
@@ -45,6 +46,12 @@ class F3D_EXPORT scene
4546
: exception(what) {};
4647
};
4748

49+
/**
50+
* Callback type for animated meshes.
51+
* Called with the current time value, should return the mesh for that time.
52+
*/
53+
using MeshCallback = std::function<mesh_t(double time)>;
54+
4855
///@{
4956
/**
5057
* Add and load provided files into the scene
@@ -60,7 +67,12 @@ class F3D_EXPORT scene
6067
/**
6168
* Add and load provided mesh into the scene
6269
*/
63-
virtual scene& add(const mesh_t& mesh, const double timeStamp = 0) = 0;
70+
virtual scene& add(const mesh_t& mesh) = 0;
71+
72+
/**
73+
* Add and load provided mesh into the scene
74+
*/
75+
virtual scene& add(const double startTime, const double endTime, MeshCallback&& Callback) = 0;
6476

6577
///@{
6678
/**

library/src/scene_impl.cxx

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,6 @@ class scene_impl::internals
192192
animationManager AnimationManager;
193193

194194
vtkNew<vtkF3DMetaImporter> MetaImporter;
195-
vtkNew<vtkF3DMemoryMesh> VtkSource;
196-
vtkNew<vtkF3DGenericImporter> MemoryMeshImporter;
197-
bool MemoryMeshLoaded;
198195
};
199196

200197
//----------------------------------------------------------------------------
@@ -299,7 +296,36 @@ scene& scene_impl::add(const std::vector<fs::path>& filePaths)
299296
}
300297

301298
//----------------------------------------------------------------------------
302-
scene& scene_impl::add(const mesh_t& mesh, const double timeStamp)
299+
scene& scene_impl::add(const double startTime, const double endTime, MeshCallback&& Callback)
300+
{
301+
if (startTime > endTime)
302+
{
303+
throw scene::load_failure_exception("startTime must be less than or equal to endTime");
304+
}
305+
306+
vtkNew<vtkF3DMemoryMesh> vtkSource;
307+
308+
auto wrappedCallback = [cb = std::move(Callback)](double time, vtkF3DMemoryMesh* vtkMesh)
309+
{
310+
mesh_t mesh = cb(time);
311+
vtkMesh->SetPoints(mesh.points);
312+
vtkMesh->SetNormals(mesh.normals);
313+
vtkMesh->SetTCoords(mesh.texture_coordinates);
314+
vtkMesh->SetFaces(mesh.face_sides, mesh.face_indices);
315+
};
316+
317+
vtkSource->SetAnimatedMesh(startTime, endTime, std::move(wrappedCallback));
318+
319+
auto importer = vtkSmartPointer<vtkF3DGenericImporter>::New();
320+
importer->SetInternalReader(vtkSource);
321+
322+
log::debug("Loading animated 3D scene from memory");
323+
324+
this->Internals->Load({ importer });
325+
return *this;
326+
}
327+
328+
scene& scene_impl::add(const mesh_t& mesh)
303329
{
304330
// sanity checks
305331
auto [valid, err] = mesh.isValid();
@@ -308,31 +334,18 @@ scene& scene_impl::add(const mesh_t& mesh, const double timeStamp)
308334
throw scene::load_failure_exception(err);
309335
}
310336

311-
auto& memoryMesh = Internals->VtkSource;
312-
auto& importer = this->Internals->MemoryMeshImporter;
337+
vtkNew<vtkF3DMemoryMesh> vtkSource;
338+
auto importer = vtkSmartPointer<vtkF3DGenericImporter>::New();
313339

314340
log::debug("Loading 3D scene from memory");
315341

316-
memoryMesh->SetPoints(mesh.points, timeStamp);
317-
memoryMesh->SetNormals(mesh.normals, timeStamp);
318-
memoryMesh->SetTCoords(mesh.texture_coordinates, timeStamp);
319-
memoryMesh->SetFaces(mesh.face_sides, mesh.face_indices, timeStamp);
320-
321-
if (!this->Internals->MemoryMeshLoaded)
322-
{
323-
importer->SetInternalReader(memoryMesh);
324-
Internals->Load({ importer });
325-
this->Internals->MemoryMeshLoaded = true;
326-
}
327-
else
328-
{
329-
memoryMesh->Modified();
330-
memoryMesh->Update();
342+
vtkSource->SetPoints(mesh.points);
343+
vtkSource->SetNormals(mesh.normals);
344+
vtkSource->SetTCoords(mesh.texture_coordinates);
345+
vtkSource->SetFaces(mesh.face_sides, mesh.face_indices);
331346

332-
importer->Modified();
333-
importer->Update();
334-
this->Internals->AnimationManager.Initialize();
335-
}
347+
importer->SetInternalReader(vtkSource);
348+
Internals->Load({ importer });
336349

337350
return *this;
338351
}

library/testing/TestSDKSceneTemporalFromMemory.cxx

Lines changed: 14 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,7 @@ int TestSDKSceneTemporalFromMemory([[maybe_unused]] int argc, [[maybe_unused]] c
2020
f3d::scene& sce = eng.getScene();
2121
f3d::window& win = eng.getWindow().setSize(300, 300);
2222

23-
std::string texturePath = std::string(argv[1]) + "data/world.png";
24-
eng.getOptions().model.color.texture = texturePath;
25-
const std::string outputPath = std::string(argv[2]);
26-
const std::string frame0Path = outputPath + "TestSDKSceneTemporalFromMemory_frame0.png";
27-
const std::string frame1Path = outputPath + "TestSDKSceneTemporalFromMemory_frame1.png";
28-
23+
// Define mesh data for two frames
2924
const std::vector<float> basePoints{ 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 1.f, 0.f, 0.f, 1.f, 1.f, 0.f };
3025
const std::vector<float> translatedPoints{ 0.25f, 0.f, 0.f, 0.25f, 1.f, 0.f, 1.25f, 0.f, 0.f,
3126
1.25f, 1.f, 0.f };
@@ -35,48 +30,32 @@ int TestSDKSceneTemporalFromMemory([[maybe_unused]] int argc, [[maybe_unused]] c
3530
const std::vector<unsigned int> faceSides{ 3, 3 };
3631
const std::vector<unsigned int> faceIndices{ 0, 1, 2, 1, 3, 2 };
3732

38-
f3d::mesh_t meshFrame0{ basePoints, normals, tcoords, faceSides, faceIndices };
39-
f3d::mesh_t meshFrame1{ translatedPoints, normals, tcoords, faceSides, faceIndices };
33+
auto meshCallback = [&](double time) -> f3d::mesh_t
34+
{
35+
if (time < 0.5)
36+
{
37+
return f3d::mesh_t{ basePoints, normals, tcoords, faceSides, faceIndices };
38+
}
39+
else
40+
{
41+
return f3d::mesh_t{ translatedPoints, normals, tcoords, faceSides, faceIndices };
42+
}
43+
};
4044

41-
test("add temporal mesh sequence", [&]() {
42-
sce.add(meshFrame0, 0.0);
43-
sce.add(meshFrame1, 1.0);
44-
});
45+
test("add animated mesh with callback", [&]() { sce.add(0.0, 1.0, meshCallback); });
4546

4647
test("animation time range", [&]() {
4748
auto range = sce.animationTimeRange();
4849
return std::abs(range.first - 0.0) < 1e-6 && std::abs(range.second - 1.0) < 1e-6;
4950
});
5051

51-
const std::string baselinePath = std::string(argv[1]) + "baselines/TestSDKSceneFromMemory.png";
52-
test("qualitative baseline comparison", [&]() {
53-
sce.loadAnimationTime(0.0);
54-
f3d::image frame0 = win.renderToImage();
55-
frame0.save(frame0Path);
56-
f3d::image baseline(baselinePath);
57-
double error = frame0.compare(baseline);
58-
if (error > 0.05)
59-
{
60-
std::ostringstream stream;
61-
stream << "baseline difference is " << error;
62-
throw stream.str();
63-
}
64-
});
65-
6652
test("quantitative temporal difference", [&]() {
6753
sce.loadAnimationTime(0.0);
6854
f3d::image frame0 = win.renderToImage();
69-
frame0.save(frame0Path);
7055
sce.loadAnimationTime(1.0);
7156
f3d::image frame1 = win.renderToImage();
72-
frame1.save(frame1Path);
7357
double error = frame0.compare(frame1);
74-
if (error <= 0.01)
75-
{
76-
std::ostringstream stream;
77-
stream << "frame delta is " << error;
78-
throw stream.str();
79-
}
58+
return error > 0.01;
8059
});
8160

8261
return test.result();

vtkext/private/module/vtkF3DMemoryMesh.cxx

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
#include "vtkF3DMemoryMesh.h"
22

3+
#include "vtkCellArray.h"
34
#include "vtkFloatArray.h"
45
#include "vtkIdTypeArray.h"
6+
#include "vtkInformation.h"
57
#include "vtkInformationVector.h"
68
#include "vtkObjectFactory.h"
79
#include "vtkPointData.h"
10+
#include "vtkPoints.h"
11+
#include "vtkPolyData.h"
812
#include "vtkSMPTools.h"
9-
#include <vtkInformation.h>
10-
#include <vtkStreamingDemandDrivenPipeline.h>
13+
#include "vtkStreamingDemandDrivenPipeline.h"
1114

1215
vtkStandardNewMacro(vtkF3DMemoryMesh);
1316

@@ -45,30 +48,38 @@ vtkF3DMemoryMesh::vtkF3DMemoryMesh()
4548
vtkF3DMemoryMesh::~vtkF3DMemoryMesh() = default;
4649

4750
//------------------------------------------------------------------------------
48-
void vtkF3DMemoryMesh::SetPoints(const std::vector<float>& positions, const double timeStamp)
51+
void vtkF3DMemoryMesh::SetPoints(const std::vector<float>& positions)
4952
{
5053
vtkNew<vtkPoints> points;
5154
points->SetDataTypeToFloat();
5255
points->SetData(ConvertToFloatArray<3>(positions));
53-
54-
this->Meshes[timeStamp]->SetPoints(points);
56+
this->StaticMesh->SetPoints(points);
57+
this->Modified();
5558
}
5659

5760
//------------------------------------------------------------------------------
58-
void vtkF3DMemoryMesh::SetNormals(const std::vector<float>& normals, const double timeStamp)
61+
void vtkF3DMemoryMesh::SetNormals(const std::vector<float>& normals)
5962
{
60-
this->Meshes[timeStamp]->GetPointData()->SetNormals(ConvertToFloatArray<3>(normals));
63+
if (!normals.empty())
64+
{
65+
this->StaticMesh->GetPointData()->SetNormals(ConvertToFloatArray<3>(normals));
66+
this->Modified();
67+
}
6168
}
6269

6370
//------------------------------------------------------------------------------
64-
void vtkF3DMemoryMesh::SetTCoords(const std::vector<float>& tcoords, const double timeStamp)
71+
void vtkF3DMemoryMesh::SetTCoords(const std::vector<float>& tcoords)
6572
{
66-
this->Meshes[timeStamp]->GetPointData()->SetTCoords(ConvertToFloatArray<2>(tcoords));
73+
if (!tcoords.empty())
74+
{
75+
this->StaticMesh->GetPointData()->SetTCoords(ConvertToFloatArray<2>(tcoords));
76+
this->Modified();
77+
}
6778
}
6879

6980
//------------------------------------------------------------------------------
70-
void vtkF3DMemoryMesh::SetFaces(const std::vector<unsigned int>& faceSizes,
71-
const std::vector<unsigned int>& faceIndices, const double timeStamp)
81+
void vtkF3DMemoryMesh::SetFaces(
82+
const std::vector<unsigned int>& faceSizes, const std::vector<unsigned int>& faceIndices)
7283
{
7384
vtkNew<vtkIdTypeArray> offsets;
7485
vtkNew<vtkIdTypeArray> connectivity;
@@ -95,19 +106,30 @@ void vtkF3DMemoryMesh::SetFaces(const std::vector<unsigned int>& faceSizes,
95106

96107
vtkNew<vtkCellArray> polys;
97108
polys->SetData(offsets, connectivity);
109+
this->StaticMesh->SetPolys(polys);
110+
this->Modified();
111+
}
98112

99-
this->Meshes[timeStamp]->SetPolys(polys);
113+
//------------------------------------------------------------------------------
114+
void vtkF3DMemoryMesh::SetAnimatedMesh(double startTime, double endTime, MeshCallback callback)
115+
{
116+
this->AnimatedCallback = std::move(callback);
117+
this->TimeRange[0] = startTime;
118+
this->TimeRange[1] = endTime;
119+
this->IsAnimated = true;
120+
this->Modified();
100121
}
101122

102123
//------------------------------------------------------------------------------
103124
int vtkF3DMemoryMesh::RequestInformation(vtkInformation* vtkNotUsed(request),
104125
vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
105126
{
106-
// timeRange = {map_min, map_max}, map_min always <= map_max
107-
const auto timeRange = std::array<double, 2>{ Meshes.begin()->first, Meshes.rbegin()->first };
108-
109127
vtkInformation* outInfo = outputVector->GetInformationObject(0);
110-
outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange.data(), 2);
128+
129+
if (this->IsAnimated)
130+
{
131+
outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), this->TimeRange, 2);
132+
}
111133

112134
return 1;
113135
}
@@ -119,21 +141,17 @@ int vtkF3DMemoryMesh::RequestData(vtkInformation* vtkNotUsed(request),
119141
vtkInformation* outInfo = outputVector->GetInformationObject(0);
120142
vtkPolyData* output = vtkPolyData::GetData(outInfo);
121143

122-
if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()) && !this->Meshes.empty())
144+
if (this->IsAnimated && this->AnimatedCallback)
123145
{
124-
const double requestedTimeValue =
125-
outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
126-
auto iter = Meshes.upper_bound(requestedTimeValue);
127-
if (iter != Meshes.begin())
146+
double requestedTime = this->TimeRange[0];
147+
if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()))
128148
{
129-
iter = std::prev(iter);
149+
requestedTime = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
130150
}
131-
output->ShallowCopy(iter->second);
132-
}
133-
else
134-
{
135-
output->ShallowCopy(this->Meshes[0.0]);
151+
this->AnimatedCallback(requestedTime, this);
136152
}
137153

154+
output->ShallowCopy(this->StaticMesh);
155+
138156
return 1;
139157
}

0 commit comments

Comments
 (0)