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 item_size;
629 int int_val;
630 unsigned int uint_val;
631 double double_val;
632 char **other_ptr;
633
634 elem = plyfile->which_elem;
635 elem_data = (char *)elem_ptr;
636 other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset);
637
638 /* write out either to an ascii or binary file */
639
640 if (plyfile->file_type == PLY_ASCII) {
641
642 /* write an ascii file */
643
644 /* write out each property of the element */
645 for (j = 0; j < elem->nprops; j++) {
646 prop = elem->props[j];
647 if (elem->store_prop[j] == OTHER_PROP)
648 elem_data = *other_ptr;
649 else
650 elem_data = (char *)elem_ptr;
651 if (prop->is_list) {
652 item = elem_data + prop->count_offset;
653 get_stored_item ((void *) item, prop->count_internal,
654 &int_val, &uint_val, &double_val);
655 write_ascii_item (fp, int_val, uint_val, double_val,
656 prop->count_external);
657 list_count = uint_val;
658 item_ptr = (char **) (elem_data + prop->offset);
659 item = item_ptr[0];
660 item_size = ply_type_size[prop->internal_type];
661 for (k = 0; k < list_count; k++) {
662 get_stored_item ((void *) item, prop->internal_type,
663 &int_val, &uint_val, &double_val);
664 write_ascii_item (fp, int_val, uint_val, double_val,
665 prop->external_type);
666 item += item_size;
667 }
668 }
669 else {
670 item = elem_data + prop->offset;
671 get_stored_item ((void *) item, prop->internal_type,
672 &int_val, &uint_val, &double_val);
673 write_ascii_item (fp, int_val, uint_val, double_val,
674 prop->external_type);
675 }
676 }
677
678 fprintf (fp, "\n");
679 }
680 else {
681
682 /* write a binary file */
683
684 /* write out each property of the element */
685 for (j = 0; j < elem->nprops; j++) {
686 prop = elem->props[j];
687 if (elem->store_prop[j] == OTHER_PROP)
688 elem_data = *other_ptr;
689 else
690 elem_data = (char *)elem_ptr;
691 if (prop->is_list) {
692 item = elem_data + prop->count_offset;
693 item_size = ply_type_size[prop->count_internal];
694 get_stored_item ((void *) item, prop->count_internal,
695 &int_val, &uint_val, &double_val);
696 write_binary_item (plyfile, int_val, uint_val, double_val,
697 prop->count_external);
698 list_count = uint_val;
699 item_ptr = (char **) (elem_data + prop->offset);
700 item = item_ptr[0];
701 item_size = ply_type_size[prop->internal_type];
702 for (k = 0; k < list_count; k++) {
703 get_stored_item ((void *) item, prop->internal_type,
704 &int_val, &uint_val, &double_val);
705 write_binary_item (plyfile, int_val, uint_val, double_val,
706 prop->external_type);
707 item += item_size;
708 }
709 }
710 else {
711 item = elem_data + prop->offset;
712 item_size = ply_type_size[prop->internal_type];
713 get_stored_item ((void *) item, prop->internal_type,
714 &int_val, &uint_val, &double_val);
715 write_binary_item (plyfile, int_val, uint_val, double_val,
716 prop->external_type);
717 }
718 }
719
720 }
721 }
722
723
724 /******************************************************************************
725 Specify a comment that will be written in the header.
726
727 Entry:
728 plyfile - file identifier
729 comment - the comment to be written
730 ******************************************************************************/
731
ply_put_comment(PlyFile * plyfile,const char * comment)732 void ply_put_comment(PlyFile *plyfile, const char *comment)
733 {
734 /* (re)allocate space for new comment */
735 if (plyfile->num_comments == 0)
736 {
737 plyfile->comments = (char **) myalloc (sizeof (char *));
738 }
739 else
740 {
741 plyfile->comments = (char **) realloc (plyfile->comments,
742 sizeof (char *) * (plyfile->num_comments + 1));
743 }
744
745 /* add comment to list */
746 plyfile->comments[plyfile->num_comments] = strdup (comment);
747 plyfile->num_comments++;
748 }
749
750
751 /******************************************************************************
752 Specify a piece of object information (arbitrary text) that will be written
753 in the header.
754
755 Entry:
756 plyfile - file identifier
757 obj_info - the text information to be written
758 ******************************************************************************/
759
ply_put_obj_info(PlyFile * plyfile,const char * obj_info)760 void ply_put_obj_info(PlyFile *plyfile, const char *obj_info)
761 {
762 /* (re)allocate space for new info */
763 if (plyfile->num_obj_info == 0)
764 {
765 plyfile->obj_info = (char **) myalloc (sizeof (char *));
766 }
767 else
768 {
769 plyfile->obj_info = (char **) realloc (plyfile->obj_info,
770 sizeof (char *) * (plyfile->num_obj_info + 1));
771 }
772
773 /* add info to list */
774 plyfile->obj_info[plyfile->num_obj_info] = strdup (obj_info);
775 plyfile->num_obj_info++;
776 }
777
778
779
780
781
782
783
784 /*************/
785 /* Reading */
786 /*************/
787
788
789
790 /******************************************************************************
791 Given a file pointer, get ready to read PLY data from the file.
792
793 Entry:
794 fp - the given file pointer
795
796 Exit:
797 nelems - number of elements in object
798 elem_names - list of element names
799 returns a pointer to a PlyFile, used to refer to this file, or NULL if error
800 ******************************************************************************/
801
ply_read(FILE * fp,int * nelems,char *** elem_names)802 PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names)
803 {
804 int i,j;
805 PlyFile *plyfile;
806 int nwords;
807 char **words;
808 char **elist;
809 PlyElement *elem;
810 char *orig_line;
811
812 /* check for NULL file pointer */
813 if (fp == NULL)
814 return (NULL);
815
816 /* create record for this object */
817
818 plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
819 if (!plyfile) return (NULL);
820
821 plyfile->nelems = 0;
822 plyfile->comments = NULL;
823 plyfile->num_comments = 0;
824 plyfile->obj_info = NULL;
825 plyfile->num_obj_info = 0;
826 plyfile->fp = fp;
827 plyfile->other_elems = NULL;
828
829 /* read and parse the file's header */
830
831 words = get_words (plyfile->fp, &nwords, &orig_line);
832 if (!words || !equal_strings (words[0], "ply"))
833 {
834 if (words) free( words);
835 free( plyfile );
836 return (NULL);
837 }
838
839 while (words)
840 {
841
842 /* parse words */
843
844 if (equal_strings (words[0], "format"))
845 {
846 if (nwords != 3)
847 {
848 free( words );
849 free( plyfile );
850 return (NULL);
851 }
852 if (equal_strings (words[1], "ascii"))
853 plyfile->file_type = PLY_ASCII;
854 else if (equal_strings (words[1], "binary_big_endian"))
855 plyfile->file_type = PLY_BINARY_BE;
856 else if (equal_strings (words[1], "binary_little_endian"))
857 plyfile->file_type = PLY_BINARY_LE;
858 else
859 {
860 free( words );
861 free( plyfile );
862 return (NULL);
863 }
864 plyfile->version = osg::asciiToDouble (words[2]);
865 }
866 else if (equal_strings (words[0], "element"))
867 add_element (plyfile, words, nwords);
868 else if (equal_strings (words[0], "property"))
869 add_property (plyfile, words, nwords);
870 else if (equal_strings (words[0], "comment"))
871 add_comment (plyfile, orig_line);
872 else if (equal_strings (words[0], "obj_info"))
873 add_obj_info (plyfile, orig_line);
874 else if (equal_strings (words[0], "end_header"))
875 {
876 free (words);
877 break;
878 }
879
880 /* free up words space */
881 free (words);
882
883 words = get_words (plyfile->fp, &nwords, &orig_line);
884 }
885
886
887 /* create tags for each property of each element, to be used */
888 /* later to say whether or not to store each property for the user */
889
890 for (i = 0; i < plyfile->nelems; i++) {
891 elem = plyfile->elems[i];
892 elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops);
893 for (j = 0; j < elem->nprops; j++)
894 elem->store_prop[j] = DONT_STORE_PROP;
895 elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */
896 }
897
898 /* set return values about the elements */
899
900 elist = (char **) myalloc (sizeof (char *) * plyfile->nelems);
901 for (i = 0; i < plyfile->nelems; i++)
902 elist[i] = strdup (plyfile->elems[i]->name);
903
904 *elem_names = elist;
905 *nelems = plyfile->nelems;
906
907 /* return a pointer to the file's information */
908
909 return (plyfile);
910 }
911
912
913 /******************************************************************************
914 Open a polygon file for reading.
915
916 Entry:
917 filename - name of file to read from
918
919 Exit:
920 nelems - number of elements in object
921 elem_names - list of element names
922 file_type - file type, either ascii or binary
923 version - version number of PLY file
924 returns a file identifier, used to refer to this file, or NULL if error
925 ******************************************************************************/
926
ply_open_for_reading(char * filename,int * nelems,char *** elem_names,int * file_type,float * version)927 PlyFile *ply_open_for_reading(
928 char *filename,
929 int *nelems,
930 char ***elem_names,
931 int *file_type,
932 float *version
933 )
934 {
935 FILE *fp;
936 PlyFile *plyfile;
937
938 /* open the file for reading */
939 fp = osgDB::fopen (filename, "rb");
940 if (fp == NULL)
941 return (NULL);
942
943 /* create the PlyFile data structure */
944
945 plyfile = ply_read (fp, nelems, elem_names);
946
947 if(!plyfile)
948 {
949 std::cout<<"Ply File Error : Could not read file " << filename <<std::endl;
950 return NULL;
951 }
952
953 /* determine the file type and version */
954
955 *file_type = plyfile->file_type;
956 *version = plyfile->version;
957
958 /* return a pointer to the file's information */
959
960 return (plyfile);
961 }
962
963
964 /******************************************************************************
965 Get information about a particular element.
966
967 Entry:
968 plyfile - file identifier
969 elem_name - name of element to get information about
970
971 Exit:
972 nelems - number of elements of this type in the file
973 nprops - number of properties
974 returns a list of properties, or NULL if the file doesn't contain that elem
975 ******************************************************************************/
976
ply_get_element_description(PlyFile * plyfile,char * elem_name,int * nelems,int * nprops)977 PlyProperty **ply_get_element_description(
978 PlyFile *plyfile,
979 char *elem_name,
980 int *nelems,
981 int *nprops
982 )
983 {
984 int i;
985 PlyElement *elem;
986 PlyProperty *prop;
987 PlyProperty **prop_list;
988
989 /* find information about the element */
990 elem = find_element (plyfile, elem_name);
991 if (elem == NULL)
992 return (NULL);
993
994 *nelems = elem->num;
995 *nprops = elem->nprops;
996
997 /* make a copy of the element's property list */
998 prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops);
999 for (i = 0; i < elem->nprops; i++) {
1000 prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
1001 copy_property (prop, elem->props[i]);
1002 prop_list[i] = prop;
1003 }
1004
1005 /* return this duplicate property list */
1006 return (prop_list);
1007 }
1008
1009
1010 /******************************************************************************
1011 Specify which properties of an element are to be returned. This should be
1012 called before a call to the routine ply_get_element().
1013
1014 Entry:
1015 plyfile - file identifier
1016 elem_name - which element we're talking about
1017 nprops - number of properties
1018 prop_list - list of properties
1019 ******************************************************************************/
1020
ply_get_element_setup(PlyFile * plyfile,char * elem_name,int nprops,PlyProperty * prop_list)1021 void ply_get_element_setup( PlyFile *plyfile, char *elem_name, int nprops,
1022 PlyProperty *prop_list )
1023 {
1024 int i;
1025 PlyElement *elem;
1026 PlyProperty *prop;
1027 int index;
1028
1029 /* find information about the element */
1030 elem = find_element (plyfile, elem_name);
1031 plyfile->which_elem = elem;
1032
1033 /* deposit the property information into the element's description */
1034 for (i = 0; i < nprops; i++)
1035 {
1036 /* look for actual property */
1037 prop = find_property (elem, prop_list[i].name, &index);
1038 if (prop == NULL)
1039 {
1040 fprintf ( stderr,
1041 "Warning: Can't find property '%s' in element '%s'\n",
1042 prop_list[i].name, elem_name );
1043 continue;
1044 }
1045
1046 /* store its description */
1047 prop->internal_type = prop_list[i].internal_type;
1048 prop->offset = prop_list[i].offset;
1049 prop->count_internal = prop_list[i].count_internal;
1050 prop->count_offset = prop_list[i].count_offset;
1051
1052 /* specify that the user wants this property */
1053 elem->store_prop[index] = STORE_PROP;
1054 }
1055 }
1056
ply_set_property(PlyProperty * prop,PlyProperty * prop_ptr,PlyElement * elem,const int & index)1057 void ply_set_property(
1058 PlyProperty *prop,
1059 PlyProperty *prop_ptr,
1060 PlyElement *elem,
1061 const int &index
1062 )
1063 {
1064 prop_ptr->internal_type = prop->internal_type;
1065 prop_ptr->offset = prop->offset;
1066 prop_ptr->count_internal = prop->count_internal;
1067 prop_ptr->count_offset = prop->count_offset;
1068
1069 /* specify that the user wants this property */
1070 elem->store_prop[index] = STORE_PROP;
1071 }
1072
1073 // Tokenize a property using the given delimiter
tokenizeProperties(const char * pnames,std::vector<std::string> & tokens,const std::string & delimiter)1074 void tokenizeProperties(const char* pnames, std::vector<std::string> &tokens, const std::string &delimiter)
1075 {
1076 std::string propNames(pnames);
1077 std::string::size_type lastPos = propNames.find_first_not_of(delimiter, 0);
1078 std::string::size_type pos = propNames.find_first_of(delimiter, lastPos);
1079
1080 while (std::string::npos != pos || std::string::npos != lastPos) {
1081 tokens.push_back(propNames.substr(lastPos, pos - lastPos));
1082 lastPos = propNames.find_first_not_of(delimiter, pos);
1083 pos = propNames.find_first_of(delimiter, lastPos);
1084 }
1085 }
1086
1087 /******************************************************************************
1088 Specify a property of an element that is to be returned. This should be
1089 called (usually multiple times) before a call to the routine ply_get_element().
1090 This routine should be used in preference to the less flexible old routine
1091 called ply_get_element_setup().
1092
1093 Entry:
1094 plyfile - file identifier
1095 elem_name - which element we're talking about
1096 prop - property to add to those that will be returned
1097 ******************************************************************************/
1098
ply_get_property(PlyFile * plyfile,const char * elem_name,PlyProperty * prop)1099 void ply_get_property(
1100 PlyFile *plyfile,
1101 const char *elem_name,
1102 PlyProperty *prop
1103 )
1104 {
1105 PlyElement *elem;
1106 PlyProperty *prop_ptr = 0;
1107 int index;
1108
1109 /* find information about the element */
1110 elem = find_element (plyfile, elem_name);
1111 plyfile->which_elem = elem;
1112
1113 /* deposit the property information into the element's description */
1114 /* Properties may have several names, separated by | with no spaces */
1115 std::vector<std::string> tokens;
1116 tokenizeProperties(prop->name, tokens, "|");
1117
1118 for(std::vector<std::string>::iterator it_property = tokens.begin();
1119 !prop_ptr && it_property != tokens.end();
1120 ++it_property)
1121 {
1122 prop_ptr = find_property(elem, it_property->c_str(), &index);
1123 }
1124
1125 if(prop_ptr)
1126 {
1127 ply_set_property(prop, prop_ptr, elem, index);
1128 }
1129 else
1130 {
1131 fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n",
1132 prop->name, elem_name);
1133 return;
1134 }
1135 }
1136
1137
1138 /******************************************************************************
1139 Read one element from the file. This routine assumes that we're reading
1140 the type of element specified in the last call to the routine
1141 ply_get_element_setup().
1142
1143 Entry:
1144 plyfile - file identifier
1145 elem_ptr - pointer to location where the element information should be put
1146 ******************************************************************************/
1147
ply_get_element(PlyFile * plyfile,void * elem_ptr)1148 void ply_get_element(PlyFile *plyfile, void *elem_ptr)
1149 {
1150 if (plyfile->file_type == PLY_ASCII)
1151 ascii_get_element (plyfile, (char *) elem_ptr);
1152 else
1153 binary_get_element (plyfile, (char *) elem_ptr);
1154 }
1155
1156
1157 /******************************************************************************
1158 Extract the comments from the header information of a PLY file.
1159
1160 Entry:
1161 plyfile - file identifier
1162
1163 Exit:
1164 num_comments - number of comments returned
1165 returns a pointer to a list of comments
1166 ******************************************************************************/
1167
ply_get_comments(PlyFile * plyfile,int * num_comments)1168 char **ply_get_comments(PlyFile *plyfile, int *num_comments)
1169 {
1170 *num_comments = plyfile->num_comments;
1171 return (plyfile->comments);
1172 }
1173
1174
1175 /******************************************************************************
1176 Extract the object information (arbitrary text) from the header information
1177 of a PLY file.
1178
1179 Entry:
1180 plyfile - file identifier
1181
1182 Exit:
1183 num_obj_info - number of lines of text information returned
1184 returns a pointer to a list of object info lines
1185 ******************************************************************************/
1186
ply_get_obj_info(PlyFile * plyfile,int * num_obj_info)1187 char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info)
1188 {
1189 *num_obj_info = plyfile->num_obj_info;
1190 return (plyfile->obj_info);
1191 }
1192
1193
1194 /******************************************************************************
1195 Make ready for "other" properties of an element-- those properties that
1196 the user has not explicitly asked for, but that are to be stashed away
1197 in a special structure to be carried along with the element's other
1198 information.
1199
1200 Entry:
1201 plyfile - file identifier
1202 elem - element for which we want to save away other properties
1203 ******************************************************************************/
1204
setup_other_props(PlyFile *,PlyElement * elem)1205 void setup_other_props(PlyFile *, PlyElement *elem)
1206 {
1207 int i;
1208 PlyProperty *prop;
1209 int size = 0;
1210 int type_size;
1211
1212 /* Examine each property in decreasing order of size. */
1213 /* We do this so that all data types will be aligned by */
1214 /* word, half-word, or whatever within the structure. */
1215
1216 for (type_size = 8; type_size > 0; type_size /= 2) {
1217
1218 /* add up the space taken by each property, and save this information */
1219 /* away in the property descriptor */
1220
1221 for (i = 0; i < elem->nprops; i++) {
1222
1223 /* don't bother with properties we've been asked to store explicitly */
1224 if (elem->store_prop[i])
1225 continue;
1226
1227 prop = elem->props[i];
1228
1229 /* internal types will be same as external */
1230 prop->internal_type = prop->external_type;
1231 prop->count_internal = prop->count_external;
1232
1233 /* check list case */
1234 if (prop->is_list) {
1235
1236 /* pointer to list */
1237 if (type_size == sizeof (void *)) {
1238 prop->offset = size;
1239 size += sizeof (void *); /* always use size of a pointer here */
1240 }
1241
1242 /* count of number of list elements */
1243 if (type_size == ply_type_size[prop->count_external]) {
1244 prop->count_offset = size;
1245 size += ply_type_size[prop->count_external];
1246 }
1247 }
1248 /* not list */
1249 else if (type_size == ply_type_size[prop->external_type]) {
1250 prop->offset = size;
1251 size += ply_type_size[prop->external_type];
1252 }
1253 }
1254
1255 }
1256
1257 /* save the size for the other_props structure */
1258 elem->other_size = size;
1259 }
1260
1261
1262 /******************************************************************************
1263 Specify that we want the "other" properties of an element to be tucked
1264 away within the user's structure. The user needn't be concerned for how
1265 these properties are stored.
1266
1267 Entry:
1268 plyfile - file identifier
1269 elem_name - name of element that we want to store other_props in
1270 offset - offset to where other_props will be stored inside user's structure
1271
1272 Exit:
1273 returns pointer to structure containing description of other_props
1274 ******************************************************************************/
1275
ply_get_other_properties(PlyFile * plyfile,char * elem_name,int offset)1276 PlyOtherProp *ply_get_other_properties(
1277 PlyFile *plyfile,
1278 char *elem_name,
1279 int offset
1280 )
1281 {
1282 int i;
1283 PlyElement *elem;
1284 PlyOtherProp *other;
1285 PlyProperty *prop;
1286 int nprops;
1287
1288 /* find information about the element */
1289 elem = find_element (plyfile, elem_name);
1290 if (elem == NULL) {
1291 fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n",
1292 elem_name);
1293 return (NULL);
1294 }
1295
1296 /* remember that this is the "current" element */
1297 plyfile->which_elem = elem;
1298
1299 /* save the offset to where to store the other_props */
1300 elem->other_offset = offset;
1301
1302 /* place the appropriate pointers, etc. in the element's property list */
1303 setup_other_props (plyfile, elem);
1304
1305 /* create structure for describing other_props */
1306 other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp));
1307 other->name = strdup (elem_name);
1308 #if 0
1309 if (elem->other_offset == NO_OTHER_PROPS) {
1310 other->size = 0;
1311 other->props = NULL;
1312 other->nprops = 0;
1313 return (other);
1314 }
1315 #endif
1316 other->size = elem->other_size;
1317 other->props = (PlyProperty **) myalloc (sizeof(PlyProperty*) * elem->nprops);
1318
1319 /* save descriptions of each "other" property */
1320 nprops = 0;
1321 for (i = 0; i < elem->nprops; i++) {
1322 if (elem->store_prop[i])
1323 continue;
1324 prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
1325 copy_property (prop, elem->props[i]);
1326 other->props[nprops] = prop;
1327 nprops++;
1328 }
1329 other->nprops = nprops;
1330
1331 #if 1
1332 /* set other_offset pointer appropriately if there are NO other properties */
1333 if (other->nprops == 0) {
1334 elem->other_offset = NO_OTHER_PROPS;
1335 }
1336 #endif
1337
1338 /* return structure */
1339 return (other);
1340 }
1341
1342
1343
1344
1345 /*************************/
1346 /* Other Element Stuff */
1347 /*************************/
1348
1349
1350
1351
1352 /******************************************************************************
1353 Grab all the data for an element that a user does not want to explicitly
1354 read in.
1355
1356 Entry:
1357 plyfile - pointer to file
1358 elem_name - name of element whose data is to be read in
1359 elem_count - number of instances of this element stored in the file
1360
1361 Exit:
1362 returns pointer to ALL the "other" element data for this PLY file
1363 ******************************************************************************/
1364
ply_get_other_element(PlyFile * plyfile,char * elem_name,int elem_count)1365 PlyOtherElems *ply_get_other_element (
1366 PlyFile *plyfile,
1367 char *elem_name,
1368 int elem_count
1369 )
1370 {
1371 int i;
1372 PlyElement *elem;
1373 PlyOtherElems *other_elems;
1374 OtherElem *other;
1375
1376 /* look for appropriate element */
1377 elem = find_element (plyfile, elem_name);
1378 if (elem == NULL) {
1379 char error[100];
1380 sprintf (error, "ply_get_other_element: can't find element '%s'\n", elem_name);
1381 throw ply::MeshException( error );
1382 }
1383
1384 /* create room for the new "other" element, initializing the */
1385 /* other data structure if necessary */
1386
1387 if (plyfile->other_elems == NULL) {
1388 plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems));
1389 other_elems = plyfile->other_elems;
1390 other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem));
1391 other = &(other_elems->other_list[0]);
1392 other_elems->num_elems = 1;
1393 }
1394 else {
1395 other_elems = plyfile->other_elems;
1396 other_elems->other_list = (OtherElem *) realloc (other_elems->other_list,
1397 sizeof (OtherElem) * other_elems->num_elems + 1);
1398 other = &(other_elems->other_list[other_elems->num_elems]);
1399 other_elems->num_elems++;
1400 }
1401
1402 /* count of element instances in file */
1403 other->elem_count = elem_count;
1404
1405 /* save name of element */
1406 other->elem_name = strdup (elem_name);
1407
1408 /* create a list to hold all the current elements */
1409 other->other_data = (OtherData **)
1410 malloc (sizeof (OtherData *) * other->elem_count);
1411
1412 /* set up for getting elements */
1413 other->other_props = ply_get_other_properties (plyfile, elem_name,
1414 offsetof(OtherData,other_props));
1415
1416 /* grab all these elements */
1417 for (i = 0; i < other->elem_count; i++) {
1418 /* grab and element from the file */
1419 other->other_data[i] = (OtherData *) malloc (sizeof (OtherData));
1420 ply_get_element (plyfile, (void *) other->other_data[i]);
1421 }
1422
1423 /* return pointer to the other elements data */
1424 return (other_elems);
1425 }
1426
1427
1428 /******************************************************************************
1429 Pass along a pointer to "other" elements that we want to save in a given
1430 PLY file. These other elements were presumably read from another PLY file.
1431
1432 Entry:
1433 plyfile - file pointer in which to store this other element info
1434 other_elems - info about other elements that we want to store
1435 ******************************************************************************/
1436
ply_describe_other_elements(PlyFile * plyfile,PlyOtherElems * other_elems)1437 void ply_describe_other_elements (
1438 PlyFile *plyfile,
1439 PlyOtherElems *other_elems
1440 )
1441 {
1442 int i;
1443 OtherElem *other;
1444
1445 /* ignore this call if there is no other element */
1446 if (other_elems == NULL)
1447 return;
1448
1449 /* save pointer to this information */
1450 plyfile->other_elems = other_elems;
1451
1452 /* describe the other properties of this element */
1453
1454 for (i = 0; i < other_elems->num_elems; i++) {
1455 other = &(other_elems->other_list[i]);
1456 ply_element_count (plyfile, other->elem_name, other->elem_count);
1457 ply_describe_other_properties (plyfile, other->other_props,
1458 offsetof(OtherData,other_props));
1459 }
1460 }
1461
1462
1463 /******************************************************************************
1464 Write out the "other" elements specified for this PLY file.
1465
1466 Entry:
1467 plyfile - pointer to PLY file to write out other elements for
1468 ******************************************************************************/
1469
ply_put_other_elements(PlyFile * plyfile)1470 void ply_put_other_elements (PlyFile *plyfile)
1471 {
1472 int i,j;
1473 OtherElem *other;
1474
1475 /* make sure we have other elements to write */
1476 if (plyfile->other_elems == NULL)
1477 return;
1478
1479 /* write out the data for each "other" element */
1480
1481 for (i = 0; i < plyfile->other_elems->num_elems; i++) {
1482
1483 other = &(plyfile->other_elems->other_list[i]);
1484 ply_put_element_setup (plyfile, other->elem_name);
1485
1486 /* write out each instance of the current element */
1487 for (j = 0; j < other->elem_count; j++)
1488 ply_put_element (plyfile, (void *) other->other_data[j]);
1489 }
1490 }
1491
1492
1493 /******************************************************************************
1494 Free up storage used by an "other" elements data structure.
1495
1496 Entry:
1497 other_elems - data structure to free up
1498 ******************************************************************************/
1499
ply_free_other_elements(PlyOtherElems *)1500 void ply_free_other_elements (PlyOtherElems *)
1501 {
1502
1503 }
1504
1505
1506
1507 /*******************/
1508 /* Miscellaneous */
1509 /*******************/
1510
1511
1512
1513 /******************************************************************************
1514 Close a PLY file.
1515
1516 Entry:
1517 plyfile - identifier of file to close
1518 ******************************************************************************/
1519
ply_close(PlyFile * plyfile)1520 void ply_close(PlyFile *plyfile)
1521 {
1522 // Changed by Will Schroeder. Old stuff leaked like a sieve.
1523
1524 /* free up memory associated with the PLY file */
1525 fclose (plyfile->fp);
1526
1527 int i, j;
1528 PlyElement *elem;
1529 for (i=0; i<plyfile->nelems; i++)
1530 {
1531 elem = plyfile->elems[i];
1532 if ( elem->name ) {free(elem->name);}
1533 for (j=0; j<elem->nprops; j++)
1534 {
1535 if ( elem->props[j]->name ) {free(const_cast<char *>(elem->props[j]->name));}
1536 free (elem->props[j]);
1537 }
1538 free (elem->props);
1539 free (elem->store_prop);
1540 free (elem);
1541 }
1542 free(plyfile->elems);
1543
1544 for (i=0; i<plyfile->num_comments; i++)
1545 {
1546 free (plyfile->comments[i]);
1547 }
1548 free (plyfile->comments);
1549
1550 for (i=0; i<plyfile->num_obj_info; i++)
1551 {
1552 free (plyfile->obj_info[i]);
1553 }
1554 free (plyfile->obj_info);
1555
1556 free (plyfile);
1557 }
1558
1559
1560 /******************************************************************************
1561 Get version number and file type of a PlyFile.
1562
1563 Entry:
1564 ply - pointer to PLY file
1565
1566 Exit:
1567 version - version of the file
1568 file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE
1569 ******************************************************************************/
1570
ply_get_info(PlyFile * ply,float * version,int * file_type)1571 void ply_get_info(PlyFile *ply, float *version, int *file_type)
1572 {
1573 if (ply == NULL)
1574 return;
1575
1576 *version = ply->version;
1577 *file_type = ply->file_type;
1578 }
1579
1580
1581 /******************************************************************************
1582 Compare two strings. Returns 1 if they are the same, 0 if not.
1583 ******************************************************************************/
1584
equal_strings(const char * s1,const char * s2)1585 int equal_strings(const char *s1, const char *s2)
1586 {
1587 while (*s1 && *s2)
1588 if (*s1++ != *s2++)
1589 return (0);
1590
1591 if (*s1 != *s2)
1592 return (0);
1593 else
1594 return (1);
1595 }
1596
1597
1598 /******************************************************************************
1599 Find an element from the element list of a given PLY object.
1600
1601 Entry:
1602 plyfile - file id for PLY file
1603 element - name of element we're looking for
1604
1605 Exit:
1606 returns the element, or NULL if not found
1607 ******************************************************************************/
1608
find_element(PlyFile * plyfile,const char * element)1609 PlyElement *find_element(PlyFile *plyfile, const char *element)
1610 {
1611 int i;
1612
1613 for (i = 0; i < plyfile->nelems; i++)
1614 if (equal_strings (element, plyfile->elems[i]->name))
1615 return (plyfile->elems[i]);
1616
1617 return (NULL);
1618 }
1619
1620
1621 /******************************************************************************
1622 Find a property in the list of properties of a given element.
1623
1624 Entry:
1625 elem - pointer to element in which we want to find the property
1626 prop_name - name of property to find
1627
1628 Exit:
1629 index - index to position in list
1630 returns a pointer to the property, or NULL if not found
1631 ******************************************************************************/
1632
find_property(PlyElement * elem,const char * prop_name,int * index)1633 PlyProperty *find_property(PlyElement *elem, const char *prop_name, int *index)
1634 {
1635 int i;
1636
1637 for( i = 0; i < elem->nprops; i++)
1638 if (equal_strings (prop_name, elem->props[i]->name))
1639 {
1640 *index = i;
1641 return (elem->props[i]);
1642 }
1643
1644 *index = -1;
1645 return (NULL);
1646 }
1647
1648
1649 /******************************************************************************
1650 Read an element from an ascii file.
1651
1652 Entry:
1653 plyfile - file identifier
1654 elem_ptr - pointer to element
1655 ******************************************************************************/
1656
ascii_get_element(PlyFile * plyfile,char * elem_ptr)1657 void ascii_get_element(PlyFile *plyfile, char *elem_ptr)
1658 {
1659 int j,k;
1660 PlyElement *elem;
1661 PlyProperty *prop;
1662 char **words;
1663 int nwords;
1664 int which_word;
1665 char *elem_data,*item=0;
1666 char *item_ptr;
1667 int item_size=0;
1668 int int_val;
1669 unsigned int uint_val;
1670 double double_val;
1671 int list_count;
1672 int store_it;
1673 char **store_array;
1674 char *orig_line;
1675 char *other_data=0;
1676 int other_flag;
1677
1678 /* the kind of element we're reading currently */
1679 elem = plyfile->which_elem;
1680
1681 /* do we need to setup for other_props? */
1682
1683 if (elem->other_offset != NO_OTHER_PROPS) {
1684 char **ptr;
1685 other_flag = 1;
1686 /* make room for other_props */
1687 other_data = (char *) myalloc (elem->other_size);
1688 /* store pointer in user's structure to the other_props */
1689 ptr = (char **) (elem_ptr + elem->other_offset);
1690 *ptr = other_data;
1691 }
1692 else
1693 other_flag = 0;
1694
1695 /* read in the element */
1696
1697 words = get_words (plyfile->fp, &nwords, &orig_line);
1698 if (words == NULL) {
1699 char error[100];
1700 sprintf (error, "ply_get_element: unexpected end of file\n");
1701 throw ply::MeshException( error );
1702 }
1703
1704 which_word = 0;
1705
1706 for (j = 0; j < elem->nprops; j++) {
1707
1708 prop = elem->props[j];
1709 store_it = (elem->store_prop[j] | other_flag);
1710
1711 /* store either in the user's structure or in other_props */
1712 if (elem->store_prop[j])
1713 elem_data = elem_ptr;
1714 else
1715 elem_data = other_data;
1716
1717 if (prop->is_list) { /* a list */
1718
1719 /* get and store the number of items in the list */
1720 get_ascii_item (words[which_word++], prop->count_external,
1721 &int_val, &uint_val, &double_val);
1722 if (store_it) {
1723 item = elem_data + prop->count_offset;
1724 store_item(item, prop->count_internal, int_val, uint_val, double_val);
1725 }
1726
1727 /* allocate space for an array of items and store a ptr to the array */
1728 list_count = int_val;
1729 item_size = ply_type_size[prop->internal_type];
1730 store_array = (char **) (elem_data + prop->offset);
1731
1732 if (list_count == 0) {
1733 if (store_it)
1734 *store_array = NULL;
1735 }
1736 else {
1737 if (store_it) {
1738 item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
1739 item = item_ptr;
1740 *store_array = item_ptr;
1741 }
1742
1743 /* read items and store them into the array */
1744 for (k = 0; k < list_count; k++) {
1745 get_ascii_item (words[which_word++], prop->external_type,
1746 &int_val, &uint_val, &double_val);
1747 if (store_it) {
1748 store_item (item, prop->internal_type,
1749 int_val, uint_val, double_val);
1750 item += item_size;
1751 }
1752 }
1753 }
1754
1755 }
1756 else { /* not a list */
1757 get_ascii_item (words[which_word++], prop->external_type,
1758 &int_val, &uint_val, &double_val);
1759 if (store_it) {
1760 item = elem_data + prop->offset;
1761 store_item (item, prop->internal_type, int_val, uint_val, double_val);
1762 }
1763 }
1764
1765 }
1766
1767 free (words);
1768 }
1769
1770
1771 /******************************************************************************
1772 Read an element from a binary file.
1773
1774 Entry:
1775 plyfile - file identifier
1776 elem_ptr - pointer to an element
1777 ******************************************************************************/
1778
binary_get_element(PlyFile * plyfile,char * elem_ptr)1779 void binary_get_element(PlyFile *plyfile, char *elem_ptr)
1780 {
1781 int j,k;
1782 PlyElement *elem;
1783 PlyProperty *prop;
1784 //FILE *fp = plyfile->fp;
1785 char *elem_data,*item=0;
1786 char *item_ptr;
1787 int item_size=0;
1788 int int_val;
1789 unsigned int uint_val;
1790 double double_val;
1791 int list_count;
1792 int store_it;
1793 char **store_array;
1794 char *other_data=0;
1795 int other_flag;
1796
1797 /* the kind of element we're reading currently */
1798 elem = plyfile->which_elem;
1799
1800 /* do we need to setup for other_props? */
1801
1802 if (elem->other_offset != NO_OTHER_PROPS) {
1803 char **ptr;
1804 other_flag = 1;
1805 /* make room for other_props */
1806 other_data = (char *) myalloc (elem->other_size);
1807 /* store pointer in user's structure to the other_props */
1808 ptr = (char **) (elem_ptr + elem->other_offset);
1809 *ptr = other_data;
1810 }
1811 else
1812 other_flag = 0;
1813
1814 /* read in a number of elements */
1815
1816 for (j = 0; j < elem->nprops; j++) {
1817
1818 prop = elem->props[j];
1819 store_it = (elem->store_prop[j] | other_flag);
1820
1821 /* store either in the user's structure or in other_props */
1822 if (elem->store_prop[j])
1823 elem_data = elem_ptr;
1824 else
1825 elem_data = other_data;
1826
1827 if (prop->is_list) { /* a list */
1828
1829 /* get and store the number of items in the list */
1830 get_binary_item (plyfile, prop->count_external,
1831 &int_val, &uint_val, &double_val);
1832 if (store_it) {
1833 item = elem_data + prop->count_offset;
1834 store_item(item, prop->count_internal, int_val, uint_val, double_val);
1835 }
1836
1837 /* allocate space for an array of items and store a ptr to the array */
1838 list_count = int_val;
1839 /* The "if" was added by Afra Zomorodian 8/22/95
1840 * so that zipper won't crash reading plies that have additional
1841 * properties.
1842 */
1843 if (store_it) {
1844 item_size = ply_type_size[prop->internal_type];
1845 }
1846 store_array = (char **) (elem_data + prop->offset);
1847 if (list_count == 0) {
1848 if (store_it)
1849 *store_array = NULL;
1850 }
1851 else {
1852 if (store_it) {
1853 item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
1854 item = item_ptr;
1855 *store_array = item_ptr;
1856 }
1857
1858 /* read items and store them into the array */
1859 for (k = 0; k < list_count; k++) {
1860 get_binary_item (plyfile, prop->external_type,
1861 &int_val, &uint_val, &double_val);
1862 if (store_it) {
1863 store_item (item, prop->internal_type,
1864 int_val, uint_val, double_val);
1865 item += item_size;
1866 }
1867 }
1868 }
1869
1870 }
1871 else { /* not a list */
1872 get_binary_item (plyfile, prop->external_type,
1873 &int_val, &uint_val, &double_val);
1874 if (store_it) {
1875 item = elem_data + prop->offset;
1876 store_item (item, prop->internal_type, int_val, uint_val, double_val);
1877 }
1878 }
1879
1880 }
1881 }
1882
1883
1884 /******************************************************************************
1885 Write to a file the word that represents a PLY data type.
1886
1887 Entry:
1888 fp - file pointer
1889 code - code for type
1890 ******************************************************************************/
1891
write_scalar_type(FILE * fp,int code)1892 void write_scalar_type (FILE *fp, int code)
1893 {
1894 /* make sure this is a valid code */
1895
1896 if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) {
1897 char error[100];
1898 sprintf (error, "write_scalar_type: bad data code = %d\n", code);
1899 throw ply::MeshException( error );
1900 }
1901
1902 /* write the code to a file */
1903
1904 fprintf (fp, "%s", type_names[code]);
1905 }
1906
1907
1908 /******************************************************************************
1909 Get a text line from a file and break it up into words.
1910
1911 IMPORTANT: The calling routine call "free" on the returned pointer once
1912 finished with it.
1913
1914 Entry:
1915 fp - file to read from
1916
1917 Exit:
1918 nwords - number of words returned
1919 orig_line - the original line of characters
1920 returns a list of words from the line, or NULL if end-of-file
1921 ******************************************************************************/
1922
get_words(FILE * fp,int * nwords,char ** orig_line)1923 char **get_words(FILE *fp, int *nwords, char **orig_line)
1924 {
1925 #define BIG_STRING 4096
1926 static char str[BIG_STRING];
1927 static char str_copy[BIG_STRING];
1928 char **words;
1929 int max_words = 10;
1930 int num_words = 0;
1931 char *ptr,*ptr2;
1932 char *result;
1933
1934 /* read in a line */
1935 result = fgets (str, BIG_STRING, fp);
1936 if (result == NULL) {
1937 *nwords = 0;
1938 *orig_line = NULL;
1939 return (NULL);
1940 }
1941
1942 words = (char **) myalloc (sizeof (char *) * max_words);
1943
1944 /* convert line-feed and tabs into spaces */
1945 /* (this guarantees that there will be a space before the */
1946 /* null character at the end of the string) */
1947
1948 str[BIG_STRING-2] = ' ';
1949 str[BIG_STRING-1] = '\0';
1950
1951 for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
1952 *ptr2 = *ptr;
1953 if (*ptr == '\t') {
1954 *ptr = ' ';
1955 *ptr2 = ' ';
1956 }
1957 else if (*ptr == '\n' || *ptr == '\r') {
1958 *ptr = ' ';
1959 *ptr2 = '\0';
1960 }
1961 }
1962
1963 /* find the words in the line */
1964
1965 ptr = str;
1966 while (*ptr != '\0') {
1967
1968 /* jump over leading spaces */
1969 while (*ptr == ' ')
1970 ptr++;
1971
1972 /* break if we reach the end */
1973 if (*ptr == '\0')
1974 break;
1975
1976 /* save pointer to beginning of word */
1977 if (num_words >= max_words) {
1978 max_words += 10;
1979 words = (char **) realloc (words, sizeof (char *) * max_words);
1980 }
1981 words[num_words++] = ptr;
1982
1983 /* jump over non-spaces */
1984 while (*ptr != ' ')
1985 ptr++;
1986
1987 /* place a null character here to mark the end of the word */
1988 *ptr++ = '\0';
1989 }
1990
1991 /* return the list of words */
1992 *nwords = num_words;
1993 *orig_line = str_copy;
1994 return (words);
1995 }
1996
1997
1998 /******************************************************************************
1999 Return the value of an item, given a pointer to it and its type.
2000
2001 Entry:
2002 item - pointer to item
2003 type - data type that "item" points to
2004
2005 Exit:
2006 returns a double-precision float that contains the value of the item
2007 ******************************************************************************/
2008
get_item_value(char * item,int type)2009 double get_item_value(char *item, int type)
2010 {
2011 unsigned char *puchar;
2012 char *pchar;
2013 short int *pshort;
2014 unsigned short int *pushort;
2015 int *pint;
2016 unsigned int *puint;
2017 float *pfloat;
2018 double *pdouble;
2019 int int_value;
2020 unsigned int uint_value;
2021 double double_value;
2022
2023 switch (type) {
2024 case PLY_CHAR:
2025 pchar = (char *) item;
2026 int_value = *pchar;
2027 return ((double) int_value);
2028 case PLY_UCHAR:
2029 case PLY_UINT8:
2030 puchar = (unsigned char *) item;
2031 int_value = *puchar;
2032 return ((double) int_value);
2033 case PLY_SHORT:
2034 pshort = (short int *) item;
2035 int_value = *pshort;
2036 return ((double) int_value);
2037 case PLY_USHORT:
2038 pushort = (unsigned short int *) item;
2039 int_value = *pushort;
2040 return ((double) int_value);
2041 case PLY_INT:
2042 case PLY_INT32:
2043 pint = (int *) item;
2044 int_value = *pint;
2045 return ((double) int_value);
2046 case PLY_UINT:
2047 puint = (unsigned int *) item;
2048 uint_value = *puint;
2049 return ((double) uint_value);
2050 case PLY_FLOAT:
2051 case PLY_FLOAT32:
2052 pfloat = (float *) item;
2053 double_value = *pfloat;
2054 return (double_value);
2055 case PLY_DOUBLE:
2056 pdouble = (double *) item;
2057 double_value = *pdouble;
2058 return (double_value);
2059 }
2060 fprintf (stderr, "get_item_value: bad type = %d\n", type);
2061 return 0;
2062 }
2063
2064
2065 /******************************************************************************
2066 Write out an item to a file as raw binary bytes.
2067
2068 Entry:
2069 fp - file to write to
2070 int_val - integer version of item
2071 uint_val - unsigned integer version of item
2072 double_val - double-precision float version of item
2073 type - data type to write out
2074 ******************************************************************************/
2075
write_binary_item(PlyFile * plyfile,int int_val,unsigned int uint_val,double double_val,int type)2076 void write_binary_item(PlyFile *plyfile,
2077 int int_val,
2078 unsigned int uint_val,
2079 double double_val,
2080 int type
2081 )
2082 {
2083 FILE *fp = plyfile->fp;
2084 unsigned char uchar_val;
2085 char char_val;
2086 unsigned short ushort_val;
2087 short short_val;
2088 float float_val;
2089
2090 switch (type) {
2091 case PLY_CHAR:
2092 char_val = int_val;
2093 fwrite (&char_val, 1, 1, fp);
2094 break;
2095 case PLY_SHORT:
2096 short_val = int_val;
2097 if( plyfile->file_type == PLY_BINARY_BE )
2098 swap2BE(&short_val);
2099 else
2100 swap2LE(&short_val);
2101 fwrite (&short_val, 2, 1, fp);
2102 break;
2103 case PLY_INT:
2104 case PLY_INT32:
2105 if( plyfile->file_type == PLY_BINARY_BE )
2106 {
2107 swap4BE(&int_val);
2108 }
2109 else
2110 {
2111 swap4LE(&int_val);
2112 }
2113 fwrite (&int_val, 4, 1, fp);
2114 break;
2115 case PLY_UCHAR:
2116 case PLY_UINT8:
2117 uchar_val = uint_val;
2118 fwrite (&uchar_val, 1, 1, fp);
2119 break;
2120 case PLY_USHORT:
2121 if( plyfile->file_type == PLY_BINARY_BE )
2122 {
2123 swap2BE(&ushort_val);
2124 }
2125 else
2126 {
2127 swap2LE(&ushort_val);
2128 }
2129 ushort_val = uint_val;
2130 fwrite (&ushort_val, 2, 1, fp);
2131 break;
2132 case PLY_UINT:
2133 if( plyfile->file_type == PLY_BINARY_BE )
2134 {
2135 swap4BE(&uint_val);
2136 }
2137 else
2138 {
2139 swap4LE(&uint_val);
2140 }
2141 fwrite (&uint_val, 4, 1, fp);
2142 break;
2143 case PLY_FLOAT:
2144 case PLY_FLOAT32:
2145 float_val = double_val;
2146 if( plyfile->file_type == PLY_BINARY_BE )
2147 {
2148 swap4BE(&float_val);
2149 }
2150 else
2151 {
2152 swap4LE(&float_val);
2153 }
2154 fwrite (&float_val, 4, 1, fp);
2155 break;
2156 case PLY_DOUBLE:
2157 if( plyfile->file_type == PLY_BINARY_BE )
2158 {
2159 swap8BE(&double_val);
2160 }
2161 else
2162 {
2163 swap8LE(&double_val);
2164 }
2165 fwrite (&double_val, 8, 1, fp);
2166 break;
2167 default:
2168 char error[100];
2169 sprintf (error, "write_binary_item: bad type = %d\n", type);
2170 throw ply::MeshException( error );
2171 }
2172 }
2173
2174
2175 /******************************************************************************
2176 Write out an item to a file as ascii characters.
2177
2178 Entry:
2179 fp - file to write to
2180 int_val - integer version of item
2181 uint_val - unsigned integer version of item
2182 double_val - double-precision float version of item
2183 type - data type to write out
2184 ******************************************************************************/
2185
write_ascii_item(FILE * fp,int int_val,unsigned int uint_val,double double_val,int type)2186 void write_ascii_item(
2187 FILE *fp,
2188 int int_val,
2189 unsigned int uint_val,
2190 double double_val,
2191 int type
2192 )
2193 {
2194 switch (type) {
2195 case PLY_CHAR:
2196 case PLY_SHORT:
2197 case PLY_INT:
2198 case PLY_INT32:
2199 fprintf (fp, "%d ", int_val);
2200 break;
2201 case PLY_UCHAR:
2202 case PLY_UINT8:
2203 case PLY_USHORT:
2204 case PLY_UINT:
2205 fprintf (fp, "%u ", uint_val);
2206 break;
2207 case PLY_FLOAT:
2208 case PLY_FLOAT32:
2209 case PLY_DOUBLE:
2210 fprintf (fp, "%g ", double_val);
2211 break;
2212 default:
2213 char error[100];
2214 sprintf (error, "write_ascii_item: bad type = %d\n", type);
2215 throw ply::MeshException( error );
2216 }
2217 }
2218
2219 /******************************************************************************
2220 Get the value of an item that is in memory, and place the result
2221 into an integer, an unsigned integer and a double.
2222
2223 Entry:
2224 ptr - pointer to the item
2225 type - data type supposedly in the item
2226
2227 Exit:
2228 int_val - integer value
2229 uint_val - unsigned integer value
2230 double_val - double-precision floating point value
2231 ******************************************************************************/
2232
get_stored_item(void * ptr,int type,int * int_val,unsigned int * uint_val,double * double_val)2233 void get_stored_item(
2234 void *ptr,
2235 int type,
2236 int *int_val,
2237 unsigned int *uint_val,
2238 double *double_val
2239 )
2240 {
2241 switch (type) {
2242 case PLY_CHAR:
2243 *int_val = *((char *) ptr);
2244 *uint_val = *int_val;
2245 *double_val = *int_val;
2246 break;
2247 case PLY_UCHAR:
2248 case PLY_UINT8:
2249 *uint_val = *((unsigned char *) ptr);
2250 *int_val = *uint_val;
2251 *double_val = *uint_val;
2252 break;
2253 case PLY_SHORT:
2254 *int_val = *((short int *) ptr);
2255 *uint_val = *int_val;
2256 *double_val = *int_val;
2257 break;
2258 case PLY_USHORT:
2259 *uint_val = *((unsigned short int *) ptr);
2260 *int_val = *uint_val;
2261 *double_val = *uint_val;
2262 break;
2263 case PLY_INT:
2264 case PLY_INT32:
2265 *int_val = *((int *) ptr);
2266 *uint_val = *int_val;
2267 *double_val = *int_val;
2268 break;
2269 case PLY_UINT:
2270 *uint_val = *((unsigned int *) ptr);
2271 *int_val = *uint_val;
2272 *double_val = *uint_val;
2273 break;
2274 case PLY_FLOAT:
2275 case PLY_FLOAT32:
2276 *double_val = *((float *) ptr);
2277 *int_val = (int) *double_val;
2278 *uint_val = (unsigned int) *double_val;
2279 break;
2280 case PLY_DOUBLE:
2281 *double_val = *((double *) ptr);
2282 *int_val = (int) *double_val;
2283 *uint_val = (unsigned int) *double_val;
2284 break;
2285 default:
2286 char error[100];
2287 sprintf (error, "get_stored_item: bad type = %d\n", type);
2288 throw ply::MeshException( error );
2289 }
2290 }
2291
2292
2293 /******************************************************************************
2294 Get the value of an item from a binary file, and place the result
2295 into an integer, an unsigned integer and a double.
2296
2297 Entry:
2298 fp - file to get item from
2299 type - data type supposedly in the word
2300
2301 Exit:
2302 int_val - integer value
2303 uint_val - unsigned integer value
2304 double_val - double-precision floating point value
2305 ******************************************************************************/
2306
get_binary_item(PlyFile * plyfile,int type,int * int_val,unsigned int * uint_val,double * double_val)2307 void get_binary_item(
2308 PlyFile *plyfile,
2309 int type,
2310 int *int_val,
2311 unsigned int *uint_val,
2312 double *double_val
2313 )
2314 {
2315 char c[8];
2316 void *ptr;
2317
2318 ptr = (void *) c;
2319 size_t result = 0;
2320
2321 switch (type) {
2322 case PLY_CHAR:
2323 result = fread (ptr, 1, 1, plyfile->fp);
2324 if(result < 1)
2325 {
2326 throw ply::MeshException( "Error in reading PLY file."
2327 "fread not succeeded." );
2328 }
2329 *int_val = *((char *) ptr);
2330 *uint_val = *int_val;
2331 *double_val = *int_val;
2332 break;
2333 case PLY_UCHAR:
2334 case PLY_UINT8:
2335 result = fread (ptr, 1, 1, plyfile->fp);
2336 if(result < 1)
2337 {
2338 throw ply::MeshException( "Error in reading PLY file."
2339 "fread not succeeded." );
2340 }
2341 *uint_val = *((unsigned char *) ptr);
2342 *int_val = *uint_val;
2343 *double_val = *uint_val;
2344 break;
2345 case PLY_SHORT:
2346 result = fread (ptr, 2, 1, plyfile->fp);
2347 if(result < 1 )
2348 {
2349 throw ply::MeshException( "Error in reading PLY file."
2350 "fread not succeeded." );
2351 }
2352 if( plyfile->file_type == PLY_BINARY_BE )
2353 {
2354 swap2BE(ptr);
2355 }
2356 else
2357 {
2358 swap2LE(ptr);
2359 }
2360 *int_val = *((short int *) ptr);
2361 *uint_val = *int_val;
2362 *double_val = *int_val;
2363 break;
2364 case PLY_USHORT:
2365 result = fread (ptr, 2, 1, plyfile->fp);
2366 if(result < 1)
2367 {
2368 throw ply::MeshException( "Error in reading PLY file."
2369 "fread not succeeded." );
2370 }
2371 if( plyfile->file_type == PLY_BINARY_BE )
2372 {
2373 swap2BE(ptr);
2374 }
2375 else
2376 {
2377 swap2LE(ptr);
2378 }
2379 *uint_val = *((unsigned short int *) ptr);
2380 *int_val = *uint_val;
2381 *double_val = *uint_val;
2382 break;
2383 case PLY_INT:
2384 case PLY_INT32:
2385 result = fread (ptr, 4, 1, plyfile->fp);
2386 if(result < 1)
2387 {
2388 throw ply::MeshException( "Error in reading PLY file."
2389 "fread not succeeded." );
2390 }
2391 if( plyfile->file_type == PLY_BINARY_BE )
2392 {
2393 swap4BE(ptr);
2394 }
2395 else
2396 {
2397 swap4LE(ptr);
2398 }
2399 *int_val = *((int *) ptr);
2400 *uint_val = *int_val;
2401 *double_val = *int_val;
2402 break;
2403 case PLY_UINT:
2404 result = fread (ptr, 4, 1, plyfile->fp);
2405 if(result < 1)
2406 {
2407 throw ply::MeshException( "Error in reading PLY file."
2408 "fread not succeeded." );
2409 }
2410 if( plyfile->file_type == PLY_BINARY_BE )
2411 {
2412 swap4BE(ptr);
2413 }
2414 else
2415 {
2416 swap4LE(ptr);
2417 }
2418 *uint_val = *((unsigned int *) ptr);
2419 *int_val = *uint_val;
2420 *double_val = *uint_val;
2421 break;
2422 case PLY_FLOAT:
2423 case PLY_FLOAT32:
2424 result = fread (ptr, 4, 1, plyfile->fp);
2425 if(result < 1)
2426 {
2427 throw ply::MeshException( "Error in reading PLY file."
2428 "fread not succeeded." );
2429 }
2430 if( plyfile->file_type == PLY_BINARY_BE )
2431 {
2432 swap4BE(ptr);
2433 }
2434 else
2435 {
2436 swap4LE(ptr);
2437 }
2438 *double_val = *((float *) ptr);
2439 *int_val = (int) *double_val;
2440 *uint_val = (unsigned int) *double_val;
2441 break;
2442 case PLY_DOUBLE:
2443 result = fread (ptr, 8, 1, plyfile->fp);
2444 if(result < 1)
2445 {
2446 throw ply::MeshException( "Error in reading PLY file."
2447 "fread not succeeded." );
2448 }
2449 if( plyfile->file_type == PLY_BINARY_BE )
2450 {
2451 swap8BE(ptr);
2452 }
2453 else
2454 {
2455 swap8LE(ptr);
2456 }
2457 *double_val = *((double *) ptr);
2458 *int_val = (int) *double_val;
2459 *uint_val = (unsigned int) *double_val;
2460 break;
2461 default:
2462 char error[100];
2463 sprintf (error, "get_binary_item: bad type = %d\n", type);
2464 throw ply::MeshException( error );
2465 }
2466 }
2467
2468
2469 /******************************************************************************
2470 Extract the value of an item from an ascii word, and place the result
2471 into an integer, an unsigned integer and a double.
2472
2473 Entry:
2474 word - word to extract value from
2475 type - data type supposedly in the word
2476
2477 Exit:
2478 int_val - integer value
2479 uint_val - unsigned integer value
2480 double_val - double-precision floating point value
2481 ******************************************************************************/
2482
get_ascii_item(char * word,int type,int * int_val,unsigned int * uint_val,double * double_val)2483 void get_ascii_item(
2484 char *word,
2485 int type,
2486 int *int_val,
2487 unsigned int *uint_val,
2488 double *double_val
2489 )
2490 {
2491 switch (type) {
2492 case PLY_CHAR:
2493 case PLY_UCHAR:
2494 case PLY_UINT8:
2495 case PLY_SHORT:
2496 case PLY_USHORT:
2497 case PLY_INT:
2498 case PLY_INT32:
2499 *int_val = atoi (word);
2500 *uint_val = *int_val;
2501 *double_val = *int_val;
2502 break;
2503
2504 case PLY_UINT:
2505 *uint_val = strtoul (word, (char **) NULL, 10);
2506 *int_val = *uint_val;
2507 *double_val = *uint_val;
2508 break;
2509
2510 case PLY_FLOAT:
2511 case PLY_FLOAT32:
2512 case PLY_DOUBLE:
2513 *double_val = osg::asciiToDouble(word);
2514 *int_val = (int) *double_val;
2515 *uint_val = (unsigned int) *double_val;
2516 break;
2517
2518 default:
2519 char error[100];
2520 sprintf (error, "get_ascii_item: bad type = %d\n", type);
2521 throw ply::MeshException( error );
2522 }
2523 }
2524
2525
2526 /******************************************************************************
2527 Store a value into a place being pointed to, guided by a data type.
2528
2529 Entry:
2530 item - place to store value
2531 type - data type
2532 int_val - integer version of value
2533 uint_val - unsigned integer version of value
2534 double_val - double version of value
2535
2536 Exit:
2537 item - pointer to stored value
2538 ******************************************************************************/
2539
store_item(char * item,int type,int int_val,unsigned int uint_val,double double_val)2540 void store_item (
2541 char *item,
2542 int type,
2543 int int_val,
2544 unsigned int uint_val,
2545 double double_val
2546 )
2547 {
2548 unsigned char *puchar;
2549 short int *pshort;
2550 unsigned short int *pushort;
2551 int *pint;
2552 unsigned int *puint;
2553 float *pfloat;
2554 double *pdouble;
2555
2556 switch (type) {
2557 case PLY_CHAR:
2558 *item = int_val;
2559 break;
2560 case PLY_UCHAR:
2561 case PLY_UINT8:
2562 puchar = (unsigned char *) item;
2563 *puchar = uint_val;
2564 break;
2565 case PLY_SHORT:
2566 pshort = (short *) item;
2567 *pshort = int_val;
2568 break;
2569 case PLY_USHORT:
2570 pushort = (unsigned short *) item;
2571 *pushort = uint_val;
2572 break;
2573 case PLY_INT:
2574 case PLY_INT32:
2575 pint = (int *) item;
2576 *pint = int_val;
2577 break;
2578 case PLY_UINT:
2579 puint = (unsigned int *) item;
2580 *puint = uint_val;
2581 break;
2582 case PLY_FLOAT:
2583 case PLY_FLOAT32:
2584 pfloat = (float *) item;
2585 *pfloat = double_val;
2586 break;
2587 case PLY_DOUBLE:
2588 pdouble = (double *) item;
2589 *pdouble = double_val;
2590 break;
2591 default:
2592 char error[100];
2593 sprintf (error, "store_item: bad type = %d\n", type);
2594 throw ply::MeshException( error );
2595 }
2596 }
2597
2598
2599 /******************************************************************************
2600 Add an element to a PLY file descriptor.
2601
2602 Entry:
2603 plyfile - PLY file descriptor
2604 words - list of words describing the element
2605 nwords - number of words in the list
2606 ******************************************************************************/
2607
add_element(PlyFile * plyfile,char ** words,int)2608 void add_element (PlyFile *plyfile, char **words, int)
2609 {
2610 PlyElement *elem;
2611
2612 /* create the new element */
2613 elem = (PlyElement *) myalloc (sizeof (PlyElement));
2614 elem->name = strdup (words[1]);
2615 elem->num = atoi (words[2]);
2616 elem->nprops = 0;
2617
2618 /* make room for new element in the object's list of elements */
2619 if (plyfile->nelems == 0)
2620 plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *));
2621 else
2622 plyfile->elems = (PlyElement **) realloc (plyfile->elems,
2623 sizeof (PlyElement *) * (plyfile->nelems + 1));
2624
2625 /* add the new element to the object's list */
2626 plyfile->elems[plyfile->nelems] = elem;
2627 plyfile->nelems++;
2628 }
2629
2630
2631 /******************************************************************************
2632 Return the type of a property, given the name of the property.
2633
2634 Entry:
2635 name - name of property type
2636
2637 Exit:
2638 returns integer code for property, or 0 if not found
2639 ******************************************************************************/
2640
get_prop_type(char * type_name)2641 int get_prop_type(char *type_name)
2642 {
2643 int i;
2644
2645 for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++)
2646 if (equal_strings (type_name, type_names[i]))
2647 return (i);
2648
2649 /* if we get here, we didn't find the type */
2650 return (0);
2651 }
2652
2653
2654 /******************************************************************************
2655 Add a property to a PLY file descriptor.
2656
2657 Entry:
2658 plyfile - PLY file descriptor
2659 words - list of words describing the property
2660 nwords - number of words in the list
2661 ******************************************************************************/
2662
add_property(PlyFile * plyfile,char ** words,int)2663 void add_property (PlyFile *plyfile, char **words, int )
2664 {
2665 PlyProperty *prop;
2666 PlyElement *elem;
2667
2668 /* create the new property */
2669
2670 prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
2671
2672 if (equal_strings (words[1], "list")) { /* is a list */
2673 prop->count_external = get_prop_type (words[2]);
2674 prop->external_type = get_prop_type (words[3]);
2675 prop->name = strdup (words[4]);
2676 prop->is_list = 1;
2677 }
2678 else { /* not a list */
2679 prop->external_type = get_prop_type (words[1]);
2680 prop->name = strdup (words[2]);
2681 prop->is_list = 0;
2682 }
2683
2684 /* add this property to the list of properties of the current element */
2685
2686 elem = plyfile->elems[plyfile->nelems - 1];
2687
2688 if (elem->nprops == 0)
2689 elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
2690 else
2691 elem->props = (PlyProperty **) realloc (elem->props,
2692 sizeof (PlyProperty *) * (elem->nprops + 1));
2693
2694 elem->props[elem->nprops] = prop;
2695 elem->nprops++;
2696 }
2697
2698
2699 /******************************************************************************
2700 Add a comment to a PLY file descriptor.
2701
2702 Entry:
2703 plyfile - PLY file descriptor
2704 line - line containing comment
2705 ******************************************************************************/
2706
add_comment(PlyFile * plyfile,char * line)2707 void add_comment (PlyFile *plyfile, char *line)
2708 {
2709 int i;
2710
2711 /* skip over "comment" and leading spaces and tabs */
2712 i = 7;
2713 while (line[i] == ' ' || line[i] == '\t')
2714 i++;
2715
2716 ply_put_comment (plyfile, &line[i]);
2717 }
2718
2719
2720 /******************************************************************************
2721 Add a some object information to a PLY file descriptor.
2722
2723 Entry:
2724 plyfile - PLY file descriptor
2725 line - line containing text info
2726 ******************************************************************************/
2727
add_obj_info(PlyFile * plyfile,char * line)2728 void add_obj_info (PlyFile *plyfile, char *line)
2729 {
2730 int i;
2731
2732 /* skip over "obj_info" and leading spaces and tabs */
2733 i = 8;
2734 while (line[i] == ' ' || line[i] == '\t')
2735 i++;
2736
2737 ply_put_obj_info (plyfile, &line[i]);
2738 }
2739
2740
2741 /******************************************************************************
2742 Copy a property.
2743 ******************************************************************************/
2744
copy_property(PlyProperty * dest,PlyProperty * src)2745 void copy_property(PlyProperty *dest, PlyProperty *src)
2746 {
2747 dest->name = strdup (src->name);
2748 dest->external_type = src->external_type;
2749 dest->internal_type = src->internal_type;
2750 dest->offset = src->offset;
2751
2752 dest->is_list = src->is_list;
2753 dest->count_external = src->count_external;
2754 dest->count_internal = src->count_internal;
2755 dest->count_offset = src->count_offset;
2756 }
2757
2758
2759 /******************************************************************************
2760 Allocate some memory.
2761
2762 Entry:
2763 size - amount of memory requested (in bytes)
2764 lnum - line number from which memory was requested
2765 fname - file name from which memory was requested
2766 ******************************************************************************/
2767
my_alloc(int size,int lnum,const char * fname)2768 char *my_alloc(int size, int lnum, const char *fname)
2769 {
2770 char *ptr;
2771
2772 ptr = (char *) malloc (size);
2773
2774 if (ptr == 0)
2775 fprintf( stderr, "Memory allocation bombed on line %d in %s\n",
2776 lnum, fname);
2777
2778 return (ptr);
2779 }
2780
2781