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) 2018
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_IStream.h>
36 #include <UT/UT_OFStream.h>
37 
38 #include <ostream>
39 #include <iostream>
40 #include <stdio.h>
41 
42 
43 static void
44 usage(const char *program)
45 {
46  std::cerr << "Usage: " << program << " sourcefile dstfile\n";
47  std::cerr << "The extension of the source/dest will be used to determine" << std::endl;
48  std::cerr << "how the conversion is done. Supported extensions are .voxel" << std::endl;
49  std::cerr << "and .bgeo" << std::endl;
50 }
51 
52 
53 bool
55 {
56  // Check our magic token
57  if (!is.checkToken("VOXELS"))
58  return false;
59 
60 #if defined(HOUDINI_11)
61  int def = -1;
62  gdp->addPrimAttrib("name", sizeof(int), GB_ATTRIB_INDEX, &def);
63  GEO_AttributeHandle name_gah = gdp->getPrimAttribute("name");
64 #else
65  GA_RWHandleS attrib(gdp->addStringTuple(GA_ATTRIB_PRIMITIVE, "name", 1));
66 #endif
67 
68  while (is.checkToken("VOLUME"))
69  {
72 
73  is.getWord(buf);
74  name.harden(buf.buffer());
75 
76  int rx, ry, rz;
77 
78  is.read(&rx); is.read(&ry); is.read(&rz);
79 
80  // Center and size
81  float tx, ty, tz, sx, sy, sz;
82 
83  is.read<fpreal32>(&tx); is.read<fpreal32>(&ty); is.read<fpreal32>(&tz);
84  is.read<fpreal32>(&sx); is.read<fpreal32>(&sy); is.read<fpreal32>(&sz);
85 
86  GU_PrimVolume *vol;
87 
88  vol = (GU_PrimVolume *)GU_PrimVolume::build(gdp);
89 
90  // Set the name of the primitive
91  attrib.set(vol->getMapOffset(), name);
92 
93  // Set the center of the volume
94  vol->getDetail().setPos3(vol->getPointOffset(0),UT_Vector3(tx, ty, tz));
95 
96  UT_Matrix3 xform;
97 
98  // The GEO_PrimVolume treats the voxel array as a -1 to 1 cube
99  // so its size is 2, so we scale by 0.5 here.
100  xform.identity();
101  xform.scale(sx/2, sy/2, sz/2);
102 
103  vol->setTransform(xform);
104 
105  UT_VoxelArrayWriteHandleF handle = vol->getVoxelWriteHandle();
106 
107  // Resize the array.
108  handle->size(rx, ry, rz);
109 
110  if (!is.checkToken("{"))
111  return false;
112 
113  for (int z = 0; z < rz; z++)
114  {
115  for (int y = 0; y < ry; y++)
116  {
117  for (int x = 0; x < rx; x++)
118  {
119  float v;
120 
121  is.read<fpreal32>(&v);
122 
123  handle->setValue(x, y, z, v);
124  }
125  }
126  }
127 
128  if (!is.checkToken("}"))
129  return false;
130 
131  // Proceed to the next volume.
132  }
133 
134  // All done successfully
135  return true;
136 }
137 
138 bool
139 voxelLoad(const char *fname, GU_Detail *gdp)
140 {
141  // The UT_IFStream is a specialization of istream which has a lot
142  // of useful utlity methods and some corrections on the behaviour.
143  UT_IFStream is(fname, UT_ISTREAM_ASCII);
144 
145  return voxelLoad(is, gdp);
146 }
147 
148 bool
149 voxelSave(std::ostream &os, const GU_Detail *gdp)
150 {
151  // Write our magic token.
152  os << "VOXELS" << std::endl;
153 
154  GA_ROHandleS attrib(gdp->findPrimitiveAttribute("name"));
155 
156  // Now, for each volume in our gdp...
157 
159  UT_String name;
160  const GEO_Primitive *prim;
161 #if defined(HOUDINI_11)
162  FOR_ALL_PRIMITIVES(gdp, prim)
163 #else
164  GA_FOR_ALL_PRIMITIVES(gdp, prim)
165 #endif
166  {
167 #if defined(HOUDINI_11)
168  if (prim->getPrimitiveId() == GEOPRIMVOLUME)
169 #else
171 #endif
172  {
173  // Default name
174  buf.sprintf("volume_%" SYS_PRId64, exint(prim->getMapIndex()));
175  name.harden(buf.buffer());
176 
177  // Which is overridden by any name attribute.
178  if (attrib.isValid())
179  {
180  name = attrib.get(prim->getMapOffset());
181  }
182 
183  os << "VOLUME " << name << std::endl;
184  const GEO_PrimVolume *vol = (GEO_PrimVolume *) prim;
185 
186  int resx, resy, resz;
187 
188  // Save resolution
189  vol->getRes(resx, resy, resz);
190  os << resx << " " << resy << " " << resz << std::endl;
191 
192  // Save the center and approximate size.
193  // Calculating the size is complicated as we could be rotated
194  // or sheared. We lose all these because the .voxel format
195  // only supports aligned arrays.
196  UT_Vector3 p1, p2;
197 
198  UT_Vector3 tmp = gdp->getPos3(vol->getPointOffset(0));
199  os << tmp.x() << " " << tmp.y() << " " << tmp.z() << std::endl;
200 
201  vol->indexToPos(0, 0, 0, p1);
202  vol->indexToPos(1, 0, 0, p2);
203  os << resx * (p1 - p2).length() << " ";
204  vol->indexToPos(0, 1, 0, p2);
205  os << resy * (p1 - p2).length() << " ";
206  vol->indexToPos(0, 0, 1, p2);
207  os << resz * (p1 - p2).length() << std::endl;
208 
210 
211  // Enough of a header, dump the data.
212  os << "{" << std::endl;
213  for (int z = 0; z < resz; z++)
214  {
215  for (int y = 0; y < resy; y++)
216  {
217  os << " ";
218  for (int x = 0; x < resx; x++)
219  {
220  os << (*handle)(x, y, z) << " ";
221  }
222  os << std::endl;
223  }
224  }
225  os << "}" << std::endl;
226  os << std::endl;
227  }
228  }
229 
230  return true;
231 }
232 
233 bool
234 voxelSave(const char *fname, const GU_Detail *gdp)
235 {
236  UT_OFStream os(fname, UT_OFStream::out, UT_IOS_ASCII);
237 
238  // Default output precision of 6 will not reproduce our floats
239  // exactly on load, this define has the value that will ensure
240  // our reads match our writes.
241  os.precision(SYS_FLT_DIG);
242 
243  return voxelSave(os, gdp);
244 }
245 
246 
247 // Convert a volume into a toy ascii voxel format.
248 //
249 // Build using:
250 // hcustom -s geo2voxel.C
251 //
252 // Example usage:
253 // geo2voxel input.bgeo output.voxel
254 // geo2voxel input.voxel output.bgeo
255 //
256 // You can add support for the .voxel format in Houdini by editing
257 // your GEOio table file and adding the line
258 // .voxel "geo2voxel %s stdout.bgeo" "geo2voxel stdin.bgeo %s"
259 //
260 int
261 main(int argc, char *argv[])
262 {
263  CMD_Args args;
264  GU_Detail gdp;
265 
266  args.initialize(argc, argv);
267 
268  if (args.argc() != 3)
269  {
270  usage(argv[0]);
271  return 1;
272  }
273 
274  // Check if we are converting from .voxel. If the source extension
275  // is .voxel, we are converting from. Otherwise we convert to.
276  // By being liberal with our accepted extensions we will support
277  // a lot more than just .bgeo since the built in gdp.load() and save()
278  // will handle the issues for us.
279 
280  UT_String inputname, outputname;
281 
282  inputname.harden(argv[1]);
283  outputname.harden(argv[2]);
284 
285  if (!strcmp(inputname.fileExtension(), ".voxel"))
286  {
287  // Convert from voxel
288  voxelLoad(inputname, &gdp);
289 
290  // Save our result.
291 #if defined(HOUDINI_11)
292  gdp.save((const char *) outputname, 0, 0);
293 #else
294  gdp.save(outputname, NULL);
295 #endif
296  }
297  else
298  {
299  // Convert to voxel.
300  gdp.load(inputname, NULL);
301 
302  voxelSave(outputname, &gdp);
303  }
304  return 0;
305 }
SYS_FORCE_INLINE void setPos3(GA_Offset ptoff, const UT_Vector3 &P)
Set P from a UT_Vector3.
Definition: GA_Detail.h:207
SYS_FORCE_INLINE GA_Detail & getDetail() const
Definition: GA_Primitive.h:133
bool getWord(UT_WorkBuffer &buffer)
void scale(T sx, T sy, T sz)
Definition: UT_Matrix3.h:717
const GLdouble * v
Definition: glcorearb.h:836
GEO_API const TypeMask GEOPRIMVOLUME
UT_Vector3T< float > UT_Vector3
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:847
bool checkToken(const char *expected)
Definition: UT_IStream.h:250
SYS_FORCE_INLINE const char * buffer() const
virtual GA_PrimCompat::TypeMask getPrimitiveId() const
const char * fileExtension() const
Return the extension of a file path string.
Definition: UT_String.h:635
GLint y
Definition: glcorearb.h:102
Read-Write string handle.
Definition: GA_Handle.h:833
SYS_FORCE_INLINE UT_Vector3 getPos3(GA_Offset ptoff) const
The ptoff passed is the point offset.
Definition: GA_Detail.h:174
SYS_FORCE_INLINE T & x(void)
Definition: UT_Vector3.h:498
3D Vector class.
static GEO_PrimVolume * build(GU_Detail *gdp)
SYS_FORCE_INLINE T & z(void)
Definition: UT_Vector3.h:502
bool voxelSave(std::ostream &os, const GU_Detail *gdp)
Definition: geo2voxel.C:149
SYS_FORCE_INLINE GA_Attribute * addPrimAttrib(const GA_Attribute *src)
Definition: GEO_Detail.h:1737
void identity()
Set the matrix to identity.
Definition: UT_Matrix3.h:945
int64 exint
Definition: SYS_Types.h:116
#define SYS_FLT_DIG
Definition: SYS_Types.h:182
exint read(bool *array, exint sz=1)
Definition: UT_IStream.h:284
void harden()
Take shallow copy and make it deep.
Definition: UT_String.h:213
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:43
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:785
Portable replacement for std::ofstream.
Definition: UT_OFStream.h:26
GEO_AttributeHandle getPrimAttribute(const char *attrib_name) const
SYS_FORCE_INLINE const GA_Attribute * findPrimitiveAttribute(GA_AttributeScope s, const UT_StringRef &name) const
Definition: GA_Detail.h:984
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2539
#define SYS_PRId64
Definition: SYS_Types.h:67
bool indexToPos(int x, int y, int z, UT_Vector3 &pos) const
SYS_FORCE_INLINE T & y(void)
Definition: UT_Vector3.h:500
SYS_FORCE_INLINE GA_Index getMapIndex() const
Gets the index of this primitive in the detail containing it.
Definition: GA_Primitive.h:143
GLsizeiptr const void GLenum usage
Definition: glcorearb.h:663
bool voxelLoad(UT_IStream &is, GU_Detail *gdp)
Definition: geo2voxel.C:54
SYS_FORCE_INLINE GA_Offset getMapOffset() const
Gets the offset of this primitive in the detail containing it.
Definition: GA_Primitive.h:138
GLint GLenum GLint x
Definition: glcorearb.h:408
int main(int argc, char *argv[])
Definition: geo2voxel.C:261
SYS_FORCE_INLINE GA_Offset getPointOffset() const
void initialize(int argc, const char *const argv[])
Read-only handle for string attribute data.
Definition: GA_Handle.h:756
UT_VoxelArrayHandleF getVoxelHandle() const
void getRes(int &rx, int &ry, int &rz) const
Returns the resolution of the voxel array.
float fpreal32
Definition: SYS_Types.h:191
GLbitfield GLuint program
Definition: glcorearb.h:1930
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:794
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())