1 /* Copyright (c) 2005-2007, Stefan Eilemann <eile@equalizergraphics.com>
2 All rights reserved.
3 - Cleaned up code for 64 bit, little and big endian support
4 - Added new ply data types (uint8, float32, int32)
5 */
6
7 /*
8
9 The interface routines for reading and writing PLY polygon files.
10
11 Greg Turk, February 1994
12
13 ---------------------------------------------------------------
14
15 A PLY file contains a single polygonal _object_.
16
17 An object is composed of lists of _elements_. Typical elements are
18 vertices, faces, edges and materials.
19
20 Each type of element for a given object has one or more _properties_
21 associated with the element type. For instance, a vertex element may
22 have as properties the floating-point values x,y,z and the three unsigned
23 chars representing red, green and blue.
24
25 ---------------------------------------------------------------
26
27 Copyright (c) 1994 The Board of Trustees of The Leland Stanford
28 Junior University. All rights reserved.
29
30 Permission to use, copy, modify and distribute this software and its
31 documentation for any purpose is hereby granted without fee, provided
32 that the above copyright notice and this permission notice appear in
33 all copies of this software and that you do not sell the software.
34
35 THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
36 EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
37 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
38
39 */
40
41 #include "ply.h"
42 #include"typedefs.h"
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <math.h>
47 #include <string.h>
48 #include <string>
49 #include <vector>
50
51 #include <osg/Math>
52 #include <osgDB/FileUtils>
53
54 #if defined(_MSC_VER) && defined(OSG_DISABLE_MSVC_WARNINGS)
55 #pragma warning( disable : 4996 )
56 #endif
57
58 #ifdef WIN32
59 # ifndef LITTLE_ENDIAN
60 # define LITTLE_ENDIAN
61 # endif
62 #endif
63
64 const char *type_names[] = {
65 "invalid",
66 "char", "short", "int",
67 "uchar", "ushort", "uint",
68 "float", "double", "float32", "uint8", "int32"
69 };
70
71 int ply_type_size[] = {
72 0, 1, 2, 4, 1, 2, 4, 4, 8, 4, 1, 4
73 };
74
75 #define NO_OTHER_PROPS -1
76
77 #define DONT_STORE_PROP 0
78 #define STORE_PROP 1
79
80 #define OTHER_PROP 0
81 #define NAMED_PROP 1
82
83
84 /* returns 1 if strings are equal, 0 if not */
85 int equal_strings(const char *, const char *);
86
87 /* find an element in a plyfile's list */
88 PlyElement *find_element(PlyFile *, const char *);
89
90 /* find a property in an element's list */
91 PlyProperty *find_property(PlyElement *, const char *, int *);
92
93 /* write to a file the word describing a PLY file data type */
94 void write_scalar_type (FILE *, int);
95
96 /* read a line from a file and break it up into separate words */
97 char **get_words(FILE *, int *, char **);
98
99 /* write an item to a file */
100 void write_binary_item(PlyFile *, int, unsigned int, double, int);
101 void write_ascii_item(FILE *, int, unsigned int, double, int);
102
103 /* add information to a PLY file descriptor */
104 void add_element(PlyFile *, char **, int);
105 void add_property(PlyFile *, char **, int);
106 void add_comment(PlyFile *, char *);
107 void add_obj_info(PlyFile *, char *);
108
109 /* copy a property */
110 void copy_property(PlyProperty *, PlyProperty *);
111
112 /* store a value into where a pointer and a type specify */
113 void store_item(char *, int, int, unsigned int, double);
114
115 /* return the value of a stored item */
116 void get_stored_item( void *, int, int *, unsigned int *, double *);
117
118 /* return the value stored in an item, given ptr to it and its type */
119 double get_item_value(char *, int);
120
121 /* get binary or ascii item and store it according to ptr and type */
122 void get_ascii_item(char *, int, int *, unsigned int *, double *);
123 void get_binary_item(PlyFile *, int, int *, unsigned int *, double *);
124
125 /* get a bunch of elements from a file */
126 void ascii_get_element(PlyFile *, char *);
127 void binary_get_element(PlyFile *, char *);
128
129 /* memory allocation */
130 char *my_alloc(int, int, const char *);
131
132 /************************/
133 /* Byte-swapping macros */
134 /************************/
135
swap2Bytes(void * ptr)136 void swap2Bytes( void* ptr )
137 {
138 unsigned char* bytes = (unsigned char*)ptr;
139 unsigned short* result = (unsigned short*)ptr;
140
141 *result = (bytes[0]<<8) | bytes[1];
142 }
143
swap4Bytes(void * ptr)144 void swap4Bytes( void* ptr )
145 {
146 unsigned char* bytes = (unsigned char*)ptr;
147 unsigned int* result = (unsigned int*)ptr;
148
149 *result = (bytes[0]<<24) | (bytes[1]<<16) | (bytes[2]<<8) | bytes[3];
150 }
151
swap8Bytes(void * ptr)152 void swap8Bytes( void* ptr )
153 {
154 unsigned char* bytes = (unsigned char*)ptr;
155 unsigned long long* result = (unsigned long long*)ptr;
156
157 *result = ((unsigned long long)(bytes[0])) << 56 |
158 ((unsigned long long)(bytes[1])) << 48 |
159 ((unsigned long long)(bytes[2])) << 40 |
160 ((unsigned long long)(bytes[3])) << 32 |
161 ((unsigned long long)(bytes[4])) << 24 |
162 ((unsigned long long)(bytes[5])) << 16 |
163 ((unsigned long long)(bytes[6])) << 8 |
164 bytes[7];
165
166
167 }
168
169 #ifdef LITTLE_ENDIAN
swap2LE(void *)170 void swap2LE( void* ) {}
swap2LE(short *)171 void swap2LE( short* ) {}
swap2LE(unsigned short *)172 void swap2LE( unsigned short* ) {}
swap4LE(void *)173 void swap4LE( void* ) {}
swap4LE(int *)174 void swap4LE( int* ) {}
swap4LE(unsigned int *)175 void swap4LE( unsigned int* ) {}
swap4LE(float *)176 void swap4LE( float* ) {}
swap8LE(void *)177 void swap8LE( void* ) {}
swap8LE(long long *)178 void swap8LE( long long* ) {}
swap8LE(unsigned long long *)179 void swap8LE( unsigned long long* ) {}
swap8LE(double *)180 void swap8LE( double* ) {}
181
swap2BE(void * ptr)182 void swap2BE( void* ptr ) { swap2Bytes(ptr); }
swap2BE(short * ptr)183 void swap2BE( short* ptr ) { swap2Bytes(ptr); }
swap2BE(unsigned short * ptr)184 void swap2BE( unsigned short* ptr ) { swap2Bytes(ptr); }
swap4BE(void * ptr)185 void swap4BE( void* ptr ) { swap4Bytes(ptr); }
swap4BE(int * ptr)186 void swap4BE( int* ptr ) { swap4Bytes(ptr); }
swap4BE(unsigned int * ptr)187 void swap4BE( unsigned int* ptr ) { swap4Bytes(ptr); }
swap4BE(float * ptr)188 void swap4BE( float* ptr ) { swap4Bytes(ptr); }
swap8BE(long long * ptr)189 void swap8BE( long long* ptr ) { swap8Bytes(ptr); }
swap8BE(void * ptr)190 void swap8BE( void* ptr ) { swap8Bytes(ptr); }
swap8BE(unsigned long long * ptr)191 void swap8BE( unsigned long long* ptr ) { swap8Bytes(ptr); }
swap8BE(double * ptr)192 void swap8BE( double* ptr ) { swap8Bytes(ptr); }
193
194 #else // LITTLE_ENDIAN
195
swap2LE(void * ptr)196 void swap2LE( void* ptr ) { swap2Bytes(ptr); }
swap2LE(short * ptr)197 void swap2LE( short* ptr ) { swap2Bytes(ptr); }
swap2LE(unsigned short * ptr)198 void swap2LE( unsigned short* ptr ) { swap2Bytes(ptr); }
swap4LE(void * ptr)199 void swap4LE( void* ptr ) { swap4Bytes(ptr); }
swap4LE(int * ptr)200 void swap4LE( int* ptr ) { swap4Bytes(ptr); }
swap4LE(unsigned int * ptr)201 void swap4LE( unsigned int* ptr ) { swap4Bytes(ptr); }
swap4LE(float * ptr)202 void swap4LE( float* ptr ) { swap4Bytes(ptr); }
swap8LE(long long * ptr)203 void swap8LE( long long* ptr ) { swap8Bytes(ptr); }
swap8LE(void * ptr)204 void swap8LE( void* ptr ) { swap8Bytes(ptr); }
swap8LE(unsigned long long * ptr)205 void swap8LE( unsigned long long* ptr ) { swap8Bytes(ptr); }
swap8LE(double * ptr)206 void swap8LE( double* ptr ) { swap8Bytes(ptr); }
207
swap2BE(void *)208 void swap2BE( void* ) {}
swap2BE(short *)209 void swap2BE( short* ) {}
swap2BE(unsigned short *)210 void swap2BE( unsigned short* ) {}
swap4BE(void *)211 void swap4BE( void* ) {}
swap4BE(int *)212 void swap4BE( int* ) {}
swap4BE(unsigned int *)213 void swap4BE( unsigned int* ) {}
swap4BE(float *)214 void swap4BE( float* ) {}
swap8BE(void *)215 void swap8BE( void* ) {}
swap8BE(long long *)216 void swap8BE( long long* ) {}
swap8BE(unsigned long long *)217 void swap8BE( unsigned long long* ) {}
swap8BE(double *)218 void swap8BE( double* ) {}
219
220 #endif // LITTLE_ENDIAN
221
222
223 /*************/
224 /* Writing */
225 /*************/
226
227
228 /******************************************************************************
229 Given a file pointer, get ready to write PLY data to the file.
230
231 Entry:
232 fp - the given file pointer
233 nelems - number of elements in object
234 elem_names - list of element names
235 file_type - file type, either ascii or binary
236
237 Exit:
238 returns a pointer to a PlyFile, used to refer to this file, or NULL if error
239 ******************************************************************************/
240
ply_write(FILE * fp,int nelems,const char ** elem_names,int file_type)241 PlyFile *ply_write(
242 FILE *fp,
243 int nelems,
244 const char **elem_names,
245 int file_type
246 )
247 {
248 int i;
249 PlyFile *plyfile;
250 PlyElement *elem;
251
252 /* check for NULL file pointer */
253 if (fp == NULL)
254 return (NULL);
255
256 /* create a record for this object */
257
258 plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
259 plyfile->file_type = file_type;
260 plyfile->num_comments = 0;
261 plyfile->num_obj_info = 0;
262 plyfile->nelems = nelems;
263 plyfile->version = 1.0;
264 plyfile->fp = fp;
265 plyfile->other_elems = NULL;
266
267 /* tuck aside the names of the elements */
268
269 plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems);
270 for (i = 0; i < nelems; i++) {
271 elem = (PlyElement *) myalloc (sizeof (PlyElement));
272 plyfile->elems[i] = elem;
273 elem->name = strdup (elem_names[i]);
274 elem->num = 0;
275 elem->nprops = 0;
276 }
277
278 /* return pointer to the file descriptor */
279 return (plyfile);
280 }
281
282
283 /******************************************************************************
284 Open a polygon file for writing.
285
286 Entry:
287 filename - name of file to read from
288 nelems - number of elements in object
289 elem_names - list of element names
290 file_type - file type, either ascii or binary
291
292 Exit:
293 version - version number of PLY file
294 returns a file identifier, used to refer to this file, or NULL if error
295 ******************************************************************************/
296
ply_open_for_writing(char * filename,int nelems,const char ** elem_names,int file_type,float * version)297 PlyFile *ply_open_for_writing(
298 char *filename,
299 int nelems,
300 const char **elem_names,
301 int file_type,
302 float *version
303 )
304 {
305 /* open the file for writing */
306
307 FILE *fp = osgDB::fopen (filename, "wb");
308 if (fp == NULL) {
309 return (NULL);
310 }
311
312 /* create the actual PlyFile structure */
313
314 PlyFile *plyfile = ply_write (fp, nelems, elem_names, file_type);
315
316 // If the plyfile could not load return NULL
317 if (plyfile == NULL)
318 return (NULL);
319
320 /* say what PLY file version number we're writing */
321 *version = plyfile->version;
322
323 /* return pointer to the file descriptor */
324 return (plyfile);
325 }
326
327
328 /******************************************************************************
329 Describe an element, including its properties and how many will be written
330 to the file.
331
332 Entry:
333 plyfile - file identifier
334 elem_name - name of element that information is being specified about
335 nelems - number of elements of this type to be written
336 nprops - number of properties contained in the element
337 prop_list - list of properties
338 ******************************************************************************/
339
ply_describe_element(PlyFile * plyfile,const char * elem_name,int nelems,int nprops,PlyProperty * prop_list)340 void ply_describe_element(
341 PlyFile *plyfile,
342 const char *elem_name,
343 int nelems,
344 int nprops,
345 PlyProperty *prop_list
346 )
347 {
348 int i;
349 PlyElement *elem;
350 PlyProperty *prop;
351
352 /* look for appropriate element */
353 elem = find_element (plyfile, elem_name);
354 if (elem == NULL) {
355 char error[100];
356 sprintf (error, "ply_describe_element: can't find element '%s'\n",elem_name);
357 throw ply::MeshException( error );
358 }
359
360 elem->num = nelems;
361
362 /* copy the list of properties */
363
364 elem->nprops = nprops;
365 elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops);
366 elem->store_prop = (char *) myalloc (sizeof (char) * nprops);
367
368 for (i = 0; i < nprops; i++) {
369 prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
370 elem->props[i] = prop;
371 elem->store_prop[i] = NAMED_PROP;
372 copy_property (prop, &prop_list[i]);
373 }
374 }
375
376
377 /******************************************************************************
378 Describe a property of an element.
379
380 Entry:
381 plyfile - file identifier
382 elem_name - name of element that information is being specified about
383 prop - the new property
384 ******************************************************************************/
385
ply_describe_property(PlyFile * plyfile,const char * elem_name,PlyProperty * prop)386 void ply_describe_property(
387 PlyFile *plyfile,
388 const char *elem_name,
389 PlyProperty *prop
390 )
391 {
392 PlyElement *elem;
393 PlyProperty *elem_prop;
394
395 /* look for appropriate element */
396 elem = find_element (plyfile, elem_name);
397 if (elem == NULL) {
398 fprintf(stderr, "ply_describe_property: can't find element '%s'\n",
399 elem_name);
400 return;
401 }
402
403 /* create room for new property */
404
405 if (elem->nprops == 0) {
406 elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
407 elem->store_prop = (char *) myalloc (sizeof (char));
408 elem->nprops = 1;
409 }
410 else {
411 elem->nprops++;
412 elem->props = (PlyProperty **)
413 realloc (elem->props, sizeof (PlyProperty *) * elem->nprops);
414 elem->store_prop = (char *)
415 realloc (elem->store_prop, sizeof (char) * elem->nprops);
416 }
417
418 /* copy the new property */
419 elem->other_offset = 0; //added by wjs Purify UMR
420 elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
421 elem->props[elem->nprops - 1] = elem_prop;
422 elem->store_prop[elem->nprops - 1] = NAMED_PROP;
423 copy_property (elem_prop, prop);
424 }
425
426
427 /******************************************************************************
428 Describe what the "other" properties are that are to be stored, and where
429 they are in an element.
430 ******************************************************************************/
431
ply_describe_other_properties(PlyFile * plyfile,PlyOtherProp * other,int offset)432 void ply_describe_other_properties(
433 PlyFile *plyfile,
434 PlyOtherProp *other,
435 int offset
436 )
437 {
438 int i;
439 PlyElement *elem;
440 PlyProperty *prop;
441
442 /* look for appropriate element */
443 elem = find_element (plyfile, other->name);
444 if (elem == NULL) {
445 fprintf(stderr, "ply_describe_other_properties: can't find element '%s'\n",
446 other->name);
447 return;
448 }
449
450 /* create room for other properties */
451
452 if (elem->nprops == 0) {
453 elem->props = (PlyProperty **)
454 myalloc (sizeof (PlyProperty *) * other->nprops);
455 elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops);
456 elem->nprops = 0;
457 }
458 else {
459 int newsize;
460 newsize = elem->nprops + other->nprops;
461 elem->props = (PlyProperty **)
462 realloc (elem->props, sizeof (PlyProperty *) * newsize);
463 elem->store_prop = (char *)
464 realloc (elem->store_prop, sizeof (char) * newsize);
465 }
466
467 /* copy the other properties */
468
469 for (i = 0; i < other->nprops; i++) {
470 prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
471 copy_property (prop, other->props[i]);
472 elem->props[elem->nprops] = prop;
473 elem->store_prop[elem->nprops] = OTHER_PROP;
474 elem->nprops++;
475 }
476
477 /* save other info about other properties */
478 elem->other_size = other->size;
479 elem->other_offset = offset;
480 }
481
482
483 /******************************************************************************
484 State how many of a given element will be written.
485
486 Entry:
487 plyfile - file identifier
488 elem_name - name of element that information is being specified about
489 nelems - number of elements of this type to be written
490 ******************************************************************************/
491
ply_element_count(PlyFile * plyfile,const char * elem_name,int nelems)492 void ply_element_count(
493 PlyFile *plyfile,
494 const char *elem_name,
495 int nelems
496 )
497 {
498 PlyElement *elem;
499
500 /* look for appropriate element */
501 elem = find_element (plyfile, elem_name);
502 if (elem == NULL) {
503 char error[100];
504 sprintf (error, "ply_element_count: can't find element '%s'\n",elem_name);
505 throw ply::MeshException( error );
506 }
507
508 elem->num = nelems;
509 }
510
511
512 /******************************************************************************
513 Signal that we've described everything a PLY file's header and that the
514 header should be written to the file.
515
516 Entry:
517 plyfile - file identifier
518 ******************************************************************************/
519
ply_header_complete(PlyFile * plyfile)520 void ply_header_complete(PlyFile *plyfile)
521 {
522 int i,j;
523 FILE *fp = plyfile->fp;
524 PlyElement *elem;
525 PlyProperty *prop;
526
527 fprintf (fp, "ply\n");
528
529 switch (plyfile->file_type) {
530 case PLY_ASCII:
531 fprintf (fp, "format ascii 1.0\n");
532 break;
533 case PLY_BINARY_BE:
534 fprintf (fp, "format binary_big_endian 1.0\n");
535 break;
536 case PLY_BINARY_LE:
537 fprintf (fp, "format binary_little_endian 1.0\n");
538 break;
539 default:
540 char error[100];
541 sprintf (error, "ply_header_complete: bad file type = %d\n",
542 plyfile->file_type);
543 throw ply::MeshException( error );
544 }
545
546 /* write out the comments */
547
548 for (i = 0; i < plyfile->num_comments; i++)
549 fprintf (fp, "comment %s\n", plyfile->comments[i]);
550
551 /* write out object information */
552
553 for (i = 0; i < plyfile->num_obj_info; i++)
554 fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]);
555
556 /* write out information about each element */
557
558 for (i = 0; i < plyfile->nelems; i++) {
559
560 elem = plyfile->elems[i];
561 fprintf (fp, "element %s %d\n", elem->name, elem->num);
562
563 /* write out each property */
564 for (j = 0; j < elem->nprops; j++) {
565 prop = elem->props[j];
566 if (prop->is_list) {
567 fprintf (fp, "property list ");
568 write_scalar_type (fp, prop->count_external);
569 fprintf (fp, " ");
570 write_scalar_type (fp, prop->external_type);
571 fprintf (fp, " %s\n", prop->name);
572 }
573 else {
574 fprintf (fp, "property ");
575 write_scalar_type (fp, prop->external_type);
576 fprintf (fp, " %s\n", prop->name);
577 }
578 }
579 }
580
581 fprintf (fp, "end_header\n");
582 }
583
584
585 /******************************************************************************
586 Specify which elements are going to be written. This should be called
587 before a call to the routine ply_put_element().
588
589 Entry:
590 plyfile - file identifier
591 elem_name - name of element we're talking about
592 ******************************************************************************/
593
ply_put_element_setup(PlyFile * plyfile,const char * elem_name)594 void ply_put_element_setup(PlyFile *plyfile, const char *elem_name)
595 {
596 PlyElement *elem;
597
598 elem = find_element (plyfile, elem_name);
599 if (elem == NULL) {
600 char error[100];
601 sprintf (error, "ply_elements_setup: can't find element '%s'\n", elem_name);
602 throw ply::MeshException( error );
603 }
604
605 plyfile->which_elem = elem;
606 }
607
608
609 /******************************************************************************
610 Write an element to the file. This routine assumes that we're
611 writing the type of element specified in the last call to the routine
612 ply_put_element_setup().
613
614 Entry:
615 plyfile - file identifier
616 elem_ptr - pointer to the element
617 ******************************************************************************/
618
ply_put_element(PlyFile * plyfile,void * elem_ptr)619 void ply_put_element(PlyFile *plyfile, void *elem_ptr)
620 {
621 int j, k;
622 FILE *fp = plyfile->fp;
623 PlyElement *elem;
624 PlyProperty *prop;
625 char *elem_data,*item;
626 char **item_ptr;
627 int list_count;
628 int int_val;
629 unsigned int uint_val;
630 double double_val;
631 char **other_ptr;
632
633 elem = plyfile->which_elem;
634 elem_data = (char *)elem_ptr;
635 other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset);
636
637 /* write out either to an ascii or binary file */
638
639 if (plyfile->file_type == PLY_ASCII) {
640
641 /* write an ascii file */
642
643 /* write out each property of the element */
644 for (j = 0; j < elem->nprops; j++) {
645 prop = elem->props[j];
646 if (elem->store_prop[j] == OTHER_PROP)
647 elem_data = *other_ptr;
648 else
649 elem_data = (char *)elem_ptr;
650 if (prop->is_list) {
651 item = elem_data + prop->count_offset;
652 get_stored_item ((void *) item, prop->count_internal,
653 &int_val, &uint_val, &double_val);
654 write_ascii_item (fp, int_val, uint_val, double_val,
655 prop->count_external);
656 list_count = uint_val;
657 item_ptr = (char **) (elem_data + prop->offset);
658 item = item_ptr[0];
659 int item_size = ply_type_size[prop->internal_type];
660 for (k = 0; k < list_count; k++) {
661 get_stored_item ((void *) item, prop->internal_type,
662 &int_val, &uint_val, &double_val);
663 write_ascii_item (fp, int_val, uint_val, double_val,
664 prop->external_type);
665 item += item_size;
666 }
667 }
668 else {
669 item = elem_data + prop->offset;
670 get_stored_item ((void *) item, prop->internal_type,
671 &int_val, &uint_val, &double_val);
672 write_ascii_item (fp, int_val, uint_val, double_val,
673 prop->external_type);
674 }
675 }
676
677 fprintf (fp, "\n");
678 }
679 else {
680
681 /* write a binary file */
682
683 /* write out each property of the element */
684 for (j = 0; j < elem->nprops; j++) {
685 prop = elem->props[j];
686 if (elem->store_prop[j] == OTHER_PROP)
687 elem_data = *other_ptr;
688 else
689 elem_data = (char *)elem_ptr;
690 if (prop->is_list) {
691 item = elem_data + prop->count_offset;
692 int item_size = ply_type_size[prop->count_internal];
693 get_stored_item ((void *) item, prop->count_internal,
694 &int_val, &uint_val, &double_val);
695 write_binary_item (plyfile, int_val, uint_val, double_val,
696 prop->count_external);
697 list_count = uint_val;
698 item_ptr = (char **) (elem_data + prop->offset);
699 item = item_ptr[0];
700 item_size = ply_type_size[prop->internal_type];
701 for (k = 0; k < list_count; k++) {
702 get_stored_item ((void *) item, prop->internal_type,
703 &int_val, &uint_val, &double_val);
704 write_binary_item (plyfile, int_val, uint_val, double_val,
705 prop->external_type);
706 item += item_size;
707 }
708 }
709 else {
710 item = elem_data + prop->offset;
711 get_stored_item ((void *) item, prop->internal_type,
712 &int_val, &uint_val, &double_val);
713 write_binary_item (plyfile, int_val, uint_val, double_val,
714 prop->external_type);
715 }
716 }
717
718 }
719 }
720
721
722 /******************************************************************************
723 Specify a comment that will be written in the header.
724
725 Entry:
726 plyfile - file identifier
727 comment - the comment to be written
728 ******************************************************************************/
729
ply_put_comment(PlyFile * plyfile,const char * comment)730 void ply_put_comment(PlyFile *plyfile, const char *comment)
731 {
732 /* (re)allocate space for new comment */
733 if (plyfile->num_comments == 0)
734 {
735 plyfile->comments = (char **) myalloc (sizeof (char *));
736 }
737 else
738 {
739 plyfile->comments = (char **) realloc (plyfile->comments,
740 sizeof (char *) * (plyfile->num_comments + 1));
741 }
742
743 /* add comment to list */
744 plyfile->comments[plyfile->num_comments] = strdup (comment);
745 plyfile->num_comments++;
746 }
747
748
749 /******************************************************************************
750 Specify a piece of object information (arbitrary text) that will be written
751 in the header.
752
753 Entry:
754 plyfile - file identifier
755 obj_info - the text information to be written
756 ******************************************************************************/
757
ply_put_obj_info(PlyFile * plyfile,const char * obj_info)758 void ply_put_obj_info(PlyFile *plyfile, const char *obj_info)
759 {
760 /* (re)allocate space for new info */
761 if (plyfile->num_obj_info == 0)
762 {
763 plyfile->obj_info = (char **) myalloc (sizeof (char *));
764 }
765 else
766 {
767 plyfile->obj_info = (char **) realloc (plyfile->obj_info,
768 sizeof (char *) * (plyfile->num_obj_info + 1));
769 }
770
771 /* add info to list */
772 plyfile->obj_info[plyfile->num_obj_info] = strdup (obj_info);
773 plyfile->num_obj_info++;
774 }
775
776
777
778
779
780
781
782 /*************/
783 /* Reading */
784 /*************/
785
786
787
788 /******************************************************************************
789 Given a file pointer, get ready to read PLY data from the file.
790
791 Entry:
792 fp - the given file pointer
793
794 Exit:
795 nelems - number of elements in object
796 elem_names - list of element names
797 returns a pointer to a PlyFile, used to refer to this file, or NULL if error
798 ******************************************************************************/
799
ply_read(FILE * fp,int * nelems,char *** elem_names)800 PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names)
801 {
802 int i,j;
803 PlyFile *plyfile;
804 int nwords;
805 char **words;
806 char **elist;
807 PlyElement *elem;
808 char *orig_line;
809
810 /* check for NULL file pointer */
811 if (fp == NULL)
812 return (NULL);
813
814 /* create record for this object */
815
816 plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
817 if (!plyfile) return (NULL);
818
819 plyfile->nelems = 0;
820 plyfile->comments = NULL;
821 plyfile->num_comments = 0;
822 plyfile->obj_info = NULL;
823 plyfile->num_obj_info = 0;
824 plyfile->fp = fp;
825 plyfile->other_elems = NULL;
826
827 /* read and parse the file's header */
828
829 words = get_words (plyfile->fp, &nwords, &orig_line);
830 if (!words || !equal_strings (words[0], "ply"))
831 {
832 if (words) free( words);
833 free( plyfile );
834 return (NULL);
835 }
836
837 while (words)
838 {
839
840 /* parse words */
841
842 if (equal_strings (words[0], "format"))
843 {
844 if (nwords != 3)
845 {
846 free( words );
847 free( plyfile );
848 return (NULL);
849 }
850 if (equal_strings (words[1], "ascii"))
851 plyfile->file_type = PLY_ASCII;
852 else if (equal_strings (words[1], "binary_big_endian"))
853 plyfile->file_type = PLY_BINARY_BE;
854 else if (equal_strings (words[1], "binary_little_endian"))
855 plyfile->file_type = PLY_BINARY_LE;
856 else
857 {
858 free( words );
859 free( plyfile );
860 return (NULL);
861 }
862 plyfile->version = osg::asciiToDouble (words[2]);
863 }
864 else if (equal_strings (words[0], "element"))
865 add_element (plyfile, words, nwords);
866 else if (equal_strings (words[0], "property"))
867 add_property (plyfile, words, nwords);
868 else if (equal_strings (words[0], "comment"))
869 add_comment (plyfile, orig_line);
870 else if (equal_strings (words[0], "obj_info"))
871 add_obj_info (plyfile, orig_line);
872 else if (equal_strings (words[0], "end_header"))
873 {
874 free (words);
875 break;
876 }
877
878 /* free up words space */
879 free (words);
880
881 words = get_words (plyfile->fp, &nwords, &orig_line);
882 }
883
884
885 /* create tags for each property of each element, to be used */
886 /* later to say whether or not to store each property for the user */
887
888 for (i = 0; i < plyfile->nelems; i++) {
889 elem = plyfile->elems[i];
890 elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops);
891 for (j = 0; j < elem->nprops; j++)
892 elem->store_prop[j] = DONT_STORE_PROP;
893 elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */
894 }
895
896 /* set return values about the elements */
897
898 elist = (char **) myalloc (sizeof (char *) * plyfile->nelems);
899 for (i = 0; i < plyfile->nelems; i++)
900 elist[i] = strdup (plyfile->elems[i]->name);
901
902 *elem_names = elist;
903 *nelems = plyfile->nelems;
904
905 /* return a pointer to the file's information */
906
907 return (plyfile);
908 }
909
910
911 /******************************************************************************
912 Open a polygon file for reading.
913
914 Entry:
915 filename - name of file to read from
916
917 Exit:
918 nelems - number of elements in object
919 elem_names - list of element names
920 file_type - file type, either ascii or binary
921 version - version number of PLY file
922 returns a file identifier, used to refer to this file, or NULL if error
923 ******************************************************************************/
924
ply_open_for_reading(char * filename,int * nelems,char *** elem_names,int * file_type,float * version)925 PlyFile *ply_open_for_reading(
926 char *filename,
927 int *nelems,
928 char ***elem_names,
929 int *file_type,
930 float *version
931 )
932 {
933 FILE *fp;
934 PlyFile *plyfile;
935
936 /* open the file for reading */
937 fp = osgDB::fopen (filename, "rb");
938 if (fp == NULL)
939 return (NULL);
940
941 /* create the PlyFile data structure */
942
943 plyfile = ply_read (fp, nelems, elem_names);
944
945 if(!plyfile)
946 {
947 std::cout<<"Ply File Error : Could not read file " << filename <<std::endl;
948 return NULL;
949 }
950
951 /* determine the file type and version */
952
953 *file_type = plyfile->file_type;
954 *version = plyfile->version;
955
956 /* return a pointer to the file's information */
957
958 return (plyfile);
959 }
960
961
962 /******************************************************************************
963 Get information about a particular element.
964
965 Entry:
966 plyfile - file identifier
967 elem_name - name of element to get information about
968
969 Exit:
970 nelems - number of elements of this type in the file
971 nprops - number of properties
972 returns a list of properties, or NULL if the file doesn't contain that elem
973 ******************************************************************************/
974
ply_get_element_description(PlyFile * plyfile,char * elem_name,int * nelems,int * nprops)975 PlyProperty **ply_get_element_description(
976 PlyFile *plyfile,
977 char *elem_name,
978 int *nelems,
979 int *nprops
980 )
981 {
982 int i;
983 PlyElement *elem;
984 PlyProperty *prop;
985 PlyProperty **prop_list;
986
987 /* find information about the element */
988 elem = find_element (plyfile, elem_name);
989 if (elem == NULL)
990 return (NULL);
991
992 *nelems = elem->num;
993 *nprops = elem->nprops;
994
995 /* make a copy of the element's property list */
996 prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops);
997 for (i = 0; i < elem->nprops; i++) {
998 prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
999 copy_property (prop, elem->props[i]);
1000 prop_list[i] = prop;
1001 }
1002
1003 /* return this duplicate property list */
1004 return (prop_list);
1005 }
1006
1007
1008 /******************************************************************************
1009 Specify which properties of an element are to be returned. This should be
1010 called before a call to the routine ply_get_element().
1011
1012 Entry:
1013 plyfile - file identifier
1014 elem_name - which element we're talking about
1015 nprops - number of properties
1016 prop_list - list of properties
1017 ******************************************************************************/
1018
ply_get_element_setup(PlyFile * plyfile,char * elem_name,int nprops,PlyProperty * prop_list)1019 void ply_get_element_setup( PlyFile *plyfile, char *elem_name, int nprops,
1020 PlyProperty *prop_list )
1021 {
1022 int i;
1023 PlyElement *elem;
1024 PlyProperty *prop;
1025 int index;
1026
1027 /* find information about the element */
1028 elem = find_element (plyfile, elem_name);
1029 if (!elem)
1030 {
1031 fprintf ( stderr, "Warning: Can't find in element '%s'\n", elem_name );
1032 return;
1033 }
1034
1035
1036 plyfile->which_elem = elem;
1037
1038 /* deposit the property information into the element's description */
1039 for (i = 0; i < nprops; i++)
1040 {
1041 /* look for actual property */
1042 prop = find_property (elem, prop_list[i].name, &index);
1043 if (prop == NULL)
1044 {
1045 fprintf ( stderr,
1046 "Warning: Can't find property '%s' in element '%s'\n",
1047 prop_list[i].name, elem_name );
1048 continue;
1049 }
1050
1051 /* store its description */
1052 prop->internal_type = prop_list[i].internal_type;
1053 prop->offset = prop_list[i].offset;
1054 prop->count_internal = prop_list[i].count_internal;
1055 prop->count_offset = prop_list[i].count_offset;
1056
1057 /* specify that the user wants this property */
1058 elem->store_prop[index] = STORE_PROP;
1059 }
1060 }
1061
ply_set_property(PlyProperty * prop,PlyProperty * prop_ptr,PlyElement * elem,const int & index)1062 void ply_set_property(
1063 PlyProperty *prop,
1064 PlyProperty *prop_ptr,
1065 PlyElement *elem,
1066 const int &index
1067 )
1068 {
1069 prop_ptr->internal_type = prop->internal_type;
1070 prop_ptr->offset = prop->offset;
1071 prop_ptr->count_internal = prop->count_internal;
1072 prop_ptr->count_offset = prop->count_offset;
1073
1074 /* specify that the user wants this property */
1075 elem->store_prop[index] = STORE_PROP;
1076 }
1077
1078 // Tokenize a property using the given delimiter
tokenizeProperties(const char * pnames,std::vector<std::string> & tokens,const std::string & delimiter)1079 void tokenizeProperties(const char* pnames, std::vector<std::string> &tokens, const std::string &delimiter)
1080 {
1081 std::string propNames(pnames);
1082 std::string::size_type lastPos = propNames.find_first_not_of(delimiter, 0);
1083 std::string::size_type pos = propNames.find_first_of(delimiter, lastPos);
1084
1085 while (std::string::npos != pos || std::string::npos != lastPos) {
1086 tokens.push_back(propNames.substr(lastPos, pos - lastPos));
1087 lastPos = propNames.find_first_not_of(delimiter, pos);
1088 pos = propNames.find_first_of(delimiter, lastPos);
1089 }
1090 }
1091
1092 /******************************************************************************
1093 Specify a property of an element that is to be returned. This should be
1094 called (usually multiple times) before a call to the routine ply_get_element().
1095 This routine should be used in preference to the less flexible old routine
1096 called ply_get_element_setup().
1097
1098 Entry:
1099 plyfile - file identifier
1100 elem_name - which element we're talking about
1101 prop - property to add to those that will be returned
1102 ******************************************************************************/
1103
ply_get_property(PlyFile * plyfile,const char * elem_name,PlyProperty * prop)1104 void ply_get_property(
1105 PlyFile *plyfile,
1106 const char *elem_name,
1107 PlyProperty *prop
1108 )
1109 {
1110 PlyElement *elem;
1111 PlyProperty *prop_ptr = 0;
1112 int index;
1113
1114 /* find information about the element */
1115 elem = find_element (plyfile, elem_name);
1116 plyfile->which_elem = elem;
1117
1118 if (elem)
1119 {
1120
1121 /* deposit the property information into the element's description */
1122 /* Properties may have several names, separated by | with no spaces */
1123 std::vector<std::string> tokens;
1124 tokenizeProperties(prop->name, tokens, "|");
1125
1126 for(std::vector<std::string>::iterator it_property = tokens.begin();
1127 !prop_ptr && it_property != tokens.end();
1128 ++it_property)
1129 {
1130 prop_ptr = find_property(elem, it_property->c_str(), &index);
1131 }
1132 }
1133
1134 if(prop_ptr)
1135 {
1136 ply_set_property(prop, prop_ptr, elem, index);
1137 }
1138 else
1139 {
1140 fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n",
1141 prop->name, elem_name);
1142 return;
1143 }
1144 }
1145
1146
1147 /******************************************************************************
1148 Read one element from the file. This routine assumes that we're reading
1149 the type of element specified in the last call to the routine
1150 ply_get_element_setup().
1151
1152 Entry:
1153 plyfile - file identifier
1154 elem_ptr - pointer to location where the element information should be put
1155 ******************************************************************************/
1156
ply_get_element(PlyFile * plyfile,void * elem_ptr)1157 void ply_get_element(PlyFile *plyfile, void *elem_ptr)
1158 {
1159 if (plyfile->file_type == PLY_ASCII)
1160 ascii_get_element (plyfile, (char *) elem_ptr);
1161 else
1162 binary_get_element (plyfile, (char *) elem_ptr);
1163 }
1164
1165
1166 /******************************************************************************
1167 Extract the comments from the header information of a PLY file.
1168
1169 Entry:
1170 plyfile - file identifier
1171
1172 Exit:
1173 num_comments - number of comments returned
1174 returns a pointer to a list of comments
1175 ******************************************************************************/
1176
ply_get_comments(PlyFile * plyfile,int * num_comments)1177 char **ply_get_comments(PlyFile *plyfile, int *num_comments)
1178 {
1179 *num_comments = plyfile->num_comments;
1180 return (plyfile->comments);
1181 }
1182
1183
1184 /******************************************************************************
1185 Extract the object information (arbitrary text) from the header information
1186 of a PLY file.
1187
1188 Entry:
1189 plyfile - file identifier
1190
1191 Exit:
1192 num_obj_info - number of lines of text information returned
1193 returns a pointer to a list of object info lines
1194 ******************************************************************************/
1195
ply_get_obj_info(PlyFile * plyfile,int * num_obj_info)1196 char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info)
1197 {
1198 *num_obj_info = plyfile->num_obj_info;
1199 return (plyfile->obj_info);
1200 }
1201
1202
1203 /******************************************************************************
1204 Make ready for "other" properties of an element-- those properties that
1205 the user has not explicitly asked for, but that are to be stashed away
1206 in a special structure to be carried along with the element's other
1207 information.
1208
1209 Entry:
1210 plyfile - file identifier
1211 elem - element for which we want to save away other properties
1212 ******************************************************************************/
1213
setup_other_props(PlyFile *,PlyElement * elem)1214 void setup_other_props(PlyFile *, PlyElement *elem)
1215 {
1216 int i;
1217 PlyProperty *prop;
1218 int size = 0;
1219 int type_size;
1220
1221 /* Examine each property in decreasing order of size. */
1222 /* We do this so that all data types will be aligned by */
1223 /* word, half-word, or whatever within the structure. */
1224
1225 for (type_size = 8; type_size > 0; type_size /= 2) {
1226
1227 /* add up the space taken by each property, and save this information */
1228 /* away in the property descriptor */
1229
1230 for (i = 0; i < elem->nprops; i++) {
1231
1232 /* don't bother with properties we've been asked to store explicitly */
1233 if (elem->store_prop[i])
1234 continue;
1235
1236 prop = elem->props[i];
1237
1238 /* internal types will be same as external */
1239 prop->internal_type = prop->external_type;
1240 prop->count_internal = prop->count_external;
1241
1242 /* check list case */
1243 if (prop->is_list) {
1244
1245 /* pointer to list */
1246 if (type_size == sizeof (void *)) {
1247 prop->offset = size;
1248 size += sizeof (void *); /* always use size of a pointer here */
1249 }
1250
1251 /* count of number of list elements */
1252 if (type_size == ply_type_size[prop->count_external]) {
1253 prop->count_offset = size;
1254 size += ply_type_size[prop->count_external];
1255 }
1256 }
1257 /* not list */
1258 else if (type_size == ply_type_size[prop->external_type]) {
1259 prop->offset = size;
1260 size += ply_type_size[prop->external_type];
1261 }
1262 }
1263
1264 }
1265
1266 /* save the size for the other_props structure */
1267 elem->other_size = size;
1268 }
1269
1270
1271 /******************************************************************************
1272 Specify that we want the "other" properties of an element to be tucked
1273 away within the user's structure. The user needn't be concerned for how
1274 these properties are stored.
1275
1276 Entry:
1277 plyfile - file identifier
1278 elem_name - name of element that we want to store other_props in
1279 offset - offset to where other_props will be stored inside user's structure
1280
1281 Exit:
1282 returns pointer to structure containing description of other_props
1283 ******************************************************************************/
1284
ply_get_other_properties(PlyFile * plyfile,char * elem_name,int offset)1285 PlyOtherProp *ply_get_other_properties(
1286 PlyFile *plyfile,
1287 char *elem_name,
1288 int offset
1289 )
1290 {
1291 int i;
1292 PlyElement *elem;
1293 PlyOtherProp *other;
1294 PlyProperty *prop;
1295 int nprops;
1296
1297 /* find information about the element */
1298 elem = find_element (plyfile, elem_name);
1299 if (elem == NULL) {
1300 fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n",
1301 elem_name);
1302 return (NULL);
1303 }
1304
1305 /* remember that this is the "current" element */
1306 plyfile->which_elem = elem;
1307
1308 /* save the offset to where to store the other_props */
1309 elem->other_offset = offset;
1310
1311 /* place the appropriate pointers, etc. in the element's property list */
1312 setup_other_props (plyfile, elem);
1313
1314 /* create structure for describing other_props */
1315 other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp));
1316 other->name = strdup (elem_name);
1317 #if 0
1318 if (elem->other_offset == NO_OTHER_PROPS) {
1319 other->size = 0;
1320 other->props = NULL;
1321 other->nprops = 0;
1322 return (other);
1323 }
1324 #endif
1325 other->size = elem->other_size;
1326 other->props = (PlyProperty **) myalloc (sizeof(PlyProperty*) * elem->nprops);
1327
1328 /* save descriptions of each "other" property */
1329 nprops = 0;
1330 for (i = 0; i < elem->nprops; i++) {
1331 if (elem->store_prop[i])
1332 continue;
1333 prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
1334 copy_property (prop, elem->props[i]);
1335 other->props[nprops] = prop;
1336 nprops++;
1337 }
1338 other->nprops = nprops;
1339
1340 #if 1
1341 /* set other_offset pointer appropriately if there are NO other properties */
1342 if (other->nprops == 0) {
1343 elem->other_offset = NO_OTHER_PROPS;
1344 }
1345 #endif
1346
1347 /* return structure */
1348 return (other);
1349 }
1350
1351
1352
1353
1354 /*************************/
1355 /* Other Element Stuff */
1356 /*************************/
1357
1358
1359
1360
1361 /******************************************************************************
1362 Grab all the data for an element that a user does not want to explicitly
1363 read in.
1364
1365 Entry:
1366 plyfile - pointer to file
1367 elem_name - name of element whose data is to be read in
1368 elem_count - number of instances of this element stored in the file
1369
1370 Exit:
1371 returns pointer to ALL the "other" element data for this PLY file
1372 ******************************************************************************/
1373
ply_get_other_element(PlyFile * plyfile,char * elem_name,int elem_count)1374 PlyOtherElems *ply_get_other_element (
1375 PlyFile *plyfile,
1376 char *elem_name,
1377 int elem_count
1378 )
1379 {
1380 int i;
1381 PlyElement *elem;
1382 PlyOtherElems *other_elems;
1383 OtherElem *other;
1384
1385 /* look for appropriate element */
1386 elem = find_element (plyfile, elem_name);
1387 if (elem == NULL) {
1388 char error[100];
1389 sprintf (error, "ply_get_other_element: can't find element '%s'\n", elem_name);
1390 throw ply::MeshException( error );
1391 }
1392
1393 /* create room for the new "other" element, initializing the */
1394 /* other data structure if necessary */
1395
1396 if (plyfile->other_elems == NULL) {
1397 plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems));
1398 other_elems = plyfile->other_elems;
1399 other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem));
1400 other = &(other_elems->other_list[0]);
1401 other_elems->num_elems = 1;
1402 }
1403 else {
1404 other_elems = plyfile->other_elems;
1405 other_elems->other_list = (OtherElem *) realloc (other_elems->other_list,
1406 sizeof (OtherElem) * other_elems->num_elems + 1);
1407 other = &(other_elems->other_list[other_elems->num_elems]);
1408 other_elems->num_elems++;
1409 }
1410
1411 /* count of element instances in file */
1412 other->elem_count = elem_count;
1413
1414 /* save name of element */
1415 other->elem_name = strdup (elem_name);
1416
1417 /* create a list to hold all the current elements */
1418 other->other_data = (OtherData **)
1419 malloc (sizeof (OtherData *) * other->elem_count);
1420
1421 /* set up for getting elements */
1422 other->other_props = ply_get_other_properties (plyfile, elem_name,
1423 offsetof(OtherData,other_props));
1424
1425 /* grab all these elements */
1426 for (i = 0; i < other->elem_count; i++) {
1427 /* grab and element from the file */
1428 other->other_data[i] = (OtherData *) malloc (sizeof (OtherData));
1429 ply_get_element (plyfile, (void *) other->other_data[i]);
1430 }
1431
1432 /* return pointer to the other elements data */
1433 return (other_elems);
1434 }
1435
1436
1437 /******************************************************************************
1438 Pass along a pointer to "other" elements that we want to save in a given
1439 PLY file. These other elements were presumably read from another PLY file.
1440
1441 Entry:
1442 plyfile - file pointer in which to store this other element info
1443 other_elems - info about other elements that we want to store
1444 ******************************************************************************/
1445
ply_describe_other_elements(PlyFile * plyfile,PlyOtherElems * other_elems)1446 void ply_describe_other_elements (
1447 PlyFile *plyfile,
1448 PlyOtherElems *other_elems
1449 )
1450 {
1451 int i;
1452 OtherElem *other;
1453
1454 /* ignore this call if there is no other element */
1455 if (other_elems == NULL)
1456 return;
1457
1458 /* save pointer to this information */
1459 plyfile->other_elems = other_elems;
1460
1461 /* describe the other properties of this element */
1462
1463 for (i = 0; i < other_elems->num_elems; i++) {
1464 other = &(other_elems->other_list[i]);
1465 ply_element_count (plyfile, other->elem_name, other->elem_count);
1466 ply_describe_other_properties (plyfile, other->other_props,
1467 offsetof(OtherData,other_props));
1468 }
1469 }
1470
1471
1472 /******************************************************************************
1473 Write out the "other" elements specified for this PLY file.
1474
1475 Entry:
1476 plyfile - pointer to PLY file to write out other elements for
1477 ******************************************************************************/
1478
ply_put_other_elements(PlyFile * plyfile)1479 void ply_put_other_elements (PlyFile *plyfile)
1480 {
1481 int i,j;
1482 OtherElem *other;
1483
1484 /* make sure we have other elements to write */
1485 if (plyfile->other_elems == NULL)
1486 return;
1487
1488 /* write out the data for each "other" element */
1489
1490 for (i = 0; i < plyfile->other_elems->num_elems; i++) {
1491
1492 other = &(plyfile->other_elems->other_list[i]);
1493 ply_put_element_setup (plyfile, other->elem_name);
1494
1495 /* write out each instance of the current element */
1496 for (j = 0; j < other->elem_count; j++)
1497 ply_put_element (plyfile, (void *) other->other_data[j]);
1498 }
1499 }
1500
1501
1502 /******************************************************************************
1503 Free up storage used by an "other" elements data structure.
1504
1505 Entry:
1506 other_elems - data structure to free up
1507 ******************************************************************************/
1508
ply_free_other_elements(PlyOtherElems *)1509 void ply_free_other_elements (PlyOtherElems *)
1510 {
1511
1512 }
1513
1514
1515
1516 /*******************/
1517 /* Miscellaneous */
1518 /*******************/
1519
1520
1521
1522 /******************************************************************************
1523 Close a PLY file.
1524
1525 Entry:
1526 plyfile - identifier of file to close
1527 ******************************************************************************/
1528
ply_close(PlyFile * plyfile)1529 void ply_close(PlyFile *plyfile)
1530 {
1531 // Changed by Will Schroeder. Old stuff leaked like a sieve.
1532
1533 /* free up memory associated with the PLY file */
1534 fclose (plyfile->fp);
1535
1536 int i, j;
1537 PlyElement *elem;
1538 for (i=0; i<plyfile->nelems; i++)
1539 {
1540 elem = plyfile->elems[i];
1541 if ( elem->name ) {free(elem->name);}
1542 for (j=0; j<elem->nprops; j++)
1543 {
1544 if ( elem->props[j]->name ) {free(const_cast<char *>(elem->props[j]->name));}
1545 free (elem->props[j]);
1546 }
1547 free (elem->props);
1548 free (elem->store_prop);
1549 free (elem);
1550 }
1551 free(plyfile->elems);
1552
1553 for (i=0; i<plyfile->num_comments; i++)
1554 {
1555 free (plyfile->comments[i]);
1556 }
1557 free (plyfile->comments);
1558
1559 for (i=0; i<plyfile->num_obj_info; i++)
1560 {
1561 free (plyfile->obj_info[i]);
1562 }
1563 free (plyfile->obj_info);
1564
1565 free (plyfile);
1566 }
1567
1568
1569 /******************************************************************************
1570 Get version number and file type of a PlyFile.
1571
1572 Entry:
1573 ply - pointer to PLY file
1574
1575 Exit:
1576 version - version of the file
1577 file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE
1578 ******************************************************************************/
1579
ply_get_info(PlyFile * ply,float * version,int * file_type)1580 void ply_get_info(PlyFile *ply, float *version, int *file_type)
1581 {
1582 if (ply == NULL)
1583 return;
1584
1585 *version = ply->version;
1586 *file_type = ply->file_type;
1587 }
1588
1589
1590 /******************************************************************************
1591 Compare two strings. Returns 1 if they are the same, 0 if not.
1592 ******************************************************************************/
1593
equal_strings(const char * s1,const char * s2)1594 int equal_strings(const char *s1, const char *s2)
1595 {
1596 while (*s1 && *s2)
1597 if (*s1++ != *s2++)
1598 return (0);
1599
1600 if (*s1 != *s2)
1601 return (0);
1602 else
1603 return (1);
1604 }
1605
1606
1607 /******************************************************************************
1608 Find an element from the element list of a given PLY object.
1609
1610 Entry:
1611 plyfile - file id for PLY file
1612 element - name of element we're looking for
1613
1614 Exit:
1615 returns the element, or NULL if not found
1616 ******************************************************************************/
1617
find_element(PlyFile * plyfile,const char * element)1618 PlyElement *find_element(PlyFile *plyfile, const char *element)
1619 {
1620 int i;
1621
1622 for (i = 0; i < plyfile->nelems; i++)
1623 if (equal_strings (element, plyfile->elems[i]->name))
1624 return (plyfile->elems[i]);
1625
1626 return (NULL);
1627 }
1628
1629
1630 /******************************************************************************
1631 Find a property in the list of properties of a given element.
1632
1633 Entry:
1634 elem - pointer to element in which we want to find the property
1635 prop_name - name of property to find
1636
1637 Exit:
1638 index - index to position in list
1639 returns a pointer to the property, or NULL if not found
1640 ******************************************************************************/
1641
find_property(PlyElement * elem,const char * prop_name,int * index)1642 PlyProperty *find_property(PlyElement *elem, const char *prop_name, int *index)
1643 {
1644 int i;
1645
1646 for( i = 0; i < elem->nprops; i++)
1647 if (equal_strings (prop_name, elem->props[i]->name))
1648 {
1649 *index = i;
1650 return (elem->props[i]);
1651 }
1652
1653 *index = -1;
1654 return (NULL);
1655 }
1656
1657
1658 /******************************************************************************
1659 Read an element from an ascii file.
1660
1661 Entry:
1662 plyfile - file identifier
1663 elem_ptr - pointer to element
1664 ******************************************************************************/
1665
ascii_get_element(PlyFile * plyfile,char * elem_ptr)1666 void ascii_get_element(PlyFile *plyfile, char *elem_ptr)
1667 {
1668 int j,k;
1669 PlyElement *elem;
1670 PlyProperty *prop;
1671 char **words;
1672 int nwords;
1673 int which_word;
1674 char *elem_data,*item=0;
1675 char *item_ptr;
1676 int item_size=0;
1677 int int_val;
1678 unsigned int uint_val;
1679 double double_val;
1680 int list_count;
1681 int store_it;
1682 char **store_array;
1683 char *orig_line;
1684 char *other_data=0;
1685 int other_flag;
1686
1687 /* the kind of element we're reading currently */
1688 elem = plyfile->which_elem;
1689
1690 /* do we need to setup for other_props? */
1691
1692 if (elem->other_offset != NO_OTHER_PROPS) {
1693 char **ptr;
1694 other_flag = 1;
1695 /* make room for other_props */
1696 other_data = (char *) myalloc (elem->other_size);
1697 /* store pointer in user's structure to the other_props */
1698 ptr = (char **) (elem_ptr + elem->other_offset);
1699 *ptr = other_data;
1700 }
1701 else
1702 other_flag = 0;
1703
1704 /* read in the element */
1705
1706 words = get_words (plyfile->fp, &nwords, &orig_line);
1707 if (words == NULL) {
1708 char error[100];
1709 sprintf (error, "ply_get_element: unexpected end of file\n");
1710 throw ply::MeshException( error );
1711 }
1712
1713 which_word = 0;
1714
1715 for (j = 0; j < elem->nprops; j++) {
1716
1717 prop = elem->props[j];
1718 store_it = (elem->store_prop[j] | other_flag);
1719
1720 /* store either in the user's structure or in other_props */
1721 if (elem->store_prop[j])
1722 elem_data = elem_ptr;
1723 else
1724 elem_data = other_data;
1725
1726 if (prop->is_list) { /* a list */
1727
1728 /* get and store the number of items in the list */
1729 get_ascii_item (words[which_word++], prop->count_external,
1730 &int_val, &uint_val, &double_val);
1731 if (store_it) {
1732 item = elem_data + prop->count_offset;
1733 store_item(item, prop->count_internal, int_val, uint_val, double_val);
1734 }
1735
1736 /* allocate space for an array of items and store a ptr to the array */
1737 list_count = int_val;
1738 item_size = ply_type_size[prop->internal_type];
1739 store_array = (char **) (elem_data + prop->offset);
1740
1741 if (list_count == 0) {
1742 if (store_it)
1743 *store_array = NULL;
1744 }
1745 else {
1746 if (store_it) {
1747 item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
1748 item = item_ptr;
1749 *store_array = item_ptr;
1750 }
1751
1752 /* read items and store them into the array */
1753 for (k = 0; k < list_count; k++) {
1754 get_ascii_item (words[which_word++], prop->external_type,
1755 &int_val, &uint_val, &double_val);
1756 if (store_it) {
1757 store_item (item, prop->internal_type,
1758 int_val, uint_val, double_val);
1759 item += item_size;
1760 }
1761 }
1762 }
1763
1764 }
1765 else { /* not a list */
1766 get_ascii_item (words[which_word++], prop->external_type,
1767 &int_val, &uint_val, &double_val);
1768 if (store_it) {
1769 item = elem_data + prop->offset;
1770 store_item (item, prop->internal_type, int_val, uint_val, double_val);
1771 }
1772 }
1773
1774 }
1775
1776 free (words);
1777 }
1778
1779
1780 /******************************************************************************
1781 Read an element from a binary file.
1782
1783 Entry:
1784 plyfile - file identifier
1785 elem_ptr - pointer to an element
1786 ******************************************************************************/
1787
binary_get_element(PlyFile * plyfile,char * elem_ptr)1788 void binary_get_element(PlyFile *plyfile, char *elem_ptr)
1789 {
1790 int j,k;
1791 PlyElement *elem;
1792 PlyProperty *prop;
1793 //FILE *fp = plyfile->fp;
1794 char *elem_data,*item=0;
1795 char *item_ptr;
1796 int item_size=0;
1797 int int_val;
1798 unsigned int uint_val;
1799 double double_val;
1800 int list_count;
1801 int store_it;
1802 char **store_array;
1803 char *other_data=0;
1804 int other_flag;
1805
1806 /* the kind of element we're reading currently */
1807 elem = plyfile->which_elem;
1808
1809 /* do we need to setup for other_props? */
1810
1811 if (elem->other_offset != NO_OTHER_PROPS) {
1812 char **ptr;
1813 other_flag = 1;
1814 /* make room for other_props */
1815 other_data = (char *) myalloc (elem->other_size);
1816 /* store pointer in user's structure to the other_props */
1817 ptr = (char **) (elem_ptr + elem->other_offset);
1818 *ptr = other_data;
1819 }
1820 else
1821 other_flag = 0;
1822
1823 /* read in a number of elements */
1824
1825 for (j = 0; j < elem->nprops; j++) {
1826
1827 prop = elem->props[j];
1828 store_it = (elem->store_prop[j] | other_flag);
1829
1830 /* store either in the user's structure or in other_props */
1831 if (elem->store_prop[j])
1832 elem_data = elem_ptr;
1833 else
1834 elem_data = other_data;
1835
1836 if (prop->is_list) { /* a list */
1837
1838 /* get and store the number of items in the list */
1839 get_binary_item (plyfile, prop->count_external,
1840 &int_val, &uint_val, &double_val);
1841 if (store_it) {
1842 item = elem_data + prop->count_offset;
1843 store_item(item, prop->count_internal, int_val, uint_val, double_val);
1844 }
1845
1846 /* allocate space for an array of items and store a ptr to the array */
1847 list_count = int_val;
1848 /* The "if" was added by Afra Zomorodian 8/22/95
1849 * so that zipper won't crash reading plies that have additional
1850 * properties.
1851 */
1852 if (store_it) {
1853 item_size = ply_type_size[prop->internal_type];
1854 }
1855 store_array = (char **) (elem_data + prop->offset);
1856 if (list_count == 0) {
1857 if (store_it)
1858 *store_array = NULL;
1859 }
1860 else {
1861 if (store_it) {
1862 item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
1863 item = item_ptr;
1864 *store_array = item_ptr;
1865 }
1866
1867 /* read items and store them into the array */
1868 for (k = 0; k < list_count; k++) {
1869 get_binary_item (plyfile, prop->external_type,
1870 &int_val, &uint_val, &double_val);
1871 if (store_it) {
1872 store_item (item, prop->internal_type,
1873 int_val, uint_val, double_val);
1874 item += item_size;
1875 }
1876 }
1877 }
1878
1879 }
1880 else { /* not a list */
1881 get_binary_item (plyfile, prop->external_type,
1882 &int_val, &uint_val, &double_val);
1883 if (store_it) {
1884 item = elem_data + prop->offset;
1885 store_item (item, prop->internal_type, int_val, uint_val, double_val);
1886 }
1887 }
1888
1889 }
1890 }
1891
1892
1893 /******************************************************************************
1894 Write to a file the word that represents a PLY data type.
1895
1896 Entry:
1897 fp - file pointer
1898 code - code for type
1899 ******************************************************************************/
1900
write_scalar_type(FILE * fp,int code)1901 void write_scalar_type (FILE *fp, int code)
1902 {
1903 /* make sure this is a valid code */
1904
1905 if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) {
1906 char error[100];
1907 sprintf (error, "write_scalar_type: bad data code = %d\n", code);
1908 throw ply::MeshException( error );
1909 }
1910
1911 /* write the code to a file */
1912
1913 fprintf (fp, "%s", type_names[code]);
1914 }
1915
1916
1917 /******************************************************************************
1918 Get a text line from a file and break it up into words.
1919
1920 IMPORTANT: The calling routine call "free" on the returned pointer once
1921 finished with it.
1922
1923 Entry:
1924 fp - file to read from
1925
1926 Exit:
1927 nwords - number of words returned
1928 orig_line - the original line of characters
1929 returns a list of words from the line, or NULL if end-of-file
1930 ******************************************************************************/
1931
get_words(FILE * fp,int * nwords,char ** orig_line)1932 char **get_words(FILE *fp, int *nwords, char **orig_line)
1933 {
1934 #define BIG_STRING 4096
1935 static char str[BIG_STRING];
1936 static char str_copy[BIG_STRING];
1937 char **words;
1938 int max_words = 10;
1939 int num_words = 0;
1940 char *ptr,*ptr2;
1941 char *result;
1942
1943 /* read in a line */
1944 result = fgets (str, BIG_STRING, fp);
1945 if (result == NULL) {
1946 *nwords = 0;
1947 *orig_line = NULL;
1948 return (NULL);
1949 }
1950
1951 words = (char **) myalloc (sizeof (char *) * max_words);
1952
1953 /* convert line-feed and tabs into spaces */
1954 /* (this guarantees that there will be a space before the */
1955 /* null character at the end of the string) */
1956
1957 str[BIG_STRING-2] = ' ';
1958 str[BIG_STRING-1] = '\0';
1959
1960 for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
1961 *ptr2 = *ptr;
1962 if (*ptr == '\t') {
1963 *ptr = ' ';
1964 *ptr2 = ' ';
1965 }
1966 else if (*ptr == '\n' || *ptr == '\r') {
1967 *ptr = ' ';
1968 *ptr2 = '\0';
1969 }
1970 }
1971
1972 /* find the words in the line */
1973
1974 ptr = str;
1975 while (*ptr != '\0') {
1976
1977 /* jump over leading spaces */
1978 while (*ptr == ' ')
1979 ptr++;
1980
1981 /* break if we reach the end */
1982 if (*ptr == '\0')
1983 break;
1984
1985 /* save pointer to beginning of word */
1986 if (num_words >= max_words) {
1987 max_words += 10;
1988 words = (char **) realloc (words, sizeof (char *) * max_words);
1989 }
1990 words[num_words++] = ptr;
1991
1992 /* jump over non-spaces */
1993 while (*ptr != ' ')
1994 ptr++;
1995
1996 /* place a null character here to mark the end of the word */
1997 *ptr++ = '\0';
1998 }
1999
2000 /* return the list of words */
2001 *nwords = num_words;
2002 *orig_line = str_copy;
2003 return (words);
2004 }
2005
2006
2007 /******************************************************************************
2008 Return the value of an item, given a pointer to it and its type.
2009
2010 Entry:
2011 item - pointer to item
2012 type - data type that "item" points to
2013
2014 Exit:
2015 returns a double-precision float that contains the value of the item
2016 ******************************************************************************/
2017
get_item_value(char * item,int type)2018 double get_item_value(char *item, int type)
2019 {
2020 unsigned char *puchar;
2021 char *pchar;
2022 short int *pshort;
2023 unsigned short int *pushort;
2024 int *pint;
2025 unsigned int *puint;
2026 float *pfloat;
2027 double *pdouble;
2028 int int_value;
2029 unsigned int uint_value;
2030 double double_value;
2031
2032 switch (type) {
2033 case PLY_CHAR:
2034 pchar = (char *) item;
2035 int_value = *pchar;
2036 return ((double) int_value);
2037 case PLY_UCHAR:
2038 case PLY_UINT8:
2039 puchar = (unsigned char *) item;
2040 int_value = *puchar;
2041 return ((double) int_value);
2042 case PLY_SHORT:
2043 pshort = (short int *) item;
2044 int_value = *pshort;
2045 return ((double) int_value);
2046 case PLY_USHORT:
2047 pushort = (unsigned short int *) item;
2048 int_value = *pushort;
2049 return ((double) int_value);
2050 case PLY_INT:
2051 case PLY_INT32:
2052 pint = (int *) item;
2053 int_value = *pint;
2054 return ((double) int_value);
2055 case PLY_UINT:
2056 puint = (unsigned int *) item;
2057 uint_value = *puint;
2058 return ((double) uint_value);
2059 case PLY_FLOAT:
2060 case PLY_FLOAT32:
2061 pfloat = (float *) item;
2062 double_value = *pfloat;
2063 return (double_value);
2064 case PLY_DOUBLE:
2065 pdouble = (double *) item;
2066 double_value = *pdouble;
2067 return (double_value);
2068 }
2069 fprintf (stderr, "get_item_value: bad type = %d\n", type);
2070 return 0;
2071 }
2072
2073
2074 /******************************************************************************
2075 Write out an item to a file as raw binary bytes.
2076
2077 Entry:
2078 fp - file to write to
2079 int_val - integer version of item
2080 uint_val - unsigned integer version of item
2081 double_val - double-precision float version of item
2082 type - data type to write out
2083 ******************************************************************************/
2084
write_binary_item(PlyFile * plyfile,int int_val,unsigned int uint_val,double double_val,int type)2085 void write_binary_item(PlyFile *plyfile,
2086 int int_val,
2087 unsigned int uint_val,
2088 double double_val,
2089 int type
2090 )
2091 {
2092 FILE *fp = plyfile->fp;
2093 unsigned char uchar_val;
2094 char char_val;
2095 unsigned short ushort_val;
2096 short short_val;
2097 float float_val;
2098
2099 switch (type) {
2100 case PLY_CHAR:
2101 char_val = int_val;
2102 fwrite (&char_val, 1, 1, fp);
2103 break;
2104 case PLY_SHORT:
2105 short_val = int_val;
2106 if( plyfile->file_type == PLY_BINARY_BE )
2107 swap2BE(&short_val);
2108 else
2109 swap2LE(&short_val);
2110 fwrite (&short_val, 2, 1, fp);
2111 break;
2112 case PLY_INT:
2113 case PLY_INT32:
2114 if( plyfile->file_type == PLY_BINARY_BE )
2115 {
2116 swap4BE(&int_val);
2117 }
2118 else
2119 {
2120 swap4LE(&int_val);
2121 }
2122 fwrite (&int_val, 4, 1, fp);
2123 break;
2124 case PLY_UCHAR:
2125 case PLY_UINT8:
2126 uchar_val = uint_val;
2127 fwrite (&uchar_val, 1, 1, fp);
2128 break;
2129 case PLY_USHORT:
2130 if( plyfile->file_type == PLY_BINARY_BE )
2131 {
2132 swap2BE(&ushort_val);
2133 }
2134 else
2135 {
2136 swap2LE(&ushort_val);
2137 }
2138 ushort_val = uint_val;
2139 fwrite (&ushort_val, 2, 1, fp);
2140 break;
2141 case PLY_UINT:
2142 if( plyfile->file_type == PLY_BINARY_BE )
2143 {
2144 swap4BE(&uint_val);
2145 }
2146 else
2147 {
2148 swap4LE(&uint_val);
2149 }
2150 fwrite (&uint_val, 4, 1, fp);
2151 break;
2152 case PLY_FLOAT:
2153 case PLY_FLOAT32:
2154 float_val = double_val;
2155 if( plyfile->file_type == PLY_BINARY_BE )
2156 {
2157 swap4BE(&float_val);
2158 }
2159 else
2160 {
2161 swap4LE(&float_val);
2162 }
2163 fwrite (&float_val, 4, 1, fp);
2164 break;
2165 case PLY_DOUBLE:
2166 if( plyfile->file_type == PLY_BINARY_BE )
2167 {
2168 swap8BE(&double_val);
2169 }
2170 else
2171 {
2172 swap8LE(&double_val);
2173 }
2174 fwrite (&double_val, 8, 1, fp);
2175 break;
2176 default:
2177 char error[100];
2178 sprintf (error, "write_binary_item: bad type = %d\n", type);
2179 throw ply::MeshException( error );
2180 }
2181 }
2182
2183
2184 /******************************************************************************
2185 Write out an item to a file as ascii characters.
2186
2187 Entry:
2188 fp - file to write to
2189 int_val - integer version of item
2190 uint_val - unsigned integer version of item
2191 double_val - double-precision float version of item
2192 type - data type to write out
2193 ******************************************************************************/
2194
write_ascii_item(FILE * fp,int int_val,unsigned int uint_val,double double_val,int type)2195 void write_ascii_item(
2196 FILE *fp,
2197 int int_val,
2198 unsigned int uint_val,
2199 double double_val,
2200 int type
2201 )
2202 {
2203 switch (type) {
2204 case PLY_CHAR:
2205 case PLY_SHORT:
2206 case PLY_INT:
2207 case PLY_INT32:
2208 fprintf (fp, "%d ", int_val);
2209 break;
2210 case PLY_UCHAR:
2211 case PLY_UINT8:
2212 case PLY_USHORT:
2213 case PLY_UINT:
2214 fprintf (fp, "%u ", uint_val);
2215 break;
2216 case PLY_FLOAT:
2217 case PLY_FLOAT32:
2218 case PLY_DOUBLE:
2219 fprintf (fp, "%g ", double_val);
2220 break;
2221 default:
2222 char error[100];
2223 sprintf (error, "write_ascii_item: bad type = %d\n", type);
2224 throw ply::MeshException( error );
2225 }
2226 }
2227
2228 /******************************************************************************
2229 Get the value of an item that is in memory, and place the result
2230 into an integer, an unsigned integer and a double.
2231
2232 Entry:
2233 ptr - pointer to the item
2234 type - data type supposedly in the item
2235
2236 Exit:
2237 int_val - integer value
2238 uint_val - unsigned integer value
2239 double_val - double-precision floating point value
2240 ******************************************************************************/
2241
get_stored_item(void * ptr,int type,int * int_val,unsigned int * uint_val,double * double_val)2242 void get_stored_item(
2243 void *ptr,
2244 int type,
2245 int *int_val,
2246 unsigned int *uint_val,
2247 double *double_val
2248 )
2249 {
2250 switch (type) {
2251 case PLY_CHAR:
2252 *int_val = *((char *) ptr);
2253 *uint_val = *int_val;
2254 *double_val = *int_val;
2255 break;
2256 case PLY_UCHAR:
2257 case PLY_UINT8:
2258 *uint_val = *((unsigned char *) ptr);
2259 *int_val = *uint_val;
2260 *double_val = *uint_val;
2261 break;
2262 case PLY_SHORT:
2263 *int_val = *((short int *) ptr);
2264 *uint_val = *int_val;
2265 *double_val = *int_val;
2266 break;
2267 case PLY_USHORT:
2268 *uint_val = *((unsigned short int *) ptr);
2269 *int_val = *uint_val;
2270 *double_val = *uint_val;
2271 break;
2272 case PLY_INT:
2273 case PLY_INT32:
2274 *int_val = *((int *) ptr);
2275 *uint_val = *int_val;
2276 *double_val = *int_val;
2277 break;
2278 case PLY_UINT:
2279 *uint_val = *((unsigned int *) ptr);
2280 *int_val = *uint_val;
2281 *double_val = *uint_val;
2282 break;
2283 case PLY_FLOAT:
2284 case PLY_FLOAT32:
2285 *double_val = *((float *) ptr);
2286 *int_val = (int) *double_val;
2287 *uint_val = (unsigned int) *double_val;
2288 break;
2289 case PLY_DOUBLE:
2290 *double_val = *((double *) ptr);
2291 *int_val = (int) *double_val;
2292 *uint_val = (unsigned int) *double_val;
2293 break;
2294 default:
2295 char error[100];
2296 sprintf (error, "get_stored_item: bad type = %d\n", type);
2297 throw ply::MeshException( error );
2298 }
2299 }
2300
2301
2302 /******************************************************************************
2303 Get the value of an item from a binary file, and place the result
2304 into an integer, an unsigned integer and a double.
2305
2306 Entry:
2307 fp - file to get item from
2308 type - data type supposedly in the word
2309
2310 Exit:
2311 int_val - integer value
2312 uint_val - unsigned integer value
2313 double_val - double-precision floating point value
2314 ******************************************************************************/
2315
get_binary_item(PlyFile * plyfile,int type,int * int_val,unsigned int * uint_val,double * double_val)2316 void get_binary_item(
2317 PlyFile *plyfile,
2318 int type,
2319 int *int_val,
2320 unsigned int *uint_val,
2321 double *double_val
2322 )
2323 {
2324 char c[8];
2325 void *ptr;
2326
2327 ptr = (void *) c;
2328 size_t result = 0;
2329
2330 switch (type) {
2331 case PLY_CHAR:
2332 result = fread (ptr, 1, 1, plyfile->fp);
2333 if(result < 1)
2334 {
2335 throw ply::MeshException( "Error in reading PLY file."
2336 "fread not succeeded." );
2337 }
2338 *int_val = *((char *) ptr);
2339 *uint_val = *int_val;
2340 *double_val = *int_val;
2341 break;
2342 case PLY_UCHAR:
2343 case PLY_UINT8:
2344 result = fread (ptr, 1, 1, plyfile->fp);
2345 if(result < 1)
2346 {
2347 throw ply::MeshException( "Error in reading PLY file."
2348 "fread not succeeded." );
2349 }
2350 *uint_val = *((unsigned char *) ptr);
2351 *int_val = *uint_val;
2352 *double_val = *uint_val;
2353 break;
2354 case PLY_SHORT:
2355 result = fread (ptr, 2, 1, plyfile->fp);
2356 if(result < 1 )
2357 {
2358 throw ply::MeshException( "Error in reading PLY file."
2359 "fread not succeeded." );
2360 }
2361 if( plyfile->file_type == PLY_BINARY_BE )
2362 {
2363 swap2BE(ptr);
2364 }
2365 else
2366 {
2367 swap2LE(ptr);
2368 }
2369 *int_val = *((short int *) ptr);
2370 *uint_val = *int_val;
2371 *double_val = *int_val;
2372 break;
2373 case PLY_USHORT:
2374 result = fread (ptr, 2, 1, plyfile->fp);
2375 if(result < 1)
2376 {
2377 throw ply::MeshException( "Error in reading PLY file."
2378 "fread not succeeded." );
2379 }
2380 if( plyfile->file_type == PLY_BINARY_BE )
2381 {
2382 swap2BE(ptr);
2383 }
2384 else
2385 {
2386 swap2LE(ptr);
2387 }
2388 *uint_val = *((unsigned short int *) ptr);
2389 *int_val = *uint_val;
2390 *double_val = *uint_val;
2391 break;
2392 case PLY_INT:
2393 case PLY_INT32:
2394 result = fread (ptr, 4, 1, plyfile->fp);
2395 if(result < 1)
2396 {
2397 throw ply::MeshException( "Error in reading PLY file."
2398 "fread not succeeded." );
2399 }
2400 if( plyfile->file_type == PLY_BINARY_BE )
2401 {
2402 swap4BE(ptr);
2403 }
2404 else
2405 {
2406 swap4LE(ptr);
2407 }
2408 *int_val = *((int *) ptr);
2409 *uint_val = *int_val;
2410 *double_val = *int_val;
2411 break;
2412 case PLY_UINT:
2413 result = fread (ptr, 4, 1, plyfile->fp);
2414 if(result < 1)
2415 {
2416 throw ply::MeshException( "Error in reading PLY file."
2417 "fread not succeeded." );
2418 }
2419 if( plyfile->file_type == PLY_BINARY_BE )
2420 {
2421 swap4BE(ptr);
2422 }
2423 else
2424 {
2425 swap4LE(ptr);
2426 }
2427 *uint_val = *((unsigned int *) ptr);
2428 *int_val = *uint_val;
2429 *double_val = *uint_val;
2430 break;
2431 case PLY_FLOAT:
2432 case PLY_FLOAT32:
2433 result = fread (ptr, 4, 1, plyfile->fp);
2434 if(result < 1)
2435 {
2436 throw ply::MeshException( "Error in reading PLY file."
2437 "fread not succeeded." );
2438 }
2439 if( plyfile->file_type == PLY_BINARY_BE )
2440 {
2441 swap4BE(ptr);
2442 }
2443 else
2444 {
2445 swap4LE(ptr);
2446 }
2447 *double_val = *((float *) ptr);
2448 *int_val = (int) *double_val;
2449 *uint_val = (unsigned int) *double_val;
2450 break;
2451 case PLY_DOUBLE:
2452 result = fread (ptr, 8, 1, plyfile->fp);
2453 if(result < 1)
2454 {
2455 throw ply::MeshException( "Error in reading PLY file."
2456 "fread not succeeded." );
2457 }
2458 if( plyfile->file_type == PLY_BINARY_BE )
2459 {
2460 swap8BE(ptr);
2461 }
2462 else
2463 {
2464 swap8LE(ptr);
2465 }
2466 *double_val = *((double *) ptr);
2467 *int_val = (int) *double_val;
2468 *uint_val = (unsigned int) *double_val;
2469 break;
2470 default:
2471 char error[100];
2472 sprintf (error, "get_binary_item: bad type = %d\n", type);
2473 throw ply::MeshException( error );
2474 }
2475 }
2476
2477
2478 /******************************************************************************
2479 Extract the value of an item from an ascii word, and place the result
2480 into an integer, an unsigned integer and a double.
2481
2482 Entry:
2483 word - word to extract value from
2484 type - data type supposedly in the word
2485
2486 Exit:
2487 int_val - integer value
2488 uint_val - unsigned integer value
2489 double_val - double-precision floating point value
2490 ******************************************************************************/
2491
get_ascii_item(char * word,int type,int * int_val,unsigned int * uint_val,double * double_val)2492 void get_ascii_item(
2493 char *word,
2494 int type,
2495 int *int_val,
2496 unsigned int *uint_val,
2497 double *double_val
2498 )
2499 {
2500 switch (type) {
2501 case PLY_CHAR:
2502 case PLY_UCHAR:
2503 case PLY_UINT8:
2504 case PLY_SHORT:
2505 case PLY_USHORT:
2506 case PLY_INT:
2507 case PLY_INT32:
2508 *int_val = atoi (word);
2509 *uint_val = *int_val;
2510 *double_val = *int_val;
2511 break;
2512
2513 case PLY_UINT:
2514 *uint_val = strtoul (word, (char **) NULL, 10);
2515 *int_val = *uint_val;
2516 *double_val = *uint_val;
2517 break;
2518
2519 case PLY_FLOAT:
2520 case PLY_FLOAT32:
2521 case PLY_DOUBLE:
2522 *double_val = osg::asciiToDouble(word);
2523 *int_val = (int) *double_val;
2524 *uint_val = (unsigned int) *double_val;
2525 break;
2526
2527 default:
2528 char error[100];
2529 sprintf (error, "get_ascii_item: bad type = %d\n", type);
2530 throw ply::MeshException( error );
2531 }
2532 }
2533
2534
2535 /******************************************************************************
2536 Store a value into a place being pointed to, guided by a data type.
2537
2538 Entry:
2539 item - place to store value
2540 type - data type
2541 int_val - integer version of value
2542 uint_val - unsigned integer version of value
2543 double_val - double version of value
2544
2545 Exit:
2546 item - pointer to stored value
2547 ******************************************************************************/
2548
store_item(char * item,int type,int int_val,unsigned int uint_val,double double_val)2549 void store_item (
2550 char *item,
2551 int type,
2552 int int_val,
2553 unsigned int uint_val,
2554 double double_val
2555 )
2556 {
2557 unsigned char *puchar;
2558 short int *pshort;
2559 unsigned short int *pushort;
2560 int *pint;
2561 unsigned int *puint;
2562 float *pfloat;
2563 double *pdouble;
2564
2565 switch (type) {
2566 case PLY_CHAR:
2567 *item = int_val;
2568 break;
2569 case PLY_UCHAR:
2570 case PLY_UINT8:
2571 puchar = (unsigned char *) item;
2572 *puchar = uint_val;
2573 break;
2574 case PLY_SHORT:
2575 pshort = (short *) item;
2576 *pshort = int_val;
2577 break;
2578 case PLY_USHORT:
2579 pushort = (unsigned short *) item;
2580 *pushort = uint_val;
2581 break;
2582 case PLY_INT:
2583 case PLY_INT32:
2584 pint = (int *) item;
2585 *pint = int_val;
2586 break;
2587 case PLY_UINT:
2588 puint = (unsigned int *) item;
2589 *puint = uint_val;
2590 break;
2591 case PLY_FLOAT:
2592 case PLY_FLOAT32:
2593 pfloat = (float *) item;
2594 *pfloat = double_val;
2595 break;
2596 case PLY_DOUBLE:
2597 pdouble = (double *) item;
2598 *pdouble = double_val;
2599 break;
2600 default:
2601 char error[100];
2602 sprintf (error, "store_item: bad type = %d\n", type);
2603 throw ply::MeshException( error );
2604 }
2605 }
2606
2607
2608 /******************************************************************************
2609 Add an element to a PLY file descriptor.
2610
2611 Entry:
2612 plyfile - PLY file descriptor
2613 words - list of words describing the element
2614 nwords - number of words in the list
2615 ******************************************************************************/
2616
add_element(PlyFile * plyfile,char ** words,int)2617 void add_element (PlyFile *plyfile, char **words, int)
2618 {
2619 PlyElement *elem;
2620
2621 /* create the new element */
2622 elem = (PlyElement *) myalloc (sizeof (PlyElement));
2623 elem->name = strdup (words[1]);
2624 elem->num = atoi (words[2]);
2625 elem->nprops = 0;
2626
2627 /* make room for new element in the object's list of elements */
2628 if (plyfile->nelems == 0)
2629 plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *));
2630 else
2631 plyfile->elems = (PlyElement **) realloc (plyfile->elems,
2632 sizeof (PlyElement *) * (plyfile->nelems + 1));
2633
2634 /* add the new element to the object's list */
2635 plyfile->elems[plyfile->nelems] = elem;
2636 plyfile->nelems++;
2637 }
2638
2639
2640 /******************************************************************************
2641 Return the type of a property, given the name of the property.
2642
2643 Entry:
2644 name - name of property type
2645
2646 Exit:
2647 returns integer code for property, or 0 if not found
2648 ******************************************************************************/
2649
get_prop_type(char * type_name)2650 int get_prop_type(char *type_name)
2651 {
2652 int i;
2653
2654 for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++)
2655 if (equal_strings (type_name, type_names[i]))
2656 return (i);
2657
2658 /* if we get here, we didn't find the type */
2659 return (0);
2660 }
2661
2662
2663 /******************************************************************************
2664 Add a property to a PLY file descriptor.
2665
2666 Entry:
2667 plyfile - PLY file descriptor
2668 words - list of words describing the property
2669 nwords - number of words in the list
2670 ******************************************************************************/
2671
add_property(PlyFile * plyfile,char ** words,int)2672 void add_property (PlyFile *plyfile, char **words, int )
2673 {
2674 PlyProperty *prop;
2675 PlyElement *elem;
2676
2677 /* create the new property */
2678
2679 prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
2680
2681 if (equal_strings (words[1], "list")) { /* is a list */
2682 prop->count_external = get_prop_type (words[2]);
2683 prop->external_type = get_prop_type (words[3]);
2684 prop->name = strdup (words[4]);
2685 prop->is_list = 1;
2686 }
2687 else { /* not a list */
2688 prop->external_type = get_prop_type (words[1]);
2689 prop->name = strdup (words[2]);
2690 prop->is_list = 0;
2691 }
2692
2693 /* add this property to the list of properties of the current element */
2694
2695 elem = plyfile->elems[plyfile->nelems - 1];
2696
2697 if (elem->nprops == 0)
2698 elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
2699 else
2700 elem->props = (PlyProperty **) realloc (elem->props,
2701 sizeof (PlyProperty *) * (elem->nprops + 1));
2702
2703 elem->props[elem->nprops] = prop;
2704 elem->nprops++;
2705 }
2706
2707
2708 /******************************************************************************
2709 Add a comment to a PLY file descriptor.
2710
2711 Entry:
2712 plyfile - PLY file descriptor
2713 line - line containing comment
2714 ******************************************************************************/
2715
add_comment(PlyFile * plyfile,char * line)2716 void add_comment (PlyFile *plyfile, char *line)
2717 {
2718 int i;
2719
2720 /* skip over "comment" and leading spaces and tabs */
2721 i = 7;
2722 while (line[i] == ' ' || line[i] == '\t')
2723 i++;
2724
2725 ply_put_comment (plyfile, &line[i]);
2726 }
2727
2728
2729 /******************************************************************************
2730 Add a some object information to a PLY file descriptor.
2731
2732 Entry:
2733 plyfile - PLY file descriptor
2734 line - line containing text info
2735 ******************************************************************************/
2736
add_obj_info(PlyFile * plyfile,char * line)2737 void add_obj_info (PlyFile *plyfile, char *line)
2738 {
2739 int i;
2740
2741 /* skip over "obj_info" and leading spaces and tabs */
2742 i = 8;
2743 while (line[i] == ' ' || line[i] == '\t')
2744 i++;
2745
2746 ply_put_obj_info (plyfile, &line[i]);
2747 }
2748
2749
2750 /******************************************************************************
2751 Copy a property.
2752 ******************************************************************************/
2753
copy_property(PlyProperty * dest,PlyProperty * src)2754 void copy_property(PlyProperty *dest, PlyProperty *src)
2755 {
2756 dest->name = strdup (src->name);
2757 dest->external_type = src->external_type;
2758 dest->internal_type = src->internal_type;
2759 dest->offset = src->offset;
2760
2761 dest->is_list = src->is_list;
2762 dest->count_external = src->count_external;
2763 dest->count_internal = src->count_internal;
2764 dest->count_offset = src->count_offset;
2765 }
2766
2767
2768 /******************************************************************************
2769 Allocate some memory.
2770
2771 Entry:
2772 size - amount of memory requested (in bytes)
2773 lnum - line number from which memory was requested
2774 fname - file name from which memory was requested
2775 ******************************************************************************/
2776
my_alloc(int size,int lnum,const char * fname)2777 char *my_alloc(int size, int lnum, const char *fname)
2778 {
2779 char *ptr;
2780
2781 ptr = (char *) malloc (size);
2782
2783 if (ptr == 0)
2784 fprintf( stderr, "Memory allocation bombed on line %d in %s\n",
2785 lnum, fname);
2786
2787 return (ptr);
2788 }
2789
2790