HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
geo2voxel.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024
3  * Side Effects Software Inc. All rights reserved.
4  *
5  * Redistribution and use of Houdini Development Kit samples in source and
6  * binary forms, with or without modification, are permitted provided that the
7  * following conditions are met:
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. The name of Side Effects Software may not be used to endorse or
11  * promote products derived from this software without specific prior
12  * written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17  * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  *----------------------------------------------------------------------------
26  */
27 
28 
29 #include <GU/GU_Detail.h>
30 #include <GU/GU_PrimVolume.h>
31 #include <GA/GA_Handle.h>
32 
33 #include <CMD/CMD_Args.h>
34 #include <UT/UT_Assert.h>
35 #include <UT/UT_Exit.h>
36 #include <UT/UT_IStream.h>
37 #include <UT/UT_Main.h>
38 #include <UT/UT_OFStream.h>
39 
40 #include <ostream>
41 #include <iostream>
42 #include <stdio.h>
43 
44 
45 static void
46 usage(const char *program)
47 {
48  std::cerr << "Usage: " << program << " sourcefile dstfile\n";
49  std::cerr << "The extension of the source/dest will be used to determine" << std::endl;
50  std::cerr << "how the conversion is done. Supported extensions are .voxel" << std::endl;
51  std::cerr << "and .bgeo" << std::endl;
52 }
53 
54 
55 bool
57 {
58  // Check our magic token
59  if (!is.checkToken("VOXELS"))
60  return false;
61 
62 #if defined(HOUDINI_11)
63  int def = -1;
64  gdp->addPrimAttrib("name", sizeof(int), GB_ATTRIB_INDEX, &def);
65  GEO_AttributeHandle name_gah = gdp->getPrimAttribute("name");
66 #else
67  GA_RWHandleS attrib(gdp->addStringTuple(GA_ATTRIB_PRIMITIVE, "name", 1));
68 #endif
69 
70  while (is.checkToken("VOLUME"))
71  {
74 
75  is.getWord(buf);
76  name.harden(buf.buffer());
77 
78  int rx, ry, rz;
79 
80  is.read(&rx); is.read(&ry); is.read(&rz);
81 
82  // Center and size
83  float tx, ty, tz, sx, sy, sz;
84 
85  is.read<fpreal32>(&tx); is.read<fpreal32>(&ty); is.read<fpreal32>(&tz);
86  is.read<fpreal32>(&sx); is.read<fpreal32>(&sy); is.read<fpreal32>(&sz);
87 
88  GU_PrimVolume *vol;
89 
90  vol = (GU_PrimVolume *)GU_PrimVolume::build(gdp);
91 
92  // Set the name of the primitive
93  attrib.set(vol->getMapOffset(), name);
94 
95  // Set the center of the volume
96  vol->getDetail().setPos3(vol->getPointOffset(0),UT_Vector3(tx, ty, tz));
97 
98  UT_Matrix3 xform;
99 
100  // The GEO_PrimVolume treats the voxel array as a -1 to 1 cube
101  // so its size is 2, so we scale by 0.5 here.
102  xform.identity();
103  xform.scale(sx/2, sy/2, sz/2);
104 
105  vol->setTransform(xform);
106 
107  UT_VoxelArrayWriteHandleF handle = vol->getVoxelWriteHandle();
108 
109  // Resize the array.
110  handle->size(rx, ry, rz);
111 
112  if (!is.checkToken("{"))
113  return false;
114 
115  for (int z = 0; z < rz; z++)
116  {
117  for (int y = 0; y < ry; y++)
118  {
119  for (int x = 0; x < rx; x++)
120  {
121  float v;
122 
123  is.read<fpreal32>(&v);
124 
125  handle->setValue(x, y, z, v);
126  }
127  }
128  }
129 
130  if (!is.checkToken("}"))
131  return false;
132 
133  // Proceed to the next volume.
134  }
135 
136  // All done successfully
137  return true;
138 }
139 
140 bool
141 voxelLoad(const char *fname, GU_Detail *gdp)
142 {
143  // The UT_IFStream is a specialization of istream which has a lot
144  // of useful utlity methods and some corrections on the behaviour.
145  UT_IFStream is(fname, UT_ISTREAM_ASCII);
146 
147  return voxelLoad(is, gdp);
148 }
149 
150 bool
151 voxelSave(std::ostream &os, const GU_Detail *gdp)
152 {
153  // Write our magic token.
154  os << "VOXELS" << std::endl;
155 
156  GA_ROHandleS attrib(gdp->findPrimitiveAttribute("name"));
157 
158  // Now, for each volume in our gdp...
159 
161  UT_String name;
162  const GEO_Primitive *prim;
163 #if defined(HOUDINI_11)
164  FOR_ALL_PRIMITIVES(gdp, prim)
165 #else
166  GA_FOR_ALL_PRIMITIVES(gdp, prim)
167 #endif
168  {
169 #if defined(HOUDINI_11)
170  if (prim->getPrimitiveId() == GEOPRIMVOLUME)
171 #else
173 #endif
174  {
175  // Default name
176  buf.sprintf("volume_%" SYS_PRId64, exint(prim->getMapIndex()));
177  name.harden(buf.buffer());
178 
179  // Which is overridden by any name attribute.
180  if (attrib.isValid())
181  {
182  name = attrib.get(prim->getMapOffset());
183  }
184 
185  os << "VOLUME " << name << std::endl;
186  const GEO_PrimVolume *vol = (GEO_PrimVolume *) prim;
187 
188  int resx, resy, resz;
189 
190  // Save resolution
191  vol->getRes(resx, resy, resz);
192  os << resx << " " << resy << " " << resz << std::endl;
193 
194  // Save the center and approximate size.
195  // Calculating the size is complicated as we could be rotated
196  // or sheared. We lose all these because the .voxel format
197  // only supports aligned arrays.
198  UT_Vector3 p1, p2;
199 
200  UT_Vector3 tmp = gdp->getPos3(vol->getPointOffset(0));
201  os << tmp.x() << " " << tmp.y() << " " << tmp.z() << std::endl;
202 
203  vol->indexToPos(0, 0, 0, p1);
204  vol->indexToPos(1, 0, 0, p2);
205  os << resx * (p1 - p2).length() << " ";
206  vol->indexToPos(0, 1, 0, p2);
207  os << resy * (p1 - p2).length() << " ";
208  vol->indexToPos(0, 0, 1, p2);
209  os << resz * (p1 - p2).length() << std::endl;
210 
212 
213  // Enough of a header, dump the data.
214  os << "{" << std::endl;
215  for (int z = 0; z < resz; z++)
216  {
217  for (int y = 0; y < resy; y++)
218  {
219  os << " ";
220  for (int x = 0; x < resx; x++)
221  {
222  os << (*handle)(x, y, z) << " ";
223  }
224  os << std::endl;
225  }
226  }
227  os << "}" << std::endl;
228  os << std::endl;
229  }
230  }
231 
232  return true;
233 }
234 
235 bool
236 voxelSave(const char *fname, const GU_Detail *gdp)
237 {
238  UT_OFStream os(fname, UT_OFStream::out, UT_IOS_ASCII);
239 
240  // Default output precision of 6 will not reproduce our floats
241  // exactly on load, this define has the value that will ensure
242  // our reads match our writes.
243  os.precision(SYS_FLT_DIG);
244 
245  return voxelSave(os, gdp);
246 }
247 
248 
249 // Convert a volume into a toy ascii voxel format.
250 //
251 // Build using:
252 // hcustom -s geo2voxel.C
253 //
254 // Example usage:
255 // geo2voxel input.bgeo output.voxel
256 // geo2voxel input.voxel output.bgeo
257 //
258 // You can add support for the .voxel format in Houdini by editing
259 // your GEOio table file and adding the line
260 // .voxel "geo2voxel %s stdout.bgeo" "geo2voxel stdin.bgeo %s"
261 //
262 int
263 theMain(int argc, char *argv[])
264 {
265  CMD_Args args;
266  GU_Detail gdp;
267 
268  args.initialize(argc, argv);
269 
270  if (args.argc() != 3)
271  {
272  usage(argv[0]);
273  return 1;
274  }
275 
276  // Check if we are converting from .voxel. If the source extension
277  // is .voxel, we are converting from. Otherwise we convert to.
278  // By being liberal with our accepted extensions we will support
279  // a lot more than just .bgeo since the built in gdp.load() and save()
280  // will handle the issues for us.
281 
282  UT_String inputname, outputname;
283 
284  inputname.harden(argv[1]);
285  outputname.harden(argv[2]);
286 
287  if (!strcmp(inputname.fileExtension(), ".voxel"))
288  {
289  // Convert from voxel
290  voxelLoad(inputname, &gdp);
291 
292  // Save our result.
293 #if defined(HOUDINI_11)
294  gdp.save((const char *) outputname, 0, 0);
295 #else
296  gdp.save(outputname, NULL);
297 #endif
298  }
299  else
300  {
301  // Convert to voxel.
302  gdp.load(inputname, NULL);
303 
304  voxelSave(outputname, &gdp);
305  }
306 
307  return 0;
308 }
309 UT_MAIN(theMain);// exit with proper tear down
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
SYS_FORCE_INLINE GA_Detail & getDetail() const
Definition: GA_Primitive.h:141
bool getWord(UT_WorkBuffer &buffer)
void scale(T sx, T sy, T sz)
Definition: UT_Matrix3.h:854
const GLdouble * v
Definition: glcorearb.h:837
GEO_API const TypeMask GEOPRIMVOLUME
char * fileExtension()
Definition: UT_String.h:640
UT_Vector3T< float > UT_Vector3
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:848
bool checkToken(const char *expected)
Definition: UT_IStream.h:242
GA_PrimCompat::TypeMask getPrimitiveId() const override
constexpr SYS_FORCE_INLINE T & z() noexcept
Definition: UT_Vector3.h:667
int64 exint
Definition: SYS_Types.h:125
SYS_FORCE_INLINE const char * buffer() const
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:795
GLint y
Definition: glcorearb.h:103
SYS_FORCE_INLINE UT_Vector3 getPos3(GA_Offset ptoff) const
The ptoff passed is the point offset.
Definition: GA_Detail.h:185
float fpreal32
Definition: SYS_Types.h:200
bool voxelSave(std::ostream &os, const GU_Detail *gdp)
Definition: geo2voxel.C:151
SYS_FORCE_INLINE GA_Attribute * addPrimAttrib(const GA_Attribute *src)
Definition: GEO_Detail.h:1825
void identity()
Set the matrix to identity.
Definition: UT_Matrix3.h:1128
#define SYS_FLT_DIG
Definition: SYS_Types.h:191
exint read(bool *array, exint sz=1)
Definition: UT_IStream.h:276
void harden()
Take shallow copy and make it deep.
Definition: UT_String.h:215
IOStatus load(const char *filename, const GA_LoadOptions *opts=0, UT_StringArray *errors=0)
Load a geometry file.
int argc() const
Definition: UT_Args.h:48
IOStatus save(const char *filename, const GA_SaveOptions *options, UT_StringArray *errors=0) const
#define GA_FOR_ALL_PRIMITIVES(gdp, prim)
Definition: GA_GBMacros.h:36
GLuint const GLchar * name
Definition: glcorearb.h:786
Portable replacement for std::ofstream.
Definition: UT_OFStream.h:26
GLint GLenum GLint x
Definition: glcorearb.h:409
int theMain(int argc, char *argv[])
Definition: geo2voxel.C:263
GEO_AttributeHandle getPrimAttribute(const char *attrib_name) const
static GEO_PrimVolume * build(GU_Detail *gdp, bool integers=false, int comps=1)
SYS_FORCE_INLINE const GA_Attribute * findPrimitiveAttribute(GA_AttributeScope s, const UT_StringRef &name) const
Definition: GA_Detail.h:1048
#define SYS_PRId64
Definition: SYS_Types.h:76
bool indexToPos(int x, int y, int z, UT_Vector3 &pos) const
SYS_FORCE_INLINE GA_Index getMapIndex() const
Gets the index of this primitive in the detail containing it.
Definition: GA_Primitive.h:151
GLsizeiptr const void GLenum usage
Definition: glcorearb.h:664
SYS_FORCE_INLINE void setPos3(GA_Offset ptoff, const UT_Vector3 &pos)
Set P from a UT_Vector3.
Definition: GA_Detail.h:237
bool voxelLoad(UT_IStream &is, GU_Detail *gdp)
Definition: geo2voxel.C:56
SYS_FORCE_INLINE GA_Offset getMapOffset() const
Gets the offset of this primitive in the detail containing it.
Definition: GA_Primitive.h:146
**If you just want to fire and args
Definition: thread.h:609
SYS_FORCE_INLINE GA_Offset getPointOffset() const
void initialize(int argc, const char *const argv[])
UT_VoxelArrayHandleF getVoxelHandle() const
constexpr SYS_FORCE_INLINE T & y() noexcept
Definition: UT_Vector3.h:665
void getRes(int &rx, int &ry, int &rz) const
Returns the resolution of the voxel array.
GLbitfield GLuint program
Definition: glcorearb.h:1931
UT_MAIN(theMain)
constexpr SYS_FORCE_INLINE T & x() noexcept
Definition: UT_Vector3.h:663
GA_Attribute * addStringTuple(GA_AttributeOwner owner, GA_AttributeScope scope, const UT_StringHolder &name, int tuple_size, const UT_Options *creation_args=0, const GA_AttributeOptions *attribute_options=0, const GA_ReuseStrategy &reuse=GA_ReuseStrategy())