foamGltfScene.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2021-2022 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "foamGltfScene.H"
29 #include "OFstream.H"
30 #include "OSspecific.H"
31 
32 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
33 
35 :
36  objects_(),
37  meshes_(),
38  bufferViews_(),
39  accessors_(),
40  animations_(),
41  bytes_(0)
42 {}
43 
44 
45 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
46 
47 Foam::glTF::mesh& Foam::glTF::scene::getMesh(label meshi)
48 {
49  const label lastMeshi = (meshes_.size() - 1);
50 
51  if (meshi < 0)
52  {
53  meshi = (lastMeshi < 0 ? static_cast<label>(0) : lastMeshi);
54  }
55 
56  if (meshi > lastMeshi)
57  {
59  << "Mesh " << meshi << " out of range: " << lastMeshi
60  << abort(FatalError);
61  }
62 
63  return meshes_[meshi];
64 }
65 
66 
68 (
69  const vectorField& fld,
70  const word& name,
71  const label meshi,
72  const scalarField& alpha
73 )
74 {
75  auto& gmesh = getMesh(meshi);
76 
77  auto& bv = bufferViews_.create(name);
78  bv.byteOffset() = bytes_;
79  bv.byteLength() = fld.size()*3*sizeof(float); // 3 components
80  bv.target() = key(targetTypes::ARRAY_BUFFER);
81  bytes_ += bv.byteLength();
82 
83  auto& acc = accessors_.create(name);
84  acc.bufferViewId() = bv.id();
85  acc.set(fld, false); // no min-max
86 
87  auto& obj = objects_.create(name);
88 
89  if (alpha.empty())
90  {
91  obj.addData(fld);
92  }
93  else
94  {
95  bv.byteLength() += fld.size()*sizeof(float);
96  bytes_ += fld.size()*sizeof(float);
97 
98  acc.type() = "VEC4";
99 
100  // Support uniform alpha vs full alpha field
101  tmp<scalarField> talpha(alpha);
102 
103  if (alpha.size() == 1 && alpha.size() < fld.size())
104  {
105  talpha = tmp<scalarField>::New(fld.size(), alpha[0]);
106  }
107 
108  obj.addData(fld, talpha());
109  }
111  gmesh.addColour(acc.id());
112 
113  return acc.id();
114 }
115 
116 
117 Foam::label Foam::glTF::scene::createAnimation(const word& name)
118 {
119  animations_.create(name);
120  return animations_.size() - 1;
121 }
122 
123 
125 (
126  const label animationi,
127  const label inputId,
128  const label outputId,
129  const label meshId,
130  const string& interpolation
131 )
132 {
133  if (animationi > animations_.size() - 1)
134  {
136  << "Animation " << animationi << " out of range "
137  << (animations_.size() - 1)
138  << abort(FatalError);
139  }
140 
141  const label nodeId = meshId + 1; // offset by 1 for parent node
142 
143  // Note
144  // using 1 mesh per node +1 parent node => meshes_.size() nodes in total
145  if (nodeId > meshes_.size())
146  {
148  << "Node " << nodeId << " out of range " << meshes_.size()
149  << abort(FatalError);
150  }
151 
152  animations_[animationi].addTranslation
153  (
154  inputId,
155  outputId,
156  nodeId,
158  );
159 }
160 
161 
162 void Foam::glTF::scene::write(const fileName& outputFile)
163 {
164  fileName jsonFile(outputFile);
165  jsonFile.replace_ext("gltf");
166 
167  // Note: called on master only
168 
169  if (!isDir(jsonFile.path()))
170  {
171  mkDir(jsonFile.path());
172  }
173 
174  OFstream os(jsonFile);
175  write(os);
176 }
177 
178 
180 {
181  fileName binFile(os.name());
182  binFile.replace_ext("bin");
183 
184  // Write binary file
185  // Note: using stdStream
186  OFstream bin(binFile, IOstreamOption::BINARY);
187  auto& osbin = bin.stdStream();
188 
189  label totalBytes = 0;
190  for (const auto& object : objects_.data())
191  {
192  for (const auto& data : object.data())
193  {
194  osbin.write
195  (
196  reinterpret_cast<const char*>(&data),
197  sizeof(float)
198  );
199 
200  totalBytes += sizeof(float);
201  }
202  }
203 
204  // Write json file
205  os << "{" << nl << incrIndent;
206 
207  os << indent << "\"asset\" : {" << nl << incrIndent
208  << indent << "\"generator\" : \"OpenFOAM - www.openfoam.com\"," << nl
209  << indent << "\"version\" : \"2.0\"" << nl << decrIndent
210  << indent << "}," << nl;
211 
212  os << indent << "\"extras\" : {" << nl << incrIndent
213  /* << content */
214  << decrIndent
215  << indent << "}," << nl;
216 
217  os << indent << "\"scene\": 0," << nl;
218 
219  os << indent << "\"scenes\": [{" << nl << incrIndent
220  << indent << "\"nodes\" : [0]" << nl << decrIndent
221  << indent << "}]," << nl;
222 
223  os << indent << "\"buffers\" : [{" << nl << incrIndent
224  << indent << "\"uri\" : " << string(fileName::name(binFile))
225  << "," << nl
226  << indent << "\"byteLength\" : " << totalBytes << nl << decrIndent
227  << indent << "}]," << nl;
228 
229  os << indent << "\"nodes\" : [" << nl << incrIndent
230  << indent << "{" << nl << incrIndent
231  << indent << "\"children\" : [" << nl << incrIndent;
232 
233  // List of child node indices
234  os << indent;
235  forAll(meshes_, meshi)
236  {
237  const label nodeId = meshi + 1;
238 
239  os << nodeId;
240 
241  if (meshi != meshes_.size() - 1) os << ", ";
242 
243  if ((meshi+1) % 10 == 0) os << nl << indent;
244  }
245 
246  os << decrIndent << nl << indent << "]," << nl
247  << indent << "\"name\" : \"parent\"" << nl << decrIndent
248  << indent << "}," << nl;
249 
250  // List of child meshes
251  forAll(meshes_, meshi)
252  {
253  os << indent << "{" << nl << incrIndent
254  << indent << "\"mesh\" : " << meshi << nl << decrIndent
255  << indent << "}";
256 
257  if (meshi != meshes_.size() - 1) os << ",";
258 
259  os << nl;
260  }
261 
262  os << decrIndent << indent << "]";
263 
264  meshes_.write(os, "meshes");
265 
266  bufferViews_.write(os, "bufferViews");
267 
268  accessors_.write(os, "accessors");
269 
270  animations_.write(os, "animations");
271 
272  os << nl;
273 
274  os << decrIndent << "}" << endl;
275 }
276 
277 
278 // ************************************************************************* //
A class for handling file names.
Definition: fileName.H:72
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:493
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
glTF mesh
Definition: foamGltfMesh.H:60
Output to file stream, using an OSstream.
Definition: OFstream.H:49
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
void addToAnimation(const label animationi, const label inputId, const label outputId, const label meshId, const string &interpolation="LINEAR")
Add to existing animation.
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:169
fileName & replace_ext(const word &ending)
Remove extension (if any) and append a new one.
Definition: fileNameI.H:230
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:860
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:614
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
label createAnimation(const word &name)
Returns index of last animation.
scene()
Default construct.
Definition: foamGltfScene.C:27
A class for handling words, derived from Foam::string.
Definition: word.H:63
word name() const
Return basename (part beyond last /), including its extension.
Definition: fileNameI.H:205
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
errorManip< error > abort(error &err)
Definition: errorManip.H:139
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
OBJstream os(runTime.globalPath()/outputName)
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:511
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< ' ';}gmvFile<< nl;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:103
label addColourToMesh(const vectorField &fld, const word &name, const label meshId, const scalarField &alpha=scalarField::null())
Add a colour field to the mesh, optionally with an alpha channel.
Definition: foamGltfScene.C:61
Abstract base class for volume field interpolation.
const dimensionedScalar alpha
Fine-structure constant: default SI units: [].
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:502
void write(const fileName &outputFile)
Write to file pair (.gltf, .bin)